summaryrefslogtreecommitdiffstats
path: root/vmem.c
blob: 6125e0d61218e31a44c9581be5ee17e82b5ed071 (plain) (blame)
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
155
156
157
158
159
/* 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 phys_page)
{
    void *result;
    if (phys_page < WIN_SZ_PAGES) {
        /* If the page is below 2GB, address it directly */
        result = (void *)(phys_page << 12);
    }
    else {
        // Higher physical pages map to a virtual address
        // in the 2G-4G range.
        unsigned long alias;
        alias = phys_page & 0x7FFFF;
        alias += 0x80000;
        result = (void *)(alias << 12);
    }
    return result;
}

void *emapping(unsigned long phys_page)
{
    void *result;
    result = mapping(phys_page - 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;
}