]> Zhao Yanbai Git Server - kernel.git/commitdiff
简单支持fixmap并把LAPIC通过fixmap映射到内核
authoracevest <zhaoyanbai@126.com>
Thu, 1 Jan 2026 08:05:31 +0000 (16:05 +0800)
committeracevest <zhaoyanbai@126.com>
Thu, 1 Jan 2026 08:05:39 +0000 (16:05 +0800)
include/fixmap.h [new file with mode: 0644]
include/kdef.h [new file with mode: 0644]
include/page.h
include/system.h
kernel/apic.c
kernel/exec.c
kernel/fixmap.c [new file with mode: 0644]
kernel/setup.c
mm/mm.c
mm/page.c

diff --git a/include/fixmap.h b/include/fixmap.h
new file mode 100644 (file)
index 0000000..21b5b35
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: fixmap.h
+ *      Author: Zhao Yanbai
+ *              2025-12-31 23:10:32 Wednesday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+#include <kdef.h>
+#include <types.h>
+#include <page.h>
+
+#define MAX_IO_APIC_CNT (16)
+
+enum {
+    FIX_BGN_PAD,
+    FIX_BGN_PAD_0 = FIX_BGN_PAD,
+    FIX_BGN_PAD_1,
+
+    // 在SMP系统中,即便有多个CPU,每个CPU都有一个LAPIC,但他们都共享同一个LAPIC物理地址
+    // 虽然每个CPU都访问同样的物理地址,但实际上硬件会根据发起请求的CPU核心,自动路由到对应的本地APIC。
+    FIX_LAPIC_BASE,
+
+    FIX_IO_APIC_BASE,
+    FIX_IO_APIC_END = FIX_IO_APIC_BASE + MAX_IO_APIC_CNT - 1,
+
+    FIX_END_PAD,
+};
+
+void set_fixmap(uint32_t fixid, paddr_t paddr);
+
+vaddr_t fixid_to_vaddr(uint32_t fixid);
+uint32_t vaddr_to_fixid(vaddr_t vaddr);
diff --git a/include/kdef.h b/include/kdef.h
new file mode 100644 (file)
index 0000000..f27aaaa
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: kdef.h
+ *      Author: Zhao Yanbai
+ *              2026-01-01 13:02:43 Thursday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+#define KERNEL_VADDR_BASE (0xC0000000)
+
+// 固定映射区划分出16MB的空间
+#define FIX_MAP_VADDR_SIZE (16 << 20)
+
+// 定义最大显存为 16MB
+// 后续内核不映射显存了,以后可以提供映射到用户空间的功能,由用户态程序操作
+#define VRAM_VADDR_SIZE (16 << 20)
+
+// 最大支持的线性地址空间为1G
+// 这里这样实现是为了简单,与Linux内核实现有显著不同
+// Linux内核还把内存大致分为了 DMA(<16MB), NORMAL(<896MB), HIGHMEM(896~4G)的内存分区(zone)
+// 并且每个分区各一个伙伴算法管理物理页。
+// 正常Linux内核只有1G的寻址空间,正常只能寻址896MB以下的内存,余下的128MB地址空间是留着用来映射高端区域的物理内存的
+#define MAX_SUPT_VADDR_SIZE (1UL << 30)
+
+// 把内核线性地址的最高部分留给显存
+// 余下的部分为支持映射其它物理内存的空间
+#define MAX_SUPT_PHYMM_SIZE (MAX_SUPT_VADDR_SIZE - VRAM_VADDR_SIZE - FIX_MAP_VADDR_SIZE)
+
+// 算出显存的线性地址
+// 之后要将这个地址映射到显存的物理地址
+#define VRAM_VADDR_BASE (PAGE_OFFSET + MAX_SUPT_PHYMM_SIZE)
+#define VRAM_VADDR_END (VRAM_VADDR_BASE + VRAM_VADDR_SIZE)
+
+// 算出固定映射区的线性地址
+#define FIX_MAP_VADDR_BASE (VRAM_VADDR_END)
+#define FIX_MAP_VADDR_END (FIX_MAP_VADDR_BASE + FIX_MAP_VADDR_SIZE)
index 4aff24d8d99ce382e5c93bb0edc75fe57c54f6d2..a3dcb7409075dac31ffcbed81079064620d56400 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _PAGE_H
 #define _PAGE_H
 
+#include <kdef.h>
+
 /*
 
 | CR0的PG | CR4的PAE | CR4的PSE | PDE的PS | 页面规模 | 物理地址规模 |
@@ -38,7 +40,7 @@
 #define PAGE_SIZE (1UL << PAGE_SHIFT)
 #define PAGE_FLAG_MASK ((1UL << PAGE_SHIFT) - 1)
 #define PAGE_MASK (~PAGE_FLAG_MASK)
-#define PAGE_OFFSET (0xC0000000)
+#define PAGE_OFFSET (KERNEL_VADDR_BASE)
 #define PAGE_PDE_CNT 1024
 #define PAGE_PTE_CNT 1024
 
@@ -129,7 +131,7 @@ static inline unsigned long get_cr3() {
 }
 
 static inline pde_t* get_pgd() {
-    return (pde_t*)(get_cr3() & PAGE_MASK);
+    return (pde_t*)pa2va((get_cr3() & PAGE_MASK));
 }
 
 typedef unsigned int gfp_t;
@@ -239,6 +241,7 @@ struct kmem_cache {
 };
 
 void page_map(vaddr_t vaddr, paddr_t paddr, uint32_t flags);
+void set_pte_paddr(vaddr_t vaddr, paddr_t paddr, uint32_t flags);
 
 #endif  // ASM
 
index e4e0341922c5ad6d1584b161b6322c5f62ac2001..67f8e299c1dd275cd059c17cda5014e27e3dc33a 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <assert.h>
 #include <page.h>
-#define KRNLADDR PAGE_OFFSET
+#include <kdef.h>
 
 #define PT_REGS_EBX 0
 #define PT_REGS_ECX 4
@@ -77,31 +77,6 @@ extern char etext, edata, end;
 
 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
 
-// 固定映射区划分出16MB的空间
-#define FIXED_MAP_VADDR_SIZE (16 << 20)
-
-// 定义最大显存为 16MB
-// 后续内核不映射显存了,以后可以提供映射到用户空间的功能,由用户态程序操作
-#define VRAM_VADDR_SIZE (16 << 20)
-
-// 最大支持的线性地址空间为1G
-// 这里这样实现是为了简单,与Linux内核实现有显著不同
-// Linux内核还把内存大致分为了 DMA(<16MB), NORMAL(<896MB), HIGHMEM(896~4G)的内存分区(zone)
-// 并且每个分区各一个伙伴算法管理物理页。
-// 正常Linux内核只有1G的寻址空间,正常只能寻址896MB以下的内存,余下的128MB地址空间是留着用来映射高端区域的物理内存的
-#define MAX_SUPT_VADDR_SIZE (1UL << 30)
-
-// 把内核线性地址的最高部分留给显存
-// 余下的部分为支持映射其它物理内存的空间
-#define MAX_SUPT_PHYMM_SIZE (MAX_SUPT_VADDR_SIZE - VRAM_VADDR_SIZE - FIXED_MAP_VADDR_SIZE)
-
-// 算出显存的线性地址
-// 之后要将这个地址映射到显存的物理地址
-#define VRAM_VADDR_BASE (PAGE_OFFSET + MAX_SUPT_PHYMM_SIZE)
-
-// 算出固定映射区的线性地址
-#define FIXED_MAP_VADDR_BASE (VRAM_VADDR_BASE + VRAM_VADDR_SIZE)
-
 #define INT_STACK_SIZE PAGE_SIZE
 
 enum GDTSelectorIndex {
@@ -181,6 +156,8 @@ typedef struct system {
     void* rsdt_addr;
 
     dev_t root_dev;
+
+    bool x2apic;
 #define CMD_LINE_SIZE 128
     const char* cmdline;
 
index d4ae8e9fc3b3623cc648b603232881ccd73cd0f1..8e3f3dca654873cc06f88b5bda3c3d50a7b2ce57 100644 (file)
 #include <msr.h>
 #include <cpuid.h>
 #include <system.h>
+#include <fixmap.h>
 
 void lapic_init() {
+    system.x2apic = false;
+
     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");
+            system.x2apic = true;
         } else {
-            panic("x2apic not supported\n");
+            printk("x2apic not supported\n");
         }
     } else {
         panic("local apic not supported\n");
@@ -28,7 +32,7 @@ void lapic_init() {
     uint64_t apic_base = read_msr(MSR_IA32_APIC_BASE);
     printk("apic base: %016lx\n", apic_base);
 
-    // apic 必然已经开启
+    // apic 必然已经开启q
     assert((apic_base & (1 << 11)) != 0);
 
     // 开启2xapic
@@ -41,16 +45,12 @@ void lapic_init() {
     uint64_t apic_version = read_msr(MSR_IA32_X2APIC_VERSION);
     printk("apic version: %08lx\n", apic_version);
 
-    paddr_t apic_phys_base_addr = apic_base & 0xFFFFF000;
-    vaddr_t apic_virt_base_addr = apic_phys_base_addr;
-#if 0
-    unsigned long ddd = 0xFEC00000;
-    while(ddd < 0xFF000000)  {
-        page_map((void*)ddd, (void*)ddd, PAGE_P);
-        ddd += 0x1000;
-    }
-#endif
-    page_map((vaddr_t)apic_virt_base_addr, (paddr_t)apic_phys_base_addr, PAGE_P);
+    uint32_t apic_phys_base_addr = (uint32_t)apic_base & PAGE_MASK;
+    set_fixmap(FIX_LAPIC_BASE, apic_phys_base_addr);
+
+    vaddr_t apic_virt_base_addr = fixid_to_vaddr(FIX_LAPIC_BASE);
+
+    printk("LAPIC base %08x mapped to %08x\n", apic_phys_base_addr, apic_virt_base_addr);
 
     {
         volatile uint32_t* base = (volatile uint32_t*)apic_virt_base_addr;
@@ -61,7 +61,5 @@ void lapic_init() {
 }
 
 void init_apic() {
-#if 0
     lapic_init();
-#endif
 }
index 056bc90ae657ed3c86288eeae10e0e248de8ea93..85e5d40697d9f69dcdc32931b0cd8d3bf1ecbba7 100644 (file)
@@ -111,13 +111,13 @@ int sysc_exec(const char* path, char* const argv[]) {
     regs->es = SELECTOR_USER_DS;
     regs->fs = SELECTOR_USER_DS;
     regs->gs = SELECTOR_USER_DS;
-    regs->esp = (KRNLADDR - 4 * sizeof(unsigned long));
+    regs->esp = (KERNEL_VADDR_BASE - 4 * sizeof(unsigned long));
     regs->eflags = 0x200;
     regs->cs = SELECTOR_USER_CS;
 #endif
     regs->eip = (unsigned long)ehdr->e_entry;
     regs->edx = regs->eip;
-    regs->ecx = KRNLADDR;  //(0xC0000000 - 16);
+    regs->ecx = KERNEL_VADDR_BASE;  //(0xC0000000 - 16);
 
     // kfree(buf);
 
diff --git a/kernel/fixmap.c b/kernel/fixmap.c
new file mode 100644 (file)
index 0000000..378b685
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * ------------------------------------------------------------------------
+ *   File Name: fixmap.c
+ *      Author: Zhao Yanbai
+ *              2025-12-31 23:10:37 Wednesday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <fixmap.h>
+#include <assert.h>
+#include <printk.h>
+
+#define FIX_MAP_VADDR_REAL_END (FIX_MAP_VADDR_BASE + (FIX_END_PAD + 1) * PAGE_SIZE)
+
+void fixmap_init() {
+    // TODO
+}
+
+typedef struct _fixmap {
+    paddr_t paddr;
+    vaddr_t vaddr;
+} fixmap_t;
+
+fixmap_t fixmap[FIX_END_PAD + 1] = {0};
+
+void set_fixmap(uint32_t fixid, paddr_t paddr) {
+    assert(fixid >= FIX_BGN_PAD);
+    assert(fixid <= FIX_END_PAD);
+
+    vaddr_t vaddr = fixid_to_vaddr(fixid);
+
+    set_pte_paddr(vaddr, paddr, PAGE_P | PAGE_WR);
+
+#if 1
+    fixmap[fixid].paddr = paddr;
+    fixmap[fixid].vaddr = vaddr;
+#endif
+}
+
+vaddr_t fixid_to_vaddr(uint32_t fixid) {
+    assert(fixid >= FIX_BGN_PAD);
+    assert(fixid <= FIX_END_PAD);
+
+    return FIX_MAP_VADDR_BASE + fixid * PAGE_SIZE;
+}
+
+uint32_t vaddr_to_fixid(vaddr_t vaddr) {
+    assert(vaddr >= FIX_MAP_VADDR_BASE);
+    assert(vaddr < FIX_MAP_VADDR_END);
+    assert(vaddr < FIX_MAP_VADDR_REAL_END);
+
+    uint32_t fixid = ((vaddr & PAGE_MASK) - FIX_MAP_VADDR_BASE) / PAGE_SIZE;
+
+    return fixid;
+}
+
+void dump_fixmap() {
+    for (int i = 0; i <= FIX_END_PAD; i++) {
+        fixmap_t* fmi = &fixmap[i];
+        if (fmi->paddr == 0 || fmi->vaddr == 0) {
+            continue;
+        }
+        printk("fixmap[%d]: map 0x%08x to kernel vaddr 0x%08x\n", i, fmi->paddr, fmi->vaddr);
+    }
+}
index 056d47a6c11b019a4c9b420d80dc2402ddcbf362..83b65da34dfefa5be72047c68bbabba2b94cc25c 100644 (file)
@@ -88,10 +88,10 @@ void setup_kernel() {
     init_mm();
 
     init_buffer();
-
 #if 0
     parse_rsdt(system.rsdt_addr);
-
+#endif
+#if 1
     void init_apic();
     init_apic();
 #endif
@@ -141,4 +141,7 @@ void setup_kernel() {
 
     void init_sata();
     init_sata();
+
+    void dump_fixmap();
+    dump_fixmap();
 }
diff --git a/mm/mm.c b/mm/mm.c
index 5119dfaa0238ab61345842f7ccea18f8c60496b5..cfb938d2d78c89348afe165e6d1d74b64044f0c1 100644 (file)
--- a/mm/mm.c
+++ b/mm/mm.c
@@ -90,7 +90,7 @@ void init_paging() {
         }
 
         // 清空页表
-        memset((void*)pg_table, 0xAC, PAGE_SIZE);
+        memset((void*)pg_table, 0x00, PAGE_SIZE);
 
         // 把页表地址填入pgd
         init_pgd[i] = (pde_t)((unsigned long)(pg_table) | PAGE_P | PAGE_WR);
index f6d345f6b2ac1a9d254d8523f29771817480d395..2ad85532cae7c3e16d89291134baaa0e1ed73ba0 100644 (file)
--- a/mm/page.c
+++ b/mm/page.c
@@ -141,7 +141,7 @@ void page_map(vaddr_t vaddr, paddr_t paddr, uint32_t flags) {
     int npte = get_npte(vaddr);
 
     // 获取页目录地址
-    pde_t* pgd = (pde_t*)pa2va(get_pgd());
+    pde_t* pgd = (pde_t*)get_pgd();
 
     pte_t* pgt = 0;
     pde_t pde = pgd[npde];
@@ -163,3 +163,34 @@ void page_map(vaddr_t vaddr, paddr_t paddr, uint32_t flags) {
 
     asm volatile("invlpg (%0)" : : "r"(vaddr));
 }
+
+typedef uint32_t pfn_t;
+
+void set_pte_pfn(vaddr_t vaddr, pfn_t pfn, uint32_t flags) {
+    assert(PAGE_ALIGN(vaddr) == vaddr);
+    assert(PAGE_FLAGS(flags) == flags);
+    assert(pfn >= 0);
+    assert(pfn < (1 << (32 - PAGE_SHIFT)));  // 最大4G空间
+
+    int npde = get_npde(vaddr);
+    int npte = get_npte(vaddr);
+
+    pde_t* pgd = (pde_t*)get_pgd();
+    assert(pgd != 0);
+
+    pde_t pde = pgd[npde];
+    assert(pde & PAGE_P == PAGE_P);
+
+    pte_t* pgt = (pte_t*)pa2va(PAGE_ALIGN(pde));
+    pte_t pte = pgt[npte];
+    assert(pte == 0);
+
+    pgt[npte] = (pfn << PAGE_SHIFT) | flags;
+}
+
+void set_pte_paddr(vaddr_t vaddr, paddr_t paddr, uint32_t flags) {
+    assert(PAGE_ALIGN(vaddr) == vaddr);
+    assert(PAGE_ALIGN(paddr) == paddr);
+    assert(PAGE_FLAGS(flags) == flags);
+    set_pte_pfn(vaddr, paddr >> PAGE_SHIFT, flags);
+}