]> Zhao Yanbai Git Server - kernel.git/commitdiff
添加解析multiboot传过来的elf信息和ACPI[OLD]的信息
authoracevest <zhaoyanbai@126.com>
Sun, 28 Dec 2025 10:46:24 +0000 (18:46 +0800)
committeracevest <zhaoyanbai@126.com>
Sun, 28 Dec 2025 10:46:24 +0000 (18:46 +0800)
boot/acpi.c [new file with mode: 0644]
boot/boot.c
boot/multiboot.S
boot/unpaged_boot.c
gdbscript
include/msr.h
include/page.h
include/system.h
kernel/setup.c
mm/page.c
qemu.sh

diff --git a/boot/acpi.c b/boot/acpi.c
new file mode 100644 (file)
index 0000000..a401d46
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: acpi.c
+ *      Author: Zhao Yanbai
+ *              2025-12-28 16:56:11 Sunday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <multiboot2.h>
+#include <string.h>
+#include <system.h>
+#include <page.h>
+
+typedef struct {
+    char signature[8];        // "RSD PTR "
+    uint8_t checksum;         // 校验和
+    char oemid[6];            // OEM厂商ID
+    uint8_t revision;         // ACPI版本(0=1.0,2=2.0)
+    uint32_t rsdt_addr;       // 指向RSDT的物理地址
+} __attribute__((packed)) rsdp_v1_t;
+
+// ACPI标准表头(所有表都有)
+typedef struct {
+    char signature[4];
+    uint32_t length;
+    uint8_t revision;
+    uint8_t checksum;
+    char oemid[6];
+    char oem_table_id[8];
+    uint32_t oem_revision;
+    char creator_id[4];
+    uint32_t creator_revision;
+} __attribute__((packed)) acpi_sdt_header_t;
+
+// RSDT(Root System Description Table)结构
+typedef struct {
+    acpi_sdt_header_t header;
+    uint32_t table_ptrs[];     // 指向其他ACPI表的物理地址数组
+} __attribute__((packed)) rsdt_t;
+
+
+typedef struct {
+    acpi_sdt_header_t header;
+    uint32_t lapic_addr; // 本地APIC地址
+    uint32_t flags;
+    // 后面跟着可变长度的结构
+} __attribute__((packed)) madt_t;
+
+
+void parse_madt(void *addr) {
+    if(0 == addr) {
+        printk("MADT addr is null\n");
+        return;
+    }
+
+    page_map(addr, addr, PAGE_P | PAGE_WR);
+
+    madt_t *madt = (madt_t *)addr;
+    printk("MADT LAPIC addr %08x flags %08x\n", madt->lapic_addr, madt->flags);
+
+    uint8_t *ptr = (uint8_t *)(madt + 1); // 跳过表头
+    uint8_t *end = (uint8_t *)madt + madt->header.length;
+
+    uint32_t ioapic_cnt = 0;
+    uint32_t lapic_cnt = 0;
+
+    while(ptr < end) {
+        uint8_t type = ptr[0]; // 条目类型
+        uint8_t length = ptr[1]; // 条目长度
+
+        if(0 == length) {
+            printk("invalid madt entry\n");
+            break;
+        }
+
+        switch(type) {
+            case 0: { // 本地APIC
+                uint8_t cpu_id = ptr[2];
+                uint8_t apic_id = ptr[3];
+                uint32_t flags = *(uint32_t *)(ptr+4);
+                if(1 == flags) {
+                    lapic_cnt++;
+                    printk("LAPIC cpu %u apic %u flags %08x\n", cpu_id, apic_id, flags);
+                } else {
+                    printk("LAPIC cpu %u apic %u flags %08x [disabled]\n", cpu_id, apic_id, flags);
+                }
+            }
+            break;
+            case 1: { // IO APIC
+                uint8_t ioapic_id = ptr[2];
+                uint8_t reserved = ptr[3];
+                uint32_t ioapic_addr = *(uint32_t *)(ptr+4);
+                uint32_t global_irq_base = *(uint32_t *)(ptr+8);
+                ioapic_cnt++;
+                printk("IOAPIC id %u addr %08x global_irq_base %u\n", ioapic_id, ioapic_addr, global_irq_base);
+            }
+            break;
+            case 2: { // IO APIC 中断源重映射
+                uint8_t bus = ptr[2];
+                uint8_t irq = ptr[3];
+                uint32_t global_irq = *(uint32_t *)(ptr+4);
+                uint16_t flags = *(uint16_t *)(ptr+8);
+                printk("IOAPIC irq %u global_irq %u flags %04x bus %u\n", irq, global_irq, flags, bus);
+            }
+            break;
+            case 3: { // 本地APIC非统一中断
+                uint8_t cpu_id = ptr[2];
+                uint8_t apic_id = ptr[3];
+                uint8_t flags = ptr[4];
+                printk("LAPIC non-uniform cpu %u apic %u flags %02x\n", cpu_id, apic_id, flags);
+            }
+            break;
+            case 4: { // 虚拟化APIC
+                uint16_t reserved = *(uint16_t *)(ptr+2);
+                uint32_t apic_addr = *(uint32_t *)(ptr+4);
+                printk("Virtual APIC addr %08x\n", apic_addr);
+            }
+            break;
+            default:
+                printk("unknown madt entry type %u\n", type);
+                break;
+        }
+        ptr += length;
+    }
+}
+
+void parse_rsdt(void *addr) {
+    if(0 == addr) {
+        printk("RSDT addr is null\n");
+        return;
+    }
+
+    // unsigned long ddd = 0xFEC00000;
+    // while(ddd < 0xFF000000)  {
+    //     page_map((void*)ddd, (void*)ddd, PAGE_P);
+    //     ddd += 0x1000;
+    // }
+
+    page_map(addr, addr, PAGE_P | PAGE_WR);
+
+    rsdt_t *rsdt = (rsdt_t *)addr;
+    // 验证签名
+    if(memcmp(rsdt->header.signature, "RSDT", 4) != 0) {
+        panic("ACPI RSDT invalid\n");
+    }
+
+    // 计算表指针数量
+    // 表总长度 - 表头长度 = 指针数组长度
+    uint32_t header_size = sizeof(acpi_sdt_header_t);
+    uint32_t pointers_size = rsdt->header.length - header_size;
+    uint32_t table_count = pointers_size / sizeof(uint32_t);
+
+    printk("RSDT have %u ACPI tables\n", table_count);
+
+    for(int i=0; i<table_count; i++) {
+        uint32_t table_phys_addr = rsdt->table_ptrs[i];
+        page_map((void *)table_phys_addr, (void *)table_phys_addr, PAGE_P | PAGE_WR);
+
+        acpi_sdt_header_t *table = (acpi_sdt_header_t *)table_phys_addr;
+        if(table == 0) {
+            printk("ACPI table %u:%x is null\n", i, table_phys_addr);
+            continue;
+        }
+
+        char sig[5] = {0};
+        memcpy(sig, table->signature, 4);
+        if(sig[0] == 0) {
+            continue;
+        }
+        printk("ACPI table %u signature %s addr %08x len %u\n", i, sig, table_phys_addr, table->length);
+        if(memcmp(sig, "APIC", 4) == 0) {
+            parse_madt(table);
+        }
+    }
+
+}
+
+
+void check_acpi(void *tag) {
+    printk("ACPI[old].RSDP ");
+    struct multiboot_tag_old_acpi *acpi_tag = (struct multiboot_tag_old_acpi *)tag;
+    uint8_t *rsdp = (uint8_t *)acpi_tag->rsdp;
+    for(int i =0; i<acpi_tag->size; i++){
+        printk("%02x ", rsdp[i]);
+    }
+    printk("\n");
+
+    if(memcmp(rsdp, "RSD PTR ", 8) != 0) {
+        panic("ACPI[old] RSDP invalid\n");
+    }
+    rsdp_v1_t *rsdp_v1 = (rsdp_v1_t *)rsdp;
+    printk("ACPI[old] RSDP checksum %02x\n", rsdp_v1->checksum);
+    printk("ACPI[old] RSDP OEM ID %6s\n", rsdp_v1->oemid);
+    printk("ACPI[old] RSDP revision %u\n", rsdp_v1->revision);
+    printk("ACPI[old] RSDP RSDT addr %08x\n", rsdp_v1->rsdt_addr);
+
+    system.rsdt_addr = (void *)rsdp_v1->rsdt_addr;
+}
index 6480e14e86ec1f7983fdab1dac38f1ed57379a55..900b5343aa642ef5af716bde3d0cc0c6253f0f31 100644 (file)
@@ -17,7 +17,8 @@
 #include <string.h>
 #include <system.h>
 #include <msr.h>
-
+#include <cpuid.h>
+#include <elf.h>
 
 struct boot_params boot_params __attribute__((aligned(32)));
 
@@ -58,6 +59,7 @@ void set_tss();
 void setup_i8254(uint16_t);
 void setup_boot_irqs();
 
+
 void check_kernel(unsigned long addr, unsigned long magic) {
     init_serial();
 
@@ -98,6 +100,7 @@ void check_kernel(unsigned long addr, unsigned long magic) {
     struct multiboot_tag_mmap *mmap_tag = 0;
     struct multiboot_tag_vbe *vbe = 0;
     struct multiboot_tag_framebuffer *fb = 0;
+    struct multiboot_tag_elf_sections *elf = 0;
 
     boot_params.e820map.map_cnt = 0;
 
@@ -187,11 +190,52 @@ void check_kernel(unsigned long addr, unsigned long magic) {
         case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
             printk("frame buffer\n");
             break;
-        // case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
-        //     struct multiboot_tag_elf_sections *s = (struct multiboot_tag_elf_sections *)tag;
-        //     break;
+        case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
+            {
+                elf = (struct multiboot_tag_elf_sections *)tag;
+                Elf32_Shdr *sections = (Elf32_Shdr *)elf->sections;
+                int sections_cnt = elf->num;
+
+                const char *strtab = 0;
+                Elf32_Shdr *strtab_section = 0;
+
+                for(int i=0; i<sections_cnt; i++) {
+                    Elf32_Shdr *section = sections + i;
+                    if (section->sh_type == 3/*SHT_STRTAB*/) {
+                        if (i == elf->shndx) {
+                            strtab_section = section;
+                            strtab = (const char *)pa2va(section->sh_addr);
+                            break;
+                        }
+                    }
+                }
+
+                for (int i=0; i<sections_cnt; i++) {
+                    Elf32_Shdr *section = sections + i;
+
+                    const char *name = 0;
+                    if(strtab && section->sh_name < strtab_section->sh_size) {
+                        name = strtab + section->sh_name;
+                    }
+
+                    uint32_t addr = section->sh_addr;
+                    uint32_t size = section->sh_size;
+                    uint32_t type = section->sh_type;
+                    uint32_t flags = section->sh_flags;
+                    printk("%20s addr %08x size %08x type %08x flags %08x\n", name ? name : "(unnamed)", addr, size, type, flags);
+                }
+            }
+            break;
         case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
             printk("load base addr %08x\n", ((struct multiboot_tag_load_base_addr *)tag)->load_base_addr);
+            break;
+        case MULTIBOOT_TAG_TYPE_ACPI_OLD:
+            extern void check_acpi(void *);
+            check_acpi(tag);
+            break;
+        case MULTIBOOT_TAG_TYPE_ACPI_NEW:
+            printk("ACPI new\n");
+            break;
         default:
             support = false;
             break;
@@ -242,6 +286,42 @@ void check_kernel(unsigned long addr, unsigned long magic) {
 #endif
 }
 
+
+void for_breakpoint() {
+
+}
+
+void lapic_init() {
+    cpuid_regs_t r;
+    r = cpuid(1);
+    if(r.edx & (1 << 9)) {
+        printk("local apic supported\n");
+        if(r.ecx & (1 << 21)) {
+            printk("x2apic supported\n");
+        } else {
+            panic("x2apic not supported\n");
+        }
+    } else {
+        panic("local apic not supported\n");
+    }
+
+    uint64_t apic_base = read_msr(MSR_IA32_APIC_BASE);
+    printk("apic base: %016lx\n", apic_base);
+
+    // 开启2xapic
+    apic_base |= (1 << 10);
+    write_msr(MSR_IA32_APIC_BASE, apic_base);
+
+    apic_base = read_msr(MSR_IA32_APIC_BASE);
+    printk("after 2xapic enable apic base: %016lx\n", apic_base);
+
+    uint64_t apic_version = read_msr(MSR_IA32_X2APIC_VERSION);
+    printk("apic version: %08lx\n", apic_version);
+
+    for_breakpoint();
+}
+
+
 extern void *kernel_begin;
 extern void *kernel_end;
 extern void *bootmem_bitmap_begin;
@@ -260,4 +340,6 @@ void init_system_info() {
 
     boot_delay(DEFAULT_BOOT_DELAY_TICKS);
 
+
+    lapic_init();
 }
index e071a1771bc3d4fd02197d4869859aed8277a1e9..1e6d69f56c3a83178e9804026efacbc25318bc01 100644 (file)
@@ -62,8 +62,6 @@ real_kernel_entry:
     addl    $KRNLADDR,%ebx
     pushl   %ebx
 
-    call lapic_init
-
     call boot_paging
 
     #movl    $init_pgd-KRNLADDR,%ebx
index b22049ee2540134ed3ba44c9a08ad7fc5c9f4a2f..175ec2e2bc29f6640bcf1367baca4299b2ca3f9e 100644 (file)
@@ -36,7 +36,7 @@ void boot_paging() {
 
     // 初始化页目录
     unsigned long kpde_base = get_npde((unsigned long)(&kernel_virtual_addr_start));
-    pde_t pd_entry = init_pgt_paddr | PAGE_US | PAGE_WR | PAGE_P;
+    pde_t pd_entry = init_pgt_paddr | PAGE_WR | PAGE_P;
     for(int i=0; i<BOOT_INIT_PAGETBL_CNT; i++) {
         dir[i] = pd_entry; // 设置低端线性地址空间的页表项
         dir[kpde_base+i] = pd_entry; // 设置内核线性地址空间的页表项
@@ -45,39 +45,12 @@ void boot_paging() {
 
 
     pte_t *table = (pte_t *)init_pgt_paddr;
-    pte_t pt_entry = PAGE_US | PAGE_WR | PAGE_P;
+    pte_t pt_entry = PAGE_WR | PAGE_P;
     for(int i=0; i<BOOT_INIT_PAGETBL_CNT*PTECNT_PER_PAGE; i++) {
         table[i] = pt_entry;
         pt_entry += PAGE_SIZE;
     }
 
-
     // 设置页目录
     asm volatile("mov %0, %%cr3"::"r"(init_pgd_paddr));
 }
-
-
-void lapic_init() {
-    // cpuid_regs_t r;
-    // r = cpuid(1);
-    // if(r.edx & (1 << 9)) {
-    //     printk("local apic supported\n");
-    //     if(r.ecx & (1 << 21)) {
-    //         printk("x2apic supported\n");
-    //     } else {
-    //         panic("x2apic not supported\n");
-    //     }
-    // } else {
-    //     panic("local apic not supported\n");
-    // }
-
-    uint64_t apic_base = read_msr(MSR_IA32_APIC_BASE);
-    // printk("apic base: %016lx\n", apic_base);
-
-    // 开启2xapic
-    apic_base |= (1 << 10);
-    write_msr(MSR_IA32_APIC_BASE, apic_base);
-
-    apic_base = read_msr(MSR_IA32_APIC_BASE);
-    // printk("after 2xapic enable apic base: %016lx\n", apic_base);
-}
index d31b702ce0c2e8e8f4342b27c73990524b441d3a..e9bf67faeb259e621770a42369f41c20e8e16f4d 100644 (file)
--- a/gdbscript
+++ b/gdbscript
@@ -3,6 +3,8 @@ set confirm off
 
 set architecture i386
 
+b main
+#b boot_paging
 #b *0x100000
 
 #b *0x7c00
index d312989e749ba219541dbdf0b723098581b71965..d25761e736243c787d9a0e090b9e1a1ee4982791 100644 (file)
 
 #include <types.h>
 
+// APIC的基地址寄存器
+// bit[8][BSP] 指示当前处理器是否为引导处理器
+// bit[11][EN] 控制APIC和xAPIC模式的开启与关闭
+// bit[12:MAXPHYADDR] 用于配置APIC寄存器组的物理基地址
 #define MSR_IA32_APIC_BASE 0x1B
 
 
 #define MSR_IA32_PERF_CRTL 0x199
 
 
-// 本地APIC的版本寄存器
-#define MSR_IA32_LOCAL_APIC_VERSION 0x803
+// APIC的ID寄存器
+#define MSR_IA32_X2APIC_APICID 0x802
+// APIC的版本寄存器
+// bit[7:0][VERSION] APIC版本
+//   - 0x0x Intel 82489DX (外部APIC芯片)
+//   - 0x1x Integrated APIC (内部APIC芯片)
+// bit[23:16][MAXLVT] 最大本地向量表
+// bit[24][EOI] 禁止广播EOI消息标志位
+#define MSR_IA32_X2APIC_VERSION 0x803
 
 #define rdmsr(msr, lowval, highval)                             \
     do {                                                        \
index 12b465d7a368a56877da02ea2aa8b8526a9670fe..2a226f91798931c528e8a9267cef1c2c7daf522a 100644 (file)
@@ -221,6 +221,9 @@ struct kmem_cache {
     list_head_t list;
 };
 
+
+void page_map(void *vaddr, void *paddr, uint32_t flags);
+
 #endif  // ASM
 
 #endif  //_PAGE_H
index b61f772d96f10974edeaa0812ad337fa2703a3e9..81054b327b4d920569264c70b2130113cfa7bae7 100644 (file)
@@ -174,6 +174,8 @@ typedef struct system {
     u16 x_resolution;
     u16 y_resolution;
 
+    void *rsdt_addr;
+
     dev_t root_dev;
 #define CMD_LINE_SIZE 128
     const char *cmdline;
index e5aa7610f63a9e302ef6fa4ccf7ca0e197c85561..5d18f830c380af29eb44c68ecd1ac5909ab24e08 100644 (file)
@@ -76,6 +76,8 @@ void print_kernel_version() {
     printk(version);
 }
 
+void parse_rsdt(void *addr);
+
 void setup_kernel() {
     printk("sysenter esp mode: %s\n",
 #if FIXED_SYSENTER_ESP_MODE
@@ -89,6 +91,8 @@ void setup_kernel() {
 
     init_buffer();
 
+    parse_rsdt(system.rsdt_addr);
+
     void init_mount();
     init_mount();
 
index 3b27a8db0b2deeaaeffb8ab8fc681b7b4c77b717..311a5daeacb7940368a693bc889c6016ae14f3b9 100644 (file)
--- a/mm/page.c
+++ b/mm/page.c
@@ -131,3 +131,32 @@ void do_wp_page(void *addr) {
 
     load_cr3(current);
 }
+
+
+void page_map(void *vaddr, void *paddr, uint32_t flags) {
+    int npde = get_npde(vaddr);
+    int npte = get_npte(vaddr);
+
+    // 获取页目录地址
+    uint32_t pgd_pyhs_addr;
+    asm("mov %%cr3, %0" : "=r"(pgd_pyhs_addr));
+    pde_t *pgd = (pde_t *) pa2va(pgd_pyhs_addr);
+
+    pte_t *pgt = 0;
+    pde_t pde = pgd[npde];
+    if(pde & PAGE_P) {
+        pgt = (pte_t *)pa2va(PAGE_ALIGN(pde));
+    } else {
+        // 分配页表
+        pgt = (pte_t *)page2va(alloc_one_page(0));
+
+        // 清空页表
+        memset(pgt, 0, PAGE_SIZE);
+
+        // 页目录指向页表
+        pgd[npde] = PAGE_ALIGN(va2pa(pgt)) | flags;
+    }
+
+    // 页表指向物理地址
+    pgt[npte] = PAGE_ALIGN(paddr) | flags;
+}
diff --git a/qemu.sh b/qemu.sh
index d129fdd501bfde3410f4467cb6544436555bcca1..1f611818ab2cc602aab62dcfcf8739da45f7449a 100755 (executable)
--- a/qemu.sh
+++ b/qemu.sh
@@ -26,13 +26,15 @@ qemu-system-i386 \
     -drive file=hd.img,format=raw,index=0,media=disk \
     -drive file=kernel.iso,index=1,media=cdrom \
     -name kernel \
-    -device ich9-ahci,id=ahci \
     -vga std \
     -display cocoa \
+    -monitor unix:/tmp/qemu-monitor.sock,server,nowait \
     -s -S \
     &
 
+    # nc -U /tmp/qemu-monitor.sock
 
+    # -machine pc-q35-9.2  \
     # -cpu qemu32,+apic \
     # -cpu qemu32,+x2apic \
     #-cpu core2duo-v1,+apic \