]> Zhao Yanbai Git Server - minix.git/commitdiff
Library call for cpu features; make kernel and vm use this to query cpu
authorBen Gras <ben@minix3.org>
Fri, 15 May 2009 17:07:36 +0000 (17:07 +0000)
committerBen Gras <ben@minix3.org>
Fri, 15 May 2009 17:07:36 +0000 (17:07 +0000)
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.

include/minix/cpufeature.h [new file with mode: 0644]
include/minix/minlib.h
include/sys/vm_i386.h
kernel/arch/i386/memory.c
kernel/debug.h
lib/i386/misc/Makefile.in
lib/i386/misc/_cpufeature.c [new file with mode: 0644]
servers/vm/i386/pagetable.c
servers/vm/main.c
servers/vm/vmproc.h

diff --git a/include/minix/cpufeature.h b/include/minix/cpufeature.h
new file mode 100644 (file)
index 0000000..0dcb9a1
--- /dev/null
@@ -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
index 52379a808e4d103a72e01e4980a0006963e21c06..79c4e7be4dfd8fcd8d6918d76d068f1af3f37f3f 100755 (executable)
@@ -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));
index f006db51191c8b31769e95e441c85c8239097721..8932dffb35d46d1b24fa78f0edb15e4ee1379425 100644 (file)
@@ -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 */
index 90be74d8def72bbb15c93ba363b5da8148a67c1b..a04b0e94c120f611c26e8eb5668ffb0ff151c41b 100644 (file)
@@ -6,6 +6,7 @@
 #include <minix/type.h>
 #include <minix/syslib.h>
 #include <minix/sysutil.h>
+#include <minix/cpufeature.h>
 #include <string.h>
 
 #include <sys/vm_i386.h>
@@ -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,
index ee2539280903bdc5761fde4b51575b97628b843f..283b00be24a0a47151c27295aaaa1e139c02044a 100644 (file)
@@ -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 */
index 3b139e97e501b377f166d4a4101db8796a2ba9cd..e76269114e77ce3fdd94ae8e4a0c04476b593b6a 100644 (file)
@@ -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 (file)
index 0000000..c1e8ef3
--- /dev/null
@@ -0,0 +1,34 @@
+
+#include <stdint.h>
+#include <minix/minlib.h>
+#include <minix/cpufeature.h>
+#include <sys/vm_i386.h>
+
+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, &params, &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;
+}
+
index f2cb0dfc41e21d8d7a96755d9b71d28d3b495d2b..235eafcf78dc0dbd75bca74e982b4c734f608084 100644 (file)
@@ -16,6 +16,7 @@
 #include <minix/sysutil.h>
 #include <minix/syslib.h>
 #include <minix/safecopies.h>
+#include <minix/cpufeature.h>
 
 #include <errno.h>
 #include <assert.h>
@@ -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)))
index 47aed88bb78e75a64b361173f02b33a32d91dbb7..8b3b18d3ae6bc1ce13e25aa0cd43c9c9c5c7a2e7 100644 (file)
@@ -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.
         */
index 66a83052df1bb76c1785e5b57ca46f1c257a08ed..7b9d6a18ea0252ecafc30078b9c51971f51e9e4c 100644 (file)
@@ -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;