From: zhaoyanbai Date: Thu, 1 Oct 2026 04:17:35 +0000 (+0800) Subject: 内核地址空间的页表项开启GLOBAL比特位 X-Git-Url: http://repos.zhaoyanbai.com/?a=commitdiff_plain;h=7fd745178cdf385d9559f0c5235bcad0ec008ace;p=kernel.git 内核地址空间的页表项开启GLOBAL比特位 --- diff --git a/drivers/vga.c b/drivers/vga.c index b8697b6..bd66bad 100644 --- a/drivers/vga.c +++ b/drivers/vga.c @@ -11,6 +11,7 @@ #include #include #include +#include static uint16_t* vga_vram_base_vaddr = (uint16_t*)pa2va(vga_vram_base_paddr); diff --git a/include/page.h b/include/page.h index 22e56bc..c2eb14e 100644 --- a/include/page.h +++ b/include/page.h @@ -18,23 +18,25 @@ #define _PAGE_H #include +#include /* -| CR0的PG | CR4的PAE | CR4的PSE | PDE的PS | 页面规模 | 物理地址规模 | -| ------- | -------- | -------- | ------- | -------- | ------------ | -| 0 | × | × | × | ― | 禁止分页 | -| 1 | 0 | 0 | × | 4KB | 32位 | -| 1 | 0 | 1 | 0 | 4KB | 32位 | -| 1 | 0 | 1 | 1 | 4MB | 32位 | -| 1 | 1 | × | 0 | 4KB | 36位 | -| 1 | 1 | × | 1 | 2MB | 36位 | +| CR0.PG | CR4.PAE | CR4.PSE | PDE.PS | PAGE SIZE | 物理地址规模 | +| ------- | -------- | -------- | ------- | --------- | ---------- | +| 0 | × | × | × | ― | disabled | +| 1 | 0 | 0 | × | 4KB | 32bit | +| 1 | 0 | 1 | 0 | 4KB | 32bit | +| 1 | 0 | 1 | 1 | 4MB | 32bit | +| 1 | 1 | × | 0 | 4KB | 36bit | +| 1 | 1 | × | 1 | 2MB | 36bit | */ -#define PAGE_P 0x1 // 在内存中 -#define PAGE_WR 0x2 // 表示可读写 -#define PAGE_US 0x4 // 用户级 +#define PAGE_P 0x001 // 在内存中 +#define PAGE_WR 0x002 // 表示可读写 +#define PAGE_US 0x004 // 用户级 +#define PAGE_G 0x100 // 全局页表项 #define PAGE_SHIFT (12) #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -44,12 +46,39 @@ #define PAGE_PDE_CNT 1024 #define PAGE_PTE_CNT 1024 -// P: 有效位。0 表示当前表项无效。 -// R/W: 0 表示只读。1表示可读写。 -// U/S: 0 表示只能0、1、2特权级可访问。3 表示只有特权级程序可访问 -// A: 0 表示该页未被访问,1表示已被访问。 -// D: 脏位。0表示该页未写过,1表示该页被写过 -// PS: 只存在于页目录表。在CR4中的PSE打开的情况下,0表示这是4KB页,指向一个页表。1表示这是4MB大页,直接指向物理页。 +// P: 有效位 +// 0 表示当前表项无效,访问该虚拟地址直接#PF缺页异常,CPU不翻译,也不看其它位,此时余下31位CPU完全不管,内核可以随便用。 +// 修改必须刷对应TLB +// R/W: 0 表示只读写就#PF; 1表示可读写。PDE和PTE要同时看,逻辑与。比如PDE.RW=0 && PTE.RW=1 最终还是只读。 +// 另外还需要注意CR0.WP,如果CR0.WP=0(默认),那么只限制用户态,内核写只读页也不缺页; CR0.WP=1,那么内核写只读页也#PF。 +// U/S: 0 表示只能0、1、2特权级可访问; 3 表示只有特权级程序可访问。 +// 同样是PDE与PTE按逻辑与。 +// PWT: 0 表示写进缓存,迟早刷回内存; 1 表示写缓存同时写内存,慢但内存总是新的。 +// 普通内存映射一般PWT=0,对页表自身、设备内存特殊映射才考虑设置为1。 +// CR0.CD=1时这个位被忽略。 +// PCD: 0 表示可以进cache; 1表示这一页不进CPU cache。 +// 映射设备寄存器、MMIO、帧缓冲时用。普通RAM页不要开,开了性能会崩。 +// CR0.CD=1时这个位也被忽略。 +// A: 0 表示该页未被访问; 1表示已被访问。 +// 改此位从1清0时,如果P=1,建议顺手刷TLB,避免硬件状态不一致。 +// D: 脏位。0表示该页未写过; 1表示该页被写过。只有PTE用这位,PDE这个位忽略或保留。 +// 用于换出页面时判断要不要写回磁盘。D=0的页换出可直接丢弃,磁盘上已经有相同内容; D=1才需要写回。 +// 清D位也要刷新TLB。 +// PS: PAGE SIZE. 只存在于页目录表项。在CR4中的PSE打开的情况下,0表示这是4KB页,指向一个页表。1表示这是4MB大页,直接指向物理页。 +// PAT: PAGE ATTRIBUTE TABLE. 只存在于页表项。 Pentium III后引入的机制。 +// G: GLOBAL 全局位 +// 4K分页下PDE.G被忽略,如果用4MB大页映射内核空间,PDE.G有效 +// 内核空间映射在所有进程页表里都一样,设为全局,切换进程不刷新这些TLB项,减少内核映射的TLB miss。 +// 用户页不能随便设G,会跨进程泄露TLB翻译。改G相关属性也需要注意TLB一致性。 +// AVL: 内核可用 +// 常见用法: +// 1. COW标记(软件位,不是硬件COW) +// 2. 页类型标记: 匿名页、文件页、设备页、共享页 +// 3. 写时复制里记录"这是共享只读页" +// 4. 页面锁标记,禁止换出 + + +// x // |<------ 31~12------>|<------ 11~0 --------->| 比特 // |b a 9 8 7 6 5 4 3 2 1 0| @@ -123,15 +152,9 @@ typedef unsigned long pte_t; #define MAX_ORDER (11) -#define set_cr3(cr3) asm volatile("movl %0, %%cr3" ::"r"(cr3)) -static inline unsigned long get_cr3() { - unsigned long cr3; - asm volatile("movl %%cr3, %0" : "=r"(cr3)); - return cr3; -} static inline pde_t* get_pgd() { - return (pde_t*)pa2va((get_cr3() & PAGE_MASK)); + return (pde_t*)pa2va((read_cr3() & PAGE_MASK)); } enum page_flags { diff --git a/include/processor.h b/include/processor.h index 1aefc19..8ce6618 100644 --- a/include/processor.h +++ b/include/processor.h @@ -221,4 +221,10 @@ extern tss_t tss; #define CR4_OSXMMEEXCPT (1 << 10) // R/W Operating System Unmasked Exception Support #define CR4_OSXSAVE (1 << 18) // R/W XSAVE and Processor Extended States Enable Bit + +uint32_t read_cr3(); +uint32_t read_cr4(); +void write_cr3(uint32_t cr3); +void write_cr4(uint32_t cr4); + #endif //_DESCRIPTOR_H diff --git a/include/system.h b/include/system.h index fb6a900..1cd8597 100644 --- a/include/system.h +++ b/include/system.h @@ -18,7 +18,6 @@ #define _SYSTEM_H #include -#include #include #define PT_REGS_EBX 0 diff --git a/kernel/sched.c b/kernel/sched.c index bb26559..2ef444a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -39,7 +39,7 @@ pid_t get_next_pid() { } void load_cr3(task_t* tsk) { - set_cr3(tsk->cr3); + write_cr3(tsk->cr3); } extern pde_t __initdata init_pgd[PDECNT_PER_PAGE] __attribute__((__aligned__(PAGE_SIZE))); @@ -220,7 +220,7 @@ task_t* alloc_task_t() { } void switch_to() { - set_cr3(current->cr3); + write_cr3(current->cr3); tss.esp0 = current->esp0; } diff --git a/kernel/setup.c b/kernel/setup.c index ae30418..4b062ff 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -161,4 +161,8 @@ void setup_kernel() { void dump_fixmap(); dump_fixmap(); + + uint32_t read_cr4(); + uint32_t cr4 = read_cr4(); + printk("CR4: %08x\n", cr4); } diff --git a/kernel/system.c b/kernel/system.c index 0b3ca1e..d4121b5 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -214,6 +214,26 @@ void set_tss() { asm("ltr %%ax" ::"a"((INDEX_TSS << 3) + 3)); } +uint32_t read_cr3() { + uint32_t cr3 = 0; + asm volatile("movl %%cr3, %0" : "=r"(cr3)); + return cr3; +} + +void write_cr3(uint32_t cr3) { + asm volatile("movl %0, %%cr3" ::"r"(cr3)); +} + +uint32_t read_cr4() { + uint32_t cr4 = 0; + asm volatile("movl %%cr4, %0" : "=r"(cr4)); + return cr4; +} + +void write_cr4(uint32_t cr4) { + asm volatile("movl %0, %%cr4" ::"r"(cr4)); +} + int sysc_reboot(int mode) { void do_reboot(); void do_poweroff(); diff --git a/kernel/task_init.c b/kernel/task_init.c index f5661c7..e71eaa8 100644 --- a/kernel/task_init.c +++ b/kernel/task_init.c @@ -226,7 +226,7 @@ void init_task_entry() { printk("RING3 ENTRY %x page %x pgd inx %u pt inx %u\n", mod_start, text_at, pgd_index, pt_index); - set_cr3(current->cr3); + write_cr3(current->cr3); asm("sysexit;" ::"d"(mod_start), "c"(mod_start + PAGE_SIZE - 4)); #endif diff --git a/mm/mm.c b/mm/mm.c index 999e433..8e9d74b 100644 --- a/mm/mm.c +++ b/mm/mm.c @@ -47,6 +47,11 @@ void init_paging() { pte_t* pg_table = 0; void* alloc_from_bootmem(unsigned long size, char* title); + // 打开CR4的 PAGE GLOBAL 功能 + uint32_t cr4 = read_cr4(); + cr4 |= CR4_PGE; + write_cr4(cr4); + // 在multiboot.S是已经初始化了BOOT_INIT_PAGETBL_CNT个页 // 这里接着初始化剩余的页 // 最大限制内存1G @@ -64,7 +69,7 @@ void init_paging() { init_pgd[get_npde(page_addr)] = (pde_t)((unsigned long)(pg_table) | PAGE_P | PAGE_WR); } - pg_table[npte] = (pte_t)(page_addr | PAGE_P | PAGE_WR); + pg_table[npte] = (pte_t)(page_addr | PAGE_P | PAGE_WR | PAGE_G); } // paging for kernel space @@ -124,7 +129,7 @@ void init_paging() { } } - set_cr3(va2pa(init_pgd)); + write_cr3(va2pa(init_pgd)); // 测试显存 for (int i = 0; i < system.x_resolution * (system.y_resolution - 32); i++) {