commit 0d436e52553b67597feaa79ea4e32ea3d12ea2e9 Author: Hopeless Tyromancy Date: Mon Feb 2 19:51:54 2026 -0500 initial state Currently limine based, cribbing from osdev wiki a bit, and from dreamportdev diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a6494ce --- /dev/null +++ b/Makefile @@ -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 diff --git a/bin/os b/bin/os new file mode 100755 index 0000000..f89cea2 Binary files /dev/null and b/bin/os differ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..48701bd --- /dev/null +++ b/flake.lock @@ -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 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..93b0572 --- /dev/null +++ b/flake.nix @@ -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 + ]; + }; + }; +} diff --git a/image.hdd b/image.hdd new file mode 100644 index 0000000..6a15664 Binary files /dev/null and b/image.hdd differ diff --git a/include/limine.h b/include/limine.h new file mode 100644 index 0000000..6b87d73 --- /dev/null +++ b/include/limine.h @@ -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 + +#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 + diff --git a/limine b/limine new file mode 160000 index 0000000..7a6892a --- /dev/null +++ b/limine @@ -0,0 +1 @@ +Subproject commit 7a6892a36f1fb6dbdd6e6f6d00b8062d5bcb813b diff --git a/limine.conf b/limine.conf new file mode 100644 index 0000000..ec26b22 --- /dev/null +++ b/limine.conf @@ -0,0 +1,5 @@ +timeout: 5 + +/LispOS + protocol: limine + path: boot():/boot/os diff --git a/limine.sh b/limine.sh new file mode 100644 index 0000000..3172b31 --- /dev/null +++ b/limine.sh @@ -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 diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..f802a81 --- /dev/null +++ b/linker.ld @@ -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.*) + } +} + diff --git a/obj/src/int.c.d b/obj/src/int.c.d new file mode 100644 index 0000000..29e5732 --- /dev/null +++ b/obj/src/int.c.d @@ -0,0 +1 @@ +obj/src/int.c.o: src/int.c diff --git a/obj/src/int.c.o b/obj/src/int.c.o new file mode 100644 index 0000000..90a1722 Binary files /dev/null and b/obj/src/int.c.o differ diff --git a/obj/src/main.c.d b/obj/src/main.c.d new file mode 100644 index 0000000..008772b --- /dev/null +++ b/obj/src/main.c.d @@ -0,0 +1,2 @@ +obj/src/main.c.o: src/main.c src/../include/limine.h +src/../include/limine.h: diff --git a/obj/src/main.c.o b/obj/src/main.c.o new file mode 100644 index 0000000..fd9ee5f Binary files /dev/null and b/obj/src/main.c.o differ diff --git a/src/int.c b/src/int.c new file mode 100644 index 0000000..c9a249c --- /dev/null +++ b/src/int.c @@ -0,0 +1,271 @@ +#include + +#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); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..2e75e1b --- /dev/null +++ b/src/main.c @@ -0,0 +1,119 @@ +#include +#include +#include +#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(); + +} +