--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * 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);
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * 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)
#ifndef _PAGE_H
#define _PAGE_H
+#include <kdef.h>
+
/*
| CR0的PG | CR4的PAE | CR4的PSE | PDE的PS | 页面规模 | 物理地址规模 |
#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
}
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;
};
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
#include <assert.h>
#include <page.h>
-#define KRNLADDR PAGE_OFFSET
+#include <kdef.h>
#define PT_REGS_EBX 0
#define PT_REGS_ECX 4
#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 {
void* rsdt_addr;
dev_t root_dev;
+
+ bool x2apic;
#define CMD_LINE_SIZE 128
const char* cmdline;
#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");
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
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;
}
void init_apic() {
-#if 0
lapic_init();
-#endif
}
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);
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * 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);
+ }
+}
init_mm();
init_buffer();
-
#if 0
parse_rsdt(system.rsdt_addr);
-
+#endif
+#if 1
void init_apic();
init_apic();
#endif
void init_sata();
init_sata();
+
+ void dump_fixmap();
+ dump_fixmap();
}
}
// 清空页表
- 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);
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];
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);
+}