From: acevest Date: Sun, 28 Dec 2025 10:46:24 +0000 (+0800) Subject: 添加解析multiboot传过来的elf信息和ACPI[OLD]的信息 X-Git-Url: http://repos.zhaoyanbai.com/?a=commitdiff_plain;h=bce047746d1a3b0dfcb43b8a24018ec6a634f914;p=kernel.git 添加解析multiboot传过来的elf信息和ACPI[OLD]的信息 --- diff --git a/boot/acpi.c b/boot/acpi.c new file mode 100644 index 0000000..a401d46 --- /dev/null +++ b/boot/acpi.c @@ -0,0 +1,199 @@ +/* + * ------------------------------------------------------------------------ + * File Name: acpi.c + * Author: Zhao Yanbai + * 2025-12-28 16:56:11 Sunday CST + * Description: none + * ------------------------------------------------------------------------ + */ + +#include +#include +#include +#include + +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; itable_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; isize; 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; +} diff --git a/boot/boot.c b/boot/boot.c index 6480e14..900b534 100644 --- a/boot/boot.c +++ b/boot/boot.c @@ -17,7 +17,8 @@ #include #include #include - +#include +#include 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; ish_type == 3/*SHT_STRTAB*/) { + if (i == elf->shndx) { + strtab_section = section; + strtab = (const char *)pa2va(section->sh_addr); + break; + } + } + } + + for (int i=0; ish_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(); } diff --git a/boot/multiboot.S b/boot/multiboot.S index e071a17..1e6d69f 100644 --- a/boot/multiboot.S +++ b/boot/multiboot.S @@ -62,8 +62,6 @@ real_kernel_entry: addl $KRNLADDR,%ebx pushl %ebx - call lapic_init - call boot_paging #movl $init_pgd-KRNLADDR,%ebx diff --git a/boot/unpaged_boot.c b/boot/unpaged_boot.c index b22049e..175ec2e 100644 --- a/boot/unpaged_boot.c +++ b/boot/unpaged_boot.c @@ -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 +// APIC的基地址寄存器 +// bit[8][BSP] 指示当前处理器是否为引导处理器 +// bit[11][EN] 控制APIC和xAPIC模式的开启与关闭 +// bit[12:MAXPHYADDR] 用于配置APIC寄存器组的物理基地址 #define MSR_IA32_APIC_BASE 0x1B @@ -31,8 +35,15 @@ #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 { \ diff --git a/include/page.h b/include/page.h index 12b465d..2a226f9 100644 --- a/include/page.h +++ b/include/page.h @@ -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 diff --git a/include/system.h b/include/system.h index b61f772..81054b3 100644 --- a/include/system.h +++ b/include/system.h @@ -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; diff --git a/kernel/setup.c b/kernel/setup.c index e5aa761..5d18f83 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -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(); diff --git a/mm/page.c b/mm/page.c index 3b27a8d..311a5da 100644 --- 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 d129fdd..1f61181 100755 --- 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 \