ia64/xen-unstable

view xen/arch/x86/x86_32/seg_fixup.c @ 19835:edfdeb150f27

Fix buildsystem to detect udev > version 124

udev removed the udevinfo symlink from versions higher than 123 and
xen's build-system could not detect if udev is in place and has the
required version.

Signed-off-by: Marc-A. Dahlhaus <mad@wol.de>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 25 13:02:37 2009 +0100 (2009-06-25)
parents 6301c3b6e1ba
children
line source
1 /******************************************************************************
2 * arch/x86/x86_32/seg_fixup.c
3 *
4 * Support for -ve accesses to pseudo-4GB segments.
5 *
6 * Copyright (c) 2004, K A Fraser
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
23 #include <xen/config.h>
24 #include <xen/init.h>
25 #include <xen/sched.h>
26 #include <xen/lib.h>
27 #include <xen/errno.h>
28 #include <xen/mm.h>
29 #include <xen/perfc.h>
30 #include <asm/current.h>
31 #include <asm/processor.h>
32 #include <asm/regs.h>
33 #include <asm/x86_emulate.h>
35 /* General instruction properties. */
36 #define INSN_SUFFIX_BYTES (7)
37 #define OPCODE_BYTE (1<<4)
38 #define HAS_MODRM (1<<5)
40 /* Short forms for the table. */
41 #define X 0 /* invalid for some random reason */
42 #define O OPCODE_BYTE
43 #define M HAS_MODRM
45 static const unsigned char insn_decode[256] = {
46 /* 0x00 - 0x0F */
47 O|M, O|M, O|M, O|M, X, X, X, X,
48 O|M, O|M, O|M, O|M, X, X, X, X,
49 /* 0x10 - 0x1F */
50 O|M, O|M, O|M, O|M, X, X, X, X,
51 O|M, O|M, O|M, O|M, X, X, X, X,
52 /* 0x20 - 0x2F */
53 O|M, O|M, O|M, O|M, X, X, X, X,
54 O|M, O|M, O|M, O|M, X, X, X, X,
55 /* 0x30 - 0x3F */
56 O|M, O|M, O|M, O|M, X, X, X, X,
57 O|M, O|M, O|M, O|M, X, X, X, X,
58 /* 0x40 - 0x4F */
59 X, X, X, X, X, X, X, X,
60 X, X, X, X, X, X, X, X,
61 /* 0x50 - 0x5F */
62 X, X, X, X, X, X, X, X,
63 X, X, X, X, X, X, X, X,
64 /* 0x60 - 0x6F */
65 X, X, X, X, X, X, X, X,
66 X, O|M|4, X, O|M|1, X, X, X, X,
67 /* 0x70 - 0x7F */
68 X, X, X, X, X, X, X, X,
69 X, X, X, X, X, X, X, X,
70 /* 0x80 - 0x8F */
71 O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M,
72 O|M, O|M, O|M, O|M, O|M, X|M, O|M, O|M,
73 /* 0x90 - 0x9F */
74 X, X, X, X, X, X, X, X,
75 X, X, X, X, X, X, X, X,
76 /* 0xA0 - 0xAF */
77 O|4, O|4, O|4, O|4, X, X, X, X,
78 X, X, X, X, X, X, X, X,
79 /* 0xB0 - 0xBF */
80 X, X, X, X, X, X, X, X,
81 X, X, X, X, X, X, X, X,
82 /* 0xC0 - 0xCF */
83 O|M|1, O|M|1, X, X, X, X, O|M|1, O|M|4,
84 X, X, X, X, X, X, X, X,
85 /* 0xD0 - 0xDF */
86 O|M, O|M, O|M, O|M, X, X, X, X,
87 X, X, X, X, X, X, X, X,
88 /* 0xE0 - 0xEF */
89 X, X, X, X, X, X, X, X,
90 X, X, X, X, X, X, X, X,
91 /* 0xF0 - 0xFF */
92 X, X, X, X, X, X, O|M, O|M,
93 X, X, X, X, X, X, O|M, O|M
94 };
96 static const unsigned char twobyte_decode[256] = {
97 /* 0x00 - 0x0F */
98 X, X, X, X, X, X, X, X,
99 X, X, X, X, X, X, X, X,
100 /* 0x10 - 0x1F */
101 X, X, X, X, X, X, X, X,
102 O|M, X, X, X, X, X, X, X,
103 /* 0x20 - 0x2F */
104 X, X, X, X, X, X, X, X,
105 X, X, X, X, X, X, X, X,
106 /* 0x30 - 0x3F */
107 X, X, X, X, X, X, X, X,
108 X, X, X, X, X, X, X, X,
109 /* 0x40 - 0x4F */
110 O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
111 O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
112 /* 0x50 - 0x5F */
113 X, X, X, X, X, X, X, X,
114 X, X, X, X, X, X, X, X,
115 /* 0x60 - 0x6F */
116 X, X, X, X, X, X, X, X,
117 X, X, X, X, X, X, X, X,
118 /* 0x70 - 0x7F */
119 X, X, X, X, X, X, X, X,
120 X, X, X, X, X, X, X, X,
121 /* 0x80 - 0x8F */
122 X, X, X, X, X, X, X, X,
123 X, X, X, X, X, X, X, X,
124 /* 0x90 - 0x9F */
125 O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
126 O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
127 /* 0xA0 - 0xAF */
128 X, X, X, O|M, O|M|1, O|M, O|M, X,
129 X, X, X, O|M, O|M|1, O|M, X, O|M,
130 /* 0xB0 - 0xBF */
131 X, X, X, O|M, X, X, O|M, O|M,
132 X, X, O|M|1, O|M, O|M, O|M, O|M, O|M,
133 /* 0xC0 - 0xCF */
134 O|M, O|M, X, O|M, X, X, X, O|M,
135 X, X, X, X, X, X, X, X,
136 /* 0xD0 - 0xDF */
137 X, X, X, X, X, X, X, X,
138 X, X, X, X, X, X, X, X,
139 /* 0xE0 - 0xEF */
140 X, X, X, X, X, X, X, X,
141 X, X, X, X, X, X, X, X,
142 /* 0xF0 - 0xFF */
143 X, X, X, X, X, X, X, X,
144 X, X, X, X, X, X, X, X
145 };
147 /*
148 * Obtain the base and limit associated with the given segment selector.
149 * The selector must identify a 32-bit code or data segment. Any segment that
150 * appears to be truncated to not overlap with Xen is assumed to be a truncated
151 * 4GB segment, and the returned limit reflects this.
152 * @seg (IN) : Segment selector to decode.
153 * @base (OUT): Decoded linear base address.
154 * @limit (OUT): Decoded segment limit, in bytes. 0 == unlimited (4GB).
155 */
156 static int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
157 {
158 struct vcpu *curr = current;
159 uint32_t *table, a, b;
160 int ldt = !!(seg & 4);
161 int idx = (seg >> 3) & 8191;
163 /* Get base and check limit. */
164 if ( ldt )
165 {
166 table = (uint32_t *)LDT_VIRT_START(curr);
167 if ( idx >= curr->arch.guest_context.ldt_ents )
168 goto fail;
169 }
170 else /* gdt */
171 {
172 table = (uint32_t *)GDT_VIRT_START(curr);
173 if ( idx >= curr->arch.guest_context.gdt_ents )
174 goto fail;
175 }
177 /* Grab the segment descriptor. */
178 if ( __get_user(a, &table[2*idx+0]) ||
179 __get_user(b, &table[2*idx+1]) )
180 goto fail; /* Barking up the wrong tree. Decode needs a page fault.*/
182 /* We only parse 32-bit code and data segments. */
183 if ( (b & (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB)) !=
184 (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB) )
185 goto fail;
187 /* Decode base and limit. */
188 *base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
189 *limit = ((b & 0xf0000) | (a & 0x0ffff)) + 1;
190 if ( (b & _SEGMENT_G) )
191 *limit <<= 12;
193 /*
194 * Anything that looks like a truncated segment we assume ought really
195 * to be a 4GB segment. DANGER!
196 */
197 if ( (GUEST_SEGMENT_MAX_ADDR - (*base + *limit)) < PAGE_SIZE )
198 *limit = 0;
200 return 1;
202 fail:
203 return 0;
204 }
206 /* Turn a segment+offset into a linear address. */
207 static int linearise_address(u16 seg, unsigned long off, unsigned long *linear)
208 {
209 unsigned long base, limit;
211 if ( !get_baselimit(seg, &base, &limit) )
212 return 0;
214 if ( off > (limit-1) )
215 return 0;
217 *linear = base + off;
219 return 1;
220 }
222 static int fixup_seg(u16 seg, unsigned long offset)
223 {
224 struct vcpu *curr = current;
225 uint32_t *table, a, b, base, limit;
226 int ldt = !!(seg & 4);
227 int idx = (seg >> 3) & 8191;
229 /* Get base and check limit. */
230 if ( ldt )
231 {
232 table = (uint32_t *)LDT_VIRT_START(curr);
233 if ( idx >= curr->arch.guest_context.ldt_ents )
234 {
235 dprintk(XENLOG_DEBUG, "Segment %04x out of LDT range (%ld)\n",
236 seg, curr->arch.guest_context.ldt_ents);
237 goto fail;
238 }
239 }
240 else /* gdt */
241 {
242 table = (uint32_t *)GDT_VIRT_START(curr);
243 if ( idx >= curr->arch.guest_context.gdt_ents )
244 {
245 dprintk(XENLOG_DEBUG, "Segment %04x out of GDT range (%ld)\n",
246 seg, curr->arch.guest_context.gdt_ents);
247 goto fail;
248 }
249 }
251 /* Grab the segment descriptor. */
252 if ( __get_user(a, &table[2*idx+0]) ||
253 __get_user(b, &table[2*idx+1]) )
254 {
255 dprintk(XENLOG_DEBUG, "Fault while reading segment %04x\n", seg);
256 goto fail; /* Barking up the wrong tree. Decode needs a page fault.*/
257 }
259 /* We only parse 32-bit page-granularity non-privileged data segments. */
260 if ( (b & (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|
261 _SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) !=
262 (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) )
263 {
264 dprintk(XENLOG_DEBUG, "Bad segment %08x:%08x\n", a, b);
265 goto fail;
266 }
268 /* Decode base and limit. */
269 base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
270 limit = (((b & 0xf0000) | (a & 0x0ffff)) + 1) << 12;
272 if ( b & _SEGMENT_EC )
273 {
274 /* Expands-down: All the way to zero? Assume 4GB if so. */
275 if ( ((base + limit) < PAGE_SIZE) && (offset <= limit) )
276 {
277 /* Flip to expands-up. */
278 limit = GUEST_SEGMENT_MAX_ADDR - base;
279 goto flip;
280 }
281 }
282 else
283 {
284 /* Expands-up: All the way to Xen space? Assume 4GB if so. */
285 if ( ((GUEST_SEGMENT_MAX_ADDR - (base + limit)) < PAGE_SIZE) &&
286 (offset > limit) )
287 {
288 /* Flip to expands-down. */
289 limit = -(base & PAGE_MASK);
290 goto flip;
291 }
292 }
294 dprintk(XENLOG_DEBUG, "None of the above! (%08x:%08x, %08x, %08x, %08x)\n",
295 a, b, base, limit, base+limit);
297 fail:
298 return 0;
300 flip:
301 limit = (limit >> 12) - 1;
302 a &= ~0x0ffff; a |= limit & 0x0ffff;
303 b &= ~0xf0000; b |= limit & 0xf0000;
304 b ^= _SEGMENT_EC; /* grows-up <-> grows-down */
305 /* NB. This can't fault. Checked readable above; must also be writable. */
306 atomic_write64((uint64_t *)&table[2*idx], ((uint64_t)b<<32) | a);
307 return 1;
308 }
310 /*
311 * Called from the general-protection fault handler to attempt to decode
312 * and emulate an instruction that depends on 4GB segments.
313 */
314 int gpf_emulate_4gb(struct cpu_user_regs *regs)
315 {
316 struct vcpu *curr = current;
317 u8 modrm, mod, rm, decode;
318 const u32 *base, *index = NULL;
319 unsigned long offset;
320 s8 disp8;
321 s32 disp32 = 0;
322 u8 *eip; /* ptr to instruction start */
323 u8 *pb, b; /* ptr into instr. / current instr. byte */
324 int gs_override = 0, scale = 0, twobyte = 0;
326 /* WARNING: We only work for ring-3 segments. */
327 if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) )
328 goto fail;
330 if ( !linearise_address((u16)regs->cs, regs->eip, (unsigned long *)&eip) )
331 {
332 dprintk(XENLOG_DEBUG, "Cannot linearise %04x:%08x\n",
333 regs->cs, regs->eip);
334 goto fail;
335 }
337 /* Parse prefix bytes. We're basically looking for segment override. */
338 for ( pb = eip; ; pb++ )
339 {
340 if ( get_user(b, pb) )
341 {
342 dprintk(XENLOG_DEBUG,
343 "Fault while accessing byte %ld of instruction\n",
344 (long)(pb-eip));
345 goto page_fault;
346 }
348 if ( (pb - eip) >= 15 )
349 {
350 dprintk(XENLOG_DEBUG, "Too many instruction prefixes for a "
351 "legal instruction\n");
352 goto fail;
353 }
355 if ( twobyte )
356 break;
358 switch ( b )
359 {
360 case 0x67: /* Address-size override */
361 case 0x2e: /* CS override */
362 case 0x3e: /* DS override */
363 case 0x26: /* ES override */
364 case 0x64: /* FS override */
365 case 0x36: /* SS override */
366 dprintk(XENLOG_DEBUG, "Unhandled prefix %02x\n", b);
367 goto fail;
368 case 0x66: /* Operand-size override */
369 case 0xf0: /* LOCK */
370 case 0xf2: /* REPNE/REPNZ */
371 case 0xf3: /* REP/REPE/REPZ */
372 break;
373 case 0x65: /* GS override */
374 gs_override = 1;
375 break;
376 case 0x0f: /* Not really a prefix byte */
377 twobyte = 1;
378 break;
379 default: /* Not a prefix byte */
380 goto done_prefix;
381 }
382 }
383 done_prefix:
385 if ( !gs_override )
386 {
387 dprintk(XENLOG_DEBUG, "Only instructions with GS override\n");
388 goto fail;
389 }
391 decode = (!twobyte ? insn_decode : twobyte_decode)[b];
392 pb++;
394 if ( !(decode & OPCODE_BYTE) )
395 {
396 dprintk(XENLOG_DEBUG, "Unsupported %sopcode %02x\n",
397 twobyte ? "two byte " : "", b);
398 goto fail;
399 }
401 if ( !(decode & HAS_MODRM) )
402 {
403 /* Must be a <disp32>, or bail. */
404 if ( (decode & INSN_SUFFIX_BYTES) != 4 )
405 goto fail;
407 if ( get_user(offset, (u32 *)pb) )
408 {
409 dprintk(XENLOG_DEBUG, "Fault while extracting <moffs32>.\n");
410 goto page_fault;
411 }
412 pb += 4;
414 goto skip_modrm;
415 }
417 /*
418 * Mod/RM processing.
419 */
421 if ( get_user(modrm, pb) )
422 {
423 dprintk(XENLOG_DEBUG, "Fault while extracting modrm byte\n");
424 goto page_fault;
425 }
427 pb++;
429 mod = (modrm >> 6) & 3;
430 rm = (modrm >> 0) & 7;
432 if ( rm == 4 )
433 {
434 u8 sib;
436 if ( get_user(sib, pb) )
437 {
438 dprintk(XENLOG_DEBUG, "Fault while extracting sib byte\n");
439 goto page_fault;
440 }
442 pb++;
444 rm = sib & 7;
445 if ( (sib & 0x38) != 0x20 )
446 index = decode_register((sib >> 3) & 7, regs, 0);
447 scale = sib >> 6;
448 }
450 /* Decode R/M field. */
451 base = decode_register(rm, regs, 0);
453 /* Decode Mod field. */
454 switch ( mod )
455 {
456 case 0:
457 if ( rm == 5 ) /* disp32 rather than (EBP) */
458 {
459 base = NULL;
460 if ( get_user(disp32, (u32 *)pb) )
461 {
462 dprintk(XENLOG_DEBUG, "Fault while extracting <base32>.\n");
463 goto page_fault;
464 }
465 pb += 4;
466 }
467 break;
469 case 1:
470 if ( get_user(disp8, pb) )
471 {
472 dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
473 goto page_fault;
474 }
475 pb++;
476 disp32 = disp8;
477 break;
479 case 2:
480 if ( get_user(disp32, (u32 *)pb) )
481 {
482 dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n");
483 goto page_fault;
484 }
485 pb += 4;
486 break;
488 case 3:
489 dprintk(XENLOG_DEBUG, "Not a memory operand!\n");
490 goto fail;
491 }
493 offset = disp32;
494 if ( base != NULL )
495 offset += *base;
496 if ( index != NULL )
497 offset += *index << scale;
499 skip_modrm:
500 if ( !fixup_seg((u16)regs->gs, offset) )
501 goto fail;
503 /* Success! */
504 perfc_incr(seg_fixups);
506 /* If requested, give a callback on otherwise unused vector 15. */
507 if ( VM_ASSIST(curr->domain, VMASST_TYPE_4gb_segments_notify) )
508 {
509 struct trap_info *ti = &curr->arch.guest_context.trap_ctxt[15];
510 struct trap_bounce *tb = &curr->arch.trap_bounce;
512 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
513 tb->error_code = pb - eip;
514 tb->cs = ti->cs;
515 tb->eip = ti->address;
516 if ( TI_GET_IF(ti) )
517 tb->flags |= TBF_INTERRUPT;
518 }
520 return EXCRET_fault_fixed;
522 fail:
523 return 0;
525 page_fault:
526 propagate_page_fault((unsigned long)pb, 0); /* read fault */
527 return EXCRET_fault_fixed;
528 }
530 /*
531 * Local variables:
532 * mode: C
533 * c-set-style: "BSD"
534 * c-basic-offset: 4
535 * tab-width: 4
536 * indent-tabs-mode: nil
537 * End:
538 */