From 05b7549a0f980efa33265a091a5174a78851ce05 Mon Sep 17 00:00:00 2001 From: Minep Date: Sat, 12 Mar 2022 01:21:58 +0000 Subject: [PATCH] Implement APIC, RTC, basic ACPI parser and timer support more flexible interrupt handler design rename the libc to klibc to avoid the confusion between user space and kernel space c std lib improved logging experience, the kprintf Some shitty workarounds on vm in order to make my ACPI parser happy Not trust on multiboot's mem map anymore! --- lunaix-os/.gitignore | 3 +- lunaix-os/.vscode/launch.json | 2 +- lunaix-os/arch/x86/boot.S | 2 +- lunaix-os/bochs.cfg | 2 + lunaix-os/config/make-cc | 5 +- lunaix-os/hal/acpi/acpi.c | 129 ++++++++++ lunaix-os/hal/acpi/parser/madt_parser.c | 40 ++++ lunaix-os/hal/acpi/parser/madt_parser.h | 14 ++ lunaix-os/hal/apic.c | 221 ++++++++++++++++++ lunaix-os/hal/cpu.c | 26 +++ lunaix-os/hal/ioapic.c | 59 +++++ lunaix-os/hal/rtc.c | 79 ++++++- lunaix-os/includes/arch/x86/boot/multiboot.h | 3 + lunaix-os/includes/arch/x86/idt.h | 5 +- lunaix-os/includes/arch/x86/interrupts.h | 49 +++- lunaix-os/includes/hal/acpi/acpi.h | 47 ++++ lunaix-os/includes/hal/acpi/madt.h | 88 +++++++ lunaix-os/includes/hal/acpi/sdt.h | 26 +++ lunaix-os/includes/hal/apic.h | 82 +++++++ lunaix-os/includes/hal/cpu.h | 15 +- lunaix-os/includes/hal/ioapic.h | 37 +++ lunaix-os/includes/hal/pic.h | 9 + lunaix-os/includes/hal/rtc.h | 17 ++ lunaix-os/includes/klibc/stdio.h | 11 + lunaix-os/includes/{libc => klibc}/stdlib.h | 0 lunaix-os/includes/{libc => klibc}/string.h | 3 + lunaix-os/includes/libc/stdio.h | 12 - lunaix-os/includes/lunaix/mm/kalloc.h | 2 +- lunaix-os/includes/lunaix/mm/vmm.h | 10 + lunaix-os/includes/lunaix/spike.h | 9 +- lunaix-os/includes/lunaix/syslog.h | 29 +++ lunaix-os/includes/lunaix/tty/tty.h | 3 + lunaix-os/kernel/asm/x86/idt.c | 7 + lunaix-os/kernel/asm/x86/interrupt.S | 11 +- lunaix-os/kernel/asm/x86/interrupts.c | 87 ++++--- lunaix-os/kernel/asm/x86/intr_routines.c | 96 ++++++++ lunaix-os/kernel/asm/x86/prologue.S | 2 +- lunaix-os/kernel/k_init.c | 124 ++++++++-- lunaix-os/kernel/k_main.c | 25 +- lunaix-os/kernel/kprintf.c | 60 +++++ lunaix-os/kernel/mm/kalloc.c | 15 +- lunaix-os/kernel/mm/vmm.c | 23 +- lunaix-os/kernel/spike.c | 12 +- lunaix-os/kernel/tty/tty.c | 7 +- .../libs/{libc => klibc}/stdio/sprintf.c | 23 +- lunaix-os/libs/{libc => klibc}/stdlib/itoa.c | 2 +- lunaix-os/libs/{libc => klibc}/string/mem.c | 2 +- .../libs/{libc => klibc}/string/strchr.c | 2 +- lunaix-os/libs/klibc/string/strcpy.c | 23 ++ .../libs/{libc => klibc}/string/strlen.c | 2 +- lunaix-os/libs/libc/stdio/printf.c | 18 -- lunaix-os/libs/libc/string/strcpy.c | 14 -- lunaix-os/makefile | 12 +- 53 files changed, 1423 insertions(+), 183 deletions(-) create mode 100644 lunaix-os/hal/acpi/acpi.c create mode 100644 lunaix-os/hal/acpi/parser/madt_parser.c create mode 100644 lunaix-os/hal/acpi/parser/madt_parser.h create mode 100644 lunaix-os/hal/apic.c create mode 100644 lunaix-os/hal/ioapic.c create mode 100644 lunaix-os/includes/hal/acpi/acpi.h create mode 100644 lunaix-os/includes/hal/acpi/madt.h create mode 100644 lunaix-os/includes/hal/acpi/sdt.h create mode 100644 lunaix-os/includes/hal/apic.h create mode 100644 lunaix-os/includes/hal/ioapic.h create mode 100644 lunaix-os/includes/klibc/stdio.h rename lunaix-os/includes/{libc => klibc}/stdlib.h (100%) rename lunaix-os/includes/{libc => klibc}/string.h (89%) delete mode 100644 lunaix-os/includes/libc/stdio.h create mode 100644 lunaix-os/includes/lunaix/syslog.h create mode 100644 lunaix-os/kernel/asm/x86/intr_routines.c create mode 100644 lunaix-os/kernel/kprintf.c rename lunaix-os/libs/{libc => klibc}/stdio/sprintf.c (92%) rename lunaix-os/libs/{libc => klibc}/stdlib/itoa.c (97%) rename lunaix-os/libs/{libc => klibc}/string/mem.c (97%) rename lunaix-os/libs/{libc => klibc}/string/strchr.c (89%) create mode 100644 lunaix-os/libs/klibc/string/strcpy.c rename lunaix-os/libs/{libc => klibc}/string/strlen.c (90%) delete mode 100644 lunaix-os/libs/libc/stdio/printf.c delete mode 100644 lunaix-os/libs/libc/string/strcpy.c diff --git a/lunaix-os/.gitignore b/lunaix-os/.gitignore index 41eb114..2b8398e 100644 --- a/lunaix-os/.gitignore +++ b/lunaix-os/.gitignore @@ -2,4 +2,5 @@ build/ playground/ .vscode/settings.json .vscode/*.log -.VSCodeCounter/ \ No newline at end of file +.VSCodeCounter/ +.idea diff --git a/lunaix-os/.vscode/launch.json b/lunaix-os/.vscode/launch.json index 1969f6d..6bbd277 100644 --- a/lunaix-os/.vscode/launch.json +++ b/lunaix-os/.vscode/launch.json @@ -7,7 +7,7 @@ { "type": "gdb", "request": "attach", - "name": "Attach to QEMU", + "name": "LunaixOS", "executable": "${workspaceRoot}/build/bin/lunaix.bin", "target": ":1234", "remote": true, diff --git a/lunaix-os/arch/x86/boot.S b/lunaix-os/arch/x86/boot.S index 7bf3005..8ba78cc 100644 --- a/lunaix-os/arch/x86/boot.S +++ b/lunaix-os/arch/x86/boot.S @@ -18,7 +18,7 @@ /* 根据System V ABI,栈地址必须16字节对齐 */ /* 这里只是一个临时栈,在_hhk_init里面我们会初始化内核专用栈 */ stack_bottom: - .skip 16318, 0 + .skip 16318 * 2, 0 stack_top: diff --git a/lunaix-os/bochs.cfg b/lunaix-os/bochs.cfg index 216cad6..1e9f946 100644 --- a/lunaix-os/bochs.cfg +++ b/lunaix-os/bochs.cfg @@ -2,4 +2,6 @@ ata0-master: type=cdrom, path="build/lunaix.iso", status=inserted memory: guest=1024, host=1024 +clock: sync=realtime, time0=utc, rtc_sync=1 + boot: cdrom \ No newline at end of file diff --git a/lunaix-os/config/make-cc b/lunaix-os/config/make-cc index 643b4ee..00ed9f3 100644 --- a/lunaix-os/config/make-cc +++ b/lunaix-os/config/make-cc @@ -1,5 +1,6 @@ -CC := i686-elf-gcc -AS := i686-elf-as +TOOLCHAIN := ${HOME}/opt/cross-compiler/bin/ +CC := ${TOOLCHAIN}i686-elf-gcc +AS := ${TOOLCHAIN}i686-elf-as ARCH_OPT := -D__ARCH_IA32 diff --git a/lunaix-os/hal/acpi/acpi.c b/lunaix-os/hal/acpi/acpi.c new file mode 100644 index 0000000..4781219 --- /dev/null +++ b/lunaix-os/hal/acpi/acpi.c @@ -0,0 +1,129 @@ +#include + +#include +#include +#include + +#include + +#include "parser/madt_parser.h" + +acpi_context* toc = NULL; + +LOG_MODULE("ACPI") + +int +acpi_rsdp_validate(acpi_rsdp_t* rsdp); + +acpi_rsdp_t* +acpi_locate_rsdp(multiboot_info_t* mb_info); + +int +acpi_init(multiboot_info_t* mb_info) +{ + acpi_rsdp_t* rsdp = acpi_locate_rsdp(mb_info); + + assert_msg(rsdp, "Fail to locate ACPI_RSDP"); + assert_msg(acpi_rsdp_validate(rsdp), "Invalid ACPI_RSDP (checksum failed)"); + + kprintf(KINFO "RSDP found at %p, RSDT: %p\n", rsdp, rsdp->rsdt); + + acpi_rsdt_t* rsdt = rsdp->rsdt; + + toc = lxcalloc(1, sizeof(acpi_context)); + assert_msg(toc, "Fail to create ACPI context"); + + strncpy(toc->oem_id, rsdt->header.oem_id, 6); + toc->oem_id[6] = '\0'; + + size_t entry_n = (rsdt->header.length - sizeof(acpi_sdthdr_t)) >> 2; + for (size_t i = 0; i < entry_n; i++) { + acpi_sdthdr_t* sdthdr = ((acpi_apic_t**)&(rsdt->entry))[i]; + switch (sdthdr->signature) { + case ACPI_MADT_SIG: + madt_parse((acpi_madt_t*)sdthdr, toc); + break; + default: + break; + } + } + + kprintf(KINFO "OEM: %s\n", toc->oem_id); + kprintf(KINFO "IOAPIC address: %p\n", toc->madt.ioapic->ioapic_addr); + kprintf(KINFO "APIC address: %p\n", toc->madt.apic_addr); + + for (size_t i = 0; i < 24; i++) { + acpi_intso_t* intso = toc->madt.irq_exception[i]; + if (!intso) + continue; + + kprintf(KINFO "IRQ #%u -> GSI #%u\n", intso->source, intso->gsi); + } +} + +acpi_context* +acpi_get_context() +{ + assert_msg(toc, "ACPI is not initialized"); + return toc; +} + +int +acpi_rsdp_validate(acpi_rsdp_t* rsdp) +{ + uint8_t sum = 0; + uint8_t* rsdp_ptr = (uint8_t*)rsdp; + for (size_t i = 0; i < 20; i++) { + sum += *(rsdp_ptr + i); + } + + return sum == 0; +} + +#define VIRTUAL_BOX_PROBLEM + +acpi_rsdp_t* +acpi_locate_rsdp(multiboot_info_t* mb_info) +{ + acpi_rsdp_t* rsdp = NULL; + + // You can't trust memory map from multiboot in virtual box! + // They put ACPI RSDP in the FUCKING 0xe0000 !!! + // Which is reported to be free area bt multiboot! + // SWEET CELESTIA!!! +#ifndef VIRTUAL_BOX_PROBLEM + multiboot_memory_map_t* mmap = (multiboot_memory_map_t*)mb_info->mmap_addr; + for (size_t i = 0, j = 0; j < mb_info->mmap_length && !rsdp; + i++, j += MB_MMAP_ENTRY_SIZE) { + multiboot_memory_map_t entry = mmap[i]; + if (entry.type != MULTIBOOT_MEMORY_RESERVED || + entry.addr_low > 0x100000) { + continue; + } + + uint8_t* mem_start = entry.addr_low & ~0xf; + size_t len = entry.len_low; + for (size_t j = 0; j < len; j += 16) { + uint32_t sig_low = *((uint32_t*)(mem_start + j)); + // uint32_t sig_high = *((uint32_t*)(mem_start+j) + 1); + if (sig_low == ACPI_RSDP_SIG_L) { + rsdp = (acpi_rsdp_t*)(mem_start + j); + break; + } + } + } +#else + // You know what, I just search the entire 1MiB for Celestia's sake. + uint8_t* mem_start = 0x4000; + for (size_t j = 0; j < 0x100000; j += 16) { + uint32_t sig_low = *((uint32_t*)(mem_start + j)); + // uint32_t sig_high = *((uint32_t*)(mem_start+j) + 1); + if (sig_low == ACPI_RSDP_SIG_L) { + rsdp = (acpi_rsdp_t*)(mem_start + j); + break; + } + } +#endif + + return rsdp; +} \ No newline at end of file diff --git a/lunaix-os/hal/acpi/parser/madt_parser.c b/lunaix-os/hal/acpi/parser/madt_parser.c new file mode 100644 index 0000000..baa866c --- /dev/null +++ b/lunaix-os/hal/acpi/parser/madt_parser.c @@ -0,0 +1,40 @@ +#include "madt_parser.h" +#include + +void +madt_parse(acpi_madt_t* madt, acpi_context* toc) +{ + toc->madt.apic_addr = madt->apic_addr; + + // FUTURE: make madt.{apic,ioapic} as array or linked list. + uint8_t* ics_start = (uint8_t*)((uintptr_t)madt + sizeof(acpi_madt_t)); + uintptr_t ics_end = (uintptr_t)madt + madt->header.length; + + // Cosidering only one IOAPIC present (max 24 pins) + // FIXME: use hash table instead + toc->madt.irq_exception = + (acpi_intso_t*)lxcalloc(24, sizeof(acpi_intso_t*)); + + size_t so_idx = 0; + while (ics_start < ics_end) { + acpi_ics_hdr_t* entry = (acpi_ics_hdr_t*)ics_start; + switch (entry->type) { + case ACPI_MADT_LAPIC: + toc->madt.apic = (acpi_apic_t*)entry; + break; + case ACPI_MADT_IOAPIC: + toc->madt.ioapic = (acpi_ioapic_t*)entry; + break; + case ACPI_MADT_INTSO: + { + acpi_intso_t* intso_tbl = (acpi_intso_t*)entry; + toc->madt.irq_exception[intso_tbl->source] = intso_tbl; + break; + } + default: + break; + } + + ics_start += entry->length; + } +} \ No newline at end of file diff --git a/lunaix-os/hal/acpi/parser/madt_parser.h b/lunaix-os/hal/acpi/parser/madt_parser.h new file mode 100644 index 0000000..6b15296 --- /dev/null +++ b/lunaix-os/hal/acpi/parser/madt_parser.h @@ -0,0 +1,14 @@ +#ifndef __LUNAIX_PARSER_MADT_PARSER_H +#define __LUNAIX_PARSER_MADT_PARSER_H + +#include + +/** + * @brief Parse the MADT and populated into main TOC + * + * @param rsdt RSDT + * @param toc The main TOC + */ +void madt_parse(acpi_madt_t* madt, acpi_context* toc); + +#endif /* __LUNAIX_PARSER_MADT_PARSER_H */ diff --git a/lunaix-os/hal/apic.c b/lunaix-os/hal/apic.c new file mode 100644 index 0000000..c74d3f9 --- /dev/null +++ b/lunaix-os/hal/apic.c @@ -0,0 +1,221 @@ +/** + * @file apic.c + * @author Lunaixsky + * @brief Abstraction for Advanced Programmable Interrupts Controller (APIC) + * @version 0.1 + * @date 2022-03-06 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include +#include +#include + +#include + +#include +#include + +LOG_MODULE("APIC") + +void +apic_setup_timer(); + +void +apic_setup_lvts(); + +void +init_apic() +{ + // ensure that external interrupt is disabled + cpu_disable_interrupt(); + + // Make sure the APIC is there + // FUTURE: Use 8259 as fallback + assert_msg(cpu_has_apic(), "No APIC detected!"); + + // As we are going to use APIC, disable the old 8259 PIC + pic_disable(); + + // Hardware enable the APIC + // By setting bit 11 of IA32_APIC_BASE register + // Note: After this point, you can't disable then re-enable it until a reset (i.e., reboot) + asm volatile ( + "movl %0, %%ecx\n" + "rdmsr\n" + "orl %1, %%eax\n" + "wrmsr\n" + ::"i"(IA32_APIC_BASE_MSR), "i"(IA32_APIC_ENABLE) + : "eax", "ecx", "edx" + ); + + // Print the basic information of our current local APIC + uint32_t apic_id = apic_read_reg(APIC_IDR) >> 24; + uint32_t apic_ver = apic_read_reg(APIC_VER); + + kprintf(KINFO "ID: %x, Version: %x, Max LVT: %u\n", + apic_id, + apic_ver & 0xff, + (apic_ver >> 16) & 0xff); + + // initialize the local vector table (LVT) + apic_setup_lvts(); + + // initialize priority registers + + // set the task priority to the lowest possible, so all external interrupts are acceptable + // Note, the lowest possible priority class is 2, not 0, 1, as they are reserved for + // internal interrupts (vector 0-31, and each p-class resposible for 16 vectors). + // See Intel Manual Vol. 3A, 10-29 + apic_write_reg(APIC_TPR, APIC_PRIORITY(2, 0)); + + // enable APIC + uint32_t spiv = apic_read_reg(APIC_SPIVR); + + // install our handler for spurious interrupt. + spiv = (spiv & ~0xff) | APIC_SPIV_APIC_ENABLE | APIC_SPIV_IV; + apic_write_reg(APIC_SPIVR, spiv); + + // setup timer and performing calibrations + apic_setup_timer(); +} + +#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector) + +// Pin LINT#1 is configured for relaying NMI, but we masked it here as I think +// it is too early for that +// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14) +#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE) +#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector) +#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) + +void +apic_setup_lvts() +{ + apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV)); + apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1); + apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV)); +} + +void +temp_intr_routine_rtc_tick(const isr_param* param); + +void +temp_intr_routine_apic_timer(const isr_param* param); + +void +test_timer(const isr_param* param); + +uint32_t apic_timer_base_freq = 0; + +// Don't optimize them! Took me an half hour to figure that out... + +volatile uint32_t rtc_counter = 0; +volatile uint8_t apic_timer_done = 0; + +#define APIC_CALIBRATION_CONST 0x100000 + +void +apic_setup_timer() +{ + cpu_disable_interrupt(); + + // Setup APIC timer + + // Setup a one-shot timer, we will use this to measure the bus speed. So we can + // then calibrate apic timer to work at *nearly* accurate hz + apic_write_reg(APIC_TIMER_LVT, LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_ONESHOT)); + + // Set divider to 64 + apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64); + + /* + Timer calibration process - measure the APIC timer base frequency + + step 1: setup a temporary isr for RTC timer which trigger at each tick (1024Hz) + step 2: setup a temporary isr for #APIC_TIMER_IV + step 3: setup the divider, APIC_TIMER_DCR + step 4: Startup RTC timer + step 5: Write a large value, v, to APIC_TIMER_ICR to start APIC timer + (this must be followed immediately after step 4) + step 6: issue a write to EOI and clean up. + + When the APIC ICR counting down to 0 #APIC_TIMER_IV triggered, save the rtc timer's + counter, k, and disable RTC timer immediately (although the RTC interrupts should be + blocked by local APIC as we are currently busy on handling #APIC_TIMER_IV) + + So the apic timer frequency F_apic in Hz can be calculate as + v / F_apic = k / 1024 + => F_apic = v / k * 1024 + + */ + + apic_timer_base_freq = 0; + rtc_counter = 0; + apic_timer_done = 0; + + intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); + intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); + + + rtc_enable_timer(); // start RTC timer + apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); // start APIC timer + + // enable interrupt, just for our RTC start ticking! + cpu_enable_interrupt(); + + wait_until(apic_timer_done); + + // cpu_disable_interrupt(); + + assert_msg(apic_timer_base_freq, "Fail to initialize timer"); + + kprintf(KINFO "Timer base frequency: %u Hz\n", apic_timer_base_freq); + + // cleanup + intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); + intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); + + // TODO: now setup timer with our custom frequency which we can derived from the base frequency + // we measured + + apic_write_reg(APIC_TIMER_LVT, LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC)); + intr_subscribe(APIC_TIMER_IV, test_timer); + + apic_write_reg(APIC_TIMER_ICR, apic_timer_base_freq); +} + +volatile rtc_datetime datetime; + +void +test_timer(const isr_param* param) { + + rtc_get_datetime(&datetime); + + kprintf(KWARN "%u/%02u/%02u %02u:%02u:%02u\r", + datetime.year, + datetime.month, + datetime.day, + datetime.hour, + datetime.minute, + datetime.second); +} + +void +temp_intr_routine_rtc_tick(const isr_param* param) { + rtc_counter++; + + // dummy read on register C so RTC can send anther interrupt + // This strange behaviour observed in virtual box & bochs + (void) rtc_read_reg(RTC_REG_C); +} + +void +temp_intr_routine_apic_timer(const isr_param* param) { + apic_timer_base_freq = APIC_CALIBRATION_CONST / rtc_counter * RTC_TIMER_BASE_FREQUENCY; + apic_timer_done = 1; + + rtc_disable_timer(); +} \ No newline at end of file diff --git a/lunaix-os/hal/cpu.c b/lunaix-os/hal/cpu.c index ad1b0a5..ab5432c 100644 --- a/lunaix-os/hal/cpu.c +++ b/lunaix-os/hal/cpu.c @@ -38,4 +38,30 @@ void cpu_get_brand(char* brand_out) { j+=4; } brand_out[48] = '\0'; +} + + +int +cpu_has_apic() { + // reference: Intel manual, section 10.4.2 + reg32 eax = 0, ebx = 0, edx = 0, ecx = 0; + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + + return (edx & 0x100); +} + +void +cpu_rdmsr(uint32_t msr_idx, uint32_t* reg_high, uint32_t* reg_low) +{ + uint32_t h = 0, l = 0; + asm volatile("rdmsr" : "=d"(h), "=a"(l) : "c"(msr_idx)); + + *reg_high = h; + *reg_low = l; +} + +void +cpu_wrmsr(uint32_t msr_idx, uint32_t reg_high, uint32_t reg_low) +{ + asm volatile("wrmsr" : : "d"(reg_high), "a"(reg_low), "c"(msr_idx)); } \ No newline at end of file diff --git a/lunaix-os/hal/ioapic.c b/lunaix-os/hal/ioapic.c new file mode 100644 index 0000000..80ab13b --- /dev/null +++ b/lunaix-os/hal/ioapic.c @@ -0,0 +1,59 @@ +#include +#include +#include + + +#define IOAPIC_REG_SEL *((volatile uint32_t*)(IOAPIC_BASE_VADDR + IOAPIC_IOREGSEL)) +#define IOAPIC_REG_WIN *((volatile uint32_t*)(IOAPIC_BASE_VADDR + IOAPIC_IOWIN)) + +uint8_t +ioapic_get_irq(acpi_context* acpi_ctx, uint8_t old_irq); + +void +ioapic_init() { + // Remapping the IRQs + + acpi_context* acpi_ctx = acpi_get_context(); + + // Remap the IRQ 8 (rtc timer's vector) to RTC_TIMER_IV in ioapic + // (Remarks IRQ 8 is pin INTIN8) + // See IBM PC/AT Technical Reference 1-10 for old RTC IRQ + // See Intel's Multiprocessor Specification for IRQ - IOAPIC INTIN mapping config. + + // The ioapic_get_irq is to make sure we capture those overriden IRQs + + // PC_AT_IRQ_RTC -> RTC_TIMER_IV, fixed, edge trigged, polarity=high, physical, APIC ID 0 + ioapic_redirect(ioapic_get_irq(acpi_ctx, PC_AT_IRQ_RTC), RTC_TIMER_IV, 0, IOAPIC_DELMOD_FIXED); +} + +uint8_t +ioapic_get_irq(acpi_context* acpi_ctx, uint8_t old_irq) { + if (old_irq >= 24) { + return old_irq; + } + acpi_intso_t* int_override = acpi_ctx->madt.irq_exception[old_irq]; + return int_override ? (uint8_t)int_override->gsi : old_irq; +} + +void +ioapic_write(uint8_t sel, uint32_t val) { + IOAPIC_REG_SEL = sel; + IOAPIC_REG_WIN = val; +} + +uint32_t +ioapic_read(uint8_t sel) { + IOAPIC_REG_SEL = sel; + return IOAPIC_REG_WIN; +} + +void +ioapic_redirect(uint8_t irq, uint8_t vector, uint8_t dest, uint32_t flags) { + uint8_t reg_sel = IOAPIC_IOREDTBL_BASE + irq * 2; + + // Write low 32 bits + ioapic_write(reg_sel, (vector | flags) & 0x1FFFF); + + // Write high 32 bits + ioapic_write(reg_sel + 1, (dest << 24)); +} \ No newline at end of file diff --git a/lunaix-os/hal/rtc.c b/lunaix-os/hal/rtc.c index 319ad65..60a1aed 100644 --- a/lunaix-os/hal/rtc.c +++ b/lunaix-os/hal/rtc.c @@ -1,4 +1,25 @@ +/** + * @file rtc.c + * @author Lunaixsky + * @brief RTC & CMOS abstraction. Reference: MC146818A & Intel Series 500 PCH datasheet + * @version 0.1 + * @date 2022-03-07 + * + * @copyright Copyright (c) 2022 + * + */ #include +#include + +void +rtc_init() { + uint8_t regA = rtc_read_reg(RTC_REG_A | WITH_NMI_DISABLED); + regA = (regA & ~0x7f) | RTC_FREQUENCY_1024HZ | RTC_DIVIDER_33KHZ; + rtc_write_reg(RTC_REG_A | WITH_NMI_DISABLED, regA); + + // Make sure the rtc timer is disabled by default + rtc_disable_timer(); +} uint8_t rtc_read_reg(uint8_t reg_selector) @@ -7,22 +28,47 @@ rtc_read_reg(uint8_t reg_selector) return io_inb(RTC_TARGET_PORT); } +void +rtc_write_reg(uint8_t reg_selector, uint8_t val) +{ + io_outb(RTC_INDEX_PORT, reg_selector); + io_outb(RTC_TARGET_PORT, val); +} + uint8_t bcd2dec(uint8_t bcd) { - return (bcd >> 4) * 10 + (bcd & 0x0f); + return ((bcd & 0xF0) >> 1) + ((bcd & 0xF0) >> 3) + (bcd & 0xf); +} + +int +rtc_date_same(rtc_datetime* a, rtc_datetime* b) { + return a->year == b->year && + a->month == b->month && + a->day == b->day && + a->weekday == b->weekday && + a->minute == b->minute && + a->second == b->second; } void rtc_get_datetime(rtc_datetime* datetime) { - datetime->year = rtc_read_reg(RTC_REG_YRS); - datetime->month = rtc_read_reg(RTC_REG_MTH); - datetime->day = rtc_read_reg(RTC_REG_DAY); - datetime->weekday = rtc_read_reg(RTC_REG_WDY); - datetime->hour = rtc_read_reg(RTC_REG_HRS); - datetime->minute = rtc_read_reg(RTC_REG_MIN); - datetime->second = rtc_read_reg(RTC_REG_SEC); + rtc_datetime current; + + do + { + while (rtc_read_reg(RTC_REG_A) & 0x80); + memcpy(¤t, datetime, sizeof(rtc_datetime)); + + datetime->year = rtc_read_reg(RTC_REG_YRS); + datetime->month = rtc_read_reg(RTC_REG_MTH); + datetime->day = rtc_read_reg(RTC_REG_DAY); + datetime->weekday = rtc_read_reg(RTC_REG_WDY); + datetime->hour = rtc_read_reg(RTC_REG_HRS); + datetime->minute = rtc_read_reg(RTC_REG_MIN); + datetime->second = rtc_read_reg(RTC_REG_SEC); + } while (!rtc_date_same(datetime, ¤t)); uint8_t regbv = rtc_read_reg(RTC_REG_B); @@ -38,10 +84,21 @@ rtc_get_datetime(rtc_datetime* datetime) // To 24 hour format - if (!RTC_24HRS_ENCODED(regbv)) { - datetime->hour = (datetime->hour >> 7) ? (12 + datetime->hour & 0x80) - : (datetime->hour & 0x80); + if (!RTC_24HRS_ENCODED(regbv) && (datetime->hour >> 7)) { + datetime->hour = (12 + datetime->hour & 0x80); } datetime->year += RTC_CURRENT_CENTRY * 100; +} + +void +rtc_enable_timer() { + uint8_t regB = rtc_read_reg(RTC_REG_B | WITH_NMI_DISABLED); + rtc_write_reg(RTC_REG_B | WITH_NMI_DISABLED, regB | RTC_TIMER_ON); +} + +void +rtc_disable_timer() { + uint8_t regB = rtc_read_reg(RTC_REG_B | WITH_NMI_DISABLED); + rtc_write_reg(RTC_REG_B | WITH_NMI_DISABLED, regB & ~RTC_TIMER_ON); } \ No newline at end of file diff --git a/lunaix-os/includes/arch/x86/boot/multiboot.h b/lunaix-os/includes/arch/x86/boot/multiboot.h index a019686..aca8f43 100644 --- a/lunaix-os/includes/arch/x86/boot/multiboot.h +++ b/lunaix-os/includes/arch/x86/boot/multiboot.h @@ -225,5 +225,8 @@ struct multiboot_apm_info multiboot_uint16_t cseg_16_len; multiboot_uint16_t dseg_len; }; + +#define MB_MMAP_ENTRY_SIZE sizeof(multiboot_memory_map_t) + #endif #endif \ No newline at end of file diff --git a/lunaix-os/includes/arch/x86/idt.h b/lunaix-os/includes/arch/x86/idt.h index af0ae7d..294cb27 100644 --- a/lunaix-os/includes/arch/x86/idt.h +++ b/lunaix-os/includes/arch/x86/idt.h @@ -1,7 +1,8 @@ #ifndef __LUNAIX_IDT_H -#define __LUNAIX_IDT_H 1 +#define __LUNAIX_IDT_H #define IDT_ATTR(dpl) ((0x70 << 5) | (dpl & 3) << 13 | 1 << 15) void _init_idt(); -#endif \ No newline at end of file + +#endif /* __LUNAIX_IDT_H */ \ No newline at end of file diff --git a/lunaix-os/includes/arch/x86/interrupts.h b/lunaix-os/includes/arch/x86/interrupts.h index 3ac415a..4ffc86f 100644 --- a/lunaix-os/includes/arch/x86/interrupts.h +++ b/lunaix-os/includes/arch/x86/interrupts.h @@ -25,8 +25,22 @@ #define FAULT_VIRTUALIZATION_EXCEPTION 20 #define FAULT_CONTROL_PROTECTION 21 +// LunaixOS related #define LUNAIX_SYS_PANIC 32 +#define EX_INTERRUPT_BEGIN 200 +// APIC related +#define APIC_ERROR_IV 200 +#define APIC_LINT0_IV 201 +#define APIC_TIMER_IV 202 +#define APIC_SPIV_IV 203 + +#define RTC_TIMER_IV 210 + + +#define PC_AT_IRQ_RTC 8 +#define PC_AT_IRQ_KBD_BUF_FULL 1 + #ifndef __ASM__ #include typedef struct { @@ -40,6 +54,9 @@ typedef struct { unsigned int ss; } __attribute__((packed)) isr_param; +typedef void (*int_subscriber)(isr_param*); + +#pragma region ISR_DECLARATION void _asm_isr0(); @@ -106,12 +123,40 @@ _asm_isr20(); void _asm_isr21(); - void _asm_isr32(); void -interrupt_handler(isr_param* param); +_asm_isr200(); + +void +_asm_isr201(); + +void +_asm_isr202(); + +void +_asm_isr203(); + +void +_asm_isr210(); + +#pragma endregion + +void +intr_subscribe(const uint8_t vector, int_subscriber); + +void +intr_unsubscribe(const uint8_t vector, int_subscriber); + +void +intr_set_fallback_handler(int_subscriber); + +void +intr_handler(isr_param* param); + +void +intr_routine_init(); #endif diff --git a/lunaix-os/includes/hal/acpi/acpi.h b/lunaix-os/includes/hal/acpi/acpi.h new file mode 100644 index 0000000..8926244 --- /dev/null +++ b/lunaix-os/includes/hal/acpi/acpi.h @@ -0,0 +1,47 @@ +#ifndef __LUNAIX_ACPI_ACPI_H +#define __LUNAIX_ACPI_ACPI_H + +#include +#include +#include + +#include "sdt.h" +#include "madt.h" + +#define ACPI_RSDP_SIG_L 0x20445352 // 'RSD ' +#define ACPI_RSDP_SIG_H 0x20525450 // 'PTR ' + +#define ACPI_MADT_SIG 0x43495041 // 'APIC' + +typedef struct { + uint32_t signature_l; + uint32_t signature_h; + uint8_t chksum; + uint8_t oem_id[6]; + // Revision + uint8_t rev; + acpi_rsdt_t* rsdt; + uint32_t length; + acpi_sdthdr_t* xsdt; + uint8_t x_chksum; + char reserved[3]; // Reserved field +} __attribute__((packed)) acpi_rsdp_t; + +/** + * @brief Main TOC of ACPI tables, provide hassle-free access of ACPI info. + * + */ +typedef struct +{ + // Make it as null terminated + char oem_id[7]; + acpi_madt_toc_t madt; +} acpi_context; + +int +acpi_init(multiboot_info_t* mb_info); + +acpi_context* +acpi_get_context(); + +#endif /* __LUNAIX_ACPI_ACPI_H */ diff --git a/lunaix-os/includes/hal/acpi/madt.h b/lunaix-os/includes/hal/acpi/madt.h new file mode 100644 index 0000000..ca75d08 --- /dev/null +++ b/lunaix-os/includes/hal/acpi/madt.h @@ -0,0 +1,88 @@ +#ifndef __LUNAIX_ACPI_MADT_H +#define __LUNAIX_ACPI_MADT_H + +#include "sdt.h" + +#define ACPI_MADT_LAPIC 0x0 // Local APIC +#define ACPI_MADT_IOAPIC 0x1 // I/O APIC +#define ACPI_MADT_INTSO 0x2 // Interrupt Source Override + +/** + * @brief ACPI Interrupt Controller Structure (ICS) Header + * + */ +typedef struct +{ + uint8_t type; + uint8_t length; +} __attribute__((packed)) acpi_ics_hdr_t; + +/** + * @brief ACPI Processor Local APIC Structure (PLAS) + * This structure tell information about our Local APIC per processor. Including + * the MMIO addr. + * + */ +typedef struct +{ + acpi_ics_hdr_t header; + uint8_t processor_id; + uint8_t apic_id; + uint32_t flags; +} __attribute__((packed)) acpi_apic_t; + +/** + * @brief ACPI IO APIC Structure (IOAS) + * + * This structure tell information about our I/O APIC on motherboard. Including + * the MMIO addr. + * + */ +typedef struct +{ + acpi_ics_hdr_t header; + uint8_t ioapic_id; + uint8_t reserved; + uint32_t ioapic_addr; + // The global system interrupt offset for this IOAPIC. (Kind of IRQ offset for a slave IOAPIC) + uint32_t gis_offset; +} __attribute__((packed)) acpi_ioapic_t; + +/** + * @brief ACPI Interrupt Source Override (INTSO) + * + * According to the ACPI Spec, the IRQ config between APIC and 8259 PIC can be + * assumed to be identically mapped. However, some manufactures may have their + * own preference and hence expections may be introduced. This structure provide + * information on such exception. + * + */ +typedef struct +{ + acpi_ics_hdr_t header; + uint8_t bus; + // source, which is the original IRQ back in the era of IBM PC/AT, the 8259 + // PIC + uint8_t source; + // global system interrupt. The override of source in APIC mode + uint32_t gsi; + uint16_t flags; +} __attribute__((packed)) acpi_intso_t; + +typedef struct +{ + acpi_sdthdr_t header; + void* apic_addr; + uint32_t flags; + // Here is a bunch of packed ICS reside here back-to-back. +} __attribute__((packed)) acpi_madt_t; + +typedef struct +{ + void* apic_addr; + acpi_apic_t* apic; + acpi_ioapic_t* ioapic; + acpi_intso_t** irq_exception; +} acpi_madt_toc_t; + +#endif /* __LUNAIX_ACPI_MADT_H */ diff --git a/lunaix-os/includes/hal/acpi/sdt.h b/lunaix-os/includes/hal/acpi/sdt.h new file mode 100644 index 0000000..fb78097 --- /dev/null +++ b/lunaix-os/includes/hal/acpi/sdt.h @@ -0,0 +1,26 @@ +#ifndef __LUNAIX_ACPI_SDT_H +#define __LUNAIX_ACPI_SDT_H + +#include + +typedef struct +{ + uint32_t signature; + uint32_t length; + // Revision + uint8_t rev; + uint8_t chksum; + char oem_id[6]; + char oem_table_id[8]; + uint32_t oem_rev; + uint32_t vendor_id; + uint32_t vendor_rev; +} __attribute__((packed)) acpi_sdthdr_t; + +typedef struct +{ + acpi_sdthdr_t header; + acpi_sdthdr_t* entry; +} __attribute__((packed)) acpi_rsdt_t; + +#endif /* __LUNAIX_ACPI_SDT_H */ diff --git a/lunaix-os/includes/hal/apic.h b/lunaix-os/includes/hal/apic.h new file mode 100644 index 0000000..851e75e --- /dev/null +++ b/lunaix-os/includes/hal/apic.h @@ -0,0 +1,82 @@ +#ifndef __LUNAIX_APIC_H +#define __LUNAIX_APIC_H + +#include + +#define APIC_BASE_VADDR 0x1000 +#define __APIC_BASE_PADDR 0xFEE00000 + +#define IA32_APIC_BASE_MSR 0x1B +#define IA32_APIC_ENABLE 0x800 + +/* + * Common APIC memory-mapped registers + * Ref: Intel Manual, Vol. 3A, Table 10-1 + */ + +#define APIC_IDR 0x20 // ID Reg +#define APIC_VER 0x30 // Version Reg +#define APIC_TPR 0x80 // Task Priority +#define APIC_APR 0x90 // Arbitration Priority +#define APIC_PPR 0xA0 // Processor Priority +#define APIC_EOI 0xB0 // End-Of-Interrupt +#define APIC_RRD 0xC0 // Remote Read +#define APIC_LDR 0xD0 // Local Destination Reg +#define APIC_DFR 0xE0 // Destination Format Reg +#define APIC_SPIVR 0xF0 // Spurious Interrupt Vector Reg +#define APIC_ISR_BASE 0x100 // Base address for In-Service-Interrupt bitmap register (256bits) +#define APIC_TMR_BASE 0x180 // Base address for Trigger-Mode bitmap register (256bits) +#define APIC_IRR_BASE 0x200 // Base address for Interrupt-Request bitmap register (256bits) +#define APIC_ESR 0x280 // Error Status Reg +#define APIC_ICR_BASE 0x300 // Interrupt Command +#define APIC_LVT_LINT0 0x350 +#define APIC_LVT_LINT1 0x360 +#define APIC_LVT_ERROR 0x370 + +// APIC Timer specific +#define APIC_TIMER_LVT 0x320 +#define APIC_TIMER_ICR 0x380 // Initial Count +#define APIC_TIMER_CCR 0x390 // Current Count +#define APIC_TIMER_DCR 0x3E0 // Divide Configuration + +#define APIC_SPIV_FOCUS_DISABLE 0x200 +#define APIC_SPIV_APIC_ENABLE 0x100 +#define APIC_SPIV_EOI_BROADCAST 0x1000 + +#define LVT_DELIVERY_FIXED 0 +#define LVT_DELIVERY_NMI (0x4 << 8) +#define LVT_TRIGGER_EDGE (0 << 15) +#define LVT_TRIGGER_LEVEL (1 << 15) +#define LVT_MASKED (1 << 16) +#define LVT_TIMER_ONESHOT (0 << 17) +#define LVT_TIMER_PERIODIC (1 << 17) + +// Dividers for timer. See Intel Manual Vol3A. 10-17 (pp. 3207), Figure 10-10 +#define APIC_TIMER_DIV1 0b1011 +#define APIC_TIMER_DIV2 0b0000 +#define APIC_TIMER_DIV4 0b0001 +#define APIC_TIMER_DIV8 0b0010 +#define APIC_TIMER_DIV16 0b0011 +#define APIC_TIMER_DIV32 0b1000 +#define APIC_TIMER_DIV64 0b1001 +#define APIC_TIMER_DIV128 0b1010 + +#define APIC_PRIORITY(cls, subcls) (((cls) << 4) | (subcls)) + +#define apic_read_reg(reg) (*(uint32_t*)(APIC_BASE_VADDR + (reg))) +#define apic_write_reg(reg, val) (*(uint32_t*)(APIC_BASE_VADDR + (reg)) = (val)) + +void +init_apic(); + +/** + * @brief Tell the APIC that the handler for current interrupt is finished. + * This will issue a write action to EOI register. + * + */ +inline static void +apic_done_servicing() { + apic_write_reg(APIC_EOI, 0); +} + +#endif /* __LUNAIX_APIC_H */ diff --git a/lunaix-os/includes/hal/cpu.h b/lunaix-os/includes/hal/cpu.h index 1a3173b..bdb07c4 100644 --- a/lunaix-os/includes/hal/cpu.h +++ b/lunaix-os/includes/hal/cpu.h @@ -31,6 +31,9 @@ typedef struct void cpu_get_brand(char* brand_out); +int +cpu_has_apic(); + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreturn-type" static inline reg32 @@ -73,19 +76,19 @@ cpu_lcr3(reg32 v) static inline void cpu_invplg(void* va) { - asm("invlpg (%0)" ::"r"((uintptr_t)va) : "memory"); + asm volatile("invlpg (%0)" ::"r"((uintptr_t)va) : "memory"); } static inline void cpu_enable_interrupt() { - asm("sti"); + asm volatile("sti"); } static inline void cpu_disable_interrupt() { - asm("cli"); + asm volatile("cli"); } static inline void @@ -98,4 +101,10 @@ cpu_invtlb() : "r"(interm)); } +void +cpu_rdmsr(uint32_t msr_idx, uint32_t* reg_high, uint32_t* reg_low); + +void +cpu_wrmsr(uint32_t msr_idx, uint32_t reg_high, uint32_t reg_low); + #endif \ No newline at end of file diff --git a/lunaix-os/includes/hal/ioapic.h b/lunaix-os/includes/hal/ioapic.h new file mode 100644 index 0000000..a6974c2 --- /dev/null +++ b/lunaix-os/includes/hal/ioapic.h @@ -0,0 +1,37 @@ +#ifndef __LUNAIX_IOAPIC_H +#define __LUNAIX_IOAPIC_H + +#include + +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 +#define IOAPIC_IOREDTBL_BASE 0x10 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 + +#define IOAPIC_DELMOD_FIXED 0b000 +#define IOAPIC_DELMOD_LPRIO 0b001 +#define IOAPIC_DELMOD_NMI 0b100 + +#define IOAPIC_MASKED (1 << 16) +#define IOAPIC_TRIG_LEVEL (1 << 15) +#define IOAPIC_INTPOL_L (1 << 13) +#define IOAPIC_DESTMOD_LOGIC (1 << 11) + +#define IOAPIC_BASE_VADDR 0x2000 + +void +ioapic_init(); + +void +ioapic_write(uint8_t sel, uint32_t val); + +uint32_t +ioapic_read(uint8_t sel); + +void +ioapic_redirect(uint8_t irq, uint8_t vector, uint8_t dest, uint32_t flags); + +#endif /* __LUNAIX_IOAPIC_H */ diff --git a/lunaix-os/includes/hal/pic.h b/lunaix-os/includes/hal/pic.h index 20ee67b..54f03b0 100644 --- a/lunaix-os/includes/hal/pic.h +++ b/lunaix-os/includes/hal/pic.h @@ -2,4 +2,13 @@ #define __LUNAIX_PIC_H // TODO: PIC +static inline void +pic_disable() +{ + // ref: https://wiki.osdev.org/8259_PIC + asm volatile ("movb $0xff, %al\n" + "outb %al, $0xa1\n" + "outb %al, $0x21\n"); +} + #endif /* __LUNAIX_PIC_H */ diff --git a/lunaix-os/includes/hal/rtc.h b/lunaix-os/includes/hal/rtc.h index 69bf38e..0092171 100644 --- a/lunaix-os/includes/hal/rtc.h +++ b/lunaix-os/includes/hal/rtc.h @@ -26,6 +26,12 @@ #define RTC_BIN_ENCODED(reg) (reg & 0x04) #define RTC_24HRS_ENCODED(reg) (reg & 0x02) +#define RTC_TIMER_BASE_FREQUENCY 1024 +#define RTC_TIMER_ON 0x40 + +#define RTC_FREQUENCY_1024HZ 0b110 +#define RTC_DIVIDER_33KHZ (0b010 << 4) + typedef struct { uint32_t year; // use int32 as we need to store the 4-digit year @@ -37,11 +43,22 @@ typedef struct uint8_t second; } rtc_datetime; +void +rtc_init(); uint8_t rtc_read_reg(uint8_t reg_selector); +void +rtc_write_reg(uint8_t reg_selector, uint8_t val); + void rtc_get_datetime(rtc_datetime* datetime); +void +rtc_enable_timer(); + +void +rtc_disable_timer(); + #endif /* __LUNAIX_RTC_H */ diff --git a/lunaix-os/includes/klibc/stdio.h b/lunaix-os/includes/klibc/stdio.h new file mode 100644 index 0000000..07f4716 --- /dev/null +++ b/lunaix-os/includes/klibc/stdio.h @@ -0,0 +1,11 @@ +#ifndef __LUNAIX_STDIO_H +#define __LUNAIX_STDIO_H +#include +#include + +void +__sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs); + +void sprintf(char* buffer, char* fmt, ...); +void snprintf(char* buffer, size_t n, char* fmt, ...); +#endif /* __LUNAIX_STDIO_H */ diff --git a/lunaix-os/includes/libc/stdlib.h b/lunaix-os/includes/klibc/stdlib.h similarity index 100% rename from lunaix-os/includes/libc/stdlib.h rename to lunaix-os/includes/klibc/stdlib.h diff --git a/lunaix-os/includes/libc/string.h b/lunaix-os/includes/klibc/string.h similarity index 89% rename from lunaix-os/includes/libc/string.h rename to lunaix-os/includes/klibc/string.h index 7347de2..9cbcb31 100644 --- a/lunaix-os/includes/libc/string.h +++ b/lunaix-os/includes/klibc/string.h @@ -24,6 +24,9 @@ strcpy(char* dest, const char* src); size_t strnlen(const char* str, size_t max_len); +char* +strncpy(char* dest, const char* src, size_t n); + const char* strchr(const char* str, int character); diff --git a/lunaix-os/includes/libc/stdio.h b/lunaix-os/includes/libc/stdio.h deleted file mode 100644 index 65edb9e..0000000 --- a/lunaix-os/includes/libc/stdio.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __LUNAIX_STDIO_H -#define __LUNAIX_STDIO_H -#include - -#ifdef __LUNAIX_LIBC -void __sprintf_internal(char* buffer, char* fmt, va_list args); -#endif - -void sprintf(char* buffer, char* fmt, ...); -void printf(char* fmt, ...); - -#endif /* __LUNAIX_STDIO_H */ diff --git a/lunaix-os/includes/lunaix/mm/kalloc.h b/lunaix-os/includes/lunaix/mm/kalloc.h index d8d712d..6b97b3f 100644 --- a/lunaix-os/includes/lunaix/mm/kalloc.h +++ b/lunaix-os/includes/lunaix/mm/kalloc.h @@ -25,7 +25,7 @@ lxmalloc(size_t size); * @return void* */ void* -lxcalloc(size_t size); +lxcalloc(size_t n, size_t elem); /** * @brief Free the memory region allocated by kmalloc diff --git a/lunaix-os/includes/lunaix/mm/vmm.h b/lunaix-os/includes/lunaix/mm/vmm.h index 752f23c..844eb0e 100644 --- a/lunaix-os/includes/lunaix/mm/vmm.h +++ b/lunaix-os/includes/lunaix/mm/vmm.h @@ -67,6 +67,16 @@ vmm_alloc_page(void* va, pt_attr tattr); int vmm_alloc_pages(void* va, size_t sz, pt_attr tattr); +/** + * @brief 设置一个映射,如果映射已存在,则忽略。 + * + * @param va + * @param pa + * @param attr + */ +void +vmm_set_mapping(void* va, void* pa, pt_attr attr); + /** * @brief 删除一个映射 * diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index e39c611..9cf4b7f 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -31,10 +31,15 @@ inline static void spin() { } void __assert_fail(const char* expr, const char* file, unsigned int line) __attribute__((noinline, noreturn)); #else -#define assert(cond) //assert nothing -#define assert_msg(cond, msg) //assert nothing +#define assert(cond) (void)(cond); //assert nothing +#define assert_msg(cond, msg) (void)(cond); //assert nothing #endif +void panick(const char* msg); + + +#define wait_until(cond) while(!(cond)); +#define loop_until(cond) while(!(cond)); #endif /* __LUNAIX_SPIKE_H */ diff --git a/lunaix-os/includes/lunaix/syslog.h b/lunaix-os/includes/lunaix/syslog.h new file mode 100644 index 0000000..91e2003 --- /dev/null +++ b/lunaix-os/includes/lunaix/syslog.h @@ -0,0 +1,29 @@ +#ifndef __LUNAIX_SYSLOG_H +#define __LUNAIX_SYSLOG_H + +#include + +#define _LEVEL_INFO "0" +#define _LEVEL_WARN "1" +#define _LEVEL_ERROR "2" + +#define KINFO "\x1b" _LEVEL_INFO +#define KWARN "\x1b" _LEVEL_WARN +#define KERROR "\x1b" _LEVEL_ERROR + +#define LOG_MODULE(module) \ + static void kprintf(const char* fmt, ...) { \ + va_list args; \ + va_start(args, fmt); \ + __kprintf(module, fmt, args); \ + va_end(args); \ + } + +void +__kprintf(const char* component, const char* fmt, va_list args); + + +void +kprint_panic(const char* fmt, ...); + +#endif /* __LUNAIX_SYSLOG_H */ diff --git a/lunaix-os/includes/lunaix/tty/tty.h b/lunaix-os/includes/lunaix/tty/tty.h index 5c03ca2..28ad83d 100644 --- a/lunaix-os/includes/lunaix/tty/tty.h +++ b/lunaix-os/includes/lunaix/tty/tty.h @@ -49,5 +49,8 @@ tty_set_cpos(unsigned int x, unsigned int y); void tty_get_cpos(unsigned int* x, unsigned int* y); +vga_attribute +tty_get_theme(); + #endif /* __LUNAIX_TTY_H */ diff --git a/lunaix-os/kernel/asm/x86/idt.c b/lunaix-os/kernel/asm/x86/idt.c index aa07140..d11d6ed 100644 --- a/lunaix-os/kernel/asm/x86/idt.c +++ b/lunaix-os/kernel/asm/x86/idt.c @@ -22,6 +22,13 @@ _init_idt() { _set_idt_entry(FAULT_GENERAL_PROTECTION, 0x08, _asm_isr13, 0); _set_idt_entry(FAULT_PAGE_FAULT, 0x08, _asm_isr14, 0); + _set_idt_entry(APIC_ERROR_IV, 0x08, _asm_isr200, 0); + _set_idt_entry(APIC_LINT0_IV, 0x08, _asm_isr201, 0); + _set_idt_entry(APIC_TIMER_IV, 0x08, _asm_isr202, 0); + _set_idt_entry(APIC_SPIV_IV, 0x08, _asm_isr203, 0); + + _set_idt_entry(RTC_TIMER_IV, 0x08, _asm_isr210, 0); + // system defined interrupts _set_idt_entry(LUNAIX_SYS_PANIC, 0x08, _asm_isr32, 0); } \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index 9d39273..11fe3fd 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -19,6 +19,12 @@ isr_template LUNAIX_SYS_PANIC + isr_template APIC_ERROR_IV + isr_template APIC_LINT0_IV + isr_template APIC_TIMER_IV + isr_template APIC_SPIV_IV + isr_template RTC_TIMER_IV + interrupt_wrapper: pushl %esp pushl %esi @@ -34,9 +40,8 @@ subl $16, %esp movl %eax, (%esp) - call interrupt_handler - popl %eax - movl %eax, %esp + call intr_handler + popl %esp popl %eax popl %ebx diff --git a/lunaix-os/kernel/asm/x86/interrupts.c b/lunaix-os/kernel/asm/x86/interrupts.c index c79ed07..869569f 100644 --- a/lunaix-os/kernel/asm/x86/interrupts.c +++ b/lunaix-os/kernel/asm/x86/interrupts.c @@ -1,60 +1,57 @@ #include +#include #include -#include +#include #include +int_subscriber subscribers[256]; + +static int_subscriber fallback = (int_subscriber) 0; + void -panic_msg(const char* msg) -{ - tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_RED); - tty_clear_line(10); - tty_clear_line(11); - tty_clear_line(12); - tty_set_cpos(0, 11); - printf(" %s", msg); +intr_subscribe(const uint8_t vector, int_subscriber subscriber) { + subscribers[vector] = subscriber; +} + +void +intr_unsubscribe(const uint8_t vector, int_subscriber subscriber) { + if (subscribers[vector] == subscriber) { + subscribers[vector] = (int_subscriber) 0; + } +} + +void +intr_set_fallback_handler(int_subscriber subscribers) { + fallback = subscribers; } void -panic(const char* msg, isr_param* param) +intr_handler(isr_param* param) { - char buf[1024]; - sprintf(buf, - "INT %u: (%x) [%p: %p] %s", + if (param->vector <= 255) { + int_subscriber subscriber = subscribers[param->vector]; + if (subscriber) { + subscriber(param); + goto done; + } + } + + if (fallback) { + fallback(param); + goto done; + } + + kprint_panic("INT %u: (%x) [%p: %p] Unknown", param->vector, param->err_code, param->cs, - param->eip, - msg); - panic_msg(buf); - while (1) - ; -} + param->eip); -void -interrupt_handler(isr_param* param) -{ - switch (param->vector) { - case 0: - panic("Division by 0", param); - break; // never reach - case FAULT_GENERAL_PROTECTION: - panic("General Protection", param); - break; // never reach - case FAULT_PAGE_FAULT: - void* pg_fault_ptr = cpu_rcr2(); - if (pg_fault_ptr) { - panic("Page Fault", param); - } else { - panic("Null pointer reference", param); - } - break; // never reach - case LUNAIX_SYS_PANIC: - panic_msg((char*)(param->registers.edi)); - while (1) - ; - break; // never reach - default: - panic("Unknown Interrupt", param); - break; // never reach +done: + // for all external interrupts except the spurious interrupt + // this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5 + if (param->vector >= EX_INTERRUPT_BEGIN && param->vector != APIC_SPIV_IV) { + apic_done_servicing(); } + return; } \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/intr_routines.c b/lunaix-os/kernel/asm/x86/intr_routines.c new file mode 100644 index 0000000..8660df6 --- /dev/null +++ b/lunaix-os/kernel/asm/x86/intr_routines.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#include + +#include + + +static void +__print_panic_msg(const char* msg, const isr_param* param) +{ + kprint_panic(" INT %u: (%x) [%p: %p] %s", + param->vector, + param->err_code, + param->cs, + param->eip, + msg); +} + +void +intr_routine_divide_zero (const isr_param* param) +{ + __print_panic_msg("Divide by zero!", param); + spin(); +} + +void +intr_routine_general_protection (const isr_param* param) +{ + __print_panic_msg("General Protection", param); + spin(); +} + +void +intr_routine_page_fault (const isr_param* param) +{ + void* pg_fault_ptr = cpu_rcr2(); + if (!pg_fault_ptr) { + __print_panic_msg("Null pointer reference", param); + } else { + char buf[32]; + sprintf(buf, "Page fault on %p", pg_fault_ptr); + __print_panic_msg(buf, param); + } + spin(); +} + +void +intr_routine_sys_panic (const isr_param* param) +{ + __print_panic_msg((char*)(param->registers.edi), param); + spin(); +} + +void +intr_routine_fallback (const isr_param* param) +{ + __print_panic_msg("Unknown Interrupt", param); + spin(); +} + +/** + * @brief ISR for Spurious interrupt + * + * @param isr_param passed by CPU + */ +void +intr_routine_apic_spi (const isr_param* param) +{ + // FUTURE: do nothing for now +} + +void +intr_routine_apic_error (const isr_param* param) +{ + uint32_t error_reg = apic_read_reg(APIC_ESR); + char buf[32]; + sprintf(buf, "APIC error, ESR=0x%x", error_reg); + __print_panic_msg(buf, param); + spin(); +} + +void +intr_routine_init() +{ + intr_subscribe(FAULT_DIVISION_ERROR, intr_routine_divide_zero); + intr_subscribe(FAULT_GENERAL_PROTECTION, intr_routine_general_protection); + intr_subscribe(FAULT_PAGE_FAULT, intr_routine_page_fault); + intr_subscribe(LUNAIX_SYS_PANIC, intr_routine_sys_panic); + intr_subscribe(APIC_SPIV_IV, intr_routine_apic_spi); + intr_subscribe(APIC_ERROR_IV, intr_routine_apic_error); + + intr_set_fallback_handler(intr_set_fallback_handler); +} \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/prologue.S b/lunaix-os/kernel/asm/x86/prologue.S index cbfd414..38716f5 100644 --- a/lunaix-os/kernel/asm/x86/prologue.S +++ b/lunaix-os/kernel/asm/x86/prologue.S @@ -38,7 +38,7 @@ _after_gdt: - movl $mb_info, (%esp) + movl $mb_info, _k_init_mb_info call _kernel_pre_init diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 444aab0..2dbd64e 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -6,11 +6,18 @@ #include #include #include +#include + +#include +#include +#include +#include #include #include +#include -#include +#include #include #include @@ -20,6 +27,10 @@ extern uint8_t __kernel_start; extern uint8_t __kernel_end; extern uint8_t __init_hhk_end; +multiboot_info_t* _k_init_mb_info; + +LOG_MODULE("INIT"); + void setup_memory(multiboot_memory_map_t* map, size_t map_size); @@ -27,49 +38,112 @@ void setup_kernel_runtime(); void -_kernel_pre_init(multiboot_info_t* mb_info) { +lock_reserved_memory(); + +void +unlock_reserved_memory(); + +void +_kernel_pre_init() { _init_idt(); + intr_routine_init(); - pmm_init(MEM_1MB + (mb_info->mem_upper << 10)); + pmm_init(MEM_1MB + (_k_init_mb_info->mem_upper << 10)); vmm_init(); + rtc_init(); tty_init((void*)VGA_BUFFER_PADDR); - tty_set_theme(VGA_COLOR_GREEN, VGA_COLOR_BLACK); + tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_BLACK); } void -_kernel_init(multiboot_info_t* mb_info) { - printf("[KERNEL] === Initialization === \n"); +_kernel_init() { + kprintf("[MM] Mem: %d KiB, Extended Mem: %d KiB\n", + _k_init_mb_info->mem_lower, + _k_init_mb_info->mem_upper); - printf("[MM] Mem: %d KiB, Extended Mem: %d KiB\n", - mb_info->mem_lower, - mb_info->mem_upper); + unsigned int map_size = _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t); + + setup_memory((multiboot_memory_map_t*)_k_init_mb_info->mmap_addr, map_size); - unsigned int map_size = mb_info->mmap_length / sizeof(multiboot_memory_map_t); - setup_memory((multiboot_memory_map_t*)mb_info->mmap_addr, map_size); setup_kernel_runtime(); } void _kernel_post_init() { - printf("[KERNEL] === Post Initialization === \n"); size_t hhk_init_pg_count = ((uintptr_t)(&__init_hhk_end)) >> PG_SIZE_BITS; - printf("[MM] Releaseing %d pages from 0x0.\n", hhk_init_pg_count); + kprintf(KINFO "[MM] Releaseing %d pages from 0x0.\n", hhk_init_pg_count); - // 清除 hhk_init 与前1MiB的映射 - for (size_t i = 0; i < hhk_init_pg_count; i++) { + // Fuck it, I will no longer bother this little 1MiB + // I just release 4 pages for my APIC & IOAPIC remappings + for (size_t i = 0; i < 3; i++) { vmm_unmap_page((void*)(i << PG_SIZE_BITS)); } + + // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射 + lock_reserved_memory(); - assert_msg(kalloc_init(), "Fail to initialize heap"); + acpi_init(_k_init_mb_info); + uintptr_t ioapic_addr = acpi_get_context()->madt.ioapic->ioapic_addr; + + pmm_mark_page_occupied(FLOOR(__APIC_BASE_PADDR, PG_SIZE_BITS)); + pmm_mark_page_occupied(FLOOR(ioapic_addr, PG_SIZE_BITS)); + + vmm_set_mapping(APIC_BASE_VADDR, __APIC_BASE_PADDR, PG_PREM_RW); + vmm_set_mapping(IOAPIC_BASE_VADDR, ioapic_addr, PG_PREM_RW); + + ioapic_init(); + init_apic(); + + for (size_t i = 256; i < hhk_init_pg_count; i++) { + vmm_unmap_page((void*)(i << PG_SIZE_BITS)); + } +} + +void +lock_reserved_memory() { + multiboot_memory_map_t* mmaps = _k_init_mb_info->mmap_addr; + size_t map_size = _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t); + for (unsigned int i = 0; i < map_size; i++) { + multiboot_memory_map_t mmap = mmaps[i]; + if (mmap.type == MULTIBOOT_MEMORY_AVAILABLE) { + continue; + } + uint8_t* pa = PG_ALIGN(mmap.addr_low); + size_t pg_num = CEIL(mmap.len_low, PG_SIZE_BITS); + for (size_t j = 0; j < pg_num; j++) + { + vmm_set_mapping((pa + (j << PG_SIZE_BITS)), (pa + (j << PG_SIZE_BITS)), PG_PREM_R); + } + } +} + +void +unlock_reserved_memory() { + multiboot_memory_map_t* mmaps = _k_init_mb_info->mmap_addr; + size_t map_size = _k_init_mb_info->mmap_length / sizeof(multiboot_memory_map_t); + for (unsigned int i = 0; i < map_size; i++) { + multiboot_memory_map_t mmap = mmaps[i]; + if (mmap.type == MULTIBOOT_MEMORY_AVAILABLE) { + continue; + } + uint8_t* pa = PG_ALIGN(mmap.addr_low); + size_t pg_num = CEIL(mmap.len_low, PG_SIZE_BITS); + for (size_t j = 0; j < pg_num; j++) + { + vmm_unmap_page((pa + (j << PG_SIZE_BITS))); + } + } } // 按照 Memory map 标识可用的物理页 void setup_memory(multiboot_memory_map_t* map, size_t map_size) { + + // First pass, to mark the physical pages for (unsigned int i = 0; i < map_size; i++) { multiboot_memory_map_t mmap = map[i]; - printf("[MM] Base: 0x%x, len: %u KiB, type: %u\n", + kprintf("[MM] Base: 0x%x, len: %u KiB, type: %u\n", map[i].addr_low, map[i].len_low >> 10, map[i].type); @@ -77,16 +151,16 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) { // 整数向上取整除法 uintptr_t pg = map[i].addr_low + 0x0fffU; pmm_mark_chunk_free(pg >> PG_SIZE_BITS, map[i].len_low >> PG_SIZE_BITS); - printf("[MM] Freed %u pages start from 0x%x\n", + kprintf(KINFO "[MM] Freed %u pages start from 0x%x\n", map[i].len_low >> PG_SIZE_BITS, pg & ~0x0fffU); } } - // 将内核占据的页设为已占用 - size_t pg_count = (uintptr_t)(&__kernel_end - &__kernel_start) >> PG_SIZE_BITS; - pmm_mark_chunk_occupied(V2P(&__kernel_start) >> PG_SIZE_BITS, pg_count); - printf("[MM] Allocated %d pages for kernel.\n", pg_count); + // 将内核占据的页,包括前1MB,hhk_init 设为已占用 + size_t pg_count = V2P(&__kernel_end) >> PG_SIZE_BITS; + pmm_mark_chunk_occupied(0, pg_count); + kprintf(KINFO "[MM] Allocated %d pages for kernel.\n", pg_count); size_t vga_buf_pgs = VGA_BUFFER_SIZE >> PG_SIZE_BITS; @@ -107,7 +181,8 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) { // 更新VGA缓冲区位置至虚拟地址 tty_set_buffer((void*)VGA_BUFFER_VADDR); - printf("[MM] Mapped VGA to %p.\n", VGA_BUFFER_VADDR); + kprintf(KINFO "[MM] Mapped VGA to %p.\n", VGA_BUFFER_VADDR); + } void @@ -116,5 +191,6 @@ setup_kernel_runtime() { for (size_t i = 0; i < (K_STACK_SIZE >> PG_SIZE_BITS); i++) { vmm_alloc_page((void*)(K_STACK_START + (i << PG_SIZE_BITS)), PG_PREM_RW); } - printf("[MM] Allocated %d pages for stack start at %p\n", K_STACK_SIZE>>PG_SIZE_BITS, K_STACK_START); + kprintf(KINFO "[MM] Allocated %d pages for stack start at %p\n", K_STACK_SIZE>>PG_SIZE_BITS, K_STACK_START); + assert_msg(kalloc_init(), "Fail to initialize heap"); } \ No newline at end of file diff --git a/lunaix-os/kernel/k_main.c b/lunaix-os/kernel/k_main.c index fc57669..8104408 100644 --- a/lunaix-os/kernel/k_main.c +++ b/lunaix-os/kernel/k_main.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -8,20 +8,21 @@ extern uint8_t __kernel_start; +LOG_MODULE("LX") + void _kernel_main() { char buf[64]; - printf("Hello higher half kernel world!\nWe are now running in virtual " + kprintf(KINFO "Hello higher half kernel world!\nWe are now running in virtual " "address space!\n\n"); cpu_get_brand(buf); - printf("CPU: %s\n\n", buf); + kprintf("CPU: %s\n\n", buf); void* k_start = vmm_v2p(&__kernel_start); - printf( - "The kernel's base address mapping: %p->%p\n", &__kernel_start, k_start); + kprintf(KINFO "The kernel's base address mapping: %p->%p\n", &__kernel_start, k_start); // test malloc & free @@ -40,21 +41,11 @@ _kernel_main() big_[1] = 23; big_[2] = 3; - printf("%u, %u, %u\n", big_[0], big_[1], big_[2]); + kprintf(KINFO "%u, %u, %u\n", big_[0], big_[1], big_[2]); // good free lxfree(arr); lxfree(big_); - rtc_datetime datetime; - - rtc_get_datetime(&datetime); - - printf("%u/%u/%u %u:%u:%u", - datetime.year, - datetime.month, - datetime.day, - datetime.hour, - datetime.minute, - datetime.second); + spin(); } \ No newline at end of file diff --git a/lunaix-os/kernel/kprintf.c b/lunaix-os/kernel/kprintf.c new file mode 100644 index 0000000..82202ba --- /dev/null +++ b/lunaix-os/kernel/kprintf.c @@ -0,0 +1,60 @@ +#include +#include +#include + +#define MAX_KPRINTF_BUF_SIZE 1024 +#define MAX_XFMT_SIZE 1024 + +char buf[MAX_KPRINTF_BUF_SIZE]; + +void +__kprintf(const char* component, const char* fmt, va_list args) { + if (!fmt) return; + char log_level = '0'; + char expanded_fmt[MAX_XFMT_SIZE]; + vga_attribute current_theme = tty_get_theme(); + + if (*fmt == '\x1b') { + log_level = *(++fmt); + fmt++; + } + + switch (log_level) + { + case '0': + snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "INFO", component, fmt); + break; + case '1': + tty_set_theme(VGA_COLOR_BROWN, current_theme >> 12); + snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "INFO", component, fmt); + break; + case '2': + tty_set_theme(VGA_COLOR_LIGHT_RED, current_theme >> 12); + snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "EROR", component, fmt); + break; + default: + snprintf(expanded_fmt, MAX_XFMT_SIZE, "[%s] (%s) %s", "LOG", component, fmt); + break; + } + + __sprintf_internal(buf, expanded_fmt, MAX_KPRINTF_BUF_SIZE, args); + tty_put_str(buf); + tty_set_theme(current_theme >> 8, current_theme >> 12); +} + +void +kprint_panic(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_RED); + tty_clear_line(10); + tty_clear_line(11); + tty_clear_line(12); + tty_set_cpos(0, 11); + + __sprintf_internal(buf, fmt, MAX_KPRINTF_BUF_SIZE, args); + tty_put_str(buf); + + va_end(args); +} \ No newline at end of file diff --git a/lunaix-os/kernel/mm/kalloc.c b/lunaix-os/kernel/mm/kalloc.c index 675a51f..6f04e2e 100644 --- a/lunaix-os/kernel/mm/kalloc.c +++ b/lunaix-os/kernel/mm/kalloc.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include @@ -82,13 +82,20 @@ lxmalloc(size_t size) { } void* -lxcalloc(size_t size) { - void* ptr = lxmalloc(size); +lxcalloc(size_t n, size_t elem) { + size_t pd = n * elem; + + // overflow detection + if (pd < elem || pd < n) { + return NULL; + } + + void* ptr = lxmalloc(pd); if (!ptr) { return NULL; } - return memset(ptr, 0, size); + return memset(ptr, 0, pd); } void diff --git a/lunaix-os/kernel/mm/vmm.c b/lunaix-os/kernel/mm/vmm.c index e1f769d..928c289 100644 --- a/lunaix-os/kernel/mm/vmm.c +++ b/lunaix-os/kernel/mm/vmm.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -168,6 +168,21 @@ vmm_alloc_pages(void* va, size_t sz, pt_attr tattr) return true; } +void +vmm_set_mapping(void* va, void* pa, pt_attr attr) { + assert(((uintptr_t)va & 0xFFFU) == 0); + + uint32_t l1_index = L1_INDEX(va); + uint32_t l2_index = L2_INDEX(va); + + // prevent map of recursive mapping region + if (l1_index == 1023) { + return; + } + + __vmm_map_internal(l1_index, l2_index, (uintptr_t)pa, attr, false); +} + void vmm_unmap_page(void* va) { @@ -175,6 +190,12 @@ vmm_unmap_page(void* va) uint32_t l1_index = L1_INDEX(va); uint32_t l2_index = L2_INDEX(va); + + // prevent unmap of recursive mapping region + if (l1_index == 1023) { + return; + } + x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR; x86_pte_t l1pte = l1pt->entry[l1_index]; diff --git a/lunaix-os/kernel/spike.c b/lunaix-os/kernel/spike.c index 8f42660..4cb2051 100644 --- a/lunaix-os/kernel/spike.c +++ b/lunaix-os/kernel/spike.c @@ -1,11 +1,11 @@ #include #include -#include +#include static char buffer[1024]; void __assert_fail(const char* expr, const char* file, unsigned int line) { - sprintf(buffer, "[ASSERT] %s (%s:%u)", expr, file, line); + sprintf(buffer, "%s (%s:%u)", expr, file, line); // Here we load the buffer's address into %edi ("D" constraint) // This is a convention we made that the LUNAIX_SYS_PANIC syscall will @@ -16,4 +16,12 @@ void __assert_fail(const char* expr, const char* file, unsigned int line) { ); spin(); // never reach +} + +void panick(const char* msg) { + asm( + "int %0" + ::"i"(LUNAIX_SYS_PANIC), "D"(msg) + ); + spin(); } \ No newline at end of file diff --git a/lunaix-os/kernel/tty/tty.c b/lunaix-os/kernel/tty/tty.c index 1ad0dd4..e9aa42a 100644 --- a/lunaix-os/kernel/tty/tty.c +++ b/lunaix-os/kernel/tty/tty.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -104,4 +104,9 @@ void tty_get_cpos(unsigned int* x, unsigned int* y) { *x = tty_x; *y = tty_y; +} + +vga_attribute +tty_get_theme() { + return tty_theme_color; } \ No newline at end of file diff --git a/lunaix-os/libs/libc/stdio/sprintf.c b/lunaix-os/libs/klibc/stdio/sprintf.c similarity index 92% rename from lunaix-os/libs/libc/stdio/sprintf.c rename to lunaix-os/libs/klibc/stdio/sprintf.c index 6177267..a48ef1f 100644 --- a/lunaix-os/libs/libc/stdio/sprintf.c +++ b/lunaix-os/libs/klibc/stdio/sprintf.c @@ -1,7 +1,7 @@ #define __LUNAIX_LIBC -#include -#include -#include +#include +#include +#include #include #define NUMBUFSIZ 24 @@ -22,7 +22,7 @@ static const char flag_chars[] = "#0- +"; // FIXME: use something like IO_FILE to abstract this into a more flexible, stream based, vprintf void -__sprintf_internal(char* buffer, char* fmt, va_list vargs) +__sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs) { // This sprintf just a random implementation I found it on Internet . lol. // Of course, with some modifications for porting to LunaixOS :) @@ -32,6 +32,10 @@ __sprintf_internal(char* buffer, char* fmt, va_list vargs) char numbuf[NUMBUFSIZ]; uint32_t ptr = 0; for (; *fmt; ++fmt) { + if (max_len && ptr >= max_len - 1) { + break; + } + if (*fmt != '%') { buffer[ptr++] = *fmt; continue; @@ -198,6 +202,15 @@ sprintf(char* buffer, char* fmt, ...) { va_list args; va_start(args, fmt); - __sprintf_internal(buffer, fmt, args); + __sprintf_internal(buffer, fmt, 0, args); + va_end(args); +} + +void +snprintf(char* buffer, size_t n, char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + __sprintf_internal(buffer, fmt, n, args); va_end(args); } \ No newline at end of file diff --git a/lunaix-os/libs/libc/stdlib/itoa.c b/lunaix-os/libs/klibc/stdlib/itoa.c similarity index 97% rename from lunaix-os/libs/libc/stdlib/itoa.c rename to lunaix-os/libs/klibc/stdlib/itoa.c index affc2f5..fe8daf9 100644 --- a/lunaix-os/libs/libc/stdlib/itoa.c +++ b/lunaix-os/libs/klibc/stdlib/itoa.c @@ -1,6 +1,6 @@ #define __LUNAIX_LIBC #include -#include +#include char base_char[] = "0123456789abcdefghijklmnopqrstuvwxyz"; diff --git a/lunaix-os/libs/libc/string/mem.c b/lunaix-os/libs/klibc/string/mem.c similarity index 97% rename from lunaix-os/libs/libc/string/mem.c rename to lunaix-os/libs/klibc/string/mem.c index 7b20725..0b93a7d 100755 --- a/lunaix-os/libs/libc/string/mem.c +++ b/lunaix-os/libs/klibc/string/mem.c @@ -1,5 +1,5 @@ #include -#include +#include void* memcpy(void* dest, const void* src, size_t num) diff --git a/lunaix-os/libs/libc/string/strchr.c b/lunaix-os/libs/klibc/string/strchr.c similarity index 89% rename from lunaix-os/libs/libc/string/strchr.c rename to lunaix-os/libs/klibc/string/strchr.c index f122a7a..352efd1 100644 --- a/lunaix-os/libs/libc/string/strchr.c +++ b/lunaix-os/libs/klibc/string/strchr.c @@ -1,4 +1,4 @@ -#include +#include const char* strchr(const char* str, int character) diff --git a/lunaix-os/libs/klibc/string/strcpy.c b/lunaix-os/libs/klibc/string/strcpy.c new file mode 100644 index 0000000..1258606 --- /dev/null +++ b/lunaix-os/libs/klibc/string/strcpy.c @@ -0,0 +1,23 @@ +#include + +char* +strcpy(char* dest, const char* src) { + char c; + unsigned int i = 0; + while ((c = src[i])) + { + dest[i] = c; + i++; + } + dest[i] = '\0'; + return dest; +} + +char* +strncpy(char* dest, const char* src, size_t n) { + char c; + unsigned int i = 0; + while ((c = src[i]) && i < n) dest[i++] = c; + while (i < n) dest[i++] = 0; + return dest; +} \ No newline at end of file diff --git a/lunaix-os/libs/libc/string/strlen.c b/lunaix-os/libs/klibc/string/strlen.c similarity index 90% rename from lunaix-os/libs/libc/string/strlen.c rename to lunaix-os/libs/klibc/string/strlen.c index b57ec90..30ceb65 100644 --- a/lunaix-os/libs/libc/string/strlen.c +++ b/lunaix-os/libs/klibc/string/strlen.c @@ -1,4 +1,4 @@ -#include +#include size_t strlen(const char* str) diff --git a/lunaix-os/libs/libc/stdio/printf.c b/lunaix-os/libs/libc/stdio/printf.c deleted file mode 100644 index 0b3865f..0000000 --- a/lunaix-os/libs/libc/stdio/printf.c +++ /dev/null @@ -1,18 +0,0 @@ -#define __LUNAIX_LIBC -#include -#include - -#include - -void -printf(char* fmt, ...) -{ - char buffer[1024]; - va_list args; - va_start(args, fmt); - __sprintf_internal(buffer, fmt, args); - va_end(args); - - // 啊哈,直接操纵framebuffer。日后须改进(FILE* ?) - tty_put_str(buffer); -} \ No newline at end of file diff --git a/lunaix-os/libs/libc/string/strcpy.c b/lunaix-os/libs/libc/string/strcpy.c deleted file mode 100644 index 0649802..0000000 --- a/lunaix-os/libs/libc/string/strcpy.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -char* -strcpy(char* dest, const char* src) { - char c; - unsigned int i = 0; - while ((c = src[i])) - { - dest[i] = c; - i++; - } - dest[i] = '\0'; - return dest; -} \ No newline at end of file diff --git a/lunaix-os/makefile b/lunaix-os/makefile index e0f3eba..164bf5c 100644 --- a/lunaix-os/makefile +++ b/lunaix-os/makefile @@ -44,7 +44,7 @@ all-debug: CFLAGS := -g -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT) -D__LUNA all-debug: LDFLAGS := -g -ffreestanding $(O) -nostdlib -lgcc all-debug: clean $(BUILD_DIR)/$(OS_ISO) @echo "Dumping the disassembled kernel code to $(BUILD_DIR)/kdump.txt" - @i686-elf-objdump -S $(BIN_DIR)/$(OS_BIN) > $(BUILD_DIR)/kdump.txt + @${TOOLCHAIN}/i686-elf-objdump -S $(BIN_DIR)/$(OS_BIN) > $(BUILD_DIR)/kdump.txt clean: @rm -rf $(BUILD_DIR) @@ -56,15 +56,15 @@ run: $(BUILD_DIR)/$(OS_ISO) @telnet 127.0.0.1 $(QEMU_MON_PORT) debug-qemu: all-debug - @i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg - @qemu-system-i386 -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait & + @${TOOLCHAIN}/i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg + @qemu-system-i386 -m 1G -rtc base=utc -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait & @sleep 1 - @$(QEMU_MON_TERM) -e "telnet 127.0.0.1 $(QEMU_MON_PORT)" + @$(QEMU_MON_TERM) -- telnet 127.0.0.1 $(QEMU_MON_PORT) @gdb -s $(BUILD_DIR)/kernel.dbg -ex "target remote localhost:1234" debug-qemu-vscode: all-debug - @i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg - @qemu-system-i386 -s -S -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait & + @${TOOLCHAIN}/i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg + @qemu-system-i386 -s -S -m 1G -cdrom $(BUILD_DIR)/$(OS_ISO) -monitor telnet::$(QEMU_MON_PORT),server,nowait & @sleep 0.5 @telnet 127.0.0.1 $(QEMU_MON_PORT) -- 2.27.0