Annotation of tme/libtme/host/x86/rc-x86-tlb.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.