Skip to content

Commit c4fc316

Browse files
Merge commit '8ed558ec0c' into merge
Signed-off-by: Francisco Iglesias <francisco.iglesias@amd.com>
2 parents 4a6c71e + 8ed558e commit c4fc316

File tree

6 files changed

+131
-29
lines changed

6 files changed

+131
-29
lines changed

accel/tcg/cpu-exec.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
187187
const TranslationBlock *tb = p;
188188
const struct tb_desc *desc = d;
189189

190-
if (tb_pc(tb) == desc->pc &&
190+
if ((TARGET_TB_PCREL || tb_pc(tb) == desc->pc) &&
191191
tb->page_addr[0] == desc->page_addr0 &&
192192
tb->cs_base == desc->cs_base &&
193193
tb->flags == desc->flags &&
@@ -238,7 +238,8 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
238238
return NULL;
239239
}
240240
desc.page_addr0 = phys_pc;
241-
h = tb_hash_func(phys_pc, pc, flags, cflags, *cpu->trace_dstate);
241+
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : pc),
242+
flags, cflags, *cpu->trace_dstate);
242243
return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
243244
}
244245

@@ -248,16 +249,18 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
248249
uint32_t flags, uint32_t cflags)
249250
{
250251
TranslationBlock *tb;
252+
CPUJumpCache *jc;
251253
uint32_t hash;
252254

253255
/* we should never be trying to look up an INVALID tb */
254256
tcg_debug_assert(!(cflags & CF_INVALID));
255257

256258
hash = tb_jmp_cache_hash_func(pc);
257-
tb = qatomic_rcu_read(&cpu->tb_jmp_cache->array[hash].tb);
259+
jc = cpu->tb_jmp_cache;
260+
tb = tb_jmp_cache_get_tb(jc, hash);
258261

259262
if (likely(tb &&
260-
tb->pc == pc &&
263+
tb_jmp_cache_get_pc(jc, hash, tb) == pc &&
261264
tb->cs_base == cs_base &&
262265
tb->flags == flags &&
263266
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
@@ -268,7 +271,7 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
268271
if (tb == NULL) {
269272
return NULL;
270273
}
271-
qatomic_set(&cpu->tb_jmp_cache->array[hash].tb, tb);
274+
tb_jmp_cache_set(jc, hash, tb, pc);
272275
return tb;
273276
}
274277

@@ -464,6 +467,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
464467
if (cc->tcg_ops->synchronize_from_tb) {
465468
cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
466469
} else {
470+
assert(!TARGET_TB_PCREL);
467471
assert(cc->set_pc);
468472
cc->set_pc(cpu, tb_pc(last_tb));
469473
}
@@ -1031,7 +1035,7 @@ int cpu_exec(CPUState *cpu)
10311035
* for the fast lookup
10321036
*/
10331037
h = tb_jmp_cache_hash_func(pc);
1034-
qatomic_set(&cpu->tb_jmp_cache->array[h].tb, tb);
1038+
tb_jmp_cache_set(cpu->tb_jmp_cache, h, tb, pc);
10351039
}
10361040

10371041
#ifndef CONFIG_USER_ONLY

accel/tcg/internal.h

+4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ void tb_htable_init(void);
2121
/* Return the current PC from CPU, which may be cached in TB. */
2222
static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb)
2323
{
24+
#if TARGET_TB_PCREL
25+
return cpu->cc->get_pc(cpu);
26+
#else
2427
return tb_pc(tb);
28+
#endif
2529
}
2630

2731
#endif /* ACCEL_TCG_INTERNAL_H */

accel/tcg/tb-jmp-cache.h

+41
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,52 @@
1414

1515
/*
1616
* Accessed in parallel; all accesses to 'tb' must be atomic.
17+
* For TARGET_TB_PCREL, accesses to 'pc' must be protected by
18+
* a load_acquire/store_release to 'tb'.
1719
*/
1820
struct CPUJumpCache {
1921
struct {
2022
TranslationBlock *tb;
23+
#if TARGET_TB_PCREL
24+
target_ulong pc;
25+
#endif
2126
} array[TB_JMP_CACHE_SIZE];
2227
};
2328

29+
static inline TranslationBlock *
30+
tb_jmp_cache_get_tb(CPUJumpCache *jc, uint32_t hash)
31+
{
32+
#if TARGET_TB_PCREL
33+
/* Use acquire to ensure current load of pc from jc. */
34+
return qatomic_load_acquire(&jc->array[hash].tb);
35+
#else
36+
/* Use rcu_read to ensure current load of pc from *tb. */
37+
return qatomic_rcu_read(&jc->array[hash].tb);
38+
#endif
39+
}
40+
41+
static inline target_ulong
42+
tb_jmp_cache_get_pc(CPUJumpCache *jc, uint32_t hash, TranslationBlock *tb)
43+
{
44+
#if TARGET_TB_PCREL
45+
return jc->array[hash].pc;
46+
#else
47+
return tb_pc(tb);
48+
#endif
49+
}
50+
51+
static inline void
52+
tb_jmp_cache_set(CPUJumpCache *jc, uint32_t hash,
53+
TranslationBlock *tb, target_ulong pc)
54+
{
55+
#if TARGET_TB_PCREL
56+
jc->array[hash].pc = pc;
57+
/* Use store_release on tb to ensure pc is written first. */
58+
qatomic_store_release(&jc->array[hash].tb, tb);
59+
#else
60+
/* Use the pc value already stored in tb->pc. */
61+
qatomic_set(&jc->array[hash].tb, tb);
62+
#endif
63+
}
64+
2465
#endif /* ACCEL_TCG_TB_JMP_CACHE_H */

accel/tcg/translate-all.c

+43-21
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
300300

301301
for (j = 0; j < TARGET_INSN_START_WORDS; ++j) {
302302
if (i == 0) {
303-
prev = (j == 0 ? tb_pc(tb) : 0);
303+
prev = (!TARGET_TB_PCREL && j == 0 ? tb_pc(tb) : 0);
304304
} else {
305305
prev = tcg_ctx->gen_insn_data[i - 1][j];
306306
}
@@ -328,7 +328,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
328328
static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
329329
uintptr_t searched_pc, bool reset_icount)
330330
{
331-
target_ulong data[TARGET_INSN_START_WORDS] = { tb_pc(tb) };
331+
target_ulong data[TARGET_INSN_START_WORDS];
332332
uintptr_t host_pc = (uintptr_t)tb->tc.ptr;
333333
CPUArchState *env = cpu->env_ptr;
334334
const uint8_t *p = tb->tc.ptr + tb->tc.size;
@@ -344,6 +344,11 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
344344
return -1;
345345
}
346346

347+
memset(data, 0, sizeof(data));
348+
if (!TARGET_TB_PCREL) {
349+
data[0] = tb_pc(tb);
350+
}
351+
347352
/* Reconstruct the stored insn data while looking for the point at
348353
which the end of the insn exceeds the searched_pc. */
349354
for (i = 0; i < num_insns; ++i) {
@@ -886,13 +891,13 @@ static bool tb_cmp(const void *ap, const void *bp)
886891
const TranslationBlock *a = ap;
887892
const TranslationBlock *b = bp;
888893

889-
return tb_pc(a) == tb_pc(b) &&
890-
a->cs_base == b->cs_base &&
891-
a->flags == b->flags &&
892-
(tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) &&
893-
a->trace_vcpu_dstate == b->trace_vcpu_dstate &&
894-
a->page_addr[0] == b->page_addr[0] &&
895-
a->page_addr[1] == b->page_addr[1];
894+
return ((TARGET_TB_PCREL || tb_pc(a) == tb_pc(b)) &&
895+
a->cs_base == b->cs_base &&
896+
a->flags == b->flags &&
897+
(tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) &&
898+
a->trace_vcpu_dstate == b->trace_vcpu_dstate &&
899+
a->page_addr[0] == b->page_addr[0] &&
900+
a->page_addr[1] == b->page_addr[1]);
896901
}
897902

898903
void tb_htable_init(void)
@@ -1149,14 +1154,35 @@ static inline void tb_jmp_unlink(TranslationBlock *dest)
11491154
qemu_spin_unlock(&dest->jmp_lock);
11501155
}
11511156

1157+
static void tb_jmp_cache_inval_tb(TranslationBlock *tb)
1158+
{
1159+
CPUState *cpu;
1160+
1161+
if (TARGET_TB_PCREL) {
1162+
/* A TB may be at any virtual address */
1163+
CPU_FOREACH(cpu) {
1164+
tcg_flush_jmp_cache(cpu);
1165+
}
1166+
} else {
1167+
uint32_t h = tb_jmp_cache_hash_func(tb_pc(tb));
1168+
1169+
CPU_FOREACH(cpu) {
1170+
CPUJumpCache *jc = cpu->tb_jmp_cache;
1171+
1172+
if (qatomic_read(&jc->array[h].tb) == tb) {
1173+
qatomic_set(&jc->array[h].tb, NULL);
1174+
}
1175+
}
1176+
}
1177+
}
1178+
11521179
/*
11531180
* In user-mode, call with mmap_lock held.
11541181
* In !user-mode, if @rm_from_page_list is set, call with the TB's pages'
11551182
* locks held.
11561183
*/
11571184
static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
11581185
{
1159-
CPUState *cpu;
11601186
PageDesc *p;
11611187
uint32_t h;
11621188
tb_page_addr_t phys_pc;
@@ -1171,8 +1197,8 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
11711197

11721198
/* remove the TB from the hash list */
11731199
phys_pc = tb->page_addr[0];
1174-
h = tb_hash_func(phys_pc, tb_pc(tb), tb->flags, orig_cflags,
1175-
tb->trace_vcpu_dstate);
1200+
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)),
1201+
tb->flags, orig_cflags, tb->trace_vcpu_dstate);
11761202
if (!qht_remove(&tb_ctx.htable, tb, h)) {
11771203
return;
11781204
}
@@ -1188,13 +1214,7 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
11881214
}
11891215

11901216
/* remove the TB from the hash list */
1191-
h = tb_jmp_cache_hash_func(tb->pc);
1192-
CPU_FOREACH(cpu) {
1193-
CPUJumpCache *jc = cpu->tb_jmp_cache;
1194-
if (qatomic_read(&jc->array[h].tb) == tb) {
1195-
qatomic_set(&jc->array[h].tb, NULL);
1196-
}
1197-
}
1217+
tb_jmp_cache_inval_tb(tb);
11981218

11991219
/* suppress this TB from the two jump lists */
12001220
tb_remove_from_jmp_list(tb, 0);
@@ -1303,8 +1323,8 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
13031323
}
13041324

13051325
/* add in the hash table */
1306-
h = tb_hash_func(phys_pc, tb_pc(tb), tb->flags, tb->cflags,
1307-
tb->trace_vcpu_dstate);
1326+
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)),
1327+
tb->flags, tb->cflags, tb->trace_vcpu_dstate);
13081328
qht_insert(&tb_ctx.htable, tb, h, &existing_tb);
13091329

13101330
/* remove TB from the page(s) if we couldn't insert it */
@@ -1375,7 +1395,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
13751395

13761396
gen_code_buf = tcg_ctx->code_gen_ptr;
13771397
tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf);
1398+
#if !TARGET_TB_PCREL
13781399
tb->pc = pc;
1400+
#endif
13791401
tb->cs_base = cs_base;
13801402
tb->flags = flags;
13811403
tb->cflags = cflags;

include/exec/cpu-defs.h

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
# error TARGET_PAGE_BITS must be defined in cpu-param.h
5555
# endif
5656
#endif
57+
#ifndef TARGET_TB_PCREL
58+
# define TARGET_TB_PCREL 0
59+
#endif
5760

5861
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
5962

include/exec/exec-all.h

+30-2
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,32 @@ struct tb_tc {
496496
};
497497

498498
struct TranslationBlock {
499-
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
500-
target_ulong cs_base; /* CS base for this block */
499+
#if !TARGET_TB_PCREL
500+
/*
501+
* Guest PC corresponding to this block. This must be the true
502+
* virtual address. Therefore e.g. x86 stores EIP + CS_BASE, and
503+
* targets like Arm, MIPS, HP-PA, which reuse low bits for ISA or
504+
* privilege, must store those bits elsewhere.
505+
*
506+
* If TARGET_TB_PCREL, the opcodes for the TranslationBlock are
507+
* written such that the TB is associated only with the physical
508+
* page and may be run in any virtual address context. In this case,
509+
* PC must always be taken from ENV in a target-specific manner.
510+
* Unwind information is taken as offsets from the page, to be
511+
* deposited into the "current" PC.
512+
*/
513+
target_ulong pc;
514+
#endif
515+
516+
/*
517+
* Target-specific data associated with the TranslationBlock, e.g.:
518+
* x86: the original user, the Code Segment virtual base,
519+
* arm: an extension of tb->flags,
520+
* s390x: instruction data for EXECUTE,
521+
* sparc: the next pc of the instruction queue (for delay slots).
522+
*/
523+
target_ulong cs_base;
524+
501525
uint32_t flags; /* flags defining in which context the code was generated */
502526
uint32_t cflags; /* compile flags */
503527

@@ -573,7 +597,11 @@ struct TranslationBlock {
573597
/* Hide the read to avoid ifdefs for TARGET_TB_PCREL. */
574598
static inline target_ulong tb_pc(const TranslationBlock *tb)
575599
{
600+
#if TARGET_TB_PCREL
601+
qemu_build_not_reached();
602+
#else
576603
return tb->pc;
604+
#endif
577605
}
578606

579607
/* Hide the qatomic_read to make code a little easier on the eyes */

0 commit comments

Comments
 (0)