1/**
2 * \file
3 * \brief Test program for large page code
4 */
5
6/*
7 * Copyright (c) 2013, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <barrelfish/barrelfish.h>
16#include <stdio.h>
17
18#define SAFE_VADDR (genvaddr_t)(8ULL<<39)
19#define SAFE_PMAP_ADDR (genvaddr_t)(9ULL<<39)
20// 2M
21#define DEFAULT_SIZE X86_64_LARGE_PAGE_SIZE
22
23static enum objtype type[] = {
24    ObjType_VNode_x86_64_pml4,
25    ObjType_VNode_x86_64_pdpt,
26    ObjType_VNode_x86_64_pdir,
27    ObjType_VNode_x86_64_ptable
28};
29
30// the offsets of the indices for the different page table levels
31static uint8_t offsets[] = { 39, 30, 21, 12 };
32
33static paging_x86_64_flags_t PAGE_DEFAULT_ACCESS =
34    PTABLE_USER_SUPERVISOR |
35    PTABLE_EXECUTE_DISABLE |
36    PTABLE_READ_WRITE;
37
38static vregion_flags_t PMAP_DEFAULT_ACCESS =
39    VREGION_FLAGS_READ_WRITE;
40
41static void test_region(uint32_t *buf, size_t size)
42{
43    int j = 0;
44    for (int i = 0; i < size; i+=4) {
45        j+=4;
46        if( (size-j) < 200)
47        {
48        printf("%i, ", i);
49        }
50
51        buf[i/4] = i;
52    }
53    for (int i = 0; i < size; i+=4) {
54        assert(buf[i/4] == i);
55    }
56    printf("\n\n");
57
58}
59
60
61int main(void)
62{
63    struct capref frame, smallframe, vnodes[4], mappings[4];
64    size_t bytes = DEFAULT_SIZE;
65    size_t bits = 4*1024;
66    errval_t err;
67
68    //get 4k frame cap
69    err = frame_alloc(&smallframe, bits, &bits);
70    assert(err_is_ok(err));
71    assert(bits >= 4*1024);
72    // get 2M frame cap
73    err = frame_alloc(&frame, bytes, &bytes);
74    assert(err_is_ok(err));
75    assert(bytes >= DEFAULT_SIZE);
76
77    // check that we have the necessary ptables (note: this is not how you
78    // should do this cf. with pmap_target.c
79    // setup reference to pml4 capability
80    vnodes[0] = (struct capref) {
81        .cnode = cnode_page,
82        .slot  = 0,
83    };
84    // note we start iterating on 1, because we're using index 0 as the
85    // well-known pml4 capref
86    for (int i = 1; i < sizeof(type) / sizeof(type[0]); i++) {
87        err = slot_alloc(&vnodes[i]);
88        assert(err_is_ok(err));
89        err = slot_alloc(&mappings[i]);
90        assert(err_is_ok(err));
91        printf("creating vnode for level %d, type %d\n", i, type[i]);
92        err = vnode_create(vnodes[i], type[i]);
93        assert(err_is_ok(err));
94        uint32_t slot = (SAFE_VADDR >> offsets[i-1]) & 0x1f;
95        printf("mapping into slot %d on level %d\n", slot, i-1);
96        err = vnode_map(vnodes[i-1], vnodes[i], slot, PTABLE_ACCESS_DEFAULT,
97                        0, 1, mappings[i]);
98        if (err_is_fail(err)) {
99            // this means we already have a page table for this level
100            // XXX: right now we've chosen the SAFE_VADDR such that we don't have
101            // any intermediate level page tables so we don't need to worry
102            // about this case
103            printf("there was a page table already?\n");
104            printf("vnode_map: %s\n", err_getstring(err));
105            exit(1);
106        }
107    }
108
109// map as 4k and 2m frames with vnode_map
110// used to test the kernel code
111#if 1
112    err = slot_alloc(&mappings[0]);
113    assert(err_is_ok(err));
114    //printf("start 4k vnode map");
115    err = vnode_map(vnodes[3], smallframe, (SAFE_VADDR>>offsets[3])&0x1f,
116            PAGE_DEFAULT_ACCESS, 0, 4*1024 / X86_64_BASE_PAGE_SIZE, mappings[0]);
117#endif
118#if 0
119    if (err_is_fail(err)) {
120        printf("error in vnode_map: %s\n", err_getstring(err));
121        exit(1);
122    }
123
124    test_region((uint32_t*)SAFE_VADDR, 4*1024);
125
126    // FROM HERE: unmap and try to map as large page
127
128    // unmap frame
129    printf("start 4k unmap\n");
130    err = vnode_unmap(vnodes[3], smallframe, (SAFE_VADDR>>offsets[3])&0x1f,
131            4*1024 / X86_64_BASE_PAGE_SIZE);
132    if (err_is_fail(err)) {
133        printf("vnode_unmap: %s\n", err_getstring(err));
134    }
135    assert(err_is_ok(err));
136    // unmap level 3 page table
137    err = vnode_unmap(vnodes[2], vnodes[3], SAFE_VADDR>>offsets[2]&0x1f, 1);
138    assert(err_is_ok(err));
139
140    // map as 2M large page
141    printf("start 2m vnodemap\n");
142    err = vnode_map(vnodes[2], frame, SAFE_VADDR>>offsets[2]&0x1f,
143            PAGE_DEFAULT_ACCESS, 0, DEFAULT_SIZE / X86_64_LARGE_PAGE_SIZE);
144    if (err_is_fail(err)) {
145        printf("error in vnode_map: %s\n", err_getstring(err));
146        exit(1);
147    }
148
149    test_region((uint32_t*)SAFE_VADDR, DEFAULT_SIZE);
150
151    err = vnode_unmap(vnodes[2], frame, SAFE_VADDR>>offsets[2]&0x1f, DEFAULT_SIZE / X86_64_LARGE_PAGE_SIZE);
152    if (err_is_fail(err)) {
153        printf("vnode_unmap: %s\n", err_getstring(err));
154    }
155    assert(err_is_ok(err));
156#endif
157
158    struct pmap *pmap;
159
160//normal page via pmap interface
161// used to test if 4k code still works
162// (although this would break the whole barrelfish boot)
163#if 0
164    printf("\n\nstart 4k map with pmap\n");
165    bits = 4*1024;
166    printf("    frame_alloc\n");
167    err = frame_alloc(&smallframe, bits, &bits);
168    assert(err_is_ok(err));
169    assert(bits >= 4*1024);
170    printf("    get pmap\n");
171    pmap = get_current_pmap();
172
173
174    printf("    map\n");
175    err = pmap->f.map(pmap, SAFE_PMAP_ADDR, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
176    if (err_is_fail(err))
177    {
178        printf("error in pmap: %s\n", err_getstring(err));
179    }
180    test_region((uint32_t*)SAFE_PMAP_ADDR, 4*1024);
181
182    printf("\tunmap\n");
183    err = pmap->f.unmap(pmap, SAFE_PMAP_ADDR, bits, NULL);
184#endif
185
186
187//large page via pmap interface
188// used to test the 2M pages on a safe address
189// looped 10 times to see if unmap does work
190#if 0
191    printf("start 2m map with pmap\n");
192    bytes = DEFAULT_SIZE;
193    err = frame_alloc(&frame, bytes, &bytes);
194    assert(err_is_ok(err));
195    assert(bytes >= DEFAULT_SIZE);
196
197    pmap = get_current_pmap();
198
199    for(int i = 0; i<10; ++i){
200        printf("map %i\n", i);
201        err = pmap->f.map(pmap, SAFE_PMAP_ADDR, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
202        if (err_is_fail(err))
203        {
204            printf("error in pmap: %s\n", err_getstring(err));
205            exit(1);
206        }
207
208        test_region((uint32_t*)SAFE_PMAP_ADDR, DEFAULT_SIZE);
209
210        err = pmap->f.unmap(pmap, SAFE_PMAP_ADDR, bytes, NULL);
211        if (err_is_fail(err))
212        {
213            printf("error in unmap: %s\n", err_getstring(err));
214            exit(1);
215        }
216    }//end for
217#endif
218
219
220        struct memobj a;
221        genvaddr_t address;
222
223//test determine_addr_raw as address obtainer
224// mapping 4k page
225#if 0
226    printf("determine_addr 4k\n");
227    bits = 4*1024;
228    err = frame_alloc(&smallframe, bits, &bits);
229    assert(err_is_ok(err));
230    assert(bits >= 4*1024);
231
232    //determine address
233    a.size = bits;
234    address = 0;
235    pmap = get_current_pmap();
236    err = pmap->f.determine_addr_raw(pmap, a.size, BASE_PAGE_SIZE, &address);
237    printf("address: %lx\n", (unsigned long) address);
238    if (err_is_fail(err))
239    {
240        printf("error in determine_addr: %s\n", err_getstring(err));
241        exit(1);
242    }
243
244    err = pmap->f.map(pmap, address, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
245    if (err_is_fail(err))
246    {
247        printf("error in pmap: %s\n", err_getstring(err));
248        exit(1);
249    }
250    test_region((uint32_t*)address, 4*1024);
251#endif
252
253
254// determine_addr_raw for 2m pages
255// for loop inserted currently
256// this was the only way multiple large pages could be accessed
257// no longer necessary
258#if 0
259    printf("determine_addr 2m\n");
260    genvaddr_t* addresses = malloc(200*sizeof(genvaddr_t));
261for(int i = 0; i<200; ++i){
262    bytes = DEFAULT_SIZE;
263    err = frame_alloc(&frame, bytes, &bytes);
264    assert(err_is_ok(err));
265    assert(bytes >= DEFAULT_SIZE);
266
267    a.size = bytes;
268    printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
269    address = 0;
270    pmap = get_current_pmap();
271    err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, &address);
272    printf("address: %x\n", (unsigned int) address);
273    if(err_is_fail(err))
274    {
275        printf("error in determine_addr: %s\n", err_getstring(err));
276        exit(1);
277    }
278
279    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
280    if (err_is_fail(err))
281    {
282        printf("error in pmap: %s\n", err_getstring(err));
283        exit(1);
284    }
285    addresses[i] = address;
286}
287for(int i = 0; i<200; ++i){
288    test_region((uint32_t*)addresses[i], DEFAULT_SIZE);
289}
290#endif
291
292
293// multiple large pages with one go
294// the for loop is to test unmap
295#if 1
296    printf("multiple 2m\n");
297    bytes = 10*DEFAULT_SIZE;
298    err = frame_alloc(&frame, bytes, &bytes);
299    assert(err_is_ok(err));
300    assert(bytes >= 10*DEFAULT_SIZE);
301
302    a.size = bytes;
303    printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
304    address = 0;
305    pmap = get_current_pmap();
306    err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, &address);
307    printf("address: %x\n", (unsigned int) address);
308    if(err_is_fail(err))
309    {
310        printf("error in determine_addr: %s\n", err_getstring(err));
311        exit(1);
312    }
313for (int i=0; i<10; ++i) {
314printf("map %i\n", i);
315    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
316    if (err_is_fail(err))
317    {
318        printf("error in pmap: %s\n", err_getstring(err));
319        exit(1);
320    }
321
322    test_region((uint32_t*)address, 10*DEFAULT_SIZE);
323
324    err = pmap->f.unmap(pmap, address, bytes, NULL);
325    if (err_is_fail(err))
326    {
327        printf("error in unmap: %s\n", err_getstring(err));
328        exit(1);
329    }
330}//endfor
331#endif
332    printf("exited successfully\n");
333    return 0;
334}
335