Commit 0b4401a9 authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

More work changing to new address types, almost done.

parent 82aa94ed
......@@ -76,6 +76,10 @@ static inline hpa_t hpa_add(hpa_t hpa, unsigned long off)
{
return __hpa(hpa_val(hpa) + off);
}
static inline hpa_t pa2hpa(unsigned long pa)
{
return (hpa_t){ pa };
}
static inline hpa_t va2hpa(void *va)
{
return (hpa_t){ __pa(va) };
......
......@@ -72,7 +72,7 @@ static int test03(void)
goto fail;
}
buf = (char *)__va(lcd->ept.root_hpa);
buf = (char *)hpa2va(lcd->ept.root);
for (i = 0; i < PAGE_SIZE; i++) {
if (buf[i]) {
printk(KERN_ERR "lcd arch : test03 nonzero in ept\n");
......@@ -93,12 +93,32 @@ fail_alloc:
return -1;
}
static int test04_help(struct lcd_arch *lcd, gpa_t base)
{
hpa_t actual;
unsigned long off;
for (off = 0; off < 0x40000; off += PAGE_SIZE) {
if (lcd_arch_ept_gpa_to_hpa(lcd, gpa_add(base, off), &actual)) {
printk(KERN_ERR "lcd arch : test04 failed lookup at %lx\n",
gpa_val(gpa_add(base, off)));
return -1;
}
if (hpa_val(actual) != gpa_val(gpa_add(base, off))) {
printk(KERN_ERR "lcd arch : test04 expected hpa %lx got %lx\n",
gpa_val(gpa_add(base, off)),
hpa_val(actual));
return -1;
}
}
}
static int test04(void)
{
struct lcd_arch *lcd;
u64 base;
u64 actual;
u64 off;
gpa_t base;
hpa_t actual;
unsigned long off;
lcd = (struct lcd_arch *)kmalloc(sizeof(*lcd), GFP_KERNEL);
if (!lcd) {
......@@ -111,26 +131,26 @@ static int test04(void)
}
/*
* Map 0x0 - 0x400000 (first 4 MBs, takes two page dirs)
* Map 0x0 - 0x400000 (first 4 MBs, takes two page tables)
*/
if (lcd_arch_ept_map_range(lcd, 0, 0, 1024)) {
if (lcd_arch_ept_map_range(lcd, __gpa(0), __hpa(0), 1024)) {
printk(KERN_ERR "lcd arch: test04 failed to map first 4 MBs\n");
goto fail3;
}
/*
* Map 0x40000000 - 0x40400000 (1GB -- 1GB + 4MBs, takes two page dirs)
* Map 0x40000000 - 0x40400000 (1GB -- 1GB + 4MBs)
*/
if (lcd_arch_ept_map_range(lcd, 1 << 30, 1 << 30, 1024)) {
if (lcd_arch_ept_map_range(lcd, __gpa(1 << 30), __hpa(1 << 30), 1024)) {
printk(KERN_ERR "lcd arch: test04 failed to map 2nd 4 MBs\n");
goto fail4;
}
/*
* Map 0x8000000000 - 0x8000400000 (512GB -- 512GB + 4MBs,
* takes two page dirs)
* Map 0x8000000000 - 0x8000400000 (512GB -- 512GB + 4MBs)
*/
if (lcd_arch_ept_map_range(lcd, 1UL << 39, 1UL << 39, 1024)) {
if (lcd_arch_ept_map_range(lcd, __gpa(1UL << 39),
__hpa(1UL << 39), 1024)) {
printk(KERN_ERR "lcd arch: test04 failed to map 3rd 4 MBs\n");
goto fail5;
}
......@@ -139,68 +159,30 @@ static int test04(void)
* CHECK
*/
base = 0;
for (off = 0; off < 0x40000; off += PAGE_SIZE) {
if (lcd_arch_ept_gpa_to_hpa(lcd, base + off, &actual)) {
printk(KERN_ERR "lcd arch : test04 failed lookup at %lx\n",
(unsigned long)(base + off));
goto fail6;
}
if (actual != (base + off)) {
printk(KERN_ERR "lcd arch : test04 expected hpa %lx got %lx\n",
(unsigned long)(base + off),
(unsigned long)actual);
goto fail6;
}
}
base = 0x40000000;
for (off = 0; off < 0x40000; off += PAGE_SIZE) {
if (lcd_arch_ept_gpa_to_hpa(lcd, base + off, &actual)) {
printk(KERN_ERR "lcd arch : test04 failed lookup at %lx\n",
(unsigned long)(base + off));
goto fail6;
}
if (actual != (base + off)) {
printk(KERN_ERR "lcd arch : test04 expected hpa %lx got %lx\n",
(unsigned long)(base + off),
(unsigned long)actual);
goto fail6;
}
}
base = 0x8000000000;
for (off = 0; off < 0x40000; off += PAGE_SIZE) {
if (lcd_arch_ept_gpa_to_hpa(lcd, base + off, &actual)) {
printk(KERN_ERR "lcd arch : test04 failed lookup at %lx\n",
(unsigned long)(base + off));
goto fail6;
}
if (actual != (base + off)) {
printk(KERN_ERR "lcd arch : test04 expected hpa %lx got %lx\n",
(unsigned long)(base + off),
(unsigned long)actual);
goto fail6;
}
}
lcd_arch_ept_unmap_range(lcd, 1UL << 39, 1024);
lcd_arch_ept_unmap_range(lcd, 1 << 30, 1024);
lcd_arch_ept_unmap_range(lcd, 0, 1024);
base = __gpa(0);
if (test04_help(lcd, base))
goto fail6;
base = __gpa(1 << 30);
if (test04_help(lcd, base))
goto fail6;
base = __gpa(1 << 39);
if (test04_help(lcd, base))
goto fail6;
lcd_arch_ept_unmap_range(lcd, __gpa(1UL << 39), 1024);
lcd_arch_ept_unmap_range(lcd, __gpa(1 << 30), 1024);
lcd_arch_ept_unmap_range(lcd, __gpa(0), 1024);
vmx_free_ept(lcd);
kfree(lcd);
return 0;
fail6:
lcd_arch_ept_unmap_range(lcd, 1UL << 39, 1024);
lcd_arch_ept_unmap_range(lcd, __gpa(1UL << 39), 1024);
fail5:
lcd_arch_ept_unmap_range(lcd, 1 << 30, 1024);
lcd_arch_ept_unmap_range(lcd, __gpa(1 << 30), 1024);
fail4:
lcd_arch_ept_unmap_range(lcd, 0, 1024);
lcd_arch_ept_unmap_range(lcd, __gpa(0), 1024);
fail3:
vmx_free_ept(lcd);
fail2:
......@@ -213,7 +195,7 @@ fail1:
static int test05(void)
{
struct lcd_arch *lcd;
u64 hpa;
hpa_t hpa;
lcd = (struct lcd_arch *)kmalloc(sizeof(*lcd), GFP_KERNEL);
if (!lcd) {
......@@ -232,7 +214,7 @@ static int test05(void)
printk(KERN_ERR "lcd arch : test05 lookup failed\n");
goto fail_lookup;
}
if (hpa != __pa(lcd->gdt)) {
if (hpa_val(hpa) != hpa_val(pa2hpa(lcd->gdt))) {
printk(KERN_ERR "lcd arch : test05 unexpected gdt addr\n");
goto fail_lookup;
}
......@@ -254,7 +236,7 @@ fail_alloc:
static int test06(void)
{
struct lcd_arch *lcd;
u64 hpa;
hpa_t hpa;
lcd = (struct lcd_arch *)kmalloc(sizeof(*lcd), GFP_KERNEL);
if (!lcd) {
......@@ -273,7 +255,7 @@ static int test06(void)
printk(KERN_ERR "lcd arch : test06 lookup failed\n");
goto fail_lookup;
}
if (hpa != __pa(lcd->tss)) {
if (hpa_val(hpa) != hpa_val(pa2hpa(lcd->tss))) {
printk(KERN_ERR "lcd arch : test06 unexpected tss addr\n");
goto fail_lookup;
}
......@@ -295,7 +277,7 @@ fail_alloc:
static int test07(void)
{
struct lcd_arch *lcd;
u64 hpa;
hpa_t hpa;
lcd = (struct lcd_arch *)kmalloc(sizeof(*lcd), GFP_KERNEL);
if (!lcd) {
......@@ -314,7 +296,7 @@ static int test07(void)
printk(KERN_ERR "lcd arch : test07 lookup failed\n");
goto fail_lookup;
}
if (hpa != __pa(lcd->utcb)) {
if (hpa_val(hpa) != hpa_val(pa2hpa(lcd->utcb))) {
printk(KERN_ERR "lcd arch : test07 unexpected utcb addr\n");
goto fail_lookup;
}
......
......@@ -21,22 +21,22 @@ struct lcd {
* Host virtual address of the root of the lcd's
* (initial) guest virtual paging hierarchy.
*/
u64 root_hva;
pgd_t *root;
/*
* Pointer to start of guest physical address space
* used for paging.
*/
u64 paging_mem_bot;
gpa_t paging_mem_bot;
/*
* Pointer to next free page in guest physical
* address space that can be used for a page table.
*/
u64 paging_mem_brk;
gpa_t paging_mem_brk;
/*
* Top of region in guest physical address space
* for page tables.
*/
u64 paging_mem_top;
gpa_t paging_mem_top;
} gv;
};
......
......@@ -28,7 +28,87 @@ MODULE_DESCRIPTION("LCD driver");
/* Guest Virtual -------------------------------------------------- */
static int lcd_mm_gva_alloc(struct lcd *lcd, u64 *gpa, u64 *hpa);
static inline gpa_t pte_gpa(pte_t *pte)
{
return __gpa(pte_pfn(*pte) << PAGE_SHIFT);
}
static inline gpa_t pmd_gpa(pmd_t *pmd_entry)
{
return __gpa(pmd_pfn(*pmd_entry) << PAGE_SHIFT);
}
static inline gpa_t pud_gpa(pud_t *pud_entry)
{
return __gpa(pud_pfn(*pud_entry) << PAGE_SHIFT);
}
static inline gpa_t pgd_gpa(pgd_t *pgd_entry)
{
return __gpa(pgd_pfn(*pgd_entry) << PAGE_SHIFT);
}
/**
* Allocates a host physical page and guest physical
* page (in the lcd's guest phys address space) for
* storing a paging structure.
*/
static int lcd_mm_gva_alloc(struct lcd *lcd, gpa_t *ga_out, hpa_t *ha_out)
{
hva_t hva;
gpa_t gpa;
hpa_t hpa;
int ret;
if (!lcd->gv.present) {
printk(KERN_ERR "lcd_mm_gva_alloc: gv paging not present\n");
ret = -EINVAL;
goto fail1;
}
/*
* Check watermark, and bump it.
*/
if (gpa_val(lcd->gv.paging_mem_brk) >=
gpa_val(lcd->gv.paging_mem_top)) {
printk(KERN_ERR "lcd_mm_gva_alloc: exhausted paging mem\n");
ret = -ENOMEM;
goto fail1;
}
gpa = lcd->gv.paging_mem_brk;
lcd->gv.paging_mem_brk = gpa_add(lcd->gv.paging_mem_brk, PAGE_SIZE);
/*
* Allocate a host physical page
*/
hva = __hva(__get_free_page(GFP_KERNEL));
if (!hva_val(hva)) {
printk(KERN_ERR "lcd_mm_gva_alloc: no host phys mem\n");
ret = -ENOMEM;
goto fail2;
}
memset(hva2va(hva), 0, PAGE_SIZE);
hpa = hva2hpa(hva);
/*
* Map in ept
*/
ret = lcd_arch_ept_map_range(lcd->lcd_arch, gpa, hpa, 1);
if (ret) {
printk(KERN_ERR "lcd_mm_gva_alloc: couldn't map gpa %lx to hpa %lx\n",
gpa_val(gpa),
hpa_val(hpa));
goto fail3;
}
*ga_out = gpa;
*ha_out = hpa;
return 0;
fail3:
free_page(hva_val(hva));
fail2:
fail1:
return ret;
}
/**
* Initializes guest virtual address space info in lcd, and
......@@ -36,11 +116,11 @@ static int lcd_mm_gva_alloc(struct lcd *lcd, u64 *gpa, u64 *hpa);
*
* Must be called before mapping any gva's.
*/
static int lcd_mm_gva_init(struct lcd *lcd, u64 gv_paging_mem_start_gpa,
u64 gv_paging_mem_end_gpa)
static int lcd_mm_gva_init(struct lcd *lcd, gpa_t gv_paging_mem_start,
gpa_t gv_paging_mem_end)
{
u64 gpa;
u64 hpa;
gpa_t gpa;
hpa_t hpa;
int ret;
/*
......@@ -50,15 +130,23 @@ static int lcd_mm_gva_init(struct lcd *lcd, u64 gv_paging_mem_start_gpa,
lcd->gv.paging_mem_brk = gv_paging_mem_start_gpa;
lcd->gv.paging_mem_top = gv_paging_mem_end_gpa;
/*
* Alloc a page for the pgd
*/
ret = lcd_mm_gva_alloc(lcd, &gpa, &hpa);
if (ret) {
printk(KERN_ERR "lcd_mm_gva_init: error alloc'ing\n");
goto fail1;
}
lcd->gv.root_hva = (u64)__va(hpa);
/*
* Mark root_hva as valid
* Store the root pointer
*/
lcd->gv.root = (pgd_t *)hpa2va(hpa);
lcd_arch_set_gva_root(lcd, gpa);
/*
* Mark paging as present
*/
lcd->gv.present = 1;
......@@ -70,21 +158,36 @@ fail1:
static int lcd_mm_pt_destroy(struct lcd *lcd, pmd_t *pmd_entry)
{
u64 gpa;
u64 hpa;
gpa_t gpa;
hpa_t hpa;
int ret;
pte_t pt;
/*
* Get hpa of page table, using gpa stored in pmd_entry.
*/
gpa = pmd_pfn(*pmd_entry) << PAGE_SHIFT;
gpa = pmd_gpa(pmd_entry);
ret = lcd_arch_ept_gpa_to_hpa(lcd->lcd_arch, gpa, &hpa);
if (ret) {
printk(KERN_ERR "lcd_mm_pt_destroy: error looking up gpa %lx\n",
(unsigned long)gpa);
gpa_val(gpa));
return ret;
}
pt = (pte_t *)hpa2va(hpa);
/*
* Check for any potential memory leaks
*/
for (i = 0; i < PTRS_PER_PTE; i++) {
if (pte_present(pt[i])) {
printk(KERN_ERR "lcd_mm_pt_destroy: possible memory leak
for gpa %lx (pt idx %d)\n",
gpa_val(pte_gpa(&pt[i])), i);
dump_stack();
}
}
/*
* Unmap page table
*/
......@@ -97,7 +200,7 @@ static int lcd_mm_pt_destroy(struct lcd *lcd, pmd_t *pmd_entry)
/*
* Free page table
*/
free_page((u64)__va(hpa));
free_page((unsigned long)pt);
return 0;
}
......@@ -105,23 +208,23 @@ static int lcd_mm_pt_destroy(struct lcd *lcd, pmd_t *pmd_entry)
static int lcd_mm_pmd_destroy(struct lcd *lcd, pud_t *pud_entry)
{
pmd_t *pmd;
u64 gpa;
u64 hpa;
gpa_t gpa;
hpa_t hpa;
int i;
int ret;
/*
* Get hpa of pmd, using gpa stored in pud_entry.
*/
gpa = pud_pfn(*pud_entry) << PAGE_SHIFT;
gpa = pud_gpa(pud_entry);
ret = lcd_arch_ept_gpa_to_hpa(lcd->lcd_arch, gpa, &hpa);
if (ret) {
printk(KERN_ERR "lcd_mm_pmd_destroy: error looking up gpa %lx\n",
(unsigned long)gpa);
gpa_val(gpa));
return ret;
}
pmd = (pmd_t *)__va(hpa);
pmd = (pmd_t *)hpa2va(hpa);
/*
* Free all present page tables
......@@ -148,7 +251,7 @@ static int lcd_mm_pmd_destroy(struct lcd *lcd, pud_t *pud_entry)
/*
* Free pmd
*/
free_page((u64)pmd);
free_page((unsigned long)pmd);
return 0;
}
......@@ -156,23 +259,23 @@ static int lcd_mm_pmd_destroy(struct lcd *lcd, pud_t *pud_entry)
static int lcd_mm_pud_destroy(struct lcd *lcd, pgd_t *pgd_entry)
{
pud_t *pud;
u64 gpa;
u64 hpa;
gpa_t gpa;
hpa_t hpa;
int i;
int ret;
/*
* Get hpa of pud, using gpa stored in pgd_entry.
*/
gpa = pgd_pfn(*pgd_entry) << PAGE_SHIFT;
gpa = pgd_gpa(pgd_entry);
ret = lcd_arch_ept_gpa_to_hpa(lcd->lcd_arch, gpa, &hpa);
if (ret) {
printk(KERN_ERR "lcd_mm_pud_destroy: error looking up gpa %lx\n",
(unsigned long)gpa);
gpa_val(gpa));
return ret;
}
pud = (pud_t *)__va(hpa);
pud = (pud_t *)hpa2va(hpa);
/*
* Destroy all present pmd's
......@@ -195,7 +298,7 @@ static int lcd_mm_pud_destroy(struct lcd *lcd, pgd_t *pgd_entry)
/*
* Free pud
*/
free_page((u64)pud);
free_page((unsigned long)pud);
return 0;
}
......@@ -213,7 +316,7 @@ static void lcd_mm_gva_destroy(struct lcd *lcd)
int i;
int ret;
pgd = (pgd_t *)lcd->gv.root_hva;
pgd = lcd->gv.root;
/*
* Free all present pud's
......@@ -242,7 +345,8 @@ static void lcd_mm_gva_destroy(struct lcd *lcd)
/*
* Free pgd
*/
free_page((u64)pgd);
free_page((unsigned long)pgd);
lcd->gv.root = NULL;
/*
* Mark as invalid
......@@ -250,91 +354,33 @@ static void lcd_mm_gva_destroy(struct lcd *lcd)
lcd->gv.present = 0;
}
/**
* Allocates a host physical page and guest physical
* page (in the lcd's guest phys address space) for
* storing a paging structure.
*/
static int lcd_mm_gva_alloc(struct lcd *lcd, u64 *gpa_out, u64 *hpa_out)
{
u64 hva;
u64 gpa;
u64 hpa;
int ret;
/*
* Check watermark, and bump it.
*/
if (lcd->gv.paging_mem_brk >= lcd->gv.paging_mem_top) {
printk(KERN_ERR "lcd_mm_gva_alloc: exhausted paging mem\n");
ret = -ENOMEM;
goto fail1;
}
gpa = lcd->gv.paging_mem_brk;
lcd->gv.paging_mem_brk += PAGE_SIZE;
/*
* Allocate a host physical page
*/
hva = __get_free_page(GFP_KERNEL);
if (!hva) {
printk(KERN_ERR "lcd_mm_gva_alloc: no host phys mem\n");
ret = -ENOMEM;
goto fail2;
}
memset((void *)hva, 0, PAGE_SIZE);
hpa = __pa(hva);
/*
* Map in ept
*/
ret = lcd_arch_ept_map_range(lcd->lcd_arch, gpa, hpa, 1);
if (ret) {
printk(KERN_ERR "lcd_mm_gva_alloc: couldn't map gpa %lx to hpa %lx\n",
(unsigned long)gpa,
(unsigned long)hpa);
goto fail3;
}
*gpa_out = gpa;
*hpa_out = hpa;
return 0;
fail3:
free_page((u64)hva);
fail2:
lcd->gv.paging_mem_brk -= PAGE_SIZE;
fail1:
return ret;
}
/**
* Get host virtual address of pte
* for gva and pmd_entry.
*/
static int lcd_mm_gva_lookup_pte(struct lcd *lcd, u64 gva, pmd_t *pmd_entry,
static int lcd_mm_gva_lookup_pte(struct lcd *lcd, gva_t gva, pmd_t *pmd_entry,
pte_t **pte_out)
{
int ret;
u64 gpa;
u64 hpa;
gpa_t gpa;
hpa_t hpa;
pte_t *entry;
/*
* Get hpa of page table, using gpa stored in pmd_entry.
*/
gpa = pmd_pfn(*pmd_entry) << PAGE_SHIFT;
gpa = pmd_gpa(pmd_entry);
ret = lcd_arch_ept_gpa_to_hpa(lcd->lcd_arch, gpa, &hpa);
if (ret) {
printk(KERN_ERR "lcd_mm_gva_lookup_pte: error looking up gpa %lx\n",
(unsigned long)gpa);
gpa_val(gpa));
return ret;
}
/*
* Look up entry in page table
*/
entry = ((pte_t *)__va(hpa)) + pte_index(gva);
entry = ((pte_t *)hpa2va(hpa)) + pte_index(gva_val(gva));