x86: Add EPTs to the boot_pmls
authorBarret Rhoden <brho@cs.berkeley.edu>
Sun, 27 Nov 2016 18:40:06 +0000 (13:40 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 29 Nov 2016 16:27:40 +0000 (11:27 -0500)
Previously, the boot page tables (set up in entry64.S) were only KPTs,
but with no space for EPTs.  If we performed any pmap functions that
assumed there were EPTs, then we'd be clobbering nearby, unused memory.

This was potentially happening for map_vmap_segment(), which innocently
called pte_write(), which assumes there is an EPT table adjacent to the
KPT.  This would only have been a problem if we were working on a boot
pml table, to include the boot_pml4.

Although the kernel will never use the EPT mappings, and those mappings
are not copied from boot_pml4 to the processes' page tables, it's safer
to always have the memory for the EPT available so that we don't have to
special case that much code.

Though for a dose of paranoia, I won't fill in the intermediate EPT
entries.  It's safe to write the memory of an EPT (e.g. pte_write()),
but since the EPT PMLs aren't linked, the walks won't go anywhere.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/entry64.S
kern/arch/x86/pmap64.c

index eeed1fc..fe60d89 100644 (file)
@@ -187,11 +187,11 @@ fill_pml3:
        push    %eax
        movl    $512, %ebp                                      # count = 512 for PML2 (map it all)
        push    %ebp
-       # compute pml2 (pml2base + (total count - current count) * PGSIZE)
+       # compute pml2 (pml2base + (total count - current count) * PGSIZE * 2)
        movl    0x28(%esp), %ebp                        # pml2base (8 push, 1 ret, arg5)
        movl    0x24(%esp), %edi                        # total count
        subl    %ebx, %edi
-       shll    $12, %edi
+       shll    $13, %edi
        addl    %edi, %ebp
        movl    %ebp, %edi                                      # arg0 for the func call
        call    fill_jpml2
@@ -426,23 +426,23 @@ no_pml3ps_string:
        .align PGSIZE
 .globl boot_pml4
 boot_pml4:
-       .space  PGSIZE
+       .space  PGSIZE * 2
 boot_pml3_lo:
-       .space  PGSIZE
+       .space  PGSIZE * 2
 boot_pml3_hi:
-       .space  PGSIZE
+       .space  PGSIZE * 2
 boot_pml3_kb:
-       .space  PGSIZE
+       .space  PGSIZE * 2
 stack32:
        .space  PGSIZE
 stack32top:
 # Could make all of the no-jumbo stuff a config var
 boot_pml2_lo:          # one pml2 (1GB in the lo pml3)
-       .space  PGSIZE
+       .space  PGSIZE * 2
 boot_pml2_hi:          # one pml2 (1GB in the hi pml3)
-       .space  PGSIZE
-boot_pml2_kb:          # 512 pml2s in the kb pml3
-       .space  PGSIZE * 512
+       .space  PGSIZE * 2
+boot_pml2_kb:          # 512 pml2s (+ epts) in the kb pml3
+       .space  PGSIZE * 512 * 2
 
 # From here down is linked for KERNBASE
 .text
index e5b149d..5e7949c 100644 (file)
@@ -112,14 +112,18 @@ static kpte_t *__pml_walk(kpte_t *pml, uintptr_t va, int flags, int pml_shift)
                 * translation is !User).  We put the perms on the last entry, not the
                 * intermediates. */
                *kpte = PADDR(new_pml_kva) | PTE_P | PTE_U | PTE_W;
-               /* The physaddr of the new_pml is one page higher than the KPT page.  A
-                * few other things:
-                * - for the same reason that we have U and X set on all intermediate
-                * PTEs, we now set R, X, and W for the EPTE.
-                * - All EPTEs have U perms
-                * - We can't use epte_write since we're workin on intermediate PTEs,
-                * and they don't have the memory type set. */
-               *epte = (PADDR(new_pml_kva) + PGSIZE) | EPTE_R | EPTE_X | EPTE_W;
+               /* For a dose of paranoia, we'll avoid mapping intermediate eptes when
+                * we know we're using an address that should never be ept-accesible. */
+               if (va < ULIM) {
+                       /* The physaddr of the new_pml is one page higher than the KPT page.
+                        * A few other things:
+                        * - for the same reason that we have U and X set on all
+                        *   intermediate PTEs, we now set R, X, and W for the EPTE.
+                        * - All EPTEs have U perms
+                        * - We can't use epte_write since we're workin on intermediate
+                        *   PTEs, and they don't have the memory type set. */
+                       *epte = (PADDR(new_pml_kva) + PGSIZE) | EPTE_R | EPTE_X | EPTE_W;
+               }
        }
        return __pml_walk(kpte2pml(*kpte), va, flags, pml_shift - BITS_PER_PML);
 }
@@ -185,8 +189,7 @@ static void map_my_pages(kpte_t *pgdir, uintptr_t va, size_t size,
             pa += pgsize) {
                kpte = get_next_pte(kpte, pgdir, va, PG_WALK_CREATE | pml_shift);
                assert(kpte);
-               *kpte = PTE_ADDR(pa) | perm |
-                       (pml_shift != PML1_SHIFT ? PTE_PS : 0);
+               pte_write(kpte, pa, perm | (pml_shift != PML1_SHIFT ? PTE_PS : 0));
                printd("Wrote *kpte %p, for va %p to pa %p tried to cover %p\n",
                       *kpte, va, pa, amt_mapped);
        }
@@ -358,7 +361,7 @@ int unmap_segment(pgdir_t pgdir, uintptr_t va, size_t size)
                if (!kpte_is_present(kpte))
                        return 0;
                if (pte_is_final(kpte, shift)) {
-                       *kpte = 0;
+                       pte_clear(kpte);
                        return 0;
                }
                /* If we haven't visited all of our subs, we might still have some
@@ -372,7 +375,7 @@ int unmap_segment(pgdir_t pgdir, uintptr_t va, size_t size)
                        }
                }
                kpages_free(KADDR(PTE_ADDR(*kpte)), 2 * PGSIZE);
-               *kpte = 0;
+               pte_clear(kpte);
                return 0;
        }
        /* Don't accidentally unmap the boot mappings */