Skip to content

Commit 0b6206b

Browse files
committed
Merge remote-tracking branch 'remotes/rth-gitlab/tags/pull-tcg-20210914-4' into staging
Fix translation race condition for user-only. Fix tcg/i386 encoding for VPSLLVQ, VPSRLVQ. Fix tcg/arm tcg_out_vec_op signature. Fix tcg/ppc (32bit) build with clang. Remove dupluate TCG_KICK_PERIOD definition. Remove unused tcg_global_reg_new. Restrict cpu_exec_interrupt and its callees to sysemu. Cleanups for tcg/arm. # gpg: Signature made Tue 14 Sep 2021 20:28:35 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "[email protected]" # gpg: Good signature from "Richard Henderson <[email protected]>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth-gitlab/tags/pull-tcg-20210914-4: (43 commits) tcg/arm: More use of the TCGReg enum tcg/arm: More use of the ARMInsn enum tcg/arm: Give enum arm_cond_code_e a typedef and use it tcg/arm: Drop inline markers tcg/arm: Simplify usage of encode_imm tcg/arm: Split out tcg_out_ldstm tcg/arm: Support armv4t in tcg_out_goto and tcg_out_call tcg/arm: Simplify use_armv5t_instructions tcg/arm: Standardize on tcg_out_<branch>_{reg,imm} tcg/arm: Remove fallback definition of __ARM_ARCH accel/tcg/user-exec: Fix read-modify-write of code on s390 hosts user: Remove cpu_get_pic_interrupt() stubs accel/tcg: Restrict TCGCPUOps::cpu_exec_interrupt() to sysemu target/xtensa: Restrict cpu_exec_interrupt() handler to sysemu target/rx: Restrict cpu_exec_interrupt() handler to sysemu target/sparc: Restrict cpu_exec_interrupt() handler to sysemu target/sh4: Restrict cpu_exec_interrupt() handler to sysemu target/riscv: Restrict cpu_exec_interrupt() handler to sysemu target/ppc: Restrict cpu_exec_interrupt() handler to sysemu target/openrisc: Restrict cpu_exec_interrupt() handler to sysemu ... Signed-off-by: Peter Maydell <[email protected]>
2 parents 831aaf2 + e028ead commit 0b6206b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+699
-627
lines changed

accel/tcg/cpu-exec.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
651651
loop */
652652
#if defined(TARGET_I386)
653653
CPUClass *cc = CPU_GET_CLASS(cpu);
654-
cc->tcg_ops->do_interrupt(cpu);
655-
#endif
654+
cc->tcg_ops->fake_user_interrupt(cpu);
655+
#endif /* TARGET_I386 */
656656
*ret = cpu->exception_index;
657657
cpu->exception_index = -1;
658658
return true;
@@ -685,6 +685,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
685685
return false;
686686
}
687687

688+
#ifndef CONFIG_USER_ONLY
688689
/*
689690
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
690691
* "real" interrupt event later. It does not need to be recorded for
@@ -698,12 +699,11 @@ static inline bool need_replay_interrupt(int interrupt_request)
698699
return true;
699700
#endif
700701
}
702+
#endif /* !CONFIG_USER_ONLY */
701703

702704
static inline bool cpu_handle_interrupt(CPUState *cpu,
703705
TranslationBlock **last_tb)
704706
{
705-
CPUClass *cc = CPU_GET_CLASS(cpu);
706-
707707
/* Clear the interrupt flag now since we're processing
708708
* cpu->interrupt_request and cpu->exit_request.
709709
* Ensure zeroing happens before reading cpu->exit_request or
@@ -725,6 +725,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
725725
qemu_mutex_unlock_iothread();
726726
return true;
727727
}
728+
#if !defined(CONFIG_USER_ONLY)
728729
if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) {
729730
/* Do nothing */
730731
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
@@ -753,12 +754,14 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
753754
qemu_mutex_unlock_iothread();
754755
return true;
755756
}
756-
#endif
757+
#endif /* !TARGET_I386 */
757758
/* The target hook has 3 exit conditions:
758759
False when the interrupt isn't processed,
759760
True when it is, and we should restart on a new TB,
760761
and via longjmp via cpu_loop_exit. */
761762
else {
763+
CPUClass *cc = CPU_GET_CLASS(cpu);
764+
762765
if (cc->tcg_ops->cpu_exec_interrupt &&
763766
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
764767
if (need_replay_interrupt(interrupt_request)) {
@@ -777,6 +780,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
777780
* reload the 'interrupt_request' value */
778781
interrupt_request = cpu->interrupt_request;
779782
}
783+
#endif /* !CONFIG_USER_ONLY */
780784
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
781785
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
782786
/* ensure that no TB jump will be modified as

accel/tcg/tcg-accel-ops-rr.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ void rr_kick_vcpu_thread(CPUState *unused)
6060
static QEMUTimer *rr_kick_vcpu_timer;
6161
static CPUState *rr_current_cpu;
6262

63-
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
64-
6563
static inline int64_t rr_next_kick_time(void)
6664
{
6765
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;

accel/tcg/translate-all.c

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,31 +1297,8 @@ static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
12971297
invalidate_page_bitmap(p);
12981298

12991299
#if defined(CONFIG_USER_ONLY)
1300-
if (p->flags & PAGE_WRITE) {
1301-
target_ulong addr;
1302-
PageDesc *p2;
1303-
int prot;
1304-
1305-
/* force the host page as non writable (writes will have a
1306-
page fault + mprotect overhead) */
1307-
page_addr &= qemu_host_page_mask;
1308-
prot = 0;
1309-
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
1310-
addr += TARGET_PAGE_SIZE) {
1311-
1312-
p2 = page_find(addr >> TARGET_PAGE_BITS);
1313-
if (!p2) {
1314-
continue;
1315-
}
1316-
prot |= p2->flags;
1317-
p2->flags &= ~PAGE_WRITE;
1318-
}
1319-
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
1320-
(prot & PAGE_BITS) & ~PAGE_WRITE);
1321-
if (DEBUG_TB_INVALIDATE_GATE) {
1322-
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
1323-
}
1324-
}
1300+
/* translator_loop() must have made all TB pages non-writable */
1301+
assert(!(p->flags & PAGE_WRITE));
13251302
#else
13261303
/* if some code is already present, then the pages are already
13271304
protected. So we handle the case where only the first TB is
@@ -2394,6 +2371,38 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
23942371
return 0;
23952372
}
23962373

2374+
void page_protect(tb_page_addr_t page_addr)
2375+
{
2376+
target_ulong addr;
2377+
PageDesc *p;
2378+
int prot;
2379+
2380+
p = page_find(page_addr >> TARGET_PAGE_BITS);
2381+
if (p && (p->flags & PAGE_WRITE)) {
2382+
/*
2383+
* Force the host page as non writable (writes will have a page fault +
2384+
* mprotect overhead).
2385+
*/
2386+
page_addr &= qemu_host_page_mask;
2387+
prot = 0;
2388+
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
2389+
addr += TARGET_PAGE_SIZE) {
2390+
2391+
p = page_find(addr >> TARGET_PAGE_BITS);
2392+
if (!p) {
2393+
continue;
2394+
}
2395+
prot |= p->flags;
2396+
p->flags &= ~PAGE_WRITE;
2397+
}
2398+
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
2399+
(prot & PAGE_BITS) & ~PAGE_WRITE);
2400+
if (DEBUG_TB_INVALIDATE_GATE) {
2401+
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
2402+
}
2403+
}
2404+
}
2405+
23972406
/* called from signal handler: invalidate the code and unprotect the
23982407
* page. Return 0 if the fault was not handled, 1 if it was handled,
23992408
* and 2 if it was handled but the caller must cause the TB to be

accel/tcg/translator.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
4242
return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
4343
}
4444

45+
static inline void translator_page_protect(DisasContextBase *dcbase,
46+
target_ulong pc)
47+
{
48+
#ifdef CONFIG_USER_ONLY
49+
dcbase->page_protect_end = pc | ~TARGET_PAGE_MASK;
50+
page_protect(pc);
51+
#endif
52+
}
53+
4554
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
4655
CPUState *cpu, TranslationBlock *tb, int max_insns)
4756
{
@@ -56,6 +65,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
5665
db->num_insns = 0;
5766
db->max_insns = max_insns;
5867
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
68+
translator_page_protect(db, db->pc_next);
5969

6070
ops->init_disas_context(db, cpu);
6171
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
@@ -137,3 +147,32 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
137147
}
138148
#endif
139149
}
150+
151+
static inline void translator_maybe_page_protect(DisasContextBase *dcbase,
152+
target_ulong pc, size_t len)
153+
{
154+
#ifdef CONFIG_USER_ONLY
155+
target_ulong end = pc + len - 1;
156+
157+
if (end > dcbase->page_protect_end) {
158+
translator_page_protect(dcbase, end);
159+
}
160+
#endif
161+
}
162+
163+
#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \
164+
type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
165+
abi_ptr pc, bool do_swap) \
166+
{ \
167+
translator_maybe_page_protect(dcbase, pc, sizeof(type)); \
168+
type ret = load_fn(env, pc); \
169+
if (do_swap) { \
170+
ret = swap_fn(ret); \
171+
} \
172+
plugin_insn_append(&ret, sizeof(ret)); \
173+
return ret; \
174+
}
175+
176+
FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
177+
178+
#undef GEN_TRANSLATOR_LD

accel/tcg/user-exec.c

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -680,18 +680,26 @@ int cpu_signal_handler(int host_signum, void *pinfo,
680680

681681
pc = uc->uc_mcontext.psw.addr;
682682

683-
/* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
684-
of the normal 2 arguments. The 3rd argument contains the "int_code"
685-
from the hardware which does in fact contain the is_write value.
686-
The rt signal handler, as far as I can tell, does not give this value
687-
at all. Not that we could get to it from here even if it were. */
688-
/* ??? This is not even close to complete, since it ignores all
689-
of the read-modify-write instructions. */
683+
/*
684+
* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
685+
* of the normal 2 arguments. The 4th argument contains the "Translation-
686+
* Exception Identification for DAT Exceptions" from the hardware (aka
687+
* "int_parm_long"), which does in fact contain the is_write value.
688+
* The rt signal handler, as far as I can tell, does not give this value
689+
* at all. Not that we could get to it from here even if it were.
690+
* So fall back to parsing instructions. Treat read-modify-write ones as
691+
* writes, which is not fully correct, but for tracking self-modifying code
692+
* this is better than treating them as reads. Checking si_addr page flags
693+
* might be a viable improvement, albeit a racy one.
694+
*/
695+
/* ??? This is not even close to complete. */
690696
pinsn = (uint16_t *)pc;
691697
switch (pinsn[0] >> 8) {
692698
case 0x50: /* ST */
693699
case 0x42: /* STC */
694700
case 0x40: /* STH */
701+
case 0xba: /* CS */
702+
case 0xbb: /* CDS */
695703
is_write = 1;
696704
break;
697705
case 0xc4: /* RIL format insns */
@@ -702,6 +710,12 @@ int cpu_signal_handler(int host_signum, void *pinfo,
702710
is_write = 1;
703711
}
704712
break;
713+
case 0xc8: /* SSF format insns */
714+
switch (pinsn[0] & 0xf) {
715+
case 0x2: /* CSST */
716+
is_write = 1;
717+
}
718+
break;
705719
case 0xe3: /* RXY format insns */
706720
switch (pinsn[2] & 0xff) {
707721
case 0x50: /* STY */
@@ -715,7 +729,27 @@ int cpu_signal_handler(int host_signum, void *pinfo,
715729
is_write = 1;
716730
}
717731
break;
732+
case 0xeb: /* RSY format insns */
733+
switch (pinsn[2] & 0xff) {
734+
case 0x14: /* CSY */
735+
case 0x30: /* CSG */
736+
case 0x31: /* CDSY */
737+
case 0x3e: /* CDSG */
738+
case 0xe4: /* LANG */
739+
case 0xe6: /* LAOG */
740+
case 0xe7: /* LAXG */
741+
case 0xe8: /* LAAG */
742+
case 0xea: /* LAALG */
743+
case 0xf4: /* LAN */
744+
case 0xf6: /* LAO */
745+
case 0xf7: /* LAX */
746+
case 0xfa: /* LAAL */
747+
case 0xf8: /* LAA */
748+
is_write = 1;
749+
}
750+
break;
718751
}
752+
719753
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
720754
}
721755

bsd-user/i386/target_arch_cpu.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,6 @@ uint64_t cpu_get_tsc(CPUX86State *env)
3333
return cpu_get_host_ticks();
3434
}
3535

36-
int cpu_get_pic_interrupt(CPUX86State *env)
37-
{
38-
return -1;
39-
}
40-
4136
void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
4237
int flags)
4338
{

bsd-user/x86_64/target_arch_cpu.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,6 @@ uint64_t cpu_get_tsc(CPUX86State *env)
3333
return cpu_get_host_ticks();
3434
}
3535

36-
int cpu_get_pic_interrupt(CPUX86State *env)
37-
{
38-
return -1;
39-
}
40-
4136
void bsd_x86_64_write_dt(void *ptr, unsigned long addr,
4237
unsigned long limit, int flags)
4338
{

include/exec/translate-all.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end);
3333
void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr);
3434

3535
#ifdef CONFIG_USER_ONLY
36+
void page_protect(tb_page_addr_t page_addr);
3637
int page_unprotect(target_ulong address, uintptr_t pc);
3738
#endif
3839

include/exec/translator.h

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "exec/exec-all.h"
2424
#include "exec/cpu_ldst.h"
2525
#include "exec/plugin-gen.h"
26+
#include "exec/translate-all.h"
2627
#include "tcg/tcg.h"
2728

2829

@@ -74,6 +75,17 @@ typedef struct DisasContextBase {
7475
int num_insns;
7576
int max_insns;
7677
bool singlestep_enabled;
78+
#ifdef CONFIG_USER_ONLY
79+
/*
80+
* Guest address of the last byte of the last protected page.
81+
*
82+
* Pages containing the translated instructions are made non-writable in
83+
* order to achieve consistency in case another thread is modifying the
84+
* code while translate_insn() fetches the instruction bytes piecemeal.
85+
* Such writer threads are blocked on mmap_lock() in page_unprotect().
86+
*/
87+
target_ulong page_protect_end;
88+
#endif
7789
} DisasContextBase;
7890

7991
/**
@@ -156,27 +168,23 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest);
156168
*/
157169

158170
#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \
159-
static inline type \
160-
fullname ## _swap(CPUArchState *env, abi_ptr pc, bool do_swap) \
171+
type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
172+
abi_ptr pc, bool do_swap); \
173+
static inline type fullname(CPUArchState *env, \
174+
DisasContextBase *dcbase, abi_ptr pc) \
161175
{ \
162-
type ret = load_fn(env, pc); \
163-
if (do_swap) { \
164-
ret = swap_fn(ret); \
165-
} \
166-
plugin_insn_append(&ret, sizeof(ret)); \
167-
return ret; \
168-
} \
169-
\
170-
static inline type fullname(CPUArchState *env, abi_ptr pc) \
171-
{ \
172-
return fullname ## _swap(env, pc, false); \
176+
return fullname ## _swap(env, dcbase, pc, false); \
173177
}
174178

175-
GEN_TRANSLATOR_LD(translator_ldub, uint8_t, cpu_ldub_code, /* no swap */)
176-
GEN_TRANSLATOR_LD(translator_ldsw, int16_t, cpu_ldsw_code, bswap16)
177-
GEN_TRANSLATOR_LD(translator_lduw, uint16_t, cpu_lduw_code, bswap16)
178-
GEN_TRANSLATOR_LD(translator_ldl, uint32_t, cpu_ldl_code, bswap32)
179-
GEN_TRANSLATOR_LD(translator_ldq, uint64_t, cpu_ldq_code, bswap64)
179+
#define FOR_EACH_TRANSLATOR_LD(F) \
180+
F(translator_ldub, uint8_t, cpu_ldub_code, /* no swap */) \
181+
F(translator_ldsw, int16_t, cpu_ldsw_code, bswap16) \
182+
F(translator_lduw, uint16_t, cpu_lduw_code, bswap16) \
183+
F(translator_ldl, uint32_t, cpu_ldl_code, bswap32) \
184+
F(translator_ldq, uint64_t, cpu_ldq_code, bswap64)
185+
186+
FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
187+
180188
#undef GEN_TRANSLATOR_LD
181189

182190
#endif /* EXEC__TRANSLATOR_H */

0 commit comments

Comments
 (0)