--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * 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;
+}
#include <string.h>
#include <system.h>
#include <msr.h>
-
+#include <cpuid.h>
+#include <elf.h>
struct boot_params boot_params __attribute__((aligned(32)));
void setup_i8254(uint16_t);
void setup_boot_irqs();
+
void check_kernel(unsigned long addr, unsigned long magic) {
init_serial();
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;
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;
#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;
boot_delay(DEFAULT_BOOT_DELAY_TICKS);
+
+ lapic_init();
}
addl $KRNLADDR,%ebx
pushl %ebx
- call lapic_init
-
call boot_paging
#movl $init_pgd-KRNLADDR,%ebx
// 初始化页目录
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; // 设置内核线性地址空间的页表项
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);
-}
set architecture i386
+b main
+#b boot_paging
#b *0x100000
#b *0x7c00
#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 { \
list_head_t list;
};
+
+void page_map(void *vaddr, void *paddr, uint32_t flags);
+
#endif // ASM
#endif //_PAGE_H
u16 x_resolution;
u16 y_resolution;
+ void *rsdt_addr;
+
dev_t root_dev;
#define CMD_LINE_SIZE 128
const char *cmdline;
printk(version);
}
+void parse_rsdt(void *addr);
+
void setup_kernel() {
printk("sysenter esp mode: %s\n",
#if FIXED_SYSENTER_ESP_MODE
init_buffer();
+ parse_rsdt(system.rsdt_addr);
+
void init_mount();
init_mount();
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;
+}
-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 \