debuggers.hg

view xen/arch/x86/x86_32/mm.c @ 3491:2c56c6b39a48

bitkeeper revision 1.1159.212.18 (41ebe1caQQ_SlJestrvsT95t1oER-Q)

Merge arcadians.cl.cam.ac.uk:/auto/groups/xeno/BK/xen-unstable.bk
into arcadians.cl.cam.ac.uk:/auto/groups/xeno/users/cl349/BK/xen-unstable.bk
author cl349@arcadians.cl.cam.ac.uk
date Mon Jan 17 16:03:22 2005 +0000 (2005-01-17)
parents d1e0d9a8fde0 b96857892a2c
children cee684f223ee fec8b1778268
line source
1 /******************************************************************************
2 * arch/x86/x86_32/mm.c
3 *
4 * Modifications to Linux original are copyright (c) 2004, K A Fraser
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 #include <xen/config.h>
22 #include <xen/lib.h>
23 #include <xen/init.h>
24 #include <xen/mm.h>
25 #include <asm/page.h>
26 #include <asm/flushtlb.h>
27 #include <asm/fixmap.h>
28 #include <asm/domain_page.h>
30 unsigned long m2p_start_mfn;
32 static inline void set_pte_phys(unsigned long vaddr,
33 l1_pgentry_t entry)
34 {
35 l2_pgentry_t *l2ent;
36 l1_pgentry_t *l1ent;
38 l2ent = &idle_pg_table[l2_table_offset(vaddr)];
39 l1ent = l2_pgentry_to_l1(*l2ent) + l1_table_offset(vaddr);
40 *l1ent = entry;
42 /* It's enough to flush this one mapping. */
43 __flush_tlb_one(vaddr);
44 }
47 void __set_fixmap(enum fixed_addresses idx,
48 l1_pgentry_t entry)
49 {
50 unsigned long address = fix_to_virt(idx);
52 if ( likely(idx < __end_of_fixed_addresses) )
53 set_pte_phys(address, entry);
54 else
55 printk("Invalid __set_fixmap\n");
56 }
59 void __init paging_init(void)
60 {
61 void *ioremap_pt;
62 unsigned long v, l2e;
63 struct pfn_info *pg;
65 /* Allocate and map the machine-to-phys table. */
66 if ( (pg = alloc_domheap_pages(NULL, 10)) == NULL )
67 panic("Not enough memory to bootstrap Xen.\n");
68 m2p_start_mfn = page_to_pfn(pg);
69 idle_pg_table[RDWR_MPT_VIRT_START >> L2_PAGETABLE_SHIFT] =
70 mk_l2_pgentry(page_to_phys(pg) | __PAGE_HYPERVISOR | _PAGE_PSE);
72 /* Xen 4MB mappings can all be GLOBAL. */
73 if ( cpu_has_pge )
74 {
75 for ( v = HYPERVISOR_VIRT_START; v; v += (1 << L2_PAGETABLE_SHIFT) )
76 {
77 l2e = l2_pgentry_val(idle_pg_table[v >> L2_PAGETABLE_SHIFT]);
78 if ( l2e & _PAGE_PSE )
79 l2e |= _PAGE_GLOBAL;
80 idle_pg_table[v >> L2_PAGETABLE_SHIFT] = mk_l2_pgentry(l2e);
81 }
82 }
84 /* Create page table for ioremap(). */
85 ioremap_pt = (void *)alloc_xenheap_page();
86 clear_page(ioremap_pt);
87 idle_pg_table[IOREMAP_VIRT_START >> L2_PAGETABLE_SHIFT] =
88 mk_l2_pgentry(__pa(ioremap_pt) | __PAGE_HYPERVISOR);
90 /* Create read-only mapping of MPT for guest-OS use. */
91 idle_pg_table[RO_MPT_VIRT_START >> L2_PAGETABLE_SHIFT] =
92 mk_l2_pgentry(l2_pgentry_val(
93 idle_pg_table[RDWR_MPT_VIRT_START >> L2_PAGETABLE_SHIFT]) &
94 ~_PAGE_RW);
96 /* Set up mapping cache for domain pages. */
97 mapcache = (unsigned long *)alloc_xenheap_page();
98 clear_page(mapcache);
99 idle_pg_table[MAPCACHE_VIRT_START >> L2_PAGETABLE_SHIFT] =
100 mk_l2_pgentry(__pa(mapcache) | __PAGE_HYPERVISOR);
102 /* Set up linear page table mapping. */
103 idle_pg_table[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
104 mk_l2_pgentry(__pa(idle_pg_table) | __PAGE_HYPERVISOR);
105 }
107 void __init zap_low_mappings(void)
108 {
109 int i;
110 for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
111 idle_pg_table[i] = mk_l2_pgentry(0);
112 flush_tlb_all_pge();
113 }
116 /*
117 * Allows shooting down of borrowed page-table use on specific CPUs.
118 * Specifically, we borrow page tables when running the idle domain.
119 */
120 static void __synchronise_pagetables(void *mask)
121 {
122 struct exec_domain *ed = current;
123 if ( ((unsigned long)mask & (1 << ed->processor)) &&
124 is_idle_task(ed->domain) )
125 write_ptbase(&ed->mm);
126 }
127 void synchronise_pagetables(unsigned long cpu_mask)
128 {
129 __synchronise_pagetables((void *)cpu_mask);
130 smp_call_function(__synchronise_pagetables, (void *)cpu_mask, 1, 1);
131 }
133 long do_stack_switch(unsigned long ss, unsigned long esp)
134 {
135 int nr = smp_processor_id();
136 struct tss_struct *t = &init_tss[nr];
138 /* We need to do this check as we load and use SS on guest's behalf. */
139 if ( (ss & 3) == 0 )
140 return -EPERM;
142 current->thread.guestos_ss = ss;
143 current->thread.guestos_sp = esp;
144 t->ss1 = ss;
145 t->esp1 = esp;
147 return 0;
148 }
151 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
152 int check_descriptor(unsigned long *d)
153 {
154 unsigned long base, limit, a = d[0], b = d[1];
156 /* A not-present descriptor will always fault, so is safe. */
157 if ( !(b & _SEGMENT_P) )
158 goto good;
160 /*
161 * We don't allow a DPL of zero. There is no legitimate reason for
162 * specifying DPL==0, and it gets rather dangerous if we also accept call
163 * gates (consider a call gate pointing at another guestos descriptor with
164 * DPL 0 -- this would get the OS ring-0 privileges).
165 */
166 if ( (b & _SEGMENT_DPL) == 0 )
167 goto bad;
169 if ( !(b & _SEGMENT_S) )
170 {
171 /*
172 * System segment:
173 * 1. Don't allow interrupt or trap gates as they belong in the IDT.
174 * 2. Don't allow TSS descriptors or task gates as we don't
175 * virtualise x86 tasks.
176 * 3. Don't allow LDT descriptors because they're unnecessary and
177 * I'm uneasy about allowing an LDT page to contain LDT
178 * descriptors. In any case, Xen automatically creates the
179 * required descriptor when reloading the LDT register.
180 * 4. We allow call gates but they must not jump to a private segment.
181 */
183 /* Disallow everything but call gates. */
184 if ( (b & _SEGMENT_TYPE) != 0xc00 )
185 goto bad;
187 /* Can't allow far jump to a Xen-private segment. */
188 if ( !VALID_CODESEL(a>>16) )
189 goto bad;
191 /* Reserved bits must be zero. */
192 if ( (b & 0xe0) != 0 )
193 goto bad;
195 /* No base/limit check is needed for a call gate. */
196 goto good;
197 }
199 /* Check that base is at least a page away from Xen-private area. */
200 base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
201 if ( base >= (PAGE_OFFSET - PAGE_SIZE) )
202 goto bad;
204 /* Check and truncate the limit if necessary. */
205 limit = (b&0xf0000) | (a&0xffff);
206 limit++; /* We add one because limit is inclusive. */
207 if ( (b & _SEGMENT_G) )
208 limit <<= 12;
210 if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
211 {
212 /*
213 * Grows-down limit check.
214 * NB. limit == 0xFFFFF provides no access (if G=1).
215 * limit == 0x00000 provides 4GB-4kB access (if G=1).
216 */
217 if ( (base + limit) > base )
218 {
219 limit = -(base & PAGE_MASK);
220 goto truncate;
221 }
222 }
223 else
224 {
225 /*
226 * Grows-up limit check.
227 * NB. limit == 0xFFFFF provides 4GB access (if G=1).
228 * limit == 0x00000 provides 4kB access (if G=1).
229 */
230 if ( ((base + limit) <= base) ||
231 ((base + limit) > PAGE_OFFSET) )
232 {
233 limit = PAGE_OFFSET - base;
234 truncate:
235 if ( !(b & _SEGMENT_G) )
236 goto bad; /* too dangerous; too hard to work out... */
237 limit = (limit >> 12) - 1;
238 d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
239 d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
240 }
241 }
243 good:
244 return 1;
245 bad:
246 return 0;
247 }
250 void destroy_gdt(struct exec_domain *ed)
251 {
252 int i;
253 unsigned long pfn;
255 for ( i = 0; i < 16; i++ )
256 {
257 if ( (pfn = l1_pgentry_to_pagenr(ed->mm.perdomain_ptes[i])) != 0 )
258 put_page_and_type(&frame_table[pfn]);
259 ed->mm.perdomain_ptes[i] = mk_l1_pgentry(0);
260 }
261 }
264 long set_gdt(struct exec_domain *ed,
265 unsigned long *frames,
266 unsigned int entries)
267 {
268 struct domain *d = ed->domain;
269 /* NB. There are 512 8-byte entries per GDT page. */
270 int i = 0, nr_pages = (entries + 511) / 512;
271 struct desc_struct *vgdt;
272 unsigned long pfn;
274 /* Check the first page in the new GDT. */
275 if ( (pfn = frames[0]) >= max_page )
276 goto fail;
278 /* The first page is special because Xen owns a range of entries in it. */
279 if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
280 {
281 /* GDT checks failed: try zapping the Xen reserved entries. */
282 if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
283 goto fail;
284 vgdt = map_domain_mem(pfn << PAGE_SHIFT);
285 memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
286 NR_RESERVED_GDT_ENTRIES*8);
287 unmap_domain_mem(vgdt);
288 put_page_and_type(&frame_table[pfn]);
290 /* Okay, we zapped the entries. Now try the GDT checks again. */
291 if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
292 goto fail;
293 }
295 /* Check the remaining pages in the new GDT. */
296 for ( i = 1; i < nr_pages; i++ )
297 if ( ((pfn = frames[i]) >= max_page) ||
298 !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
299 goto fail;
301 /* Copy reserved GDT entries to the new GDT. */
302 vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
303 memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
304 gdt_table + FIRST_RESERVED_GDT_ENTRY,
305 NR_RESERVED_GDT_ENTRIES*8);
306 unmap_domain_mem(vgdt);
308 /* Tear down the old GDT. */
309 destroy_gdt(ed);
311 /* Install the new GDT. */
312 for ( i = 0; i < nr_pages; i++ )
313 ed->mm.perdomain_ptes[i] =
314 mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
316 SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
317 SET_GDT_ENTRIES(ed, entries);
319 return 0;
321 fail:
322 while ( i-- > 0 )
323 put_page_and_type(&frame_table[frames[i]]);
324 return -EINVAL;
325 }
328 long do_set_gdt(unsigned long *frame_list, unsigned int entries)
329 {
330 int nr_pages = (entries + 511) / 512;
331 unsigned long frames[16];
332 long ret;
334 if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
335 return -EINVAL;
337 if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
338 return -EFAULT;
340 LOCK_BIGLOCK(current->domain);
342 if ( (ret = set_gdt(current, frames, entries)) == 0 )
343 {
344 local_flush_tlb();
345 __asm__ __volatile__ ("lgdt %0" : "=m" (*current->mm.gdt));
346 }
348 UNLOCK_BIGLOCK(current->domain);
350 return ret;
351 }
354 long do_update_descriptor(
355 unsigned long pa, unsigned long word1, unsigned long word2)
356 {
357 unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
358 struct pfn_info *page;
359 struct exec_domain *ed;
360 long ret = -EINVAL;
362 d[0] = word1;
363 d[1] = word2;
365 LOCK_BIGLOCK(current->domain);
367 if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) ) {
368 UNLOCK_BIGLOCK(current->domain);
369 return -EINVAL;
370 }
372 page = &frame_table[pfn];
373 if ( unlikely(!get_page(page, current->domain)) ) {
374 UNLOCK_BIGLOCK(current->domain);
375 return -EINVAL;
376 }
378 /* Check if the given frame is in use in an unsafe context. */
379 switch ( page->u.inuse.type_info & PGT_type_mask )
380 {
381 case PGT_gdt_page:
382 /* Disallow updates of Xen-reserved descriptors in the current GDT. */
383 for_each_exec_domain(current->domain, ed) {
384 if ( (l1_pgentry_to_pagenr(ed->mm.perdomain_ptes[0]) == pfn) &&
385 (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
386 (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
387 goto out;
388 }
389 if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
390 goto out;
391 break;
392 case PGT_ldt_page:
393 if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
394 goto out;
395 break;
396 default:
397 if ( unlikely(!get_page_type(page, PGT_writable_page)) )
398 goto out;
399 break;
400 }
402 /* All is good so make the update. */
403 gdt_pent = map_domain_mem(pa);
404 memcpy(gdt_pent, d, 8);
405 unmap_domain_mem(gdt_pent);
407 put_page_type(page);
409 ret = 0; /* success */
411 out:
412 put_page(page);
414 UNLOCK_BIGLOCK(current->domain);
416 return ret;
417 }
419 #ifdef MEMORY_GUARD
421 void *memguard_init(void *heap_start)
422 {
423 l1_pgentry_t *l1;
424 int i, j;
426 /* Round the allocation pointer up to a page boundary. */
427 heap_start = (void *)(((unsigned long)heap_start + (PAGE_SIZE-1)) &
428 PAGE_MASK);
430 /* Memory guarding is incompatible with super pages. */
431 for ( i = 0; i < (xenheap_phys_end >> L2_PAGETABLE_SHIFT); i++ )
432 {
433 l1 = (l1_pgentry_t *)heap_start;
434 heap_start = (void *)((unsigned long)heap_start + PAGE_SIZE);
435 for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ )
436 l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) |
437 (j << L1_PAGETABLE_SHIFT) |
438 __PAGE_HYPERVISOR);
439 idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] =
440 mk_l2_pgentry(virt_to_phys(l1) | __PAGE_HYPERVISOR);
441 }
443 return heap_start;
444 }
446 static void __memguard_change_range(void *p, unsigned long l, int guard)
447 {
448 l1_pgentry_t *l1;
449 l2_pgentry_t *l2;
450 unsigned long _p = (unsigned long)p;
451 unsigned long _l = (unsigned long)l;
453 /* Ensure we are dealing with a page-aligned whole number of pages. */
454 ASSERT((_p&PAGE_MASK) != 0);
455 ASSERT((_l&PAGE_MASK) != 0);
456 ASSERT((_p&~PAGE_MASK) == 0);
457 ASSERT((_l&~PAGE_MASK) == 0);
459 while ( _l != 0 )
460 {
461 l2 = &idle_pg_table[l2_table_offset(_p)];
462 l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
463 if ( guard )
464 *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) & ~_PAGE_PRESENT);
465 else
466 *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) | _PAGE_PRESENT);
467 _p += PAGE_SIZE;
468 _l -= PAGE_SIZE;
469 }
470 }
472 void memguard_guard_range(void *p, unsigned long l)
473 {
474 __memguard_change_range(p, l, 1);
475 local_flush_tlb();
476 }
478 void memguard_unguard_range(void *p, unsigned long l)
479 {
480 __memguard_change_range(p, l, 0);
481 }
483 #endif