|
|
1.1 root 1: /* $Id: rc-x86-tlb.c,v 1.1 2010/01/15 03:05:59 fredette Exp $ */
2:
3: /* libtme/host/x86/rc-x86-tlb.c - x86 host recode TLB support: */
4:
5: /*
6: * Copyright (c) 2008, 2009 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: _TME_RCSID("$Id: rc-x86-tlb.c,v 1.1 2010/01/15 03:05:59 fredette Exp $");
37:
38: /* macros: */
39:
40: /* the x86 register for the TLB entry pointer for a TLB busy or unbusy: */
41: #define TME_RECODE_X86_REG_TLB (TME_RECODE_X86_REG_D)
42:
43: /* the x86 register for scratch values during a TLB busy: */
44: #define TME_RECODE_X86_REG_TLB_SCRATCH (TME_RECODE_X86_REG_C)
45:
46: /* types: */
47:
48: /* a recode x86 TLB type: */
49: struct tme_recode_x86_tlb_type {
50:
51: /* the generic TLB type: */
52: struct tme_recode_tlb_type tme_recode_tlb_type;
53:
54: /* the pointer in the thunk build memory of any assist jump for
55: the most-significant half of a double-host-size guest address.
56: at this assist jump, the guest address is unmodified: */
57: tme_uint8_t *tme_recode_x86_tlb_type_assist_jmp_address_ok;
58:
59: /* the pointer in the thunk build memory of the main assist jump.
60: at this assist jump, the (least-significant half of the) guest
61: address has been exclusive-ORed with the (least-significant half
62: of the) TLB page: */
63: tme_uint8_t *tme_recode_x86_tlb_type_assist_jmp;
64: };
65:
66: /* this returns the host register number for the address (on entry,
67: the guest address, on exit, the host address) for a TLB busy: */
68: /* NB: for a double-host-size guest, the guest address is in the a:bp
69: register pair, otherwise it's in the a register. NB that we
70: primarily deal with only a host-sized part: */
71: static inline unsigned long
72: _tme_recode_x86_tlb_reg_host_address(const struct tme_recode_ic *ic)
73: {
74: assert (tme_recode_x86_reg_from_host[TME_RECODE_X86_REG_HOST_FREE_CALL]
75: == TME_RECODE_X86_REG_A);
76: assert (tme_recode_x86_reg_from_host[TME_RECODE_X86_REG_HOST_FREE_CALL - 1]
77: == TME_RECODE_X86_REG_BP);
78: return (TME_RECODE_X86_REG_HOST_FREE_CALL
79: - (TME_RECODE_SIZE_IS_DOUBLE_HOST(ic->tme_recode_ic_reg_size) != 0));
80: }
81:
82: /* this emits an instruction that references a TLB entry: */
83: static tme_uint8_t *
84: _tme_recode_x86_tlb_ref(tme_uint8_t *thunk_bytes,
85: unsigned int size,
86: unsigned int opcode,
87: unsigned int reg_x86_tlb,
88: unsigned int tlb_offset,
89: tme_uint8_t opreg)
90: {
91: unsigned int rex;
92:
93: /* emit any rex prefix: */
94: rex = TME_RECODE_X86_REX_B(0, reg_x86_tlb);
95: if (opcode != TME_RECODE_X86_OPCODE_GRP1_Ib_Eb
96: && opcode != TME_RECODE_X86_OPCODE_MOV_Ib_Eb) {
97: assert (size <= TME_RECODE_SIZE_HOST);
98: rex |= TME_RECODE_X86_REX_R(size, opreg);
99: }
100: if (rex != 0) {
101: *(thunk_bytes++) = rex;
102: }
103:
104: /* emit the opcode: */
105: thunk_bytes[0] = opcode;
106:
107: /* emit the ModR/M byte and an optional 8-bit displacement: */
108: assert (tlb_offset < 0x80);
109: thunk_bytes[1]
110: = TME_RECODE_X86_MOD_OPREG_RM((tlb_offset
111: ? TME_RECODE_X86_MOD_RM_EA_DISP8(reg_x86_tlb)
112: : TME_RECODE_X86_MOD_RM_EA(reg_x86_tlb)),
113: TME_RECODE_X86_REG(opreg));
114: thunk_bytes += 2;
115: if (tlb_offset) {
116: *(thunk_bytes++) = tlb_offset;
117: }
118:
119: return (thunk_bytes);
120: }
121:
122: /* this emits instructions that unbusy a TLB entry: */
123: static void
124: _tme_recode_x86_tlb_unbusy(struct tme_recode_ic *ic,
125: unsigned long tlb_offset_token)
126: {
127: unsigned int reg_x86_tlb;
128: tme_uint8_t *thunk_bytes;
129:
130: /* get the x86 register with the TLB entry pointer or token
131: pointer: */
132: reg_x86_tlb = TME_RECODE_X86_REG_TLB;
133:
134: /* start more instructions: */
135: tme_recode_x86_insns_start(ic, thunk_bytes);
136:
137: #if !TME_THREADS_COOPERATIVE || !defined(TME_NO_DEBUG_LOCKS)
138:
139: /* unbusy the TLB entry: */
140: thunk_bytes
141: = _tme_recode_x86_tlb_ref(thunk_bytes,
142: TME_RECODE_SIZE_8,
143: TME_RECODE_X86_OPCODE_MOV_Ib_Eb,
144: reg_x86_tlb,
145: (tlb_offset_token
146: + ((unsigned long)
147: &((struct tme_token *) 0)->tme_token_busy)),
148: 0 /* undefined */);
149: *(thunk_bytes++) = 0;
150:
151: #endif /* !TME_THREADS_COOPERATIVE || !defined(TME_NO_DEBUG_LOCKS) */
152:
153: /* finish these instructions: */
154: tme_recode_x86_insns_finish(ic, thunk_bytes);
155: }
156:
157: /* this emits instructions that find, busy, and check a TLB entry: */
158: static void
159: _tme_recode_x86_tlb_busy(struct tme_recode_ic *ic,
160: const struct tme_recode_address_type *address_type,
161: struct tme_recode_x86_tlb_type *x86_tlb_type)
162: {
163: unsigned int reg_x86_address;
164: struct tme_recode_insn insn_buffer;
165: tme_uint8_t *thunk_bytes;
166: unsigned int reg_x86_tlb;
167: unsigned int reg_x86_scratch;
168: unsigned int reg_x86_tlb_flags;
169: unsigned int rex;
170: tme_uint32_t address_mask_tlb_index_one;
171: unsigned long tlb_factor;
172: int shift_count;
173: unsigned int opcode;
174: unsigned int opreg;
175: tme_uint32_t tlb_flags;
176:
177: /* assume that this is not a double-host-size guest: */
178: x86_tlb_type->tme_recode_x86_tlb_type_assist_jmp_address_ok = (tme_uint8_t *) NULL;
179:
180: /* for a double-host-size guest, the guest address is in the a:bp
181: register pair, otherwise it's in the a register. NB that we
182: primarily deal with only a host-sized part: */
183: reg_x86_address
184: = tme_recode_x86_reg_from_host[_tme_recode_x86_tlb_reg_host_address(ic)];
185:
186: /* if the guest address size is less than the host size: */
187: if (address_type->tme_recode_address_type_size < TME_RECODE_SIZE_HOST) {
188:
189: /* zero- or sign-extend the guest address register to the host
190: size: */
191: insn_buffer.tme_recode_insn_opcode
192: = (address_type->tme_recode_address_type_signed
193: ? TME_RECODE_OPCODE_EXTS
194: : TME_RECODE_OPCODE_EXTZ);
195: insn_buffer.tme_recode_insn_operand_src[0] = _tme_recode_x86_tlb_reg_host_address(ic);
196: insn_buffer.tme_recode_insn_operand_src[1] = address_type->tme_recode_address_type_size;
197: insn_buffer.tme_recode_insn_operand_dst = insn_buffer.tme_recode_insn_operand_src[0];
198: _tme_recode_x86_insn_ext(ic, &insn_buffer);
199: }
200:
201: /* start more instructions: */
202: tme_recode_x86_insns_start(ic, thunk_bytes);
203:
204: /* we will hash the guest address into a TLB entry pointer in the
205: d register: */
206: reg_x86_tlb = TME_RECODE_X86_REG_TLB;
207:
208: /* we will use the c register for a multiply scratch register and
209: the TLB flags: */
210: reg_x86_scratch = TME_RECODE_X86_REG_TLB_SCRATCH;
211: reg_x86_tlb_flags = reg_x86_scratch;
212:
213: /* copy the least significant 32 bits of the guest address into the
214: TLB entry pointer register: */
215: thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
216: thunk_bytes[1]
217: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_address),
218: TME_RECODE_X86_REG(reg_x86_tlb));
219: thunk_bytes += 2;
220:
221: /* mask the TLB entry pointer register with the TLB index address
222: mask: */
223: thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Iz_Ev;
224: thunk_bytes[1]
225: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_tlb),
226: TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_AND));
227: *((tme_uint32_t *) &thunk_bytes[2]) = address_type->tme_recode_address_type_mask_tlb_index;
228: thunk_bytes += 2 + sizeof(tme_uint32_t);
229:
230: /* shift the TLB index in the TLB entry pointer register all the way
231: down to the right, except for any factors of two in the size of a
232: TLB entry: */
233: address_mask_tlb_index_one
234: = (address_type->tme_recode_address_type_mask_tlb_index
235: & (0 - address_type->tme_recode_address_type_mask_tlb_index));
236: tlb_factor = x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_sizeof;
237: for (shift_count = _tme_recode_x86_ffs(address_mask_tlb_index_one);
238: shift_count > 0 && (tlb_factor % 2) == 0;
239: shift_count--) {
240: tlb_factor /= 2;
241: }
242: if (shift_count > 0) {
243: thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP2_Ib_Ev;
244: thunk_bytes[1]
245: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_tlb),
246: TME_RECODE_X86_OPCODE_GRP2_SHR);
247: thunk_bytes[2] = shift_count;
248: thunk_bytes += 3;
249: }
250:
251: /* multiply the TLB index in the TLB entry pointer register by the
252: remaining factors in the size of a TLB entry: */
253: thunk_bytes
254: = _tme_recode_x86_emit_mul_constant(thunk_bytes,
255: TME_RECODE_SIZE_32,
256: reg_x86_tlb,
257: tlb_factor,
258: reg_x86_scratch);
259:
260: /* add in the address of tlb zero to finish the TLB entry pointer
261: register: */
262: rex
263: = (TME_RECODE_X86_REX_B(0, TME_RECODE_X86_REG_IC)
264: | TME_RECODE_X86_REX_X(reg_x86_tlb)
265: | TME_RECODE_X86_REX_R(TME_RECODE_SIZE_HOST, reg_x86_tlb));
266: if (rex != 0) {
267: *(thunk_bytes++) = rex;
268: }
269: thunk_bytes[0] = TME_RECODE_X86_OPCODE_LEA;
270: thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP32(TME_RECODE_X86_EA_BASE_SIB),
271: TME_RECODE_X86_REG(reg_x86_tlb));
272: thunk_bytes[2] = TME_RECODE_X86_SIB(TME_RECODE_X86_REG_IC, reg_x86_tlb, 1);
273: *((tme_int32_t *) &thunk_bytes[3]) = address_type->tme_recode_address_type_tlb0_ic_offset;
274: thunk_bytes += 3 + sizeof(tme_int32_t);
275:
276: #if !TME_THREADS_COOPERATIVE || !defined(TME_NO_DEBUG_LOCKS)
277:
278: /* busy the TLB entry: */
279: thunk_bytes
280: = _tme_recode_x86_tlb_ref(thunk_bytes,
281: TME_RECODE_SIZE_8,
282: TME_RECODE_X86_OPCODE_MOV_Ib_Eb,
283: reg_x86_tlb,
284: (x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_token
285: + ((unsigned long)
286: &((struct tme_token *) 0)->tme_token_busy)),
287: 0 /* undefined */);
288: *(thunk_bytes++) = 1;
289:
290: #endif /* !TME_THREADS_COOPERATIVE || !defined(TME_NO_DEBUG_LOCKS) */
291:
292: /* if this is a double-host-size guest: */
293: if (TME_RECODE_SIZE_IS_DOUBLE_HOST(ic->tme_recode_ic_reg_size)) {
294:
295: /* compare the most-significant half of the guest address to the
296: most-significant half of the TLB entry page: */
297:
298: /* assume that either the guest address size is the guest
299: register size, or the guest address is sign-extended: */
300: opcode
301: = (TME_RECODE_X86_OPCODE_BINOP_CMP
302: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
303: opreg
304: = TME_RECODE_X86_REG(tme_recode_x86_reg_from_host
305: [_tme_recode_x86_tlb_reg_host_address(ic) + 1]);
306:
307: /* if the guest address size is less than the guest register size: */
308: if (address_type->tme_recode_address_type_size < ic->tme_recode_ic_reg_size) {
309:
310: /* if the guest address is sign-extended: */
311: if (address_type->tme_recode_address_type_signed) {
312:
313: /* sign-extend the guest address to double host size: */
314: /* NB: the guest address has already been sign-extended to
315: host size by the _tme_recode_x86_insn_ext() call above: */
316: _tme_recode_x86_emit_reg_binop(thunk_bytes,
317: TME_RECODE_X86_OPCODE_BINOP_MOV,
318: reg_x86_address,
319: opreg);
320: _tme_recode_x86_emit_reg_binop(thunk_bytes,
321: TME_RECODE_X86_OPCODE_BINOP_ADD,
322: reg_x86_address,
323: opreg);
324: _tme_recode_x86_emit_reg_binop(thunk_bytes,
325: TME_RECODE_X86_OPCODE_BINOP_SBB,
326: opreg,
327: opreg);
328: }
329:
330: /* otherwise, the guest address is unsigned: */
331: else {
332:
333: /* we can simply compare the most-significant half of the
334: TLB entry page to zero: */
335: opcode = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
336: opreg = TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_CMP);
337: }
338: }
339:
340: /* do the comparison: */
341: thunk_bytes
342: = _tme_recode_x86_tlb_ref(thunk_bytes,
343: TME_RECODE_SIZE_HOST,
344: opcode,
345: reg_x86_tlb,
346: (x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_page
347: + TME_BIT(TME_RECODE_SIZE_HOST
348: - TME_RECODE_SIZE_8)),
349: opreg);
350: if (opcode == TME_RECODE_X86_OPCODE_GRP1_Ib_Ev) {
351: *(thunk_bytes++) = 0;
352: }
353:
354: /* if the comparison fails, jump to the assist code: */
355: x86_tlb_type->tme_recode_x86_tlb_type_assist_jmp_address_ok = thunk_bytes;
356: thunk_bytes
357: = _tme_recode_x86_emit_jmp(thunk_bytes,
358: TME_RECODE_X86_OPCODE_JCC(TME_RECODE_X86_COND_NOT
359: | TME_RECODE_X86_COND_Z),
360: (tme_uint8_t *) NULL);
361: }
362:
363: /* get the guest fixed TLB flags for this operation: */
364: tlb_flags = address_type->tme_recode_address_type_tlb_flags;
365:
366: /* in the TLB flags, set TME_RECODE_X86_TLB_FLAG_INVALID(ic), and
367: also set all of the bits below it, down to bit zero.
368:
369: eventually, we will set the carry flag when a recode TLB entry is
370: found valid, and use an add-with-carry instruction to clear all
371: of these bits so they won't cause an assist (although this will
372: carry out into the next TLB flag bit, which is unused and must
373: always be clear in the TLB flags in TLB entries, otherwise it
374: will cause an assist): */
375: assert ((tlb_flags
376: & ((TME_RECODE_X86_TLB_FLAG_INVALID(ic) * 2)
377: + TME_RECODE_X86_TLB_FLAG_INVALID(ic)
378: + (TME_RECODE_X86_TLB_FLAG_INVALID(ic) - 1))) == 0);
379: tlb_flags
380: += (TME_RECODE_X86_TLB_FLAG_INVALID(ic)
381: + (TME_RECODE_X86_TLB_FLAG_INVALID(ic) - 1));
382:
383: /* if this address type includes a context: */
384: if (address_type->tme_recode_address_type_context_ic_offset >= 0) {
385:
386: /* guest contexts can't be bigger than a host register: */
387: assert (address_type->tme_recode_address_type_context_size <= TME_RECODE_SIZE_HOST);
388:
389: /* emit one of:
390: movzb context(%tlb), %reg
391: movzw context(%tlb), %reg
392: movl context(%tlb), %reg
393: movq context(%tlb), %reg
394:
395: where %reg is the TLB flags register:
396: */
397: rex = (TME_RECODE_X86_REX_B(0, reg_x86_tlb)
398: | TME_RECODE_X86_REX_R(TME_MAX(TME_RECODE_SIZE_32,
399: address_type->tme_recode_address_type_context_size),
400: reg_x86_tlb_flags));
401: if (rex != 0) {
402: *(thunk_bytes++) = rex;
403: }
404: if (address_type->tme_recode_address_type_context_size < TME_RECODE_SIZE_32) {
405: *(thunk_bytes++) = TME_RECODE_X86_OPCODE_ESC_0F;
406: thunk_bytes[0]
407: = (address_type->tme_recode_address_type_context_size == TME_RECODE_SIZE_8
408: ? TME_RECODE_X86_OPCODE0F_MOVZ_Eb_Gv
409: : TME_RECODE_X86_OPCODE0F_MOVZ_Ew_Gv);
410: }
411: else {
412: thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_MOV + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
413: }
414: assert (x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_context < 0x80);
415: thunk_bytes[1]
416: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_EA_DISP8(reg_x86_tlb),
417: TME_RECODE_X86_REG(reg_x86_tlb_flags));
418: thunk_bytes[2] = x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_context;
419: thunk_bytes += 3;
420:
421: /* the guest context register is a tme_bus_context_t, which must
422: be at least a tme_uint32_t, because we read that much in the
423: next instruction: */
424: assert (sizeof(tme_bus_context_t) >= sizeof(tme_uint32_t));
425:
426: /* exclusive-or the guest context register into the TLB context in
427: the TLB flags register: */
428: rex = (TME_RECODE_X86_REX_B(0, TME_RECODE_X86_REG_IC)
429: | TME_RECODE_X86_REX_R(TME_MAX(TME_RECODE_SIZE_32,
430: address_type->tme_recode_address_type_context_size),
431: reg_x86_tlb_flags));
432: if (rex != 0) {
433: *(thunk_bytes++) = rex;
434: }
435: thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_XOR + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
436: thunk_bytes
437: = _tme_recode_x86_emit_ic_modrm(&thunk_bytes[1],
438: address_type->tme_recode_address_type_context_ic_offset,
439: reg_x86_tlb_flags);
440:
441: /* set the carry flag if the context register doesn't match the
442: TLB context, by negating the TLB flags register: */
443: rex = TME_RECODE_X86_REX_B(TME_MAX(TME_RECODE_SIZE_32,
444: address_type->tme_recode_address_type_context_size),
445: reg_x86_tlb_flags);
446: if (rex != 0) {
447: *(thunk_bytes++) = rex;
448: }
449: thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP3_Ev;
450: thunk_bytes[1] = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_tlb_flags),
451: TME_RECODE_X86_OPCODE_GRP3_NEG);
452: thunk_bytes += 2;
453:
454: /* initialize the TLB flags register with the read/write flags,
455: shifted left by one. we'll eventually rotate the register to
456: the right by one: */
457: rex = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, reg_x86_tlb_flags);
458: if (rex != 0) {
459: *(thunk_bytes++) = rex;
460: }
461: thunk_bytes[0] = TME_RECODE_X86_OPCODE_MOV_Iv_Gv(reg_x86_tlb_flags);
462: *((tme_uint32_t *) &thunk_bytes[1]) = (tlb_flags << 1);
463: thunk_bytes += 1 + sizeof(tme_uint32_t);
464:
465: /* this add with carry will set bit zero of the read/write flags
466: register if the context register doesn't match the TLB
467: context: */
468: rex = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, reg_x86_tlb_flags);
469: if (rex != 0) {
470: *(thunk_bytes++) = rex;
471: }
472: thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
473: thunk_bytes[1]
474: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_tlb_flags),
475: TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_ADC));
476: thunk_bytes[2] = 0;
477: thunk_bytes += 3;
478:
479: /* rotate the read/write flags register to the right by one. this
480: will rotate bit zero around and up to
481: TME_RECODE_RW_FLAG_CONTEXT_MISMATCH(ic), and put all of the
482: other read/write flags in their correct positions: */
483: rex = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, reg_x86_tlb_flags);
484: if (rex != 0) {
485: *(thunk_bytes++) = rex;
486: }
487: thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP2_1_Ev;
488: thunk_bytes[1]
489: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_tlb_flags),
490: TME_RECODE_X86_OPCODE_GRP2_ROR);
491: thunk_bytes += 2;
492: }
493:
494: /* make sure the token busy write completes before the token invalid
495: read: */
496: if (!TME_THREADS_COOPERATIVE) {
497: thunk_bytes[0] = TME_RECODE_X86_OPCODE_ESC_0F;
498: thunk_bytes[1] = TME_RECODE_X86_OPCODE0F_GRP15;
499: thunk_bytes[2] = TME_RECODE_X86_OPCODE0F_GRP15_MFENCE;
500: thunk_bytes += 3;
501: }
502:
503: /* set the carry flag if this TLB entry is still valid: */
504: thunk_bytes
505: = _tme_recode_x86_tlb_ref(thunk_bytes,
506: TME_RECODE_SIZE_8,
507: TME_RECODE_X86_OPCODE_GRP1_Ib_Eb,
508: reg_x86_tlb,
509: (x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_token
510: + ((unsigned long)
511: &((struct tme_token *) 0)->tme_token_invalid)),
512: TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_CMP));
513: *(thunk_bytes++) = 1;
514:
515: /* if this address type includes a context: */
516: if (address_type->tme_recode_address_type_context_ic_offset < 0) {
517:
518: /* initialize the TLB flags register with the TLB flags: */
519: rex = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, reg_x86_tlb_flags);
520: if (rex != 0) {
521: *(thunk_bytes++) = rex;
522: }
523: thunk_bytes[0] = TME_RECODE_X86_OPCODE_MOV_Iv_Gv(reg_x86_tlb_flags);
524: *((tme_uint32_t *) &thunk_bytes[1]) = tlb_flags;
525: thunk_bytes += 1 + sizeof(tme_uint32_t);
526: }
527:
528: /* add one to the read/write flags register if the TLB entry is
529: still valid. adding one will clear all of the
530: (TME_RECODE_X86_TLB_FLAG_INVALID(ic) - 1) bits and
531: TME_RECODE_X86_TLB_FLAG_INVALID(ic), so they won't cause an
532: assist (but this will set the next bit, which is unused and must
533: always be clear in the read/write flags in TLB entries so it
534: doesn't cause an assist).
535:
536: not adding one will leave the
537: (TME_RECODE_X86_TLB_FLAG_INVALID(ic) - 1) bits set, but this
538: doesn't matter, because TME_RECODE_X86_TLB_FLAG_INVALID(ic) will
539: still be set and will definitely cause an assist: */
540: rex = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_32, reg_x86_tlb_flags);
541: if (rex != 0) {
542: *(thunk_bytes++) = rex;
543: }
544: thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP1_Ib_Ev;
545: thunk_bytes[1]
546: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_tlb_flags),
547: TME_RECODE_X86_OPCODE_GRP1_BINOP(TME_RECODE_X86_OPCODE_BINOP_ADC));
548: thunk_bytes[2] = 0;
549: thunk_bytes += 3;
550:
551: /* exclusive-or the (least-significant half of the) guest address
552: with the (least-significant half of the) TLB entry page, to
553: convert the guest address into the TLB entry page offset: */
554: thunk_bytes
555: = _tme_recode_x86_tlb_ref(thunk_bytes,
556: TME_MIN(TME_RECODE_SIZE_HOST,
557: address_type->tme_recode_address_type_size),
558: (TME_RECODE_X86_OPCODE_BINOP_XOR
559: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv),
560: reg_x86_tlb,
561: x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_page,
562: TME_RECODE_X86_REG(reg_x86_address));
563:
564: /* if this address type has TLB flags in the guest IC to and with
565: the fixed TLB flags from the address type: */
566: if (address_type->tme_recode_address_type_tlb_flags_ic_offset >= 0) {
567:
568: /* and in the read/write flags from the guest IC: */
569: rex
570: = (TME_RECODE_X86_REX_B(0, TME_RECODE_X86_REG_IC)
571: | TME_RECODE_X86_REX_R(TME_RECODE_SIZE_32, reg_x86_tlb_flags));
572: if (rex != 0) {
573: *(thunk_bytes++) = rex;
574: }
575: thunk_bytes[0] = (TME_RECODE_X86_OPCODE_BINOP_AND + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv);
576: thunk_bytes
577: = _tme_recode_x86_emit_ic_modrm(&thunk_bytes[1],
578: address_type->tme_recode_address_type_tlb_flags_ic_offset,
579: reg_x86_tlb_flags);
580: }
581:
582: /* and in the TLB flags from the TLB entry: */
583: thunk_bytes
584: = _tme_recode_x86_tlb_ref(thunk_bytes,
585: TME_RECODE_SIZE_32,
586: (TME_RECODE_X86_OPCODE_BINOP_AND
587: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv),
588: reg_x86_tlb,
589: x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_flags,
590: TME_RECODE_X86_REG(reg_x86_tlb_flags));
591:
592: /* or the TLB entry page offset into the TLB flags register: */
593: _tme_recode_x86_emit_reg_binop(thunk_bytes,
594: TME_RECODE_X86_OPCODE_BINOP_OR,
595: reg_x86_address,
596: reg_x86_tlb_flags);
597:
598: /* test if any TLB flags above the TLB page size are set, or if any
599: TLB page offset bits are set that don't meet the access' minimum
600: alignment: */
601: /* NB that this will catch TLB flags that survived all of
602: the mask ands, and also a TLB page mismatch, since the mismatch
603: bits will be above the TLB page size: */
604: rex = TME_RECODE_X86_REX_B(TME_RECODE_SIZE_HOST, reg_x86_tlb_flags);
605: if (rex != 0) {
606: *(thunk_bytes++) = rex;
607: }
608: thunk_bytes[0] = TME_RECODE_X86_OPCODE_GRP3_Ev;
609: thunk_bytes[1]
610: = TME_RECODE_X86_MOD_OPREG_RM(TME_RECODE_X86_MOD_RM_REG(reg_x86_tlb_flags),
611: TME_RECODE_X86_OPCODE_GRP3_TEST);
612: *((tme_int32_t *) &thunk_bytes[2])
613: = ((0 - ic->tme_recode_ic_tlb_page_size)
614: | (address_type->tme_recode_address_type_align_min - 1));
615: thunk_bytes += 2 + sizeof(tme_int32_t);
616:
617: /* if the test fails, jump to the assist code: */
618: x86_tlb_type->tme_recode_x86_tlb_type_assist_jmp = thunk_bytes;
619: thunk_bytes
620: = _tme_recode_x86_emit_jmp(thunk_bytes,
621: TME_RECODE_X86_OPCODE_JCC(TME_RECODE_X86_COND_NOT
622: | TME_RECODE_X86_COND_Z),
623: (tme_uint8_t *) NULL);
624:
625: /* add the TLB entry memory base to the TLB entry page offset, to
626: make the host address: */
627: thunk_bytes
628: = _tme_recode_x86_tlb_ref(thunk_bytes,
629: TME_RECODE_SIZE_HOST,
630: (TME_RECODE_X86_OPCODE_BINOP_ADD
631: + TME_RECODE_X86_OPCODE_BINOP_Ev_Gv),
632: reg_x86_tlb,
633: x86_tlb_type->tme_recode_tlb_type.tme_recode_tlb_type_offset_memory,
634: TME_RECODE_X86_REG(reg_x86_address));
635:
636: /* finish these instructions: */
637: tme_recode_x86_insns_finish(ic, thunk_bytes);
638: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.