2 #include "../port/lib.h"
9 uvlong *xenpdpt; /* this needs to go in Mach for multiprocessor guest */
13 #define MFN(pa) (patomfn[(pa)>>PGSHIFT])
14 #define MAPPN(x) (paemode? matopfn[*(uvlong*)(&x)>>PGSHIFT]<<PGSHIFT : matopfn[(x)>>PGSHIFT]<<PGSHIFT)
16 /* note: pdb must already be pinned */
18 taskswitch(Page *pdb, ulong stack)
20 HYPERVISOR_stack_switch(KDSEL, stack);
25 mmuflushtlb(Page *pdb)
33 xenptswitch(PADDR(m->pdb));
37 for(i = 0; i < 3; i++){
38 xenupdate((ulong*)&xenpdpt[i], pdb->pa | PTEVALID);
44 for(i = 0; i < 3; i++)
45 xenupdatema((ulong*)&xenpdpt[i], ((uvlong*)m->pdb)[i]);
53 * On processors that support it, we set the PTEGLOBAL bit in
54 * page table and page directory entries that map kernel memory.
55 * Doing this tells the processor not to bother flushing them
56 * from the TLB when doing the TLB flush associated with a
57 * context switch (write to CR3). Since kernel memory mappings
58 * are never removed, this is safe. (If we ever remove kernel memory
59 * mappings, we can do a full flush by turning off the PGE bit in CR4,
60 * writing to CR3, and then turning the PGE bit back on.)
62 * See also mmukmap below.
64 * Processor support for the PTEGLOBAL bit is enabled in devarch.c.
72 /* only need to do this once, on bootstrap processor */
80 for(i=512; i<1024; i++){ /* 512: start at entry for virtual 0x80000000 */
81 if(pde[i] & PTEVALID){
83 if(!(pde[i] & PTESIZE)){
84 pte = KADDR(pde[i]&~(BY2PG-1));
94 mmumapframe(ulong va, ulong mfn)
100 * map machine frame number to a virtual address.
101 * When called the pagedir and page table exist, we just
102 * need to fill in a page table entry.
104 ma = ((uvlong)mfn<<PGSHIFT) | PTEVALID|PTEWRITE;
106 pte = KADDR(MAPPN(PDB(m->pdb,va)[pdbx]));
107 xenupdatema(&pte[PTX(va)], ma);
114 ulong *pdb, *pte, va, pa, pdbx;
116 if(strstr(xenstart->magic, "x86_32p"))
118 hypervisor_virt_start = paemode ? 0xF5800000 : 0xFC000000;
119 patomfn = (ulong*)xenstart->mfn_list;
120 matopfn = (ulong*)hypervisor_virt_start;
121 /* Xen bug ? can't touch top entry in PDPT */
123 hypervisor_virt_start = 0xC0000000;
126 * map CPU0MACH at MACHADDR.
127 * When called the pagedir and page table exist, we just
128 * need to fill in a page table entry.
130 pdb = (ulong*)xenstart->pt_base;
132 pa = PADDR(CPU0MACH) | PTEVALID|PTEWRITE;
135 pte = KADDR(MAPPN(pdb[pdbx]));
136 xenupdate(&pte[PTX(va)], pa);
142 ulong *pte, npgs, pa;
146 xenpdpt = (uvlong*)m->pdb;
147 m->pdb = xspanalloc(32, 32, 0);
148 /* clear "reserved" bits in initial page directory pointers -- Xen bug? */
149 for(i = 0; i < 4; i++)
150 ((uvlong*)m->pdb)[i] = xenpdpt[i] & ~0x1E6LL;
154 * So far only memory up to xentop is mapped, map the rest.
155 * We cant use large pages because our contiguous PA space
156 * is not necessarily contiguous in MA.
158 npgs = conf.mem[0].npage;
159 for(pa=conf.mem[0].base; npgs; npgs--, pa+=BY2PG) {
160 pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 1);
163 xenupdate(pte, pa|PTEVALID|PTEWRITE);
168 #ifdef we_may_eventually_want_this
169 /* make kernel text unwritable */
170 for(x = KTZERO; x < (ulong)etext; x += BY2PG){
171 p = mmuwalk(m->pdb, x, 2, 0);
178 taskswitch(0, (ulong)m + BY2PG);
193 mmupdb(Page *pg, ulong va)
197 for(i = PAX(va); i > 0; i -= 2)
199 return (ulong*)pg->va;
202 /* this can be called with an active pdb, so use Xen calls to zero it out.
205 mmuptefree(Proc* proc)
210 if(proc->mmupdb && proc->mmuused){
211 last = &proc->mmuused;
212 for(page = *last; page; page = page->next){
213 /* this is no longer a pte page so make it readwrite */
215 pdb = mmupdb(proc->mmupdb, va);
216 xenupdatema(&pdb[PDX(va)], 0);
217 xenptunpin(page->va);
220 *last = proc->mmufree;
221 proc->mmufree = proc->mmuused;
227 mmuswitch(Proc* proc)
237 //XXX doesn't work for some reason, but it's not needed for uniprocessor
238 //pdb = (ulong*)proc->mmupdb->va;
239 //xenupdate(&pdb[PDX(MACHADDR)], m->pdb[PDX(MACHADDR)]);
240 taskswitch(proc->mmupdb, (ulong)(proc->kstack+KSTACK));
243 taskswitch(0, (ulong)(proc->kstack+KSTACK));
247 mmurelease(Proc* proc)
252 * Release any pages allocated for a page directory base or page-tables
254 * switch to the prototype pdb for this processor (m->pdb);
255 * call mmuptefree() to place all pages used for page-tables (proc->mmuused)
256 * onto the process' free list (proc->mmufree). This has the side-effect of
257 * cleaning any user entries in the pdb (proc->mmupdb);
258 * if there's a pdb put it in the cache of pre-initialised pdb's
259 * for this processor (m->pdbpool) or on the process' free list;
260 * finally, place any pages freed back into the free pool (palloc).
261 * This routine is only called from sched() with palloc locked.
263 taskswitch(0, (ulong)m + BY2PG);
266 if((page = proc->mmupdb) != 0){
270 /* its not a page table anymore, mark it rw */
271 xenptunpin(page->va);
272 if(paemode || m->pdbcnt > 10){
273 page->next = proc->mmufree;
274 proc->mmufree = page;
277 page->next = m->pdbpool;
285 for(page = proc->mmufree; page; page = next){
288 panic("mmurelease: page->ref %ld\n", page->ref);
297 mmupdballoc(ulong va, void *mpdb)
305 * All page tables must be read-only. We will mark them
306 * readwrite later when we free them and they are no
307 * longer used as page tables.
313 page = newpage(0, 0, 0);
314 page->va = VA(kmap(page));
316 memmove((void*)page->va, mpdb, BY2PG);
318 memset((void*)page->va, 0, BY2PG);
319 if (xenpgdpin(page->va))
322 * XXX Plan 9 is a bit lax about putting pages on the free list when they are
323 * still mapped (r/w) by some process's page table. From Plan 9's point
324 * of view this is safe because the any such process will have up->newtlb set,
325 * so the mapping will be cleared before the process is dispatched. But the Xen
326 * hypervisor has no way of knowing this, so it refuses to pin the page for use
329 if(0) print("bad pgdpin %lux va %lux copy %lux %s\n", MFN(PADDR(page->va)), va, (ulong)mpdb, up? up->text: "");
330 page->next = badpages;
333 while (badpages != 0) {
335 badpages = badpages->next;
341 m->pdbpool = page->next;
343 if (!xenpgdpin(page->va))
353 checkmmu(ulong va, ulong pa)
361 pdb = mmupdb(up->mmupdb, va);
363 if(MAPPN(pdb[pdbx]) == 0){
364 /* okay to be empty - will fault and get filled */
368 pte = KADDR(MAPPN(pdb[pdbx]));
369 if(MAPPN(pte[PTX(va)]) != pa){
371 print("%ld %s: va=0x%08lux pa=0x%08lux pte=0x%08lux (0x%08lux)\n",
373 va, pa, pte[PTX(va)], MAPPN(pte[PTX(va)]));
375 print("%ld %s: va=0x%08lux pa=0x%08lux pte=0x%16llux (0x%08lux)\n",
377 va, pa, *(uvlong*)&pte[PTX(va)], MAPPN(pte[PTX(va)]));
382 putmmu(ulong va, ulong pa, Page*)
390 PUTMMULOG(dprint("putmmu va %lux pa %lux\n", va, pa);)
393 up->mmupdb = mmupdballoc(va, m->pdb);
396 for(i = 4; i >= 0; i -= 2){
398 pg = mmupdballoc(va, KADDR(MAPPN(m->pdb[i])));
400 pg = mmupdballoc(va, 0);
407 pdb = mmupdb(up->mmupdb, va);
410 if(PPN(pdb[pdbx]) == 0){
411 PUTMMULOG(dprint("new pt page for index %d pdb %lux\n", pdbx, (ulong)pdb);)
412 /* mark page as readonly before using as a page table */
413 if(up->mmufree == 0){
416 page = newpage(1, 0, 0);
417 page->va = VA(kmap(page));
418 if (xenptpin(page->va))
420 if(0) print("bad pin %lux va %lux %s\n", MFN(PADDR(page->va)), va, up->text);
421 page->next = badpages;
424 while (badpages != 0) {
426 badpages = badpages->next;
432 up->mmufree = page->next;
433 memset((void*)page->va, 0, BY2PG);
434 if (!xenptpin(page->va))
438 xenupdate(&pdb[pdbx], page->pa|PTEVALID|PTEUSER|PTEWRITE);
441 page->next = up->mmuused;
445 pte = KADDR(MAPPN(pdb[pdbx]));
446 PUTMMULOG(dprint("pte %lux index %lud old %lux new %lux mfn %lux\n", (ulong)pte, PTX(va), pte[PTX(va)], pa|PTEUSER, MFN(pa));)
447 xenupdate(&pte[PTX(va)], pa|PTEUSER);
450 //XXX doesn't work for some reason, but it's not needed for uniprocessor
451 //xenupdate(&pdb[PDX(MACHADDR)], m->pdb[PDX(MACHADDR)]);
452 mmuflushtlb(up->mmupdb);
457 mmuwalk(ulong* pdb, ulong va, int level, int create)
459 ulong pa, va2, *table;
462 * Walk the page-table pointed to by pdb and return a pointer
463 * to the entry for virtual address va at the requested level.
464 * If the entry is invalid and create isn't requested then bail
465 * out early. Otherwise, for the 2nd level walk, allocate a new
466 * page-table page and register it in the 1st level.
470 if(!(*pdb & PTEVALID)){
473 panic("mmuwalk: missing pgdir ptr for va=%lux\n", va);
475 pdb = KADDR(MAPPN(*pdb));
477 table = &pdb[PDX(va)];
478 if(!(*table & PTEVALID) && create == 0)
491 panic("mmuwalk2: va %luX entry %luX\n", va, *table);
492 if(!(*table & PTEVALID)){
493 va2 = (ulong)xspanalloc(BY2PG, BY2PG, 0);
496 xenupdate(table, pa|PTEWRITE|PTEVALID);
498 table = KADDR(MAPPN(*table));
500 return &table[PTX(va)];
505 mmukmapsync(ulong va)
512 * Return the number of bytes that can be accessed via KADDR(pa).
513 * If pa is not a valid argument to KADDR, return 0.