|
|
1.1 root 1: /* $Id: sparc-recode.c,v 1.6 2010/06/05 18:42:35 fredette Exp $ */
2:
3: /* ic/sparc/sparc-recode.c - recodes SPARC instructions: */
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: /* includes: */
37: #include "sparc-impl.h"
38:
39: _TME_RCSID("$Id: sparc-recode.c,v 1.6 2010/06/05 18:42:35 fredette Exp $");
40:
41: #if TME_HAVE_RECODE
42:
43: /* macros: */
44:
45: /* this gives the number of recode page bitmap bits needed to cover
46: the given number of bytes. this is always a multiple of eight: */
47: #define TME_SPARC_RECODE_PAGE_BITMAP_BITS(ic, size_bytes) \
48: ((((size_bytes) >> (ic)->tme_sparc_tlb_page_size_log2) \
49: + 7) \
50: & (0 - (unsigned long) 8))
51:
52: /* this returns a read/write thunk index for an opcode: */
53: #define TME_SPARC_RECODE_RW_THUNK_INDEX(ic, address_size, endian, no_fault, opcode_0_3) \
54: ((opcode_0_3) \
55: + ((TME_SPARC_VERSION(ic) >= 9) \
56: * ((16 * ((no_fault) != 0)) \
57: + (32 * ((endian) == TME_ENDIAN_LITTLE)) \
58: + (64 * (TME_SPARC_RECODE_SIZE(ic) - (address_size))))))
59:
60: /* how many source address hash positions are probed: */
61: #define TME_SPARC_RECODE_SRC_HASH_SIZE_PROBE (TME_SPARC_RECODE_SRC_HASH_SIZE_SET * 2)
62:
63: /* the undefined source address hash key: */
64: #define TME_SPARC_RECODE_SRC_KEY_UNDEF ((tme_sparc_recode_src_key_t) (0 - (tme_sparc_recode_src_key_t) 1))
65:
66: /* flags in a source address hash key: */
67: /* NB: an architecture can't have more than two flags, since those are
68: the only bits available in a source address hash key (because PCs
69: are 32-bit aligned): */
70: #define TME_SPARC64_RECODE_SRC_KEY_FLAG_AM (1 << 0)
71: #define TME_SPARC64_RECODE_SRC_KEY_FLAG_CLE (1 << 1)
72:
73: /* the hit count threshold for recoding a source address: */
74: #define TME_SPARC_RECODE_HIT_COUNT_THRESHOLD (512)
75:
76: /* this returns the recode size for the architecture size: */
77: #define TME_SPARC_RECODE_SIZE(ic) (TME_RECODE_SIZE_32 + (TME_SPARC_VERSION(ic) >= 9))
78:
79: /* fix certain things based on the architecture size: */
80: #undef TME_SPARC_VERSION
81: #define TME_SPARC_VERSION(ic) (8 + (_TME_SPARC_RECODE_SIZE(/**/,/**/) == 64))
82: #define tme_sparc_ireg_t _TME_SPARC_RECODE_SIZE(tme_uint,_t)
83: #define tme_sparc_ireg _TME_SPARC_RECODE_SIZE(tme_sparc_ireg_uint,/**/)
84: #define TME_SPARC_IREG_MSBIT (((tme_sparc_ireg_t) 1) << (sizeof(tme_sparc_ireg_t) * 8 - 1))
85:
86: /* the current verify state: */
87: #ifdef _TME_SPARC_RECODE_VERIFY
88: static int _tme_sparc_recode_off;
89: static int _tme_sparc_recode_verify_on;
90: #else /* !_TME_SPARC_RECODE_VERIFY */
91: #define _tme_sparc_recode_off (FALSE)
92: #define _tme_sparc_recode_verify_on (FALSE)
93: #endif /* !_TME_SPARC_RECODE_VERIFY */
94:
95: /* make the sparc32 recode support: */
96: #define _TME_SPARC_RECODE_SIZE(x,y) _TME_CONCAT(_TME_CONCAT(x,32),y)
97: #include "sparc-rc-cc.c"
98: #include "sparc-rc-chain.c"
99: #include "sparc-rc-insns.c"
100: #include "sparc-rc-ls.c"
101: #undef _TME_SPARC_RECODE_SIZE
102:
103: #if TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32
104:
105: /* make the sparc64 recode support: */
106: #define _TME_SPARC_RECODE_SIZE(x,y) _TME_CONCAT(_TME_CONCAT(x,64),y)
107: #include "sparc-rc-cc.c"
108: #include "sparc-rc-chain.c"
109: #include "sparc-rc-insns.c"
110: #include "sparc-rc-ls.c"
111: #undef _TME_SPARC_RECODE_SIZE
112:
113: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32 */
114:
115: /* unfix certain things: */
116: #undef TME_SPARC_VERSION
117: #define TME_SPARC_VERSION(ic) _TME_SPARC_VERSION(ic)
118: #undef tme_sparc_ireg_t
119: #undef tme_sparc_ireg
120: #undef TME_SPARC_IREG_MSBIT
121:
122: /* this invalidates pages in the source address hash: */
123: static void
124: _tme_sparc_recode_src_hash_invalidate(struct tme_sparc *ic,
125: tme_sparc_recode_src_key_t src_key_mask,
126: tme_sparc_recode_src_key_t src_key_match)
127: {
128: signed long src_hash_i;
129: tme_sparc_recode_src_key_t src_key;
130: tme_recode_thunk_off_t insns_thunk;
131:
132: /* walk all of the positions in the source address hash: */
133: src_hash_i
134: = ((TME_SPARC_RECODE_SRC_HASH_MODULUS
135: * TME_SPARC_RECODE_SRC_HASH_SIZE_SET)
136: - 1);
137: do {
138:
139: /* if the source address key in this position matches: */
140: src_key
141: = (ic->tme_sparc_recode_src_hash
142: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
143: .tme_sparc_recode_src_hash_keys
144: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]);
145: if (((src_key ^ src_key_match) & src_key_mask) == 0) {
146:
147: /* invalidate this source address key: */
148: (ic->tme_sparc_recode_src_hash
149: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
150: .tme_sparc_recode_src_hash_keys
151: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT])
152: = TME_SPARC_RECODE_SRC_KEY_UNDEF;
153:
154: /* if this source address key has an instructions thunk: */
155: insns_thunk
156: = (ic->tme_sparc_recode_src_hash
157: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
158: .tme_sparc_recode_src_hash_values
159: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]);
160: if ((insns_thunk & TME_BIT(0)) == 0
161: && insns_thunk != 0) {
162:
163: /* invalidate the instructions thunk: */
164: tme_recode_insns_thunk_invalidate(ic->tme_sparc_recode_ic,
165: insns_thunk);
166: }
167:
168: /* reset the value for this position to a hit count of zero: */
169: (ic->tme_sparc_recode_src_hash
170: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
171: .tme_sparc_recode_src_hash_values
172: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT])
173: = TME_BIT(0);
174: }
175: } while (--src_hash_i >= 0);
176: }
177:
178: /* this invalidates our entire source hash and all instructions
179: thunks: */
180: void
181: tme_sparc_recode_invalidate_all(struct tme_sparc *ic)
182: {
183:
184: /* invalidate our entire source hash: */
185: _tme_sparc_recode_src_hash_invalidate(ic, 0, 0);
186:
187: /* invalidate all instructions thunks: */
188: tme_recode_insns_thunk_invalidate_all(ic->tme_sparc_recode_ic);
189:
190: /* clear the return address stack: */
191: tme_recode_chain_ras_clear(ic->tme_sparc_recode_ic,
192: &ic->tme_sparc_ic);
193: }
194:
195: /* include the verify support: */
196: #ifdef _TME_SPARC_RECODE_VERIFY
197: #include "sparc-rc-verify.c"
198: #endif /* _TME_SPARC_RECODE_VERIFY */
199:
200: /* this adds a new cacheable: */
201: static struct tme_sparc_recode_cacheable *
202: _tme_sparc_recode_cacheable_new(struct tme_sparc *ic,
203: const struct tme_sparc_tlb *itlb,
204: const tme_shared tme_uint32_t *src)
205: {
206: unsigned int page_size_log2;
207: tme_uint32_t page_size;
208: tme_uint32_t page_byte_offset;
209: struct tme_sparc_recode_cacheable *cacheable;
210: const struct tme_bus_cacheable *bus_cacheable;
211: unsigned long bitmap_bytes_old;
212: unsigned long bitmap_bytes;
213:
214: /* get the page size: */
215: page_size_log2 = ic->tme_sparc_tlb_page_size_log2;
216: page_size = (((tme_uint32_t) 1) << page_size_log2);
217:
218: /* get the offset of the current PC into this page: */
219: page_byte_offset
220: = (
221: #if TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32
222: TME_SPARC_VERSION(ic) >= 9
223: ? ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC)
224: :
225: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32 */
226: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC));
227: page_byte_offset %= page_size;
228:
229: /* if we have run out of cacheables, return failure: */
230: cacheable = ic->tme_sparc_recode_cacheable_first;
231: if (cacheable == &ic->tme_sparc_recode_cacheables[TME_SPARC_RECODE_CACHEABLES_MAX - 1]) {
232: return (NULL);
233: }
234: cacheable += (ic->tme_sparc_recode_cacheables[0].tme_sparc_recode_cacheable_size != 0);
235:
236: /* if this instruction TLB entry isn't for cacheable memory, return
237: failure: */
238: bus_cacheable = itlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_cacheable;
239: if (bus_cacheable == NULL) {
240: return (NULL);
241: }
242:
243: /* if the cacheable memory doesn't cover some whole number of
244: aligned pages, return failure: */
245: assert (bus_cacheable->tme_bus_cacheable_size > 0);
246: if ((((((tme_uint8_t *) src)
247: - bus_cacheable->tme_bus_cacheable_contents)
248: % page_size)
249: != page_byte_offset)
250: || ((bus_cacheable->tme_bus_cacheable_size
251: % page_size)
252: != 0)) {
253: return (NULL);
254: }
255:
256: /* initialize our cacheable: */
257: /* NB: we round up the first source address key for this cacheable
258: so that its page index is a multiple of eight, which will be used
259: to index the least-significant bit in the first byte of the
260: valids bitmap we allocate below: */
261: cacheable->tme_sparc_recode_cacheable_contents = bus_cacheable->tme_bus_cacheable_contents;
262: cacheable->tme_sparc_recode_cacheable_size = bus_cacheable->tme_bus_cacheable_size;
263: cacheable->tme_sparc_recode_cacheable_src_key_first
264: = (cacheable == &ic->tme_sparc_recode_cacheables[0]
265: ? 0
266: : ((cacheable - 1)->tme_sparc_recode_cacheable_src_key_first
267:
268: + (TME_SPARC_RECODE_PAGE_BITMAP_BITS(ic, (cacheable - 1)->tme_sparc_recode_cacheable_size)
269: * page_size)));
270:
271: /* allocate the valids bitmap, and adjust the pointer to account
272: for the first source key in this cacheable: */
273: cacheable->tme_sparc_recode_cacheable_valids
274: = ((*bus_cacheable->tme_bus_cacheable_valids_new)
275: (bus_cacheable->tme_bus_cacheable_private,
276: page_size_log2)
277: - ((cacheable->tme_sparc_recode_cacheable_src_key_first
278: / page_size)
279: / 8));
280:
281: /* allocate or reallocate the active recode pages bitmap, and zero
282: the new parts of the bitmap: */
283: bitmap_bytes_old
284: = (cacheable->tme_sparc_recode_cacheable_src_key_first
285: / (page_size * 8));
286: bitmap_bytes
287: = (bitmap_bytes_old
288: + (TME_SPARC_RECODE_PAGE_BITMAP_BITS(ic, cacheable->tme_sparc_recode_cacheable_size)
289: / 8));
290: ic->tme_sparc_recode_cacheable_actives
291: = (cacheable == &ic->tme_sparc_recode_cacheables[0]
292: ? tme_new(tme_uint8_t, bitmap_bytes)
293: : tme_renew(tme_uint8_t, ic->tme_sparc_recode_cacheable_actives, bitmap_bytes));
294: memset((ic->tme_sparc_recode_cacheable_actives + bitmap_bytes_old),
295: 0,
296: (bitmap_bytes - bitmap_bytes_old));
297:
298: /* finish allocating this cacheable: */
299: ic->tme_sparc_recode_cacheable_first = cacheable;
300:
301: /* return success: */
302: return (cacheable);
303: }
304:
305: tme_recode_thunk_off_t
306: tme_sparc_recode(struct tme_sparc *ic,
307: const struct tme_sparc_tlb *itlb,
308: const tme_shared tme_uint32_t *src)
309: {
310:
311: const struct tme_sparc_recode_cacheable *cacheable;
312: tme_sparc_recode_src_key_t src_key;
313: tme_uint32_t pstate;
314: unsigned long page_index;
315: tme_uint8_t page_invalid;
316: const tme_shared tme_uint8_t *cacheable_valid_byte;
317: unsigned int cacheable_valid_mask;
318: signed long src_hash_i;
319: signed int src_hash_probe;
320: tme_sparc_recode_src_key_t src_key_other;
321: tme_recode_thunk_off_t insns_thunk;
322: tme_recode_thunk_off_t hit_count;
323:
324: TME_SPARC_STAT(ic, tme_sparc_stats_recode_calls);
325:
326: /* if recoding is off: */
327: if (_tme_sparc_recode_off) {
328:
329: /* we can't recode this source address: */
330: return (0);
331: }
332:
333: /* if this instruction TLB entry doesn't extend to the end of the
334: page: */
335: /* XXX FIXME - this isn't right, since it will reject all itlb
336: entries that don't end right at a recode page boundary, instead
337: of only those that end before the end of the page containing the
338: current PC. maybe this check should move to sparc-rc-insns.c or
339: sparc-execute.c, where we have the current PC? */
340: if (__tme_predict_false((~itlb->tme_sparc_tlb_addr_last)
341: & ((1 << ic->tme_sparc_tlb_page_size_log2)
342: - sizeof(tme_uint32_t)))) {
343:
344: /* we can't recode this source address: */
345: return (0);
346: }
347:
348: /* assume that we will recode at this source address, and save it: */
349: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_src
350: = (const tme_shared tme_uint8_t *) src;
351:
352: /* search for a cacheable that contains this source address: */
353: cacheable = ic->tme_sparc_recode_cacheable_first;
354: for (;;) {
355:
356: /* assume that this cacheable contains this source address, and get the
357: source address key relative to the start of the cacheable: */
358: src_key = ((tme_uint8_t *) src) - cacheable->tme_sparc_recode_cacheable_contents;
359:
360: /* if this cacheable contains this source address: */
361: if (__tme_predict_true(src_key
362: < cacheable->tme_sparc_recode_cacheable_size)) {
363:
364: /* stop now: */
365: break;
366: }
367:
368: /* if we have not run out of cacheables: */
369: if (__tme_predict_true(--cacheable != (&ic->tme_sparc_recode_cacheables[0] - 1))) {
370: continue;
371: }
372:
373: /* if this instruction TLB entry isn't for a cacheable, or if we
374: can't add this cacheable: */
375: cacheable = _tme_sparc_recode_cacheable_new(ic, itlb, src);
376: if (cacheable == NULL) {
377:
378: /* we can't recode this source address: */
379: return (0);
380: }
381: }
382:
383: /* make the absolute source address key by adding in the first
384: source address key in this cacheable: */
385: src_key += cacheable->tme_sparc_recode_cacheable_src_key_first;
386: assert ((src_key % sizeof(tme_uint32_t)) == 0);
387:
388: /* if this is a v9 CPU: */
389: if (TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32
390: && TME_SPARC_VERSION(ic) >= 9) {
391:
392: /* add PSTATE.AM and PSTATE.CLE to the source address key: */
393: pstate = ic->tme_sparc64_ireg_pstate;
394: if (pstate & TME_SPARC64_PSTATE_AM) {
395: src_key += TME_SPARC64_RECODE_SRC_KEY_FLAG_AM;
396: }
397: if (pstate & TME_SPARC64_PSTATE_CLE) {
398: src_key += TME_SPARC64_RECODE_SRC_KEY_FLAG_CLE;
399: }
400: }
401:
402: /* the source address key must be defined: */
403: assert (src_key != TME_SPARC_RECODE_SRC_KEY_UNDEF);
404:
405: /* make the index for the page containing this source address: */
406: page_index = src_key >> ic->tme_sparc_tlb_page_size_log2;
407:
408: /* assume that this recode page is still valid: */
409: page_invalid = FALSE;
410:
411: /* get the cacheable valid byte and mask for this page: */
412: cacheable_valid_byte = &cacheable->tme_sparc_recode_cacheable_valids[page_index / 8];
413: cacheable_valid_mask = TME_BIT(page_index % 8);
414:
415: /* assume that we will recode at this source address, and save the
416: cacheable valid byte and mask for this page: */
417: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_valid_byte = cacheable_valid_byte;
418: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_valid_mask = cacheable_valid_mask;
419:
420: /* if the valid bit for this page is no longer set: */
421: if (__tme_predict_false(((*cacheable_valid_byte) & cacheable_valid_mask) == 0)) {
422:
423: /* this page is invalid: */
424: page_invalid = TRUE;
425:
426: /* if this page was active: */
427: if (__tme_predict_false(ic->tme_sparc_recode_cacheable_actives[page_index / 8]
428: & TME_BIT(page_index % 8))) {
429:
430: TME_SPARC_STAT(ic, tme_sparc_stats_recode_page_invalids);
431:
432: /* mark this page as inactive: */
433: ic->tme_sparc_recode_cacheable_actives[page_index / 8] &= ~TME_BIT(page_index % 8);
434:
435: /* re-set the valid bit for the page containing this
436: source address: */
437: /* NB: we cheat and pass our
438: page-index-base-greater-than-zero-relative valids bitmap
439: pointer instead of the original pointer returned by the
440: allocator. this only works if the re-set function will work
441: given arbitrary valids bitmap pointers and page indices: */
442: (*itlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_cacheable->tme_bus_cacheable_valids_set)
443: (itlb->tme_sparc_tlb_bus_tlb.tme_bus_tlb_cacheable->tme_bus_cacheable_private,
444: cacheable->tme_sparc_recode_cacheable_valids,
445: page_index);
446:
447: /* invalidate this page in the source address hash: */
448: _tme_sparc_recode_src_hash_invalidate(ic,
449: (0
450: - ((tme_sparc_recode_src_key_t)
451: (1 << ic->tme_sparc_tlb_page_size_log2))),
452: src_key);
453: }
454: }
455:
456: /* hash the source address key: */
457: src_hash_i
458: = ((((src_key
459: / sizeof(tme_uint32_t))
460: % TME_SPARC_RECODE_SRC_HASH_MODULUS)
461: * TME_SPARC_RECODE_SRC_HASH_SIZE_SET)
462: + (TME_SPARC_RECODE_SRC_HASH_SIZE_SET
463: - 1));
464:
465: /* search for the source address key in the hash: */
466: src_hash_probe = TME_SPARC_RECODE_SRC_HASH_SIZE_PROBE;
467: for (;;) {
468:
469: TME_SPARC_STAT(ic, tme_sparc_stats_recode_source_hash_probes);
470:
471: /* get the source address key at this position: */
472: src_key_other
473: = (ic->tme_sparc_recode_src_hash
474: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
475: .tme_sparc_recode_src_hash_keys
476: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]);
477:
478: /* if we found the source address key, stop now: */
479: if (__tme_predict_true(src_key_other == src_key)) {
480: break;
481: }
482:
483: /* if this position in the hash is free: */
484: if (src_key_other == TME_SPARC_RECODE_SRC_KEY_UNDEF) {
485:
486: /* allocate this position in the hash: */
487: (ic->tme_sparc_recode_src_hash
488: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
489: .tme_sparc_recode_src_hash_keys
490: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT])
491: = src_key;
492:
493: /* stop now: */
494: break;
495: }
496:
497: /* if we have searched enough: */
498: if (__tme_predict_false(--src_hash_probe < 0)) {
499:
500: TME_SPARC_STAT(ic, tme_sparc_stats_recode_source_hash_misses);
501:
502: /* we won't recode this source address: */
503: return (0);
504: }
505:
506: /* move to the next position to search: */
507: if (__tme_predict_false(--src_hash_i < 0)) {
508: src_hash_i
509: = ((TME_SPARC_RECODE_SRC_HASH_MODULUS
510: * TME_SPARC_RECODE_SRC_HASH_SIZE_SET)
511: - 1);
512: }
513: }
514:
515: /* assume that this source address has been recoded, and get the
516: instructions thunk: */
517: insns_thunk
518: = (ic->tme_sparc_recode_src_hash
519: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
520: .tme_sparc_recode_src_hash_values
521: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]);
522:
523: /* if the source address has not been recoded yet: */
524: if (__tme_predict_false(insns_thunk & TME_BIT(0))) {
525:
526: /* update the hit count for this source address: */
527: hit_count = insns_thunk + 2;
528:
529: /* if the hit count for this source address is still less than the
530: recode threshold: */
531: if (__tme_predict_true(hit_count
532: < ((TME_SPARC_RECODE_HIT_COUNT_THRESHOLD * 2)
533: + 1))) {
534:
535: /* update the hit count for this source address: */
536: (ic->tme_sparc_recode_src_hash
537: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
538: .tme_sparc_recode_src_hash_values
539: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT])
540: = hit_count;
541:
542: /* we won't recode this source address now: */
543: return (0);
544: }
545:
546: /* mark this page as active: */
547: ic->tme_sparc_recode_cacheable_actives[page_index / 8] |= TME_BIT(page_index % 8);
548:
549: /* if this page is invalid: */
550: if (page_invalid) {
551:
552: /* return now and interpret instructions normally - the next
553: time we encounter this page again, we will mark this
554: page as inactive, re-set the page's valid bit and
555: invalidate the page in the source address hash.
556:
557: this somewhat limits the work we do for pages that are
558: both executed from and written to frequently. we will only
559: recode an instructions thunk when its page was valid for the
560: entire time it took for its hit count to go from zero to the
561: threshold, and we will only invalidate an invalid page in the
562: source address hash when any hit count in the page reaches
563: the threshold: */
564: return (0);
565: }
566:
567: /* recode starting from this source address: */
568: insns_thunk
569: = (
570: #if TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32
571: TME_SPARC_VERSION(ic) >= 9
572: ? _tme_sparc64_recode_recode(ic, itlb)
573: :
574: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32 */
575: _tme_sparc32_recode_recode(ic, itlb));
576:
577: /* if we couldn't recode at this source address: */
578: if (__tme_predict_false(insns_thunk < 0)) {
579:
580: /* the only time we can't recode is when the host runs out of
581: memory for instructions thunks. when this happens, the host
582: invalidates all previous instructions thunks, so we have to
583: invalidate our entire source hash: */
584: tme_sparc_recode_invalidate_all(ic);
585: return (0);
586: }
587:
588: /* set the instructions thunk for this source address: */
589: assert ((insns_thunk & TME_BIT(0)) == 0);
590: (ic->tme_sparc_recode_src_hash
591: [src_hash_i / TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT]
592: .tme_sparc_recode_src_hash_values
593: [src_hash_i % TME_SPARC_RECODE_SRC_HASH_SIZE_ELEMENT])
594: = insns_thunk;
595:
596: /* we can't run the new instructions thunk without re-checking the
597: valid bit for the page containing this source address
598: first - if it wasn't set for the entire time we were recoding,
599: the instructions thunk might not be consistent with the source
600: memory.
601:
602: to keep things simple, we just return now and interpret
603: instructions normally - the next time we get to this source
604: address, we'll check the valid bit and either run the
605: instructions thunk for the first time, or we'll do the
606: invalidate: */
607: return (0);
608: }
609:
610: /* return the instructions thunk offset: */
611: return (insns_thunk);
612: }
613:
614: #ifdef TME_RECODE_DEBUG
615: #include <stdio.h>
616:
617: void tme_sparc_recode_dump_ic _TME_P((const struct tme_sparc *));
618: void
619: tme_sparc_recode_dump_ic(const struct tme_sparc *ic)
620: {
621: const char *conds_integer[] = {
622: "n", "e", "le", "l", "leu", "cs", "neg", "vs",
623: NULL
624: };
625:
626: printf("sparc%u add flags thunk %p:\n",
627: (1 << TME_SPARC_RECODE_SIZE(ic)),
628: ic->tme_sparc_recode_flags_thunk_add);
629: tme_recode_flags_thunk_dump(ic->tme_sparc_recode_ic,
630: ic->tme_sparc_recode_flags_thunk_add);
631: printf("sparc%u sub flags thunk %p:\n",
632: (1 << TME_SPARC_RECODE_SIZE(ic)),
633: ic->tme_sparc_recode_flags_thunk_sub);
634: tme_recode_flags_thunk_dump(ic->tme_sparc_recode_ic,
635: ic->tme_sparc_recode_flags_thunk_sub);
636: printf("sparc%u logical flags thunk %p:\n",
637: (1 << TME_SPARC_RECODE_SIZE(ic)),
638: ic->tme_sparc_recode_flags_thunk_logical);
639: tme_recode_flags_thunk_dump(ic->tme_sparc_recode_ic,
640: ic->tme_sparc_recode_flags_thunk_logical);
641:
642: if (TME_SPARC_VERSION(ic) >= 9) {
643: printf("sparc%u rcc flags thunk %p:\n",
644: (1 << TME_SPARC_RECODE_SIZE(ic)),
645: ic->tme_sparc_recode_flags_thunk_rcc);
646: tme_recode_flags_thunk_dump(ic->tme_sparc_recode_ic,
647: ic->tme_sparc_recode_flags_thunk_rcc);
648: }
649: printf("sparc%u %%icc conds thunk %p:\n",
650: (1 << TME_SPARC_RECODE_SIZE(ic)),
651: ic->tme_sparc_recode_conds_thunk_icc);
652: tme_recode_conds_thunk_dump(ic->tme_sparc_recode_ic,
653: ic->tme_sparc_recode_conds_thunk_icc,
654: conds_integer);
655: if (TME_SPARC_VERSION(ic) >= 9) {
656: printf("sparc%u %%xcc conds thunk %p:\n",
657: (1 << TME_SPARC_RECODE_SIZE(ic)),
658: ic->tme_sparc_recode_conds_thunk_xcc);
659: tme_recode_conds_thunk_dump(ic->tme_sparc_recode_ic,
660: ic->tme_sparc_recode_conds_thunk_xcc,
661: conds_integer);
662: printf("sparc%u %%rcc conds thunk %p:\n",
663: (1 << TME_SPARC_RECODE_SIZE(ic)),
664: ic->tme_sparc_recode_conds_thunk_rcc);
665: tme_recode_conds_thunk_dump(ic->tme_sparc_recode_ic,
666: ic->tme_sparc_recode_conds_thunk_rcc,
667: conds_integer);
668: }
669: }
670:
671: void tme_sparc_recode_dump_insns _TME_P((const struct tme_sparc *));
672: void
673: tme_sparc_recode_dump_insns(const struct tme_sparc *ic)
674: {
675: const struct tme_recode_insn *insns;
676: const struct tme_recode_insn *insns_end;
677: unsigned int insn_i;
678: const char *s;
679: unsigned int insn_size;
680: unsigned int operands_mask;
681: unsigned int thunk_i;
682: unsigned int operand_i;
683: int delim;
684: const char *regcs = "goli";
685: const char *conds_integer[] = {
686: "n", "e", "le", "l", "leu", "cs", "neg", "vs",
687: "a", "ne", "g", "ge", "gu", "cc", "pos", "vc",
688: };
689: tme_uint32_t chain_info;
690:
691: printf("%%pc = ");
692: tme_recode_uguest_dump(
693: #if TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32
694: TME_SPARC_VERSION(ic) >= 9
695: ? ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC)
696: :
697: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32 */
698: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC));
699: printf("\n");
700:
701: insns = ic->tme_sparc_recode_insns_group.tme_recode_insns_group_insns;
702: insns_end = ic->tme_sparc_recode_insns_group.tme_recode_insns_group_insns_end;
703: for (insn_i = 0; insns < insns_end; insns++, insn_i++) {
704:
705: printf("%2u: ", insn_i);
706:
707: s = tme_recode_opcode_dump(insns->tme_recode_insn_opcode);
708: insn_size = insns->tme_recode_insn_size;
709: switch (insns->tme_recode_insn_opcode) {
710: case TME_RECODE_OPCODE_EXTZ:
711: case TME_RECODE_OPCODE_EXTS:
712: printf("ext%u%c",
713: (1 << insns->tme_recode_insn_operand_src[1]),
714: (insns->tme_recode_insn_opcode == TME_RECODE_OPCODE_EXTZ ? 'z' : 's'));
715: s = "";
716: operands_mask = (1 << 0) | (1 << 2);
717: break;
718: case TME_RECODE_OPCODE_DEFC:
719: printf("defc\t %%%ccc:%s, %%c%u\n",
720: (insns->tme_recode_insn_conds_thunk == ic->tme_sparc_recode_conds_thunk_icc
721: ? 'i'
722: : insns->tme_recode_insn_conds_thunk == ic->tme_sparc_recode_conds_thunk_xcc
723: ? 'x'
724: : 'r'),
725: conds_integer
726: [insns->tme_recode_insn_operand_src[0]
727: + (TME_SPARC_COND_NOT
728: * (insns->tme_recode_insn_operand_src[1] != 0))],
729: insns->tme_recode_insn_operand_dst);
730: continue;
731: case TME_RECODE_OPCODE_IF:
732: printf("%s\t %%c%u\n", s, insns->tme_recode_insn_operand_src[0]);
733: continue;
734: case TME_RECODE_OPCODE_ELSE:
735: case TME_RECODE_OPCODE_ENDIF:
736: printf("%s\n", s);
737: continue;
738: case TME_RECODE_OPCODE_RW:
739: for (thunk_i = 0;; thunk_i++) {
740: assert (thunk_i < TME_ARRAY_ELS(ic->tme_sparc_recode_rw_thunks));
741: if (insns->tme_recode_insn_rw_thunk == ic->tme_sparc_recode_rw_thunks[thunk_i]) {
742: break;
743: }
744: }
745: s = "?rw?";
746: switch (thunk_i % 0x10) {
747: case 0x0: s = (TME_SPARC_VERSION(ic) >= 9 ? "lduw" : "ld"); break;
748: case 0x1: s = "ldub"; break;
749: case 0x2: s = "lduh"; break;
750: case 0x4: s = (TME_SPARC_VERSION(ic) >= 9 ? "stw" : "st"); break;
751: case 0x5: s = "stb"; break;
752: case 0x6: s = "sth"; break;
753: case 0x8: if (TME_SPARC_VERSION(ic) >= 9) { s = "ldsw"; } break;
754: case 0x9: s = "ldsb"; break;
755: case 0xa: s = "ldsh"; break;
756: case 0xb: if (TME_SPARC_VERSION(ic) >= 9) { s = "ldx"; } break;
757: case 0xe: if (TME_SPARC_VERSION(ic) >= 9) { s = "stx"; } break;
758: }
759: if (thunk_i & 16) {
760: printf("%s", s);
761: s = ".nf";
762: }
763: if (thunk_i & 32) {
764: printf("%s", s);
765: s = ".el";
766: }
767: if (thunk_i & 64) {
768: printf("%s", s);
769: s = ".am";
770: }
771: insn_size = 0;
772: operands_mask = (1 << 0);
773: if (insns->tme_recode_insn_rw_thunk->tme_recode_rw_thunk_write) {
774: operands_mask |= (1 << 1);
775: }
776: else {
777: operands_mask |= (1 << 2);
778: }
779: break;
780: default:
781: operands_mask = (1 << 0) | (1 << 1) | (1 << 2);
782: break;
783: }
784:
785: printf("%s", s);
786: if (insn_size > 0) {
787: printf("%u", (1 << insns->tme_recode_insn_size));
788: }
789: delim = '\t';
790: for (operand_i = 0; operand_i <= 2; operand_i++) {
791: if (operands_mask & (1 << operand_i)) {
792: putchar(delim);
793: putchar(' ');
794: delim = ',';
795: switch (insns->tme_recode_insn_operands[operand_i]) {
796: case TME_RECODE_OPERAND_UNDEF:
797: s = "undef";
798: break;
799: case TME_RECODE_OPERAND_IMM:
800: tme_recode_uguest_dump(insns->tme_recode_insn_imm_uguest);
801: continue;
802: #if TME_RECODE_OPERAND_NULL != TME_RECODE_OPERAND_ZERO
803: #error "TME_RECODE_OPERAND_ values changed"
804: #endif
805: case TME_RECODE_OPERAND_ZERO:
806: s = "g0";
807: if (operand_i == 2
808: && insns->tme_recode_insn_opcode == TME_RECODE_OPCODE_GUEST) {
809: s = "null";
810: }
811: break;
812: case TME_SPARC_IREG_PC: s = "pc"; break;
813: case TME_SPARC_IREG_PC_NEXT: s = "pc_next"; break;
814: case TME_SPARC_IREG_PC_NEXT_NEXT: s = "pc_next_next"; break;
815: case TME_SPARC_IREG_INSN: s = "insn"; break;
816: case TME_SPARC_IREG_TMP(0): s = "tmp0"; break;
817: case TME_SPARC_IREG_TMP(1): s = "tmp1"; break;
818: case TME_SPARC_IREG_TMP(2): s = "tmp2"; break;
819: default:
820: if (insns->tme_recode_insn_operands[operand_i] < 32) {
821: printf("%%%c%u",
822: regcs[insns->tme_recode_insn_operands[operand_i] / 8],
823: (insns->tme_recode_insn_operands[operand_i] % 8));
824: continue;
825: }
826: s = "??";
827: break;
828: }
829: printf("%%%s", s);
830: }
831: }
832:
833: if (insns->tme_recode_insn_opcode < TME_RECODE_OPCODES_INTEGER
834: && insns->tme_recode_insn_flags_thunk != NULL) {
835: printf(", %%%s",
836: (TME_SPARC_VERSION(ic) < 9
837: ? "icc"
838: : insns->tme_recode_insn_flags_thunk == ic->tme_sparc_recode_flags_thunk_rcc
839: ? "rcc"
840: : "ccr"));
841: }
842:
843: putchar('\n');
844: }
845:
846: chain_info = ic->tme_sparc_recode_insns_group.tme_recode_insns_group_chain_info;
847: printf("chain %s %s ",
848: ((chain_info & TME_RECODE_CHAIN_INFO_JUMP)
849: ? "jump"
850: : (chain_info & TME_RECODE_CHAIN_INFO_RETURN)
851: ? "return"
852: : "call"),
853: (((chain_info
854: & (TME_RECODE_CHAIN_INFO_NEAR
855: | TME_RECODE_CHAIN_INFO_FAR))
856: == TME_RECODE_CHAIN_INFO_NEAR)
857: ? "near"
858: : "far"));
859: if ((chain_info
860: & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL
861: | TME_RECODE_CHAIN_INFO_CONDITIONAL))
862: == TME_RECODE_CHAIN_INFO_UNCONDITIONAL) {
863: printf("unconditional\n");
864: }
865: else {
866: printf("conditional alternate %s\n",
867: (((chain_info
868: & (TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR
869: | TME_RECODE_CHAIN_INFO_ALTERNATE_FAR))
870: == TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR)
871: ? "near"
872: : "far"));
873: }
874: }
875:
876: #endif /* TME_RECODE_DEBUG */
877:
878: #endif /* TME_HAVE_RECODE */
879:
880: /* this initializes sparc recoding: */
881: void
882: tme_sparc_recode_init(struct tme_sparc *ic)
883: {
884: #if TME_HAVE_RECODE
885: unsigned long reg_guest_count;
886: unsigned long reg_guest;
887: struct tme_recode_ic *recode_ic;
888:
889: /* get the number of guest registers: */
890: reg_guest_count = TME_SPARC_IREG_TMP(3);
891:
892: /* allocate the recode ic: */
893: recode_ic
894: = tme_malloc0(sizeof(struct tme_recode_ic)
895: + (sizeof(union tme_recode_reginfo)
896: * reg_guest_count));
897: ic->tme_sparc_recode_ic = recode_ic;
898:
899: /* set the register size: */
900: recode_ic->tme_recode_ic_reg_size = TME_SPARC_RECODE_SIZE(ic);
901:
902: /* set the register count: */
903: recode_ic->tme_recode_ic_reg_count = reg_guest_count;
904:
905: /* allocate some number of read-uses records: */
906: /* XXX FIXME - this can be anything, and doesn't affect correctness,
907: just performance. should it be tunable? */
908: recode_ic->tme_recode_ic_reg_guest_ruses_record_count = 512;
909: recode_ic->tme_recode_ic_reg_guest_ruses_records
910: = tme_new(tme_uint16_t,
911: recode_ic->tme_recode_ic_reg_guest_ruses_record_count + 1);
912: recode_ic->tme_recode_ic_reg_guest_ruses_records
913: [recode_ic->tme_recode_ic_reg_guest_ruses_record_count]
914: = TME_RECODE_REG_RUSES_RECORD_UNDEF;
915:
916: /* assume that all registers use flat addressing: */
917: for (reg_guest = 0;
918: reg_guest < reg_guest_count;
919: reg_guest++) {
920: (recode_ic->tme_recode_ic_reginfo
921: + reg_guest)->tme_recode_reginfo_all = TME_RECODE_REGINFO_TYPE_FLAT;
922: }
923:
924: /* %g0 is fixed: */
925: (recode_ic->tme_recode_ic_reginfo
926: + TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0))->tme_recode_reginfo_all
927: |= TME_RECODE_REGINFO_TYPE_FIXED;
928:
929: /* %r8 through %r23 are addressed through window zero, and %r24
930: through %r31 are addressed through window one: */
931: reg_guest = TME_RECODE_REG_GUEST(8);
932: do {
933: (recode_ic->tme_recode_ic_reginfo
934: + reg_guest)->tme_recode_reginfo_all = TME_RECODE_REGINFO_TYPE_WINDOW(0);
935: } while (++reg_guest <= TME_RECODE_REG_GUEST(23));
936: do {
937: (recode_ic->tme_recode_ic_reginfo
938: + reg_guest)->tme_recode_reginfo_all = TME_RECODE_REGINFO_TYPE_WINDOW(1);
939: } while (++reg_guest <= TME_RECODE_REG_GUEST(31));
940:
941: /* on a v9 CPU, %r1 through %r7 are addressed through window two: */
942: if (TME_SPARC_VERSION(ic) >= 9) {
943: reg_guest = TME_RECODE_REG_GUEST(1);
944: do {
945: (recode_ic->tme_recode_ic_reginfo
946: + reg_guest)->tme_recode_reginfo_all = TME_RECODE_REGINFO_TYPE_WINDOW(2);
947: } while (++reg_guest <= TME_RECODE_REG_GUEST(7));
948: }
949:
950: /* the temporary registers are temporary: */
951: reg_guest = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(0));
952: do {
953: (recode_ic->tme_recode_ic_reginfo
954: + reg_guest)->tme_recode_reginfo_all
955: |= TME_RECODE_REGINFO_TYPE_TEMPORARY;
956: } while (++reg_guest <= TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(2)));
957:
958: /* set the window base offsets: */
959: recode_ic->tme_recode_ic_window_base_offsets[0]
960: = (((char *) &ic->tme_sparc_recode_window_base_offsets[0]) - ((char *) ic));
961: recode_ic->tme_recode_ic_window_base_offsets[1]
962: = (((char *) &ic->tme_sparc_recode_window_base_offsets[1]) - ((char *) ic));
963: recode_ic->tme_recode_ic_window_base_offsets[2]
964: = (((char *) &ic->tme_sparc_recode_window_base_offsets[2]) - ((char *) ic));
965:
966: /* initialize the cacheables: */
967: ic->tme_sparc_recode_cacheables[0].tme_sparc_recode_cacheable_size = 0;
968: ic->tme_sparc_recode_cacheable_first = &ic->tme_sparc_recode_cacheables[0];
969:
970: /* invalidate the entire source hash: */
971: _tme_sparc_recode_src_hash_invalidate(ic, 0, 0);
972:
973: /* set the TLB page size: */
974: recode_ic->tme_recode_ic_tlb_page_size
975: = (((tme_uint32_t) 1) << ic->tme_sparc_tlb_page_size_log2);
976:
977: /* set the pointer to the first instruction in a group: */
978: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_insns
979: = &ic->tme_sparc_recode_insns[0];
980:
981: /* initialize the recode ic: */
982: /* XXX FIXME - this run size should be passed in as an argument. it
983: needs to be big enough for the maximum number of non-variable
984: thunks (flags, conds, chain, etc.) that we will make, probably
985: TME_RECODE_HOST_THUNK_SIZE_MAX times some n? */
986: tme_recode_ic_new(recode_ic, 4 * 1024 * 1024);
987:
988: /* call the architecture-specific init functions: */
989: if (TME_SPARC_VERSION(ic) >= 9) {
990: #if TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32
991: _tme_sparc64_recode_cc_init(ic);
992: _tme_sparc64_recode_chain_init(ic);
993: _tme_sparc64_recode_ls_init(ic);
994: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_RECODE_SIZE_32 */
995: }
996: else {
997: _tme_sparc32_recode_cc_init(ic);
998: _tme_sparc32_recode_chain_init(ic);
999: _tme_sparc32_recode_ls_init(ic);
1000: }
1001:
1002: #ifdef _TME_SPARC_RECODE_VERIFY
1003:
1004: /* initialize the verifier: */
1005: _tme_sparc_recode_verify_init(ic);
1006:
1007: #endif /* _TME_SPARC_RECODE_VERIFY */
1008:
1009: #else /* !TME_HAVE_RECODE */
1010: /* unused: */
1011: ic = 0;
1012: #endif /* !TME_HAVE_RECODE */
1013: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.