From 92d8a91be4d6f87dc8225b5043fbfe1d68d74412 Mon Sep 17 00:00:00 2001 From: Katharina Heidenreich Date: Fri, 26 Jun 2026 21:17:31 +0200 Subject: [PATCH] feat: initial --- .gitignore | 4 + kernel/.gitignore | 3 + kernel/Makefile | 36 ++++ kernel/include/init/init.h | 3 + kernel/include/init/multiboot2.h | 303 +++++++++++++++++++++++++++++++ kernel/include/init/print.h | 38 ++++ kernel/include/memory/pointer.h | 39 ++++ kernel/include/memory/sections.h | 19 ++ kernel/include/util/function.h | 9 + kernel/include/util/number.h | 6 + kernel/iso/boot/grub/grub.cfg | 7 + kernel/linker.ld | 89 +++++++++ kernel/src/init/init.cpp | 51 ++++++ kernel/src/init/print.cpp | 80 ++++++++ kernel/src/init/sections.cpp | 28 +++ kernel/src/startup/entry.cpp | 227 +++++++++++++++++++++++ kernel/src/startup/multiboot.cpp | 16 ++ run.sh | 16 ++ testenv/.gitignore | 3 + testenv/qemuConfig.cfg | 81 +++++++++ 20 files changed, 1058 insertions(+) create mode 100644 .gitignore create mode 100644 kernel/.gitignore create mode 100644 kernel/Makefile create mode 100644 kernel/include/init/init.h create mode 100644 kernel/include/init/multiboot2.h create mode 100644 kernel/include/init/print.h create mode 100644 kernel/include/memory/pointer.h create mode 100644 kernel/include/memory/sections.h create mode 100644 kernel/include/util/function.h create mode 100644 kernel/include/util/number.h create mode 100644 kernel/iso/boot/grub/grub.cfg create mode 100644 kernel/linker.ld create mode 100644 kernel/src/init/init.cpp create mode 100644 kernel/src/init/print.cpp create mode 100644 kernel/src/init/sections.cpp create mode 100644 kernel/src/startup/entry.cpp create mode 100644 kernel/src/startup/multiboot.cpp create mode 100755 run.sh create mode 100644 testenv/.gitignore create mode 100644 testenv/qemuConfig.cfg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d373a4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.claude +.vscode +compile_commands.json +CLAUDE.md \ No newline at end of file diff --git a/kernel/.gitignore b/kernel/.gitignore new file mode 100644 index 0000000..c4b47e3 --- /dev/null +++ b/kernel/.gitignore @@ -0,0 +1,3 @@ +build/ +output/ +iso/boot/kernel.bin diff --git a/kernel/Makefile b/kernel/Makefile new file mode 100644 index 0000000..b2f612d --- /dev/null +++ b/kernel/Makefile @@ -0,0 +1,36 @@ +root_dir := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +source_dir := $(root_dir)/src +object_dir := $(root_dir)/build +linker_script := $(root_dir)/linker.ld +output_dir := $(root_dir)/output + +LD := ld +CXX := clang++ +CXXFLAGS := -std=c++20 -fpie -fno-strict-aliasing -fno-stack-protector -fno-asynchronous-unwind-tables -fno-exceptions -fno-rtti -fno-common -mno-red-zone -mgeneral-regs-only -ffreestanding -Og -g -Wall -Wextra -Wno-reserved-identifier -I$(root_dir)/include + +source_files := $(shell find $(source_dir) -type f -name "*.cpp") +object_files := $(patsubst $(source_dir)/%,$(object_dir)/%.o,$(source_files)) + +$(object_files): $(object_dir)%.o : $(source_dir)% + @mkdir -p $(dir $@) + @echo "Compiling $<" + @$(CXX) $(CXXFLAGS) -c $< -o $@ + +kernel.bin: $(object_files) + @mkdir -p $(output_dir) + @echo "Linking kernel" + @$(LD) --build-id=none --no-relax -nostdlib -o $(output_dir)/kernel.bin -T $(linker_script) $(object_files) + @echo "Disassembling kernel" + @objdump -dC $(output_dir)/kernel.bin > $(output_dir)/kernel.asm + @objdump -DC $(output_dir)/kernel.bin > $(output_dir)/kernel_full.asm + + +iso: kernel.bin + @echo "Creating ISO" + @cp $(output_dir)/kernel.bin $(root_dir)/iso/boot/kernel.bin + @grub-mkrescue -d /usr/lib/grub/i386-pc -o $(output_dir)/kernel.iso iso + +all: kernel.bin iso + +clean: + @rm -rf $(object_dir) $(output_dir) iso/boot/kernel.bin \ No newline at end of file diff --git a/kernel/include/init/init.h b/kernel/include/init/init.h new file mode 100644 index 0000000..7ad7c4d --- /dev/null +++ b/kernel/include/init/init.h @@ -0,0 +1,3 @@ +#pragma once + +[[maybe_unused]] [[noreturn]] __attribute__((used)) void init(); \ No newline at end of file diff --git a/kernel/include/init/multiboot2.h b/kernel/include/init/multiboot2.h new file mode 100644 index 0000000..ccb0744 --- /dev/null +++ b/kernel/include/init/multiboot2.h @@ -0,0 +1,303 @@ +#pragma once + +#include "util/number.h" +#include "util/function.h" +#include "memory/pointer.h" + +namespace multiboot { + +inline constexpr uint32_t magic = 0x36d76289; +inline constexpr uint32_t alignment = 8; + +enum class tag_type : uint32_t { + end = 0, + cmdline = 1, + boot_loader_name = 2, + module = 3, + basic_meminfo = 4, + bootdev = 5, + mmap = 6, + vbe = 7, + framebuffer = 8, + elf_sections = 9, + apm = 10, + efi32 = 14, + efi64 = 15, + smbios = 16, + acpi_old = 17, + acpi_new = 18, + network = 19, + efi_mmap = 20, + efi_bs = 21, + efi32_ih = 22, + efi64_ih = 23, + load_base_addr = 24, +}; + +enum class framebuffer_type : uint8_t { + indexed = 0, + rgb = 1, + ega_text = 2, +}; + +enum class mem_type : uint32_t { + available = 1, + reserved = 2, + acpi_reclaimable = 3, + nvs = 4, + badram = 5, +}; + +struct color { + uint8_t red; + uint8_t green; + uint8_t blue; +}; + +struct mem_entry { + uint64_t addr; + uint64_t len; + mem_type type; + uint32_t zero; +}; + +struct tag { + tag_type type; + uint32_t size; +}; + +struct tag_string { + tag_type type; + uint32_t size; + char string[0]; +}; + +struct tag_module { + tag_type type; + uint32_t size; + uint32_t mod_start; + uint32_t mod_end; + char cmdline[0]; +}; + +struct tag_basic_meminfo { + tag_type type; + uint32_t size; + uint32_t mem_lower; + uint32_t mem_upper; +}; + +struct tag_bootdev { + tag_type type; + uint32_t size; + uint32_t biosdev; + uint32_t slice; + uint32_t part; +}; + +struct tag_mmap { + tag_type type; + uint32_t size; + uint32_t entry_size; + uint32_t entry_version; + mem_entry entries[0]; +}; + +struct vbe_info_block { + uint8_t external_specification[512]; +}; + +struct vbe_mode_info_block { + uint8_t external_specification[256]; +}; + +struct tag_vbe { + tag_type type; + uint32_t size; + uint16_t vbe_mode; + uint16_t vbe_interface_seg; + uint16_t vbe_interface_off; + uint16_t vbe_interface_len; + vbe_info_block vbe_control_info; + vbe_mode_info_block vbe_mode_info; +}; + + +struct tag_framebuffer { + tag_type type; + uint32_t size; + uint64_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + framebuffer_type framebuffer_type; + uint16_t reserved; + + union { + struct { + uint16_t framebuffer_palette_num_colors; + color framebuffer_palette[0]; + }; + struct { + uint8_t framebuffer_red_field_position; + uint8_t framebuffer_red_mask_size; + uint8_t framebuffer_green_field_position; + uint8_t framebuffer_green_mask_size; + uint8_t framebuffer_blue_field_position; + uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +struct tag_elf_sections { + tag_type type; + uint32_t size; + uint32_t num; + uint32_t entsize; + uint32_t shndx; + char sections[0]; +}; + +struct tag_apm { + tag_type type; + uint32_t size; + uint16_t version; + uint16_t cseg; + uint32_t offset; + uint16_t cseg_16; + uint16_t dseg; + uint16_t flags; + uint16_t cseg_len; + uint16_t cseg_16_len; + uint16_t dseg_len; +}; + +struct tag_efi32 { + tag_type type; + uint32_t size; + uint32_t pointer; +}; + +struct tag_efi64 { + tag_type type; + uint32_t size; + uint64_t pointer; +}; + +struct tag_smbios { + tag_type type; + uint32_t size; + uint8_t major; + uint8_t minor; + uint8_t reserved[6]; + uint8_t tables[0]; +}; + +struct tag_old_acpi { + tag_type type; + uint32_t size; + uint8_t rsdp[0]; +}; + +struct tag_new_acpi { + tag_type type; + uint32_t size; + uint8_t rsdp[0]; +}; + +struct tag_network { + tag_type type; + uint32_t size; + uint8_t dhcpack[0]; +}; + +struct tag_efi_mmap { + tag_type type; + uint32_t size; + uint32_t descr_size; + uint32_t descr_vers; + uint8_t efi_mmap[0]; +}; + +struct tag_efi32_ih { + tag_type type; + uint32_t size; + uint32_t pointer; +}; + +struct tag_efi64_ih { + tag_type type; + uint32_t size; + uint64_t pointer; +}; + +struct tag_load_base_addr { + tag_type type; + uint32_t size; + uint32_t load_base_addr; +}; + +struct info { + uint32_t total_size; + uint32_t reserved; +}; + +inline info* get_multiboot_info() { + auto addr = read_symbol("__multiboot_info"); + uint32_t phys = *paddr_t{addr}.access(); + return paddr_t{phys}.access(); +} + +template +void visit(const tag* t, Fn&& fn) { +#define MB_DISPATCH(tag_enum, TagType) \ + case tag_type::tag_enum: \ + if constexpr (requires { fn(static_cast(nullptr)); }) \ + fn(reinterpret_cast(t)); \ + break; + + switch (t->type) { + MB_DISPATCH(cmdline, tag_string) + MB_DISPATCH(boot_loader_name, tag_string) + MB_DISPATCH(module, tag_module) + MB_DISPATCH(basic_meminfo, tag_basic_meminfo) + MB_DISPATCH(bootdev, tag_bootdev) + MB_DISPATCH(mmap, tag_mmap) + MB_DISPATCH(vbe, tag_vbe) + MB_DISPATCH(framebuffer, tag_framebuffer) + MB_DISPATCH(elf_sections, tag_elf_sections) + MB_DISPATCH(apm, tag_apm) + MB_DISPATCH(efi32, tag_efi32) + MB_DISPATCH(efi64, tag_efi64) + MB_DISPATCH(smbios, tag_smbios) + MB_DISPATCH(acpi_old, tag_old_acpi) + MB_DISPATCH(acpi_new, tag_new_acpi) + MB_DISPATCH(network, tag_network) + MB_DISPATCH(efi_mmap, tag_efi_mmap) + MB_DISPATCH(efi32_ih, tag_efi32_ih) + MB_DISPATCH(efi64_ih, tag_efi64_ih) + MB_DISPATCH(load_base_addr, tag_load_base_addr) + default: break; + } + +#undef MB_DISPATCH +} + +template +void visit_all(const info* mb, Fn&& fn) { + auto ptr = reinterpret_cast(mb) + sizeof(info); + const auto end = reinterpret_cast(mb) + mb->total_size; + while (ptr < end) { + auto t = reinterpret_cast(ptr); + if (t->type == tag_type::end) break; + visit(t, fn); + ptr += (t->size + alignment - 1) & ~(alignment - 1); + } +} + +template +void visit_all(Fn&& fn) { + visit_all(get_multiboot_info(), fn); +} +} // namespace multiboot diff --git a/kernel/include/init/print.h b/kernel/include/init/print.h new file mode 100644 index 0000000..ee5fc81 --- /dev/null +++ b/kernel/include/init/print.h @@ -0,0 +1,38 @@ +#pragma once +#include + +enum class Color : uint8_t { + Black = 0, + Blue = 1, + Green = 2, + Cyan = 3, + Red = 4, + Magenta = 5, + Brown = 6, + LightGray = 7, + DarkGray = 8, + LightBlue = 9, + LightGreen = 10, + LightCyan = 11, + LightRed = 12, + LightMagenta = 13, + Yellow = 14, + White = 15, +}; + +struct TextAttr { + Color fg; + Color bg; + + constexpr TextAttr(Color fg = Color::White, Color bg = Color::Black) : fg(fg), bg(bg) {} + + // Returns the attribute in the high byte, ready to OR with a character value. + constexpr uint16_t word() const { + return (uint16_t)(((uint8_t)bg << 4) | (uint8_t)fg) << 8; + } +}; + +void clear(); +void print(const char* str, TextAttr attr = {}); +void print_dec(uint64_t value, TextAttr attr = {}); +void print_hex(uint64_t value, TextAttr attr = {}); diff --git a/kernel/include/memory/pointer.h b/kernel/include/memory/pointer.h new file mode 100644 index 0000000..82fab09 --- /dev/null +++ b/kernel/include/memory/pointer.h @@ -0,0 +1,39 @@ +#pragma once + +#include "util/number.h" + +constexpr uint64_t high_base = 0xFFFF800000000000; + +#define read_symbol(symbol) [](){uint64_t res; asm volatile("movabsq $" symbol ", %0": "=r"(res)); return res;}() + +struct paddr_t { +uint64_t address; + +template +T* access() { + return reinterpret_cast(address+high_base); +} + +}; + +inline void* operator new(size_t, void* p) { + return p; +} + +inline void* operator new[](size_t, void* p) { + return p; +} + +inline void* memcpy(void* dest, const void* src, size_t n) { + for (size_t i = 0; i < n; i++) { + ((uint8_t*) dest)[i] = ((uint8_t*) src)[i]; + } + return dest; +} + +inline void* memset(void* dest, int c, size_t n) { + for (size_t i = 0; i < n; i++) { + ((uint8_t*) dest)[i] = (uint8_t) c; + } + return dest; +} diff --git a/kernel/include/memory/sections.h b/kernel/include/memory/sections.h new file mode 100644 index 0000000..8071bf8 --- /dev/null +++ b/kernel/include/memory/sections.h @@ -0,0 +1,19 @@ +#pragma once +#include "memory/pointer.h" + +struct KernelSection { + uint64_t vma_start; + uint64_t vma_end; + const char* name; + + paddr_t phys_start() const { return paddr_t{vma_start >= high_base ? vma_start - high_base : vma_start}; } + paddr_t phys_end() const { return paddr_t{vma_end >= high_base ? vma_end - high_base : vma_end}; } +}; + +extern KernelSection __reserved_ranges_start__[], __reserved_ranges_end__[]; + +template +void for_each_reserved_section(Fn&& fn) { + for (auto* s = __reserved_ranges_start__; s < __reserved_ranges_end__; ++s) + fn(*s); +} diff --git a/kernel/include/util/function.h b/kernel/include/util/function.h new file mode 100644 index 0000000..2b5ae0b --- /dev/null +++ b/kernel/include/util/function.h @@ -0,0 +1,9 @@ +#pragma once + +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +template +overloaded(Ts...) -> overloaded; diff --git a/kernel/include/util/number.h b/kernel/include/util/number.h new file mode 100644 index 0000000..3751f41 --- /dev/null +++ b/kernel/include/util/number.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +using size_t = uint64_t; +using ssize_t = int64_t; \ No newline at end of file diff --git a/kernel/iso/boot/grub/grub.cfg b/kernel/iso/boot/grub/grub.cfg new file mode 100644 index 0000000..74987d3 --- /dev/null +++ b/kernel/iso/boot/grub/grub.cfg @@ -0,0 +1,7 @@ +set timeout=0 +set default=0 + +menuentry "PrOSess" { + multiboot2 /boot/kernel.bin + boot +} diff --git a/kernel/linker.ld b/kernel/linker.ld new file mode 100644 index 0000000..36995be --- /dev/null +++ b/kernel/linker.ld @@ -0,0 +1,89 @@ + +ENTRY(__start) + +MEMORY +{ + MULTIBOOT_HEADER_PV : ORIGIN = 16k, LENGTH = 4k + TRAMPOLINE_PV : ORIGIN = 0x0, LENGTH = 16k + START_MEMORY_PV : ORIGIN = 20k, LENGTH = 44k + + KERNEL_MEMORY_P : ORIGIN = 64k, LENGTH = (1024M - ORIGIN(KERNEL_MEMORY_P)) + + HIGH_KERNEL_V : ORIGIN = 0xFFFF800000000000 + 64k, LENGTH = LENGTH(KERNEL_MEMORY_P) +} + +SECTIONS +{ + .boot : { + __boot_start__ = .; + KEEP(*(.multiboot_header)) + __boot_end__ = .; + } > MULTIBOOT_HEADER_PV + .startup_text : { + __startup_text_start__ = .; + *(.startup_text) + __startup_text_end__ = .; + } > START_MEMORY_PV + .startup_data : { + __startup_data_start__ = .; + KEEP(*(.startup_data)) + __startup_data_end__ = .; + } > START_MEMORY_PV + .text : { + __text_start__ = .; + *(EXCLUDE_FILE(*trampoline*) .text) + __text_end__ = .; + } > HIGH_KERNEL_V AT > KERNEL_MEMORY_P + .rodata : { + __rodata_start__ = .; + *(EXCLUDE_FILE(*trampoline*) .rodata) + __rodata_end__ = .; + } > HIGH_KERNEL_V AT > KERNEL_MEMORY_P + .data : { + __data_start__ = .; + *(EXCLUDE_FILE(*trampoline*) .data) + __data_end__ = .; + } > HIGH_KERNEL_V AT > KERNEL_MEMORY_P + .bss : { + __bss_start__ = .; + *(EXCLUDE_FILE(*trampoline*) .bss) + __bss_end__ = .; + } > HIGH_KERNEL_V AT > KERNEL_MEMORY_P + .reserved_ranges : { + __reserved_ranges_start__ = .; + KEEP(*(.reserved_ranges)) + __reserved_ranges_end__ = .; + } > HIGH_KERNEL_V AT > KERNEL_MEMORY_P + + .trampoline_text : { + __trampoline_text_start__ = .; + *trampoline*(.text) + __trampoline_text_end__ = .; + } > TRAMPOLINE_PV + + .trampoline_data : { + __trampoline_data_start__ = .; + *trampoline*(.data) + __trampoline_data_end__ = .; + } > TRAMPOLINE_PV + + .trampoline_bss : { + __trampoline_bss_start__ = .; + *trampoline*(.bss) + __trampoline_bss_end__ = .; + } > TRAMPOLINE_PV + + .trampoline_rodata : { + __trampoline_rodata_start__ = .; + *trampoline*(.rodata) + __trampoline_rodata_end__ = .; + } > TRAMPOLINE_PV + + /DISCARD/ : { + *(.comment) + *(.eh_frame) + *(.note) + *(.note.gnu.build-id) + } +} + diff --git a/kernel/src/init/init.cpp b/kernel/src/init/init.cpp new file mode 100644 index 0000000..971980e --- /dev/null +++ b/kernel/src/init/init.cpp @@ -0,0 +1,51 @@ +#include "memory/pointer.h" +#include "memory/sections.h" +#include "init/init.h" +#include "init/multiboot2.h" +#include "init/print.h" + +[[maybe_unused]] [[noreturn]] __attribute__((used)) static void halt() { + while (true) __asm__ volatile (""); +} + +[[maybe_unused]] [[noreturn]] __attribute__((used)) static void panic(const char* msg) { + print(msg, TextAttr{Color::Red, Color::Black}); + halt(); +} + +template +static void step(const char* name, T&& fn) { + print("Starting ", {}); + print(name, {}); + print("\n", {}); + fn(); + print("Finished ", {}); + print(name, {}); + print("\n", {}); +} + +static void loadMultiboot() { + multiboot::visit_all(overloaded{ + [](const multiboot::tag_mmap* mem) { + print("Tag Memory\n", {}); + }, + [](const multiboot::tag_string* str) { + print("Tag String (0x", {}); + print_hex(static_cast(str->type), {}); + print("): ", {}); + print(str->string, {}); + print("\n", {}); + }, + [](const auto* tag) { + print("Tag (0x", {}); + print_hex(static_cast(tag->type), {}); + print(")\n", {}); + } + }); +} + +[[maybe_unused]] [[noreturn]] __attribute__((used)) void init() { + print("Reached init\n", {}); + //step("multiboot", loadMultiboot); + halt(); +} diff --git a/kernel/src/init/print.cpp b/kernel/src/init/print.cpp new file mode 100644 index 0000000..62d2b3b --- /dev/null +++ b/kernel/src/init/print.cpp @@ -0,0 +1,80 @@ +#include "init/print.h" +#include "memory/pointer.h" + +static constexpr uint64_t VGA_PHYS_BASE = 0xb8000; +static constexpr int VGA_COLS = 80; +static constexpr int VGA_ROWS = 25; +static constexpr int BYTES_PER_CELL = 2; +static constexpr int BYTES_PER_ROW = VGA_COLS * BYTES_PER_CELL; +static constexpr int HEX_BITS = 4; +static constexpr int HEX_TOP_SHIFT = (sizeof(uint64_t) * 8) - HEX_BITS; + +static const char hex_chars[] = "0123456789ABCDEF"; + +static volatile uint32_t* cursor() { + auto cursor_addr = read_symbol("__cursor"); + return paddr_t{cursor_addr}.access(); +} + +static volatile uint16_t* vga_cell(uint32_t offset) { + return paddr_t{VGA_PHYS_BASE + offset}.access(); +} + +static void next_line() { + *cursor() = ((*cursor() + BYTES_PER_ROW - 1) / BYTES_PER_ROW) * BYTES_PER_ROW; +} + +static void put_char(char ch, uint16_t attr_word) { + if (ch == '\n') { + next_line(); + return; + } + *vga_cell(*cursor()) = attr_word | (uint8_t)ch; + *cursor() += BYTES_PER_CELL; +} + +void clear() { + *cursor() = 0; + for (int i = 0; i < VGA_COLS * VGA_ROWS; i++) { + *vga_cell(i * BYTES_PER_CELL) = 0; + } +} + +void print(const char* str, TextAttr attr) { + uint16_t w = attr.word(); + while (*str) { + put_char(*str++, w); + } +} + +void print_dec(uint64_t value, TextAttr attr) { + uint16_t w = attr.word(); + if (value == 0) { + put_char('0', w); + return; + } + char buf[20]; + int len = 0; + while (value > 0) { + buf[len++] = '0' + (value % 10); + value /= 10; + } + for (int i = len - 1; i >= 0; i--) { + put_char(buf[i], w); + } +} + +void print_hex(uint64_t value, TextAttr attr) { + uint16_t w = attr.word(); + put_char('0', w); + put_char('x', w); + bool leading = true; + for (int shift = HEX_TOP_SHIFT; shift >= 0; shift -= HEX_BITS) { + uint8_t nibble = (value >> shift) & 0xF; + if (leading && nibble == 0 && shift > 0) { + continue; + } + leading = false; + put_char(hex_chars[nibble], w); + } +} diff --git a/kernel/src/init/sections.cpp b/kernel/src/init/sections.cpp new file mode 100644 index 0000000..c68fdee --- /dev/null +++ b/kernel/src/init/sections.cpp @@ -0,0 +1,28 @@ +#include "memory/sections.h" + +#define RESERVE_SECTION(n) \ + extern char __##n##_start__[], __##n##_end__[]; \ + [[maybe_unused]] static const KernelSection _rsv_##n \ + __attribute__((section(".reserved_ranges"), used)) = { \ + (uint64_t)__##n##_start__, \ + (uint64_t)__##n##_end__, \ + #n \ + } + +RESERVE_SECTION(boot); +RESERVE_SECTION(startup_text); +RESERVE_SECTION(startup_data); +RESERVE_SECTION(text); +RESERVE_SECTION(rodata); +RESERVE_SECTION(data); +RESERVE_SECTION(bss); +[[maybe_unused]] static const KernelSection _rsv_reserved_ranges +__attribute__((section(".reserved_ranges"), used)) = { + (uint64_t)__reserved_ranges_start__, + (uint64_t)__reserved_ranges_end__, + "reserved_ranges" +}; +RESERVE_SECTION(trampoline_text); +RESERVE_SECTION(trampoline_data); +RESERVE_SECTION(trampoline_bss); +RESERVE_SECTION(trampoline_rodata); diff --git a/kernel/src/startup/entry.cpp b/kernel/src/startup/entry.cpp new file mode 100644 index 0000000..01a0cfe --- /dev/null +++ b/kernel/src/startup/entry.cpp @@ -0,0 +1,227 @@ +#include "init/init.h" + +extern "C" [[maybe_unused]] [[noreturn]] __attribute__((used)) void __entry64() { + init(); + while (true) __asm__ volatile (""); +} + +asm(R"( +.global __start + +.section .startup_text, "ax" +.type __start, @function +.code32 +.align 16 +__start: + cli + mov $__start_stack_end, %esp + mov %ebx, __multiboot_info + call __clear + mov $__hello_string, %esi + call __print + call __check_if_x64 + call __go_to_x64 + jmp __stop32 +__stop32: + hlt + jmp __stop32 + +__x64_not_supported: + mov $__x64_not_supported_string, %esi + call __print + jmp __stop32 + +__check_if_x64: + pushfl + pop %eax + mov %eax, %ecx + xor $(1 << 21), %eax + push %eax + popfl + pushfl + pop %eax + push %ecx + popfl + cmp %eax, %ecx + je __x64_not_supported + + mov $0x80000000, %eax + cpuid + cmp $0x80000001, %eax + jb __x64_not_supported + mov $0x80000001, %eax + cpuid + test $(1 << 29), %edx + jz __x64_not_supported + mov $__x64_supported_string, %esi + call __print + ret + +__go_to_x64: + push %ebx + mov $__page_level_4, %eax + mov %eax, %cr3 + + mov %cr4, %eax + or $(0x1 << 5), %eax + mov %eax, %cr4 + + mov $0xC0000080, %ecx + rdmsr + or $(0x1 << 8), %eax + wrmsr + + mov %cr0, %eax + or $(0x1 << 31), %eax + mov %eax, %cr0 + + pop %edi + + lgdt __gdt_end + jmp $0b1000, $__start64 + + jmp __stop32 + +.code64 +.align 16 +__start64: + mov $0b10000, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + movabsq $__start64_high, %rax + jmp* %rax +__stop64: + hlt + jmp __stop64 + +.section .text +.type __start64_high, @function +.code64 +.align 16 +__start64_high: + call __entry64 + hlt + jmp __start64_high +)"); + +// data section +asm(R"( +.global __multiboot_info +.global __cursor +.section .startup_data, "aw" +__cursor: + .int 0x0 +__hello_string: + .string "Starting PrOSess! 32bit start!\n" +__x64_not_supported_string: + .string "x64 is not supported!\n" +__x64_supported_string: + .string "x64 is supported!\n" +__multiboot_info: + .long 0x0 + +__start_stack: + .skip 0x1000 + .align 8 +__start_stack_end: + .quad 0 +)"); + +// string operation section +asm(R"( +.section .startup_text, "ax" +.code32 +.align 16 +__clear: + movl $0, (__cursor) + mov $0x0, %eax + mov $0xb8000, %edi + mov $0x2000, %ecx + rep stosw + ret + +__print: + mov $0xB8000, %edi + add (__cursor), %edi +__print_loop: + mov (%esi), %al + mov $0x0F, %ah + cmp $0, %al + je __print_end + cmp $'\n', %al + je __print_next_line + mov %ax, (%edi) + add $2, %edi + add $1, %esi + jmp __print_loop +__print_next_line: + sub $0xB8000, %edi + mov %edi, (__cursor) + add $0xB8000, %edi + call __next_line + mov $0xB8000, %edi + add (__cursor), %edi + add $1, %esi + jmp __print_loop +__print_end: + sub $0xB8000, %edi + mov %edi, (__cursor) + ret + +__next_line: + push %eax + push %ecx + mov (__cursor), %eax + + leal 159(%eax), %ecx + movl $1717986919, %eax + imull %ecx + sarl $31, %ecx + sarl $6, %edx + subl %ecx, %edx + leal (%edx,%edx,4), %eax + sall $5, %eax + + mov %eax, (__cursor) + pop %ecx + pop %eax + ret +)"); + +// tmp page table +asm(R"( +.section .startup_data, "aw" +.align 0x1000 +__page_level_4: + .quad __page_level_3_low_1gb_identity_map + ((1 << 0) | (1 << 1)) + .zero 0x7F8 + .quad __page_level_3_kernel_1gb_identity_map + ((1 << 0) | (1 << 1)) + .zero 0x7F8 + +.align 0x1000 +__page_level_3_low_1gb_identity_map: + .quad (1 << 0) | (1 << 1) | (1 << 7) | 0x0 + .zero 0xFF8 # rest of table is 0 + +.align 0x1000 +__page_level_3_kernel_1gb_identity_map: + .quad (1 << 0) | (1 << 1) | (1 << 7) | 0x0 + .zero 0xFF8 # rest of table is 0 +)"); + +// startup gdt +asm(R"( +.section .startup_data, "aw" +.align 0x1000 +__gdt: + .quad 0 + .quad (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) # code segment + .quad (1 << 41) | (1 << 44) | (1 << 47) # data segment +.align 0x1000 +__gdt_end: + .word __gdt_end - __gdt - 1 + .quad __gdt +)"); diff --git a/kernel/src/startup/multiboot.cpp b/kernel/src/startup/multiboot.cpp new file mode 100644 index 0000000..7bc5fc4 --- /dev/null +++ b/kernel/src/startup/multiboot.cpp @@ -0,0 +1,16 @@ +asm(R"( +.global __multiboot_header +.section .multiboot_header, "a" + +.align 8 +__multiboot_header: + .int 0xe85250d6 # multiboot2 + .int 0 # protected mode i386 + .int __multiboot_header_end - __multiboot_header + .int 0x100000000 - (0xe85250d6 + 0 + (__multiboot_header_end - __multiboot_header)) + + .word 0 + .word 0 + .int 8 +__multiboot_header_end: +)"); \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..3253008 --- /dev/null +++ b/run.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +bear --output "$SCRIPT_DIR/compile_commands.json" -- make -C "$SCRIPT_DIR/kernel" all || exit 1 +mkdir -p "$SCRIPT_DIR/testenv/dist" +cp "$SCRIPT_DIR/kernel/output/kernel.iso" "$SCRIPT_DIR/testenv/dist/kernel.iso" +cd "$SCRIPT_DIR/testenv" || exit 1 + +CPU="-cpu Opteron_G1-v1,pdpe1gb=on" + +if [ "$1" = "debug" ]; then + qemu-system-x86_64 -nodefaults -readconfig qemuConfig.cfg $CPU -s -S -daemonize +else + qemu-system-x86_64 -nodefaults -readconfig qemuConfig.cfg $CPU +fi diff --git a/testenv/.gitignore b/testenv/.gitignore new file mode 100644 index 0000000..16f3129 --- /dev/null +++ b/testenv/.gitignore @@ -0,0 +1,3 @@ +dist/ +image_file +dump.dat \ No newline at end of file diff --git a/testenv/qemuConfig.cfg b/testenv/qemuConfig.cfg new file mode 100644 index 0000000..7b3f166 --- /dev/null +++ b/testenv/qemuConfig.cfg @@ -0,0 +1,81 @@ +[machine] +type = "q35" +[memory] +size = "6144" +[device "ich9-pcie-port-1"] +driver = "ioh3420" +multifunction = "on" +bus = "pcie.0" +addr = "1c.0" +port = "1" +chassis = "1" +[device "ich9-pcie-port-2"] +driver = "ioh3420" +multifunction = "on" +bus = "pcie.0" +addr = "1c.1" +port = "2" +chassis = "2" +[device "ich9-pcie-port-3"] +driver = "ioh3420" +multifunction = "on" +bus = "pcie.0" +addr = "1c.2" +port = "3" +chassis = "3" +[device "ich9-pcie-port-4"] +driver = "ioh3420" +multifunction = "on" +bus = "pcie.0" +addr = "1c.3" +port = "4" +chassis = "4" +[device "ich9-pci-bridge"] +driver = "i82801b11-bridge" +bus = "pcie.0" +addr = "1e.0" +[device "usbDevice"] +driver = "qemu-xhci" +bus = "pcie.0" +addr = "1d.0" +[device "video"] +driver = "virtio-vga" +bus = "pcie.0" +addr = "01.0" +[device "sata-optical-disk"] +driver = "ide-cd" +bus = "ide.0" +drive = "optical-disk" +bootindex = "1" +[drive "optical-disk"] +file = "dist/kernel.iso" +format = "raw" +if = "none" +[device "sata-disk"] +driver = "ide-hd" +bus = "ide.1" +drive = "disk" +bootindex = "2" +[drive "disk"] +file = "image_file" +format = "raw" +if = "none" +[smp-opts] +cpus = "4" +cores = "4" +threads = "1" +sockets = "1" +[device "usb-kbd"] +driver = "usb-kbd" +bus = "usbDevice.0" +[netdev "n1"] +type = "user" +hostfwd = "udp:127.0.0.1:1234-:1234" +hostfwd = "tcp:127.0.0.1:1234-:1234" +[object "net-dump"] +qom-type = "filter-dump" +netdev = "n1" +file = "dump.dat" +[device "nic"] +driver = "e1000e" +netdev = "n1" \ No newline at end of file