diff options
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r-- | arch/x86/kvm/mmu.c | 83 |
1 files changed, 29 insertions, 54 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index c669f2af1d12..a25e1adb5cff 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -1846,67 +1846,42 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) | |||
1846 | { | 1846 | { |
1847 | } | 1847 | } |
1848 | 1848 | ||
1849 | struct direct_shadow_walk { | 1849 | static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, |
1850 | struct kvm_shadow_walk walker; | 1850 | int largepage, gfn_t gfn, pfn_t pfn) |
1851 | pfn_t pfn; | ||
1852 | int write; | ||
1853 | int largepage; | ||
1854 | int pt_write; | ||
1855 | }; | ||
1856 | |||
1857 | static int direct_map_entry(struct kvm_shadow_walk *_walk, | ||
1858 | struct kvm_vcpu *vcpu, | ||
1859 | u64 addr, u64 *sptep, int level) | ||
1860 | { | 1851 | { |
1861 | struct direct_shadow_walk *walk = | 1852 | struct kvm_shadow_walk_iterator iterator; |
1862 | container_of(_walk, struct direct_shadow_walk, walker); | ||
1863 | struct kvm_mmu_page *sp; | 1853 | struct kvm_mmu_page *sp; |
1854 | int pt_write = 0; | ||
1864 | gfn_t pseudo_gfn; | 1855 | gfn_t pseudo_gfn; |
1865 | gfn_t gfn = addr >> PAGE_SHIFT; | ||
1866 | |||
1867 | if (level == PT_PAGE_TABLE_LEVEL | ||
1868 | || (walk->largepage && level == PT_DIRECTORY_LEVEL)) { | ||
1869 | mmu_set_spte(vcpu, sptep, ACC_ALL, ACC_ALL, | ||
1870 | 0, walk->write, 1, &walk->pt_write, | ||
1871 | walk->largepage, 0, gfn, walk->pfn, false); | ||
1872 | ++vcpu->stat.pf_fixed; | ||
1873 | return 1; | ||
1874 | } | ||
1875 | 1856 | ||
1876 | if (*sptep == shadow_trap_nonpresent_pte) { | 1857 | for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) { |
1877 | pseudo_gfn = (addr & PT64_DIR_BASE_ADDR_MASK) >> PAGE_SHIFT; | 1858 | if (iterator.level == PT_PAGE_TABLE_LEVEL |
1878 | sp = kvm_mmu_get_page(vcpu, pseudo_gfn, (gva_t)addr, level - 1, | 1859 | || (largepage && iterator.level == PT_DIRECTORY_LEVEL)) { |
1879 | 1, ACC_ALL, sptep); | 1860 | mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, |
1880 | if (!sp) { | 1861 | 0, write, 1, &pt_write, |
1881 | pgprintk("nonpaging_map: ENOMEM\n"); | 1862 | largepage, 0, gfn, pfn, false); |
1882 | kvm_release_pfn_clean(walk->pfn); | 1863 | ++vcpu->stat.pf_fixed; |
1883 | return -ENOMEM; | 1864 | break; |
1884 | } | 1865 | } |
1885 | 1866 | ||
1886 | set_shadow_pte(sptep, | 1867 | if (*iterator.sptep == shadow_trap_nonpresent_pte) { |
1887 | __pa(sp->spt) | 1868 | pseudo_gfn = (iterator.addr & PT64_DIR_BASE_ADDR_MASK) >> PAGE_SHIFT; |
1888 | | PT_PRESENT_MASK | PT_WRITABLE_MASK | 1869 | sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr, |
1889 | | shadow_user_mask | shadow_x_mask); | 1870 | iterator.level - 1, |
1890 | } | 1871 | 1, ACC_ALL, iterator.sptep); |
1891 | return 0; | 1872 | if (!sp) { |
1892 | } | 1873 | pgprintk("nonpaging_map: ENOMEM\n"); |
1874 | kvm_release_pfn_clean(pfn); | ||
1875 | return -ENOMEM; | ||
1876 | } | ||
1893 | 1877 | ||
1894 | static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, | 1878 | set_shadow_pte(iterator.sptep, |
1895 | int largepage, gfn_t gfn, pfn_t pfn) | 1879 | __pa(sp->spt) |
1896 | { | 1880 | | PT_PRESENT_MASK | PT_WRITABLE_MASK |
1897 | int r; | 1881 | | shadow_user_mask | shadow_x_mask); |
1898 | struct direct_shadow_walk walker = { | 1882 | } |
1899 | .walker = { .entry = direct_map_entry, }, | 1883 | } |
1900 | .pfn = pfn, | 1884 | return pt_write; |
1901 | .largepage = largepage, | ||
1902 | .write = write, | ||
1903 | .pt_write = 0, | ||
1904 | }; | ||
1905 | |||
1906 | r = walk_shadow(&walker.walker, vcpu, gfn << PAGE_SHIFT); | ||
1907 | if (r < 0) | ||
1908 | return r; | ||
1909 | return walker.pt_write; | ||
1910 | } | 1885 | } |
1911 | 1886 | ||
1912 | static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) | 1887 | static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) |