1*7d36db35SAvi Kivity #include "vm.h" 2*7d36db35SAvi Kivity #include "libcflat.h" 3*7d36db35SAvi Kivity 4*7d36db35SAvi Kivity #define PAGE_SIZE 4096ul 5*7d36db35SAvi Kivity #ifdef __x86_64__ 6*7d36db35SAvi Kivity #define LARGE_PAGE_SIZE (512 * PAGE_SIZE) 7*7d36db35SAvi Kivity #else 8*7d36db35SAvi Kivity #define LARGE_PAGE_SIZE (1024 * PAGE_SIZE) 9*7d36db35SAvi Kivity #endif 10*7d36db35SAvi Kivity 11*7d36db35SAvi Kivity #define X86_CR0_PE 0x00000001 12*7d36db35SAvi Kivity #define X86_CR0_PG 0x80000000 13*7d36db35SAvi Kivity #define X86_CR4_PSE 0x00000010 14*7d36db35SAvi Kivity static void *free = 0; 15*7d36db35SAvi Kivity static void *vfree_top = 0; 16*7d36db35SAvi Kivity 17*7d36db35SAvi Kivity static void free_memory(void *mem, unsigned long size) 18*7d36db35SAvi Kivity { 19*7d36db35SAvi Kivity while (size >= PAGE_SIZE) { 20*7d36db35SAvi Kivity *(void **)mem = free; 21*7d36db35SAvi Kivity free = mem; 22*7d36db35SAvi Kivity mem += PAGE_SIZE; 23*7d36db35SAvi Kivity size -= PAGE_SIZE; 24*7d36db35SAvi Kivity } 25*7d36db35SAvi Kivity } 26*7d36db35SAvi Kivity 27*7d36db35SAvi Kivity void *alloc_page() 28*7d36db35SAvi Kivity { 29*7d36db35SAvi Kivity void *p; 30*7d36db35SAvi Kivity 31*7d36db35SAvi Kivity if (!free) 32*7d36db35SAvi Kivity return 0; 33*7d36db35SAvi Kivity 34*7d36db35SAvi Kivity p = free; 35*7d36db35SAvi Kivity free = *(void **)free; 36*7d36db35SAvi Kivity 37*7d36db35SAvi Kivity return p; 38*7d36db35SAvi Kivity } 39*7d36db35SAvi Kivity 40*7d36db35SAvi Kivity void free_page(void *page) 41*7d36db35SAvi Kivity { 42*7d36db35SAvi Kivity *(void **)page = free; 43*7d36db35SAvi Kivity free = page; 44*7d36db35SAvi Kivity } 45*7d36db35SAvi Kivity 46*7d36db35SAvi Kivity extern char edata; 47*7d36db35SAvi Kivity static unsigned long end_of_memory; 48*7d36db35SAvi Kivity 49*7d36db35SAvi Kivity #ifdef __x86_64__ 50*7d36db35SAvi Kivity #define PAGE_LEVEL 4 51*7d36db35SAvi Kivity #define PGDIR_WIDTH 9 52*7d36db35SAvi Kivity #define PGDIR_MASK 511 53*7d36db35SAvi Kivity #else 54*7d36db35SAvi Kivity #define PAGE_LEVEL 2 55*7d36db35SAvi Kivity #define PGDIR_WIDTH 10 56*7d36db35SAvi Kivity #define PGDIR_MASK 1023 57*7d36db35SAvi Kivity #endif 58*7d36db35SAvi Kivity 59*7d36db35SAvi Kivity void install_pte(unsigned long *cr3, 60*7d36db35SAvi Kivity int pte_level, 61*7d36db35SAvi Kivity void *virt, 62*7d36db35SAvi Kivity unsigned long pte, 63*7d36db35SAvi Kivity unsigned long *pt_page) 64*7d36db35SAvi Kivity { 65*7d36db35SAvi Kivity int level; 66*7d36db35SAvi Kivity unsigned long *pt = cr3; 67*7d36db35SAvi Kivity unsigned offset; 68*7d36db35SAvi Kivity 69*7d36db35SAvi Kivity for (level = PAGE_LEVEL; level > pte_level; --level) { 70*7d36db35SAvi Kivity offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK; 71*7d36db35SAvi Kivity if (!(pt[offset] & PTE_PRESENT)) { 72*7d36db35SAvi Kivity unsigned long *new_pt = pt_page; 73*7d36db35SAvi Kivity if (!new_pt) 74*7d36db35SAvi Kivity new_pt = alloc_page(); 75*7d36db35SAvi Kivity else 76*7d36db35SAvi Kivity pt_page = 0; 77*7d36db35SAvi Kivity memset(new_pt, 0, PAGE_SIZE); 78*7d36db35SAvi Kivity pt[offset] = virt_to_phys(new_pt) | PTE_PRESENT | PTE_WRITE; 79*7d36db35SAvi Kivity } 80*7d36db35SAvi Kivity pt = phys_to_virt(pt[offset] & 0xffffffffff000ull); 81*7d36db35SAvi Kivity } 82*7d36db35SAvi Kivity offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK; 83*7d36db35SAvi Kivity pt[offset] = pte; 84*7d36db35SAvi Kivity } 85*7d36db35SAvi Kivity 86*7d36db35SAvi Kivity static unsigned long get_pte(unsigned long *cr3, void *virt) 87*7d36db35SAvi Kivity { 88*7d36db35SAvi Kivity int level; 89*7d36db35SAvi Kivity unsigned long *pt = cr3, pte; 90*7d36db35SAvi Kivity unsigned offset; 91*7d36db35SAvi Kivity 92*7d36db35SAvi Kivity for (level = PAGE_LEVEL; level > 1; --level) { 93*7d36db35SAvi Kivity offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK; 94*7d36db35SAvi Kivity pte = pt[offset]; 95*7d36db35SAvi Kivity if (!(pte & PTE_PRESENT)) 96*7d36db35SAvi Kivity return 0; 97*7d36db35SAvi Kivity if (level == 2 && (pte & PTE_PSE)) 98*7d36db35SAvi Kivity return pte; 99*7d36db35SAvi Kivity pt = phys_to_virt(pte & 0xffffffffff000ull); 100*7d36db35SAvi Kivity } 101*7d36db35SAvi Kivity offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK; 102*7d36db35SAvi Kivity pte = pt[offset]; 103*7d36db35SAvi Kivity return pte; 104*7d36db35SAvi Kivity } 105*7d36db35SAvi Kivity 106*7d36db35SAvi Kivity void install_large_page(unsigned long *cr3, 107*7d36db35SAvi Kivity unsigned long phys, 108*7d36db35SAvi Kivity void *virt) 109*7d36db35SAvi Kivity { 110*7d36db35SAvi Kivity install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_PSE, 0); 111*7d36db35SAvi Kivity } 112*7d36db35SAvi Kivity 113*7d36db35SAvi Kivity void install_page(unsigned long *cr3, 114*7d36db35SAvi Kivity unsigned long phys, 115*7d36db35SAvi Kivity void *virt) 116*7d36db35SAvi Kivity { 117*7d36db35SAvi Kivity install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE, 0); 118*7d36db35SAvi Kivity } 119*7d36db35SAvi Kivity 120*7d36db35SAvi Kivity 121*7d36db35SAvi Kivity static inline void load_gdt(unsigned long *table, int nent) 122*7d36db35SAvi Kivity { 123*7d36db35SAvi Kivity struct descriptor_table_ptr descr; 124*7d36db35SAvi Kivity 125*7d36db35SAvi Kivity descr.limit = nent * 8 - 1; 126*7d36db35SAvi Kivity descr.base = (ulong)table; 127*7d36db35SAvi Kivity lgdt(&descr); 128*7d36db35SAvi Kivity } 129*7d36db35SAvi Kivity 130*7d36db35SAvi Kivity #define SEG_CS_32 8 131*7d36db35SAvi Kivity #define SEG_CS_64 16 132*7d36db35SAvi Kivity 133*7d36db35SAvi Kivity struct ljmp { 134*7d36db35SAvi Kivity void *ofs; 135*7d36db35SAvi Kivity unsigned short seg; 136*7d36db35SAvi Kivity }; 137*7d36db35SAvi Kivity 138*7d36db35SAvi Kivity static void setup_mmu(unsigned long len) 139*7d36db35SAvi Kivity { 140*7d36db35SAvi Kivity unsigned long *cr3 = alloc_page(); 141*7d36db35SAvi Kivity unsigned long phys = 0; 142*7d36db35SAvi Kivity 143*7d36db35SAvi Kivity if (len < (1ul << 32)) 144*7d36db35SAvi Kivity len = 1ul << 32; /* map mmio 1:1 */ 145*7d36db35SAvi Kivity 146*7d36db35SAvi Kivity memset(cr3, 0, PAGE_SIZE); 147*7d36db35SAvi Kivity while (phys + LARGE_PAGE_SIZE <= len) { 148*7d36db35SAvi Kivity install_large_page(cr3, phys, (void *)phys); 149*7d36db35SAvi Kivity phys += LARGE_PAGE_SIZE; 150*7d36db35SAvi Kivity } 151*7d36db35SAvi Kivity while (phys + PAGE_SIZE <= len) { 152*7d36db35SAvi Kivity install_page(cr3, phys, (void *)phys); 153*7d36db35SAvi Kivity phys += PAGE_SIZE; 154*7d36db35SAvi Kivity } 155*7d36db35SAvi Kivity write_cr3(virt_to_phys(cr3)); 156*7d36db35SAvi Kivity #ifndef __x86_64__ 157*7d36db35SAvi Kivity write_cr4(X86_CR4_PSE); 158*7d36db35SAvi Kivity #endif 159*7d36db35SAvi Kivity write_cr0(X86_CR0_PG |X86_CR0_PE); 160*7d36db35SAvi Kivity 161*7d36db35SAvi Kivity printf("paging enabled\n"); 162*7d36db35SAvi Kivity printf("cr0 = %x\n", read_cr0()); 163*7d36db35SAvi Kivity printf("cr3 = %x\n", read_cr3()); 164*7d36db35SAvi Kivity printf("cr4 = %x\n", read_cr4()); 165*7d36db35SAvi Kivity } 166*7d36db35SAvi Kivity 167*7d36db35SAvi Kivity static unsigned int inl(unsigned short port) 168*7d36db35SAvi Kivity { 169*7d36db35SAvi Kivity unsigned int val; 170*7d36db35SAvi Kivity asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port)); 171*7d36db35SAvi Kivity return val; 172*7d36db35SAvi Kivity } 173*7d36db35SAvi Kivity 174*7d36db35SAvi Kivity void setup_vm() 175*7d36db35SAvi Kivity { 176*7d36db35SAvi Kivity end_of_memory = inl(0xd1); 177*7d36db35SAvi Kivity free_memory(&edata, end_of_memory - (unsigned long)&edata); 178*7d36db35SAvi Kivity setup_mmu(end_of_memory); 179*7d36db35SAvi Kivity } 180*7d36db35SAvi Kivity 181*7d36db35SAvi Kivity void *vmalloc(unsigned long size) 182*7d36db35SAvi Kivity { 183*7d36db35SAvi Kivity void *mem, *p; 184*7d36db35SAvi Kivity unsigned pages; 185*7d36db35SAvi Kivity 186*7d36db35SAvi Kivity size += sizeof(unsigned long); 187*7d36db35SAvi Kivity 188*7d36db35SAvi Kivity size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 189*7d36db35SAvi Kivity vfree_top -= size; 190*7d36db35SAvi Kivity mem = p = vfree_top; 191*7d36db35SAvi Kivity pages = size / PAGE_SIZE; 192*7d36db35SAvi Kivity while (pages--) { 193*7d36db35SAvi Kivity install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p); 194*7d36db35SAvi Kivity p += PAGE_SIZE; 195*7d36db35SAvi Kivity } 196*7d36db35SAvi Kivity *(unsigned long *)mem = size; 197*7d36db35SAvi Kivity mem += sizeof(unsigned long); 198*7d36db35SAvi Kivity return mem; 199*7d36db35SAvi Kivity } 200*7d36db35SAvi Kivity 201*7d36db35SAvi Kivity void vfree(void *mem) 202*7d36db35SAvi Kivity { 203*7d36db35SAvi Kivity unsigned long size = ((unsigned long *)mem)[-1]; 204*7d36db35SAvi Kivity 205*7d36db35SAvi Kivity while (size) { 206*7d36db35SAvi Kivity free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR)); 207*7d36db35SAvi Kivity mem += PAGE_SIZE; 208*7d36db35SAvi Kivity size -= PAGE_SIZE; 209*7d36db35SAvi Kivity } 210*7d36db35SAvi Kivity } 211*7d36db35SAvi Kivity 212*7d36db35SAvi Kivity void *vmap(unsigned long long phys, unsigned long size) 213*7d36db35SAvi Kivity { 214*7d36db35SAvi Kivity void *mem, *p; 215*7d36db35SAvi Kivity unsigned pages; 216*7d36db35SAvi Kivity 217*7d36db35SAvi Kivity size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 218*7d36db35SAvi Kivity vfree_top -= size; 219*7d36db35SAvi Kivity phys &= ~(unsigned long long)(PAGE_SIZE - 1); 220*7d36db35SAvi Kivity 221*7d36db35SAvi Kivity mem = p = vfree_top; 222*7d36db35SAvi Kivity pages = size / PAGE_SIZE; 223*7d36db35SAvi Kivity while (pages--) { 224*7d36db35SAvi Kivity install_page(phys_to_virt(read_cr3()), phys, p); 225*7d36db35SAvi Kivity phys += PAGE_SIZE; 226*7d36db35SAvi Kivity p += PAGE_SIZE; 227*7d36db35SAvi Kivity } 228*7d36db35SAvi Kivity return mem; 229*7d36db35SAvi Kivity } 230