debuggers.hg

view xen/include/asm-x86/guest_pt.h @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents 7831b8e5aae2
children
line source
1 /******************************************************************************
2 * xen/asm-x86/guest_pt.h
3 *
4 * Types and accessors for guest pagetable entries, as distinct from
5 * Xen's pagetable types.
6 *
7 * Users must #define GUEST_PAGING_LEVELS to 2, 3 or 4 before including
8 * this file.
9 *
10 * Parts of this code are Copyright (c) 2006 by XenSource Inc.
11 * Parts of this code are Copyright (c) 2006 by Michael A Fetterman
12 * Parts based on earlier work by Michael A Fetterman, Ian Pratt et al.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 */
29 #ifndef _XEN_ASM_GUEST_PT_H
30 #define _XEN_ASM_GUEST_PT_H
32 #if !defined(GUEST_PAGING_LEVELS)
33 #error GUEST_PAGING_LEVELS not defined
34 #endif
36 /* Type of the guest's frame numbers */
37 TYPE_SAFE(unsigned long,gfn)
38 #define PRI_gfn "05lx"
40 #define VALID_GFN(m) (m != INVALID_GFN)
42 static inline int
43 valid_gfn(gfn_t m)
44 {
45 return VALID_GFN(gfn_x(m));
46 }
48 static inline paddr_t
49 gfn_to_paddr(gfn_t gfn)
50 {
51 return ((paddr_t)gfn_x(gfn)) << PAGE_SHIFT;
52 }
54 /* Override gfn_to_mfn to work with gfn_t */
55 #undef gfn_to_mfn
56 #define gfn_to_mfn(d, g, t) _gfn_to_mfn_type((d), gfn_x(g), (t), p2m_alloc)
59 /* Types of the guest's page tables and access functions for them */
61 #if GUEST_PAGING_LEVELS == 2
63 #define GUEST_L1_PAGETABLE_ENTRIES 1024
64 #define GUEST_L2_PAGETABLE_ENTRIES 1024
65 #define GUEST_L1_PAGETABLE_SHIFT 12
66 #define GUEST_L2_PAGETABLE_SHIFT 22
68 typedef uint32_t guest_intpte_t;
69 typedef struct { guest_intpte_t l1; } guest_l1e_t;
70 typedef struct { guest_intpte_t l2; } guest_l2e_t;
72 #define PRI_gpte "08x"
74 static inline paddr_t guest_l1e_get_paddr(guest_l1e_t gl1e)
75 { return ((paddr_t) gl1e.l1) & (PADDR_MASK & PAGE_MASK); }
76 static inline paddr_t guest_l2e_get_paddr(guest_l2e_t gl2e)
77 { return ((paddr_t) gl2e.l2) & (PADDR_MASK & PAGE_MASK); }
79 static inline gfn_t guest_l1e_get_gfn(guest_l1e_t gl1e)
80 { return _gfn(guest_l1e_get_paddr(gl1e) >> PAGE_SHIFT); }
81 static inline gfn_t guest_l2e_get_gfn(guest_l2e_t gl2e)
82 { return _gfn(guest_l2e_get_paddr(gl2e) >> PAGE_SHIFT); }
84 static inline u32 guest_l1e_get_flags(guest_l1e_t gl1e)
85 { return gl1e.l1 & 0xfff; }
86 static inline u32 guest_l2e_get_flags(guest_l2e_t gl2e)
87 { return gl2e.l2 & 0xfff; }
89 static inline guest_l1e_t guest_l1e_from_gfn(gfn_t gfn, u32 flags)
90 { return (guest_l1e_t) { (gfn_x(gfn) << PAGE_SHIFT) | flags }; }
91 static inline guest_l2e_t guest_l2e_from_gfn(gfn_t gfn, u32 flags)
92 { return (guest_l2e_t) { (gfn_x(gfn) << PAGE_SHIFT) | flags }; }
94 #define guest_l1_table_offset(_va) \
95 (((_va) >> GUEST_L1_PAGETABLE_SHIFT) & (GUEST_L1_PAGETABLE_ENTRIES - 1))
96 #define guest_l2_table_offset(_va) \
97 (((_va) >> GUEST_L2_PAGETABLE_SHIFT) & (GUEST_L2_PAGETABLE_ENTRIES - 1))
99 #else /* GUEST_PAGING_LEVELS != 2 */
101 #if GUEST_PAGING_LEVELS == 3
102 #define GUEST_L1_PAGETABLE_ENTRIES 512
103 #define GUEST_L2_PAGETABLE_ENTRIES 512
104 #define GUEST_L3_PAGETABLE_ENTRIES 4
105 #define GUEST_L1_PAGETABLE_SHIFT 12
106 #define GUEST_L2_PAGETABLE_SHIFT 21
107 #define GUEST_L3_PAGETABLE_SHIFT 30
108 #else /* GUEST_PAGING_LEVELS == 4 */
109 #define GUEST_L1_PAGETABLE_ENTRIES 512
110 #define GUEST_L2_PAGETABLE_ENTRIES 512
111 #define GUEST_L3_PAGETABLE_ENTRIES 512
112 #define GUEST_L4_PAGETABLE_ENTRIES 512
113 #define GUEST_L1_PAGETABLE_SHIFT 12
114 #define GUEST_L2_PAGETABLE_SHIFT 21
115 #define GUEST_L3_PAGETABLE_SHIFT 30
116 #define GUEST_L4_PAGETABLE_SHIFT 39
117 #endif
119 typedef l1_pgentry_t guest_l1e_t;
120 typedef l2_pgentry_t guest_l2e_t;
121 typedef l3_pgentry_t guest_l3e_t;
122 #if GUEST_PAGING_LEVELS >= 4
123 typedef l4_pgentry_t guest_l4e_t;
124 #endif
125 typedef intpte_t guest_intpte_t;
127 #define PRI_gpte "016"PRIx64
129 static inline paddr_t guest_l1e_get_paddr(guest_l1e_t gl1e)
130 { return l1e_get_paddr(gl1e); }
131 static inline paddr_t guest_l2e_get_paddr(guest_l2e_t gl2e)
132 { return l2e_get_paddr(gl2e); }
133 static inline paddr_t guest_l3e_get_paddr(guest_l3e_t gl3e)
134 { return l3e_get_paddr(gl3e); }
135 #if GUEST_PAGING_LEVELS >= 4
136 static inline paddr_t guest_l4e_get_paddr(guest_l4e_t gl4e)
137 { return l4e_get_paddr(gl4e); }
138 #endif
140 static inline gfn_t guest_l1e_get_gfn(guest_l1e_t gl1e)
141 { return _gfn(l1e_get_paddr(gl1e) >> PAGE_SHIFT); }
142 static inline gfn_t guest_l2e_get_gfn(guest_l2e_t gl2e)
143 { return _gfn(l2e_get_paddr(gl2e) >> PAGE_SHIFT); }
144 static inline gfn_t guest_l3e_get_gfn(guest_l3e_t gl3e)
145 { return _gfn(l3e_get_paddr(gl3e) >> PAGE_SHIFT); }
146 #if GUEST_PAGING_LEVELS >= 4
147 static inline gfn_t guest_l4e_get_gfn(guest_l4e_t gl4e)
148 { return _gfn(l4e_get_paddr(gl4e) >> PAGE_SHIFT); }
149 #endif
151 static inline u32 guest_l1e_get_flags(guest_l1e_t gl1e)
152 { return l1e_get_flags(gl1e); }
153 static inline u32 guest_l2e_get_flags(guest_l2e_t gl2e)
154 { return l2e_get_flags(gl2e); }
155 static inline u32 guest_l3e_get_flags(guest_l3e_t gl3e)
156 { return l3e_get_flags(gl3e); }
157 #if GUEST_PAGING_LEVELS >= 4
158 static inline u32 guest_l4e_get_flags(guest_l4e_t gl4e)
159 { return l4e_get_flags(gl4e); }
160 #endif
162 static inline guest_l1e_t guest_l1e_from_gfn(gfn_t gfn, u32 flags)
163 { return l1e_from_pfn(gfn_x(gfn), flags); }
164 static inline guest_l2e_t guest_l2e_from_gfn(gfn_t gfn, u32 flags)
165 { return l2e_from_pfn(gfn_x(gfn), flags); }
166 static inline guest_l3e_t guest_l3e_from_gfn(gfn_t gfn, u32 flags)
167 { return l3e_from_pfn(gfn_x(gfn), flags); }
168 #if GUEST_PAGING_LEVELS >= 4
169 static inline guest_l4e_t guest_l4e_from_gfn(gfn_t gfn, u32 flags)
170 { return l4e_from_pfn(gfn_x(gfn), flags); }
171 #endif
173 #define guest_l1_table_offset(a) l1_table_offset(a)
174 #define guest_l2_table_offset(a) l2_table_offset(a)
175 #define guest_l3_table_offset(a) l3_table_offset(a)
176 #define guest_l4_table_offset(a) l4_table_offset(a)
178 #endif /* GUEST_PAGING_LEVELS != 2 */
181 /* Which pagetable features are supported on this vcpu? */
183 static inline int
184 guest_supports_superpages(struct vcpu *v)
185 {
186 /* The _PAGE_PSE bit must be honoured in HVM guests, whenever
187 * CR4.PSE is set or the guest is in PAE or long mode.
188 * It's also used in the dummy PT for vcpus with CR4.PG cleared. */
189 return (!is_hvm_vcpu(v)
190 ? opt_allow_superpage
191 : (GUEST_PAGING_LEVELS != 2
192 || !hvm_paging_enabled(v)
193 || (v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PSE)));
194 }
196 static inline int
197 guest_supports_nx(struct vcpu *v)
198 {
199 if ( GUEST_PAGING_LEVELS == 2 || !cpu_has_nx )
200 return 0;
201 if ( !is_hvm_vcpu(v) )
202 return cpu_has_nx;
203 return hvm_nx_enabled(v);
204 }
207 /* Some bits are invalid in any pagetable entry. */
208 #if GUEST_PAGING_LEVELS == 2
209 #define _PAGE_INVALID_BITS (0)
210 #elif GUEST_PAGING_LEVELS == 3
211 #define _PAGE_INVALID_BITS \
212 get_pte_flags(((1ull<<63) - 1) & ~((1ull<<paddr_bits) - 1))
213 #else /* GUEST_PAGING_LEVELS == 4 */
214 #define _PAGE_INVALID_BITS \
215 get_pte_flags(((1ull<<52) - 1) & ~((1ull<<paddr_bits) - 1))
216 #endif
219 /* Type used for recording a walk through guest pagetables. It is
220 * filled in by the pagetable walk function, and also used as a cache
221 * for later walks. When we encounter a superpage l2e, we fabricate an
222 * l1e for propagation to the shadow (for splintering guest superpages
223 * into many shadow l1 entries). */
224 typedef struct guest_pagetable_walk walk_t;
225 struct guest_pagetable_walk
226 {
227 unsigned long va; /* Address we were looking for */
228 #if GUEST_PAGING_LEVELS >= 3
229 #if GUEST_PAGING_LEVELS >= 4
230 guest_l4e_t l4e; /* Guest's level 4 entry */
231 #endif
232 guest_l3e_t l3e; /* Guest's level 3 entry */
233 #endif
234 guest_l2e_t l2e; /* Guest's level 2 entry */
235 guest_l1e_t l1e; /* Guest's level 1 entry (or fabrication) */
236 #if GUEST_PAGING_LEVELS >= 4
237 mfn_t l4mfn; /* MFN that the level 4 entry was in */
238 mfn_t l3mfn; /* MFN that the level 3 entry was in */
239 #endif
240 mfn_t l2mfn; /* MFN that the level 2 entry was in */
241 mfn_t l1mfn; /* MFN that the level 1 entry was in */
242 };
244 /* Given a walk_t, translate the gw->va into the guest's notion of the
245 * corresponding frame number. */
246 static inline gfn_t
247 guest_walk_to_gfn(walk_t *gw)
248 {
249 if ( !(guest_l1e_get_flags(gw->l1e) & _PAGE_PRESENT) )
250 return _gfn(INVALID_GFN);
251 return guest_l1e_get_gfn(gw->l1e);
252 }
254 /* Given a walk_t, translate the gw->va into the guest's notion of the
255 * corresponding physical address. */
256 static inline paddr_t
257 guest_walk_to_gpa(walk_t *gw)
258 {
259 if ( !(guest_l1e_get_flags(gw->l1e) & _PAGE_PRESENT) )
260 return 0;
261 return guest_l1e_get_paddr(gw->l1e) + (gw->va & ~PAGE_MASK);
262 }
264 /* Walk the guest pagetables, after the manner of a hardware walker.
265 *
266 * Inputs: a vcpu, a virtual address, a walk_t to fill, a
267 * pointer to a pagefault code, the MFN of the guest's
268 * top-level pagetable, and a mapping of the
269 * guest's top-level pagetable.
270 *
271 * We walk the vcpu's guest pagetables, filling the walk_t with what we
272 * see and adding any Accessed and Dirty bits that are needed in the
273 * guest entries. Using the pagefault code, we check the permissions as
274 * we go. For the purposes of reading pagetables we treat all non-RAM
275 * memory as contining zeroes.
276 *
277 * Returns 0 for success, or the set of permission bits that we failed on
278 * if the walk did not complete. */
280 /* Macro-fu so you can call guest_walk_tables() and get the right one. */
281 #define GPT_RENAME2(_n, _l) _n ## _ ## _l ## _levels
282 #define GPT_RENAME(_n, _l) GPT_RENAME2(_n, _l)
283 #define guest_walk_tables GPT_RENAME(guest_walk_tables, GUEST_PAGING_LEVELS)
285 extern uint32_t
286 guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, unsigned long va,
287 walk_t *gw, uint32_t pfec, mfn_t top_mfn, void *top_map);
289 /* Pretty-print the contents of a guest-walk */
290 static inline void print_gw(walk_t *gw)
291 {
292 gdprintk(XENLOG_INFO, "GUEST WALK TO %#lx:\n", gw->va);
293 #if GUEST_PAGING_LEVELS >= 3 /* PAE or 64... */
294 #if GUEST_PAGING_LEVELS >= 4 /* 64-bit only... */
295 gdprintk(XENLOG_INFO, " l4mfn=%" PRI_mfn "\n", mfn_x(gw->l4mfn));
296 gdprintk(XENLOG_INFO, " l4e=%" PRI_gpte "\n", gw->l4e.l4);
297 gdprintk(XENLOG_INFO, " l3mfn=%" PRI_mfn "\n", mfn_x(gw->l3mfn));
298 #endif /* PAE or 64... */
299 gdprintk(XENLOG_INFO, " l3e=%" PRI_gpte "\n", gw->l3e.l3);
300 #endif /* All levels... */
301 gdprintk(XENLOG_INFO, " l2mfn=%" PRI_mfn "\n", mfn_x(gw->l2mfn));
302 gdprintk(XENLOG_INFO, " l2e=%" PRI_gpte "\n", gw->l2e.l2);
303 gdprintk(XENLOG_INFO, " l1mfn=%" PRI_mfn "\n", mfn_x(gw->l1mfn));
304 gdprintk(XENLOG_INFO, " l1e=%" PRI_gpte "\n", gw->l1e.l1);
305 }
307 #endif /* _XEN_ASM_GUEST_PT_H */