ia64/xen-unstable

view xen/arch/x86/x86_64/mm.c @ 6433:0610add7c3fe

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 16:27:04 2005 +0000 (2005-08-25)
parents b54144915ae6 85ccfd035658
children b4b3f6be5226
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 <asm/current.h>
26 #include <asm/asm_defns.h>
27 #include <asm/page.h>
28 #include <asm/flushtlb.h>
29 #include <asm/fixmap.h>
30 #include <asm/msr.h>
32 struct pfn_info *alloc_xen_pagetable(void)
33 {
34 extern int early_boot;
35 unsigned long pfn;
37 if ( !early_boot )
38 return alloc_domheap_page(NULL);
40 pfn = alloc_boot_pages(1, 1);
41 return ((pfn == 0) ? NULL : pfn_to_page(pfn));
42 }
44 void free_xen_pagetable(struct pfn_info *pg)
45 {
46 free_domheap_page(pg);
47 }
49 l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
50 {
51 l4_pgentry_t *pl4e;
52 l3_pgentry_t *pl3e;
53 l2_pgentry_t *pl2e;
55 pl4e = &idle_pg_table[l4_table_offset(v)];
56 if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) )
57 {
58 pl3e = page_to_virt(alloc_xen_pagetable());
59 clear_page(pl3e);
60 *pl4e = l4e_from_paddr(__pa(pl3e), __PAGE_HYPERVISOR);
61 }
63 pl3e = l4e_to_l3e(*pl4e) + l3_table_offset(v);
64 if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
65 {
66 pl2e = page_to_virt(alloc_xen_pagetable());
67 clear_page(pl2e);
68 *pl3e = l3e_from_paddr(__pa(pl2e), __PAGE_HYPERVISOR);
69 }
71 pl2e = l3e_to_l2e(*pl3e) + l2_table_offset(v);
72 return pl2e;
73 }
75 void __init paging_init(void)
76 {
77 unsigned long i;
78 l3_pgentry_t *l3_ro_mpt;
79 l2_pgentry_t *l2_ro_mpt;
80 struct pfn_info *pg;
82 idle0_vcpu.arch.monitor_table = mk_pagetable(__pa(idle_pg_table));
84 /* Create user-accessible L2 directory to map the MPT for guests. */
85 l3_ro_mpt = alloc_xenheap_page();
86 clear_page(l3_ro_mpt);
87 idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)] =
88 l4e_from_page(
89 virt_to_page(l3_ro_mpt), __PAGE_HYPERVISOR | _PAGE_USER);
90 l2_ro_mpt = alloc_xenheap_page();
91 clear_page(l2_ro_mpt);
92 l3_ro_mpt[l3_table_offset(RO_MPT_VIRT_START)] =
93 l3e_from_page(
94 virt_to_page(l2_ro_mpt), __PAGE_HYPERVISOR | _PAGE_USER);
95 l2_ro_mpt += l2_table_offset(RO_MPT_VIRT_START);
97 /*
98 * Allocate and map the machine-to-phys table.
99 * This also ensures L3 is present for fixmaps.
100 */
101 for ( i = 0; i < max_page; i += ((1UL << L2_PAGETABLE_SHIFT) / 4) )
102 {
103 pg = alloc_domheap_pages(NULL, PAGETABLE_ORDER, 0);
104 if ( pg == NULL )
105 panic("Not enough memory for m2p table\n");
106 map_pages_to_xen(
107 RDWR_MPT_VIRT_START + i*8, page_to_pfn(pg),
108 1UL << PAGETABLE_ORDER,
109 PAGE_HYPERVISOR);
110 memset((void *)(RDWR_MPT_VIRT_START + i*8), 0x55,
111 1UL << L2_PAGETABLE_SHIFT);
112 *l2_ro_mpt++ = l2e_from_page(
113 pg, _PAGE_GLOBAL|_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT);
114 BUG_ON(((unsigned long)l2_ro_mpt & ~PAGE_MASK) == 0);
115 }
117 /* Set up linear page table mapping. */
118 idle_pg_table[l4_table_offset(LINEAR_PT_VIRT_START)] =
119 l4e_from_paddr(__pa(idle_pg_table), __PAGE_HYPERVISOR);
120 }
122 void __init zap_low_mappings(void)
123 {
124 idle_pg_table[0] = l4e_empty();
125 flush_tlb_all_pge();
126 }
128 void subarch_init_memory(struct domain *dom_xen)
129 {
130 unsigned long i, v, m2p_start_mfn;
131 l3_pgentry_t l3e;
132 l2_pgentry_t l2e;
134 /*
135 * We are rather picky about the layout of 'struct pfn_info'. The
136 * count_info and domain fields must be adjacent, as we perform atomic
137 * 64-bit operations on them.
138 */
139 if ( (offsetof(struct pfn_info, u.inuse._domain) !=
140 (offsetof(struct pfn_info, count_info) + sizeof(u32))) )
141 {
142 printk("Weird pfn_info layout (%ld,%ld,%ld)\n",
143 offsetof(struct pfn_info, count_info),
144 offsetof(struct pfn_info, u.inuse._domain),
145 sizeof(struct pfn_info));
146 for ( ; ; ) ;
147 }
149 /* M2P table is mappable read-only by privileged domains. */
150 for ( v = RDWR_MPT_VIRT_START;
151 v != RDWR_MPT_VIRT_END;
152 v += 1 << L2_PAGETABLE_SHIFT )
153 {
154 l3e = l4e_to_l3e(idle_pg_table[l4_table_offset(v)])[
155 l3_table_offset(v)];
156 if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
157 continue;
158 l2e = l3e_to_l2e(l3e)[l2_table_offset(v)];
159 if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
160 continue;
161 m2p_start_mfn = l2e_get_pfn(l2e);
163 for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
164 {
165 frame_table[m2p_start_mfn+i].count_info = PGC_allocated | 1;
166 /* gdt to make sure it's only mapped read-only by non-privileged
167 domains. */
168 frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1;
169 page_set_owner(&frame_table[m2p_start_mfn+i], dom_xen);
170 }
171 }
172 }
174 long do_stack_switch(unsigned long ss, unsigned long esp)
175 {
176 if ( (ss & 3) != 3 )
177 return -EPERM;
178 current->arch.guest_context.kernel_ss = ss;
179 current->arch.guest_context.kernel_sp = esp;
180 return 0;
181 }
183 long do_set_segment_base(unsigned int which, unsigned long base)
184 {
185 struct vcpu *v = current;
186 long ret = 0;
188 switch ( which )
189 {
190 case SEGBASE_FS:
191 if ( wrmsr_user(MSR_FS_BASE, base, base>>32) )
192 ret = -EFAULT;
193 else
194 v->arch.guest_context.fs_base = base;
195 break;
197 case SEGBASE_GS_USER:
198 if ( wrmsr_user(MSR_SHADOW_GS_BASE, base, base>>32) )
199 ret = -EFAULT;
200 else
201 v->arch.guest_context.gs_base_user = base;
202 break;
204 case SEGBASE_GS_KERNEL:
205 if ( wrmsr_user(MSR_GS_BASE, base, base>>32) )
206 ret = -EFAULT;
207 else
208 v->arch.guest_context.gs_base_kernel = base;
209 break;
211 case SEGBASE_GS_USER_SEL:
212 __asm__ __volatile__ (
213 " swapgs \n"
214 "1: movl %k0,%%gs \n"
215 " "safe_swapgs" \n"
216 ".section .fixup,\"ax\" \n"
217 "2: xorl %k0,%k0 \n"
218 " jmp 1b \n"
219 ".previous \n"
220 ".section __ex_table,\"a\"\n"
221 " .align 8 \n"
222 " .quad 1b,2b \n"
223 ".previous "
224 : : "r" (base&0xffff) );
225 break;
227 default:
228 ret = -EINVAL;
229 break;
230 }
232 return ret;
233 }
236 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
237 int check_descriptor(struct desc_struct *d)
238 {
239 u32 a = d->a, b = d->b;
241 /* A not-present descriptor will always fault, so is safe. */
242 if ( !(b & _SEGMENT_P) )
243 goto good;
245 /* The guest can only safely be executed in ring 3. */
246 if ( (b & _SEGMENT_DPL) != _SEGMENT_DPL )
247 goto bad;
249 /* All code and data segments are okay. No base/limit checking. */
250 if ( (b & _SEGMENT_S) )
251 goto good;
253 /* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
254 if ( (b & _SEGMENT_TYPE) == 0x000 )
255 goto good;
257 /* Everything but a call gate is discarded here. */
258 if ( (b & _SEGMENT_TYPE) != 0xc00 )
259 goto bad;
261 /* Can't allow far jump to a Xen-private segment. */
262 if ( !VALID_CODESEL(a>>16) )
263 goto bad;
265 /* Reserved bits must be zero. */
266 if ( (b & 0xe0) != 0 )
267 goto bad;
269 good:
270 return 1;
271 bad:
272 return 0;
273 }
275 void memguard_guard_stack(void *p)
276 {
277 p = (void *)((unsigned long)p + PAGE_SIZE);
278 memguard_guard_range(p, 2 * PAGE_SIZE);
279 }
281 /*
282 * Local variables:
283 * mode: C
284 * c-set-style: "BSD"
285 * c-basic-offset: 4
286 * tab-width: 4
287 * indent-tabs-mode: nil
288 * End:
289 */