diff --git a/kernel/include/acpi/discovery.h b/kernel/include/acpi/discovery.h index 23aaa15..0c133da 100644 --- a/kernel/include/acpi/discovery.h +++ b/kernel/include/acpi/discovery.h @@ -10,6 +10,7 @@ namespace acpi { struct discovery_result_t { optional rsdp; optional madt; + // TODO(wiring): capture the FADT in setupAcpi and store it here optional fadt; }; diff --git a/kernel/include/apic/core.h b/kernel/include/apic/core.h deleted file mode 100644 index 1d1da06..0000000 --- a/kernel/include/apic/core.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "memory/pointer.h" - -#include "acpi/discovery.h" -#include "memory/pagetable.h" - -namespace apic { - -struct stack_t { - paddr_t ptr; - size_t size; -}; - -using core_id = uint8_t; - -struct Core { - core_id id; - stack_t stack; - PageTable kernelPageTable; -}; - -optional initCore(acpi::Madt madt, core_id id); - -void initCores(acpi::discovery_result_t); - -void transitionStartupCore(); - -} // namespace apic \ No newline at end of file diff --git a/kernel/include/apic/lapic.h b/kernel/include/apic/lapic.h deleted file mode 100644 index b9f8d13..0000000 --- a/kernel/include/apic/lapic.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "acpi/discovery.h" -#include "util/number.h" - -namespace apic { - -using lapic_id_t = uint32_t; - -void initLocalApic(const acpi::discovery_result_t& discovery); - -lapic_id_t localApicId(); - -void sendInit(lapic_id_t destination); - -// startup_page: physical address of the real-mode entry point divided by 4096; -// must point below 1 MiB, so only values < 0x100 are meaningful. -void sendStartup(lapic_id_t destination, uint8_t startup_page); - -void sendInterrupt(lapic_id_t destination, uint8_t vector); - -void signalEndOfInterrupt(); - -} // namespace apic diff --git a/kernel/include/apic/timer.h b/kernel/include/apic/timer.h index afec73e..22016b3 100644 --- a/kernel/include/apic/timer.h +++ b/kernel/include/apic/timer.h @@ -33,26 +33,6 @@ constexpr duration_t operator*(uint64_t scalar, duration_t duration) { return duration_t{duration.timer_count * scalar}; } -constexpr bool operator==(duration_t left, duration_t right) { - return left.timer_count == right.timer_count; -} - -constexpr bool operator<(duration_t left, duration_t right) { - return left.timer_count < right.timer_count; -} - -constexpr bool operator<=(duration_t left, duration_t right) { - return left.timer_count <= right.timer_count; -} - -constexpr bool operator>(duration_t left, duration_t right) { - return left.timer_count > right.timer_count; -} - -constexpr bool operator>=(duration_t left, duration_t right) { - return left.timer_count >= right.timer_count; -} - constexpr timestamp_t operator+(timestamp_t timestamp, duration_t duration) { return timestamp_t{timestamp.timer_count + duration.timer_count}; } @@ -82,4 +62,9 @@ void busyWait(duration_t duration); timestamp_t now(); +// TODO: when dynamic allocation and lists are available +// struct Timer {}; +// +// Timer getCoreTimerInstance(); + } // namespace apic diff --git a/kernel/include/cpu/gdt.h b/kernel/include/cpu/gdt.h deleted file mode 100644 index 054838d..0000000 --- a/kernel/include/cpu/gdt.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "memory/pointer.h" -#include "util/optional.h" - -struct [[gnu::packed]] gdt_register_t { - uint16_t limit; - uint64_t base; -}; -static_assert(sizeof(gdt_register_t) == 10); - -struct Gdt { - using selector_t = uint16_t; - - enum class segment_type_t : uint8_t { - code, - data, - task_state, - }; - - struct flags_t { - segment_type_t type; - uint8_t privilege_level; - bool long_mode; - bool default_operand_32bit; - bool granularity_4KiB; - bool readable_writeable; - }; - - struct segment_t { - flags_t flags; - uint64_t base; - uint32_t limit; - }; - - static Gdt fromCurrent(); - static optional allocNew(); - - void activate(); - optional add(segment_t segment); - optional get(selector_t selector); - - paddr_t base; - uint16_t limit; -}; - -struct [[gnu::packed]] tss_t { - uint32_t reserved0; - uint64_t rsp[3]; - uint64_t reserved1; - uint64_t ist[7]; - uint64_t reserved2; - uint16_t reserved3; - uint16_t iomap_base; -}; -static_assert(sizeof(tss_t) == 104); - -void reloadSegments(Gdt::selector_t code_selector, Gdt::selector_t data_selector); diff --git a/kernel/include/main.h b/kernel/include/main.h deleted file mode 100644 index 2332afb..0000000 --- a/kernel/include/main.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -[[noreturn]] void main(); diff --git a/kernel/include/memory/allocator.h b/kernel/include/memory/allocator.h index 82e6e79..1188352 100644 --- a/kernel/include/memory/allocator.h +++ b/kernel/include/memory/allocator.h @@ -12,17 +12,10 @@ struct PhysicalAllocator { size_t page_count; }; - enum class address_range_t : uint8_t { - any, - below_4gib, - }; - static void init(const multiboot::tag_mmap* multiboot_info); static PhysicalAllocator& getInstance(); - optional allocPages( - size_t page_count, size_t alignment_pages = 1, address_range_t range = address_range_t::any - ); + optional allocPages(size_t page_count, size_t alignment_pages = 1); void free(allocation_t ptr); bool force(allocation_t ptr, bool free); diff --git a/kernel/include/memory/pagetable.h b/kernel/include/memory/pagetable.h deleted file mode 100644 index 8fade15..0000000 --- a/kernel/include/memory/pagetable.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "memory/pointer.h" -#include "util/optional.h" - -struct PageTable { - struct flags_t { - enum class granularity_t : uint8_t { - page_4KiB, - page_2MiB, - page_1GiB, - }; - - bool writeable : 1; // allow writes - bool user_accessible : 1; // allow ring-3 access - bool write_through : 1; // write-through instead of write-back - bool cache_disabled : 1; // uncached (MMIO) - bool execute_disabled : 1; // forbid instruction fetch - bool global : 1; // keep in TLB across CR3 switches - granularity_t granularity : 2; // mapping size - }; - struct info_t { - flags_t flags; - paddr_t address; - }; - - static PageTable fromCurrent(); - static optional allocNew(); - - void activate(); - bool map(void* vaddress, paddr_t paddress, flags_t flags); - void unmap(void* vaddress); - optional get(void* vaddress); - - paddr_t l4; -}; \ No newline at end of file diff --git a/kernel/include/memory/pointer.h b/kernel/include/memory/pointer.h index 0ae44a8..9ba35c9 100644 --- a/kernel/include/memory/pointer.h +++ b/kernel/include/memory/pointer.h @@ -3,7 +3,6 @@ #include "util/number.h" constexpr uint64_t high_base = 0xFFFF800000000000; -constexpr uint64_t uncached_base = high_base + (uint64_t{1} << 38); #define read_symbol(symbol) \ []() { \ @@ -19,11 +18,6 @@ struct paddr_t { T* access() { return reinterpret_cast(address + high_base); } - - template - T* access_uc() { - return reinterpret_cast(address + uncached_base); - } }; inline void* operator new(size_t, void* p) { diff --git a/kernel/include/util/msr.h b/kernel/include/util/msr.h deleted file mode 100644 index 59c167d..0000000 --- a/kernel/include/util/msr.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "util/number.h" - -inline uint64_t msr_read(uint32_t msr) { - uint32_t low = 0; - uint32_t high = 0; - __asm__ volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); - return (static_cast(high) << 32) | low; -} - -inline void msr_write(uint32_t msr, uint64_t value) { - uint32_t low = static_cast(value); - uint32_t high = static_cast(value >> 32); - __asm__ volatile("wrmsr" : : "c"(msr), "a"(low), "d"(high)); -} diff --git a/kernel/include/util/optional.h b/kernel/include/util/optional.h index 4826929..91e1c1d 100644 --- a/kernel/include/util/optional.h +++ b/kernel/include/util/optional.h @@ -131,7 +131,7 @@ public: } } - explicit operator bool() const { + operator bool() const { return initialized; } diff --git a/kernel/linker.ld b/kernel/linker.ld index 200651f..a511bf6 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -33,13 +33,13 @@ SECTIONS } > START_MEMORY_PV .text : AT(ADDR(.text) - high_base) { __text_start__ = .; - *(.text .text.*) - *(.iplt) + *(EXCLUDE_FILE(*trampoline*) .text .text.*) + *(EXCLUDE_FILE(*trampoline*) .iplt) __text_end__ = .; } > HIGH_KERNEL_V .rodata : AT(ADDR(.rodata) - high_base) { __rodata_start__ = .; - *(.rodata .rodata.*) + *(EXCLUDE_FILE(*trampoline*) .rodata .rodata.*) . = ALIGN(8); __reserved_ranges_start__ = .; KEEP(*(.reserved_ranges)) @@ -52,37 +52,37 @@ SECTIONS } > HIGH_KERNEL_V .data : AT(ADDR(.data) - high_base) { __data_start__ = .; - *(.data .data.*) - *(.got .got.plt .igot.plt .data.rel.ro .data.rel.ro.*) + *(EXCLUDE_FILE(*trampoline*) .data .data.*) + *(EXCLUDE_FILE(*trampoline*) .got .got.plt .igot.plt .data.rel.ro .data.rel.ro.*) __data_end__ = .; } > HIGH_KERNEL_V .bss (NOLOAD) : AT(ADDR(.bss) - high_base) { __bss_start__ = .; - *(.bss .bss.*) + *(EXCLUDE_FILE(*trampoline*) .bss .bss.*) __bss_end__ = .; } > HIGH_KERNEL_V .trampoline_text : { __trampoline_text_start__ = .; - *(.trampoline_text) + *trampoline*(.text) __trampoline_text_end__ = .; } > TRAMPOLINE_PV .trampoline_data : { __trampoline_data_start__ = .; - *(.trampoline_data) + *trampoline*(.data) __trampoline_data_end__ = .; } > TRAMPOLINE_PV .trampoline_rodata : { __trampoline_rodata_start__ = .; - *(.trampoline_rodata) + *trampoline*(.rodata) __trampoline_rodata_end__ = .; } > TRAMPOLINE_PV .trampoline_bss (NOLOAD) : { __trampoline_bss_start__ = .; - *(.trampoline_bss) + *trampoline*(.bss) __trampoline_bss_end__ = .; } > TRAMPOLINE_PV diff --git a/kernel/src/apic/core.cpp b/kernel/src/apic/core.cpp deleted file mode 100644 index 7e87df7..0000000 --- a/kernel/src/apic/core.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "apic/core.h" -#include "apic/lapic.h" -#include "apic/timer.h" -#include "cpu/gdt.h" -#include "memory/allocator.h" - -static volatile gdt_register_t secondary_gdt_register; - -static optional createSecondaryGdt() { - optional gdtOpt = Gdt::allocNew(); - if (!gdtOpt.has_value()) { - return {}; - } - Gdt gdt = gdtOpt.value(); - Gdt::segment_t codeSegment{}; - codeSegment.flags.type = Gdt::segment_type_t::code; - codeSegment.flags.privilege_level = 0; - codeSegment.flags.long_mode = true; - codeSegment.flags.readable_writeable = true; - Gdt::segment_t dataSegment{}; - dataSegment.flags.type = Gdt::segment_type_t::data; - dataSegment.flags.privilege_level = 0; - dataSegment.flags.readable_writeable = true; - optional codeSelector = gdt.add(codeSegment); - optional dataSelector = gdt.add(dataSegment); - if (codeSelector.value_or(0) != 0x08 || dataSelector.value_or(0) != 0x10) { - return {}; - } - return gdt; -} - -static bool waitForStartedInfo(volatile uint64_t* started_info, uint64_t expected, apic::duration_t timeout) { - auto start = apic::now(); - while (*started_info < expected) { - if (apic::now() - start > timeout) { - return false; - } - __asm__ volatile("pause"); - } - return true; -} - -bool sendStartupWithTimeout(uint8_t apicId, uint8_t page, volatile uint64_t* started_info) { - apic::sendStartup(apicId, page); - return waitForStartedInfo(started_info, 1, apic::milliseconds(10)); -} - -bool startupCore(uint8_t apicId, paddr_t code, paddr_t stack, PageTable pageTable, Gdt gdt) { - auto started_info_s = read_symbol("__started_info"); - auto stack_ptr_s = read_symbol("__stack_ptr"); - auto page_table_ptr_s = read_symbol("__page_table_ptr"); - auto gdt_addr_ptr_s = read_symbol("__gdt_addr_ptr"); - auto started_info = paddr_t{started_info_s}.access(); - auto stack_ptr = paddr_t{stack_ptr_s}.access(); - auto page_table_ptr = paddr_t{page_table_ptr_s}.access(); - auto gdt_addr_ptr = paddr_t{gdt_addr_ptr_s}.access(); - secondary_gdt_register.limit = gdt.limit; - secondary_gdt_register.base = gdt.base.address; - *started_info = 0; - *stack_ptr = stack.address; - *page_table_ptr = pageTable.l4.address; - *gdt_addr_ptr = reinterpret_cast(&secondary_gdt_register) - high_base; - uint8_t page = code.address / page_size; - apic::sendInit(apicId); - apic::busyWait(apic::milliseconds(10)); - if (!(sendStartupWithTimeout(apicId, page, started_info) // - || sendStartupWithTimeout(apicId, page, started_info))) { - return false; - } - return waitForStartedInfo(started_info, 2, apic::milliseconds(100)); -} - -PageTable createPageTable() { - PageTable pageTable = PageTable::allocNew().value(); - PageTable::flags_t cachedFlags = { - .writeable = 1, - .user_accessible = 0, - .write_through = 0, - .cache_disabled = 0, - .execute_disabled = 0, - .global = 0, - .granularity = PageTable::flags_t::granularity_t::page_1GiB - }; - for (uint64_t i = 0; i < 256; i++) { - auto vaddr = i * (1ull << 30); - auto paddr = i * (1ull << 30); - pageTable.map(reinterpret_cast(vaddr), paddr_t{paddr}, cachedFlags); - } - for (uint64_t i = 0; i < 256; i++) { - auto vaddr = i * (1ull << 30) + high_base; - auto paddr = i * (1ull << 30); - pageTable.map(reinterpret_cast(vaddr), paddr_t{paddr}, cachedFlags); - } - PageTable::flags_t uncachedFlags = { - .writeable = 1, - .user_accessible = 0, - .write_through = 1, - .cache_disabled = 1, - .execute_disabled = 0, - .global = 0, - .granularity = PageTable::flags_t::granularity_t::page_1GiB - }; - for (uint64_t i = 0; i < 256; i++) { - auto vaddr = i * (1ull << 30) + uncached_base; - auto paddr = i * (1ull << 30); - pageTable.map(reinterpret_cast(vaddr), paddr_t{paddr}, uncachedFlags); - } - return pageTable; -} - -optional apic::initCore(acpi::Madt madt, core_id id) { - optional apicId; - madt.for_each_entry([&](const acpi::madt_local_apic_t* apic) { - if (apic->acpi_processor_uid == id) { - apicId = apic->apic_id; - } - }); - if (!apicId.has_value()) { - return {}; - } - if (apicId.value() == apic::localApicId()) { - return {}; - } - apic::Core core{}; - size_t stackPageCount = 256; - paddr_t stackBase = PhysicalAllocator::getInstance().allocPages(stackPageCount).value().ptr; - paddr_t stackPtr = {stackBase.address + stackPageCount * page_size - 8}; - paddr_t code = {read_symbol("__16bitStartup")}; - auto pageTable = createPageTable(); - optional gdt = createSecondaryGdt(); - if (!gdt.has_value()) { - return {}; - } - if (!startupCore(apicId.value(), code, stackPtr, pageTable, gdt.value())) { - return {}; - } - return core; -} - -void apic::initCores(acpi::discovery_result_t discovery) { - if (!discovery.madt.has_value()) { - return; - } - discovery.madt->for_each_entry([&](const acpi::madt_local_apic_t* apic) { - apic::initCore(discovery.madt.value(), apic->acpi_processor_uid); - }); -} - -void apic::transitionStartupCore() {} - -extern "C" [[noreturn]] void __secondary_init() { - while (true) { - __asm__ volatile("hlt"); - } -} \ No newline at end of file diff --git a/kernel/src/apic/lapic.cpp b/kernel/src/apic/lapic.cpp deleted file mode 100644 index 01df3bb..0000000 --- a/kernel/src/apic/lapic.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "apic/lapic.h" - -#include "memory/pointer.h" -#include "util/msr.h" - -namespace { - -constexpr uint32_t apic_base_msr = 0x1B; -constexpr uint64_t apic_base_enable = uint64_t{1} << 11; -constexpr uint64_t apic_base_address_mask = 0x000FFFFFFFFFF000; - -constexpr size_t id_register = 0x20; -constexpr size_t eoi_register = 0xB0; -constexpr size_t spurious_vector_register = 0xF0; -constexpr size_t icr_low_register = 0x300; -constexpr size_t icr_high_register = 0x310; - -constexpr uint32_t software_enable = 1u << 8; -constexpr uint32_t spurious_vector = 0xFF; - -constexpr uint32_t delivery_mode_fixed = 0b000u << 8; -constexpr uint32_t delivery_mode_init = 0b101u << 8; -constexpr uint32_t delivery_mode_startup = 0b110u << 8; -constexpr uint32_t delivery_status_pending = 1u << 12; -constexpr uint32_t level_assert = 1u << 14; - -volatile uint32_t* lapic_registers = nullptr; - -volatile uint32_t& lapicRegister(size_t offset) { - return lapic_registers[offset / sizeof(uint32_t)]; -} - -void waitWhileDeliveryPending() { - while ((lapicRegister(icr_low_register) & delivery_status_pending) != 0) { - __asm__ volatile("pause"); - } -} - -void sendIpi(apic::lapic_id_t destination, uint32_t command) { - waitWhileDeliveryPending(); - lapicRegister(icr_high_register) = destination << 24; - lapicRegister(icr_low_register) = command; - waitWhileDeliveryPending(); -} - -paddr_t localApicPhysicalBase(const acpi::discovery_result_t& discovery) { - paddr_t msr_base{msr_read(apic_base_msr) & apic_base_address_mask}; - return discovery.madt - .map([](acpi::Madt madt) { - return madt.local_apic_address(); - }) - .value_or(msr_base); -} - -} // namespace - -void apic::initLocalApic(const acpi::discovery_result_t& discovery) { - msr_write(apic_base_msr, msr_read(apic_base_msr) | apic_base_enable); - lapic_registers = localApicPhysicalBase(discovery).access_uc(); - lapicRegister(spurious_vector_register) = spurious_vector | software_enable; -} - -apic::lapic_id_t apic::localApicId() { - return lapicRegister(id_register) >> 24; -} - -void apic::sendInit(lapic_id_t destination) { - sendIpi(destination, delivery_mode_init | level_assert); -} - -void apic::sendStartup(lapic_id_t destination, uint8_t startup_page) { - sendIpi(destination, delivery_mode_startup | level_assert | startup_page); -} - -void apic::sendInterrupt(lapic_id_t destination, uint8_t vector) { - sendIpi(destination, delivery_mode_fixed | level_assert | vector); -} - -void apic::signalEndOfInterrupt() { - lapicRegister(eoi_register) = 0; -} diff --git a/kernel/src/apic/timer.cpp b/kernel/src/apic/timer.cpp index b913922..45aadcc 100644 --- a/kernel/src/apic/timer.cpp +++ b/kernel/src/apic/timer.cpp @@ -11,11 +11,11 @@ constexpr uint32_t processor_frequency_leaf = 0x16; constexpr uint32_t feature_edx_tsc = 1u << 4; -struct timer_calibration_t { +struct lapic_timer_calibration_t { uint64_t tsc_frequency_hz; }; -timer_calibration_t timer_calibration{}; +lapic_timer_calibration_t timer_calibration{}; bool isTscSupported() { return cpuid(feature_info_leaf) diff --git a/kernel/src/cpu/gdt.cpp b/kernel/src/cpu/gdt.cpp deleted file mode 100644 index 127f763..0000000 --- a/kernel/src/cpu/gdt.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "cpu/gdt.h" -#include "memory/allocator.h" - -struct segment_descriptor_t { - uint64_t limit_low : 16; - uint64_t base_low : 24; - uint64_t accessed : 1; - uint64_t readable_writeable : 1; - uint64_t conforming_expand_down : 1; - uint64_t executable : 1; - uint64_t user_segment : 1; - uint64_t privilege_level : 2; - uint64_t present : 1; - uint64_t limit_high : 4; - uint64_t available : 1; - uint64_t long_mode : 1; - uint64_t default_operand_32bit : 1; - uint64_t granularity_4KiB : 1; - uint64_t base_high : 8; -}; -static_assert(sizeof(segment_descriptor_t) == sizeof(uint64_t)); - -struct system_descriptor_t { - uint64_t limit_low : 16; - uint64_t base_low : 24; - uint64_t type : 4; - uint64_t user_segment : 1; - uint64_t privilege_level : 2; - uint64_t present : 1; - uint64_t limit_high : 4; - uint64_t available : 1; - uint64_t reserved_long_mode : 1; - uint64_t reserved_default_operand_32bit : 1; - uint64_t granularity_4KiB : 1; - uint64_t base_high : 8; - uint64_t base_upper : 32; - uint64_t reserved : 32; -}; -static_assert(sizeof(system_descriptor_t) == 2 * sizeof(uint64_t)); - -constexpr uint64_t task_state_available_type = 0b1001; -constexpr uint64_t task_state_busy_type = 0b1011; - -static size_t entry_count_of(uint16_t limit) { - return (static_cast(limit) + 1) / sizeof(uint64_t); -} - -static bool is_present(uint64_t entry) { - const auto* descriptor = reinterpret_cast(&entry); - return descriptor->present; -} - -static bool is_task_state_low_half(uint64_t entry) { - const auto* descriptor = reinterpret_cast(&entry); - if (!descriptor->present) { - return false; - } - if (descriptor->user_segment) { - return false; - } - return descriptor->type == task_state_available_type || descriptor->type == task_state_busy_type; -} - -static segment_descriptor_t encode_segment(Gdt::segment_t segment) { - segment_descriptor_t descriptor{}; - descriptor.limit_low = segment.limit & 0xFFFF; - descriptor.limit_high = (segment.limit >> 16) & 0xF; - descriptor.base_low = segment.base & 0xFFFFFF; - descriptor.base_high = (segment.base >> 24) & 0xFF; - descriptor.readable_writeable = segment.flags.readable_writeable; - descriptor.executable = segment.flags.type == Gdt::segment_type_t::code; - descriptor.user_segment = 1; - descriptor.privilege_level = segment.flags.privilege_level; - descriptor.present = 1; - descriptor.long_mode = segment.flags.long_mode; - descriptor.default_operand_32bit = segment.flags.default_operand_32bit; - descriptor.granularity_4KiB = segment.flags.granularity_4KiB; - return descriptor; -} - -static system_descriptor_t encode_task_state(Gdt::segment_t segment) { - system_descriptor_t descriptor{}; - descriptor.limit_low = segment.limit & 0xFFFF; - descriptor.limit_high = (segment.limit >> 16) & 0xF; - descriptor.base_low = segment.base & 0xFFFFFF; - descriptor.base_high = (segment.base >> 24) & 0xFF; - descriptor.base_upper = segment.base >> 32; - descriptor.type = task_state_available_type; - descriptor.user_segment = 0; - descriptor.privilege_level = segment.flags.privilege_level; - descriptor.present = 1; - descriptor.granularity_4KiB = segment.flags.granularity_4KiB; - return descriptor; -} - -static Gdt::segment_t decode_task_state(const system_descriptor_t* descriptor) { - Gdt::segment_t segment{}; - segment.flags.type = Gdt::segment_type_t::task_state; - segment.flags.privilege_level = descriptor->privilege_level; - segment.flags.granularity_4KiB = descriptor->granularity_4KiB; - segment.base = static_cast(descriptor->base_low) | (static_cast(descriptor->base_high) << 24) | - (static_cast(descriptor->base_upper) << 32); - segment.limit = static_cast(descriptor->limit_low | (descriptor->limit_high << 16)); - return segment; -} - -static Gdt::segment_t decode_segment(const segment_descriptor_t* descriptor) { - Gdt::segment_t segment{}; - segment.flags.type = descriptor->executable ? Gdt::segment_type_t::code : Gdt::segment_type_t::data; - segment.flags.privilege_level = descriptor->privilege_level; - segment.flags.long_mode = descriptor->long_mode; - segment.flags.default_operand_32bit = descriptor->default_operand_32bit; - segment.flags.granularity_4KiB = descriptor->granularity_4KiB; - segment.flags.readable_writeable = descriptor->readable_writeable; - segment.base = static_cast(descriptor->base_low) | (static_cast(descriptor->base_high) << 24); - segment.limit = static_cast(descriptor->limit_low | (descriptor->limit_high << 16)); - return segment; -} - -Gdt Gdt::fromCurrent() { - gdt_register_t gdt_register{}; - asm volatile("sgdt %0" : "=m"(gdt_register)); - Gdt gdt{}; - gdt.limit = gdt_register.limit; - if (gdt_register.base >= high_base) { - gdt.base = paddr_t{gdt_register.base - high_base}; - } else { - gdt.base = paddr_t{gdt_register.base}; - } - return gdt; -} - -optional Gdt::allocNew() { - auto allocation = - PhysicalAllocator::getInstance().allocPages(1, 1, PhysicalAllocator::address_range_t::below_4gib); - if (!allocation.has_value()) { - return {}; - } - memset(allocation->ptr.access(), 0, page_size); - Gdt gdt{}; - gdt.base = allocation->ptr; - gdt.limit = page_size - 1; - return gdt; -} - -void Gdt::activate() { - gdt_register_t gdt_register{}; - gdt_register.limit = limit; - gdt_register.base = reinterpret_cast(base.access()); - asm volatile("lgdt %0" : : "m"(gdt_register)); -} - -optional Gdt::add(segment_t segment) { - uint64_t* entries = base.access(); - size_t entry_count = entry_count_of(limit); - size_t needed_slots = segment.flags.type == segment_type_t::task_state ? 2 : 1; - size_t index = 1; - while (index + needed_slots <= entry_count) { - if (is_task_state_low_half(entries[index])) { - index += 2; - continue; - } - if (is_present(entries[index])) { - index += 1; - continue; - } - if (needed_slots == 2 && is_present(entries[index + 1])) { - index += 1; - continue; - } - if (segment.flags.type == segment_type_t::task_state) { - *reinterpret_cast(&entries[index]) = encode_task_state(segment); - } else { - *reinterpret_cast(&entries[index]) = encode_segment(segment); - } - return static_cast(index * sizeof(uint64_t)); - } - return {}; -} - -optional Gdt::get(selector_t selector) { - size_t index = selector / sizeof(uint64_t); - size_t entry_count = entry_count_of(limit); - if (index == 0 || index >= entry_count) { - return {}; - } - uint64_t* entries = base.access(); - if (is_task_state_low_half(entries[index])) { - if (index + 2 > entry_count) { - return {}; - } - return decode_task_state(reinterpret_cast(&entries[index])); - } - if (!is_present(entries[index])) { - return {}; - } - return decode_segment(reinterpret_cast(&entries[index])); -} - -void reloadSegments(Gdt::selector_t code_selector, Gdt::selector_t data_selector) { - uint64_t code = code_selector; - uint16_t data = data_selector; - asm volatile( - "pushq %[code]\n" - "leaq 1f(%%rip), %%rax\n" - "pushq %%rax\n" - "lretq\n" - "1:\n" - "mov %[data], %%ds\n" - "mov %[data], %%es\n" - "mov %[data], %%fs\n" - "mov %[data], %%gs\n" - "mov %[data], %%ss\n" - : - : [code] "r"(code), [data] "r"(data) - : "rax", "memory" - ); -} diff --git a/kernel/src/init/init.cpp b/kernel/src/init/init.cpp index 5b140a6..6feb16d 100644 --- a/kernel/src/init/init.cpp +++ b/kernel/src/init/init.cpp @@ -3,8 +3,6 @@ #include "acpi/discovery.h" #include "acpi/fadt.h" #include "acpi/madt.h" -#include "apic/core.h" -#include "apic/lapic.h" #include "apic/timer.h" #include "init/multiboot2.h" #include "init/print.h" @@ -213,18 +211,31 @@ static void calibrateTimer(acpi::discovery_result_t acpi) { } } +static void demonstateTimer() { + auto time1 = apic::now(); + print("Time 1: "); + print_hex(time1.timer_count); + print("\nTime 2: "); + auto time2 = apic::now(); + print_hex(time2.timer_count); + print("\n"); + auto duration = time2 - time1; + auto readableDuration = apic::toSecondsAndNanoseconds(duration); + print_dec(readableDuration.seconds); + print("s "); + print_dec(readableDuration.nanoseconds); + print("ns\n"); + print("Wait for 5s!\n"); + apic::busyWait(apic::seconds(5)); + print("Waited for 5s!\n"); +} + [[maybe_unused]] [[noreturn]] __attribute__((used)) void init() { initFromLow(); print("Reached init\n"); step("memory", setupMemory); auto acpi = step("acpi", setupAcpi); - step("lapic", [&]() { - apic::initLocalApic(acpi); - }); - print("BSP local APIC id: "); - print_dec(apic::localApicId()); - print("\n"); step("timer", partial(calibrateTimer, acpi)); - step("cpu startup", partial(apic::initCores, acpi)); + demonstateTimer(); halt(); } diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp deleted file mode 100644 index 49a3652..0000000 --- a/kernel/src/main.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "main.h" - -[[noreturn]] void main() { - while (true) { - __asm__ volatile("hlt"); - } -} diff --git a/kernel/src/memory/allocator.cpp b/kernel/src/memory/allocator.cpp index ccc1747..80ec9aa 100644 --- a/kernel/src/memory/allocator.cpp +++ b/kernel/src/memory/allocator.cpp @@ -286,7 +286,7 @@ struct PhysicalAllocatorImpl { return true; } - optional allocPages(size_t page_count, size_t alignment_pages, PhysicalAllocator::address_range_t range) { + optional allocPages(size_t page_count, size_t alignment_pages) { if (page_count == 0) { return {}; } @@ -297,11 +297,6 @@ struct PhysicalAllocatorImpl { return {}; } - uint64_t page_limit = ~uint64_t{0}; - if (range == PhysicalAllocator::address_range_t::below_4gib) { - page_limit = (uint64_t{1} << 32) / page_size; - } - Cursor cursor = cursor_at(0); uint64_t run_start = 0; size_t i = 0; @@ -311,16 +306,9 @@ struct PhysicalAllocatorImpl { if (length == 0 && prev_zero) { break; } - if (run_start >= page_limit) { - break; - } if ((i & 1) && length > 0) { - uint64_t run_end = run_start + length; - if (run_end > page_limit) { - run_end = page_limit; - } uint64_t aligned_start = ((run_start + alignment_pages - 1) / alignment_pages) * alignment_pages; - if (aligned_start + page_count <= run_end) { + if (aligned_start + page_count <= run_start + length) { set_range(aligned_start, page_count, false); reclaim_nodes(); return allocation_t{paddr_t{aligned_start * page_size}, page_count}; @@ -343,9 +331,8 @@ bool PhysicalAllocator::force(allocation_t ptr, bool free) { return PhysicalAllocatorImpl{*this}.force(ptr, free); } -optional -PhysicalAllocator::allocPages(size_t page_count, size_t alignment_pages, address_range_t range) { - return PhysicalAllocatorImpl{*this}.allocPages(page_count, alignment_pages, range); +optional PhysicalAllocator::allocPages(size_t page_count, size_t alignment_pages) { + return PhysicalAllocatorImpl{*this}.allocPages(page_count, alignment_pages); } void PhysicalAllocator::free(allocation_t ptr) { diff --git a/kernel/src/memory/pagetable.cpp b/kernel/src/memory/pagetable.cpp deleted file mode 100644 index d931609..0000000 --- a/kernel/src/memory/pagetable.cpp +++ /dev/null @@ -1,363 +0,0 @@ -#include "memory/pagetable.h" -#include "memory/allocator.h" -#include "util/function.h" - -template -struct entry_table_t { - EntryType entries[512]; -}; - -struct frame_entry_t { - static constexpr size_t level = 1; - - uint64_t present : 1; - uint64_t writeable : 1; - uint64_t user_accessible : 1; - uint64_t write_through : 1; - uint64_t cache_disabled : 1; - uint64_t accessed : 1; - uint64_t dirty : 1; - uint64_t page_attribute_table : 1; - uint64_t global : 1; - uint64_t available_low : 3; - uint64_t frame_address : 40; - uint64_t available_high : 11; - uint64_t execute_disabled : 1; -}; - -template -struct subtable_entry_t { - using next_table_t = entry_table_t; - static constexpr size_t level = NextEntryType::level + 1; - - uint64_t present : 1; - uint64_t writeable : 1; - uint64_t user_accessible : 1; - uint64_t write_through : 1; - uint64_t cache_disabled : 1; - uint64_t accessed : 1; - uint64_t ignored_dirty : 1; - uint64_t huge_page : 1; - uint64_t ignored_global : 1; - uint64_t available_low : 3; - uint64_t table_address : 40; - uint64_t available_high : 11; - uint64_t execute_disabled : 1; -}; - -template -struct huge_frame_entry_t { - static constexpr size_t level = level_; - - uint64_t present : 1; - uint64_t writeable : 1; - uint64_t user_accessible : 1; - uint64_t write_through : 1; - uint64_t cache_disabled : 1; - uint64_t accessed : 1; - uint64_t dirty : 1; - uint64_t huge_page : 1; - uint64_t global : 1; - uint64_t available_low : 3; - uint64_t page_attribute_table : 1; - uint64_t frame_address : 39; - uint64_t available_high : 11; - uint64_t execute_disabled : 1; -}; - -using frame_2MiB_entry_t = huge_frame_entry_t<2>; -using frame_1GiB_entry_t = huge_frame_entry_t<3>; - -template -union table_or_huge_entry_t { - static constexpr size_t level = NextEntryType::level + 1; - - subtable_entry_t subtable; - huge_frame_entry_t huge; -}; - -using level1_entry_t = frame_entry_t; -using level2_entry_t = table_or_huge_entry_t; -using level3_entry_t = table_or_huge_entry_t; -using level4_entry_t = table_or_huge_entry_t; - -using level1_table_t = entry_table_t; -using level2_table_t = entry_table_t; -using level3_table_t = entry_table_t; -using level4_table_t = entry_table_t; - -static_assert(sizeof(frame_2MiB_entry_t) == sizeof(uint64_t)); -static_assert(sizeof(frame_1GiB_entry_t) == sizeof(uint64_t)); -static_assert(sizeof(level1_entry_t) == sizeof(uint64_t)); -static_assert(sizeof(level2_entry_t) == sizeof(uint64_t)); -static_assert(sizeof(level3_entry_t) == sizeof(uint64_t)); -static_assert(sizeof(level4_entry_t) == sizeof(uint64_t)); -static_assert(sizeof(level1_table_t) == page_size); -static_assert(sizeof(level2_table_t) == page_size); -static_assert(sizeof(level3_table_t) == page_size); -static_assert(sizeof(level4_table_t) == page_size); - -template -static paddr_t address_of(subtable_entry_t entry) { - return paddr_t{entry.table_address << 12}; -} - -static paddr_t address_of(frame_entry_t entry) { - return paddr_t{entry.frame_address << 12}; -} - -template -static paddr_t address_of(huge_frame_entry_t entry) { - return paddr_t{entry.frame_address << 13}; -} - -template -static size_t table_index(void* vaddress) { - uint64_t address = reinterpret_cast(vaddress); - return (address >> (12 + 9 * (level - 1))) & 0x1FF; -} - -template -static optional walk(level1_table_t* table, void* vaddress, Fn&& fn) { - frame_entry_t& entry = table->entries[table_index(vaddress)]; - if constexpr (requires { fn(entry); }) { - fn(entry); - } - return &entry; -} - -struct ascend_t {}; - -template -static optional -walk(entry_table_t>* table, void* vaddress, Fn&& fn) { - using entry_t = table_or_huge_entry_t; - entry_t& entry = table->entries[table_index(vaddress)]; - if constexpr (requires { fn(entry); }) { - fn(entry); - } - optional leaf{}; - if (entry.subtable.present && entry.subtable.huge_page) { - if constexpr (requires { fn(entry.huge); }) { - fn(entry.huge); - } - } else if (entry.subtable.present) { - leaf = walk(address_of(entry.subtable).template access>(), vaddress, fn); - } - if constexpr (requires { fn(entry, ascend_t{}); }) { - fn(entry, ascend_t{}); - } - return leaf; -} - -static bool is_present(frame_entry_t entry) { - return entry.present; -} - -template -static bool is_present(table_or_huge_entry_t entry) { - return entry.subtable.present; -} - -template -static bool is_table_empty(entry_table_t* table) { - for (EntryType& entry : table->entries) { - if (is_present(entry)) { - return false; - } - } - return true; -} - -template -static void reclaim_if_empty(table_or_huge_entry_t& entry) { - if (!entry.subtable.present) { - return; - } - if (entry.subtable.huge_page) { - return; - } - entry_table_t* child_table = - address_of(entry.subtable).template access>(); - if (!is_table_empty(child_table)) { - return; - } - PhysicalAllocator::getInstance().free({address_of(entry.subtable), 1}); - entry = table_or_huge_entry_t{}; -} - -template -static PageTable::flags_t::granularity_t granularity_of() { - using granularity_t = PageTable::flags_t::granularity_t; - if constexpr (LeafEntryType::level == 1) { - return granularity_t::page_4KiB; - } else if constexpr (LeafEntryType::level == 2) { - return granularity_t::page_2MiB; - } else { - return granularity_t::page_1GiB; - } -} - -template -static PageTable::info_t info_of(LeafEntryType entry, void* vaddress) { - PageTable::info_t info{}; - info.flags.writeable = entry.writeable; - info.flags.user_accessible = entry.user_accessible; - info.flags.write_through = entry.write_through; - info.flags.cache_disabled = entry.cache_disabled; - info.flags.execute_disabled = entry.execute_disabled; - info.flags.global = entry.global; - info.flags.granularity = granularity_of(); - uint64_t offset_mask = (uint64_t{1} << (12 + 9 * (LeafEntryType::level - 1))) - 1; - info.address = paddr_t{address_of(entry).address + (reinterpret_cast(vaddress) & offset_mask)}; - return info; -} - -static paddr_t current_l4() { - uint64_t cr3; - asm volatile("mov %%cr3, %0" : "=r"(cr3)); - return paddr_t{cr3 & ~uint64_t{0xFFF}}; -} - -static bool is_active(paddr_t l4) { - return current_l4().address == l4.address; -} - -template -static void apply_flags(LeafEntryType& entry, PageTable::flags_t flags) { - entry.present = 1; - entry.writeable = flags.writeable; - entry.user_accessible = flags.user_accessible; - entry.write_through = flags.write_through; - entry.cache_disabled = flags.cache_disabled; - entry.execute_disabled = flags.execute_disabled; - entry.global = flags.global; -} - -static size_t target_level_of(PageTable::flags_t::granularity_t granularity) { - if (granularity == PageTable::flags_t::granularity_t::page_1GiB) { - return 3; - } - if (granularity == PageTable::flags_t::granularity_t::page_2MiB) { - return 2; - } - return 1; -} - -template -static void ensure_subtable(table_or_huge_entry_t& entry) { - if (entry.subtable.present) { - return; - } - optional allocation = PhysicalAllocator::getInstance().allocPages(1); - if (!allocation.has_value()) { - return; - } - memset(allocation->ptr.access(), 0, page_size); - subtable_entry_t subtable{}; - subtable.present = 1; - subtable.writeable = 1; - subtable.user_accessible = 1; - subtable.table_address = allocation->ptr.address >> 12; - entry.subtable = subtable; -} - -void PageTable::activate() { - asm volatile("mov %0, %%cr3" : : "r"(l4.address) : "memory"); -} -PageTable PageTable::fromCurrent() { - PageTable table; - table.l4 = current_l4(); - return table; -} - -optional PageTable::allocNew() { - auto alloc = PhysicalAllocator::getInstance().allocPages(1, 1, PhysicalAllocator::address_range_t::below_4gib); - if (!alloc.has_value()) { - return {}; - } - auto addr = alloc->ptr; - memset(addr.access(), 0, page_size); - PageTable table{}; - table.l4 = addr; - return table; -} - -bool PageTable::map(void* vaddress, paddr_t paddress, flags_t flags) { - size_t target_level = target_level_of(flags.granularity); - bool mapped = false; - walk( - l4.access(), vaddress, - overloaded{ - [&](frame_entry_t& entry) { - frame_entry_t leaf{}; - apply_flags(leaf, flags); - leaf.frame_address = paddress.address >> 12; - entry = leaf; - mapped = true; - }, - [&](table_or_huge_entry_t& entry) { - constexpr size_t level = table_or_huge_entry_t::level; - if (level == target_level) { - if (entry.subtable.present && !entry.subtable.huge_page) { - return; - } - huge_frame_entry_t leaf{}; - apply_flags(leaf, flags); - leaf.huge_page = 1; - leaf.frame_address = paddress.address >> 13; - entry.huge = leaf; - mapped = true; - } else { - ensure_subtable(entry); - } - } - } - ); - if (mapped && is_active(l4)) { - asm volatile("invlpg (%0)" : : "r"(vaddress) : "memory"); - } - return mapped; -} -void PageTable::unmap(void* vaddress) { - walk( - l4.access(), vaddress, - overloaded{ - [](frame_entry_t& entry) { - entry = frame_entry_t{}; - }, - [](frame_2MiB_entry_t& entry) { - entry = frame_2MiB_entry_t{}; - }, - [](frame_1GiB_entry_t& entry) { - entry = frame_1GiB_entry_t{}; - }, - [](auto& entry, ascend_t) { - reclaim_if_empty(entry); - } - } - ); - if (is_active(l4)) { - asm volatile("invlpg (%0)" : : "r"(vaddress) : "memory"); - } -} -optional PageTable::get(void* vaddress) { - optional result{}; - walk( - l4.access(), vaddress, - overloaded{ - [&](frame_entry_t& entry) { - if (entry.present) { - result = info_of(entry, vaddress); - } - }, - [&](frame_2MiB_entry_t& entry) { - result = info_of(entry, vaddress); - }, - [&](frame_1GiB_entry_t& entry) { - result = info_of(entry, vaddress); - } - } - ); - return result; -} \ No newline at end of file diff --git a/kernel/src/startup/entry.cpp b/kernel/src/startup/entry.cpp index add74f3..03bda63 100644 --- a/kernel/src/startup/entry.cpp +++ b/kernel/src/startup/entry.cpp @@ -48,11 +48,6 @@ __x64_not_supported: call __print jmp __stop32 -__nx_not_supported: - mov $__nx_not_supported_string, %esi - call __print - jmp __stop32 - __check_if_x64: pushfl pop %eax @@ -75,8 +70,6 @@ __check_if_x64: cpuid test $(1 << 29), %edx jz __x64_not_supported - test $(1 << 20), %edx - jz __nx_not_supported mov $__x64_supported_string, %esi call __print ret @@ -92,7 +85,7 @@ __go_to_x64: mov $0xC0000080, %ecx rdmsr - or $((0x1 << 8) | (0x1 << 11)), %eax + or $(0x1 << 8), %eax wrmsr mov %cr0, %eax @@ -142,8 +135,6 @@ __hello_string: .string "Starting PrOSess! 32bit start!\n" __x64_not_supported_string: .string "x64 is not supported!\n" -__nx_not_supported_string: - .string "CPU lacks the NX (no-execute) feature, refusing to boot!\n" __x64_supported_string: .string "x64 is supported!\n" __multiboot_info: @@ -236,28 +227,18 @@ __page_level_4: .align 0x1000 __page_level_3_low_1gb_identity_map: .set gib_index, 0 - .rept 256 # identity-map the first 256 GiB, cached, one 1 GiB huge page each + .rept 512 # identity-map all 512 GiB the PDPT spans, one 1 GiB huge page each .quad (1 << 0) | (1 << 1) | (1 << 7) | (gib_index << 30) .set gib_index, gib_index + 1 .endr - .set gib_index, 0 - .rept 256 # alias the same 256 GiB uncached (PWT | PCD) for MMIO - .quad (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 7) | (gib_index << 30) - .set gib_index, gib_index + 1 - .endr .align 0x1000 __page_level_3_kernel_1gb_identity_map: .set gib_index, 0 - .rept 256 # identity-map the first 256 GiB, cached, one 1 GiB huge page each + .rept 512 # identity-map all 512 GiB the PDPT spans, one 1 GiB huge page each .quad (1 << 0) | (1 << 1) | (1 << 7) | (gib_index << 30) .set gib_index, gib_index + 1 .endr - .set gib_index, 0 - .rept 256 # alias the same 256 GiB uncached (PWT | PCD) for MMIO - .quad (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 7) | (gib_index << 30) - .set gib_index, gib_index + 1 - .endr )"); // startup gdt diff --git a/kernel/src/startup/secondaryStartup.cpp b/kernel/src/startup/secondaryStartup.cpp deleted file mode 100644 index 76858fc..0000000 --- a/kernel/src/startup/secondaryStartup.cpp +++ /dev/null @@ -1,90 +0,0 @@ -asm(R"( -.global __16bitStartup -.global __started_info -.global __stack_ptr -.global __page_table_ptr -.global __gdt_addr_ptr - -.extern __secondary_init - -.section .trampoline_text, "ax" -.align 0x1000 -.code16 -__16bitStartup: - cli - movw $1, __started_info - mov $__tmp_gdt_ptr, %eax - lgdtl (%eax) - mov %cr0, %eax - or $1, %eax - mov %eax, %cr0 - ljmp $0x08, $__tmp32BitStartup -stop: - hlt - jmp stop - -.code32 -__tmp32BitStartup: - mov $0x10, %eax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - mov __page_table_ptr, %eax - mov %eax, %cr3 - - mov %cr4, %eax - or $(0x1 << 5), %eax - mov %eax, %cr4 - - mov $0xC0000080, %ecx - rdmsr - or $((0x1 << 8) | (0x1 << 11)), %eax - wrmsr - - mov %cr0, %eax - or $(0x1 << 31), %eax - mov %eax, %cr0 - - mov $__gdt_addr_ptr, %eax - mov (%eax), %eax - lgdt (%eax) - jmp $0b1000, $__tmp64BitStartup -.code64 -__tmp64BitStartup: - mov $0b10000, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - mov __stack_ptr, %rsp - movq $2, __started_info - movabsq $__secondary_init, %rax - jmp* %rax - -.section .trampoline_data, "aw" -.align 0x1000 -__started_info: -.quad 0 # write here 1 as soon as started, 2 as soon as in 64bit mode and all tmp resources released -__stack_ptr: -.quad 0 # pointer to top of stack -__page_table_ptr: -.quad 0 # value of l4 page table -__gdt_addr_ptr: -.quad 0 # pointer to gdt descriptor (limit word + base) to load before entering 64 bit mode -__tmp_stack: - .skip 0x1000 - .align 8 -__tmp_stack_end: - .quad 0 -__tmp_gdt: - .quad 0 # zero - .quad (0xFFFF) | (0xF << 48) | (1 << 43) | (1 << 44) | (1 << 47) | (1 << 54) | (1 << 55) # 32 bit code - .quad (0xFFFF) | (0xF << 48) | (1 << 41) | (1 << 44) | (1 << 47) | (1 << 54) | (1 << 55) # 32 bit data -__tmp_gdt_ptr: - .word __tmp_gdt_ptr - __tmp_gdt - 1 - .long __tmp_gdt -)");