/root/src/xen/xen/arch/x86/mm/hap/guest_walk.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * arch/x86/mm/hap/guest_walk.c |
3 | | * |
4 | | * Guest page table walker |
5 | | * Copyright (c) 2007, AMD Corporation (Wei Huang) |
6 | | * Copyright (c) 2007, XenSource Inc. |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms and conditions of the GNU General Public License, |
10 | | * version 2, as published by the Free Software Foundation. |
11 | | * |
12 | | * This program is distributed in the hope it will be useful, but WITHOUT |
13 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 | | * more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License along with |
18 | | * this program; If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | /* Allow uniquely identifying static symbols in the 3 generated objects. */ |
22 | | asm(".file \"" __OBJECT_FILE__ "\""); |
23 | | |
24 | | #include <xen/domain_page.h> |
25 | | #include <xen/paging.h> |
26 | | #include <xen/sched.h> |
27 | | #include "private.h" /* for hap_gva_to_gfn_* */ |
28 | | |
29 | | #define _hap_gva_to_gfn(levels) hap_gva_to_gfn_##levels##_levels |
30 | | #define hap_gva_to_gfn(levels) _hap_gva_to_gfn(levels) |
31 | | |
32 | 364k | #define _hap_p2m_ga_to_gfn(levels) hap_p2m_ga_to_gfn_##levels##_levels |
33 | 364k | #define hap_p2m_ga_to_gfn(levels) _hap_p2m_ga_to_gfn(levels) |
34 | | |
35 | | #if GUEST_PAGING_LEVELS > CONFIG_PAGING_LEVELS |
36 | | #error GUEST_PAGING_LEVELS must not exceed CONFIG_PAGING_LEVELS |
37 | | #endif |
38 | | |
39 | | #include <asm/guest_pt.h> |
40 | | #include <asm/p2m.h> |
41 | | |
42 | | unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)( |
43 | | struct vcpu *v, struct p2m_domain *p2m, unsigned long gva, uint32_t *pfec) |
44 | 364k | { |
45 | 364k | unsigned long cr3 = v->arch.hvm_vcpu.guest_cr[3]; |
46 | 364k | return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec, NULL); |
47 | 364k | } Unexecuted instantiation: hap_gva_to_gfn_2_levels Unexecuted instantiation: hap_gva_to_gfn_3_levels Line | Count | Source | 44 | 364k | { | 45 | 364k | unsigned long cr3 = v->arch.hvm_vcpu.guest_cr[3]; | 46 | 364k | return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec, NULL); | 47 | 364k | } |
|
48 | | |
49 | | unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)( |
50 | | struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, |
51 | | paddr_t ga, uint32_t *pfec, unsigned int *page_order) |
52 | 364k | { |
53 | 364k | bool walk_ok; |
54 | 364k | mfn_t top_mfn; |
55 | 364k | void *top_map; |
56 | 364k | p2m_type_t p2mt; |
57 | 364k | walk_t gw; |
58 | 364k | gfn_t top_gfn; |
59 | 364k | struct page_info *top_page; |
60 | 364k | |
61 | 364k | /* Get the top-level table's MFN */ |
62 | 364k | top_gfn = _gfn(cr3 >> PAGE_SHIFT); |
63 | 364k | top_page = p2m_get_page_from_gfn(p2m, top_gfn, &p2mt, NULL, |
64 | 364k | P2M_ALLOC | P2M_UNSHARE); |
65 | 364k | if ( p2m_is_paging(p2mt) ) |
66 | 0 | { |
67 | 0 | ASSERT(p2m_is_hostp2m(p2m)); |
68 | 0 | *pfec = PFEC_page_paged; |
69 | 0 | if ( top_page ) |
70 | 0 | put_page(top_page); |
71 | 0 | p2m_mem_paging_populate(p2m->domain, cr3 >> PAGE_SHIFT); |
72 | 0 | return gfn_x(INVALID_GFN); |
73 | 0 | } |
74 | 364k | if ( p2m_is_shared(p2mt) ) |
75 | 0 | { |
76 | 0 | *pfec = PFEC_page_shared; |
77 | 0 | if ( top_page ) |
78 | 0 | put_page(top_page); |
79 | 0 | return gfn_x(INVALID_GFN); |
80 | 0 | } |
81 | 364k | if ( !top_page ) |
82 | 0 | { |
83 | 0 | *pfec &= ~PFEC_page_present; |
84 | 0 | goto out_tweak_pfec; |
85 | 0 | } |
86 | 364k | top_mfn = _mfn(page_to_mfn(top_page)); |
87 | 364k | |
88 | 364k | /* Map the top-level table and call the tree-walker */ |
89 | 364k | ASSERT(mfn_valid(top_mfn)); |
90 | 364k | top_map = map_domain_page(top_mfn); |
91 | 364k | #if GUEST_PAGING_LEVELS == 3 |
92 | 0 | top_map += (cr3 & ~(PAGE_MASK | 31)); |
93 | | #endif |
94 | 364k | walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map); |
95 | 364k | unmap_domain_page(top_map); |
96 | 364k | put_page(top_page); |
97 | 364k | |
98 | 364k | /* Interpret the answer */ |
99 | 364k | if ( walk_ok ) |
100 | 366k | { |
101 | 366k | gfn_t gfn = guest_walk_to_gfn(&gw); |
102 | 366k | struct page_info *page; |
103 | 366k | |
104 | 366k | page = p2m_get_page_from_gfn(p2m, gfn, &p2mt, NULL, |
105 | 366k | P2M_ALLOC | P2M_UNSHARE); |
106 | 366k | if ( page ) |
107 | 366k | put_page(page); |
108 | 366k | if ( p2m_is_paging(p2mt) ) |
109 | 0 | { |
110 | 0 | ASSERT(p2m_is_hostp2m(p2m)); |
111 | 0 | *pfec = PFEC_page_paged; |
112 | 0 | p2m_mem_paging_populate(p2m->domain, gfn_x(gfn)); |
113 | 0 | return gfn_x(INVALID_GFN); |
114 | 0 | } |
115 | 366k | if ( p2m_is_shared(p2mt) ) |
116 | 0 | { |
117 | 0 | *pfec = PFEC_page_shared; |
118 | 0 | return gfn_x(INVALID_GFN); |
119 | 0 | } |
120 | 366k | |
121 | 366k | if ( page_order ) |
122 | 0 | *page_order = guest_walk_to_page_order(&gw); |
123 | 366k | |
124 | 366k | return gfn_x(gfn); |
125 | 366k | } |
126 | 364k | |
127 | 18.4E | *pfec = gw.pfec; |
128 | 18.4E | |
129 | 0 | out_tweak_pfec: |
130 | 0 | /* |
131 | 0 | * SDM Intel 64 Volume 3, Chapter Paging, PAGE-FAULT EXCEPTIONS: |
132 | 0 | * The PFEC_insn_fetch flag is set only when NX or SMEP are enabled. |
133 | 0 | */ |
134 | 0 | if ( !hvm_nx_enabled(v) && !hvm_smep_enabled(v) ) |
135 | 0 | *pfec &= ~PFEC_insn_fetch; |
136 | 0 |
|
137 | 0 | return gfn_x(INVALID_GFN); |
138 | 18.4E | } Unexecuted instantiation: hap_p2m_ga_to_gfn_2_levels Unexecuted instantiation: hap_p2m_ga_to_gfn_3_levels hap_p2m_ga_to_gfn_4_levels Line | Count | Source | 52 | 364k | { | 53 | 364k | bool walk_ok; | 54 | 364k | mfn_t top_mfn; | 55 | 364k | void *top_map; | 56 | 364k | p2m_type_t p2mt; | 57 | 364k | walk_t gw; | 58 | 364k | gfn_t top_gfn; | 59 | 364k | struct page_info *top_page; | 60 | 364k | | 61 | 364k | /* Get the top-level table's MFN */ | 62 | 364k | top_gfn = _gfn(cr3 >> PAGE_SHIFT); | 63 | 364k | top_page = p2m_get_page_from_gfn(p2m, top_gfn, &p2mt, NULL, | 64 | 364k | P2M_ALLOC | P2M_UNSHARE); | 65 | 364k | if ( p2m_is_paging(p2mt) ) | 66 | 0 | { | 67 | 0 | ASSERT(p2m_is_hostp2m(p2m)); | 68 | 0 | *pfec = PFEC_page_paged; | 69 | 0 | if ( top_page ) | 70 | 0 | put_page(top_page); | 71 | 0 | p2m_mem_paging_populate(p2m->domain, cr3 >> PAGE_SHIFT); | 72 | 0 | return gfn_x(INVALID_GFN); | 73 | 0 | } | 74 | 364k | if ( p2m_is_shared(p2mt) ) | 75 | 0 | { | 76 | 0 | *pfec = PFEC_page_shared; | 77 | 0 | if ( top_page ) | 78 | 0 | put_page(top_page); | 79 | 0 | return gfn_x(INVALID_GFN); | 80 | 0 | } | 81 | 364k | if ( !top_page ) | 82 | 0 | { | 83 | 0 | *pfec &= ~PFEC_page_present; | 84 | 0 | goto out_tweak_pfec; | 85 | 0 | } | 86 | 364k | top_mfn = _mfn(page_to_mfn(top_page)); | 87 | 364k | | 88 | 364k | /* Map the top-level table and call the tree-walker */ | 89 | 364k | ASSERT(mfn_valid(top_mfn)); | 90 | 364k | top_map = map_domain_page(top_mfn); | 91 | 364k | #if GUEST_PAGING_LEVELS == 3 | 92 | | top_map += (cr3 & ~(PAGE_MASK | 31)); | 93 | | #endif | 94 | 364k | walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map); | 95 | 364k | unmap_domain_page(top_map); | 96 | 364k | put_page(top_page); | 97 | 364k | | 98 | 364k | /* Interpret the answer */ | 99 | 364k | if ( walk_ok ) | 100 | 366k | { | 101 | 366k | gfn_t gfn = guest_walk_to_gfn(&gw); | 102 | 366k | struct page_info *page; | 103 | 366k | | 104 | 366k | page = p2m_get_page_from_gfn(p2m, gfn, &p2mt, NULL, | 105 | 366k | P2M_ALLOC | P2M_UNSHARE); | 106 | 366k | if ( page ) | 107 | 366k | put_page(page); | 108 | 366k | if ( p2m_is_paging(p2mt) ) | 109 | 0 | { | 110 | 0 | ASSERT(p2m_is_hostp2m(p2m)); | 111 | 0 | *pfec = PFEC_page_paged; | 112 | 0 | p2m_mem_paging_populate(p2m->domain, gfn_x(gfn)); | 113 | 0 | return gfn_x(INVALID_GFN); | 114 | 0 | } | 115 | 366k | if ( p2m_is_shared(p2mt) ) | 116 | 0 | { | 117 | 0 | *pfec = PFEC_page_shared; | 118 | 0 | return gfn_x(INVALID_GFN); | 119 | 0 | } | 120 | 366k | | 121 | 366k | if ( page_order ) | 122 | 0 | *page_order = guest_walk_to_page_order(&gw); | 123 | 366k | | 124 | 366k | return gfn_x(gfn); | 125 | 366k | } | 126 | 364k | | 127 | 18.4E | *pfec = gw.pfec; | 128 | 18.4E | | 129 | 0 | out_tweak_pfec: | 130 | 0 | /* | 131 | 0 | * SDM Intel 64 Volume 3, Chapter Paging, PAGE-FAULT EXCEPTIONS: | 132 | 0 | * The PFEC_insn_fetch flag is set only when NX or SMEP are enabled. | 133 | 0 | */ | 134 | 0 | if ( !hvm_nx_enabled(v) && !hvm_smep_enabled(v) ) | 135 | 0 | *pfec &= ~PFEC_insn_fetch; | 136 | 0 |
| 137 | 0 | return gfn_x(INVALID_GFN); | 138 | 18.4E | } |
|
139 | | |
140 | | |
141 | | /* |
142 | | * Local variables: |
143 | | * mode: C |
144 | | * c-file-style: "BSD" |
145 | | * c-basic-offset: 4 |
146 | | * tab-width: 4 |
147 | | * indent-tabs-mode: nil |
148 | | * End: |
149 | | */ |