debuggers.hg

view xen/arch/x86/x86_64/mm.c @ 19964:3952eaeb70b0

Introduce and use a per-CPU read-mostly sub-section

Since mixing data that only gets setup once and then (perhaps
frequently) gets read by remote CPUs with data that the local CPU may
modify (again, perhaps frequently) still causes undesirable cache
protocol related bus traffic, separate the former class of objects
from the latter.

These objects converted here are just picked based on their write-once
(or write-very-rarely) properties; perhaps some more adjustments may
be desirable subsequently. The primary users of the new sub-section
will result from the next patch.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jul 13 11:32:41 2009 +0100 (2009-07-13)
parents d6c1d7992f43
children 62b7fc245d1f
line source
1 /******************************************************************************
2 * arch/x86/x86_64/mm.c
3 *
4 * Modifications to Linux original are copyright (c) 2004, K A Fraser tr This
5 * program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc., 59
17 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
20 #include <xen/config.h>
21 #include <xen/lib.h>
22 #include <xen/init.h>
23 #include <xen/mm.h>
24 #include <xen/sched.h>
25 #include <xen/numa.h>
26 #include <xen/guest_access.h>
27 #include <asm/current.h>
28 #include <asm/asm_defns.h>
29 #include <asm/page.h>
30 #include <asm/flushtlb.h>
31 #include <asm/fixmap.h>
32 #include <asm/hypercall.h>
33 #include <asm/msr.h>
34 #include <public/memory.h>
36 #ifdef CONFIG_COMPAT
37 unsigned int m2p_compat_vstart = __HYPERVISOR_COMPAT_VIRT_START;
38 #endif
40 DEFINE_PER_CPU_READ_MOSTLY(void *, compat_arg_xlat);
42 /* Top-level master (and idle-domain) page directory. */
43 l4_pgentry_t __attribute__ ((__section__ (".bss.page_aligned")))
44 idle_pg_table[L4_PAGETABLE_ENTRIES];
46 /* Enough page directories to map bottom 4GB of the memory map. */
47 l3_pgentry_t __attribute__ ((__section__ (".bss.page_aligned")))
48 l3_identmap[L3_PAGETABLE_ENTRIES];
49 l2_pgentry_t __attribute__ ((__section__ (".bss.page_aligned")))
50 l2_identmap[4*L2_PAGETABLE_ENTRIES];
52 /* Enough page directories to map the Xen text and static data. */
53 l3_pgentry_t __attribute__ ((__section__ (".bss.page_aligned")))
54 l3_xenmap[L3_PAGETABLE_ENTRIES];
55 l2_pgentry_t __attribute__ ((__section__ (".bss.page_aligned")))
56 l2_xenmap[L2_PAGETABLE_ENTRIES];
58 void *alloc_xen_pagetable(void)
59 {
60 extern int early_boot;
61 unsigned long mfn;
63 if ( !early_boot )
64 {
65 struct page_info *pg = alloc_domheap_page(NULL, 0);
66 BUG_ON(pg == NULL);
67 return page_to_virt(pg);
68 }
70 mfn = alloc_boot_pages(1, 1);
71 return mfn_to_virt(mfn);
72 }
74 l3_pgentry_t *virt_to_xen_l3e(unsigned long v)
75 {
76 l4_pgentry_t *pl4e;
78 pl4e = &idle_pg_table[l4_table_offset(v)];
79 if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) )
80 {
81 l3_pgentry_t *pl3e = alloc_xen_pagetable();
82 clear_page(pl3e);
83 l4e_write(pl4e, l4e_from_paddr(__pa(pl3e), __PAGE_HYPERVISOR));
84 }
86 return l4e_to_l3e(*pl4e) + l3_table_offset(v);
87 }
89 l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
90 {
91 l3_pgentry_t *pl3e;
93 pl3e = virt_to_xen_l3e(v);
94 if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
95 {
96 l2_pgentry_t *pl2e = alloc_xen_pagetable();
97 clear_page(pl2e);
98 l3e_write(pl3e, l3e_from_paddr(__pa(pl2e), __PAGE_HYPERVISOR));
99 }
101 BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE);
102 return l3e_to_l2e(*pl3e) + l2_table_offset(v);
103 }
105 void *do_page_walk(struct vcpu *v, unsigned long addr)
106 {
107 unsigned long mfn = pagetable_get_pfn(v->arch.guest_table);
108 l4_pgentry_t l4e, *l4t;
109 l3_pgentry_t l3e, *l3t;
110 l2_pgentry_t l2e, *l2t;
111 l1_pgentry_t l1e, *l1t;
113 if ( is_hvm_vcpu(v) )
114 return NULL;
116 l4t = mfn_to_virt(mfn);
117 l4e = l4t[l4_table_offset(addr)];
118 mfn = l4e_get_pfn(l4e);
119 if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )
120 return NULL;
122 l3t = mfn_to_virt(mfn);
123 l3e = l3t[l3_table_offset(addr)];
124 mfn = l3e_get_pfn(l3e);
125 if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) || !mfn_valid(mfn) )
126 if ( (l3e_get_flags(l3e) & _PAGE_PSE) )
127 return mfn_to_virt(mfn) + (addr & ((1UL << L3_PAGETABLE_SHIFT) - 1));
129 l2t = mfn_to_virt(mfn);
130 l2e = l2t[l2_table_offset(addr)];
131 mfn = l2e_get_pfn(l2e);
132 if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) || !mfn_valid(mfn) )
133 return NULL;
134 if ( (l2e_get_flags(l2e) & _PAGE_PSE) )
135 return mfn_to_virt(mfn) + (addr & ((1UL << L2_PAGETABLE_SHIFT) - 1));
137 l1t = mfn_to_virt(mfn);
138 l1e = l1t[l1_table_offset(addr)];
139 mfn = l1e_get_pfn(l1e);
140 if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) || !mfn_valid(mfn) )
141 return NULL;
143 return mfn_to_virt(mfn) + (addr & ~PAGE_MASK);
144 }
146 void __init paging_init(void)
147 {
148 unsigned long i, mpt_size, va;
149 unsigned int memflags;
150 l3_pgentry_t *l3_ro_mpt;
151 l2_pgentry_t *l2_ro_mpt = NULL;
152 struct page_info *l1_pg, *l2_pg, *l3_pg;
154 /* Create user-accessible L2 directory to map the MPT for guests. */
155 if ( (l3_pg = alloc_domheap_page(NULL, 0)) == NULL )
156 goto nomem;
157 l3_ro_mpt = page_to_virt(l3_pg);
158 clear_page(l3_ro_mpt);
159 l4e_write(&idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)],
160 l4e_from_page(l3_pg, __PAGE_HYPERVISOR | _PAGE_USER));
162 /*
163 * Allocate and map the machine-to-phys table.
164 * This also ensures L3 is present for fixmaps.
165 */
166 mpt_size = (max_page * BYTES_PER_LONG) + (1UL << L2_PAGETABLE_SHIFT) - 1;
167 mpt_size &= ~((1UL << L2_PAGETABLE_SHIFT) - 1UL);
168 for ( i = 0; i < (mpt_size >> L2_PAGETABLE_SHIFT); i++ )
169 {
170 BUILD_BUG_ON(RO_MPT_VIRT_START & ((1UL << L3_PAGETABLE_SHIFT) - 1));
171 va = RO_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT);
172 memflags = MEMF_node(phys_to_nid(i <<
173 (L2_PAGETABLE_SHIFT - 3 + PAGE_SHIFT)));
175 if ( cpu_has_page1gb &&
176 !((unsigned long)l2_ro_mpt & ~PAGE_MASK) &&
177 (mpt_size >> L3_PAGETABLE_SHIFT) > (i >> PAGETABLE_ORDER) &&
178 (l1_pg = alloc_domheap_pages(NULL, 2 * PAGETABLE_ORDER,
179 memflags)) != NULL )
180 {
181 map_pages_to_xen(
182 RDWR_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT),
183 page_to_mfn(l1_pg),
184 1UL << (2 * PAGETABLE_ORDER),
185 PAGE_HYPERVISOR);
186 memset((void *)(RDWR_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT)),
187 0x77, 1UL << L3_PAGETABLE_SHIFT);
189 ASSERT(!l2_table_offset(va));
190 /* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */
191 l3e_write(&l3_ro_mpt[l3_table_offset(va)],
192 l3e_from_page(l1_pg,
193 /*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT));
194 i += (1UL << PAGETABLE_ORDER) - 1;
195 continue;
196 }
198 if ( (l1_pg = alloc_domheap_pages(NULL, PAGETABLE_ORDER,
199 memflags)) == NULL )
200 goto nomem;
201 map_pages_to_xen(
202 RDWR_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT),
203 page_to_mfn(l1_pg),
204 1UL << PAGETABLE_ORDER,
205 PAGE_HYPERVISOR);
206 memset((void *)(RDWR_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT)), 0x55,
207 1UL << L2_PAGETABLE_SHIFT);
208 if ( !((unsigned long)l2_ro_mpt & ~PAGE_MASK) )
209 {
210 if ( (l2_pg = alloc_domheap_page(NULL, memflags)) == NULL )
211 goto nomem;
212 l2_ro_mpt = page_to_virt(l2_pg);
213 clear_page(l2_ro_mpt);
214 l3e_write(&l3_ro_mpt[l3_table_offset(va)],
215 l3e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER));
216 ASSERT(!l2_table_offset(va));
217 }
218 /* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */
219 l2e_write(l2_ro_mpt, l2e_from_page(
220 l1_pg, /*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT));
221 l2_ro_mpt++;
222 }
224 /* Create user-accessible L2 directory to map the MPT for compat guests. */
225 BUILD_BUG_ON(l4_table_offset(RDWR_MPT_VIRT_START) !=
226 l4_table_offset(HIRO_COMPAT_MPT_VIRT_START));
227 l3_ro_mpt = l4e_to_l3e(idle_pg_table[l4_table_offset(
228 HIRO_COMPAT_MPT_VIRT_START)]);
229 if ( (l2_pg = alloc_domheap_page(NULL, 0)) == NULL )
230 goto nomem;
231 compat_idle_pg_table_l2 = l2_ro_mpt = page_to_virt(l2_pg);
232 clear_page(l2_ro_mpt);
233 l3e_write(&l3_ro_mpt[l3_table_offset(HIRO_COMPAT_MPT_VIRT_START)],
234 l3e_from_page(l2_pg, __PAGE_HYPERVISOR));
235 l2_ro_mpt += l2_table_offset(HIRO_COMPAT_MPT_VIRT_START);
236 /* Allocate and map the compatibility mode machine-to-phys table. */
237 mpt_size = (mpt_size >> 1) + (1UL << (L2_PAGETABLE_SHIFT - 1));
238 if ( mpt_size > RDWR_COMPAT_MPT_VIRT_END - RDWR_COMPAT_MPT_VIRT_START )
239 mpt_size = RDWR_COMPAT_MPT_VIRT_END - RDWR_COMPAT_MPT_VIRT_START;
240 mpt_size &= ~((1UL << L2_PAGETABLE_SHIFT) - 1UL);
241 if ( (m2p_compat_vstart + mpt_size) < MACH2PHYS_COMPAT_VIRT_END )
242 m2p_compat_vstart = MACH2PHYS_COMPAT_VIRT_END - mpt_size;
243 for ( i = 0; i < (mpt_size >> L2_PAGETABLE_SHIFT); i++ )
244 {
245 memflags = MEMF_node(phys_to_nid(i <<
246 (L2_PAGETABLE_SHIFT - 2 + PAGE_SHIFT)));
247 if ( (l1_pg = alloc_domheap_pages(NULL, PAGETABLE_ORDER,
248 memflags)) == NULL )
249 goto nomem;
250 map_pages_to_xen(
251 RDWR_COMPAT_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT),
252 page_to_mfn(l1_pg),
253 1UL << PAGETABLE_ORDER,
254 PAGE_HYPERVISOR);
255 memset((void *)(RDWR_COMPAT_MPT_VIRT_START +
256 (i << L2_PAGETABLE_SHIFT)),
257 0x55,
258 1UL << L2_PAGETABLE_SHIFT);
259 /* NB. Cannot be GLOBAL as the ptes get copied into per-VM space. */
260 l2e_write(l2_ro_mpt, l2e_from_page(l1_pg, _PAGE_PSE|_PAGE_PRESENT));
261 l2_ro_mpt++;
262 }
264 /* Set up linear page table mapping. */
265 l4e_write(&idle_pg_table[l4_table_offset(LINEAR_PT_VIRT_START)],
266 l4e_from_paddr(__pa(idle_pg_table), __PAGE_HYPERVISOR));
267 return;
269 nomem:
270 panic("Not enough memory for m2p table\n");
271 }
273 void __init setup_idle_pagetable(void)
274 {
275 /* Install per-domain mappings for idle domain. */
276 l4e_write(&idle_pg_table[l4_table_offset(PERDOMAIN_VIRT_START)],
277 l4e_from_page(
278 virt_to_page(idle_vcpu[0]->domain->arch.mm_perdomain_l3),
279 __PAGE_HYPERVISOR));
280 }
282 void __init zap_low_mappings(void)
283 {
284 BUG_ON(num_online_cpus() != 1);
286 /* Remove aliased mapping of first 1:1 PML4 entry. */
287 l4e_write(&idle_pg_table[0], l4e_empty());
288 flush_local(FLUSH_TLB_GLOBAL);
290 /* Replace with mapping of the boot trampoline only. */
291 map_pages_to_xen(BOOT_TRAMPOLINE, BOOT_TRAMPOLINE >> PAGE_SHIFT,
292 0x10, __PAGE_HYPERVISOR);
293 }
295 int __cpuinit setup_compat_arg_xlat(unsigned int cpu, int node)
296 {
297 unsigned int order = get_order_from_bytes(COMPAT_ARG_XLAT_SIZE);
298 unsigned long sz = PAGE_SIZE << order;
299 unsigned int memflags = node != NUMA_NO_NODE ? MEMF_node(node) : 0;
300 struct page_info *pg;
302 pg = alloc_domheap_pages(NULL, order, memflags);
303 if ( !pg )
304 return -ENOMEM;
306 for ( ; (sz -= PAGE_SIZE) >= COMPAT_ARG_XLAT_SIZE; ++pg )
307 free_domheap_page(pg);
309 per_cpu(compat_arg_xlat, cpu) = page_to_virt(pg);
311 return 0;
312 }
314 void __init subarch_init_memory(void)
315 {
316 unsigned long i, n, v, m2p_start_mfn;
317 l3_pgentry_t l3e;
318 l2_pgentry_t l2e;
320 BUILD_BUG_ON(RDWR_MPT_VIRT_START & ((1UL << L3_PAGETABLE_SHIFT) - 1));
321 BUILD_BUG_ON(RDWR_MPT_VIRT_END & ((1UL << L3_PAGETABLE_SHIFT) - 1));
322 /* M2P table is mappable read-only by privileged domains. */
323 for ( v = RDWR_MPT_VIRT_START;
324 v != RDWR_MPT_VIRT_END;
325 v += n << PAGE_SHIFT )
326 {
327 n = L2_PAGETABLE_ENTRIES * L1_PAGETABLE_ENTRIES;
328 l3e = l4e_to_l3e(idle_pg_table[l4_table_offset(v)])[
329 l3_table_offset(v)];
330 if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
331 continue;
332 if ( !(l3e_get_flags(l3e) & _PAGE_PSE) )
333 {
334 n = L1_PAGETABLE_ENTRIES;
335 l2e = l3e_to_l2e(l3e)[l2_table_offset(v)];
336 if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
337 continue;
338 m2p_start_mfn = l2e_get_pfn(l2e);
339 }
340 else
341 {
342 m2p_start_mfn = l3e_get_pfn(l3e);
343 }
345 for ( i = 0; i < n; i++ )
346 {
347 struct page_info *page = mfn_to_page(m2p_start_mfn + i);
348 share_xen_page_with_privileged_guests(page, XENSHARE_readonly);
349 }
350 }
352 for ( v = RDWR_COMPAT_MPT_VIRT_START;
353 v != RDWR_COMPAT_MPT_VIRT_END;
354 v += 1 << L2_PAGETABLE_SHIFT )
355 {
356 l3e = l4e_to_l3e(idle_pg_table[l4_table_offset(v)])[
357 l3_table_offset(v)];
358 if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
359 continue;
360 l2e = l3e_to_l2e(l3e)[l2_table_offset(v)];
361 if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
362 continue;
363 m2p_start_mfn = l2e_get_pfn(l2e);
365 for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
366 {
367 struct page_info *page = mfn_to_page(m2p_start_mfn + i);
368 share_xen_page_with_privileged_guests(page, XENSHARE_readonly);
369 }
370 }
372 if ( setup_compat_arg_xlat(smp_processor_id(),
373 apicid_to_node[boot_cpu_physical_apicid]) )
374 panic("Could not setup argument translation area");
375 }
377 long subarch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
378 {
379 struct xen_machphys_mfn_list xmml;
380 l3_pgentry_t l3e;
381 l2_pgentry_t l2e;
382 unsigned long v;
383 xen_pfn_t mfn;
384 unsigned int i;
385 long rc = 0;
387 switch ( op )
388 {
389 case XENMEM_machphys_mfn_list:
390 if ( copy_from_guest(&xmml, arg, 1) )
391 return -EFAULT;
393 BUILD_BUG_ON(RDWR_MPT_VIRT_START & ((1UL << L3_PAGETABLE_SHIFT) - 1));
394 BUILD_BUG_ON(RDWR_MPT_VIRT_END & ((1UL << L3_PAGETABLE_SHIFT) - 1));
395 for ( i = 0, v = RDWR_MPT_VIRT_START;
396 (i != xmml.max_extents) && (v != RDWR_MPT_VIRT_END);
397 i++, v += 1UL << L2_PAGETABLE_SHIFT )
398 {
399 l3e = l4e_to_l3e(idle_pg_table[l4_table_offset(v)])[
400 l3_table_offset(v)];
401 if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
402 break;
403 if ( !(l3e_get_flags(l3e) & _PAGE_PSE) )
404 {
405 l2e = l3e_to_l2e(l3e)[l2_table_offset(v)];
406 if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
407 break;
408 mfn = l2e_get_pfn(l2e);
409 }
410 else
411 {
412 mfn = l3e_get_pfn(l3e)
413 + (l2_table_offset(v) << PAGETABLE_ORDER);
414 }
415 ASSERT(!l1_table_offset(v));
416 if ( copy_to_guest_offset(xmml.extent_start, i, &mfn, 1) )
417 return -EFAULT;
418 }
420 xmml.nr_extents = i;
421 if ( copy_to_guest(arg, &xmml, 1) )
422 return -EFAULT;
424 break;
426 default:
427 rc = -ENOSYS;
428 break;
429 }
431 return rc;
432 }
434 long do_stack_switch(unsigned long ss, unsigned long esp)
435 {
436 fixup_guest_stack_selector(current->domain, ss);
437 current->arch.guest_context.kernel_ss = ss;
438 current->arch.guest_context.kernel_sp = esp;
439 return 0;
440 }
442 long do_set_segment_base(unsigned int which, unsigned long base)
443 {
444 struct vcpu *v = current;
445 long ret = 0;
447 switch ( which )
448 {
449 case SEGBASE_FS:
450 if ( wrmsr_safe(MSR_FS_BASE, base, base>>32) )
451 ret = -EFAULT;
452 else
453 v->arch.guest_context.fs_base = base;
454 break;
456 case SEGBASE_GS_USER:
457 if ( wrmsr_safe(MSR_SHADOW_GS_BASE, base, base>>32) )
458 ret = -EFAULT;
459 else
460 v->arch.guest_context.gs_base_user = base;
461 break;
463 case SEGBASE_GS_KERNEL:
464 if ( wrmsr_safe(MSR_GS_BASE, base, base>>32) )
465 ret = -EFAULT;
466 else
467 v->arch.guest_context.gs_base_kernel = base;
468 break;
470 case SEGBASE_GS_USER_SEL:
471 __asm__ __volatile__ (
472 " swapgs \n"
473 "1: movl %k0,%%gs \n"
474 " "safe_swapgs" \n"
475 ".section .fixup,\"ax\" \n"
476 "2: xorl %k0,%k0 \n"
477 " jmp 1b \n"
478 ".previous \n"
479 ".section __ex_table,\"a\"\n"
480 " .align 8 \n"
481 " .quad 1b,2b \n"
482 ".previous "
483 : : "r" (base&0xffff) );
484 break;
486 default:
487 ret = -EINVAL;
488 break;
489 }
491 return ret;
492 }
495 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
496 int check_descriptor(const struct domain *dom, struct desc_struct *d)
497 {
498 u32 a = d->a, b = d->b;
499 u16 cs;
500 unsigned int dpl;
502 /* A not-present descriptor will always fault, so is safe. */
503 if ( !(b & _SEGMENT_P) )
504 goto good;
506 /* Check and fix up the DPL. */
507 dpl = (b >> 13) & 3;
508 __fixup_guest_selector(dom, dpl);
509 b = (b & ~_SEGMENT_DPL) | (dpl << 13);
511 /* All code and data segments are okay. No base/limit checking. */
512 if ( (b & _SEGMENT_S) )
513 {
514 if ( is_pv_32bit_domain(dom) )
515 {
516 unsigned long base, limit;
518 if ( b & _SEGMENT_L )
519 goto bad;
521 /*
522 * Older PAE Linux guests use segments which are limited to
523 * 0xf6800000. Extend these to allow access to the larger read-only
524 * M2P table available in 32on64 mode.
525 */
526 base = (b & (0xff << 24)) | ((b & 0xff) << 16) | (a >> 16);
528 limit = (b & 0xf0000) | (a & 0xffff);
529 limit++; /* We add one because limit is inclusive. */
531 if ( (b & _SEGMENT_G) )
532 limit <<= 12;
534 if ( (base == 0) && (limit > HYPERVISOR_COMPAT_VIRT_START(dom)) )
535 {
536 a |= 0x0000ffff;
537 b |= 0x000f0000;
538 }
539 }
541 goto good;
542 }
544 /* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
545 if ( (b & _SEGMENT_TYPE) == 0x000 )
546 goto good;
548 /* Everything but a call gate is discarded here. */
549 if ( (b & _SEGMENT_TYPE) != 0xc00 )
550 goto bad;
552 /* Validate the target code selector. */
553 cs = a >> 16;
554 if ( !guest_gate_selector_okay(dom, cs) )
555 goto bad;
556 /*
557 * Force DPL to zero, causing a GP fault with its error code indicating
558 * the gate in use, allowing emulation. This is necessary because with
559 * native guests (kernel in ring 3) call gates cannot be used directly
560 * to transition from user to kernel mode (and whether a gate is used
561 * to enter the kernel can only be determined when the gate is being
562 * used), and with compat guests call gates cannot be used at all as
563 * there are only 64-bit ones.
564 * Store the original DPL in the selector's RPL field.
565 */
566 b &= ~_SEGMENT_DPL;
567 cs = (cs & ~3) | dpl;
568 a = (a & 0xffffU) | (cs << 16);
570 /* Reserved bits must be zero. */
571 if ( b & (is_pv_32bit_domain(dom) ? 0xe0 : 0xff) )
572 goto bad;
574 good:
575 d->a = a;
576 d->b = b;
577 return 1;
578 bad:
579 return 0;
580 }
582 void domain_set_alloc_bitsize(struct domain *d)
583 {
584 if ( !is_pv_32on64_domain(d) ||
585 (MACH2PHYS_COMPAT_NR_ENTRIES(d) >= max_page) ||
586 d->arch.physaddr_bitsize > 0 )
587 return;
588 d->arch.physaddr_bitsize =
589 /* 2^n entries can be contained in guest's p2m mapping space */
590 fls(MACH2PHYS_COMPAT_NR_ENTRIES(d)) - 1
591 /* 2^n pages -> 2^(n+PAGE_SHIFT) bits */
592 + PAGE_SHIFT;
593 }
595 unsigned int domain_clamp_alloc_bitsize(struct domain *d, unsigned int bits)
596 {
597 if ( (d == NULL) || (d->arch.physaddr_bitsize == 0) )
598 return bits;
599 return min(d->arch.physaddr_bitsize, bits);
600 }
602 #include "compat/mm.c"
604 /*
605 * Local variables:
606 * mode: C
607 * c-set-style: "BSD"
608 * c-basic-offset: 4
609 * tab-width: 4
610 * indent-tabs-mode: nil
611 * End:
612 */