1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
/* vmem.c - MemTest-86
*
* Virtual memory handling (PAE)
*
* Released under version 2 of the Gnu Public License.
* By Chris Brady
*/
#include "stdint.h"
#include "test.h"
#include "cpuid.h"
extern struct cpu_ident cpu_id;
static unsigned long mapped_win = 1;
void paging_off(void)
{
if (!cpu_id.fid.bits.pae)
return;
__asm__ __volatile__ (
/* Disable paging */
"movl %%cr0, %%eax\n\t"
"andl $0x7FFFFFFF, %%eax\n\t"
"movl %%eax, %%cr0\n\t"
: :
: "ax"
);
}
static void paging_on(void *pdp)
{
if (!cpu_id.fid.bits.pae)
return;
__asm__ __volatile__(
/* Load the page table address */
"movl %0, %%cr3\n\t"
/* Enable paging */
"movl %%cr0, %%eax\n\t"
"orl $0x80000000, %%eax\n\t"
"movl %%eax, %%cr0\n\t"
:
: "r" (pdp)
: "ax"
);
}
static void paging_on_lm(void *pml)
{
if (!cpu_id.fid.bits.pae)
return;
__asm__ __volatile__(
/* Load the page table address */
"movl %0, %%cr3\n\t"
/* Enable paging */
"movl %%cr0, %%eax\n\t"
"orl $0x80000000, %%eax\n\t"
"movl %%eax, %%cr0\n\t"
:
: "r" (pml)
: "ax"
);
}
int map_page(unsigned long page)
{
unsigned long i;
struct pde {
unsigned long addr_lo;
unsigned long addr_hi;
};
extern unsigned char pdp[];
extern unsigned char pml4[];
extern struct pde pd2[];
unsigned long win = page >> 19;
/* Less than 2 GB so no mapping is required */
if (win == 0) {
return 0;
}
if (cpu_id.fid.bits.pae == 0) {
/* Fail, we don't have PAE */
return -1;
}
if (cpu_id.fid.bits.lm == 0 && (page > 0x1000000)) {
/* Fail, we want an address that is out of bounds (> 64GB)
* for PAE and no long mode (ie. 32 bit CPU).
*/
return -1;
}
/* Compute the page table entries... */
for(i = 0; i < 1024; i++) {
/*-----------------10/30/2004 12:37PM---------------
* 0xE3 --
* Bit 0 = Present bit. 1 = PDE is present
* Bit 1 = Read/Write. 1 = memory is writable
* Bit 2 = Supervisor/User. 0 = Supervisor only (CPL 0-2)
* Bit 3 = Writethrough. 0 = writeback cache policy
* Bit 4 = Cache Disable. 0 = page level cache enabled
* Bit 5 = Accessed. 1 = memory has been accessed.
* Bit 6 = Dirty. 1 = memory has been written to.
* Bit 7 = Page Size. 1 = page size is 2 MBytes
* --------------------------------------------------*/
pd2[i].addr_lo = ((win & 1) << 31) + ((i & 0x3ff) << 21) + 0xE3;
pd2[i].addr_hi = (win >> 1);
}
paging_off();
if (cpu_id.fid.bits.lm == 1) {
paging_on_lm(pml4);
} else {
paging_on(pdp);
}
mapped_win = win;
return 0;
}
void *mapping(unsigned long page_addr)
{
void *result;
if (page_addr < 0x80000) {
/* If the address is less than 1GB directly use the address */
result = (void *)(page_addr << 12);
}
else {
unsigned long alias;
alias = page_addr & 0x7FFFF;
alias += 0x80000;
result = (void *)(alias << 12);
}
return result;
}
void *emapping(unsigned long page_addr)
{
void *result;
result = mapping(page_addr -1);
/* Fill in the low address bits */
result = ((unsigned char *)result) + 0xffc;
return result;
}
unsigned long page_of(void *addr)
{
unsigned long page;
page = ((unsigned long)addr) >> 12;
if (page >= 0x80000) {
page &= 0x7FFFF;
page += mapped_win << 19;
}
#if 0
cprint(LINE_SCROLL -2, 0, "page_of( )-> ");
hprint(LINE_SCROLL -2, 8, ((unsigned long)addr));
hprint(LINE_SCROLL -2, 20, page);
#endif
return page;
}
|