From: Ben Gras Date: Fri, 15 May 2009 17:07:36 +0000 (+0000) Subject: Library call for cpu features; make kernel and vm use this to query cpu X-Git-Tag: v3.1.4~28 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=bdab3c4cfb0a3d55ea4e587a8b4f5c40348c1d05;p=minix.git Library call for cpu features; make kernel and vm use this to query cpu features (specifically: 4MB pages and TLB global bit). Only enable these features in CR4 if available. 4MB pages to be used in the near future. --- diff --git a/include/minix/cpufeature.h b/include/minix/cpufeature.h new file mode 100644 index 000000000..0dcb9a154 --- /dev/null +++ b/include/minix/cpufeature.h @@ -0,0 +1,10 @@ + +#ifndef _MINIX_CPUFEATURE_H +#define _MINIX_CPUFEATURE_H 1 + +#define _CPUF_I386_PSE 1 /* Page Size Extension */ +#define _CPUF_I386_PGE 2 /* Page Global Enable */ + +_PROTOTYPE(int _cpufeature, (int featureno)); + +#endif diff --git a/include/minix/minlib.h b/include/minix/minlib.h index 52379a808..79c4e7be4 100755 --- a/include/minix/minlib.h +++ b/include/minix/minlib.h @@ -15,6 +15,7 @@ _PROTOTYPE(void std_err, (char *_s)); _PROTOTYPE(void prints, (const char *_s, ...)); _PROTOTYPE(int fsversion, (char *_dev, char *_prog)); _PROTOTYPE(int getprocessor, (void)); +_PROTOTYPE(int _cpuid, (u32_t eax_in, u32_t *eax, u32_t *ebx, u32_t *ecx, u32_t *edx)); _PROTOTYPE(int load_mtab, (char *_prog_name)); _PROTOTYPE(int rewrite_mtab, (char *_prog_name)); _PROTOTYPE(int get_mtab_entry, (char *_s1, char *_s2, char *_s3, char *_s4)); diff --git a/include/sys/vm_i386.h b/include/sys/vm_i386.h index f006db511..8932dffb3 100644 --- a/include/sys/vm_i386.h +++ b/include/sys/vm_i386.h @@ -58,3 +58,7 @@ sys/vm_i386.h */ #define I386_VM_PFE_W 0x02 /* Caused by write (otherwise read) */ #define I386_VM_PFE_U 0x04 /* CPU in user mode (otherwise supervisor) */ + +/* CPUID flags */ +#define CPUID1_EDX_PSE (1L << 3) /* Page Size Extension */ +#define CPUID1_EDX_PGE (1L << 13) /* Page Global (bit) Enable */ diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 90be74d8d..a04b0e94c 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -155,7 +156,10 @@ PRIVATE void set_cr3() PRIVATE void vm_enable_paging(void) { u32_t cr0, cr4; + int psok, pgeok; + psok = _cpufeature(_CPUF_I386_PSE); + pgeok = _cpufeature(_CPUF_I386_PGE); cr0= read_cr0(); cr4= read_cr4(); @@ -169,7 +173,14 @@ PRIVATE void vm_enable_paging(void) /* First enable paging, then enable global page flag. */ write_cr0(cr0 | I386_CR0_PG); - write_cr4(cr4 | I386_CR4_PGE); + + /* May we enable these features? */ + if(pgeok) + cr4 |= I386_CR4_PGE; + if(psok) + cr4 |= I386_CR4_PSE; + + write_cr4(cr4); } PUBLIC vir_bytes alloc_remote_segment(u32_t *selector, diff --git a/kernel/debug.h b/kernel/debug.h index ee2539280..283b00be2 100644 --- a/kernel/debug.h +++ b/kernel/debug.h @@ -24,7 +24,7 @@ #define DEBUG_TIME_LOCKS 1 /* Runtime sanity checking. */ -#define DEBUG_VMASSERT 0 +#define DEBUG_VMASSERT 1 #define DEBUG_SCHED_CHECK 0 #endif /* DEBUG_H */ diff --git a/lib/i386/misc/Makefile.in b/lib/i386/misc/Makefile.in index 3b139e97e..e76269114 100644 --- a/lib/i386/misc/Makefile.in +++ b/lib/i386/misc/Makefile.in @@ -6,6 +6,7 @@ LIBRARIES=libc libc_FILES=" \ _cpuid.s \ + _cpufeature.c \ alloca.s \ get_bp.s \ getprocessor.s \ diff --git a/lib/i386/misc/_cpufeature.c b/lib/i386/misc/_cpufeature.c new file mode 100644 index 000000000..c1e8ef353 --- /dev/null +++ b/lib/i386/misc/_cpufeature.c @@ -0,0 +1,34 @@ + +#include +#include +#include +#include + +int _cpufeature(int cpufeature) +{ + u32_t cpuid_feature_edx = 0; + int proc; + + proc = getprocessor(); + + /* If processor supports CPUID and its CPUID supports enough + * parameters, retrieve EDX feature flags to test against. + */ + if(proc >= 586) { + u32_t params, a, b, c, d; + _cpuid(0, ¶ms, &b, &c, &d); + if(params > 0) { + _cpuid(1, &a, &b, &c, &cpuid_feature_edx); + } + } + + switch(cpufeature) { + case _CPUF_I386_PSE: + return cpuid_feature_edx & CPUID1_EDX_PSE; + case _CPUF_I386_PGE: + return cpuid_feature_edx & CPUID1_EDX_PGE; + } + + return 0; +} + diff --git a/servers/vm/i386/pagetable.c b/servers/vm/i386/pagetable.c index f2cb0dfc4..235eafcf7 100644 --- a/servers/vm/i386/pagetable.c +++ b/servers/vm/i386/pagetable.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,9 @@ #include "memory.h" +int global_bit_ok = 0; +int bigpage_ok = 0; + /* Location in our virtual address space where we can map in * any physical page we want. */ @@ -70,6 +74,9 @@ static struct { /* Nevertheless, introduce these macros to make the code readable. */ #define CLICK2PAGE(c) ((c) / CLICKSPERPAGE) +/* Page table that contains pointers to all page directories. */ +u32_t page_directories_phys, *page_directories = NULL; + #if SANITYCHECKS #define PT_SANE(p) { pt_sanitycheck((p), __FILE__, __LINE__); SANITYCHECK(SCL_DETAIL); } /*===========================================================================* @@ -507,7 +514,10 @@ PUBLIC void pt_init(void) phys_bytes lo, hi; vir_bytes extra_clicks; u32_t moveup = 0; - + + global_bit_ok = _cpufeature(_CPUF_I386_PGE); + bigpage_ok = _cpufeature(_CPUF_I386_PSE); + /* Shorthand. */ newpt = &vmp->vm_pt; @@ -567,6 +577,15 @@ PUBLIC void pt_init(void) /* Map in kernel. */ if(pt_mapkernel(newpt) != OK) vm_panic("pt_init: pt_mapkernel failed", NO_NUM); + +#if 0 + /* Allocate us a page table in which to remember page directory + * pointers. + */ + if(!(page_directories = vm_allocpages(&page_directories_phys, + 1, VMP_PAGETABLE))) + vm_panic("no virt addr for vm mappings", NO_NUM); +#endif /* Give our process the new, copied, private page table. */ pt_bind(newpt, vmp); @@ -627,10 +646,23 @@ PUBLIC void pt_init(void) *===========================================================================*/ PUBLIC int pt_bind(pt_t *pt, struct vmproc *who) { + int slot; + /* Basic sanity checks. */ vm_assert(who); vm_assert(who->vm_flags & VMF_INUSE); if(pt) PT_SANE(pt); + vm_assert(pt); + +#if 0 + slot = who->vm_slot; + vm_assert(slot >= 0); + vm_assert(slot < ELEMENTS(vmproc)); + vm_assert(!(pt->pt_dir_phys & ~I386_VM_ADDR_MASK)); + + page_directories[slot] = (pt->pt_dir_phys & I386_VM_ADDR_MASK) | + (I386_VM_PRESENT|I386_VM_WRITE); +#endif /* Tell kernel about new page table root. */ return sys_vmctl(who->vm_endpoint, VMCTL_I386_SETCR3, @@ -673,18 +705,31 @@ PUBLIC void pt_free(pt_t *pt) PUBLIC int pt_mapkernel(pt_t *pt) { int r; + static int pde = -1; + int global; + + if(global_bit_ok) global = I386_VM_GLOBAL; /* Any i386 page table needs to map in the kernel address space. */ vm_assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE); + if(pde == -1) { + int pde1, pde2; + pde1 = I386_VM_PDE(KERNEL_TEXT); + pde2 = I386_VM_PDE(KERNEL_DATA+KERNEL_DATA_LEN); + vm_assert(pde1 == pde2); + pde = pde1; + vm_assert(pde >= 0); + } + /* Map in text. flags: don't write, supervisor only */ if((r=pt_writemap(pt, KERNEL_TEXT, KERNEL_TEXT, KERNEL_TEXT_LEN, - I386_VM_PRESENT|I386_VM_GLOBAL, 0)) != OK) + I386_VM_PRESENT|global, 0)) != OK) return r; /* Map in data. flags: read-write, supervisor only */ if((r=pt_writemap(pt, KERNEL_DATA, KERNEL_DATA, KERNEL_DATA_LEN, - I386_VM_PRESENT|I386_VM_WRITE|I386_VM_GLOBAL, 0)) != OK) + I386_VM_PRESENT|I386_VM_WRITE|global, 0)) != OK) return r; return OK; @@ -739,17 +784,25 @@ PUBLIC void pt_cycle(void) #define MAPFLAGS WMF_OVERWRITE #endif +static u32_t ismapped = MAP_NONE; + #define PHYS_MAP(a, o) \ { int r; \ - u32_t wipeme = (u32_t) varmap; \ + u32_t wantmapped; \ vm_assert(varmap); \ (o) = (a) % I386_PAGE_SIZE; \ - r = pt_writemap(&vmp->vm_pt, (vir_bytes) varmap_loc, (a) - (o), I386_PAGE_SIZE, \ - I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE, MAPFLAGS); \ - if(r != OK) \ - vm_panic("PHYS_MAP: pt_writemap failed", NO_NUM); \ - /* pt_bind() flushes TLB. */ \ - pt_bind(&vmp->vm_pt, vmp); \ + wantmapped = (a) - (o); \ + if(wantmapped != ismapped || ismapped == MAP_NONE) { \ + r = pt_writemap(&vmp->vm_pt, (vir_bytes) varmap_loc, \ + wantmapped, I386_PAGE_SIZE, \ + I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE, \ + MAPFLAGS); \ + if(r != OK) \ + vm_panic("PHYS_MAP: pt_writemap", NO_NUM); \ + ismapped = wantmapped; \ + /* pt_bind() flushes TLB. */ \ + pt_bind(&vmp->vm_pt, vmp); \ + } \ } #define PHYSMAGIC 0x7b9a0590 @@ -758,6 +811,7 @@ PUBLIC void pt_cycle(void) #define PHYS_UNMAP if(OK != pt_writemap(&vmp->vm_pt, varmap_loc, MAP_NONE,\ I386_PAGE_SIZE, 0, WMF_OVERWRITE)) { \ vm_panic("PHYS_UNMAP: pt_writemap failed", NO_NUM); } + ismapped = MAP_NONE; #endif #define PHYS_VAL(o) (* (phys_bytes *) (varmap + (o))) diff --git a/servers/vm/main.c b/servers/vm/main.c index 47aed88bb..8b3b18d3a 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -176,7 +176,7 @@ PUBLIC int main(void) *===========================================================================*/ PRIVATE void vm_init(void) { - int s; + int s, i; struct memory mem_chunks[NR_MEMS]; struct boot_image image[NR_BOOT_PROCS]; struct boot_image *ip; @@ -194,6 +194,10 @@ PRIVATE void vm_init(void) /* Set table to 0. This invalidates all slots (clear VMF_INUSE). */ memset(vmproc, 0, sizeof(vmproc)); + for(i = 0; i < ELEMENTS(vmproc); i++) { + vmproc[i].vm_slot = i; + } + /* Walk through boot-time system processes that are alive * now and make valid slot entries for them. */ diff --git a/servers/vm/vmproc.h b/servers/vm/vmproc.h index 66a83052d..7b9d6a18e 100644 --- a/servers/vm/vmproc.h +++ b/servers/vm/vmproc.h @@ -37,6 +37,8 @@ struct vmproc { callback_t vm_callback; /* function to call on vfs reply */ int vm_callback_type; /* expected message type */ + int vm_slot; /* process table slot */ + union { struct { cp_grant_id_t gid;