initial state

Currently limine based, cribbing from osdev wiki a bit, and from
dreamportdev
This commit is contained in:
Hopeless Tyromancy 2026-02-02 19:51:54 -05:00
commit 0d436e5255
16 changed files with 1245 additions and 0 deletions

136
Makefile Normal file
View File

@ -0,0 +1,136 @@
# Nuke built-in rules.
.SUFFIXES:
override OUTPUT := os
# User controllable toolchain and toolchain prefix.
TOOLCHAIN :=
TOOLCHAIN_PREFIX :=
ifneq ($(TOOLCHAIN),)
ifeq ($(TOOLCHAIN_PREFIX),)
TOOLCHAIN_PREFIX := $(TOOLCHAIN)-
endif
endif
# User controllable C compiler command.
ifneq ($(TOOLCHAIN_PREFIX),)
CC := $(TOOLCHAIN_PREFIX)gcc
else
CC := cc
endif
# User controllable linker command.
LD := $(TOOLCHAIN_PREFIX)ld
# Defaults overrides for variables if using "llvm" as toolchain.
ifeq ($(TOOLCHAIN),llvm)
CC := clang
LD := ld.lld
endif
# User controllable C flags.
CFLAGS := -g -O2 -pipe -Iinclude
# User controllable C preprocessor flags. We set none by default.
CPPFLAGS :=
# User controllable nasm flags.
NASMFLAGS := -g
# User controllable linker flags. We set none by default.
LDFLAGS :=
# Check if CC is Clang.
override CC_IS_CLANG := $(shell ! $(CC) --version 2>/dev/null | grep -q '^Target: '; echo $$?)
# If the C compiler is Clang, set the target as needed.
ifeq ($(CC_IS_CLANG),1)
override CC += \
-target x86_64-unknown-none-elf
endif
# Internal C flags that should not be changed by the user.
override CFLAGS += \
-Wall \
-Wextra \
-std=gnu11 \
-ffreestanding \
-fno-stack-protector \
-fno-stack-check \
-fno-lto \
-fno-PIC \
-ffunction-sections \
-fdata-sections \
-m64 \
-march=x86-64 \
-mabi=sysv \
-mno-80387 \
-mno-mmx \
-mno-sse \
-mno-sse2 \
-mno-red-zone \
-mcmodel=kernel
# Internal C preprocessor flags that should not be changed by the user.
override CPPFLAGS := \
-I src \
$(CPPFLAGS) \
-MMD \
-MP
# Internal nasm flags that should not be changed by the user.
override NASMFLAGS := \
-f elf64 \
$(patsubst -g,-g -F dwarf,$(NASMFLAGS)) \
-Wall
# Internal linker flags that should not be changed by the user.
override LDFLAGS += \
-m elf_x86_64 \
-nostdlib \
-static \
-z max-page-size=0x1000 \
--gc-sections \
-T linker.ld
# Use "find" to glob all *.c, *.S, and *.asm files in the tree and obtain the
# object and header dependency file names.
override SRCFILES := $(shell find -L src -type f 2>/dev/null | LC_ALL=C sort)
override CFILES := $(filter %.c,$(SRCFILES))
override ASFILES := $(filter %.S,$(SRCFILES))
override NASMFILES := $(filter %.asm,$(SRCFILES))
override OBJ := $(addprefix obj/,$(CFILES:.c=.c.o) $(ASFILES:.S=.S.o) $(NASMFILES:.asm=.asm.o))
override HEADER_DEPS := $(addprefix obj/,$(CFILES:.c=.c.d) $(ASFILES:.S=.S.d))
# Default target. This must come first, before header dependencies.
.PHONY: all
all: bin/$(OUTPUT)
sh limine.sh
# Include header dependencies.
-include $(HEADER_DEPS)
# Link rules for the final executable.
bin/$(OUTPUT): linker.ld $(OBJ)
mkdir -p "$(dir $@)"
$(LD) $(LDFLAGS) $(OBJ) -o $@
# Compilation rules for *.c files.
obj/%.c.o: %.c Makefile
mkdir -p "$(dir $@)"
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
# Compilation rules for *.S files.
obj/%.S.o: %.S Makefile
mkdir -p "$(dir $@)"
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
# Compilation rules for *.asm (nasm) files.
obj/%.asm.o: %.asm Makefile
mkdir -p "$(dir $@)"
nasm $(NASMFLAGS) $< -o $@
# Remove object files and the final executable.
.PHONY: clean
clean:
rm -rf bin obj

BIN
bin/os Executable file

Binary file not shown.

26
flake.lock generated Normal file
View File

@ -0,0 +1,26 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1770057536,
"narHash": "sha256-Y/Dqu+7StqRVlzQEbow5l2Ws02P9IrHO3eVnpVWbLTE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "79faf5ae0424fe8cd1d07064a513667e6b6ae65a",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

23
flake.nix Normal file
View File

@ -0,0 +1,23 @@
{
description = "NEURON with custom mechanisms";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
in {
devShells.${system}.default = pkgs.mkShell {
packages = [
pkgs.limine
pkgs.clang
pkgs.gcc
pkgs.gnumake
pkgs.nasm
];
};
};
}

BIN
image.hdd Normal file

Binary file not shown.

576
include/limine.h Normal file
View File

@ -0,0 +1,576 @@
/* SPDX-License-Identifier: 0BSD */
/* Copyright (C) 2022-2026 Mintsuki and contributors.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LIMINE_H
#define LIMINE_H 1
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Misc */
#ifdef LIMINE_NO_POINTERS
# define LIMINE_PTR(TYPE) uint64_t
#else
# define LIMINE_PTR(TYPE) TYPE
#endif
#define LIMINE_REQUESTS_START_MARKER { 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, \
0x785c6ed015d3e316, 0x181e920a7852b9d9 }
#define LIMINE_REQUESTS_END_MARKER { 0xadc0e0531bb10d03, 0x9572709f31764c62 }
#define LIMINE_BASE_REVISION(N) { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) }
#define LIMINE_BASE_REVISION_SUPPORTED(VAR) ((VAR)[2] == 0)
#define LIMINE_LOADED_BASE_REVISION_VALID(VAR) ((VAR)[1] != 0x6a7b384944536bdc)
#define LIMINE_LOADED_BASE_REVISION(VAR) ((VAR)[1])
#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b
struct limine_uuid {
uint32_t a;
uint16_t b;
uint16_t c;
uint8_t d[8];
};
#define LIMINE_MEDIA_TYPE_GENERIC 0
#define LIMINE_MEDIA_TYPE_OPTICAL 1
#define LIMINE_MEDIA_TYPE_TFTP 2
struct limine_file {
uint64_t revision;
LIMINE_PTR(void *) address;
uint64_t size;
LIMINE_PTR(char *) path;
LIMINE_PTR(char *) string;
uint32_t media_type;
uint32_t unused;
uint32_t tftp_ip;
uint32_t tftp_port;
uint32_t partition_index;
uint32_t mbr_disk_id;
struct limine_uuid gpt_disk_uuid;
struct limine_uuid gpt_part_uuid;
struct limine_uuid part_uuid;
};
/* Boot info */
#define LIMINE_BOOTLOADER_INFO_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 }
struct limine_bootloader_info_response {
uint64_t revision;
LIMINE_PTR(char *) name;
LIMINE_PTR(char *) version;
};
struct limine_bootloader_info_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_bootloader_info_response *) response;
};
/* Executable command line */
#define LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x4b161536e598651e, 0xb390ad4a2f1f303a }
struct limine_executable_cmdline_response {
uint64_t revision;
LIMINE_PTR(char *) cmdline;
};
struct limine_executable_cmdline_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_executable_cmdline_response *) response;
};
/* Firmware type */
#define LIMINE_FIRMWARE_TYPE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3 }
#define LIMINE_FIRMWARE_TYPE_X86BIOS 0
#define LIMINE_FIRMWARE_TYPE_EFI32 1
#define LIMINE_FIRMWARE_TYPE_EFI64 2
#define LIMINE_FIRMWARE_TYPE_SBI 3
struct limine_firmware_type_response {
uint64_t revision;
uint64_t firmware_type;
};
struct limine_firmware_type_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_firmware_type_response *) response;
};
/* Stack size */
#define LIMINE_STACK_SIZE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d }
struct limine_stack_size_response {
uint64_t revision;
};
struct limine_stack_size_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_stack_size_response *) response;
uint64_t stack_size;
};
/* HHDM */
#define LIMINE_HHDM_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b }
struct limine_hhdm_response {
uint64_t revision;
uint64_t offset;
};
struct limine_hhdm_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_hhdm_response *) response;
};
/* Framebuffer */
#define LIMINE_FRAMEBUFFER_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b }
#define LIMINE_FRAMEBUFFER_RGB 1
struct limine_video_mode {
uint64_t pitch;
uint64_t width;
uint64_t height;
uint16_t bpp;
uint8_t memory_model;
uint8_t red_mask_size;
uint8_t red_mask_shift;
uint8_t green_mask_size;
uint8_t green_mask_shift;
uint8_t blue_mask_size;
uint8_t blue_mask_shift;
};
struct limine_framebuffer {
LIMINE_PTR(void *) address;
uint64_t width;
uint64_t height;
uint64_t pitch;
uint16_t bpp;
uint8_t memory_model;
uint8_t red_mask_size;
uint8_t red_mask_shift;
uint8_t green_mask_size;
uint8_t green_mask_shift;
uint8_t blue_mask_size;
uint8_t blue_mask_shift;
uint8_t unused[7];
uint64_t edid_size;
LIMINE_PTR(void *) edid;
/* Response revision 1 */
uint64_t mode_count;
LIMINE_PTR(struct limine_video_mode **) modes;
};
struct limine_framebuffer_response {
uint64_t revision;
uint64_t framebuffer_count;
LIMINE_PTR(struct limine_framebuffer **) framebuffers;
};
struct limine_framebuffer_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_framebuffer_response *) response;
};
/* Paging mode */
#define LIMINE_PAGING_MODE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a }
#define LIMINE_PAGING_MODE_X86_64_4LVL 0
#define LIMINE_PAGING_MODE_X86_64_5LVL 1
#define LIMINE_PAGING_MODE_X86_64_MIN LIMINE_PAGING_MODE_X86_64_4LVL
#define LIMINE_PAGING_MODE_X86_64_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL
#define LIMINE_PAGING_MODE_AARCH64_4LVL 0
#define LIMINE_PAGING_MODE_AARCH64_5LVL 1
#define LIMINE_PAGING_MODE_AARCH64_MIN LIMINE_PAGING_MODE_AARCH64_4LVL
#define LIMINE_PAGING_MODE_AARCH64_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL
#define LIMINE_PAGING_MODE_RISCV_SV39 0
#define LIMINE_PAGING_MODE_RISCV_SV48 1
#define LIMINE_PAGING_MODE_RISCV_SV57 2
#define LIMINE_PAGING_MODE_RISCV_MIN LIMINE_PAGING_MODE_RISCV_SV39
#define LIMINE_PAGING_MODE_RISCV_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48
#define LIMINE_PAGING_MODE_LOONGARCH_4LVL 0
#define LIMINE_PAGING_MODE_LOONGARCH_MIN LIMINE_PAGING_MODE_LOONGARCH_4LVL
#define LIMINE_PAGING_MODE_LOONGARCH_DEFAULT LIMINE_PAGING_MODE_LOONGARCH_4LVL
struct limine_paging_mode_response {
uint64_t revision;
uint64_t mode;
};
struct limine_paging_mode_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_paging_mode_response *) response;
uint64_t mode;
uint64_t max_mode;
uint64_t min_mode;
};
/* MP */
#define LIMINE_MP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
struct limine_mp_info;
typedef void (*limine_goto_address)(struct limine_mp_info *);
#if defined (__x86_64__) || defined (__i386__)
#define LIMINE_MP_RESPONSE_X86_64_X2APIC (1 << 0)
struct limine_mp_info {
uint32_t processor_id;
uint32_t lapic_id;
uint64_t reserved;
LIMINE_PTR(limine_goto_address) goto_address;
uint64_t extra_argument;
};
struct limine_mp_response {
uint64_t revision;
uint32_t flags;
uint32_t bsp_lapic_id;
uint64_t cpu_count;
LIMINE_PTR(struct limine_mp_info **) cpus;
};
#elif defined (__aarch64__)
struct limine_mp_info {
uint32_t processor_id;
uint32_t reserved1;
uint64_t mpidr;
uint64_t reserved;
LIMINE_PTR(limine_goto_address) goto_address;
uint64_t extra_argument;
};
struct limine_mp_response {
uint64_t revision;
uint64_t flags;
uint64_t bsp_mpidr;
uint64_t cpu_count;
LIMINE_PTR(struct limine_mp_info **) cpus;
};
#elif defined (__riscv) && (__riscv_xlen == 64)
struct limine_mp_info {
uint64_t processor_id;
uint64_t hartid;
uint64_t reserved;
LIMINE_PTR(limine_goto_address) goto_address;
uint64_t extra_argument;
};
struct limine_mp_response {
uint64_t revision;
uint64_t flags;
uint64_t bsp_hartid;
uint64_t cpu_count;
LIMINE_PTR(struct limine_mp_info **) cpus;
};
#elif defined (__loongarch__) && (__loongarch_grlen == 64)
struct limine_mp_info {
uint64_t reserved;
};
struct limine_mp_response {
uint64_t cpu_count;
LIMINE_PTR(struct limine_mp_info **) cpus;
};
#else
#error Unknown architecture
#endif
#define LIMINE_MP_REQUEST_X86_64_X2APIC (1 << 0)
struct limine_mp_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_mp_response *) response;
uint64_t flags;
};
/* Memory map */
#define LIMINE_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 }
#define LIMINE_MEMMAP_USABLE 0
#define LIMINE_MEMMAP_RESERVED 1
#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2
#define LIMINE_MEMMAP_ACPI_NVS 3
#define LIMINE_MEMMAP_BAD_MEMORY 4
#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5
#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6
#define LIMINE_MEMMAP_FRAMEBUFFER 7
#define LIMINE_MEMMAP_ACPI_TABLES 8
struct limine_memmap_entry {
uint64_t base;
uint64_t length;
uint64_t type;
};
struct limine_memmap_response {
uint64_t revision;
uint64_t entry_count;
LIMINE_PTR(struct limine_memmap_entry **) entries;
};
struct limine_memmap_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_memmap_response *) response;
};
/* Entry point */
#define LIMINE_ENTRY_POINT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a }
typedef void (*limine_entry_point)(void);
struct limine_entry_point_response {
uint64_t revision;
};
struct limine_entry_point_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_entry_point_response *) response;
LIMINE_PTR(limine_entry_point) entry;
};
/* Executable File */
#define LIMINE_EXECUTABLE_FILE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 }
struct limine_executable_file_response {
uint64_t revision;
LIMINE_PTR(struct limine_file *) executable_file;
};
struct limine_executable_file_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_executable_file_response *) response;
};
/* Module */
#define LIMINE_MODULE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee }
#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0)
#define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1)
struct limine_internal_module {
LIMINE_PTR(const char *) path;
LIMINE_PTR(const char *) string;
uint64_t flags;
};
struct limine_module_response {
uint64_t revision;
uint64_t module_count;
LIMINE_PTR(struct limine_file **) modules;
};
struct limine_module_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_module_response *) response;
/* Request revision 1 */
uint64_t internal_module_count;
LIMINE_PTR(struct limine_internal_module **) internal_modules;
};
/* RSDP */
#define LIMINE_RSDP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c }
struct limine_rsdp_response {
uint64_t revision;
LIMINE_PTR(void *) address;
};
struct limine_rsdp_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_rsdp_response *) response;
};
/* SMBIOS */
#define LIMINE_SMBIOS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee }
struct limine_smbios_response {
uint64_t revision;
uint64_t entry_32;
uint64_t entry_64;
};
struct limine_smbios_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_smbios_response *) response;
};
/* EFI system table */
#define LIMINE_EFI_SYSTEM_TABLE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc }
struct limine_efi_system_table_response {
uint64_t revision;
uint64_t address;
};
struct limine_efi_system_table_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_efi_system_table_response *) response;
};
/* EFI memory map */
#define LIMINE_EFI_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x7df62a431d6872d5, 0xa4fcdfb3e57306c8 }
struct limine_efi_memmap_response {
uint64_t revision;
LIMINE_PTR(void *) memmap;
uint64_t memmap_size;
uint64_t desc_size;
uint64_t desc_version;
};
struct limine_efi_memmap_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_efi_memmap_response *) response;
};
/* Date at boot */
#define LIMINE_DATE_AT_BOOT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 }
struct limine_date_at_boot_response {
uint64_t revision;
int64_t timestamp;
};
struct limine_date_at_boot_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_date_at_boot_response *) response;
};
/* Executable address */
#define LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 }
struct limine_executable_address_response {
uint64_t revision;
uint64_t physical_base;
uint64_t virtual_base;
};
struct limine_executable_address_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_executable_address_response *) response;
};
/* Device Tree Blob */
#define LIMINE_DTB_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 }
struct limine_dtb_response {
uint64_t revision;
LIMINE_PTR(void *) dtb_ptr;
};
struct limine_dtb_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_dtb_response *) response;
};
/* RISC-V Boot Hart ID */
#define LIMINE_RISCV_BSP_HARTID_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x1369359f025525f9, 0x2ff2a56178391bb6 }
struct limine_riscv_bsp_hartid_response {
uint64_t revision;
uint64_t bsp_hartid;
};
struct limine_riscv_bsp_hartid_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response;
};
/* Bootloader Performance */
#define LIMINE_BOOTLOADER_PERFORMANCE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x6b50ad9bf36d13ad, 0xdc4c7e88fc759e17 }
struct limine_bootloader_performance_response {
uint64_t revision;
uint64_t reset_usec;
uint64_t init_usec;
uint64_t exec_usec;
};
struct limine_bootloader_performance_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_bootloader_performance_response *) response;
};
#ifdef __cplusplus
}
#endif
#endif

1
limine Submodule

@ -0,0 +1 @@
Subproject commit 7a6892a36f1fb6dbdd6e6f6d00b8062d5bcb813b

5
limine.conf Normal file
View File

@ -0,0 +1,5 @@
timeout: 5
/LispOS
protocol: limine
path: boot():/boot/os

28
limine.sh Normal file
View File

@ -0,0 +1,28 @@
# Create an empty zeroed-out 64MiB image file.
dd if=/dev/zero bs=1M count=0 seek=64 of=image.hdd
# Create a partition table.
, sgdisk image.hdd -n 1:2048 -t 1:ef00 -m 1
#rm -rf limine
# Download the latest Limine binary release for the 10.x branch.
#git clone https://codeberg.org/Limine/Limine.git limine --branch=v10.x-binary --depth=1
# Build "limine" utility.
#make -C limine
# Install the Limine BIOS stages onto the image.
./limine/limine bios-install image.hdd
# Format the image as fat32.
, mformat -i image.hdd@@1M
# Make relevant subdirectories.
, mmd -i image.hdd@@1M ::/EFI ::/EFI/BOOT ::/boot ::/boot/limine
# Copy over the relevant files.
, mcopy -i image.hdd@@1M bin/os ::/boot
, mcopy -i image.hdd@@1M limine.conf limine/limine-bios.sys ::/boot/limine
, mcopy -i image.hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT
, mcopy -i image.hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT

57
linker.ld Normal file
View File

@ -0,0 +1,57 @@
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(kmain)
/* program headers to get MMU perms */
PHDRS {
limine_requests PT_LOAD;
text PT_LOAD;
rodata PT_LOAD;
data PT_LOAD;
}
SECTIONS {
/* we want topmost 2GiB of addr space */
. = 0xffffffff80000000;
.limine_requests : {
KEEP(*(.limine_requests_start))
KEEP(*(.limine_requests))
KEEP(*(.limine_requests_end))
} :limine_requests
. = ALIGN(CONSTANT(MAXPAGESIZE));
.text : {
*(.text .text.*)
} :text
. = ALIGN(CONSTANT(MAXPAGESIZE));
.rodata : {
*(.rodata .rodata.*)
} :rodata
.note.gnu.build-id : {
*(.note.gnu.build-id)
} :rodata
. = ALIGN(CONSTANT(MAXPAGESIZE));
.data : {
*(.data .data.*)
} :data
/* .bss need sto be the last thing mapped */
.bss : {
*(.bss .bss.*)
*(COMMON)
} :data
/DISCARD/ : {
*(.eh_frame*)
*(.note .note.*)
}
}

1
obj/src/int.c.d Normal file
View File

@ -0,0 +1 @@
obj/src/int.c.o: src/int.c

BIN
obj/src/int.c.o Normal file

Binary file not shown.

2
obj/src/main.c.d Normal file
View File

@ -0,0 +1,2 @@
obj/src/main.c.o: src/main.c src/../include/limine.h
src/../include/limine.h:

BIN
obj/src/main.c.o Normal file

Binary file not shown.

271
src/int.c Normal file
View File

@ -0,0 +1,271 @@
#include <stdint.h>
#define pstruct struct __attribute__((packed))
pstruct int_desc {
uint16_t addr_low;
uint16_t selector;
uint8_t ist;
uint8_t flags;
uint16_t addr_mid;
uint32_t addr_high;
uint32_t resv;
};
enum INT_DESC_FLAGS {
ID_GATE_INT = 0b00001110,
ID_GATE_TRAP = 0b00001111,
ID_DPL = 0b00100000,
ID_PRESENT = 0b10000000,
};
#define CODE64_SELECTOR 0x28
struct int_desc idt[256];
void set_idt(uint8_t vect, void* handler, uint8_t dpl) {
struct int_desc* ent = &idt[vect];
uint64_t addr = (uint64_t) handler;
ent->addr_low = addr & 0xFFFF;
ent->addr_mid = (addr >> 16) & 0xFFFF;
ent->addr_mid = addr >> 32;
ent->selector = CODE64_SELECTOR;
ent->flags = ID_GATE_INT | dpl*ID_DPL | ID_PRESENT;
ent->ist = 0;
}
pstruct idtr {
uint16_t limit;
uint64_t base;
};
#define IDTR_LIMIT (sizeof(struct int_desc)*256 - 1)
void load_idt(void* addr) {
struct idtr ir = (struct idtr) {
.limit = IDTR_LIMIT,
.base = (uint64_t) addr,
};
asm volatile("lidt %0" :: "m"(ir));
}
extern void draw(uint8_t vect);
struct cpu_ctx {
uint64_t r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rdx, rcx, rbx, rax;
uint64_t vect;
uint64_t err;
uint64_t iret_rip;
uint64_t iret_cs;
uint64_t iret_flags;
uint64_t iret_rsp;
uint64_t iret_ss;
};
struct cpu_ctx* interrupt_dispatch(struct cpu_ctx* ctx) {
draw(ctx->vect);
return ctx;
}
void int_stub(void) {
__asm__ volatile (
"push %%rax\n"
"push %%rbx\n"
"push %%rcx\n"
"push %%rdx\n"
"push %%rsi\n"
"push %%rdi\n"
"push %%r8\n"
"push %%r9\n"
"push %%r10\n"
"push %%r11\n"
"push %%r12\n"
"push %%r13\n"
"push %%r14\n"
"push %%r15\n"
"mov %%rsp, %%rdi\n"
"call interrupt_dispatch\n"
"mov %%rax, %%rsp\n"
"pop %%r15\n"
"pop %%r14\n"
"pop %%r13\n"
"pop %%r12\n"
"pop %%r11\n"
"pop %%r10\n"
"pop %%r9\n"
"pop %%r8\n"
"pop %%rdi\n"
"pop %%rsi\n"
"pop %%rdx\n"
"pop %%rcx\n"
"pop %%rbx\n"
"pop %%rax\n"
"add $16, %%rsp\n"
"iret\n"
:
:
: "memory"
);
}
// Macro to generate interrupt stubs without error codes (push dummy 0)
#define ISR_NO_ERR(num) \
__attribute__((naked)) void isr##num(void) { \
asm volatile( \
"push $0\n" \
"push %0\n" \
"jmp int_stub\n" \
: : "i"(num)); \
}
// Macro to generate interrupt stubs with error codes
#define ISR_ERR(num) \
__attribute__((naked)) void isr##num(void) { \
asm volatile( \
"push %0\n" \
"jmp int_stub\n" \
: : "i"(num)); \
}
// CPU exceptions (0-31)
ISR_NO_ERR(0) // Divide by zero
ISR_NO_ERR(1) // Debug
ISR_NO_ERR(2) // NMI
ISR_NO_ERR(3) // Breakpoint
ISR_NO_ERR(4) // Overflow
ISR_NO_ERR(5) // Bound range exceeded
ISR_NO_ERR(6) // Invalid opcode
ISR_NO_ERR(7) // Device not available
ISR_ERR(8) // Double fault (pushes error code)
ISR_NO_ERR(9) // Coprocessor segment overrun
ISR_ERR(10) // Invalid TSS (pushes error code)
ISR_ERR(11) // Segment not present (pushes error code)
ISR_ERR(12) // Stack-segment fault (pushes error code)
ISR_ERR(13) // General protection fault (pushes error code)
ISR_ERR(14) // Page fault (pushes error code)
ISR_NO_ERR(15) // Reserved
ISR_NO_ERR(16) // x87 FPU error
ISR_ERR(17) // Alignment check (pushes error code)
ISR_NO_ERR(18) // Machine check
ISR_NO_ERR(19) // SIMD floating-point exception
ISR_NO_ERR(20) // Virtualization exception
ISR_ERR(21) // Control protection exception (pushes error code)
ISR_NO_ERR(22) // Reserved
ISR_NO_ERR(23) // Reserved
ISR_NO_ERR(24) // Reserved
ISR_NO_ERR(25) // Reserved
ISR_NO_ERR(26) // Reserved
ISR_NO_ERR(27) // Reserved
ISR_NO_ERR(28) // Reserved
ISR_NO_ERR(29) // Reserved
ISR_ERR(30) // Security exception (pushes error code)
ISR_NO_ERR(31) // Reserved
// IRQs and user-defined interrupts (32-255)
ISR_NO_ERR(32) ISR_NO_ERR(33) ISR_NO_ERR(34) ISR_NO_ERR(35)
ISR_NO_ERR(36) ISR_NO_ERR(37) ISR_NO_ERR(38) ISR_NO_ERR(39)
ISR_NO_ERR(40) ISR_NO_ERR(41) ISR_NO_ERR(42) ISR_NO_ERR(43)
ISR_NO_ERR(44) ISR_NO_ERR(45) ISR_NO_ERR(46) ISR_NO_ERR(47)
ISR_NO_ERR(48) ISR_NO_ERR(49) ISR_NO_ERR(50) ISR_NO_ERR(51)
ISR_NO_ERR(52) ISR_NO_ERR(53) ISR_NO_ERR(54) ISR_NO_ERR(55)
ISR_NO_ERR(56) ISR_NO_ERR(57) ISR_NO_ERR(58) ISR_NO_ERR(59)
ISR_NO_ERR(60) ISR_NO_ERR(61) ISR_NO_ERR(62) ISR_NO_ERR(63)
ISR_NO_ERR(64) ISR_NO_ERR(65) ISR_NO_ERR(66) ISR_NO_ERR(67)
ISR_NO_ERR(68) ISR_NO_ERR(69) ISR_NO_ERR(70) ISR_NO_ERR(71)
ISR_NO_ERR(72) ISR_NO_ERR(73) ISR_NO_ERR(74) ISR_NO_ERR(75)
ISR_NO_ERR(76) ISR_NO_ERR(77) ISR_NO_ERR(78) ISR_NO_ERR(79)
ISR_NO_ERR(80) ISR_NO_ERR(81) ISR_NO_ERR(82) ISR_NO_ERR(83)
ISR_NO_ERR(84) ISR_NO_ERR(85) ISR_NO_ERR(86) ISR_NO_ERR(87)
ISR_NO_ERR(88) ISR_NO_ERR(89) ISR_NO_ERR(90) ISR_NO_ERR(91)
ISR_NO_ERR(92) ISR_NO_ERR(93) ISR_NO_ERR(94) ISR_NO_ERR(95)
ISR_NO_ERR(96) ISR_NO_ERR(97) ISR_NO_ERR(98) ISR_NO_ERR(99)
ISR_NO_ERR(100) ISR_NO_ERR(101) ISR_NO_ERR(102) ISR_NO_ERR(103)
ISR_NO_ERR(104) ISR_NO_ERR(105) ISR_NO_ERR(106) ISR_NO_ERR(107)
ISR_NO_ERR(108) ISR_NO_ERR(109) ISR_NO_ERR(110) ISR_NO_ERR(111)
ISR_NO_ERR(112) ISR_NO_ERR(113) ISR_NO_ERR(114) ISR_NO_ERR(115)
ISR_NO_ERR(116) ISR_NO_ERR(117) ISR_NO_ERR(118) ISR_NO_ERR(119)
ISR_NO_ERR(120) ISR_NO_ERR(121) ISR_NO_ERR(122) ISR_NO_ERR(123)
ISR_NO_ERR(124) ISR_NO_ERR(125) ISR_NO_ERR(126) ISR_NO_ERR(127)
ISR_NO_ERR(128) ISR_NO_ERR(129) ISR_NO_ERR(130) ISR_NO_ERR(131)
ISR_NO_ERR(132) ISR_NO_ERR(133) ISR_NO_ERR(134) ISR_NO_ERR(135)
ISR_NO_ERR(136) ISR_NO_ERR(137) ISR_NO_ERR(138) ISR_NO_ERR(139)
ISR_NO_ERR(140) ISR_NO_ERR(141) ISR_NO_ERR(142) ISR_NO_ERR(143)
ISR_NO_ERR(144) ISR_NO_ERR(145) ISR_NO_ERR(146) ISR_NO_ERR(147)
ISR_NO_ERR(148) ISR_NO_ERR(149) ISR_NO_ERR(150) ISR_NO_ERR(151)
ISR_NO_ERR(152) ISR_NO_ERR(153) ISR_NO_ERR(154) ISR_NO_ERR(155)
ISR_NO_ERR(156) ISR_NO_ERR(157) ISR_NO_ERR(158) ISR_NO_ERR(159)
ISR_NO_ERR(160) ISR_NO_ERR(161) ISR_NO_ERR(162) ISR_NO_ERR(163)
ISR_NO_ERR(164) ISR_NO_ERR(165) ISR_NO_ERR(166) ISR_NO_ERR(167)
ISR_NO_ERR(168) ISR_NO_ERR(169) ISR_NO_ERR(170) ISR_NO_ERR(171)
ISR_NO_ERR(172) ISR_NO_ERR(173) ISR_NO_ERR(174) ISR_NO_ERR(175)
ISR_NO_ERR(176) ISR_NO_ERR(177) ISR_NO_ERR(178) ISR_NO_ERR(179)
ISR_NO_ERR(180) ISR_NO_ERR(181) ISR_NO_ERR(182) ISR_NO_ERR(183)
ISR_NO_ERR(184) ISR_NO_ERR(185) ISR_NO_ERR(186) ISR_NO_ERR(187)
ISR_NO_ERR(188) ISR_NO_ERR(189) ISR_NO_ERR(190) ISR_NO_ERR(191)
ISR_NO_ERR(192) ISR_NO_ERR(193) ISR_NO_ERR(194) ISR_NO_ERR(195)
ISR_NO_ERR(196) ISR_NO_ERR(197) ISR_NO_ERR(198) ISR_NO_ERR(199)
ISR_NO_ERR(200) ISR_NO_ERR(201) ISR_NO_ERR(202) ISR_NO_ERR(203)
ISR_NO_ERR(204) ISR_NO_ERR(205) ISR_NO_ERR(206) ISR_NO_ERR(207)
ISR_NO_ERR(208) ISR_NO_ERR(209) ISR_NO_ERR(210) ISR_NO_ERR(211)
ISR_NO_ERR(212) ISR_NO_ERR(213) ISR_NO_ERR(214) ISR_NO_ERR(215)
ISR_NO_ERR(216) ISR_NO_ERR(217) ISR_NO_ERR(218) ISR_NO_ERR(219)
ISR_NO_ERR(220) ISR_NO_ERR(221) ISR_NO_ERR(222) ISR_NO_ERR(223)
ISR_NO_ERR(224) ISR_NO_ERR(225) ISR_NO_ERR(226) ISR_NO_ERR(227)
ISR_NO_ERR(228) ISR_NO_ERR(229) ISR_NO_ERR(230) ISR_NO_ERR(231)
ISR_NO_ERR(232) ISR_NO_ERR(233) ISR_NO_ERR(234) ISR_NO_ERR(235)
ISR_NO_ERR(236) ISR_NO_ERR(237) ISR_NO_ERR(238) ISR_NO_ERR(239)
ISR_NO_ERR(240) ISR_NO_ERR(241) ISR_NO_ERR(242) ISR_NO_ERR(243)
ISR_NO_ERR(244) ISR_NO_ERR(245) ISR_NO_ERR(246) ISR_NO_ERR(247)
ISR_NO_ERR(248) ISR_NO_ERR(249) ISR_NO_ERR(250) ISR_NO_ERR(251)
ISR_NO_ERR(252) ISR_NO_ERR(253) ISR_NO_ERR(254) ISR_NO_ERR(255)
// Array of all ISR handlers for easy initialization
void* isr_table[256] = {
isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7,
isr8, isr9, isr10, isr11, isr12, isr13, isr14, isr15,
isr16, isr17, isr18, isr19, isr20, isr21, isr22, isr23,
isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31,
isr32, isr33, isr34, isr35, isr36, isr37, isr38, isr39,
isr40, isr41, isr42, isr43, isr44, isr45, isr46, isr47,
isr48, isr49, isr50, isr51, isr52, isr53, isr54, isr55,
isr56, isr57, isr58, isr59, isr60, isr61, isr62, isr63,
isr64, isr65, isr66, isr67, isr68, isr69, isr70, isr71,
isr72, isr73, isr74, isr75, isr76, isr77, isr78, isr79,
isr80, isr81, isr82, isr83, isr84, isr85, isr86, isr87,
isr88, isr89, isr90, isr91, isr92, isr93, isr94, isr95,
isr96, isr97, isr98, isr99, isr100, isr101, isr102, isr103,
isr104, isr105, isr106, isr107, isr108, isr109, isr110, isr111,
isr112, isr113, isr114, isr115, isr116, isr117, isr118, isr119,
isr120, isr121, isr122, isr123, isr124, isr125, isr126, isr127,
isr128, isr129, isr130, isr131, isr132, isr133, isr134, isr135,
isr136, isr137, isr138, isr139, isr140, isr141, isr142, isr143,
isr144, isr145, isr146, isr147, isr148, isr149, isr150, isr151,
isr152, isr153, isr154, isr155, isr156, isr157, isr158, isr159,
isr160, isr161, isr162, isr163, isr164, isr165, isr166, isr167,
isr168, isr169, isr170, isr171, isr172, isr173, isr174, isr175,
isr176, isr177, isr178, isr179, isr180, isr181, isr182, isr183,
isr184, isr185, isr186, isr187, isr188, isr189, isr190, isr191,
isr192, isr193, isr194, isr195, isr196, isr197, isr198, isr199,
isr200, isr201, isr202, isr203, isr204, isr205, isr206, isr207,
isr208, isr209, isr210, isr211, isr212, isr213, isr214, isr215,
isr216, isr217, isr218, isr219, isr220, isr221, isr222, isr223,
isr224, isr225, isr226, isr227, isr228, isr229, isr230, isr231,
isr232, isr233, isr234, isr235, isr236, isr237, isr238, isr239,
isr240, isr241, isr242, isr243, isr244, isr245, isr246, isr247,
isr248, isr249, isr250, isr251, isr252, isr253, isr254, isr255,
};
// Initialize all IDT entries
void init_idt(void) {
for (int i = 0; i < 256; i++) {
set_idt(i, isr_table[i], 0);
}
load_idt(idt);
}

119
src/main.c Normal file
View File

@ -0,0 +1,119 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "../include/limine.h"
// credit owed to https://wiki.osdev.org/Limine_Bare_Bones
__attribute__((used, section(".limine_requests")))
static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(4);
__attribute__((used, section(".limine_requests")))
static volatile struct limine_framebuffer_request fb_req = {
.id = LIMINE_FRAMEBUFFER_REQUEST_ID,
.revision = 0
};
__attribute__((used, section(".limine_requests_start")))
static volatile uint64_t limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".limine_requests_end")))
static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER;
void* memcpy(void* restrict dst, const void* src, size_t n) {
uint8_t* restrict pdst = (uint8_t* restrict)dst;
const uint8_t* restrict psrc = (const uint8_t* restrict)src;
for(size_t i = 0; i < n; i++) {
pdst[i] = psrc[i];
}
return dst;
}
void* memset(void* s, int c, size_t n) {
uint8_t* p = (uint8_t*) s;
for(size_t i = 0; i < n; i++) {
p[i] = (uint8_t)c;
}
return s;
}
void* memmove(void* dst, const void* src, size_t n) {
uint8_t* restrict pdst = (uint8_t* restrict)dst;
const uint8_t* restrict psrc = (const uint8_t* restrict)src;
if(src > dst) {
for(size_t i = 0; i < n; i++) {
pdst[i] = psrc[i];
}
} else if(src < dst) {
for(size_t i = n; i > 0; i--) {
pdst[i-1] = psrc[i-1];
}
}
return dst;
}
int memcmp(const void* s1, const void* s2, size_t n) {
const uint8_t* p1 = (const uint8_t* )s1;
const uint8_t* p2 = (const uint8_t* )s2;
for(size_t i = 0; i < n; i++) {
if(p1[i] != p2[i]) {
return p1[i] < p2[i] ? -1 : 1;
}
}
return 0;
}
static void hang() {
for(;;) {
asm ("hlt");
}
}
struct limine_framebuffer* fb;
void draw(uint8_t vect) {
for(size_t y = 0; y < fb->height; y++) {
for(size_t x = 0; x < fb->width; x++) {
volatile uint32_t* fb_ptr = fb->address;
fb_ptr[y * fb->width + x] = (
(x + y) * 0x00010000 |
(x ^ y) * 0x00000100 |
(x - y) * 0x00000001
)*vect;
}
}
}
extern void init_idt(void);
void kmain() {
if(LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
hang();
}
if(fb_req.response == NULL || fb_req.response->framebuffer_count < 1) {
hang();
}
fb = fb_req.response->framebuffers[0];
init_idt();
for(size_t i = 0; ~i & (1<<30); i++) {
draw(i&0xFF);
}
hang();
}