diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-10 23:45:09 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-11 01:17:31 -0500 |
commit | c9e433e4b852b70ea267388cf9b5d8096b04c44c (patch) | |
tree | e456fdc2a7b08ded02723f9235e6d6afd7991642 /drivers/lguest | |
parent | 8ed313001a892f240269dea05d4b925cbd150492 (diff) |
lguest: add infrastructure to check mappings.
We normally abort the guest unconditionally when it gives us a bad address,
but in the next patch we want to copy some bytes which may not be mapped.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest')
-rw-r--r-- | drivers/lguest/lg.h | 1 | ||||
-rw-r--r-- | drivers/lguest/page_tables.c | 42 |
2 files changed, 30 insertions, 13 deletions
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 020fec5bb072..9da4f351e077 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h | |||
@@ -202,6 +202,7 @@ void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir, | |||
202 | void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages); | 202 | void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages); |
203 | bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode); | 203 | bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode); |
204 | void pin_page(struct lg_cpu *cpu, unsigned long vaddr); | 204 | void pin_page(struct lg_cpu *cpu, unsigned long vaddr); |
205 | bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr); | ||
205 | unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr); | 206 | unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr); |
206 | void page_table_guest_data_init(struct lg_cpu *cpu); | 207 | void page_table_guest_data_init(struct lg_cpu *cpu); |
207 | 208 | ||
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index e8b55c3a6170..69c35caa955a 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -647,7 +647,7 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu) | |||
647 | /*:*/ | 647 | /*:*/ |
648 | 648 | ||
649 | /* We walk down the guest page tables to get a guest-physical address */ | 649 | /* We walk down the guest page tables to get a guest-physical address */ |
650 | unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr) | 650 | bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr) |
651 | { | 651 | { |
652 | pgd_t gpgd; | 652 | pgd_t gpgd; |
653 | pte_t gpte; | 653 | pte_t gpte; |
@@ -656,31 +656,47 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr) | |||
656 | #endif | 656 | #endif |
657 | 657 | ||
658 | /* Still not set up? Just map 1:1. */ | 658 | /* Still not set up? Just map 1:1. */ |
659 | if (unlikely(cpu->linear_pages)) | 659 | if (unlikely(cpu->linear_pages)) { |
660 | return vaddr; | 660 | *paddr = vaddr; |
661 | return true; | ||
662 | } | ||
661 | 663 | ||
662 | /* First step: get the top-level Guest page table entry. */ | 664 | /* First step: get the top-level Guest page table entry. */ |
663 | gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t); | 665 | gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t); |
664 | /* Toplevel not present? We can't map it in. */ | 666 | /* Toplevel not present? We can't map it in. */ |
665 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) { | 667 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) |
666 | kill_guest(cpu, "Bad address %#lx", vaddr); | 668 | goto fail; |
667 | return -1UL; | ||
668 | } | ||
669 | 669 | ||
670 | #ifdef CONFIG_X86_PAE | 670 | #ifdef CONFIG_X86_PAE |
671 | gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t); | 671 | gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t); |
672 | if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) { | 672 | if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) |
673 | kill_guest(cpu, "Bad address %#lx", vaddr); | 673 | goto fail; |
674 | return -1UL; | ||
675 | } | ||
676 | gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t); | 674 | gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t); |
677 | #else | 675 | #else |
678 | gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t); | 676 | gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t); |
679 | #endif | 677 | #endif |
680 | if (!(pte_flags(gpte) & _PAGE_PRESENT)) | 678 | if (!(pte_flags(gpte) & _PAGE_PRESENT)) |
681 | kill_guest(cpu, "Bad address %#lx", vaddr); | 679 | goto fail; |
680 | |||
681 | *paddr = pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK); | ||
682 | return true; | ||
683 | |||
684 | fail: | ||
685 | *paddr = -1UL; | ||
686 | return false; | ||
687 | } | ||
682 | 688 | ||
683 | return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK); | 689 | /* |
690 | * This is the version we normally use: kills the Guest if it uses a | ||
691 | * bad address | ||
692 | */ | ||
693 | unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr) | ||
694 | { | ||
695 | unsigned long paddr; | ||
696 | |||
697 | if (!__guest_pa(cpu, vaddr, &paddr)) | ||
698 | kill_guest(cpu, "Bad address %#lx", vaddr); | ||
699 | return paddr; | ||
684 | } | 700 | } |
685 | 701 | ||
686 | /* | 702 | /* |