예제 #1
0
파일: mmu.c 프로젝트: Shamar/harvey
int
mmuwalk(PTE* pml4, uintptr_t va, int level, PTE** ret,
        uint64_t (*alloc)(usize))
{
    int l;
    uintmem pa;
    PTE *pte;

    Mpl pl;

    pl = splhi();
    if(DBGFLG > 1)
        DBG("mmuwalk%d: va %#p level %d\n", machp()->machno, va, level);
    pte = &pml4[PTLX(va, 3)];
    for(l = 3; l >= 0; l--) {
        if(l == level)
            break;
        if(!(*pte & PteP)) {
            if(alloc == nil)
                break;
            pa = alloc(PTSZ);
            if(pa == ~0)
                return -1;
            memset(UINT2PTR(KADDR(pa)), 0, PTSZ);
            *pte = pa|PteRW|PteP;
        }
        else if(*pte & PtePS)
            break;
        pte = UINT2PTR(KADDR(PPN(*pte)));
        pte += PTLX(va, l-1);
    }
    *ret = pte;
    splx(pl);
    return l;
}
예제 #2
0
/* virtual address fmt */
static int
fmtW(Fmt *f)
{
	uint64_t va;

	va = va_arg(f->args, uint64_t);
	return fmtprint(f, "%#llx=0x[%llx][%llx][%llx][%llx][%llx]", va,
		PTLX(va, 3), PTLX(va, 2), PTLX(va, 1), PTLX(va, 0),
		va & ((1<<PGSHFT)-1));

}
예제 #3
0
파일: mmu.c 프로젝트: Nurb432/plan9front
static void
mmuzap(void)
{
	uintptr *pte;
	u64int w;
	int i, x;

	pte = m->pml4;
	pte[PTLX(KMAP, 3)] = 0;

	/* common case */
	pte[PTLX(UTZERO, 3)] = 0;
	pte[PTLX(TSTKTOP, 3)] = 0;
	m->mmumap[PTLX(UTZERO, 3)/MAPBITS] &= ~(1ull<<(PTLX(UTZERO, 3)%MAPBITS));
	m->mmumap[PTLX(TSTKTOP, 3)/MAPBITS] &= ~(1ull<<(PTLX(TSTKTOP, 3)%MAPBITS));

	for(i = 0; i < nelem(m->mmumap); pte += MAPBITS, i++){
		if((w = m->mmumap[i]) == 0)
			continue;
		m->mmumap[i] = 0;
		for(x = 0; w != 0; w >>= 1, x++){
			if(w & 1)
				pte[x] = 0;
		}
	}
}
예제 #4
0
파일: mmu.c 프로젝트: Nurb432/plan9front
uintptr*
mmuwalk(uintptr* table, uintptr va, int level, int create)
{
	uintptr pte;
	int i, x;

	x = PTLX(va, 3);
	for(i = 2; i >= level; i--){
		pte = table[x];
		if(pte & PTEVALID){
			if(pte & PTESIZE)
				return 0;
			table = KADDR(PPN(pte));
		} else {
			if(!create)
				return 0;
			table = mmucreate(table, va, i, x);
		}
		x = PTLX(va, i);
	}
	return &table[x];
}
예제 #5
0
파일: mmu.c 프로젝트: Nurb432/plan9front
void
mmuswitch(Proc *proc)
{
	MMU *p;

	mmuzap();
	if(proc->newtlb){
		mmufree(proc);
		proc->newtlb = 0;
	}
	if((p = proc->kmaphead) != nil)
		m->pml4[PTLX(KMAP, 3)] = PADDR(p->page) | PTEWRITE|PTEVALID;
	for(p = proc->mmuhead; p != nil && p->level == PML4E; p = p->next){
		m->mmumap[p->index/MAPBITS] |= 1ull<<(p->index%MAPBITS);
		m->pml4[p->index] = PADDR(p->page) | PTEUSER|PTEWRITE|PTEVALID;
	}
	taskswitch((uintptr)proc->kstack+KSTACK);
}
예제 #6
0
파일: mmu.c 프로젝트: Shamar/harvey
/*
 * pg->pgszi indicates the page size in machp()->pgsz[] used for the mapping.
 * For the user, it can be either 2*MiB or 1*GiB pages.
 * For 2*MiB pages, we use three levels, not four.
 * For 1*GiB pages, we use two levels.
 */
void
mmuput(uintptr_t va, Page *pg, uint attr)
{
    Proc *up = externup();
    int lvl, user, x, pgsz;
    PTE *pte;
    Page *page, *prev;
    Mpl pl;
    uintmem pa, ppn;
    char buf[80];

    ppn = 0;
    pa = pg->pa;
    if(pa == 0)
        panic("mmuput: zero pa");

    if(DBGFLG) {
        snprint(buf, sizeof buf, "cpu%d: up %#p mmuput %#p %#P %#ux\n",
                machp()->machno, up, va, pa, attr);
        print("%s", buf);
    }
    assert(pg->pgszi >= 0);
    pgsz = sys->pgsz[pg->pgszi];
    if(pa & (pgsz-1))
        panic("mmuput: pa offset non zero: %#ullx\n", pa);
    pa |= pteflags(attr);

    pl = splhi();
    if(DBGFLG)
        mmuptpcheck(up);
    user = (va < KZERO);
    x = PTLX(va, 3);

    pte = UINT2PTR(machp()->MMU.pml4->va);
    pte += x;
    prev = machp()->MMU.pml4;

    for(lvl = 3; lvl >= 0; lvl--) {
        if(user) {
            if(pgsz == 2*MiB && lvl == 1)	 /* use 2M */
                break;
            if(pgsz == 1ull*GiB && lvl == 2)	/* use 1G */
                break;
        }
        for(page = up->MMU.mmuptp[lvl]; page != nil; page = page->next)
            if(page->prev == prev && page->daddr == x) {
                if(*pte == 0) {
                    print("mmu: jmk and nemo had fun\n");
                    *pte = PPN(page->pa)|PteU|PteRW|PteP;
                }
                break;
            }

        if(page == nil) {
            if(up->MMU.mmuptp[0] == nil)
                page = mmuptpalloc();
            else {
                page = up->MMU.mmuptp[0];
                up->MMU.mmuptp[0] = page->next;
            }
            page->daddr = x;
            page->next = up->MMU.mmuptp[lvl];
            up->MMU.mmuptp[lvl] = page;
            page->prev = prev;
            *pte = PPN(page->pa)|PteU|PteRW|PteP;
            if(lvl == 3 && x >= machp()->MMU.pml4->daddr)
                machp()->MMU.pml4->daddr = x+1;
        }
        x = PTLX(va, lvl-1);

        ppn = PPN(*pte);
        if(ppn == 0)
            panic("mmuput: ppn=0 l%d pte %#p = %#P\n", lvl, pte, *pte);

        pte = UINT2PTR(KADDR(ppn));
        pte += x;
        prev = page;
    }

    if(DBGFLG)
        checkpte(ppn, pte);
    *pte = pa|PteU;

    if(user)
        switch(pgsz) {
        case 2*MiB:
        case 1*GiB:
            *pte |= PtePS;
            break;
        default:
            panic("mmuput: user pages must be 2M or 1G");
        }
    splx(pl);

    if(DBGFLG) {
        snprint(buf, sizeof buf, "cpu%d: up %#p new pte %#p = %#llux\n",
                machp()->machno, up, pte, pte?*pte:~0);
        print("%s", buf);
    }

    invlpg(va);			/* only if old entry valid? */
}