xv6

port of xv6 to x86-64
git clone http://frotz.net/git/xv6.git
Log | Files | Refs | README | LICENSE

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