ia64/xen-unstable

view xen/arch/x86/x86_32/mm.c @ 1805:70dea4b6904d

bitkeeper revision 1.1096.1.1 (40f6a8c7wXaMcm4UCjotaqA0KGAqcQ)

Fix an error-path bug in Xen.
author kaf24@scramble.cl.cam.ac.uk
date Thu Jul 15 15:54:47 2004 +0000 (2004-07-15)
parents 726a6efbd601
children 81936d3b712c
line source
1 /******************************************************************************
2 * arch/i386/mm.c
3 *
4 * Modifications to Linux original are copyright (c) 2002-2003, 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 static inline void set_pte_phys(unsigned long vaddr,
31 l1_pgentry_t entry)
32 {
33 l2_pgentry_t *l2ent;
34 l1_pgentry_t *l1ent;
36 l2ent = &idle_pg_table[l2_table_offset(vaddr)];
37 l1ent = l2_pgentry_to_l1(*l2ent) + l1_table_offset(vaddr);
38 *l1ent = entry;
40 /* It's enough to flush this one mapping. */
41 __flush_tlb_one(vaddr);
42 }
45 void __set_fixmap(enum fixed_addresses idx,
46 l1_pgentry_t entry)
47 {
48 unsigned long address = fix_to_virt(idx);
50 if ( likely(idx < __end_of_fixed_addresses) )
51 set_pte_phys(address, entry);
52 else
53 printk("Invalid __set_fixmap\n");
54 }
57 static void __init fixrange_init(unsigned long start,
58 unsigned long end,
59 l2_pgentry_t *pg_base)
60 {
61 l2_pgentry_t *l2e;
62 int i;
63 unsigned long vaddr, page;
65 vaddr = start;
66 i = l2_table_offset(vaddr);
67 l2e = pg_base + i;
69 for ( ; (i < ENTRIES_PER_L2_PAGETABLE) && (vaddr != end); l2e++, i++ )
70 {
71 if ( l2_pgentry_val(*l2e) != 0 )
72 continue;
73 page = (unsigned long)get_free_page();
74 clear_page(page);
75 *l2e = mk_l2_pgentry(__pa(page) | __PAGE_HYPERVISOR);
76 vaddr += 1 << L2_PAGETABLE_SHIFT;
77 }
78 }
80 void __init paging_init(void)
81 {
82 unsigned long addr;
83 void *ioremap_pt;
84 int i;
86 /* Idle page table 1:1 maps the first part of physical memory. */
87 for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
88 idle_pg_table[i] =
89 mk_l2_pgentry((i << L2_PAGETABLE_SHIFT) |
90 __PAGE_HYPERVISOR | _PAGE_PSE);
92 /*
93 * Fixed mappings, only the page table structure has to be
94 * created - mappings will be set by set_fixmap():
95 */
96 addr = FIXADDR_START & ~((1<<L2_PAGETABLE_SHIFT)-1);
97 fixrange_init(addr, 0, idle_pg_table);
99 /* Create page table for ioremap(). */
100 ioremap_pt = (void *)get_free_page();
101 clear_page(ioremap_pt);
102 idle_pg_table[IOREMAP_VIRT_START >> L2_PAGETABLE_SHIFT] =
103 mk_l2_pgentry(__pa(ioremap_pt) | __PAGE_HYPERVISOR);
105 /* Create read-only mapping of MPT for guest-OS use. */
106 idle_pg_table[RO_MPT_VIRT_START >> L2_PAGETABLE_SHIFT] =
107 mk_l2_pgentry(l2_pgentry_val(
108 idle_pg_table[RDWR_MPT_VIRT_START >> L2_PAGETABLE_SHIFT]) &
109 ~_PAGE_RW);
111 /* Set up mapping cache for domain pages. */
112 mapcache = (unsigned long *)get_free_page();
113 clear_page(mapcache);
114 idle_pg_table[MAPCACHE_VIRT_START >> L2_PAGETABLE_SHIFT] =
115 mk_l2_pgentry(__pa(mapcache) | __PAGE_HYPERVISOR);
117 /* Set up linear page table mapping. */
118 idle_pg_table[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
119 mk_l2_pgentry(__pa(idle_pg_table) | __PAGE_HYPERVISOR);
121 }
123 void __init zap_low_mappings(void)
124 {
125 int i;
126 for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
127 idle_pg_table[i] = mk_l2_pgentry(0);
128 flush_tlb_all_pge();
129 }
132 /*
133 * Allows shooting down of borrowed page-table use on specific CPUs.
134 * Specifically, we borrow page tables when running the idle domain.
135 */
136 static void __synchronise_pagetables(void *mask)
137 {
138 struct domain *d = current;
139 if ( ((unsigned long)mask & (1<<d->processor)) && is_idle_task(d) )
140 write_ptbase(&d->mm);
141 }
142 void synchronise_pagetables(unsigned long cpu_mask)
143 {
144 __synchronise_pagetables((void *)cpu_mask);
145 smp_call_function(__synchronise_pagetables, (void *)cpu_mask, 1, 1);
146 }
148 long do_stack_switch(unsigned long ss, unsigned long esp)
149 {
150 int nr = smp_processor_id();
151 struct tss_struct *t = &init_tss[nr];
153 /* We need to do this check as we load and use SS on guest's behalf. */
154 if ( (ss & 3) == 0 )
155 return -EPERM;
157 current->thread.guestos_ss = ss;
158 current->thread.guestos_sp = esp;
159 t->ss1 = ss;
160 t->esp1 = esp;
162 return 0;
163 }
166 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
167 int check_descriptor(unsigned long a, unsigned long b)
168 {
169 unsigned long base, limit;
171 /* A not-present descriptor will always fault, so is safe. */
172 if ( !(b & _SEGMENT_P) )
173 goto good;
175 /*
176 * We don't allow a DPL of zero. There is no legitimate reason for
177 * specifying DPL==0, and it gets rather dangerous if we also accept call
178 * gates (consider a call gate pointing at another guestos descriptor with
179 * DPL 0 -- this would get the OS ring-0 privileges).
180 */
181 if ( (b & _SEGMENT_DPL) == 0 )
182 goto bad;
184 if ( !(b & _SEGMENT_S) )
185 {
186 /*
187 * System segment:
188 * 1. Don't allow interrupt or trap gates as they belong in the IDT.
189 * 2. Don't allow TSS descriptors or task gates as we don't
190 * virtualise x86 tasks.
191 * 3. Don't allow LDT descriptors because they're unnecessary and
192 * I'm uneasy about allowing an LDT page to contain LDT
193 * descriptors. In any case, Xen automatically creates the
194 * required descriptor when reloading the LDT register.
195 * 4. We allow call gates but they must not jump to a private segment.
196 */
198 /* Disallow everything but call gates. */
199 if ( (b & _SEGMENT_TYPE) != 0xc00 )
200 goto bad;
202 /* Can't allow far jump to a Xen-private segment. */
203 if ( !VALID_CODESEL(a>>16) )
204 goto bad;
206 /* Reserved bits must be zero. */
207 if ( (b & 0xe0) != 0 )
208 goto bad;
210 /* No base/limit check is needed for a call gate. */
211 goto good;
212 }
214 /* Check that base/limit do not overlap Xen-private space. */
215 base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
216 limit = (b&0xf0000) | (a&0xffff);
217 limit++; /* We add one because limit is inclusive. */
218 if ( (b & _SEGMENT_G) )
219 limit <<= 12;
220 if ( ((base + limit) <= base) ||
221 ((base + limit) > PAGE_OFFSET) )
222 goto bad;
224 good:
225 return 1;
226 bad:
227 return 0;
228 }
231 void destroy_gdt(struct domain *d)
232 {
233 int i;
234 unsigned long pfn;
236 for ( i = 0; i < 16; i++ )
237 {
238 if ( (pfn = l1_pgentry_to_pagenr(d->mm.perdomain_pt[i])) != 0 )
239 put_page_and_type(&frame_table[pfn]);
240 d->mm.perdomain_pt[i] = mk_l1_pgentry(0);
241 }
242 }
245 long set_gdt(struct domain *d,
246 unsigned long *frames,
247 unsigned int entries)
248 {
249 /* NB. There are 512 8-byte entries per GDT page. */
250 int i, nr_pages = (entries + 511) / 512;
251 struct desc_struct *vgdt;
253 /* Check the new GDT. */
254 for ( i = 0; i < nr_pages; i++ )
255 {
256 if ( unlikely(frames[i] >= max_page) ||
257 unlikely(!get_page_and_type(&frame_table[frames[i]],
258 d, PGT_gdt_page)) )
259 goto fail;
260 }
262 /* Copy reserved GDT entries to the new GDT. */
263 vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
264 memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
265 gdt_table + FIRST_RESERVED_GDT_ENTRY,
266 NR_RESERVED_GDT_ENTRIES*8);
267 unmap_domain_mem(vgdt);
269 /* Tear down the old GDT. */
270 destroy_gdt(d);
272 /* Install the new GDT. */
273 for ( i = 0; i < nr_pages; i++ )
274 d->mm.perdomain_pt[i] =
275 mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
277 SET_GDT_ADDRESS(d, GDT_VIRT_START);
278 SET_GDT_ENTRIES(d, (entries*8)-1);
280 return 0;
282 fail:
283 while ( i-- > 0 )
284 put_page_and_type(&frame_table[frames[i]]);
285 return -EINVAL;
286 }
289 long do_set_gdt(unsigned long *frame_list, unsigned int entries)
290 {
291 int nr_pages = (entries + 511) / 512;
292 unsigned long frames[16];
293 long ret;
295 if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
296 return -EINVAL;
298 if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
299 return -EFAULT;
301 if ( (ret = set_gdt(current, frames, entries)) == 0 )
302 {
303 local_flush_tlb();
304 __asm__ __volatile__ ("lgdt %0" : "=m" (*current->mm.gdt));
305 }
307 return ret;
308 }
311 long do_update_descriptor(
312 unsigned long pa, unsigned long word1, unsigned long word2)
313 {
314 unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT;
315 struct pfn_info *page;
316 long ret = -EINVAL;
318 if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(word1, word2) )
319 return -EINVAL;
321 page = &frame_table[pfn];
322 if ( unlikely(!get_page(page, current)) )
323 return -EINVAL;
325 /* Check if the given frame is in use in an unsafe context. */
326 switch ( page->type_and_flags & PGT_type_mask )
327 {
328 case PGT_gdt_page:
329 /* Disallow updates of Xen-reserved descriptors in the current GDT. */
330 if ( (l1_pgentry_to_pagenr(current->mm.perdomain_pt[0]) == pfn) &&
331 (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
332 (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
333 goto out;
334 if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
335 goto out;
336 break;
337 case PGT_ldt_page:
338 if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
339 goto out;
340 break;
341 default:
342 if ( unlikely(!get_page_type(page, PGT_writeable_page)) )
343 goto out;
344 break;
345 }
347 /* All is good so make the update. */
348 gdt_pent = map_domain_mem(pa);
349 gdt_pent[0] = word1;
350 gdt_pent[1] = word2;
351 unmap_domain_mem(gdt_pent);
353 put_page_type(page);
355 ret = 0; /* success */
357 out:
358 put_page(page);
359 return ret;
360 }
362 #ifdef MEMORY_GUARD
364 void *memguard_init(void *heap_start)
365 {
366 l1_pgentry_t *l1;
367 int i, j;
369 /* Round the allocation pointer up to a page boundary. */
370 heap_start = (void *)(((unsigned long)heap_start + (PAGE_SIZE-1)) &
371 PAGE_MASK);
373 /* Memory guarding is incompatible with super pages. */
374 for ( i = 0; i < (xenheap_phys_end >> L2_PAGETABLE_SHIFT); i++ )
375 {
376 l1 = (l1_pgentry_t *)heap_start;
377 heap_start = (void *)((unsigned long)heap_start + PAGE_SIZE);
378 for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ )
379 l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) |
380 (j << L1_PAGETABLE_SHIFT) |
381 __PAGE_HYPERVISOR);
382 idle_pg_table[i] = idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] =
383 mk_l2_pgentry(virt_to_phys(l1) | __PAGE_HYPERVISOR);
384 }
386 return heap_start;
387 }
389 static void __memguard_change_range(void *p, unsigned long l, int guard)
390 {
391 l1_pgentry_t *l1;
392 l2_pgentry_t *l2;
393 unsigned long _p = (unsigned long)p;
394 unsigned long _l = (unsigned long)l;
396 /* Ensure we are dealing with a page-aligned whole number of pages. */
397 ASSERT((_p&PAGE_MASK) != 0);
398 ASSERT((_l&PAGE_MASK) != 0);
399 ASSERT((_p&~PAGE_MASK) == 0);
400 ASSERT((_l&~PAGE_MASK) == 0);
402 while ( _l != 0 )
403 {
404 l2 = &idle_pg_table[l2_table_offset(_p)];
405 l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
406 if ( guard )
407 *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) & ~_PAGE_PRESENT);
408 else
409 *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) | _PAGE_PRESENT);
410 _p += PAGE_SIZE;
411 _l -= PAGE_SIZE;
412 }
413 }
415 void memguard_guard_range(void *p, unsigned long l)
416 {
417 __memguard_change_range(p, l, 1);
418 local_flush_tlb();
419 }
421 void memguard_unguard_range(void *p, unsigned long l)
422 {
423 __memguard_change_range(p, l, 0);
424 }
426 int memguard_is_guarded(void *p)
427 {
428 l1_pgentry_t *l1;
429 l2_pgentry_t *l2;
430 unsigned long _p = (unsigned long)p;
431 l2 = &idle_pg_table[l2_table_offset(_p)];
432 l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
433 return !(l1_pgentry_val(*l1) & _PAGE_PRESENT);
434 }
436 #endif