From a652906986e061b69fee367ff20a87d2a6b16dd3 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 10 Nov 2008 15:18:48 +0000 Subject: 2008-11-10 Samuel Thibault [task #8135 --- ``PAE for GNU Mach'] * i386/configfrag.ac: Add --enable-pae option, which defines PAE. * i386/i386/i386asm.sym (PDPSHIFT, PDEMASK): New assembly macros. * i386/i386/locore.S [PAE] (copyout_retry): Use page directory pointer bits. * i386/i386at/model_dep.c [PAE] (i386at_init): Set second initial 2MB page. Enable PAE bit. Set cr3 to page directory pointer table instead of page directory. * i386/intel/pmap.c [PAE] (pmap_bootstrap, pmap_create): Allocate 4 pages for dirbase. Setup pdpbase. [PAE] (pmap_destroy): Free 4 pages from dirbase. Free pdpbase. * i386/intel/pmap.h [PAE] (pt_entry_t): Typedef to unsigned long long. [PAE] (PDPSHIFT, PDPNUM, PDPMASK): New macros. [PAE] (PDESHIFT, PDEMASK, PTEMASK): Set to PAE values. [PAE] (lin2pdenum, NPDES): Make them take the page directory pointer index into account too. [PAE] (struct pmap): Add `pdpbase' member. (set_dirbase): Remove macro, replaced by... (set_pmap): New macro, taking a pmap instead of the dirbase. (PMAP_ACTIVATE_USER): Use set_pmap instead of set_dirbase. --- ChangeLog | 23 +++++++++++++++++++++++ i386/configfrag.ac | 10 ++++++++++ i386/i386/i386asm.sym | 4 ++++ i386/i386/locore.S | 10 ++++++++++ i386/i386at/model_dep.c | 14 +++++++++++++- i386/intel/pmap.c | 36 +++++++++++++++++++++++++++++++++--- i386/intel/pmap.h | 39 +++++++++++++++++++++++++++++++++------ 7 files changed, 126 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index a8fed73..6cb1052 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2008-11-10 Samuel Thibault + + [task #8135 --- ``PAE for GNU Mach'] + * i386/configfrag.ac: Add --enable-pae option, which defines PAE. + * i386/i386/i386asm.sym (PDPSHIFT, PDEMASK): New assembly macros. + * i386/i386/locore.S [PAE] (copyout_retry): Use page directory pointer + bits. + * i386/i386at/model_dep.c [PAE] (i386at_init): Set second initial 2MB + page. Enable PAE bit. Set cr3 to page directory pointer table instead + of page directory. + * i386/intel/pmap.c [PAE] (pmap_bootstrap, pmap_create): Allocate 4 + pages for dirbase. Setup pdpbase. + [PAE] (pmap_destroy): Free 4 pages from dirbase. Free pdpbase. + * i386/intel/pmap.h [PAE] (pt_entry_t): Typedef to unsigned long long. + [PAE] (PDPSHIFT, PDPNUM, PDPMASK): New macros. + [PAE] (PDESHIFT, PDEMASK, PTEMASK): Set to PAE values. + [PAE] (lin2pdenum, NPDES): Make them take the page directory pointer + index into account too. + [PAE] (struct pmap): Add `pdpbase' member. + (set_dirbase): Remove macro, replaced by... + (set_pmap): New macro, taking a pmap instead of the dirbase. + (PMAP_ACTIVATE_USER): Use set_pmap instead of set_dirbase. + 2008-11-05 Shakthi Kannan * ipc/mach_port.c (mach_port_insert_right): Cast poly into diff --git a/i386/configfrag.ac b/i386/configfrag.ac index bada87d..19112a0 100644 --- a/i386/configfrag.ac +++ b/i386/configfrag.ac @@ -102,6 +102,16 @@ if [ x"$enable_lpr" = xyes ]; then] [else] AM_CONDITIONAL([enable_lpr], [false]) [fi] + + +AC_ARG_ENABLE([pae], + AS_HELP_STRING([--enable-pae], [enable PAE support])) +[if [ x"$enable_pae" = xyes ]; then] + AC_DEFINE([PAE], [1], [PAE support]) + AM_CONDITIONAL([enable_pae], [true]) +[else] + AM_CONDITIONAL([enable_pae], [false]) +[fi] dnl Local Variables: dnl mode: autoconf diff --git a/i386/i386/i386asm.sym b/i386/i386/i386asm.sym index 8cfb2c0..f31341e 100644 --- a/i386/i386/i386asm.sym +++ b/i386/i386/i386asm.sym @@ -91,7 +91,11 @@ expr VM_MAX_ADDRESS expr VM_MIN_KERNEL_ADDRESS KERNELBASE expr KERNEL_STACK_SIZE +#if PAE +expr PDPSHIFT +#endif /* PAE */ expr PDESHIFT +expr PDEMASK expr PTESHIFT expr PTEMASK diff --git a/i386/i386/locore.S b/i386/i386/locore.S index 252ecaf..2228482 100644 --- a/i386/i386/locore.S +++ b/i386/i386/locore.S @@ -1267,8 +1267,18 @@ Entry(copyoutmsg) */ copyout_retry: movl %cr3,%ecx /* point to page directory */ +#if PAE + movl %edi,%eax /* get page directory pointer bits */ + shrl $(PDPSHIFT),%eax /* from user address */ + movl KERNELBASE(%ecx,%eax,4),%ecx + /* get page directory pointer */ + andl $(PTE_PFN),%ecx /* isolate page frame address */ +#endif /* PAE */ movl %edi,%eax /* get page directory bits */ shrl $(PDESHIFT),%eax /* from user address */ +#if PAE + andl $(PDEMASK),%eax +#endif /* PAE */ movl KERNELBASE(%ecx,%eax,4),%ecx /* get page directory pointer */ testl $(PTE_V),%ecx /* present? */ diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c index b208cb2..2426cde 100644 --- a/i386/i386at/model_dep.c +++ b/i386/i386at/model_dep.c @@ -279,7 +279,16 @@ i386at_init(void) */ kernel_page_dir[lin2pdenum(0)] = kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)]; +#if PAE + kernel_page_dir[lin2pdenum(0) + 1] = + kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS) + 1]; + set_cr3((unsigned)kernel_pmap->pdpbase); + if (!CPU_HAS_FEATURE(CPU_FEATURE_PAE)) + panic("CPU doesn't have support for PAE."); + set_cr4(get_cr4() | CR4_PAE); +#else set_cr3((unsigned)kernel_page_dir); +#endif /* PAE */ if (CPU_HAS_FEATURE(CPU_FEATURE_PGE)) set_cr4(get_cr4() | CR4_PGE); set_cr0(get_cr0() | CR0_PG | CR0_WP); @@ -296,7 +305,10 @@ i386at_init(void) /* Get rid of the temporary direct mapping and flush it out of the TLB. */ kernel_page_dir[lin2pdenum(0)] = 0; - set_cr3((unsigned)kernel_page_dir); +#if PAE + kernel_page_dir[lin2pdenum(0) + 1] = 0; +#endif /* PAE */ + flush_tlb(); diff --git a/i386/intel/pmap.c b/i386/intel/pmap.c index b08252e..a648592 100644 --- a/i386/intel/pmap.c +++ b/i386/intel/pmap.c @@ -579,7 +579,21 @@ void pmap_bootstrap() /* * Allocate and clear a kernel page directory. */ +#if PAE + { + vm_offset_t addr; + init_alloc_aligned(PDPNUM * INTEL_PGBYTES, &addr); + kernel_pmap->dirbase = kernel_page_dir = (pt_entry_t*)addr; + } + kernel_pmap->pdpbase = (pt_entry_t*)pmap_grab_page(); + { + int i; + for (i = 0; i < PDPNUM; i++) + kernel_pmap->pdpbase[i] = pa_to_pte((vm_offset_t) kernel_pmap->dirbase + i * INTEL_PGBYTES) | INTEL_PTE_VALID; + } +#else /* PAE */ kernel_pmap->dirbase = kernel_page_dir = (pt_entry_t*)pmap_grab_page(); +#endif /* PAE */ { int i; for (i = 0; i < NPDES; i++) @@ -859,11 +873,24 @@ pmap_t pmap_create(size) panic("pmap_create"); if (kmem_alloc_wired(kernel_map, - (vm_offset_t *)&p->dirbase, INTEL_PGBYTES) + (vm_offset_t *)&p->dirbase, PDPNUM * INTEL_PGBYTES) != KERN_SUCCESS) panic("pmap_create"); - memcpy(p->dirbase, kernel_page_dir, INTEL_PGBYTES); + memcpy(p->dirbase, kernel_page_dir, PDPNUM * INTEL_PGBYTES); + +#if PAE + if (kmem_alloc_wired(kernel_map, + (vm_offset_t *)&p->pdpbase, INTEL_PGBYTES) + != KERN_SUCCESS) + panic("pmap_create"); + { + int i; + for (i = 0; i < PDPNUM; i++) + p->pdpbase[i] = pa_to_pte(kvtophys((vm_offset_t) p->dirbase + i * INTEL_PGBYTES)) | INTEL_PTE_VALID; + } +#endif /* PAE */ + p->ref_count = 1; simple_lock_init(&p->lock); @@ -927,7 +954,10 @@ void pmap_destroy(p) vm_object_unlock(pmap_object); } } - kmem_free(kernel_map, (vm_offset_t)p->dirbase, INTEL_PGBYTES); + kmem_free(kernel_map, (vm_offset_t)p->dirbase, PDPNUM * INTEL_PGBYTES); +#if PAE + kmem_free(kernel_map, (vm_offset_t)p->pdpbase, INTEL_PGBYTES); +#endif /* PAE */ zfree(pmap_zone, (vm_offset_t) p); } diff --git a/i386/intel/pmap.h b/i386/intel/pmap.h index c1d741b..7354a0f 100644 --- a/i386/intel/pmap.h +++ b/i386/intel/pmap.h @@ -65,21 +65,41 @@ * i386/i486 Page Table Entry */ +#if PAE +typedef unsigned long long pt_entry_t; +#else /* PAE */ typedef unsigned int pt_entry_t; +#endif /* PAE */ #define PT_ENTRY_NULL ((pt_entry_t *) 0) #endif /* __ASSEMBLER__ */ #define INTEL_OFFMASK 0xfff /* offset within page */ +#if PAE +#define PDPSHIFT 30 /* page directory pointer */ +#define PDPNUM 4 /* number of page directory pointers */ +#define PDPMASK 3 /* mask for page directory pointer index */ +#define PDESHIFT 21 /* page descriptor shift */ +#define PDEMASK 0x1ff /* mask for page descriptor index */ +#define PTESHIFT 12 /* page table shift */ +#define PTEMASK 0x1ff /* mask for page table index */ +#else /* PAE */ +#define PDPNUM 1 /* number of page directory pointers */ #define PDESHIFT 22 /* page descriptor shift */ #define PDEMASK 0x3ff /* mask for page descriptor index */ #define PTESHIFT 12 /* page table shift */ #define PTEMASK 0x3ff /* mask for page table index */ +#endif /* PAE */ /* * Convert linear offset to page descriptor index */ +#if PAE +/* Making it include the page directory pointer table index too */ +#define lin2pdenum(a) (((a) >> PDESHIFT) & 0x7ff) +#else #define lin2pdenum(a) (((a) >> PDESHIFT) & PDEMASK) +#endif /* * Convert page descriptor index to linear address @@ -92,7 +112,7 @@ typedef unsigned int pt_entry_t; #define ptenum(a) (((a) >> PTESHIFT) & PTEMASK) #define NPTES (intel_ptob(1)/sizeof(pt_entry_t)) -#define NPDES (intel_ptob(1)/sizeof(pt_entry_t)) +#define NPDES (PDPNUM * (intel_ptob(1)/sizeof(pt_entry_t))) /* * Hardware pte bit definitions (to be used directly on the ptes @@ -124,7 +144,10 @@ typedef volatile long cpu_set; /* set of CPUs - must be <= 32 */ /* changed by other processors */ struct pmap { - pt_entry_t *dirbase; /* page directory pointer register */ + pt_entry_t *dirbase; /* page directory table */ +#if PAE + pt_entry_t *pdpbase; /* page directory pointer table */ +#endif /* PAE */ int ref_count; /* reference count */ decl_simple_lock_data(,lock) /* lock on map */ @@ -136,7 +159,11 @@ typedef struct pmap *pmap_t; #define PMAP_NULL ((pmap_t) 0) -#define set_dirbase(dirbase) set_cr3(dirbase) +#if PAE +#define set_pmap(pmap) set_cr3(kvtophys((vm_offset_t)(pmap)->pdpbase)) +#else /* PAE */ +#define set_pmap(pmap) set_cr3(kvtophys((vm_offset_t)(pmap)->dirbase)) +#endif /* PAE */ #if NCPUS > 1 /* @@ -234,7 +261,7 @@ pt_entry_t *pmap_pte(pmap_t pmap, vm_offset_t addr); /* \ * If this is the kernel pmap, switch to its page tables. \ */ \ - set_dirbase(kvtophys((vm_offset_t)tpmap->dirbase)); \ + set_pmap(tpmap); \ } \ else { \ /* \ @@ -252,7 +279,7 @@ pt_entry_t *pmap_pte(pmap_t pmap, vm_offset_t addr); * No need to invalidate the TLB - the entire user pmap \ * will be invalidated by reloading dirbase. \ */ \ - set_dirbase(kvtophys((vm_offset_t)tpmap->dirbase)); \ + set_pmap(tpmap); \ \ /* \ * Mark that this cpu is using the pmap. \ @@ -341,7 +368,7 @@ pt_entry_t *pmap_pte(pmap_t pmap, vm_offset_t addr); #define PMAP_ACTIVATE_USER(pmap, th, my_cpu) { \ register pmap_t tpmap = (pmap); \ \ - set_dirbase(kvtophys((vm_offset_t)tpmap->dirbase)); \ + set_pmap(tpmap); \ if (tpmap != kernel_pmap) { \ tpmap->cpus_using = TRUE; \ } \ -- cgit v1.2.3