|
|
1.1 ! root 1: /* $Id: sparc-rc-ls.c,v 1.6 2010/06/05 17:08:57 fredette Exp $ */ ! 2: ! 3: /* ic/sparc/sparc-rc-cc.c - SPARC recode ld/st support: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2008 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: #if TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32 ! 37: ! 38: _TME_RCSID("$Id: sparc-rc-ls.c,v 1.6 2010/06/05 17:08:57 fredette Exp $"); ! 39: ! 40: /* macros: */ ! 41: ! 42: /* rename various things by the architecture size: */ ! 43: #define _tme_sparc_recode_ls_assist_check _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_ls_assist_check) ! 44: #define _tme_sparc_recode_ls_assist_ld _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_ls_assist_ld) ! 45: #define _tme_sparc_recode_ls_assist_st _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_ls_assist_st) ! 46: #define tme_sparc_recode_ls_tlb_update _TME_SPARC_RECODE_SIZE(tme_sparc,_recode_ls_tlb_update) ! 47: #define _tme_sparc_recode_ls_init _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_ls_init) ! 48: ! 49: #endif /* TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32 */ ! 50: ! 51: /* this checks whether a load or store needs an assist: */ ! 52: void ! 53: _tme_sparc_recode_ls_assist_check(const struct tme_sparc *ic, ! 54: tme_recode_uguest_t recode_address, ! 55: int assisted) ! 56: { ! 57: tme_uint32_t sparc_insn; ! 58: unsigned int reg_rs2; ! 59: tme_sparc_ireg_t sparc_address; ! 60: unsigned int reg_rs1; ! 61: tme_uint32_t sparc_opcode; ! 62: tme_bus_context_t context; ! 63: tme_uint32_t asi_mask_flags_assist; ! 64: unsigned int asi; ! 65: tme_uint32_t asi_mask_flags; ! 66: const struct tme_sparc_tlb *dtlb; ! 67: tme_uint32_t asi_mask; ! 68: tme_uint32_t dtlb_page_size; ! 69: tme_sparc_ireg_t sparc_page; ! 70: ! 71: /* get the instruction: */ ! 72: sparc_insn = ic->_tme_sparc_insn; ! 73: ! 74: /* if the i bit is zero: */ ! 75: if ((sparc_insn & TME_BIT(13)) == 0) { ! 76: ! 77: /* decode rs2: */ ! 78: reg_rs2 = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2); ! 79: TME_SPARC_REG_INDEX(ic, reg_rs2); ! 80: sparc_address = ic->tme_sparc_ireg(reg_rs2); ! 81: } ! 82: ! 83: /* otherwise, the i bit is one: */ ! 84: else { ! 85: ! 86: /* decode simm13: */ ! 87: sparc_address = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x1fff); ! 88: } ! 89: ! 90: /* decode rs1: */ ! 91: reg_rs1 = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1); ! 92: TME_SPARC_REG_INDEX(ic, reg_rs1); ! 93: sparc_address += ic->tme_sparc_ireg(reg_rs1); ! 94: ! 95: /* mask the addresses: */ ! 96: if (TME_SPARC_VERSION(ic) >= 9) { ! 97: sparc_address &= ic->tme_sparc_address_mask; ! 98: recode_address &= ic->tme_sparc_address_mask; ! 99: } ! 100: ! 101: /* check the address: */ ! 102: assert (sparc_address == (tme_sparc_ireg_t) recode_address); ! 103: ! 104: /* if this instruction is being assisted, return now: */ ! 105: if (assisted) { ! 106: return; ! 107: } ! 108: ! 109: /* the verifier must not be on: */ ! 110: assert (!_tme_sparc_recode_verify_on); ! 111: ! 112: /* get the instruction opcode: */ ! 113: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19)); ! 114: ! 115: /* the address must be aligned: */ ! 116: assert ((sparc_address ! 117: & ((TME_SPARC_VERSION(ic) >= 9 ! 118: && (sparc_opcode == 0x0b /* v9: ldx */ ! 119: || sparc_opcode == 0x0e)) ! 120: ? (sizeof(tme_sparc_ireg_t) - 1) ! 121: : ((sparc_opcode - 1) ! 122: & (sizeof(tme_uint32_t) - 1)))) == 0); ! 123: ! 124: /* assume that this load or store uses the default context: */ ! 125: context = ic->tme_sparc_memory_context_default; ! 126: ! 127: /* assume that only DTLB ASI mask flags for special ASIs must be assisted: */ ! 128: asi_mask_flags_assist = TME_SPARC_ASI_MASK_FLAG_SPECIAL; ! 129: ! 130: /* if this is a v9 CPU, assume that a load or store to a no-fault ! 131: address must be assisted: */ ! 132: if (TME_SPARC_VERSION(ic) >= 9) { ! 133: asi_mask_flags_assist += TME_SPARC64_ASI_FLAG_NO_FAULT; ! 134: } ! 135: ! 136: /* if this is a load or store with an alternate space: */ ! 137: if (__tme_predict_false(sparc_insn & TME_BIT(19 + 4))) { ! 138: ! 139: /* get the ASI: */ ! 140: asi = ((TME_SPARC_VERSION(ic) >= 9 ! 141: && (sparc_insn & TME_BIT(13))) ! 142: ? ic->tme_sparc64_ireg_asi ! 143: : TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xff << 5))); ! 144: ! 145: /* get the flags for this ASI: */ ! 146: asi_mask_flags = ic->tme_sparc_asis[asi].tme_sparc_asi_mask_flags; ! 147: ! 148: /* if this is a v9 CPU: */ ! 149: if (TME_SPARC_VERSION(ic) >= 9) { ! 150: ! 151: /* get the context: */ ! 152: context ! 153: = (((TME_SPARC_MEMORY_FLAGS(ic) & TME_SPARC_MEMORY_FLAG_HAS_NUCLEUS) ! 154: && (asi_mask_flags & TME_SPARC64_ASI_MASK_FLAG_INSN_NUCLEUS)) ! 155: ? 0 ! 156: : (asi_mask_flags & TME_SPARC64_ASI_FLAG_SECONDARY) ! 157: ? ic->tme_sparc_memory_context_secondary ! 158: : ic->tme_sparc_memory_context_primary); ! 159: } ! 160: ! 161: /* this must be a load from an alternate space: */ ! 162: assert ((sparc_insn & TME_BIT(19 + 2)) == 0); ! 163: ! 164: /* this must be a v9 CPU: */ ! 165: assert (TME_SPARC_VERSION(ic) >= 9); ! 166: ! 167: /* this v9 CPU must not be in nucleus context: */ ! 168: /* NB: this implies that when a v9 CPU is in nucleus context, even ! 169: loads that specify an immediate no-fault ASI are assisted: */ ! 170: assert ((TME_SPARC_MEMORY_FLAGS(ic) & TME_SPARC_MEMORY_FLAG_HAS_NUCLEUS) == 0 ! 171: || ic->tme_sparc64_ireg_tl == 0); ! 172: ! 173: /* this ASI must be the default data ASI with the no-fault bit ! 174: set: */ ! 175: assert (asi ! 176: == (TME_SPARC_ASI_MASK_WHICH(ic->tme_sparc_asi_mask_data) ! 177: + TME_SPARC64_ASI_FLAG_NO_FAULT)); ! 178: ! 179: /* this load doesn't necessarily need an assist if it's to a ! 180: no-fault address: */ ! 181: asi_mask_flags_assist -= TME_SPARC64_ASI_FLAG_NO_FAULT; ! 182: } ! 183: ! 184: /* get the DTLB entry: */ ! 185: dtlb = &ic->tme_sparc_tlbs[TME_SPARC_DTLB_ENTRY(ic, TME_SPARC_TLB_HASH(ic, context, sparc_address))]; ! 186: ! 187: /* the DTLB entry must be valid: */ ! 188: assert (!tme_bus_tlb_is_invalid(&dtlb->tme_sparc_tlb_bus_tlb)); ! 189: ! 190: /* the DTLB entry must match the context: */ ! 191: assert (dtlb->tme_sparc_tlb_context == context ! 192: || dtlb->tme_sparc_tlb_context > ic->tme_sparc_memory_context_max); ! 193: ! 194: /* the DTLB entry must cover the page: */ ! 195: dtlb_page_size = (1 << ic->tme_sparc_tlb_page_size_log2); ! 196: sparc_page = sparc_address & (0 - (tme_sparc_ireg_t) dtlb_page_size); ! 197: assert ((((tme_sparc_ireg_t) dtlb->tme_sparc_tlb_addr_first) ! 198: <= sparc_page) ! 199: && (((tme_sparc_ireg_t) dtlb->tme_sparc_tlb_addr_last) ! 200: >= (sparc_page + dtlb_page_size - 1))); ! 201: ! 202: /* if the DTLB entry doesn't allow this privilege load or store: */ ! 203: asi_mask ! 204: = (TME_SPARC_VERSION(ic) >= 9 ! 205: ? (TME_SPARC_PRIV(ic) ! 206: ? TME_SPARC64_ASI_MASK_REQUIRED_UNRESTRICTED(!TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) ! 207: : TME_SPARC64_ASI_MASK_REQUIRED_UNRESTRICTED(TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER)) ! 208: : (TME_SPARC_PRIV(ic) ! 209: ? TME_SPARC32_ASI_MASK_SD ! 210: : TME_SPARC32_ASI_MASK_UD)); ! 211: assert (TME_SPARC_TLB_ASI_MASK_OK(dtlb, asi_mask)); ! 212: ! 213: /* the DTLB entry ASI flags must not require an assist: */ ! 214: assert ((dtlb->tme_sparc_tlb_asi_mask ! 215: & asi_mask_flags_assist) == 0); ! 216: ! 217: /* the DTLB entry must allow the fast load or store, and if this is ! 218: a store, it must not allow fast loads, or it must allow both to ! 219: the same memory: */ ! 220: assert ((sparc_insn & TME_BIT(19 + 2)) ! 221: ? (dtlb->tme_sparc_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF ! 222: && (dtlb->tme_sparc_tlb_emulator_off_read == TME_EMULATOR_OFF_UNDEF ! 223: || dtlb->tme_sparc_tlb_emulator_off_read == dtlb->tme_sparc_tlb_emulator_off_write)) ! 224: : (dtlb->tme_sparc_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF)); ! 225: } ! 226: ! 227: /* the assist function for ld instructions: */ ! 228: static tme_recode_uguest_t ! 229: _tme_sparc_recode_ls_assist_ld(struct tme_ic *_ic, ! 230: tme_recode_uguest_t address) ! 231: { ! 232: struct tme_sparc *ic; ! 233: tme_uint32_t sparc_insn; ! 234: tme_uint32_t sparc_opcode; ! 235: int insn_is_ld; ! 236: unsigned int reg_rd; ! 237: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) ! 238: tme_sparc_ireg_t rs1_buffer; ! 239: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) */ ! 240: tme_sparc_ireg_t rs2; ! 241: tme_sparc_ireg_t *_rs1; ! 242: ! 243: /* recover our ic: */ ! 244: ic = (struct tme_sparc *) _ic; ! 245: ! 246: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_ld); ! 247: ! 248: /* set PC_next_next from PC_next: */ ! 249: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) ! 250: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) ! 251: + sizeof(tme_uint32_t)); ! 252: ! 253: /* get the instruction: */ ! 254: sparc_insn = tme_sparc_recode_insn_current(ic); ! 255: ic->_tme_sparc_insn = sparc_insn; ! 256: ! 257: /* see if this instruction is a load: */ ! 258: sparc_opcode = 0x40 + TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19)); ! 259: insn_is_ld ! 260: = (sparc_insn >= 0xc0000000 ! 261: && _tme_sparc_recode_insn_opmap[sparc_opcode] == TME_SPARC_RECODE_INSN_LD); ! 262: ! 263: /* if this is a cooperative threading system: */ ! 264: if (TME_THREADS_COOPERATIVE) { ! 265: ! 266: /* this instruction must be the original load instruction from ! 267: when the instructions thunk was recoded. we have no way to ! 268: confirm this. if it's not, because this is a cooperative ! 269: threading system, that means that either ! 270: tme_sparc_recode_insn_assist_redispatch(), or ! 271: tme_sparc_recode(), or the host chain in failed to detect that ! 272: the page containing this PC is no longer cache-valid: */ ! 273: assert (insn_is_ld); ! 274: } ! 275: ! 276: /* otherwise, this isn't a cooperative threading system: */ ! 277: else { ! 278: ! 279: /* if this isn't a load instruction: */ ! 280: if (__tme_predict_false(!insn_is_ld)) { ! 281: abort(); ! 282: } ! 283: ! 284: /* otherwise, this is a load instruction: */ ! 285: ! 286: /* NB: it's possible that this load instruction is not the ! 287: original load instruction from when the instructions thunk was ! 288: recoded. we have no way of knowing if it is or isn't. if it ! 289: isn't, this new load instruction may have different rs1, rs2, ! 290: and rd fields than the original load instruction: */ ! 291: abort(); ! 292: } ! 293: ! 294: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[sparc_opcode]); ! 295: ! 296: /* decode rd: */ ! 297: reg_rd = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD); ! 298: TME_SPARC_REG_INDEX(ic, reg_rd); ! 299: ! 300: /* run the instruction: */ ! 301: rs2 = 0; ! 302: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) ! 303: rs1_buffer = address; ! 304: _rs1 = &rs1_buffer; ! 305: #else /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */ ! 306: _rs1 = &address; ! 307: #endif /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */ ! 308: #ifdef _TME_SPARC_RECODE_VERIFY ! 309: _tme_sparc_recode_ls_assist_check(ic, *_rs1, TRUE); ! 310: #endif /* _TME_SPARC_RECODE_VERIFY */ ! 311: (*ic->_tme_sparc_execute_opmap[sparc_opcode]) ! 312: (ic, ! 313: _rs1, ! 314: &rs2, ! 315: &ic->tme_sparc_ireg(reg_rd)); ! 316: ! 317: /* set %g0 to zero, in case the instruction changed it: */ ! 318: ic->tme_sparc_ireg(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G0) = 0; ! 319: ! 320: /* do any required redispatch: */ ! 321: /* NB: in a noncooperative threading system, this will do any needed ! 322: redispatch after we executed a new load instruction that is ! 323: different from the original load instruction from when the ! 324: instructions thunk was recoded. in that case, we can't return to ! 325: the instructions thunk since it will take our return value for ! 326: the rd register in the original instruction, not for the rd ! 327: register in the new instruction: */ ! 328: /* NB: in any threading system, this will do any needed redispatch ! 329: after a load instruction changes the state of the system such ! 330: that we can't return to the instructions thunk. this is very ! 331: unusual: */ ! 332: tme_sparc_recode_insn_assist_redispatch(ic); ! 333: ! 334: /* return the result: */ ! 335: return (ic->tme_sparc_ireg(reg_rd)); ! 336: } ! 337: ! 338: /* the assist function for st instructions: */ ! 339: static void ! 340: _tme_sparc_recode_ls_assist_st(struct tme_ic *_ic, ! 341: tme_recode_uguest_t address, ! 342: tme_recode_uguest_t rd) ! 343: { ! 344: struct tme_sparc *ic; ! 345: tme_uint32_t sparc_insn; ! 346: tme_uint32_t sparc_opcode; ! 347: int insn_is_st; ! 348: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) ! 349: tme_sparc_ireg_t rs1_buffer; ! 350: tme_sparc_ireg_t rd_buffer; ! 351: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) */ ! 352: tme_sparc_ireg_t *_rs1; ! 353: tme_sparc_ireg_t rs2; ! 354: tme_sparc_ireg_t *_rd; ! 355: ! 356: /* recover our ic: */ ! 357: ic = (struct tme_sparc *) _ic; ! 358: ! 359: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_st); ! 360: ! 361: /* set PC_next_next from PC_next: */ ! 362: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) ! 363: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) ! 364: + sizeof(tme_uint32_t)); ! 365: ! 366: /* get the instruction: */ ! 367: sparc_insn = tme_sparc_recode_insn_current(ic); ! 368: ic->_tme_sparc_insn = sparc_insn; ! 369: ! 370: /* see if this instruction is a store: */ ! 371: sparc_opcode = (0x40 + TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19))); ! 372: insn_is_st ! 373: = (sparc_insn >= 0xc0000000 ! 374: && _tme_sparc_recode_insn_opmap[sparc_opcode] == TME_SPARC_RECODE_INSN_ST); ! 375: ! 376: /* if this is a cooperative threading system: */ ! 377: if (TME_THREADS_COOPERATIVE) { ! 378: ! 379: /* this instruction must be the original store instruction from ! 380: when the instructions thunk was recoded. we have no way to ! 381: confirm this. if it's not, because this is a cooperative ! 382: threading system, that means that either ! 383: tme_sparc_recode_insn_assist_redispatch(), or ! 384: tme_sparc_recode(), or the host chain in failed to detect that ! 385: the page containing this PC is no longer cache-valid: */ ! 386: assert (insn_is_st); ! 387: } ! 388: ! 389: /* otherwise, this isn't a cooperative threading system: */ ! 390: else { ! 391: ! 392: /* if this isn't a store instruction: */ ! 393: if (__tme_predict_false(!insn_is_st)) { ! 394: abort(); ! 395: } ! 396: ! 397: /* otherwise, this is a store instruction: */ ! 398: ! 399: /* NB: it's possible that this store instruction is not the ! 400: original store instruction from when the instructions thunk was ! 401: recoded. we have no way of knowing if it is or isn't. if it ! 402: isn't, this new store instruction may have different rs1, rs2, ! 403: and rd fields than the original store instruction: */ ! 404: abort(); ! 405: } ! 406: ! 407: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[sparc_opcode]); ! 408: ! 409: /* run the store instruction: */ ! 410: rs2 = 0; ! 411: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) ! 412: rs1_buffer = address; ! 413: rd_buffer = rd; ! 414: _rs1 = &rs1_buffer; ! 415: _rd = &rd_buffer; ! 416: #else /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */ ! 417: _rs1 = &address; ! 418: _rd = &rd; ! 419: #endif /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */ ! 420: #ifdef _TME_SPARC_RECODE_VERIFY ! 421: _tme_sparc_recode_ls_assist_check(ic, *_rs1, TRUE); ! 422: #endif /* _TME_SPARC_RECODE_VERIFY */ ! 423: (*ic->_tme_sparc_execute_opmap[sparc_opcode]) ! 424: (ic, _rs1, &rs2, _rd); ! 425: ! 426: /* return no result: */ ! 427: tme_sparc_recode_insn_assist_redispatch(ic); ! 428: } ! 429: ! 430: /* this updates a recode DTLB entry: */ ! 431: void ! 432: tme_sparc_recode_ls_tlb_update(struct tme_sparc *ic, ! 433: const struct tme_sparc_ls *ls) ! 434: { ! 435: const struct tme_sparc_tlb *dtlb; ! 436: tme_uint32_t dtlb_page_size; ! 437: struct _TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,/**/) *recode_tlb; ! 438: tme_uint32_t rw_flags_tlb; ! 439: tme_sparc_ireg_t recode_tlb_page; ! 440: ! 441: /* get the sparc DTLB entry: */ ! 442: dtlb = ls->tme_sparc_ls_tlb; ! 443: ! 444: /* get the recode DTLB entry: */ ! 445: recode_tlb = &ic->_TME_SPARC_RECODE_SIZE(tme_sparc_recode_tlb,s)[ls->tme_sparc_ls_tlb_i]; ! 446: ! 447: /* assume that this recode DTLB entry will assist all loads and ! 448: stores (this mask includes at least ! 449: TME_SPARC_RECODE_TLB_FLAG_LD_USER(ic), ! 450: TME_SPARC_RECODE_TLB_FLAG_LD_PRIV(ic), ! 451: TME_SPARC_RECODE_TLB_FLAG_ST_USER(ic), and ! 452: TME_SPARC_RECODE_TLB_FLAG_ST_PRIV(ic)): */ ! 453: rw_flags_tlb = TME_RECODE_TLB_FLAGS_MASK(ic->tme_sparc_recode_ic); ! 454: ! 455: /* get our DTLB page size: */ ! 456: dtlb_page_size = (1 << ic->tme_sparc_tlb_page_size_log2); ! 457: ! 458: /* update the recode DTLB entry page: */ ! 459: recode_tlb_page = ls->_TME_SPARC_RECODE_SIZE(tme_sparc_ls_address,/**/) & (0 - (tme_sparc_ireg_t) dtlb_page_size); ! 460: recode_tlb->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_page) = recode_tlb_page; ! 461: ! 462: /* if the sparc DTLB entry covers an entire page for one or more ! 463: normal ASIs, and verification isn't on: */ ! 464: if ((((tme_sparc_ireg_t) dtlb->tme_sparc_tlb_addr_first) ! 465: <= recode_tlb_page) ! 466: && ((recode_tlb_page | (dtlb_page_size - 1)) ! 467: <= ((tme_sparc_ireg_t) dtlb->tme_sparc_tlb_addr_last)) ! 468: && (dtlb->tme_sparc_tlb_asi_mask & TME_SPARC_ASI_MASK_FLAG_SPECIAL) == 0 ! 469: && !_tme_sparc_recode_verify_on) { ! 470: ! 471: /* if the sparc DTLB entry allows fast reading: */ ! 472: if (dtlb->tme_sparc_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF) { ! 473: ! 474: /* update the recode DTLB entry page memory pointer: */ ! 475: recode_tlb->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_memory) ! 476: = (dtlb->tme_sparc_tlb_emulator_off_read ! 477: + recode_tlb_page); ! 478: ! 479: /* if this sparc DTLB entry allows user loads: */ ! 480: if (TME_SPARC_TLB_ASI_MASK_OK(dtlb, ! 481: (TME_SPARC_VERSION(ic) >= 9 ! 482: ? TME_SPARC64_ASI_MASK_REQUIRED_UNRESTRICTED(TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) ! 483: : TME_SPARC32_ASI_MASK_UD))) { ! 484: ! 485: /* this recode DTLB entry probably won't need an assist for ! 486: user loads (a sparc DTLB entry with side-effects will ! 487: override this): */ ! 488: rw_flags_tlb ! 489: -= TME_SPARC_RECODE_TLB_FLAG_LD_USER(ic); ! 490: } ! 491: ! 492: /* if this sparc DTLB entry allows privileged/supervisor ! 493: loads: */ ! 494: if (TME_SPARC_TLB_ASI_MASK_OK(dtlb, ! 495: (TME_SPARC_VERSION(ic) >= 9 ! 496: ? TME_SPARC64_ASI_MASK_REQUIRED_UNRESTRICTED(!TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) ! 497: : TME_SPARC32_ASI_MASK_SD))) { ! 498: ! 499: /* this recode DTLB entry probably won't need an assist for ! 500: privileged/supervisor loads (a sparc DTLB entry with ! 501: side-effects will override this): */ ! 502: rw_flags_tlb ! 503: -= TME_SPARC_RECODE_TLB_FLAG_LD_PRIV(ic); ! 504: } ! 505: } ! 506: ! 507: /* if the sparc DTLB entry allows fast writing, and it either ! 508: doesn't allow fast reading or the fast read and write pointers ! 509: are the same: */ ! 510: if (dtlb->tme_sparc_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF ! 511: && (dtlb->tme_sparc_tlb_emulator_off_read == TME_EMULATOR_OFF_UNDEF ! 512: || dtlb->tme_sparc_tlb_emulator_off_write == dtlb->tme_sparc_tlb_emulator_off_read)) { ! 513: ! 514: /* update the recode DTLB entry page memory pointer: */ ! 515: recode_tlb->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_memory) ! 516: = (dtlb->tme_sparc_tlb_emulator_off_write ! 517: + recode_tlb_page); ! 518: ! 519: /* if this sparc DTLB entry allows user stores: */ ! 520: if (TME_SPARC_TLB_ASI_MASK_OK(dtlb, ! 521: (TME_SPARC_VERSION(ic) >= 9 ! 522: ? TME_SPARC64_ASI_MASK_REQUIRED_UNRESTRICTED(TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) ! 523: : TME_SPARC32_ASI_MASK_UD))) { ! 524: ! 525: /* this recode DTLB entry probably won't need an assist for ! 526: user stores (a sparc DTLB entry with side-effects will ! 527: override this): */ ! 528: rw_flags_tlb ! 529: -= TME_SPARC_RECODE_TLB_FLAG_ST_USER(ic); ! 530: } ! 531: ! 532: /* if this sparc DTLB entry allows privileged/supervisor ! 533: stores: */ ! 534: if (TME_SPARC_TLB_ASI_MASK_OK(dtlb, ! 535: (TME_SPARC_VERSION(ic) >= 9 ! 536: ? TME_SPARC64_ASI_MASK_REQUIRED_UNRESTRICTED(!TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) ! 537: : TME_SPARC32_ASI_MASK_SD))) { ! 538: ! 539: /* this recode DTLB entry probably won't need an assist for ! 540: privileged/supervisor stores (a sparc DTLB entry with ! 541: side-effects will override this): */ ! 542: rw_flags_tlb ! 543: -= TME_SPARC_RECODE_TLB_FLAG_ST_PRIV(ic); ! 544: } ! 545: } ! 546: ! 547: /* this recode DTLB entry needs an assist for no-fault loads when ! 548: the ASI register is not loaded with the correct default ! 549: no-fault ASI: */ ! 550: assert (rw_flags_tlb & TME_SPARC_RECODE_TLB_FLAG_LD_NF(ic)); ! 551: ! 552: /* if this sparc DTLB entry does not only allow no-fault loads: */ ! 553: if (TME_SPARC_VERSION(ic) < 9 ! 554: || (dtlb->tme_sparc_tlb_asi_mask & TME_SPARC64_ASI_FLAG_NO_FAULT) == 0) { ! 555: ! 556: /* this recode DTLB entry doesn't need an assist for faulting ! 557: loads: */ ! 558: rw_flags_tlb -= TME_SPARC_RECODE_TLB_FLAG_LD_F(ic); ! 559: } ! 560: ! 561: /* if this sparc DTLB entry is for addresses with side-effects ! 562: (regardless of whether or not the sparc DTLB entry allows fast ! 563: reads and/or writes): */ ! 564: if (TME_SPARC_VERSION(ic) >= 9 ! 565: && (dtlb->tme_sparc_tlb_asi_mask & TME_SPARC64_ASI_MASK_FLAG_TLB_SIDE_EFFECTS)) { ! 566: ! 567: /* this recode DTLB entry needs an assist for all loads and stores: */ ! 568: rw_flags_tlb ! 569: |= (TME_SPARC_RECODE_TLB_FLAG_LD_USER(ic) ! 570: | TME_SPARC_RECODE_TLB_FLAG_LD_PRIV(ic) ! 571: | TME_SPARC_RECODE_TLB_FLAG_ST_USER(ic) ! 572: | TME_SPARC_RECODE_TLB_FLAG_ST_PRIV(ic)); ! 573: } ! 574: ! 575: /* if this is sparc32, or if this sparc64 MMU has an invert-endian bit: */ ! 576: if (TME_SPARC_VERSION(ic) < 9 ! 577: || (TME_SPARC_MEMORY_FLAGS(ic) & TME_SPARC_MEMORY_FLAG_HAS_INVERT_ENDIAN)) { ! 578: ! 579: /* this recode DTLB entry doesn't need an assist for loads and ! 580: stores based on their explicit endianness: */ ! 581: rw_flags_tlb ! 582: -= (TME_SPARC_RECODE_TLB_FLAG_LS_ENDIAN_BIG(ic) ! 583: + TME_SPARC_RECODE_TLB_FLAG_LS_ENDIAN_LITTLE(ic)); ! 584: ! 585: /* if this is sparc32, or if this sparc64 DTLB entry's ! 586: invert-endian bit is not set: */ ! 587: if (TME_SPARC_VERSION(ic) < 9 ! 588: || (dtlb->tme_sparc_tlb_asi_mask & TME_SPARC64_ASI_FLAG_LITTLE) == 0) { ! 589: ! 590: /* this recode DTLB entry doesn't need an assist for loads and ! 591: stores to invert their endianness: */ ! 592: rw_flags_tlb ! 593: -= TME_SPARC_RECODE_TLB_FLAG_LS_ENDIAN_INVERT(ic); ! 594: } ! 595: } ! 596: ! 597: /* otherwise, we don't know how this v9 MMU affects endianness: */ ! 598: else { ! 599: assert (FALSE); ! 600: } ! 601: ! 602: /* update the recode DTLB entry context: */ ! 603: recode_tlb->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_context) ! 604: = dtlb->tme_sparc_tlb_context; ! 605: ! 606: /* if this sparc DTLB entry matches any context: */ ! 607: if (dtlb->tme_sparc_tlb_context > ic->tme_sparc_memory_context_max) { ! 608: ! 609: /* this recode DTLB entry doesn't need an assist for loads and ! 610: stores whose context mismatches the recode DTLB entry: */ ! 611: rw_flags_tlb ! 612: -= TME_RECODE_TLB_FLAG_CONTEXT_MISMATCH(ic); ! 613: } ! 614: } ! 615: ! 616: /* update the recode DTLB entry read/write flags: */ ! 617: recode_tlb->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_flags) = rw_flags_tlb; ! 618: } ! 619: ! 620: /* this initializes for ld and st instructions: */ ! 621: static void ! 622: _tme_sparc_recode_ls_init(struct tme_sparc *ic) ! 623: { ! 624: signed long rw_thunk_index; ! 625: struct tme_recode_rw rw; ! 626: tme_uint32_t sparc_opcode_ldu; ! 627: tme_uint32_t sparc_opcode_st; ! 628: tme_uint32_t rw_flags_insn_common; ! 629: tme_uint32_t rw_flags_insn; ! 630: unsigned int other_signed; ! 631: unsigned int no_fault; ! 632: ! 633: /* initialize the array of read/write thunks: */ ! 634: for (rw_thunk_index = 0; ! 635: rw_thunk_index < TME_ARRAY_ELS(ic->tme_sparc_recode_rw_thunks); ! 636: rw_thunk_index++) { ! 637: ic->tme_sparc_recode_rw_thunks[rw_thunk_index] = NULL; ! 638: } ! 639: ! 640: /* make the common read/write structure for all sizes: */ ! 641: rw.tme_recode_rw_bus_boundary = TME_BIT(TME_SPARC_RECODE_SIZE(ic) - TME_RECODE_SIZE_8); ! 642: rw.tme_recode_rw_address_type.tme_recode_address_type_context_ic_offset ! 643: = (((char *) &ic->tme_sparc_memory_context_default) - (char *) ic); ! 644: rw.tme_recode_rw_address_type.tme_recode_address_type_context_size ! 645: = TME_RECODE_SIZE_16; ! 646: rw.tme_recode_rw_address_type.tme_recode_address_type_signed = FALSE; ! 647: rw.tme_recode_rw_address_type.tme_recode_address_type_tlb_flags_ic_offset ! 648: = (((char *) &ic->tme_sparc_recode_rw_tlb_flags) - (char *) ic); ! 649: rw.tme_recode_rw_address_type.tme_recode_address_type_mask_tlb_index ! 650: = ((_TME_SPARC_DTLB_HASH_SIZE - 1) ! 651: * ic->tme_sparc_recode_ic->tme_recode_ic_tlb_page_size); ! 652: rw.tme_recode_rw_address_type.tme_recode_address_type_tlb0_ic_offset ! 653: = (((char *) &ic->_tme_sparc_tlb_tokens_u) - (char *) ic); ! 654: ! 655: /* initialize the read/write structure for the first ld and st ! 656: instructions: */ ! 657: rw.tme_recode_rw_address_type.tme_recode_address_type_size = TME_SPARC_RECODE_SIZE(ic); ! 658: rw.tme_recode_rw_memory_endian = TME_ENDIAN_BIG; ! 659: rw.tme_recode_rw_memory_size = TME_RECODE_SIZE_8; ! 660: for (;;) { ! 661: ! 662: /* get the sparc ld/st opcodes for this size: */ ! 663: sparc_opcode_ldu = TME_BIT(rw.tme_recode_rw_memory_size - TME_RECODE_SIZE_8) % sizeof(tme_uint32_t); ! 664: sparc_opcode_st = sparc_opcode_ldu + 4; ! 665: if (TME_SPARC_VERSION(ic) >= 9 ! 666: && rw.tme_recode_rw_memory_size == TME_SPARC_RECODE_SIZE(ic)) { ! 667: sparc_opcode_ldu = 0x0b; /* v9: ldx */ ! 668: sparc_opcode_st = 0x0e; /* v9: stx */ ! 669: } ! 670: ! 671: /* make the common read/write structure for this size: */ ! 672: rw.tme_recode_rw_address_type.tme_recode_address_type_align_min ! 673: = TME_BIT(rw.tme_recode_rw_memory_size - TME_RECODE_SIZE_8); ! 674: ! 675: /* start the common read/write structure flags: */ ! 676: rw_flags_insn_common = 0; ! 677: ! 678: /* all loads and stores will need an assist when they encounter a ! 679: recode TLB entry from the wrong context: */ ! 680: /* NB: TME_RECODE_TLB_FLAG_CONTEXT_MISMATCH() will get set ! 681: automatically as needed by the read/write thunk; there's no ! 682: need to set it here: */ ! 683: ! 684: /* all loads and stores will need an assist when they encounter a ! 685: recode TLB entry that inverts their endianness: */ ! 686: rw_flags_insn_common |= TME_SPARC_RECODE_TLB_FLAG_LS_ENDIAN_INVERT(ic); ! 687: ! 688: /* all loads and stores will need an assist when they encounter a ! 689: recode TLB entry that doesn't allow their endianness: */ ! 690: rw_flags_insn_common ! 691: |= (rw.tme_recode_rw_memory_endian == TME_ENDIAN_BIG ! 692: ? TME_SPARC_RECODE_TLB_FLAG_LS_ENDIAN_BIG(ic) ! 693: : TME_SPARC_RECODE_TLB_FLAG_LS_ENDIAN_LITTLE(ic)); ! 694: ! 695: /* make the common structure for loads: */ ! 696: rw.tme_recode_rw_write = FALSE; ! 697: rw.tme_recode_rw_reg_size = TME_SPARC_RECODE_SIZE(ic); ! 698: rw.tme_recode_rw_guest_func_read = _tme_sparc_recode_ls_assist_ld; ! 699: ! 700: /* set the signedness of the (first) ld instructions at this size ! 701: that we will make a read thunk for: */ ! 702: /* NB: we assume that 8- and 32-bit loads are signed more often ! 703: than not (because we assume that the C char and int types are ! 704: used more often than the unsigned char and unsigned int types), ! 705: so we make their thunks first, assuming that if we made them ! 706: second, that they might reuse an unsigned thunk and then ! 707: require extra sign-extension instructions in an instructions ! 708: thunk: */ ! 709: rw.tme_recode_rw_memory_signed ! 710: = (rw.tme_recode_rw_memory_size < TME_SPARC_RECODE_SIZE(ic) ! 711: && (rw.tme_recode_rw_memory_size == TME_RECODE_SIZE_8 ! 712: || rw.tme_recode_rw_memory_size == TME_RECODE_SIZE_32)); ! 713: ! 714: /* permute over signedness and no-fault, making the read thunk(s) ! 715: for the ld instruction(s) with this size and endianness: */ ! 716: for (other_signed = 0; ! 717: other_signed <= (rw.tme_recode_rw_memory_size < TME_SPARC_RECODE_SIZE(ic)); ! 718: other_signed++, rw.tme_recode_rw_memory_signed = !rw.tme_recode_rw_memory_signed) { ! 719: for (no_fault = 0; ! 720: no_fault <= (TME_SPARC_VERSION(ic) >= 9); ! 721: no_fault++) { ! 722: ! 723: /* start the read structure flags: */ ! 724: rw_flags_insn = rw_flags_insn_common; ! 725: ! 726: /* this load will need an assist when it encounters a recode ! 727: TLB entry that needs an assist on all loads (because the ! 728: sparc TLB entry doesn't allow fast reads, or has ! 729: side-effects) or doesn't allow loads at the current ! 730: privilege level (at load instruction time, the and of the ! 731: recode ic read/write flags will leave only one of these ! 732: flags set): */ ! 733: rw_flags_insn ! 734: |= (TME_SPARC_RECODE_TLB_FLAG_LD_USER(ic) ! 735: | TME_SPARC_RECODE_TLB_FLAG_LD_PRIV(ic)); ! 736: ! 737: /* if this is a no-fault load: */ ! 738: if (no_fault) { ! 739: ! 740: /* this no-fault load will need an assist when the ASI ! 741: register is not loaded with the correct default no-fault ! 742: ASI (at load instruction time, the and of the recode ic ! 743: read/write flags will clear this bit if the ASI register ! 744: is correct, and recode TLB entries always need this ! 745: assist): */ ! 746: rw_flags_insn |= TME_SPARC_RECODE_TLB_FLAG_LD_NF(ic); ! 747: } ! 748: ! 749: /* otherwise, this is a faulting load: */ ! 750: else { ! 751: ! 752: /* this faulting load will need an assist when it encounters ! 753: a recode TLB entry that doesn't allow faulting loads ! 754: (i.e., it only allows non-faulting loads): */ ! 755: rw_flags_insn |= TME_SPARC_RECODE_TLB_FLAG_LD_F(ic); ! 756: } ! 757: ! 758: /* make the read thunk for this ld instruction: */ ! 759: rw.tme_recode_rw_address_type.tme_recode_address_type_tlb_flags = rw_flags_insn; ! 760: ic->tme_sparc_recode_rw_thunks ! 761: [TME_SPARC_RECODE_RW_THUNK_INDEX(ic, ! 762: rw.tme_recode_rw_address_type.tme_recode_address_type_size, ! 763: rw.tme_recode_rw_memory_endian, ! 764: no_fault, ! 765: (sparc_opcode_ldu ! 766: + (8 * rw.tme_recode_rw_memory_signed)))] ! 767: /* NB: for an 8-bit little-endian ld instructions, we reuse ! 768: the 8-bit big-endian read thunk: */ ! 769: = ((rw.tme_recode_rw_memory_size == TME_RECODE_SIZE_8 ! 770: && rw.tme_recode_rw_memory_endian == TME_ENDIAN_LITTLE) ! 771: ? (ic->tme_sparc_recode_rw_thunks ! 772: [TME_SPARC_RECODE_RW_THUNK_INDEX(ic, ! 773: rw.tme_recode_rw_address_type.tme_recode_address_type_size, ! 774: TME_ENDIAN_BIG, ! 775: no_fault, ! 776: (sparc_opcode_ldu ! 777: + (8 * rw.tme_recode_rw_memory_signed)))]) ! 778: : tme_recode_rw_thunk(ic->tme_sparc_recode_ic, &rw)); ! 779: } ! 780: } ! 781: ! 782: /* make the common structure for reads: */ ! 783: rw.tme_recode_rw_write = TRUE; ! 784: rw.tme_recode_rw_reg_size = rw.tme_recode_rw_memory_size; ! 785: rw.tme_recode_rw_guest_func_write = _tme_sparc_recode_ls_assist_st; ! 786: ! 787: /* start the write structure flags: */ ! 788: rw_flags_insn = rw_flags_insn_common; ! 789: ! 790: /* this store will need an assist when it encounters a recode TLB ! 791: entry that needs an assist on all store (because the sparc TLB ! 792: entry doesn't allow fast stores, or has side-effects, or only ! 793: allows no-fault loads) or doesn't allow stores at the current ! 794: privilege level (at store instruction time, the and of the ! 795: recode ic read/write flags will leave only one of these flags ! 796: set): */ ! 797: rw_flags_insn ! 798: |= (TME_SPARC_RECODE_TLB_FLAG_ST_USER(ic) ! 799: | TME_SPARC_RECODE_TLB_FLAG_ST_PRIV(ic)); ! 800: ! 801: /* make the write thunk for this st instruction: */ ! 802: rw.tme_recode_rw_address_type.tme_recode_address_type_tlb_flags = rw_flags_insn; ! 803: ic->tme_sparc_recode_rw_thunks ! 804: [TME_SPARC_RECODE_RW_THUNK_INDEX(ic, ! 805: rw.tme_recode_rw_address_type.tme_recode_address_type_size, ! 806: rw.tme_recode_rw_memory_endian, ! 807: FALSE, ! 808: sparc_opcode_st)] ! 809: /* NB: for an 8-bit little-endian st instruction, we reuse the ! 810: 8-bit big-endian write thunk: */ ! 811: = ((rw.tme_recode_rw_memory_size == TME_RECODE_SIZE_8 ! 812: && rw.tme_recode_rw_memory_endian == TME_ENDIAN_LITTLE) ! 813: ? (ic->tme_sparc_recode_rw_thunks ! 814: [TME_SPARC_RECODE_RW_THUNK_INDEX(ic, ! 815: rw.tme_recode_rw_address_type.tme_recode_address_type_size, ! 816: TME_ENDIAN_BIG, ! 817: FALSE, ! 818: sparc_opcode_st)]) ! 819: : tme_recode_rw_thunk(ic->tme_sparc_recode_ic, &rw)); ! 820: ! 821: /* advance: */ ! 822: if (++rw.tme_recode_rw_memory_size > TME_SPARC_RECODE_SIZE(ic)) { ! 823: rw.tme_recode_rw_memory_size = TME_RECODE_SIZE_8; ! 824: if (rw.tme_recode_rw_memory_endian == TME_ENDIAN_BIG ! 825: && TME_SPARC_VERSION(ic) >= 9) { ! 826: rw.tme_recode_rw_memory_endian = TME_ENDIAN_LITTLE; ! 827: } ! 828: else { ! 829: rw.tme_recode_rw_memory_endian = TME_ENDIAN_BIG; ! 830: if (--rw.tme_recode_rw_address_type.tme_recode_address_type_size ! 831: < (TME_SPARC_RECODE_SIZE(ic) - (TME_SPARC_VERSION(ic) >= 9))) { ! 832: break; ! 833: } ! 834: } ! 835: } ! 836: } ! 837: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.