vm64.c (5508B)
1 /* vm64.c 2 * 3 * Copyright (c) 2013 Brian Swetland 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 26 #include "param.h" 27 #include "types.h" 28 #include "defs.h" 29 #include "x86.h" 30 #include "memlayout.h" 31 #include "mmu.h" 32 #include "proc.h" 33 #include "elf.h" 34 35 __thread struct cpu *cpu; 36 __thread struct proc *proc; 37 38 static pde_t *kpml4; 39 static pde_t *kpdpt; 40 static pde_t *iopgdir; 41 static pde_t *kpgdir0; 42 static pde_t *kpgdir1; 43 44 void wrmsr(uint msr, uint64 val); 45 46 void tvinit(void) {} 47 void idtinit(void) {} 48 49 static void mkgate(uint *idt, uint n, void *kva, uint pl, uint trap) { 50 uint64 addr = (uint64) kva; 51 n *= 4; 52 trap = trap ? 0x8F00 : 0x8E00; // TRAP vs INTERRUPT gate; 53 idt[n+0] = (addr & 0xFFFF) | ((SEG_KCODE << 3) << 16); 54 idt[n+1] = (addr & 0xFFFF0000) | trap | ((pl & 3) << 13); // P=1 DPL=pl 55 idt[n+2] = addr >> 32; 56 idt[n+3] = 0; 57 } 58 59 static void tss_set_rsp(uint *tss, uint n, uint64 rsp) { 60 tss[n*2 + 1] = rsp; 61 tss[n*2 + 2] = rsp >> 32; 62 } 63 64 static void tss_set_ist(uint *tss, uint n, uint64 ist) { 65 tss[n*2 + 7] = ist; 66 tss[n*2 + 8] = ist >> 32; 67 } 68 69 extern void* vectors[]; 70 71 // Set up CPU's kernel segment descriptors. 72 // Run once on entry on each CPU. 73 void 74 seginit(void) 75 { 76 uint64 *gdt; 77 uint *tss; 78 uint64 addr; 79 void *local; 80 struct cpu *c; 81 uint *idt = (uint*) kalloc(); 82 int n; 83 memset(idt, 0, PGSIZE); 84 85 for (n = 0; n < 256; n++) 86 mkgate(idt, n, vectors[n], 0, 0); 87 mkgate(idt, 64, vectors[64], 3, 1); 88 89 lidt((void*) idt, PGSIZE); 90 91 // create a page for cpu local storage 92 local = kalloc(); 93 memset(local, 0, PGSIZE); 94 95 gdt = (uint64*) local; 96 tss = (uint*) (((char*) local) + 1024); 97 tss[16] = 0x00680000; // IO Map Base = End of TSS 98 99 // point FS smack in the middle of our local storage page 100 wrmsr(0xC0000100, ((uint64) local) + (PGSIZE / 2)); 101 102 c = &cpus[cpunum()]; 103 c->local = local; 104 105 cpu = c; 106 proc = 0; 107 108 addr = (uint64) tss; 109 gdt[0] = 0x0000000000000000; 110 gdt[SEG_KCODE] = 0x0020980000000000; // Code, DPL=0, R/X 111 gdt[SEG_UCODE] = 0x0020F80000000000; // Code, DPL=3, R/X 112 gdt[SEG_KDATA] = 0x0000920000000000; // Data, DPL=0, W 113 gdt[SEG_KCPU] = 0x0000000000000000; // unused 114 gdt[SEG_UDATA] = 0x0000F20000000000; // Data, DPL=3, W 115 gdt[SEG_TSS+0] = (0x0067) | ((addr & 0xFFFFFF) << 16) | 116 (0x00E9LL << 40) | (((addr >> 24) & 0xFF) << 56); 117 gdt[SEG_TSS+1] = (addr >> 32); 118 119 lgdt((void*) gdt, 8 * sizeof(uint64)); 120 121 ltr(SEG_TSS << 3); 122 }; 123 124 // The core xv6 code only knows about two levels of page tables, 125 // so we will create all four, but only return the second level. 126 // because we need to find the other levels later, we'll stash 127 // backpointers to them in the top two entries of the level two 128 // table. 129 pde_t* 130 setupkvm(void) 131 { 132 pde_t *pml4 = (pde_t*) kalloc(); 133 pde_t *pdpt = (pde_t*) kalloc(); 134 pde_t *pgdir = (pde_t*) kalloc(); 135 136 memset(pml4, 0, PGSIZE); 137 memset(pdpt, 0, PGSIZE); 138 memset(pgdir, 0, PGSIZE); 139 pml4[511] = v2p(kpdpt) | PTE_P | PTE_W | PTE_U; 140 pml4[0] = v2p(pdpt) | PTE_P | PTE_W | PTE_U; 141 pdpt[0] = v2p(pgdir) | PTE_P | PTE_W | PTE_U; 142 143 // virtual backpointers 144 pgdir[511] = ((uintp) pml4) | PTE_P; 145 pgdir[510] = ((uintp) pdpt) | PTE_P; 146 147 return pgdir; 148 }; 149 150 // Allocate one page table for the machine for the kernel address 151 // space for scheduler processes. 152 // 153 // linear map the first 4GB of physical memory starting at 0xFFFFFFFF80000000 154 void 155 kvmalloc(void) 156 { 157 int n; 158 kpml4 = (pde_t*) kalloc(); 159 kpdpt = (pde_t*) kalloc(); 160 kpgdir0 = (pde_t*) kalloc(); 161 kpgdir1 = (pde_t*) kalloc(); 162 iopgdir = (pde_t*) kalloc(); 163 memset(kpml4, 0, PGSIZE); 164 memset(kpdpt, 0, PGSIZE); 165 memset(iopgdir, 0, PGSIZE); 166 kpml4[511] = v2p(kpdpt) | PTE_P | PTE_W; 167 kpdpt[511] = v2p(kpgdir1) | PTE_P | PTE_W; 168 kpdpt[510] = v2p(kpgdir0) | PTE_P | PTE_W; 169 kpdpt[509] = v2p(iopgdir) | PTE_P | PTE_W; 170 for (n = 0; n < NPDENTRIES; n++) { 171 kpgdir0[n] = (n << PDXSHIFT) | PTE_PS | PTE_P | PTE_W; 172 kpgdir1[n] = ((n + 512) << PDXSHIFT) | PTE_PS | PTE_P | PTE_W; 173 } 174 for (n = 0; n < 16; n++) 175 iopgdir[n] = (DEVSPACE + (n << PDXSHIFT)) | PTE_PS | PTE_P | PTE_W | PTE_PWT | PTE_PCD; 176 switchkvm(); 177 } 178 179 void 180 switchkvm(void) 181 { 182 lcr3(v2p(kpml4)); 183 } 184 185 void 186 switchuvm(struct proc *p) 187 { 188 void *pml4; 189 uint *tss; 190 pushcli(); 191 if(p->pgdir == 0) 192 panic("switchuvm: no pgdir"); 193 tss = (uint*) (((char*) cpu->local) + 1024); 194 tss_set_rsp(tss, 0, (uintp)proc->kstack + KSTACKSIZE); 195 pml4 = (void*) PTE_ADDR(p->pgdir[511]); 196 lcr3(v2p(pml4)); 197 popcli(); 198 } 199