ia64/xen-unstable

view xen/arch/x86/x86_32/seg_fixup.c @ 13969:047b3e9f9032

Remove unuseful and noisy seg-fixup warning message.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Feb 15 10:34:21 2007 +0000 (2007-02-15)
parents 4fb80f21c77d
children ea0b50ca4999
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 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, O|M, O|M, X,
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, X, X,
93 X, X, X, X, X, X, O|M, O|M
94 };
96 /*
97 * Obtain the base and limit associated with the given segment selector.
98 * The selector must identify a 32-bit code or data segment. Any segment that
99 * appears to be truncated to not overlap with Xen is assumed to be a truncated
100 * 4GB segment, and the returned limit reflects this.
101 * @seg (IN) : Segment selector to decode.
102 * @base (OUT): Decoded linear base address.
103 * @limit (OUT): Decoded segment limit, in bytes. 0 == unlimited (4GB).
104 */
105 int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
106 {
107 struct vcpu *d = current;
108 unsigned long *table, a, b;
109 int ldt = !!(seg & 4);
110 int idx = (seg >> 3) & 8191;
112 /* Get base and check limit. */
113 if ( ldt )
114 {
115 table = (unsigned long *)LDT_VIRT_START(d);
116 if ( idx >= d->arch.guest_context.ldt_ents )
117 goto fail;
118 }
119 else /* gdt */
120 {
121 table = (unsigned long *)GDT_VIRT_START(d);
122 if ( idx >= d->arch.guest_context.gdt_ents )
123 goto fail;
124 }
126 /* Grab the segment descriptor. */
127 if ( __get_user(a, &table[2*idx+0]) ||
128 __get_user(b, &table[2*idx+1]) )
129 goto fail; /* Barking up the wrong tree. Decode needs a page fault.*/
131 /* We only parse 32-bit code and data segments. */
132 if ( (b & (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB)) !=
133 (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB) )
134 goto fail;
136 /* Decode base and limit. */
137 *base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
138 *limit = ((b & 0xf0000) | (a & 0x0ffff)) + 1;
139 if ( (b & _SEGMENT_G) )
140 *limit <<= 12;
142 /*
143 * Anything that looks like a truncated segment we assume ought really
144 * to be a 4GB segment. DANGER!
145 */
146 if ( (GUEST_SEGMENT_MAX_ADDR - (*base + *limit)) < PAGE_SIZE )
147 *limit = 0;
149 return 1;
151 fail:
152 return 0;
153 }
155 /* Turn a segment+offset into a linear address. */
156 int linearise_address(u16 seg, unsigned long off, unsigned long *linear)
157 {
158 unsigned long base, limit;
160 if ( !get_baselimit(seg, &base, &limit) )
161 return 0;
163 if ( off > (limit-1) )
164 return 0;
166 *linear = base + off;
168 return 1;
169 }
171 int fixup_seg(u16 seg, unsigned long offset)
172 {
173 struct vcpu *d = current;
174 unsigned long *table, a, b, base, limit;
175 int ldt = !!(seg & 4);
176 int idx = (seg >> 3) & 8191;
178 /* Get base and check limit. */
179 if ( ldt )
180 {
181 table = (unsigned long *)LDT_VIRT_START(d);
182 if ( idx >= d->arch.guest_context.ldt_ents )
183 {
184 dprintk(XENLOG_DEBUG, "Segment %04x out of LDT range (%ld)\n",
185 seg, d->arch.guest_context.ldt_ents);
186 goto fail;
187 }
188 }
189 else /* gdt */
190 {
191 table = (unsigned long *)GDT_VIRT_START(d);
192 if ( idx >= d->arch.guest_context.gdt_ents )
193 {
194 dprintk(XENLOG_DEBUG, "Segment %04x out of GDT range (%ld)\n",
195 seg, d->arch.guest_context.gdt_ents);
196 goto fail;
197 }
198 }
200 /* Grab the segment descriptor. */
201 if ( __get_user(a, &table[2*idx+0]) ||
202 __get_user(b, &table[2*idx+1]) )
203 {
204 dprintk(XENLOG_DEBUG, "Fault while reading segment %04x\n", seg);
205 goto fail; /* Barking up the wrong tree. Decode needs a page fault.*/
206 }
208 /* We only parse 32-bit page-granularity non-privileged data segments. */
209 if ( (b & (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|
210 _SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) !=
211 (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) )
212 {
213 dprintk(XENLOG_DEBUG, "Bad segment %08lx:%08lx\n", a, b);
214 goto fail;
215 }
217 /* Decode base and limit. */
218 base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
219 limit = (((b & 0xf0000) | (a & 0x0ffff)) + 1) << 12;
221 if ( b & _SEGMENT_EC )
222 {
223 /* Expands-down: All the way to zero? Assume 4GB if so. */
224 if ( ((base + limit) < PAGE_SIZE) && (offset <= limit) )
225 {
226 /* Flip to expands-up. */
227 limit = GUEST_SEGMENT_MAX_ADDR - base;
228 goto flip;
229 }
230 }
231 else
232 {
233 /* Expands-up: All the way to Xen space? Assume 4GB if so. */
234 if ( ((GUEST_SEGMENT_MAX_ADDR - (base + limit)) < PAGE_SIZE) &&
235 (offset > limit) )
236 {
237 /* Flip to expands-down. */
238 limit = -(base & PAGE_MASK);
239 goto flip;
240 }
241 }
243 dprintk(XENLOG_DEBUG, "None of the above! "
244 "(%08lx:%08lx, %08lx, %08lx, %08lx)\n",
245 a, b, base, limit, base+limit);
247 fail:
248 return 0;
250 flip:
251 limit = (limit >> 12) - 1;
252 a &= ~0x0ffff; a |= limit & 0x0ffff;
253 b &= ~0xf0000; b |= limit & 0xf0000;
254 b ^= _SEGMENT_EC; /* grows-up <-> grows-down */
255 /* NB. These can't fault. Checked readable above; must also be writable. */
256 table[2*idx+0] = a;
257 table[2*idx+1] = b;
258 return 1;
259 }
261 /*
262 * Called from the general-protection fault handler to attempt to decode
263 * and emulate an instruction that depends on 4GB segments.
264 */
265 int gpf_emulate_4gb(struct cpu_user_regs *regs)
266 {
267 struct vcpu *d = current;
268 struct trap_info *ti;
269 struct trap_bounce *tb;
270 u8 modrm, mod, reg, rm, decode;
271 void *memreg;
272 unsigned long offset;
273 u8 disp8;
274 u32 disp32 = 0;
275 u8 *eip; /* ptr to instruction start */
276 u8 *pb, b; /* ptr into instr. / current instr. byte */
277 int gs_override = 0;
279 /* WARNING: We only work for ring-3 segments. */
280 if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) )
281 goto fail;
283 if ( !linearise_address((u16)regs->cs, regs->eip, (unsigned long *)&eip) )
284 {
285 dprintk(XENLOG_DEBUG, "Cannot linearise %04x:%08x\n",
286 regs->cs, regs->eip);
287 goto fail;
288 }
290 /* Parse prefix bytes. We're basically looking for segment override. */
291 for ( pb = eip; ; pb++ )
292 {
293 if ( get_user(b, pb) )
294 {
295 dprintk(XENLOG_DEBUG,
296 "Fault while accessing byte %ld of instruction\n",
297 (long)(pb-eip));
298 goto page_fault;
299 }
301 if ( (pb - eip) >= 15 )
302 {
303 dprintk(XENLOG_DEBUG, "Too many instruction prefixes for a "
304 "legal instruction\n");
305 goto fail;
306 }
308 switch ( b )
309 {
310 case 0x67: /* Address-size override */
311 case 0x2e: /* CS override */
312 case 0x3e: /* DS override */
313 case 0x26: /* ES override */
314 case 0x64: /* FS override */
315 case 0x36: /* SS override */
316 dprintk(XENLOG_DEBUG, "Unhandled prefix %02x\n", b);
317 goto fail;
318 case 0x66: /* Operand-size override */
319 case 0xf0: /* LOCK */
320 case 0xf2: /* REPNE/REPNZ */
321 case 0xf3: /* REP/REPE/REPZ */
322 break;
323 case 0x65: /* GS override */
324 gs_override = 1;
325 break;
326 default: /* Not a prefix byte */
327 goto done_prefix;
328 }
329 }
330 done_prefix:
332 if ( !gs_override )
333 {
334 dprintk(XENLOG_DEBUG, "Only instructions with GS override\n");
335 goto fail;
336 }
338 decode = insn_decode[b]; /* opcode byte */
339 pb++;
340 if ( decode == 0 )
341 {
342 dprintk(XENLOG_DEBUG, "Unsupported opcode %02x\n", b);
343 goto fail;
344 }
346 if ( !(decode & HAS_MODRM) )
347 {
348 /* Must be a <disp32>, or bail. */
349 if ( (decode & 7) != 4 )
350 goto fail;
352 if ( get_user(offset, (u32 *)pb) )
353 {
354 dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n");
355 goto page_fault;
356 }
357 pb += 4;
359 goto skip_modrm;
360 }
362 /*
363 * Mod/RM processing.
364 */
366 if ( get_user(modrm, pb) )
367 {
368 dprintk(XENLOG_DEBUG, "Fault while extracting modrm byte\n");
369 goto page_fault;
370 }
372 pb++;
374 mod = (modrm >> 6) & 3;
375 reg = (modrm >> 3) & 7;
376 rm = (modrm >> 0) & 7;
378 if ( rm == 4 )
379 {
380 dprintk(XENLOG_DEBUG, "FIXME: Add decoding for the SIB byte.\n");
381 goto fixme;
382 }
384 /* Decode R/M field. */
385 memreg = decode_register(rm, regs, 0);
387 /* Decode Mod field. */
388 switch ( modrm >> 6 )
389 {
390 case 0:
391 disp32 = 0;
392 if ( rm == 5 ) /* disp32 rather than (EBP) */
393 {
394 memreg = NULL;
395 if ( get_user(disp32, (u32 *)pb) )
396 {
397 dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
398 goto page_fault;
399 }
400 pb += 4;
401 }
402 break;
404 case 1:
405 if ( get_user(disp8, pb) )
406 {
407 dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
408 goto page_fault;
409 }
410 pb++;
411 disp32 = (disp8 & 0x80) ? (disp8 | ~0xff) : disp8;;
412 break;
414 case 2:
415 if ( get_user(disp32, (u32 *)pb) )
416 {
417 dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
418 goto page_fault;
419 }
420 pb += 4;
421 break;
423 case 3:
424 dprintk(XENLOG_DEBUG, "Not a memory operand!\n");
425 goto fail;
426 }
428 offset = disp32;
429 if ( memreg != NULL )
430 offset += *(u32 *)memreg;
432 skip_modrm:
433 if ( !fixup_seg((u16)regs->gs, offset) )
434 goto fail;
436 /* Success! */
437 perfc_incrc(seg_fixups);
439 /* If requested, give a callback on otherwise unused vector 15. */
440 if ( VM_ASSIST(d->domain, VMASST_TYPE_4gb_segments_notify) )
441 {
442 ti = &d->arch.guest_context.trap_ctxt[15];
443 tb = &d->arch.trap_bounce;
444 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
445 tb->error_code = pb - eip;
446 tb->cs = ti->cs;
447 tb->eip = ti->address;
448 if ( TI_GET_IF(ti) )
449 tb->flags |= TBF_INTERRUPT;
450 }
452 return EXCRET_fault_fixed;
454 fixme:
455 dprintk(XENLOG_DEBUG, "Undecodable instruction "
456 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
457 "caused GPF(0) at %04x:%08x\n",
458 eip[0], eip[1], eip[2], eip[3],
459 eip[4], eip[5], eip[6], eip[7],
460 regs->cs, regs->eip);
461 fail:
462 return 0;
464 page_fault:
465 propagate_page_fault((unsigned long)pb, 0); /* read fault */
466 return EXCRET_fault_fixed;
467 }
469 /*
470 * Local variables:
471 * mode: C
472 * c-set-style: "BSD"
473 * c-basic-offset: 4
474 * tab-width: 4
475 * indent-tabs-mode: nil
476 * End:
477 */