|
|
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.