#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "mmu64.h" #define Pml4 0x00108000 typedef unsigned long long u64intptr; #define u64ptr2int(p) ((u64intptr)(p)) #define u64int2ptr(i) ((void*)(i)) static u64intptr mach0ptalloc(int l) { static u64intptr table = Pml4; static int ntable = 6; if(ntable <= 0) return ~0ULL; table += PGSIZE64; memset(KADDR(table), 0, PGSIZE64); ntable--; if(vflag) print("table[%d] used 0x%llux\n", l, table); return table; } PTE* mmuwalk64(PTE* pml4, u64intptr va, int level, u64intptr (*alloc)(int)) { int l, idx; PTE *pte; u64intptr pa; idx = PTEX64(va, 4); pte = &pml4[idx]; for(l = 4; l > 0; l--){ if(vflag) print("mmuwalk64 0x%p 0x%llux %d: entry %d\n", pml4, va, l, idx); if(l == level) return pte; if(l == 2 && (*pte & PtePS)) break; if(!(*pte & PteP)){ if(alloc == nil) break; pa = alloc(l); if(pa == ~0ULL) break; *pte = pa|PteRW|PteP; if(vflag) print("mmuwalk64 0x%p 0x%llux %d: alloc 0x%llux\n", pml4, va, l, pa); } pte = u64int2ptr(KADDR(PPN64(*pte))); idx = PTEX64(va, l-1); pte += idx; } return nil; } void mkmach0pt(u64intptr kzero64) { //u32int r; u64intptr pa, va; PTE *pml4, *pte, *pte0; //uvlong uvlr; pml4 = u64int2ptr(KADDR(Pml4)); if(vflag) print("pml4 = %p\n", pml4); memset(pml4, 0, PGSIZE64); va = kzero64; for(pa = 0; pa < 4*MiB; pa += 2*MiB){ pte = mmuwalk64(pml4, va, 2, mach0ptalloc); *pte = (PPN64(pa))|PtePS|PteRW|PteP; if(vflag) print("va %#llux pte %#p *pte %#llux\n", va, pte, *pte); va += 2*MiB; } pte = mmuwalk64(pml4, kzero64, 4, 0); if(vflag) print("pte l4 %llux == 0x%llux\n", kzero64, *pte); pte0 = mmuwalk64(pml4, 0ULL, 2, mach0ptalloc); pte0 += PTEX64(0, 2); if(vflag) print("pte0 l2 @ 0x%p 0 == 0x%llux\n", pte0, *pte0); *pte0 = (PPN64(0))|PtePS|PteRW|PteP; if(vflag) print("pte0 l2 @ 0x%p 0 == 0x%llux\n", pte0, *pte0); /* * Have to do this with paging turned off. Bugger. r = getcr4(); r |= Pae; putcr4(r); r = getcr3(); putcr3(Pml4); rdmsr(Efer, &uvlr); uvlr |= Lme; wrmsr(Efer, uvlr); */ } void warp64(uvlong entry) { u64intptr kzero64; extern void _warp64(ulong); // kzero64 = KZERO64; // if(entry != 0xFFFFFFFF80110000ULL){ // print("bad entry address %#llux\n", entry); // return; // } kzero64 = entry & ~0x000000000fffffffull; print("warp64(%#llux) %#llux %d\n", entry, kzero64, nmmap); if(vflag) print("mkmultiboot\n"); mkmultiboot(); if(vflag) print("mkmach0pt\n"); mkmach0pt(kzero64); if(vflag) print("impulse\n"); /* * No output after impulse(). */ if(vflag) print("_warp64\n"); impulse(); _warp64(Pml4); }