Implement APIC, RTC, basic ACPI parser and timer support
authorMinep <zelong56@gmail.com>
Sat, 12 Mar 2022 01:21:58 +0000 (01:21 +0000)
committerMinep <zelong56@gmail.com>
Sat, 12 Mar 2022 01:21:58 +0000 (01:21 +0000)
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!

53 files changed:
lunaix-os/.gitignore
lunaix-os/.vscode/launch.json
lunaix-os/arch/x86/boot.S
lunaix-os/bochs.cfg
lunaix-os/config/make-cc
lunaix-os/hal/acpi/acpi.c [new file with mode: 0644]
lunaix-os/hal/acpi/parser/madt_parser.c [new file with mode: 0644]
lunaix-os/hal/acpi/parser/madt_parser.h [new file with mode: 0644]
lunaix-os/hal/apic.c [new file with mode: 0644]
lunaix-os/hal/cpu.c
lunaix-os/hal/ioapic.c [new file with mode: 0644]
lunaix-os/hal/rtc.c
lunaix-os/includes/arch/x86/boot/multiboot.h
lunaix-os/includes/arch/x86/idt.h
lunaix-os/includes/arch/x86/interrupts.h
lunaix-os/includes/hal/acpi/acpi.h [new file with mode: 0644]
lunaix-os/includes/hal/acpi/madt.h [new file with mode: 0644]
lunaix-os/includes/hal/acpi/sdt.h [new file with mode: 0644]
lunaix-os/includes/hal/apic.h [new file with mode: 0644]
lunaix-os/includes/hal/cpu.h
lunaix-os/includes/hal/ioapic.h [new file with mode: 0644]
lunaix-os/includes/hal/pic.h
lunaix-os/includes/hal/rtc.h
lunaix-os/includes/klibc/stdio.h [new file with mode: 0644]
lunaix-os/includes/klibc/stdlib.h [moved from lunaix-os/includes/libc/stdlib.h with 100% similarity]
lunaix-os/includes/klibc/string.h [moved from lunaix-os/includes/libc/string.h with 89% similarity]
lunaix-os/includes/libc/stdio.h [deleted file]
lunaix-os/includes/lunaix/mm/kalloc.h
lunaix-os/includes/lunaix/mm/vmm.h
lunaix-os/includes/lunaix/spike.h
lunaix-os/includes/lunaix/syslog.h [new file with mode: 0644]
lunaix-os/includes/lunaix/tty/tty.h
lunaix-os/kernel/asm/x86/idt.c
lunaix-os/kernel/asm/x86/interrupt.S
lunaix-os/kernel/asm/x86/interrupts.c
lunaix-os/kernel/asm/x86/intr_routines.c [new file with mode: 0644]
lunaix-os/kernel/asm/x86/prologue.S
lunaix-os/kernel/k_init.c
lunaix-os/kernel/k_main.c
lunaix-os/kernel/kprintf.c [new file with mode: 0644]
lunaix-os/kernel/mm/kalloc.c
lunaix-os/kernel/mm/vmm.c
lunaix-os/kernel/spike.c
lunaix-os/kernel/tty/tty.c
lunaix-os/libs/klibc/stdio/sprintf.c [moved from lunaix-os/libs/libc/stdio/sprintf.c with 92% similarity]
lunaix-os/libs/klibc/stdlib/itoa.c [moved from lunaix-os/libs/libc/stdlib/itoa.c with 97% similarity]
lunaix-os/libs/klibc/string/mem.c [moved from lunaix-os/libs/libc/string/mem.c with 97% similarity]
lunaix-os/libs/klibc/string/strchr.c [moved from lunaix-os/libs/libc/string/strchr.c with 89% similarity]
lunaix-os/libs/klibc/string/strcpy.c [new file with mode: 0644]
lunaix-os/libs/klibc/string/strlen.c [moved from lunaix-os/libs/libc/string/strlen.c with 90% similarity]
lunaix-os/libs/libc/stdio/printf.c [deleted file]
lunaix-os/libs/libc/string/strcpy.c [deleted file]
lunaix-os/makefile

index 41eb114e3b2086976af5ded7da0ba794caaaf2f3..2b8398e2eb5ccededdd3d2fba00ce90432a2a4c7 100644 (file)
@@ -2,4 +2,5 @@ build/
 playground/
 .vscode/settings.json
 .vscode/*.log
 playground/
 .vscode/settings.json
 .vscode/*.log
-.VSCodeCounter/
\ No newline at end of file
+.VSCodeCounter/
+.idea
index 1969f6d5aa5d8c1ac49b5bf475160a34ce6d3735..6bbd277cdee1144e997dea81515cc450d86a5a9c 100644 (file)
@@ -7,7 +7,7 @@
         {
             "type": "gdb",
             "request": "attach",
         {
             "type": "gdb",
             "request": "attach",
-            "name": "Attach to QEMU",
+            "name": "LunaixOS",
             "executable": "${workspaceRoot}/build/bin/lunaix.bin",
             "target": ":1234",
             "remote": true,
             "executable": "${workspaceRoot}/build/bin/lunaix.bin",
             "target": ":1234",
             "remote": true,
index 7bf30055a54e13689b11269908a9de937a62346e..8ba78cc39ab8443004b394545a786061c7995369 100644 (file)
@@ -18,7 +18,7 @@
     /* 根据System V ABI,栈地址必须16字节对齐 */
     /* 这里只是一个临时栈,在_hhk_init里面我们会初始化内核专用栈 */
     stack_bottom:
     /* 根据System V ABI,栈地址必须16字节对齐 */
     /* 这里只是一个临时栈,在_hhk_init里面我们会初始化内核专用栈 */
     stack_bottom:
-        .skip 16318, 0
+        .skip 16318 * 2, 0
     stack_top:
 
 
     stack_top:
 
 
index 216cad634d4c5f7fb25d972cb028c26284b60225..1e9f94642ee7880bff94126ed2790770d2068d83 100644 (file)
@@ -2,4 +2,6 @@ ata0-master: type=cdrom, path="build/lunaix.iso", status=inserted
 
 memory: guest=1024, host=1024
 
 
 memory: guest=1024, host=1024
 
+clock: sync=realtime, time0=utc, rtc_sync=1
+
 boot: cdrom
\ No newline at end of file
 boot: cdrom
\ No newline at end of file
index 643b4eee1dbefc44c9c9e0f86d9f0c4534b62f8a..00ed9f34898ebbf84ae083fee944822d85dec0f3 100644 (file)
@@ -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
 
 
 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 (file)
index 0000000..4781219
--- /dev/null
@@ -0,0 +1,129 @@
+#include <hal/acpi/acpi.h>
+
+#include <lunaix/mm/kalloc.h>
+#include <lunaix/spike.h>
+#include <lunaix/syslog.h>
+
+#include <klibc/string.h>
+
+#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 (file)
index 0000000..baa866c
--- /dev/null
@@ -0,0 +1,40 @@
+#include "madt_parser.h"
+#include <lunaix/mm/kalloc.h>
+
+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 (file)
index 0000000..6b15296
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LUNAIX_PARSER_MADT_PARSER_H
+#define __LUNAIX_PARSER_MADT_PARSER_H
+
+#include <hal/acpi/acpi.h>
+
+/**
+ * @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 (file)
index 0000000..c74d3f9
--- /dev/null
@@ -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 <hal/apic.h>
+#include <hal/cpu.h>
+#include <hal/pic.h>
+#include <hal/rtc.h>
+
+#include <arch/x86/interrupts.h>
+
+#include <lunaix/spike.h>
+#include <lunaix/syslog.h>
+
+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
index ad1b0a5937e3edc1df80cfb1df96332cbac8bc4d..ab5432c9642402556c0282eb8f0ee5982d22d9fb 100644 (file)
@@ -38,4 +38,30 @@ void cpu_get_brand(char* brand_out) {
         j+=4;
     }
     brand_out[48] = '\0';
         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
 }
\ No newline at end of file
diff --git a/lunaix-os/hal/ioapic.c b/lunaix-os/hal/ioapic.c
new file mode 100644 (file)
index 0000000..80ab13b
--- /dev/null
@@ -0,0 +1,59 @@
+#include <arch/x86/interrupts.h>
+#include <hal/ioapic.h>
+#include <hal/acpi/acpi.h>
+
+
+#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
index 319ad65663eea4e2e946ed6cb3b80e4ad023850e..60a1aed86654652bb225e655fdd46669aa439719 100644 (file)
@@ -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 <hal/rtc.h>
 #include <hal/rtc.h>
+#include <klibc/string.h>
+
+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)
 
 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);
 }
 
     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)
 {
 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)
 {
 }
 
 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(&current, 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, &current));
 
     uint8_t regbv = rtc_read_reg(RTC_REG_B);
 
 
     uint8_t regbv = rtc_read_reg(RTC_REG_B);
 
@@ -38,10 +84,21 @@ rtc_get_datetime(rtc_datetime* datetime)
 
 
     // To 24 hour format
 
 
     // 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;
     }
 
     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
 }
\ No newline at end of file
index a019686fe4743db6dda7094bec18286ddef672fa..aca8f433ef7cc3d94f525546e91c89f2ef8e4408 100644 (file)
@@ -225,5 +225,8 @@ struct multiboot_apm_info
     multiboot_uint16_t cseg_16_len;
     multiboot_uint16_t dseg_len;
 };
     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
 #endif
 #endif
\ No newline at end of file
index af0ae7d57bc457d5cc23fac361efe8389d20c7db..294cb27589d21e909f0037f85efa530ba98974d2 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef __LUNAIX_IDT_H
 #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();
 #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
index 3ac415a15c693faec8471d02e3d58b2713be07fc..4ffc86fe2b28920e19a334369f44718ce2e8cc73 100644 (file)
 #define FAULT_VIRTUALIZATION_EXCEPTION  20
 #define FAULT_CONTROL_PROTECTION        21
 
 #define FAULT_VIRTUALIZATION_EXCEPTION  20
 #define FAULT_CONTROL_PROTECTION        21
 
+// LunaixOS related
 #define LUNAIX_SYS_PANIC                32
 
 #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 <hal/cpu.h>
 typedef struct {
 #ifndef __ASM__
 #include <hal/cpu.h>
 typedef struct {
@@ -40,6 +54,9 @@ typedef struct {
     unsigned int ss;
 } __attribute__((packed)) isr_param;
 
     unsigned int ss;
 } __attribute__((packed)) isr_param;
 
+typedef void (*int_subscriber)(isr_param*);
+
+#pragma region ISR_DECLARATION
 void
 _asm_isr0();
 
 void
 _asm_isr0();
 
@@ -106,12 +123,40 @@ _asm_isr20();
 void
 _asm_isr21();
 
 void
 _asm_isr21();
 
-
 void
 _asm_isr32();
 
 void
 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
 
 
 #endif
 
diff --git a/lunaix-os/includes/hal/acpi/acpi.h b/lunaix-os/includes/hal/acpi/acpi.h
new file mode 100644 (file)
index 0000000..8926244
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __LUNAIX_ACPI_ACPI_H
+#define __LUNAIX_ACPI_ACPI_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <arch/x86/boot/multiboot.h>
+
+#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 (file)
index 0000000..ca75d08
--- /dev/null
@@ -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 (file)
index 0000000..fb78097
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __LUNAIX_ACPI_SDT_H
+#define __LUNAIX_ACPI_SDT_H
+
+#include <stdint.h>
+
+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 (file)
index 0000000..851e75e
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __LUNAIX_APIC_H
+#define __LUNAIX_APIC_H
+
+#include <stdint.h>
+
+#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 */
index 1a3173bb2771079c9c564aa9392b1aa75eb3d6aa..bdb07c467267c56aa911bf3f37795b10b0747fc1 100644 (file)
@@ -31,6 +31,9 @@ typedef struct
 void
 cpu_get_brand(char* brand_out);
 
 void
 cpu_get_brand(char* brand_out);
 
+int
+cpu_has_apic();
+
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wreturn-type"
 static inline reg32
 #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)
 {
 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()
 {
 }
 
 static inline void
 cpu_enable_interrupt()
 {
-    asm("sti");
+    asm volatile("sti");
 }
 
 static inline void
 cpu_disable_interrupt()
 {
 }
 
 static inline void
 cpu_disable_interrupt()
 {
-    asm("cli");
+    asm volatile("cli");
 }
 
 static inline void
 }
 
 static inline void
@@ -98,4 +101,10 @@ cpu_invtlb()
         : "r"(interm));
 }
 
         : "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
 #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 (file)
index 0000000..a6974c2
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __LUNAIX_IOAPIC_H
+#define __LUNAIX_IOAPIC_H
+
+#include <stdint.h>
+
+#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 */
index 20ee67bb69abf9838ad77e0fd42bb14a74778183..54f03b0d9afac600c7178e58503665fb6e75dae1 100644 (file)
@@ -2,4 +2,13 @@
 #define __LUNAIX_PIC_H
 // TODO: PIC
 
 #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 */
 #endif /* __LUNAIX_PIC_H */
index 69bf38e96fcf0434cf17691984d1db2b80a700aa..0092171230650eb3c4527082ea95bc2a112750eb 100644 (file)
 #define RTC_BIN_ENCODED(reg)    (reg & 0x04)
 #define RTC_24HRS_ENCODED(reg)  (reg & 0x02)
 
 #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
 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;
 
     uint8_t second;
 } rtc_datetime;
 
+void
+rtc_init();
 
 uint8_t
 rtc_read_reg(uint8_t reg_selector);
 
 
 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_get_datetime(rtc_datetime* datetime);
 
+void
+rtc_enable_timer();
+
+void
+rtc_disable_timer();
+
 #endif /* __LUNAIX_RTC_H */
 #endif /* __LUNAIX_RTC_H */
diff --git a/lunaix-os/includes/klibc/stdio.h b/lunaix-os/includes/klibc/stdio.h
new file mode 100644 (file)
index 0000000..07f4716
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __LUNAIX_STDIO_H
+#define __LUNAIX_STDIO_H
+#include <stdarg.h>
+#include <stddef.h>
+
+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 */
similarity index 89%
rename from lunaix-os/includes/libc/string.h
rename to lunaix-os/includes/klibc/string.h
index 7347de2abc2f1bce7fbe4ca46865cd4e87a8318d..9cbcb31d06ae7a8501dc7862ac5fb7793343673c 100644 (file)
@@ -24,6 +24,9 @@ strcpy(char* dest, const char* src);
 size_t
 strnlen(const char* str, size_t max_len);
 
 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);
 
 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 (file)
index 65edb9e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __LUNAIX_STDIO_H
-#define __LUNAIX_STDIO_H
-#include <stdarg.h>
-
-#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 */
index d8d712d6258b109fc8f6a86cfc2cef392033a546..6b97b3fdbbe8519c69e99410f63c579cd460e645 100644 (file)
@@ -25,7 +25,7 @@ lxmalloc(size_t size);
  * @return void*
  */
 void*
  * @return void*
  */
 void*
-lxcalloc(size_t size);
+lxcalloc(size_t n, size_t elem);
 
 /**
  * @brief Free the memory region allocated by kmalloc
 
 /**
  * @brief Free the memory region allocated by kmalloc
index 752f23caf40efa7369170b95b612a3722a907444..844eb0ec31c61430c099e928da29e61f7141fb4f 100644 (file)
@@ -67,6 +67,16 @@ vmm_alloc_page(void* va, pt_attr tattr);
 int
 vmm_alloc_pages(void* va, size_t sz, 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 删除一个映射
  *
 /**
  * @brief 删除一个映射
  *
index e39c6119a96c5ba1dd868ed65eb6b20d3fd45980..9cf4b7fee0e442873e7a39498ca8252d1ff568f1 100644 (file)
@@ -31,10 +31,15 @@ inline static void spin() {
     }
 void __assert_fail(const char* expr, const char* file, unsigned int line) __attribute__((noinline, noreturn));
 #else
     }
 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
 
 #endif
 
+void panick(const char* msg);
+
+
+#define wait_until(cond)    while(!(cond));
+#define loop_until(cond)    while(!(cond));
 
 
 #endif /* __LUNAIX_SPIKE_H */
 
 
 #endif /* __LUNAIX_SPIKE_H */
diff --git a/lunaix-os/includes/lunaix/syslog.h b/lunaix-os/includes/lunaix/syslog.h
new file mode 100644 (file)
index 0000000..91e2003
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __LUNAIX_SYSLOG_H
+#define __LUNAIX_SYSLOG_H
+
+#include <stdarg.h>
+
+#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 */
index 5c03ca29a845a0d3e76986b4ca89679376f831ac..28ad83d794211575c5e07b7133358ef02d51972a 100644 (file)
@@ -49,5 +49,8 @@ tty_set_cpos(unsigned int x, unsigned int y);
 void
 tty_get_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 */
 
 #endif /* __LUNAIX_TTY_H */
index aa0714070ff63e44e7a22761d7f0ed79f3389963..d11d6ed0969a820d8d0ee3f75e4ac765c627f638 100644 (file)
@@ -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(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
     // system defined interrupts
     _set_idt_entry(LUNAIX_SYS_PANIC, 0x08, _asm_isr32, 0);
 }
\ No newline at end of file
index 9d392734efbbd7e7f640e01c7611984ce193e447..11fe3fd505f54af8a0b68e5fbef73483dd41d6c0 100644 (file)
 
     isr_template LUNAIX_SYS_PANIC
 
 
     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
     interrupt_wrapper:
         pushl %esp
         pushl %esi
@@ -34,9 +40,8 @@
         subl $16, %esp
         movl %eax, (%esp)
 
         subl $16, %esp
         movl %eax, (%esp)
 
-        call interrupt_handler
-        popl %eax
-        movl %eax, %esp
+        call intr_handler
+        popl %esp
 
         popl %eax
         popl %ebx
 
         popl %eax
         popl %ebx
index c79ed07300e12492d01e8c97ed6a4383543c2ca2..869569f81928e31e3270b51a1166b22e17c426f8 100644 (file)
@@ -1,60 +1,57 @@
 #include <arch/x86/interrupts.h>
 #include <arch/x86/interrupts.h>
+#include <hal/apic.h>
 #include <hal/cpu.h>
 #include <hal/cpu.h>
-#include <libc/stdio.h>
+#include <lunaix/syslog.h>
 #include <lunaix/tty/tty.h>
 
 #include <lunaix/tty/tty.h>
 
+int_subscriber subscribers[256];
+
+static int_subscriber fallback = (int_subscriber) 0;
+
 void
 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
 }
 
 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->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
 }
\ 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 (file)
index 0000000..8660df6
--- /dev/null
@@ -0,0 +1,96 @@
+#include <arch/x86/interrupts.h>
+#include <lunaix/tty/tty.h>
+#include <lunaix/spike.h>
+#include <lunaix/syslog.h>
+
+#include <klibc/stdio.h>
+
+#include <hal/apic.h>
+
+
+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
index cbfd414765ed0cfa3086f3b1fb21cb1002ed7be6..38716f52094de74a277466effacc0c52eb6a9bfe 100644 (file)
@@ -38,7 +38,7 @@
 
     _after_gdt:
 
 
     _after_gdt:
 
-        movl $mb_info, (%esp)
+        movl $mb_info, _k_init_mb_info
 
         call _kernel_pre_init
 
 
         call _kernel_pre_init
 
index 444aab0e818c1433f78ea03d4973948e54a3ece6..2dbd64ee7d76f87261716f7e05cea38a77193267 100644 (file)
@@ -6,11 +6,18 @@
 #include <lunaix/mm/vmm.h>
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/spike.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/spike.h>
+#include <lunaix/syslog.h>
+
+#include <hal/rtc.h>
+#include <hal/apic.h>
+#include <hal/ioapic.h>
+#include <hal/acpi/acpi.h>
 
 #include <arch/x86/boot/multiboot.h>
 #include <arch/x86/idt.h>
 
 #include <arch/x86/boot/multiboot.h>
 #include <arch/x86/idt.h>
+#include <arch/x86/interrupts.h>
 
 
-#include <libc/stdio.h>
+#include <klibc/stdio.h>
 
 #include <stdint.h>
 #include <stddef.h>
 
 #include <stdint.h>
 #include <stddef.h>
@@ -20,6 +27,10 @@ extern uint8_t __kernel_start;
 extern uint8_t __kernel_end;
 extern uint8_t __init_hhk_end;
 
 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);
 
 void
 setup_memory(multiboot_memory_map_t* map, size_t map_size);
 
@@ -27,49 +38,112 @@ void
 setup_kernel_runtime();
 
 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();
     _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();
     vmm_init();
+    rtc_init();
 
     tty_init((void*)VGA_BUFFER_PADDR);
 
     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
 }
 
 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() {
     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;
     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));
     }
         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) {
 }
 
 // 按照 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];
     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);
                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);
             // 整数向上取整除法
             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);
         }
     }
 
                    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;
 
 
     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);
 
     // 更新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
 }
 
 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);
     }
     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
 }
\ No newline at end of file
index fc57669154f79a48bfd5f004fa98326bca85ecfb..8104408692b8f4111a0aa168c8125c24266e7160 100644 (file)
@@ -1,6 +1,6 @@
 #include <hal/cpu.h>
 #include <hal/rtc.h>
 #include <hal/cpu.h>
 #include <hal/rtc.h>
-#include <libc/stdio.h>
+#include <lunaix/syslog.h>
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/spike.h>
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/spike.h>
@@ -8,20 +8,21 @@
 
 extern uint8_t __kernel_start;
 
 
 extern uint8_t __kernel_start;
 
+LOG_MODULE("LX")
+
 void
 _kernel_main()
 {
     char buf[64];
 
 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);
            "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);
 
     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
 
 
     // test malloc & free
 
@@ -40,21 +41,11 @@ _kernel_main()
     big_[1] = 23;
     big_[2] = 3;
 
     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_);
 
 
     // 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
 }
\ No newline at end of file
diff --git a/lunaix-os/kernel/kprintf.c b/lunaix-os/kernel/kprintf.c
new file mode 100644 (file)
index 0000000..82202ba
--- /dev/null
@@ -0,0 +1,60 @@
+#include <lunaix/syslog.h>
+#include <lunaix/tty/tty.h>
+#include <klibc/stdio.h>
+
+#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
index 675a51f4033fe0191a5fba16c46e0f558e22f40e..6f04e2edebcabe6a2497e00b5288e4e1509af0bb 100644 (file)
@@ -17,7 +17,7 @@
 #include <lunaix/constants.h>
 #include <lunaix/spike.h>
 
 #include <lunaix/constants.h>
 #include <lunaix/spike.h>
 
-#include <libc/string.h>
+#include <klibc/string.h>
 
 #include <stdint.h>
 
 
 #include <stdint.h>
 
@@ -82,13 +82,20 @@ lxmalloc(size_t size) {
 }
 
 void*
 }
 
 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;
     }
 
     if (!ptr) {
         return NULL;
     }
 
-    return memset(ptr, 0, size);
+    return memset(ptr, 0, pd);
 }
 
 void
 }
 
 void
index e1f769dd9c0abb351defcc3ee52bd51194c117ee..928c289f86f4fc6c03017ab104574a7990ecc8e5 100644 (file)
@@ -1,5 +1,5 @@
 #include <hal/cpu.h>
 #include <hal/cpu.h>
-#include <libc/string.h>
+#include <klibc/string.h>
 #include <lunaix/mm/page.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/mm/page.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/vmm.h>
@@ -168,6 +168,21 @@ vmm_alloc_pages(void* va, size_t sz, pt_attr tattr)
     return true;
 }
 
     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)
 {
 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);
 
     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];
     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
 
     x86_pte_t l1pte = l1pt->entry[l1_index];
index 8f42660930a23b91b65ff4e344de680f188e115e..4cb205105d84b6086fbfc9f7573574cdcc17e697 100644 (file)
@@ -1,11 +1,11 @@
 #include <lunaix/spike.h>
 #include <arch/x86/interrupts.h>
 #include <lunaix/spike.h>
 #include <arch/x86/interrupts.h>
-#include <libc/stdio.h>
+#include <klibc/stdio.h>
 
 static char buffer[1024];
 
 void __assert_fail(const char* expr, const char* file, unsigned int line) {
 
 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
 
     // 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
     );
 
     spin();     // never reach
+}
+
+void panick(const char* msg) {
+    asm(
+        "int %0"
+        ::"i"(LUNAIX_SYS_PANIC), "D"(msg)
+    );
+    spin();
 }
\ No newline at end of file
 }
\ No newline at end of file
index 1ad0dd47e0390aad672ecd180d09cf1239bde5a3..e9aa42aba3fe09c713e2508baf2e7e0a07844726 100644 (file)
@@ -1,4 +1,4 @@
-#include <libc/string.h>
+#include <klibc/string.h>
 #include <lunaix/tty/tty.h>
 #include <lunaix/constants.h>
 #include <stdint.h>
 #include <lunaix/tty/tty.h>
 #include <lunaix/constants.h>
 #include <stdint.h>
@@ -104,4 +104,9 @@ void
 tty_get_cpos(unsigned int* x, unsigned int* y) {
     *x = tty_x;
     *y = tty_y;
 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
 }
\ No newline at end of file
similarity index 92%
rename from lunaix-os/libs/libc/stdio/sprintf.c
rename to lunaix-os/libs/klibc/stdio/sprintf.c
index 61772676c3aeff4bcc4da7ea10c96f704d37738c..a48ef1f0e9c37d0c061b04cbf9a64099e8a25f8b 100644 (file)
@@ -1,7 +1,7 @@
 #define __LUNAIX_LIBC
 #define __LUNAIX_LIBC
-#include <libc/stdio.h>
-#include <libc/stdlib.h>
-#include <libc/string.h>
+#include <klibc/stdio.h>
+#include <klibc/stdlib.h>
+#include <klibc/string.h>
 #include <stdint.h>
 
 #define NUMBUFSIZ 24
 #include <stdint.h>
 
 #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
 
 // 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 :)
 {
     // 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) {
     char numbuf[NUMBUFSIZ];
     uint32_t ptr = 0;
     for (; *fmt; ++fmt) {
+        if (max_len && ptr >= max_len - 1) {
+            break;
+        }
+        
         if (*fmt != '%') {
             buffer[ptr++] = *fmt;
             continue;
         if (*fmt != '%') {
             buffer[ptr++] = *fmt;
             continue;
@@ -198,6 +202,15 @@ sprintf(char* buffer, char* fmt, ...)
 {
     va_list args;
     va_start(args, 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
     va_end(args);
 }
\ No newline at end of file
similarity index 97%
rename from lunaix-os/libs/libc/stdlib/itoa.c
rename to lunaix-os/libs/klibc/stdlib/itoa.c
index affc2f5fe6f3d4f969485feb3184a08427f3c73d..fe8daf9295cae2ce962edde1819bcaf41653e00f 100644 (file)
@@ -1,6 +1,6 @@
 #define __LUNAIX_LIBC
 #include <stddef.h>
 #define __LUNAIX_LIBC
 #include <stddef.h>
-#include <libc/stdlib.h>
+#include <klibc/stdlib.h>
 
 char base_char[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 
 
 char base_char[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 
similarity index 97%
rename from lunaix-os/libs/libc/string/mem.c
rename to lunaix-os/libs/klibc/string/mem.c
index 7b20725943c90bf3ffb726aabe5ac3b1e8fe5a6c..0b93a7d065f198ba18cba0c471e2b09990a61c7a 100755 (executable)
@@ -1,5 +1,5 @@
 #include <stdint.h>
 #include <stdint.h>
-#include <libc/string.h>
+#include <klibc/string.h>
 
 void*
 memcpy(void* dest, const void* src, size_t num)
 
 void*
 memcpy(void* dest, const void* src, size_t num)
similarity index 89%
rename from lunaix-os/libs/libc/string/strchr.c
rename to lunaix-os/libs/klibc/string/strchr.c
index f122a7ad785606737f4ae7d9eae5167e9a577ada..352efd1e649f6fd2d026f4c7053ca8fa2d09f1fb 100644 (file)
@@ -1,4 +1,4 @@
-#include <libc/string.h>
+#include <klibc/string.h>
 
 const char*
 strchr(const char* str, int character)
 
 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 (file)
index 0000000..1258606
--- /dev/null
@@ -0,0 +1,23 @@
+#include <klibc/string.h>
+
+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
similarity index 90%
rename from lunaix-os/libs/libc/string/strlen.c
rename to lunaix-os/libs/klibc/string/strlen.c
index b57ec902fde1ec7489f700c783294a1f3c1da830..30ceb654ddc584f0d0d9b89ec83108fc155475bf 100644 (file)
@@ -1,4 +1,4 @@
-#include <libc/string.h>
+#include <klibc/string.h>
 
 size_t
 strlen(const char* str)
 
 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 (file)
index 0b3865f..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#define __LUNAIX_LIBC
-#include <libc/stdio.h>
-#include <stdarg.h>
-
-#include <lunaix/tty/tty.h>
-
-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 (file)
index 0649802..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <libc/string.h>
-
-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
index e0f3eba9e1b3c979edcdb440f6868abb359a1ae4..164bf5c4ea660472d6da372c6bfe6ea6fd220d76 100644 (file)
@@ -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"
 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)
 
 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
        @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
        @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
        @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)
 
        @sleep 0.5
        @telnet 127.0.0.1 $(QEMU_MON_PORT)