Annotation of tme/libtme/host/x86/rc-x86-tlb.c, revision 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.