From: acevest Date: Thu, 1 Jan 2026 08:05:31 +0000 (+0800) Subject: 简单支持fixmap并把LAPIC通过fixmap映射到内核 X-Git-Url: http://repos.zhaoyanbai.com/Mou_128.png?a=commitdiff_plain;h=ed5885d0426fdd6a5b0e0436ba067d075c8c4b93;p=kernel.git 简单支持fixmap并把LAPIC通过fixmap映射到内核 --- diff --git a/include/fixmap.h b/include/fixmap.h new file mode 100644 index 0000000..21b5b35 --- /dev/null +++ b/include/fixmap.h @@ -0,0 +1,36 @@ +/* + * ------------------------------------------------------------------------ + * File Name: fixmap.h + * Author: Zhao Yanbai + * 2025-12-31 23:10:32 Wednesday CST + * Description: none + * ------------------------------------------------------------------------ + */ + +#pragma once + +#include +#include +#include + +#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 index 0000000..f27aaaa --- /dev/null +++ b/include/kdef.h @@ -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) diff --git a/include/page.h b/include/page.h index 4aff24d..a3dcb74 100644 --- a/include/page.h +++ b/include/page.h @@ -17,6 +17,8 @@ #ifndef _PAGE_H #define _PAGE_H +#include + /* | 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 diff --git a/include/system.h b/include/system.h index e4e0341..67f8e29 100644 --- a/include/system.h +++ b/include/system.h @@ -19,7 +19,7 @@ #include #include -#define KRNLADDR PAGE_OFFSET +#include #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; diff --git a/kernel/apic.c b/kernel/apic.c index d4ae8e9..8e3f3dc 100644 --- a/kernel/apic.c +++ b/kernel/apic.c @@ -10,16 +10,20 @@ #include #include #include +#include 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 } diff --git a/kernel/exec.c b/kernel/exec.c index 056bc90..85e5d40 100644 --- a/kernel/exec.c +++ b/kernel/exec.c @@ -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 index 0000000..378b685 --- /dev/null +++ b/kernel/fixmap.c @@ -0,0 +1,66 @@ +/* + * ------------------------------------------------------------------------ + * File Name: fixmap.c + * Author: Zhao Yanbai + * 2025-12-31 23:10:37 Wednesday CST + * Description: none + * ------------------------------------------------------------------------ + */ + +#include +#include +#include + +#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); + } +} diff --git a/kernel/setup.c b/kernel/setup.c index 056d47a..83b65da 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -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 5119dfa..cfb938d 100644 --- 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); diff --git a/mm/page.c b/mm/page.c index f6d345f..2ad8553 100644 --- 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); +}