#include <string.h>
#include <system.h>
#include <page.h>
+#include <ioremap.h>
typedef struct {
char signature[8]; // "RSD PTR "
// 后面跟着可变长度的结构
} __attribute__((packed)) madt_t;
-void parse_madt(paddr_t addr) {
+void parse_madt(vaddr_t addr) {
if (0 == addr) {
printk("MADT addr is null\n");
return;
}
- page_map(addr, addr, PAGE_P | PAGE_WR);
-
+ printk("MADT vaddr %08x\n", addr);
madt_t* madt = (madt_t*)addr;
printk("MADT LAPIC addr %08x flags %08x\n", madt->lapic_addr, madt->flags);
+ printk("MADT header size %u total length %u\n", sizeof(madt_t), madt->header.length);
+
+ system.lapic_addr = madt->lapic_addr;
uint8_t* ptr = (uint8_t*)(madt + 1); // 跳过表头
uint8_t* end = (uint8_t*)madt + madt->header.length;
uint32_t ioapic_addr = *(uint32_t*)(ptr + 4);
uint32_t global_irq_base = *(uint32_t*)(ptr + 8);
ioapic_cnt++;
+ if (ioapic_cnt == 1) {
+ system.ioapic_addr = ioapic_addr;
+ } else {
+ // 多个IO-APIC,就不支持了
+ panic("multiple IO-APIC not supported\n");
+ }
printk("IOAPIC id %u addr %08x global_irq_base %u\n", ioapic_id, ioapic_addr, global_irq_base);
} break;
case 2: { // IO APIC 中断源重映射
return;
}
- page_map(addr, addr, PAGE_P | PAGE_WR);
+ printk("parse rsdt\n");
+ rsdt_t* rsdt = (rsdt_t*)(ioremap(PAGE_ALIGN(addr), PAGE_SIZE) + (addr - PAGE_ALIGN(addr)));
+ assert(rsdt != NULL);
- rsdt_t* rsdt = (rsdt_t*)addr;
// 验证签名
if (memcmp(rsdt->header.signature, "RSDT", 4) != 0) {
panic("ACPI RSDT invalid\n");
for (int i = 0; i < table_count; i++) {
uint32_t table_phys_addr = rsdt->table_ptrs[i];
- page_map((vaddr_t)table_phys_addr, (paddr_t)table_phys_addr, PAGE_P | PAGE_WR);
-
- acpi_sdt_header_t* table = (acpi_sdt_header_t*)table_phys_addr;
+ // TODO unioremap
+ printk("ACPI table %u addr %08x\n", i, table_phys_addr);
+ acpi_sdt_header_t* table = (acpi_sdt_header_t*)(ioremap(PAGE_ALIGN(table_phys_addr), PAGE_SIZE) +
+ (table_phys_addr - PAGE_ALIGN(table_phys_addr)));
if (table == 0) {
printk("ACPI table %u:%x is null\n", i, table_phys_addr);
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((paddr_t)table);
+ printk("found MADT table, length %u\n", table->length);
+ parse_madt((vaddr_t)table);
}
}
}
+void init_acpi() {
+ parse_rsdt((paddr_t)system.rsdt_addr);
+}
+
void parse_acpi(void* tag) {
printk("ACPI[old].RSDP ");
struct multiboot_tag_old_acpi* acpi_tag = (struct multiboot_tag_old_acpi*)tag;
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: ioremap.h
+ * Author: Zhao Yanbai
+ * 2026-01-02 13:38:08 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+#include <vmalloc.h>
+
+void* ioremap(paddr_t paddr, size_t size);
+void iounmap(void* vaddr);
// 后续内核不映射显存了,以后可以提供映射到用户空间的功能,由用户态程序操作
#define VRAM_VADDR_SIZE (16 << 20)
+// VMALLOC区 128MB
+#define VMALLOC_VADDR_SIZE (128 << 20)
+
// 最大支持的线性地址空间为1G
// 这里这样实现是为了简单,与Linux内核实现有显著不同
// Linux内核还把内存大致分为了 DMA(<16MB), NORMAL(<896MB), HIGHMEM(896~4G)的内存分区(zone)
// 把内核线性地址的最高部分留给显存
// 余下的部分为支持映射其它物理内存的空间
-#define MAX_SUPT_PHYMM_SIZE (MAX_SUPT_VADDR_SIZE - VRAM_VADDR_SIZE - FIX_MAP_VADDR_SIZE)
+#define MAX_SUPT_PHYMM_SIZE (MAX_SUPT_VADDR_SIZE - VMALLOC_VADDR_SIZE - VRAM_VADDR_SIZE - FIX_MAP_VADDR_SIZE)
+
+// 算出VMALLOC区的线性地址
+#define VMALLOC_VADDR_BASE (KERNEL_VADDR_BASE + MAX_SUPT_PHYMM_SIZE)
+#define VMALLOC_VADDR_END (VMALLOC_VADDR_BASE + VMALLOC_VADDR_SIZE)
// 算出显存的线性地址
// 之后要将这个地址映射到显存的物理地址
-#define VRAM_VADDR_BASE (PAGE_OFFSET + MAX_SUPT_PHYMM_SIZE)
+#define VRAM_VADDR_BASE (VMALLOC_VADDR_END)
#define VRAM_VADDR_END (VRAM_VADDR_BASE + VRAM_VADDR_SIZE)
// 算出固定映射区的线性地址
dev_t root_dev;
- // æ\8c\89ç\90\86è¿\99个信息应该按CPU存储,简化实现
+ // æ\8c\89ç\90\86è¿\99äº\9b信息应该按CPU存储,简化实现
lapic_t* lapic;
+ paddr_t lapic_addr;
+
+ //
+ paddr_t ioapic_addr;
#define CMD_LINE_SIZE 128
const char* cmdline;
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: vmalloc.h
+ * Author: Zhao Yanbai
+ * 2026-01-02 12:21:21 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+#include <types.h>
+#include <kdef.h>
+
+#define VM_ALLOC 0x01
+#define VM_IOREMAP 0x02
+
+typedef struct vm_struct {
+ vaddr_t vm_vaddr;
+ size_t vm_size;
+ paddr_t vm_paddr;
+ uint32_t vm_flags;
+ struct vm_struct* vm_next;
+} vm_struct_t;
+
+vm_struct_t* get_vm_area(size_t size, uint32_t flags);
+vm_struct_t* find_vm_area(vaddr_t vaddr);
+
+void free_vm_area(vm_struct_t* vm);
#include <system.h>
#include <fixmap.h>
#include <apic.h>
+#include <pci.h>
+#include <ioremap.h>
static inline uint32_t apic_offset_to_msr(uint32_t offset) {
return 0x800 + (offset >> 4);
uint32_t PPR = lapic->read(LAPIC_PPR);
}
+void ioapic_init() {
+ // 先找到RCBA: Root Complex Base Address寄存器
+ uint32_t cmd = PCI_CMD(0, 31, 0, 0xF0);
+ printk("CMD: %08x\n", cmd);
+ uint32_t RCBA = pci_read_config_long(cmd);
+
+ if ((RCBA & 1) == 0) {
+ panic("RCBA not enabled\n");
+ }
+
+ // RCBA
+ // bit[0]: 使能位
+ // bit[13:1]: 保留
+ // bit[31:14]: RCBA物理基地址
+ // 0x3FFF == (1 << 14) - 1
+ uint32_t rcba_phys_base = RCBA & (~0x3FFF);
+
+ printk("RCBA: %08x %08x\n", RCBA, rcba_phys_base);
+
+ // 把RCBA物理基地址映射到内核空间
+ vaddr_t rcba_virt_base = (vaddr_t)ioremap(rcba_phys_base, 4 * PAGE_SIZE);
+ // set_fixmap(FIX_RCBA_BASE, rcba_phys_base);
+ // uint32_t rcba_virt_base = fixid_to_vaddr(FIX_RCBA_BASE);
+ printk("RCBA base %08x mapped to %08x\n", rcba_phys_base, rcba_virt_base);
+
+ // OIC
+ // 位于RCBA 的 0x31FE 偏移处,是一个16位寄存器
+ // bit[7:0]: APIC映射区。决定了IO APIC的间接访问寄存器的地址区间。只有在禁用IO APIC的情况下才能修。
+ // bit[8]: IO APIC使能标志位。 置位使能 复位禁用
+ // bit[9] 协处理器错误使能标志位
+ // bit[15:10]: 保留
+ //
+ // 上面得搞成ioremap映射, 因为0x31FE这个超过一页也就是4K了。
+ uint16_t* pOIC = (uint16_t*)((uint8_t*)rcba_virt_base + 0x31FE);
+ printk("OIC: %04x\n", *pOIC);
+ *pOIC = *pOIC | (1 << 8);
+ printk("OIC: %04x\n", *pOIC);
+}
+
void init_apic() {
+ lapic_init();
ioapic_init();
}
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: ioremap.c
+ * Author: Zhao Yanbai
+ * 2026-01-02 13:38:43 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <ioremap.h>
+#include <page.h>
+#include <assert.h>
+#include <printk.h>
+
+void ioremap_page_range(vaddr_t vaddr, paddr_t paddr, size_t size) {
+ assert(PAGE_DOWN(size) == size);
+
+ for (int i = 0; i < size / PAGE_SIZE; i++) {
+ page_map(vaddr + i * PAGE_SIZE, paddr + i * PAGE_SIZE, PAGE_P | PAGE_WR);
+ }
+}
+
+void* ioremap(paddr_t phys_addr, size_t size) {
+ size = PAGE_UP(size);
+
+ vm_struct_t* vm_area = get_vm_area(size, VM_IOREMAP);
+ if (!vm_area) {
+ return NULL;
+ }
+
+ // 映射物理地址到虚拟地址
+ vm_area->vm_paddr = phys_addr;
+ vm_area->vm_flags |= VM_IOREMAP;
+
+ printk("ioremap: 0x%08x -> 0x%08x size %u\n", phys_addr, vm_area->vm_vaddr, vm_area->vm_size);
+
+ ioremap_page_range(vm_area->vm_vaddr, vm_area->vm_paddr, vm_area->vm_size);
+
+ return (void*)vm_area->vm_vaddr;
+}
+
+void iounmap(void* addr) {
+ // vm_struct_t* vm_area = find_vm_area((vaddr_t)addr);
+ // if (!vm_area) {
+ // return;
+ // }
+
+ // if (!(vm_area->vm_flags & VM_IOREMAP)) {
+ // return;
+ // }
+
+ // free_vm_area(vm_area);
+}
printk(version);
}
-void parse_rsdt(void* addr);
-
void setup_kernel() {
printk("sysenter esp mode: %s\n",
#if FIXED_SYSENTER_ESP_MODE
init_mm();
init_buffer();
-#if 0
- parse_rsdt(system.rsdt_addr);
+#if 1
+ void init_acpi();
+ init_acpi();
#endif
#if 1
void init_apic();
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: vmalloc.c
+ * Author: Zhao Yanbai
+ * 2026-01-02 12:21:28 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <vmalloc.h>
+#include <assert.h>
+#include <irq.h>
+#include <page.h>
+#include <assert.h>
+
+static vm_struct_t* vm_area_list = NULL;
+
+vaddr_t vm_vaddr_base = VMALLOC_VADDR_BASE + (8 * 1024 * 1024);
+vaddr_t vm_vaddr_end = VMALLOC_VADDR_END;
+
+vm_struct_t* get_vm_area(size_t size, uint32_t flags) {
+ // assert size是页对齐
+ assert(PAGE_DOWN(size) == size);
+ assert(vm_vaddr_base < vm_vaddr_end);
+
+ size += PAGE_SIZE; // 尾部添加一个空页
+
+ vaddr_t vm_area_gap_bgn = 0;
+ vaddr_t vm_area_gap_end = 0;
+
+ uint32_t eflags;
+ irq_save(eflags);
+
+ vm_struct_t* prev = NULL;
+ vm_struct_t* curt = vm_area_list;
+
+ while (curt != NULL) {
+ assert(curt->vm_vaddr >= vm_vaddr_base);
+ assert(curt->vm_vaddr + curt->vm_size <= vm_vaddr_end);
+
+ //
+ vm_area_gap_bgn = prev == NULL ? vm_vaddr_base : prev->vm_vaddr + prev->vm_size;
+ vm_area_gap_end = curt->vm_vaddr;
+
+ assert(vm_area_gap_bgn <= vm_area_gap_end);
+
+ // 找到了
+ if (vm_area_gap_end - vm_area_gap_bgn >= size) {
+ break;
+ }
+
+ prev = curt;
+ curt = curt->vm_next;
+ }
+
+ // 如果找到最后了也还没找到
+ if (curt == NULL) {
+ vm_area_gap_bgn = prev == NULL ? vm_vaddr_base : prev->vm_vaddr + prev->vm_size;
+ vm_area_gap_end = vm_vaddr_end;
+
+ assert(vm_area_gap_bgn <= vm_area_gap_end);
+
+ if (vm_area_gap_end - vm_area_gap_bgn < size) {
+ irq_restore(eflags);
+ return NULL;
+ }
+ }
+
+ // 创建一人vm_struct
+ vm_struct_t* vm_area = kmalloc(sizeof(vm_struct_t), 0);
+ if (vm_area == NULL) {
+ irq_restore(eflags);
+ return NULL;
+ }
+
+ vm_area->vm_vaddr = vm_area_gap_bgn;
+ vm_area->vm_size = size;
+ vm_area->vm_flags = flags;
+
+ // add to list
+ vm_area->vm_next = curt;
+ if (prev == NULL) {
+ vm_area_list = vm_area;
+ } else {
+ prev->vm_next = vm_area;
+ }
+
+ irq_restore(eflags);
+
+ return vm_area;
+}
+
+vm_struct_t* find_vm_area(vaddr_t vaddr) {
+ assert(PAGE_DOWN(vaddr) == vaddr);
+ assert(vaddr >= vm_vaddr_base);
+ assert(vaddr < vm_vaddr_end);
+ assert(vm_area_list != NULL);
+
+ vm_struct_t* curt = vm_area_list;
+
+ while (curt != NULL) {
+ assert(curt->vm_size != 0);
+ assert(curt->vm_vaddr >= vm_vaddr_base);
+ assert(curt->vm_vaddr + curt->vm_size <= vm_vaddr_end);
+
+ if (vaddr == curt->vm_vaddr) {
+ return curt;
+ }
+
+ assert(vaddr >= curt->vm_vaddr + curt->vm_size);
+
+ curt = curt->vm_next;
+ }
+
+ return NULL;
+}
+
+void free_vm_area(vm_struct_t* vm_area) {
+ assert(vm_area != NULL);
+ assert(vm_area->vm_size != 0);
+ assert(vm_area->vm_vaddr >= vm_vaddr_base);
+ assert(vm_area->vm_vaddr + vm_area->vm_size <= vm_vaddr_end);
+ assert(vm_area_list != NULL);
+ // TODO
+}
+
+void* vmalloc(size_t size) {
+ return NULL;
+}
+
+void vfree(void* addr) {
+}