1
This is mostly my code_gen_buffer cleanup, plus a few other random
1
The following changes since commit 6587b0c1331d427b0939c37e763842550ed581db:
2
changes thrown in. Including a fix for a recent float32_exp2 bug.
3
2
4
3
Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2021-10-15' into staging (2021-10-15 14:16:28 -0700)
5
r~
6
7
8
The following changes since commit 894fc4fd670aaf04a67dc7507739f914ff4bacf2:
9
10
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging (2021-06-11 09:21:48 +0100)
11
4
12
are available in the Git repository at:
5
are available in the Git repository at:
13
6
14
https://gitlab.com/rth7680/qemu.git tags/pull-tcg-20210611
7
https://gitlab.com/rth7680/qemu.git tags/pull-tcg-20211016
15
8
16
for you to fetch changes up to 60afaddc208d34f6dc86dd974f6e02724fba6eb6:
9
for you to fetch changes up to 995b87dedc78b0467f5f18bbc3546072ba97516a:
17
10
18
docs/devel: Explain in more detail the TB chaining mechanisms (2021-06-11 09:41:25 -0700)
11
Revert "cpu: Move cpu_common_props to hw/core/cpu.c" (2021-10-15 16:39:15 -0700)
19
12
20
----------------------------------------------------------------
13
----------------------------------------------------------------
21
Clean up code_gen_buffer allocation.
14
Move gdb singlestep to generic code
22
Add tcg_remove_ops_after.
15
Fix cpu_common_props
23
Fix tcg_constant_* documentation.
24
Improve TB chaining documentation.
25
Fix float32_exp2.
26
16
27
----------------------------------------------------------------
17
----------------------------------------------------------------
28
Jose R. Ziviani (1):
18
Richard Henderson (24):
29
tcg/arm: Fix tcg_out_op function signature
19
accel/tcg: Handle gdb singlestep in cpu_tb_exec
20
target/alpha: Drop checks for singlestep_enabled
21
target/avr: Drop checks for singlestep_enabled
22
target/cris: Drop checks for singlestep_enabled
23
target/hexagon: Drop checks for singlestep_enabled
24
target/arm: Drop checks for singlestep_enabled
25
target/hppa: Drop checks for singlestep_enabled
26
target/i386: Check CF_NO_GOTO_TB for dc->jmp_opt
27
target/i386: Drop check for singlestep_enabled
28
target/m68k: Drop checks for singlestep_enabled
29
target/microblaze: Check CF_NO_GOTO_TB for DISAS_JUMP
30
target/microblaze: Drop checks for singlestep_enabled
31
target/mips: Fix single stepping
32
target/mips: Drop exit checks for singlestep_enabled
33
target/openrisc: Drop checks for singlestep_enabled
34
target/ppc: Drop exit checks for singlestep_enabled
35
target/riscv: Remove dead code after exception
36
target/riscv: Remove exit_tb and lookup_and_goto_ptr
37
target/rx: Drop checks for singlestep_enabled
38
target/s390x: Drop check for singlestep_enabled
39
target/sh4: Drop check for singlestep_enabled
40
target/tricore: Drop check for singlestep_enabled
41
target/xtensa: Drop check for singlestep_enabled
42
Revert "cpu: Move cpu_common_props to hw/core/cpu.c"
30
43
31
Luis Pires (1):
44
include/hw/core/cpu.h | 1 +
32
docs/devel: Explain in more detail the TB chaining mechanisms
45
target/i386/helper.h | 1 -
46
target/rx/helper.h | 1 -
47
target/sh4/helper.h | 1 -
48
target/tricore/helper.h | 1 -
49
accel/tcg/cpu-exec.c | 11 ++++
50
cpu.c | 21 ++++++++
51
hw/core/cpu-common.c | 17 +-----
52
target/alpha/translate.c | 13 ++---
53
target/arm/translate-a64.c | 10 +---
54
target/arm/translate.c | 36 +++----------
55
target/avr/translate.c | 19 ++-----
56
target/cris/translate.c | 16 ------
57
target/hexagon/translate.c | 12 +----
58
target/hppa/translate.c | 17 ++----
59
target/i386/tcg/misc_helper.c | 8 ---
60
target/i386/tcg/translate.c | 9 ++--
61
target/m68k/translate.c | 44 ++++-----------
62
target/microblaze/translate.c | 18 ++-----
63
target/mips/tcg/translate.c | 75 ++++++++++++--------------
64
target/openrisc/translate.c | 18 ++-----
65
target/ppc/translate.c | 38 +++----------
66
target/riscv/translate.c | 27 +---------
67
target/rx/op_helper.c | 8 ---
68
target/rx/translate.c | 12 +----
69
target/s390x/tcg/translate.c | 8 +--
70
target/sh4/op_helper.c | 5 --
71
target/sh4/translate.c | 14 ++---
72
target/tricore/op_helper.c | 7 ---
73
target/tricore/translate.c | 14 +----
74
target/xtensa/translate.c | 25 +++------
75
target/riscv/insn_trans/trans_privileged.c.inc | 10 ++--
76
target/riscv/insn_trans/trans_rvi.c.inc | 8 ++-
77
target/riscv/insn_trans/trans_rvv.c.inc | 2 +-
78
34 files changed, 141 insertions(+), 386 deletions(-)
33
79
34
Richard Henderson (32):
35
meson: Split out tcg/meson.build
36
meson: Split out fpu/meson.build
37
tcg: Re-order tcg_region_init vs tcg_prologue_init
38
tcg: Remove error return from tcg_region_initial_alloc__locked
39
tcg: Split out tcg_region_initial_alloc
40
tcg: Split out tcg_region_prologue_set
41
tcg: Split out region.c
42
accel/tcg: Inline cpu_gen_init
43
accel/tcg: Move alloc_code_gen_buffer to tcg/region.c
44
accel/tcg: Rename tcg_init to tcg_init_machine
45
tcg: Create tcg_init
46
accel/tcg: Merge tcg_exec_init into tcg_init_machine
47
accel/tcg: Use MiB in tcg_init_machine
48
accel/tcg: Pass down max_cpus to tcg_init
49
tcg: Introduce tcg_max_ctxs
50
tcg: Move MAX_CODE_GEN_BUFFER_SIZE to tcg-target.h
51
tcg: Replace region.end with region.total_size
52
tcg: Rename region.start to region.after_prologue
53
tcg: Tidy tcg_n_regions
54
tcg: Tidy split_cross_256mb
55
tcg: Move in_code_gen_buffer and tests to region.c
56
tcg: Allocate code_gen_buffer into struct tcg_region_state
57
tcg: Return the map protection from alloc_code_gen_buffer
58
tcg: Sink qemu_madvise call to common code
59
util/osdep: Add qemu_mprotect_rw
60
tcg: Round the tb_size default from qemu_get_host_physmem
61
tcg: Merge buffer protection and guard page protection
62
tcg: When allocating for !splitwx, begin with PROT_NONE
63
tcg: Move tcg_init_ctx and tcg_ctx from accel/tcg/
64
tcg: Introduce tcg_remove_ops_after
65
tcg: Fix documentation for tcg_constant_* vs tcg_temp_free_*
66
softfloat: Fix tp init in float32_exp2
67
68
docs/devel/tcg.rst | 101 ++++-
69
meson.build | 12 +-
70
accel/tcg/internal.h | 2 +
71
include/qemu/osdep.h | 1 +
72
include/sysemu/tcg.h | 2 -
73
include/tcg/tcg.h | 28 +-
74
tcg/aarch64/tcg-target.h | 1 +
75
tcg/arm/tcg-target.h | 1 +
76
tcg/i386/tcg-target.h | 2 +
77
tcg/mips/tcg-target.h | 6 +
78
tcg/ppc/tcg-target.h | 2 +
79
tcg/riscv/tcg-target.h | 1 +
80
tcg/s390/tcg-target.h | 3 +
81
tcg/sparc/tcg-target.h | 1 +
82
tcg/tcg-internal.h | 40 ++
83
tcg/tci/tcg-target.h | 1 +
84
accel/tcg/tcg-all.c | 32 +-
85
accel/tcg/translate-all.c | 439 +-------------------
86
bsd-user/main.c | 3 +-
87
fpu/softfloat.c | 2 +-
88
linux-user/main.c | 1 -
89
tcg/region.c | 999 ++++++++++++++++++++++++++++++++++++++++++++++
90
tcg/tcg.c | 649 +++---------------------------
91
util/osdep.c | 9 +
92
tcg/arm/tcg-target.c.inc | 3 +-
93
fpu/meson.build | 1 +
94
tcg/meson.build | 14 +
95
27 files changed, 1266 insertions(+), 1090 deletions(-)
96
create mode 100644 tcg/tcg-internal.h
97
create mode 100644 tcg/region.c
98
create mode 100644 fpu/meson.build
99
create mode 100644 tcg/meson.build
100
diff view generated by jsdifflib
Deleted patch
1
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
2
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
---
6
meson.build | 8 +-------
7
tcg/meson.build | 13 +++++++++++++
8
2 files changed, 14 insertions(+), 7 deletions(-)
9
create mode 100644 tcg/meson.build
10
1
11
diff --git a/meson.build b/meson.build
12
index XXXXXXX..XXXXXXX 100644
13
--- a/meson.build
14
+++ b/meson.build
15
@@ -XXX,XX +XXX,XX @@ common_ss.add(capstone)
16
specific_ss.add(files('cpu.c', 'disas.c', 'gdbstub.c'), capstone)
17
specific_ss.add(when: 'CONFIG_TCG', if_true: files(
18
'fpu/softfloat.c',
19
- 'tcg/optimize.c',
20
- 'tcg/tcg-common.c',
21
- 'tcg/tcg-op-gvec.c',
22
- 'tcg/tcg-op-vec.c',
23
- 'tcg/tcg-op.c',
24
- 'tcg/tcg.c',
25
))
26
-specific_ss.add(when: 'CONFIG_TCG_INTERPRETER', if_true: files('tcg/tci.c'))
27
28
# Work around a gcc bug/misfeature wherein constant propagation looks
29
# through an alias:
30
@@ -XXX,XX +XXX,XX @@ subdir('net')
31
subdir('replay')
32
subdir('semihosting')
33
subdir('hw')
34
+subdir('tcg')
35
subdir('accel')
36
subdir('plugins')
37
subdir('bsd-user')
38
diff --git a/tcg/meson.build b/tcg/meson.build
39
new file mode 100644
40
index XXXXXXX..XXXXXXX
41
--- /dev/null
42
+++ b/tcg/meson.build
43
@@ -XXX,XX +XXX,XX @@
44
+tcg_ss = ss.source_set()
45
+
46
+tcg_ss.add(files(
47
+ 'optimize.c',
48
+ 'tcg.c',
49
+ 'tcg-common.c',
50
+ 'tcg-op.c',
51
+ 'tcg-op-gvec.c',
52
+ 'tcg-op-vec.c',
53
+))
54
+tcg_ss.add(when: 'CONFIG_TCG_INTERPRETER', if_true: files('tci.c'))
55
+
56
+specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
57
--
58
2.25.1
59
60
diff view generated by jsdifflib
1
Typo in the conversion to FloatParts64.
1
Currently the change in cpu_tb_exec is masked by the debug exception
2
being raised by the translators. But this allows us to remove that code.
2
3
3
Fixes: 572c4d862ff2
4
Fixes: Coverity CID 1457457
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Message-Id: <20210607223812.110596-1-richard.henderson@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
---
5
---
10
fpu/softfloat.c | 2 +-
6
accel/tcg/cpu-exec.c | 11 +++++++++++
11
1 file changed, 1 insertion(+), 1 deletion(-)
7
1 file changed, 11 insertions(+)
12
8
13
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
9
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
14
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
15
--- a/fpu/softfloat.c
11
--- a/accel/tcg/cpu-exec.c
16
+++ b/fpu/softfloat.c
12
+++ b/accel/tcg/cpu-exec.c
17
@@ -XXX,XX +XXX,XX @@ float32 float32_exp2(float32 a, float_status *status)
13
@@ -XXX,XX +XXX,XX @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
18
14
cc->set_pc(cpu, last_tb->pc);
19
float_raise(float_flag_inexact, status);
15
}
20
16
}
21
- float64_unpack_canonical(&xnp, float64_ln2, status);
17
+
22
+ float64_unpack_canonical(&tp, float64_ln2, status);
18
+ /*
23
xp = *parts_mul(&xp, &tp, status);
19
+ * If gdb single-step, and we haven't raised another exception,
24
xnp = xp;
20
+ * raise a debug exception. Single-step with another exception
21
+ * is handled in cpu_handle_exception.
22
+ */
23
+ if (unlikely(cpu->singlestep_enabled) && cpu->exception_index == -1) {
24
+ cpu->exception_index = EXCP_DEBUG;
25
+ cpu_loop_exit(cpu);
26
+ }
27
+
28
return last_tb;
29
}
25
30
26
--
31
--
27
2.25.1
32
2.25.1
28
33
29
34
diff view generated by jsdifflib
1
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
1
GDB single-stepping is now handled generically.
2
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
2
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
---
5
---
6
meson.build | 4 +---
6
target/alpha/translate.c | 13 +++----------
7
fpu/meson.build | 1 +
7
1 file changed, 3 insertions(+), 10 deletions(-)
8
2 files changed, 2 insertions(+), 3 deletions(-)
9
create mode 100644 fpu/meson.build
10
8
11
diff --git a/meson.build b/meson.build
9
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
12
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
13
--- a/meson.build
11
--- a/target/alpha/translate.c
14
+++ b/meson.build
12
+++ b/target/alpha/translate.c
15
@@ -XXX,XX +XXX,XX @@ subdir('softmmu')
13
@@ -XXX,XX +XXX,XX @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
16
14
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
17
common_ss.add(capstone)
15
/* FALLTHRU */
18
specific_ss.add(files('cpu.c', 'disas.c', 'gdbstub.c'), capstone)
16
case DISAS_PC_UPDATED:
19
-specific_ss.add(when: 'CONFIG_TCG', if_true: files(
17
- if (!ctx->base.singlestep_enabled) {
20
- 'fpu/softfloat.c',
18
- tcg_gen_lookup_and_goto_ptr();
21
-))
19
- break;
22
20
- }
23
# Work around a gcc bug/misfeature wherein constant propagation looks
21
- /* FALLTHRU */
24
# through an alias:
22
+ tcg_gen_lookup_and_goto_ptr();
25
@@ -XXX,XX +XXX,XX @@ subdir('replay')
23
+ break;
26
subdir('semihosting')
24
case DISAS_PC_UPDATED_NOCHAIN:
27
subdir('hw')
25
- if (ctx->base.singlestep_enabled) {
28
subdir('tcg')
26
- gen_excp_1(EXCP_DEBUG, 0);
29
+subdir('fpu')
27
- } else {
30
subdir('accel')
28
- tcg_gen_exit_tb(NULL, 0);
31
subdir('plugins')
29
- }
32
subdir('bsd-user')
30
+ tcg_gen_exit_tb(NULL, 0);
33
diff --git a/fpu/meson.build b/fpu/meson.build
31
break;
34
new file mode 100644
32
default:
35
index XXXXXXX..XXXXXXX
33
g_assert_not_reached();
36
--- /dev/null
37
+++ b/fpu/meson.build
38
@@ -0,0 +1 @@
39
+specific_ss.add(when: 'CONFIG_TCG', if_true: files('softfloat.c'))
40
--
34
--
41
2.25.1
35
2.25.1
42
36
43
37
diff view generated by jsdifflib
Deleted patch
1
Instead of delaying tcg_region_init until after tcg_prologue_init
2
is complete, do tcg_region_init first and let tcg_prologue_init
3
shrink the first region by the size of the generated prologue.
4
1
5
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
accel/tcg/tcg-all.c | 11 ---------
10
accel/tcg/translate-all.c | 3 +++
11
bsd-user/main.c | 1 -
12
linux-user/main.c | 1 -
13
tcg/tcg.c | 52 ++++++++++++++-------------------------
14
5 files changed, 22 insertions(+), 46 deletions(-)
15
16
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/accel/tcg/tcg-all.c
19
+++ b/accel/tcg/tcg-all.c
20
@@ -XXX,XX +XXX,XX @@ static int tcg_init(MachineState *ms)
21
22
tcg_exec_init(s->tb_size * 1024 * 1024, s->splitwx_enabled);
23
mttcg_enabled = s->mttcg_enabled;
24
-
25
- /*
26
- * Initialize TCG regions only for softmmu.
27
- *
28
- * This needs to be done later for user mode, because the prologue
29
- * generation needs to be delayed so that GUEST_BASE is already set.
30
- */
31
-#ifndef CONFIG_USER_ONLY
32
- tcg_region_init();
33
-#endif /* !CONFIG_USER_ONLY */
34
-
35
return 0;
36
}
37
38
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/accel/tcg/translate-all.c
41
+++ b/accel/tcg/translate-all.c
42
@@ -XXX,XX +XXX,XX @@ void tcg_exec_init(unsigned long tb_size, int splitwx)
43
splitwx, &error_fatal);
44
assert(ok);
45
46
+ /* TODO: allocating regions is hand-in-glove with code_gen_buffer. */
47
+ tcg_region_init();
48
+
49
#if defined(CONFIG_SOFTMMU)
50
/* There's no guest base to take into account, so go ahead and
51
initialize the prologue now. */
52
diff --git a/bsd-user/main.c b/bsd-user/main.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/bsd-user/main.c
55
+++ b/bsd-user/main.c
56
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
57
* the real value of GUEST_BASE into account.
58
*/
59
tcg_prologue_init(tcg_ctx);
60
- tcg_region_init();
61
62
/* build Task State */
63
memset(ts, 0, sizeof(TaskState));
64
diff --git a/linux-user/main.c b/linux-user/main.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/linux-user/main.c
67
+++ b/linux-user/main.c
68
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
69
generating the prologue until now so that the prologue can take
70
the real value of GUEST_BASE into account. */
71
tcg_prologue_init(tcg_ctx);
72
- tcg_region_init();
73
74
target_cpu_copy_regs(env, regs);
75
76
diff --git a/tcg/tcg.c b/tcg/tcg.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/tcg/tcg.c
79
+++ b/tcg/tcg.c
80
@@ -XXX,XX +XXX,XX @@ TranslationBlock *tcg_tb_alloc(TCGContext *s)
81
82
void tcg_prologue_init(TCGContext *s)
83
{
84
- size_t prologue_size, total_size;
85
- void *buf0, *buf1;
86
+ size_t prologue_size;
87
88
/* Put the prologue at the beginning of code_gen_buffer. */
89
- buf0 = s->code_gen_buffer;
90
- total_size = s->code_gen_buffer_size;
91
- s->code_ptr = buf0;
92
- s->code_buf = buf0;
93
+ tcg_region_assign(s, 0);
94
+ s->code_ptr = s->code_gen_ptr;
95
+ s->code_buf = s->code_gen_ptr;
96
s->data_gen_ptr = NULL;
97
98
- /*
99
- * The region trees are not yet configured, but tcg_splitwx_to_rx
100
- * needs the bounds for an assert.
101
- */
102
- region.start = buf0;
103
- region.end = buf0 + total_size;
104
-
105
#ifndef CONFIG_TCG_INTERPRETER
106
- tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(buf0);
107
+ tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
108
#endif
109
110
- /* Compute a high-water mark, at which we voluntarily flush the buffer
111
- and start over. The size here is arbitrary, significantly larger
112
- than we expect the code generation for any one opcode to require. */
113
- s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
114
-
115
#ifdef TCG_TARGET_NEED_POOL_LABELS
116
s->pool_labels = NULL;
117
#endif
118
@@ -XXX,XX +XXX,XX @@ void tcg_prologue_init(TCGContext *s)
119
}
120
#endif
121
122
- buf1 = s->code_ptr;
123
+ prologue_size = tcg_current_code_size(s);
124
+
125
#ifndef CONFIG_TCG_INTERPRETER
126
- flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(buf0), (uintptr_t)buf0,
127
- tcg_ptr_byte_diff(buf1, buf0));
128
+ flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
129
+ (uintptr_t)s->code_buf, prologue_size);
130
#endif
131
132
- /* Deduct the prologue from the buffer. */
133
- prologue_size = tcg_current_code_size(s);
134
- s->code_gen_ptr = buf1;
135
- s->code_gen_buffer = buf1;
136
- s->code_buf = buf1;
137
- total_size -= prologue_size;
138
- s->code_gen_buffer_size = total_size;
139
+ /* Deduct the prologue from the first region. */
140
+ region.start = s->code_ptr;
141
142
- tcg_register_jit(tcg_splitwx_to_rx(s->code_gen_buffer), total_size);
143
+ /* Recompute boundaries of the first region. */
144
+ tcg_region_assign(s, 0);
145
+
146
+ tcg_register_jit(tcg_splitwx_to_rx(region.start),
147
+ region.end - region.start);
148
149
#ifdef DEBUG_DISAS
150
if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
151
FILE *logfile = qemu_log_lock();
152
qemu_log("PROLOGUE: [size=%zu]\n", prologue_size);
153
if (s->data_gen_ptr) {
154
- size_t code_size = s->data_gen_ptr - buf0;
155
+ size_t code_size = s->data_gen_ptr - s->code_gen_ptr;
156
size_t data_size = prologue_size - code_size;
157
size_t i;
158
159
- log_disas(buf0, code_size);
160
+ log_disas(s->code_gen_ptr, code_size);
161
162
for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
163
if (sizeof(tcg_target_ulong) == 8) {
164
@@ -XXX,XX +XXX,XX @@ void tcg_prologue_init(TCGContext *s)
165
}
166
}
167
} else {
168
- log_disas(buf0, prologue_size);
169
+ log_disas(s->code_gen_ptr, prologue_size);
170
}
171
qemu_log("\n");
172
qemu_log_flush();
173
--
174
2.25.1
175
176
diff view generated by jsdifflib
1
Finish the divorce of tcg/ from hw/, and do not take
1
GDB single-stepping is now handled generically.
2
the max cpu value from MachineState; just remember what
3
we were passed in tcg_init.
4
2
5
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
3
Tested-by: Michael Rolnik <mrolnik@gmail.com>
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
4
Reviewed-by: Michael Rolnik <mrolnik@gmail.com>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
---
7
---
10
tcg/tcg-internal.h | 3 ++-
8
target/avr/translate.c | 19 ++++---------------
11
tcg/region.c | 6 +++---
9
1 file changed, 4 insertions(+), 15 deletions(-)
12
tcg/tcg.c | 23 ++++++++++-------------
13
3 files changed, 15 insertions(+), 17 deletions(-)
14
10
15
diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h
11
diff --git a/target/avr/translate.c b/target/avr/translate.c
16
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
17
--- a/tcg/tcg-internal.h
13
--- a/target/avr/translate.c
18
+++ b/tcg/tcg-internal.h
14
+++ b/target/avr/translate.c
19
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
20
#define TCG_HIGHWATER 1024
16
tcg_gen_exit_tb(tb, n);
21
17
} else {
22
extern TCGContext **tcg_ctxs;
18
tcg_gen_movi_i32(cpu_pc, dest);
23
-extern unsigned int n_tcg_ctxs;
19
- if (ctx->base.singlestep_enabled) {
24
+extern unsigned int tcg_cur_ctxs;
20
- gen_helper_debug(cpu_env);
25
+extern unsigned int tcg_max_ctxs;
21
- } else {
26
22
- tcg_gen_lookup_and_goto_ptr();
27
void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus);
23
- }
28
bool tcg_region_alloc(TCGContext *s);
24
+ tcg_gen_lookup_and_goto_ptr();
29
diff --git a/tcg/region.c b/tcg/region.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/tcg/region.c
32
+++ b/tcg/region.c
33
@@ -XXX,XX +XXX,XX @@ void tcg_region_initial_alloc(TCGContext *s)
34
/* Call from a safe-work context */
35
void tcg_region_reset_all(void)
36
{
37
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
38
+ unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
39
unsigned int i;
40
41
qemu_mutex_lock(&region.lock);
42
@@ -XXX,XX +XXX,XX @@ void tcg_region_prologue_set(TCGContext *s)
43
*/
44
size_t tcg_code_size(void)
45
{
46
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
47
+ unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
48
unsigned int i;
49
size_t total;
50
51
@@ -XXX,XX +XXX,XX @@ size_t tcg_code_capacity(void)
52
53
size_t tcg_tb_phys_invalidate_count(void)
54
{
55
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
56
+ unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
57
unsigned int i;
58
size_t total = 0;
59
60
diff --git a/tcg/tcg.c b/tcg/tcg.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/tcg/tcg.c
63
+++ b/tcg/tcg.c
64
@@ -XXX,XX +XXX,XX @@
65
#define NO_CPU_IO_DEFS
66
67
#include "exec/exec-all.h"
68
-
69
-#if !defined(CONFIG_USER_ONLY)
70
-#include "hw/boards.h"
71
-#endif
72
-
73
#include "tcg/tcg-op.h"
74
75
#if UINTPTR_MAX == UINT32_MAX
76
@@ -XXX,XX +XXX,XX @@ static int tcg_out_ldst_finalize(TCGContext *s);
77
#endif
78
79
TCGContext **tcg_ctxs;
80
-unsigned int n_tcg_ctxs;
81
+unsigned int tcg_cur_ctxs;
82
+unsigned int tcg_max_ctxs;
83
TCGv_env cpu_env = 0;
84
const void *tcg_code_gen_epilogue;
85
uintptr_t tcg_splitwx_diff;
86
@@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void)
87
#else
88
void tcg_register_thread(void)
89
{
90
- MachineState *ms = MACHINE(qdev_get_machine());
91
TCGContext *s = g_malloc(sizeof(*s));
92
unsigned int i, n;
93
94
@@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void)
95
}
25
}
96
26
ctx->base.is_jmp = DISAS_NORETURN;
97
/* Claim an entry in tcg_ctxs */
27
}
98
- n = qatomic_fetch_inc(&n_tcg_ctxs);
28
@@ -XXX,XX +XXX,XX @@ static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
99
- g_assert(n < ms->smp.max_cpus);
29
tcg_gen_movi_tl(cpu_pc, ctx->npc);
100
+ n = qatomic_fetch_inc(&tcg_cur_ctxs);
30
/* fall through */
101
+ g_assert(n < tcg_max_ctxs);
31
case DISAS_LOOKUP:
102
qatomic_set(&tcg_ctxs[n], s);
32
- if (!ctx->base.singlestep_enabled) {
103
33
- tcg_gen_lookup_and_goto_ptr();
104
if (n > 0) {
34
- break;
105
@@ -XXX,XX +XXX,XX @@ static void tcg_context_init(unsigned max_cpus)
35
- }
106
*/
36
- /* fall through */
107
#ifdef CONFIG_USER_ONLY
37
+ tcg_gen_lookup_and_goto_ptr();
108
tcg_ctxs = &tcg_ctx;
38
+ break;
109
- n_tcg_ctxs = 1;
39
case DISAS_EXIT:
110
+ tcg_cur_ctxs = 1;
40
- if (ctx->base.singlestep_enabled) {
111
+ tcg_max_ctxs = 1;
41
- gen_helper_debug(cpu_env);
112
#else
42
- } else {
113
- tcg_ctxs = g_new(TCGContext *, max_cpus);
43
- tcg_gen_exit_tb(NULL, 0);
114
+ tcg_max_ctxs = max_cpus;
44
- }
115
+ tcg_ctxs = g_new0(TCGContext *, max_cpus);
45
+ tcg_gen_exit_tb(NULL, 0);
116
#endif
46
break;
117
47
default:
118
tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0));
48
g_assert_not_reached();
119
@@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
120
static inline
121
void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
122
{
123
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
124
+ unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
125
unsigned int i;
126
127
for (i = 0; i < n_ctxs; i++) {
128
@@ -XXX,XX +XXX,XX @@ void tcg_dump_op_count(void)
129
130
int64_t tcg_cpu_exec_time(void)
131
{
132
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
133
+ unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
134
unsigned int i;
135
int64_t ret = 0;
136
137
--
49
--
138
2.25.1
50
2.25.1
139
51
140
52
diff view generated by jsdifflib
1
There's a change in mprotect() behaviour [1] in the latest macOS
1
GDB single-stepping is now handled generically.
2
on M1 and it's not yet clear if it's going to be fixed by Apple.
3
2
4
In this case, instead of changing permissions of N guard pages,
5
we change permissions of N rwx regions. The same number of
6
syscalls are required either way.
7
8
[1] https://gist.github.com/hikalium/75ae822466ee4da13cbbe486498a191f
9
10
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
---
4
---
13
tcg/region.c | 19 +++++++++----------
5
target/cris/translate.c | 16 ----------------
14
1 file changed, 9 insertions(+), 10 deletions(-)
6
1 file changed, 16 deletions(-)
15
7
16
diff --git a/tcg/region.c b/tcg/region.c
8
diff --git a/target/cris/translate.c b/target/cris/translate.c
17
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
18
--- a/tcg/region.c
10
--- a/target/cris/translate.c
19
+++ b/tcg/region.c
11
+++ b/target/cris/translate.c
20
@@ -XXX,XX +XXX,XX @@ static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
12
@@ -XXX,XX +XXX,XX @@ static void cris_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
21
error_free_or_abort(errp);
22
}
23
24
- prot = PROT_READ | PROT_WRITE | PROT_EXEC;
25
+ /*
26
+ * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
27
+ * rejects a permission change from RWX -> NONE when reserving the
28
+ * guard pages later. We can go the other way with the same number
29
+ * of syscalls, so always begin with PROT_NONE.
30
+ */
31
+ prot = PROT_NONE;
32
flags = MAP_PRIVATE | MAP_ANONYMOUS;
33
-#ifdef CONFIG_TCG_INTERPRETER
34
- /* The tcg interpreter does not need execute permission. */
35
- prot = PROT_READ | PROT_WRITE;
36
-#elif defined(CONFIG_DARWIN)
37
+#ifdef CONFIG_DARWIN
38
/* Applicable to both iOS and macOS (Apple Silicon). */
39
if (!splitwx) {
40
flags |= MAP_JIT;
41
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
42
}
43
}
44
if (have_prot != 0) {
45
- /*
46
- * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
47
- * rejects a permission change from RWX -> NONE. Guard pages are
48
- * nice for bug detection but are not essential; ignore any failure.
49
- */
50
+ /* Guard pages are nice for bug detection but are not essential. */
51
(void)qemu_mprotect_none(end, page_size);
52
}
13
}
53
}
14
}
15
16
- if (unlikely(dc->base.singlestep_enabled)) {
17
- switch (is_jmp) {
18
- case DISAS_TOO_MANY:
19
- case DISAS_UPDATE_NEXT:
20
- tcg_gen_movi_tl(env_pc, npc);
21
- /* fall through */
22
- case DISAS_JUMP:
23
- case DISAS_UPDATE:
24
- t_gen_raise_exception(EXCP_DEBUG);
25
- return;
26
- default:
27
- break;
28
- }
29
- g_assert_not_reached();
30
- }
31
-
32
switch (is_jmp) {
33
case DISAS_TOO_MANY:
34
gen_goto_tb(dc, 0, npc);
54
--
35
--
55
2.25.1
36
2.25.1
56
37
57
38
diff view generated by jsdifflib
1
All callers immediately assert on error, so move the assert
1
GDB single-stepping is now handled generically.
2
into the function itself.
3
2
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
5
---
9
tcg/tcg.c | 19 ++++++-------------
6
target/hexagon/translate.c | 12 ++----------
10
1 file changed, 6 insertions(+), 13 deletions(-)
7
1 file changed, 2 insertions(+), 10 deletions(-)
11
8
12
diff --git a/tcg/tcg.c b/tcg/tcg.c
9
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
13
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
14
--- a/tcg/tcg.c
11
--- a/target/hexagon/translate.c
15
+++ b/tcg/tcg.c
12
+++ b/target/hexagon/translate.c
16
@@ -XXX,XX +XXX,XX @@ static bool tcg_region_alloc(TCGContext *s)
13
@@ -XXX,XX +XXX,XX @@ static void gen_end_tb(DisasContext *ctx)
17
* Perform a context's first region allocation.
18
* This function does _not_ increment region.agg_size_full.
19
*/
20
-static inline bool tcg_region_initial_alloc__locked(TCGContext *s)
21
+static void tcg_region_initial_alloc__locked(TCGContext *s)
22
{
14
{
23
- return tcg_region_alloc__locked(s);
15
gen_exec_counters(ctx);
24
+ bool err = tcg_region_alloc__locked(s);
16
tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC);
25
+ g_assert(!err);
17
- if (ctx->base.singlestep_enabled) {
18
- gen_exception_raw(EXCP_DEBUG);
19
- } else {
20
- tcg_gen_exit_tb(NULL, 0);
21
- }
22
+ tcg_gen_exit_tb(NULL, 0);
23
ctx->base.is_jmp = DISAS_NORETURN;
26
}
24
}
27
25
28
/* Call from a safe-work context */
26
@@ -XXX,XX +XXX,XX @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
29
@@ -XXX,XX +XXX,XX @@ void tcg_region_reset_all(void)
27
case DISAS_TOO_MANY:
30
28
gen_exec_counters(ctx);
31
for (i = 0; i < n_ctxs; i++) {
29
tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next);
32
TCGContext *s = qatomic_read(&tcg_ctxs[i]);
30
- if (ctx->base.singlestep_enabled) {
33
- bool err = tcg_region_initial_alloc__locked(s);
31
- gen_exception_raw(EXCP_DEBUG);
34
-
32
- } else {
35
- g_assert(!err);
33
- tcg_gen_exit_tb(NULL, 0);
36
+ tcg_region_initial_alloc__locked(s);
34
- }
37
}
35
+ tcg_gen_exit_tb(NULL, 0);
38
qemu_mutex_unlock(&region.lock);
36
break;
39
37
case DISAS_NORETURN:
40
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(void)
38
break;
41
42
/* In user-mode we support only one ctx, so do the initial allocation now */
43
#ifdef CONFIG_USER_ONLY
44
- {
45
- bool err = tcg_region_initial_alloc__locked(tcg_ctx);
46
-
47
- g_assert(!err);
48
- }
49
+ tcg_region_initial_alloc__locked(tcg_ctx);
50
#endif
51
}
52
53
@@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void)
54
MachineState *ms = MACHINE(qdev_get_machine());
55
TCGContext *s = g_malloc(sizeof(*s));
56
unsigned int i, n;
57
- bool err;
58
59
*s = tcg_init_ctx;
60
61
@@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void)
62
63
tcg_ctx = s;
64
qemu_mutex_lock(&region.lock);
65
- err = tcg_region_initial_alloc__locked(tcg_ctx);
66
- g_assert(!err);
67
+ tcg_region_initial_alloc__locked(s);
68
qemu_mutex_unlock(&region.lock);
69
}
70
#endif /* !CONFIG_USER_ONLY */
71
--
39
--
72
2.25.1
40
2.25.1
73
41
74
42
diff view generated by jsdifflib
Deleted patch
1
This has only one user, and currently needs an ifdef,
2
but will make more sense after some code motion.
3
1
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
8
tcg/tcg.c | 13 ++++++++++---
9
1 file changed, 10 insertions(+), 3 deletions(-)
10
11
diff --git a/tcg/tcg.c b/tcg/tcg.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/tcg/tcg.c
14
+++ b/tcg/tcg.c
15
@@ -XXX,XX +XXX,XX @@ static void tcg_region_initial_alloc__locked(TCGContext *s)
16
g_assert(!err);
17
}
18
19
+#ifndef CONFIG_USER_ONLY
20
+static void tcg_region_initial_alloc(TCGContext *s)
21
+{
22
+ qemu_mutex_lock(&region.lock);
23
+ tcg_region_initial_alloc__locked(s);
24
+ qemu_mutex_unlock(&region.lock);
25
+}
26
+#endif
27
+
28
/* Call from a safe-work context */
29
void tcg_region_reset_all(void)
30
{
31
@@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void)
32
}
33
34
tcg_ctx = s;
35
- qemu_mutex_lock(&region.lock);
36
- tcg_region_initial_alloc__locked(s);
37
- qemu_mutex_unlock(&region.lock);
38
+ tcg_region_initial_alloc(s);
39
}
40
#endif /* !CONFIG_USER_ONLY */
41
42
--
43
2.25.1
44
45
diff view generated by jsdifflib
1
Compute the value using straight division and bounds,
1
GDB single-stepping is now handled generically.
2
rather than a loop. Pass in tb_size rather than reading
3
from tcg_init_ctx.code_gen_buffer_size,
4
2
5
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
4
---
9
tcg/region.c | 29 ++++++++++++-----------------
5
target/arm/translate-a64.c | 10 ++--------
10
1 file changed, 12 insertions(+), 17 deletions(-)
6
target/arm/translate.c | 36 ++++++------------------------------
7
2 files changed, 8 insertions(+), 38 deletions(-)
11
8
12
diff --git a/tcg/region.c b/tcg/region.c
9
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
13
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
14
--- a/tcg/region.c
11
--- a/target/arm/translate-a64.c
15
+++ b/tcg/region.c
12
+++ b/target/arm/translate-a64.c
16
@@ -XXX,XX +XXX,XX @@ void tcg_region_reset_all(void)
13
@@ -XXX,XX +XXX,XX @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
17
tcg_region_tree_reset_all();
14
gen_a64_set_pc_im(dest);
15
if (s->ss_active) {
16
gen_step_complete_exception(s);
17
- } else if (s->base.singlestep_enabled) {
18
- gen_exception_internal(EXCP_DEBUG);
19
} else {
20
tcg_gen_lookup_and_goto_ptr();
21
s->base.is_jmp = DISAS_NORETURN;
22
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
23
{
24
DisasContext *dc = container_of(dcbase, DisasContext, base);
25
26
- if (unlikely(dc->base.singlestep_enabled || dc->ss_active)) {
27
+ if (unlikely(dc->ss_active)) {
28
/* Note that this means single stepping WFI doesn't halt the CPU.
29
* For conditional branch insns this is harmless unreachable code as
30
* gen_goto_tb() has already handled emitting the debug exception
31
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
32
/* fall through */
33
case DISAS_EXIT:
34
case DISAS_JUMP:
35
- if (dc->base.singlestep_enabled) {
36
- gen_exception_internal(EXCP_DEBUG);
37
- } else {
38
- gen_step_complete_exception(dc);
39
- }
40
+ gen_step_complete_exception(dc);
41
break;
42
case DISAS_NORETURN:
43
break;
44
diff --git a/target/arm/translate.c b/target/arm/translate.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/target/arm/translate.c
47
+++ b/target/arm/translate.c
48
@@ -XXX,XX +XXX,XX @@ static void gen_exception_internal(int excp)
49
tcg_temp_free_i32(tcg_excp);
18
}
50
}
19
51
20
-static size_t tcg_n_regions(unsigned max_cpus)
52
-static void gen_step_complete_exception(DisasContext *s)
21
+static size_t tcg_n_regions(size_t tb_size, unsigned max_cpus)
53
+static void gen_singlestep_exception(DisasContext *s)
22
{
54
{
23
#ifdef CONFIG_USER_ONLY
55
/* We just completed step of an insn. Move from Active-not-pending
24
return 1;
56
* to Active-pending, and then also take the swstep exception.
25
#else
57
@@ -XXX,XX +XXX,XX @@ static void gen_step_complete_exception(DisasContext *s)
26
+ size_t n_regions;
58
s->base.is_jmp = DISAS_NORETURN;
27
+
59
}
60
61
-static void gen_singlestep_exception(DisasContext *s)
62
-{
63
- /* Generate the right kind of exception for singlestep, which is
64
- * either the architectural singlestep or EXCP_DEBUG for QEMU's
65
- * gdb singlestepping.
66
- */
67
- if (s->ss_active) {
68
- gen_step_complete_exception(s);
69
- } else {
70
- gen_exception_internal(EXCP_DEBUG);
71
- }
72
-}
73
-
74
-static inline bool is_singlestepping(DisasContext *s)
75
-{
76
- /* Return true if we are singlestepping either because of
77
- * architectural singlestep or QEMU gdbstub singlestep. This does
78
- * not include the command line '-singlestep' mode which is rather
79
- * misnamed as it only means "one instruction per TB" and doesn't
80
- * affect the code we generate.
81
- */
82
- return s->base.singlestep_enabled || s->ss_active;
83
-}
84
-
85
void clear_eci_state(DisasContext *s)
86
{
28
/*
87
/*
29
* It is likely that some vCPUs will translate more code than others,
88
@@ -XXX,XX +XXX,XX @@ static inline void gen_bx_excret_final_code(DisasContext *s)
30
* so we first try to set more regions than max_cpus, with those regions
89
/* Is the new PC value in the magic range indicating exception return? */
31
* being of reasonable size. If that's not possible we make do by evenly
90
tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label);
32
* dividing the code_gen_buffer among the vCPUs.
91
/* No: end the TB as we would for a DISAS_JMP */
33
*/
92
- if (is_singlestepping(s)) {
34
- size_t i;
93
+ if (s->ss_active) {
35
-
94
gen_singlestep_exception(s);
36
/* Use a single region if all we have is one vCPU thread */
95
} else {
37
if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
96
tcg_gen_exit_tb(NULL, 0);
38
return 1;
97
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
98
/* Jump, specifying which TB number to use if we gen_goto_tb() */
99
static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
100
{
101
- if (unlikely(is_singlestepping(s))) {
102
+ if (unlikely(s->ss_active)) {
103
/* An indirect jump so that we still trigger the debug exception. */
104
gen_set_pc_im(s, dest);
105
s->base.is_jmp = DISAS_JUMP;
106
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
107
dc->page_start = dc->base.pc_first & TARGET_PAGE_MASK;
108
109
/* If architectural single step active, limit to 1. */
110
- if (is_singlestepping(dc)) {
111
+ if (dc->ss_active) {
112
dc->base.max_insns = 1;
39
}
113
}
40
114
41
- /* Try to have more regions than max_cpus, with each region being >= 2 MB */
115
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
42
- for (i = 8; i > 0; i--) {
116
* insn codepath itself.
43
- size_t regions_per_thread = i;
117
*/
44
- size_t region_size;
118
gen_bx_excret_final_code(dc);
45
-
119
- } else if (unlikely(is_singlestepping(dc))) {
46
- region_size = tcg_init_ctx.code_gen_buffer_size;
120
+ } else if (unlikely(dc->ss_active)) {
47
- region_size /= max_cpus * regions_per_thread;
121
/* Unconditional and "condition passed" instruction codepath. */
48
-
122
switch (dc->base.is_jmp) {
49
- if (region_size >= 2 * 1024u * 1024) {
123
case DISAS_SWI:
50
- return max_cpus * regions_per_thread;
124
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
51
- }
125
/* "Condition failed" instruction codepath for the branch/trap insn */
52
+ /*
126
gen_set_label(dc->condlabel);
53
+ * Try to have more regions than max_cpus, with each region being >= 2 MB.
127
gen_set_condexec(dc);
54
+ * If we can't, then just allocate one region per vCPU thread.
128
- if (unlikely(is_singlestepping(dc))) {
55
+ */
129
+ if (unlikely(dc->ss_active)) {
56
+ n_regions = tb_size / (2 * MiB);
130
gen_set_pc_im(dc, dc->base.pc_next);
57
+ if (n_regions <= max_cpus) {
131
gen_singlestep_exception(dc);
58
+ return max_cpus;
132
} else {
59
}
60
- /* If we can't, then just allocate one region per vCPU thread */
61
- return max_cpus;
62
+ return MIN(n_regions, max_cpus * 8);
63
#endif
64
}
65
66
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
67
buf = tcg_init_ctx.code_gen_buffer;
68
total_size = tcg_init_ctx.code_gen_buffer_size;
69
page_size = qemu_real_host_page_size;
70
- n_regions = tcg_n_regions(max_cpus);
71
+ n_regions = tcg_n_regions(total_size, max_cpus);
72
73
/* The first region will be 'aligned - buf' bytes larger than the others */
74
aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
75
--
133
--
76
2.25.1
134
2.25.1
77
135
78
136
diff view generated by jsdifflib
1
Start removing the include of hw/boards.h from tcg/.
1
GDB single-stepping is now handled generically.
2
Pass down the max_cpus value from tcg_init_machine,
3
where we have the MachineState already.
4
2
5
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
---
5
---
10
include/tcg/tcg.h | 2 +-
6
target/hppa/translate.c | 17 ++++-------------
11
tcg/tcg-internal.h | 2 +-
7
1 file changed, 4 insertions(+), 13 deletions(-)
12
accel/tcg/tcg-all.c | 10 +++++++++-
13
tcg/region.c | 32 +++++++++++---------------------
14
tcg/tcg.c | 10 ++++------
15
5 files changed, 26 insertions(+), 30 deletions(-)
16
8
17
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
9
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
18
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
19
--- a/include/tcg/tcg.h
11
--- a/target/hppa/translate.c
20
+++ b/include/tcg/tcg.h
12
+++ b/target/hppa/translate.c
21
@@ -XXX,XX +XXX,XX @@ static inline void *tcg_malloc(int size)
13
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *ctx, int which,
14
} else {
15
copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
16
copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
17
- if (ctx->base.singlestep_enabled) {
18
- gen_excp_1(EXCP_DEBUG);
19
- } else {
20
- tcg_gen_lookup_and_goto_ptr();
21
- }
22
+ tcg_gen_lookup_and_goto_ptr();
22
}
23
}
23
}
24
}
24
25
25
-void tcg_init(size_t tb_size, int splitwx);
26
@@ -XXX,XX +XXX,XX @@ static bool do_rfi(DisasContext *ctx, bool rfi_r)
26
+void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus);
27
gen_helper_rfi(cpu_env);
27
void tcg_register_thread(void);
28
void tcg_prologue_init(TCGContext *s);
29
void tcg_func_start(TCGContext *s);
30
diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/tcg/tcg-internal.h
33
+++ b/tcg/tcg-internal.h
34
@@ -XXX,XX +XXX,XX @@
35
extern TCGContext **tcg_ctxs;
36
extern unsigned int n_tcg_ctxs;
37
38
-void tcg_region_init(size_t tb_size, int splitwx);
39
+void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus);
40
bool tcg_region_alloc(TCGContext *s);
41
void tcg_region_initial_alloc(TCGContext *s);
42
void tcg_region_prologue_set(TCGContext *s);
43
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/accel/tcg/tcg-all.c
46
+++ b/accel/tcg/tcg-all.c
47
@@ -XXX,XX +XXX,XX @@
48
#include "qemu/accel.h"
49
#include "qapi/qapi-builtin-visit.h"
50
#include "qemu/units.h"
51
+#if !defined(CONFIG_USER_ONLY)
52
+#include "hw/boards.h"
53
+#endif
54
#include "internal.h"
55
56
struct TCGState {
57
@@ -XXX,XX +XXX,XX @@ bool mttcg_enabled;
58
static int tcg_init_machine(MachineState *ms)
59
{
60
TCGState *s = TCG_STATE(current_accel());
61
+#ifdef CONFIG_USER_ONLY
62
+ unsigned max_cpus = 1;
63
+#else
64
+ unsigned max_cpus = ms->smp.max_cpus;
65
+#endif
66
67
tcg_allowed = true;
68
mttcg_enabled = s->mttcg_enabled;
69
70
page_init();
71
tb_htable_init();
72
- tcg_init(s->tb_size * MiB, s->splitwx_enabled);
73
+ tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_cpus);
74
75
#if defined(CONFIG_SOFTMMU)
76
/*
77
diff --git a/tcg/region.c b/tcg/region.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/tcg/region.c
80
+++ b/tcg/region.c
81
@@ -XXX,XX +XXX,XX @@
82
#include "qapi/error.h"
83
#include "exec/exec-all.h"
84
#include "tcg/tcg.h"
85
-#if !defined(CONFIG_USER_ONLY)
86
-#include "hw/boards.h"
87
-#endif
88
#include "tcg-internal.h"
89
90
91
@@ -XXX,XX +XXX,XX @@ void tcg_region_reset_all(void)
92
tcg_region_tree_reset_all();
93
}
94
95
+static size_t tcg_n_regions(unsigned max_cpus)
96
+{
97
#ifdef CONFIG_USER_ONLY
98
-static size_t tcg_n_regions(void)
99
-{
100
return 1;
101
-}
102
#else
103
-/*
104
- * It is likely that some vCPUs will translate more code than others, so we
105
- * first try to set more regions than max_cpus, with those regions being of
106
- * reasonable size. If that's not possible we make do by evenly dividing
107
- * the code_gen_buffer among the vCPUs.
108
- */
109
-static size_t tcg_n_regions(void)
110
-{
111
+ /*
112
+ * It is likely that some vCPUs will translate more code than others,
113
+ * so we first try to set more regions than max_cpus, with those regions
114
+ * being of reasonable size. If that's not possible we make do by evenly
115
+ * dividing the code_gen_buffer among the vCPUs.
116
+ */
117
size_t i;
118
119
/* Use a single region if all we have is one vCPU thread */
120
-#if !defined(CONFIG_USER_ONLY)
121
- MachineState *ms = MACHINE(qdev_get_machine());
122
- unsigned int max_cpus = ms->smp.max_cpus;
123
-#endif
124
if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
125
return 1;
126
}
28
}
127
@@ -XXX,XX +XXX,XX @@ static size_t tcg_n_regions(void)
29
/* Exit the TB to recognize new interrupts. */
128
}
30
- if (ctx->base.singlestep_enabled) {
129
/* If we can't, then just allocate one region per vCPU thread */
31
- gen_excp_1(EXCP_DEBUG);
130
return max_cpus;
32
- } else {
131
-}
33
- tcg_gen_exit_tb(NULL, 0);
132
#endif
34
- }
133
+}
35
+ tcg_gen_exit_tb(NULL, 0);
134
36
ctx->base.is_jmp = DISAS_NORETURN;
135
/*
37
136
* Minimum size of the code gen buffer. This number is randomly chosen,
38
return nullify_end(ctx);
137
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
39
@@ -XXX,XX +XXX,XX @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
138
* in practice. Multi-threaded guests share most if not all of their translated
40
nullify_save(ctx);
139
* code, which makes parallel code generation less appealing than in softmmu.
41
/* FALLTHRU */
140
*/
42
case DISAS_IAQ_N_UPDATED:
141
-void tcg_region_init(size_t tb_size, int splitwx)
43
- if (ctx->base.singlestep_enabled) {
142
+void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
44
- gen_excp_1(EXCP_DEBUG);
143
{
45
- } else if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
144
void *buf, *aligned;
46
+ if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
145
size_t size;
47
tcg_gen_lookup_and_goto_ptr();
146
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx)
48
+ break;
147
buf = tcg_init_ctx.code_gen_buffer;
49
}
148
size = tcg_init_ctx.code_gen_buffer_size;
50
/* FALLTHRU */
149
page_size = qemu_real_host_page_size;
51
case DISAS_EXIT:
150
- n_regions = tcg_n_regions();
151
+ n_regions = tcg_n_regions(max_cpus);
152
153
/* The first region will be 'aligned - buf' bytes larger than the others */
154
aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
155
diff --git a/tcg/tcg.c b/tcg/tcg.c
156
index XXXXXXX..XXXXXXX 100644
157
--- a/tcg/tcg.c
158
+++ b/tcg/tcg.c
159
@@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s);
160
static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
161
TCGReg reg, const char *name);
162
163
-static void tcg_context_init(void)
164
+static void tcg_context_init(unsigned max_cpus)
165
{
166
TCGContext *s = &tcg_init_ctx;
167
int op, total_args, n, i;
168
@@ -XXX,XX +XXX,XX @@ static void tcg_context_init(void)
169
tcg_ctxs = &tcg_ctx;
170
n_tcg_ctxs = 1;
171
#else
172
- MachineState *ms = MACHINE(qdev_get_machine());
173
- unsigned int max_cpus = ms->smp.max_cpus;
174
tcg_ctxs = g_new(TCGContext *, max_cpus);
175
#endif
176
177
@@ -XXX,XX +XXX,XX @@ static void tcg_context_init(void)
178
cpu_env = temp_tcgv_ptr(ts);
179
}
180
181
-void tcg_init(size_t tb_size, int splitwx)
182
+void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus)
183
{
184
- tcg_context_init();
185
- tcg_region_init(tb_size, splitwx);
186
+ tcg_context_init(max_cpus);
187
+ tcg_region_init(tb_size, splitwx, max_cpus);
188
}
189
190
/*
191
--
52
--
192
2.25.1
53
2.25.1
193
54
194
55
diff view generated by jsdifflib
1
From: Luis Pires <luis.pires@eldorado.org.br>
1
We were using singlestep_enabled as a proxy for whether
2
translator_use_goto_tb would always return false.
2
3
3
Signed-off-by: Luis Pires <luis.pires@eldorado.org.br>
4
Message-Id: <20210601125143.191165-1-luis.pires@eldorado.org.br>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
---
5
---
7
docs/devel/tcg.rst | 101 ++++++++++++++++++++++++++++++++++++++++-----
6
target/i386/tcg/translate.c | 5 +++--
8
1 file changed, 90 insertions(+), 11 deletions(-)
7
1 file changed, 3 insertions(+), 2 deletions(-)
9
8
10
diff --git a/docs/devel/tcg.rst b/docs/devel/tcg.rst
9
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
11
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
12
--- a/docs/devel/tcg.rst
11
--- a/target/i386/tcg/translate.c
13
+++ b/docs/devel/tcg.rst
12
+++ b/target/i386/tcg/translate.c
14
@@ -XXX,XX +XXX,XX @@ performances.
13
@@ -XXX,XX +XXX,XX @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
15
QEMU's dynamic translation backend is called TCG, for "Tiny Code
14
DisasContext *dc = container_of(dcbase, DisasContext, base);
16
Generator". For more information, please take a look at ``tcg/README``.
15
CPUX86State *env = cpu->env_ptr;
17
16
uint32_t flags = dc->base.tb->flags;
18
-Some notable features of QEMU's dynamic translator are:
17
+ uint32_t cflags = tb_cflags(dc->base.tb);
19
+The following sections outline some notable features and implementation
18
int cpl = (flags >> HF_CPL_SHIFT) & 3;
20
+details of QEMU's dynamic translator.
19
int iopl = (flags >> IOPL_SHIFT) & 3;
21
20
22
CPU state optimisations
21
@@ -XXX,XX +XXX,XX @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
23
-----------------------
22
dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
24
23
dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
25
-The target CPUs have many internal states which change the way it
24
dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
26
-evaluates instructions. In order to achieve a good speed, the
25
- dc->jmp_opt = !(dc->base.singlestep_enabled ||
27
+The target CPUs have many internal states which change the way they
26
+ dc->jmp_opt = !((cflags & CF_NO_GOTO_TB) ||
28
+evaluate instructions. In order to achieve a good speed, the
27
(flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)));
29
translation phase considers that some state information of the virtual
28
/*
30
CPU cannot change in it. The state is recorded in the Translation
29
* If jmp_opt, we want to handle each string instruction individually.
31
Block (TB). If the state changes (e.g. privilege level), a new TB will
30
* For icount also disable repz optimization so that each iteration
32
@@ -XXX,XX +XXX,XX @@ Direct block chaining
31
* is accounted separately.
33
---------------------
32
*/
34
33
- dc->repz_opt = !dc->jmp_opt && !(tb_cflags(dc->base.tb) & CF_USE_ICOUNT);
35
After each translated basic block is executed, QEMU uses the simulated
34
+ dc->repz_opt = !dc->jmp_opt && !(cflags & CF_USE_ICOUNT);
36
-Program Counter (PC) and other cpu state information (such as the CS
35
37
+Program Counter (PC) and other CPU state information (such as the CS
36
dc->T0 = tcg_temp_new();
38
segment base value) to find the next basic block.
37
dc->T1 = tcg_temp_new();
39
40
-In order to accelerate the most common cases where the new simulated PC
41
-is known, QEMU can patch a basic block so that it jumps directly to the
42
-next one.
43
+In its simplest, less optimized form, this is done by exiting from the
44
+current TB, going through the TB epilogue, and then back to the
45
+main loop. That’s where QEMU looks for the next TB to execute,
46
+translating it from the guest architecture if it isn’t already available
47
+in memory. Then QEMU proceeds to execute this next TB, starting at the
48
+prologue and then moving on to the translated instructions.
49
50
-The most portable code uses an indirect jump. An indirect jump makes
51
-it easier to make the jump target modification atomic. On some host
52
-architectures (such as x86 or PowerPC), the ``JUMP`` opcode is
53
-directly patched so that the block chaining has no overhead.
54
+Exiting from the TB this way will cause the ``cpu_exec_interrupt()``
55
+callback to be re-evaluated before executing additional instructions.
56
+It is mandatory to exit this way after any CPU state changes that may
57
+unmask interrupts.
58
+
59
+In order to accelerate the cases where the TB for the new
60
+simulated PC is already available, QEMU has mechanisms that allow
61
+multiple TBs to be chained directly, without having to go back to the
62
+main loop as described above. These mechanisms are:
63
+
64
+``lookup_and_goto_ptr``
65
+^^^^^^^^^^^^^^^^^^^^^^^
66
+
67
+Calling ``tcg_gen_lookup_and_goto_ptr()`` will emit a call to
68
+``helper_lookup_tb_ptr``. This helper will look for an existing TB that
69
+matches the current CPU state. If the destination TB is available its
70
+code address is returned, otherwise the address of the JIT epilogue is
71
+returned. The call to the helper is always followed by the tcg ``goto_ptr``
72
+opcode, which branches to the returned address. In this way, we either
73
+branch to the next TB or return to the main loop.
74
+
75
+``goto_tb + exit_tb``
76
+^^^^^^^^^^^^^^^^^^^^^
77
+
78
+The translation code usually implements branching by performing the
79
+following steps:
80
+
81
+1. Call ``tcg_gen_goto_tb()`` passing a jump slot index (either 0 or 1)
82
+ as a parameter.
83
+
84
+2. Emit TCG instructions to update the CPU state with any information
85
+ that has been assumed constant and is required by the main loop to
86
+ correctly locate and execute the next TB. For most guests, this is
87
+ just the PC of the branch destination, but others may store additional
88
+ data. The information updated in this step must be inferable from both
89
+ ``cpu_get_tb_cpu_state()`` and ``cpu_restore_state()``.
90
+
91
+3. Call ``tcg_gen_exit_tb()`` passing the address of the current TB and
92
+ the jump slot index again.
93
+
94
+Step 1, ``tcg_gen_goto_tb()``, will emit a ``goto_tb`` TCG
95
+instruction that later on gets translated to a jump to an address
96
+associated with the specified jump slot. Initially, this is the address
97
+of step 2's instructions, which update the CPU state information. Step 3,
98
+``tcg_gen_exit_tb()``, exits from the current TB returning a tagged
99
+pointer composed of the last executed TB’s address and the jump slot
100
+index.
101
+
102
+The first time this whole sequence is executed, step 1 simply jumps
103
+to step 2. Then the CPU state information gets updated and we exit from
104
+the current TB. As a result, the behavior is very similar to the less
105
+optimized form described earlier in this section.
106
+
107
+Next, the main loop looks for the next TB to execute using the
108
+current CPU state information (creating the TB if it wasn’t already
109
+available) and, before starting to execute the new TB’s instructions,
110
+patches the previously executed TB by associating one of its jump
111
+slots (the one specified in the call to ``tcg_gen_exit_tb()``) with the
112
+address of the new TB.
113
+
114
+The next time this previous TB is executed and we get to that same
115
+``goto_tb`` step, it will already be patched (assuming the destination TB
116
+is still in memory) and will jump directly to the first instruction of
117
+the destination TB, without going back to the main loop.
118
+
119
+For the ``goto_tb + exit_tb`` mechanism to be used, the following
120
+conditions need to be satisfied:
121
+
122
+* The change in CPU state must be constant, e.g., a direct branch and
123
+ not an indirect branch.
124
+
125
+* The direct branch cannot cross a page boundary. Memory mappings
126
+ may change, causing the code at the destination address to change.
127
+
128
+Note that, on step 3 (``tcg_gen_exit_tb()``), in addition to the
129
+jump slot index, the address of the TB just executed is also returned.
130
+This address corresponds to the TB that will be patched; it may be
131
+different than the one that was directly executed from the main loop
132
+if the latter had already been chained to other TBs.
133
134
Self-modifying code and translated code invalidation
135
----------------------------------------------------
136
--
38
--
137
2.25.1
39
2.25.1
138
40
139
41
diff view generated by jsdifflib
1
Introduce a function to remove everything emitted
1
GDB single-stepping is now handled generically.
2
since a given point.
3
2
4
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
---
4
---
7
include/tcg/tcg.h | 10 ++++++++++
5
target/i386/helper.h | 1 -
8
tcg/tcg.c | 13 +++++++++++++
6
target/i386/tcg/misc_helper.c | 8 --------
9
2 files changed, 23 insertions(+)
7
target/i386/tcg/translate.c | 4 +---
8
3 files changed, 1 insertion(+), 12 deletions(-)
10
9
11
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
10
diff --git a/target/i386/helper.h b/target/i386/helper.h
12
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
13
--- a/include/tcg/tcg.h
12
--- a/target/i386/helper.h
14
+++ b/include/tcg/tcg.h
13
+++ b/target/i386/helper.h
15
@@ -XXX,XX +XXX,XX @@ void tcg_op_remove(TCGContext *s, TCGOp *op);
14
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_2(syscall, void, env, int)
16
TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, TCGOpcode opc);
15
DEF_HELPER_2(sysret, void, env, int)
17
TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, TCGOpcode opc);
16
#endif
18
17
DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int)
19
+/**
18
-DEF_HELPER_FLAGS_1(debug, TCG_CALL_NO_WG, noreturn, env)
20
+ * tcg_remove_ops_after:
19
DEF_HELPER_1(reset_rf, void, env)
21
+ * @op: target operation
20
DEF_HELPER_FLAGS_3(raise_interrupt, TCG_CALL_NO_WG, noreturn, env, int, int)
22
+ *
21
DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, int)
23
+ * Discard any opcodes emitted since @op. Expected usage is to save
22
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
24
+ * a starting point with tcg_last_op(), speculatively emit opcodes,
25
+ * then decide whether or not to keep those opcodes after the fact.
26
+ */
27
+void tcg_remove_ops_after(TCGOp *op);
28
+
29
void tcg_optimize(TCGContext *s);
30
31
/* Allocate a new temporary and initialize it with a constant. */
32
diff --git a/tcg/tcg.c b/tcg/tcg.c
33
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
34
--- a/tcg/tcg.c
24
--- a/target/i386/tcg/misc_helper.c
35
+++ b/tcg/tcg.c
25
+++ b/target/i386/tcg/misc_helper.c
36
@@ -XXX,XX +XXX,XX @@ void tcg_op_remove(TCGContext *s, TCGOp *op)
26
@@ -XXX,XX +XXX,XX @@ void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend)
37
#endif
27
do_pause(env);
38
}
28
}
39
29
40
+void tcg_remove_ops_after(TCGOp *op)
30
-void QEMU_NORETURN helper_debug(CPUX86State *env)
41
+{
31
-{
42
+ TCGContext *s = tcg_ctx;
32
- CPUState *cs = env_cpu(env);
43
+
33
-
44
+ while (true) {
34
- cs->exception_index = EXCP_DEBUG;
45
+ TCGOp *last = tcg_last_op();
35
- cpu_loop_exit(cs);
46
+ if (last == op) {
36
-}
47
+ return;
37
-
48
+ }
38
uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
49
+ tcg_op_remove(s, last);
50
+ }
51
+}
52
+
53
static TCGOp *tcg_op_alloc(TCGOpcode opc)
54
{
39
{
55
TCGContext *s = tcg_ctx;
40
if ((env->cr[4] & CR4_PKE_MASK) == 0) {
41
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/target/i386/tcg/translate.c
44
+++ b/target/i386/tcg/translate.c
45
@@ -XXX,XX +XXX,XX @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr)
46
if (s->base.tb->flags & HF_RF_MASK) {
47
gen_helper_reset_rf(cpu_env);
48
}
49
- if (s->base.singlestep_enabled) {
50
- gen_helper_debug(cpu_env);
51
- } else if (recheck_tf) {
52
+ if (recheck_tf) {
53
gen_helper_rechecking_single_step(cpu_env);
54
tcg_gen_exit_tb(NULL, 0);
55
} else if (s->flags & HF_TF_MASK) {
56
--
56
--
57
2.25.1
57
2.25.1
58
58
59
59
diff view generated by jsdifflib
1
Buffer management is integral to tcg. Do not leave the allocation
1
GDB single-stepping is now handled generically.
2
to code outside of tcg/. This is code movement, with further
3
cleanups to follow.
4
2
5
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
3
Acked-by: Laurent Vivier <laurent@vivier.eu>
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
5
---
9
include/tcg/tcg.h | 2 +-
6
target/m68k/translate.c | 44 +++++++++--------------------------------
10
accel/tcg/translate-all.c | 414 +-----------------------------------
7
1 file changed, 9 insertions(+), 35 deletions(-)
11
tcg/region.c | 431 +++++++++++++++++++++++++++++++++++++-
12
3 files changed, 428 insertions(+), 419 deletions(-)
13
8
14
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
9
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
15
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
16
--- a/include/tcg/tcg.h
11
--- a/target/m68k/translate.c
17
+++ b/include/tcg/tcg.h
12
+++ b/target/m68k/translate.c
18
@@ -XXX,XX +XXX,XX @@ void *tcg_malloc_internal(TCGContext *s, int size);
13
@@ -XXX,XX +XXX,XX @@ static void do_writebacks(DisasContext *s)
19
void tcg_pool_reset(TCGContext *s);
20
TranslationBlock *tcg_tb_alloc(TCGContext *s);
21
22
-void tcg_region_init(void);
23
+void tcg_region_init(size_t tb_size, int splitwx);
24
void tb_destroy(TranslationBlock *tb);
25
void tcg_region_reset_all(void);
26
27
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/accel/tcg/translate-all.c
30
+++ b/accel/tcg/translate-all.c
31
@@ -XXX,XX +XXX,XX @@
32
*/
33
34
#include "qemu/osdep.h"
35
-#include "qemu/units.h"
36
#include "qemu-common.h"
37
38
#define NO_CPU_IO_DEFS
39
@@ -XXX,XX +XXX,XX @@
40
#include "exec/cputlb.h"
41
#include "exec/translate-all.h"
42
#include "qemu/bitmap.h"
43
-#include "qemu/error-report.h"
44
#include "qemu/qemu-print.h"
45
#include "qemu/timer.h"
46
#include "qemu/main-loop.h"
47
@@ -XXX,XX +XXX,XX @@ static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
48
}
14
}
49
}
15
}
50
16
51
-/* Minimum size of the code gen buffer. This number is randomly chosen,
17
-static bool is_singlestepping(DisasContext *s)
52
- but not so small that we can't have a fair number of TB's live. */
53
-#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB)
54
-
55
-/* Maximum size of the code gen buffer we'd like to use. Unless otherwise
56
- indicated, this is constrained by the range of direct branches on the
57
- host cpu, as used by the TCG implementation of goto_tb. */
58
-#if defined(__x86_64__)
59
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
60
-#elif defined(__sparc__)
61
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
62
-#elif defined(__powerpc64__)
63
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
64
-#elif defined(__powerpc__)
65
-# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
66
-#elif defined(__aarch64__)
67
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
68
-#elif defined(__s390x__)
69
- /* We have a +- 4GB range on the branches; leave some slop. */
70
-# define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
71
-#elif defined(__mips__)
72
- /* We have a 256MB branch region, but leave room to make sure the
73
- main executable is also within that region. */
74
-# define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB)
75
-#else
76
-# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
77
-#endif
78
-
79
-#if TCG_TARGET_REG_BITS == 32
80
-#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32 * MiB)
81
-#ifdef CONFIG_USER_ONLY
82
-/*
83
- * For user mode on smaller 32 bit systems we may run into trouble
84
- * allocating big chunks of data in the right place. On these systems
85
- * we utilise a static code generation buffer directly in the binary.
86
- */
87
-#define USE_STATIC_CODE_GEN_BUFFER
88
-#endif
89
-#else /* TCG_TARGET_REG_BITS == 64 */
90
-#ifdef CONFIG_USER_ONLY
91
-/*
92
- * As user-mode emulation typically means running multiple instances
93
- * of the translator don't go too nuts with our default code gen
94
- * buffer lest we make things too hard for the OS.
95
- */
96
-#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (128 * MiB)
97
-#else
98
-/*
99
- * We expect most system emulation to run one or two guests per host.
100
- * Users running large scale system emulation may want to tweak their
101
- * runtime setup via the tb-size control on the command line.
102
- */
103
-#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (1 * GiB)
104
-#endif
105
-#endif
106
-
107
-#define DEFAULT_CODE_GEN_BUFFER_SIZE \
108
- (DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \
109
- ? DEFAULT_CODE_GEN_BUFFER_SIZE_1 : MAX_CODE_GEN_BUFFER_SIZE)
110
-
111
-static size_t size_code_gen_buffer(size_t tb_size)
112
-{
18
-{
113
- /* Size the buffer. */
19
- /*
114
- if (tb_size == 0) {
20
- * Return true if we are singlestepping either because of
115
- size_t phys_mem = qemu_get_host_physmem();
21
- * architectural singlestep or QEMU gdbstub singlestep. This does
116
- if (phys_mem == 0) {
22
- * not include the command line '-singlestep' mode which is rather
117
- tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
23
- * misnamed as it only means "one instruction per TB" and doesn't
118
- } else {
24
- * affect the code we generate.
119
- tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, phys_mem / 8);
25
- */
120
- }
26
- return s->base.singlestep_enabled || s->ss_active;
121
- }
122
- if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
123
- tb_size = MIN_CODE_GEN_BUFFER_SIZE;
124
- }
125
- if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) {
126
- tb_size = MAX_CODE_GEN_BUFFER_SIZE;
127
- }
128
- return tb_size;
129
-}
27
-}
130
-
28
-
131
-#ifdef __mips__
29
/* is_jmp field values */
132
-/* In order to use J and JAL within the code_gen_buffer, we require
30
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
133
- that the buffer not cross a 256MB boundary. */
31
#define DISAS_EXIT DISAS_TARGET_1 /* cpu state was modified dynamically */
134
-static inline bool cross_256mb(void *addr, size_t size)
32
@@ -XXX,XX +XXX,XX @@ static void gen_exception(DisasContext *s, uint32_t dest, int nr)
33
s->base.is_jmp = DISAS_NORETURN;
34
}
35
36
-static void gen_singlestep_exception(DisasContext *s)
135
-{
37
-{
136
- return ((uintptr_t)addr ^ ((uintptr_t)addr + size)) & ~0x0ffffffful;
38
- /*
39
- * Generate the right kind of exception for singlestep, which is
40
- * either the architectural singlestep or EXCP_DEBUG for QEMU's
41
- * gdb singlestepping.
42
- */
43
- if (s->ss_active) {
44
- gen_raise_exception(EXCP_TRACE);
45
- } else {
46
- gen_raise_exception(EXCP_DEBUG);
47
- }
137
-}
48
-}
138
-
49
-
139
-/* We weren't able to allocate a buffer without crossing that boundary,
50
static inline void gen_addr_fault(DisasContext *s)
140
- so make do with the larger portion of the buffer that doesn't cross.
141
- Returns the new base of the buffer, and adjusts code_gen_buffer_size. */
142
-static inline void *split_cross_256mb(void *buf1, size_t size1)
143
-{
144
- void *buf2 = (void *)(((uintptr_t)buf1 + size1) & ~0x0ffffffful);
145
- size_t size2 = buf1 + size1 - buf2;
146
-
147
- size1 = buf2 - buf1;
148
- if (size1 < size2) {
149
- size1 = size2;
150
- buf1 = buf2;
151
- }
152
-
153
- tcg_ctx->code_gen_buffer_size = size1;
154
- return buf1;
155
-}
156
-#endif
157
-
158
-#ifdef USE_STATIC_CODE_GEN_BUFFER
159
-static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
160
- __attribute__((aligned(CODE_GEN_ALIGN)));
161
-
162
-static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
163
-{
164
- void *buf, *end;
165
- size_t size;
166
-
167
- if (splitwx > 0) {
168
- error_setg(errp, "jit split-wx not supported");
169
- return false;
170
- }
171
-
172
- /* page-align the beginning and end of the buffer */
173
- buf = static_code_gen_buffer;
174
- end = static_code_gen_buffer + sizeof(static_code_gen_buffer);
175
- buf = QEMU_ALIGN_PTR_UP(buf, qemu_real_host_page_size);
176
- end = QEMU_ALIGN_PTR_DOWN(end, qemu_real_host_page_size);
177
-
178
- size = end - buf;
179
-
180
- /* Honor a command-line option limiting the size of the buffer. */
181
- if (size > tb_size) {
182
- size = QEMU_ALIGN_DOWN(tb_size, qemu_real_host_page_size);
183
- }
184
- tcg_ctx->code_gen_buffer_size = size;
185
-
186
-#ifdef __mips__
187
- if (cross_256mb(buf, size)) {
188
- buf = split_cross_256mb(buf, size);
189
- size = tcg_ctx->code_gen_buffer_size;
190
- }
191
-#endif
192
-
193
- if (qemu_mprotect_rwx(buf, size)) {
194
- error_setg_errno(errp, errno, "mprotect of jit buffer");
195
- return false;
196
- }
197
- qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
198
-
199
- tcg_ctx->code_gen_buffer = buf;
200
- return true;
201
-}
202
-#elif defined(_WIN32)
203
-static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
204
-{
205
- void *buf;
206
-
207
- if (splitwx > 0) {
208
- error_setg(errp, "jit split-wx not supported");
209
- return false;
210
- }
211
-
212
- buf = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT,
213
- PAGE_EXECUTE_READWRITE);
214
- if (buf == NULL) {
215
- error_setg_win32(errp, GetLastError(),
216
- "allocate %zu bytes for jit buffer", size);
217
- return false;
218
- }
219
-
220
- tcg_ctx->code_gen_buffer = buf;
221
- tcg_ctx->code_gen_buffer_size = size;
222
- return true;
223
-}
224
-#else
225
-static bool alloc_code_gen_buffer_anon(size_t size, int prot,
226
- int flags, Error **errp)
227
-{
228
- void *buf;
229
-
230
- buf = mmap(NULL, size, prot, flags, -1, 0);
231
- if (buf == MAP_FAILED) {
232
- error_setg_errno(errp, errno,
233
- "allocate %zu bytes for jit buffer", size);
234
- return false;
235
- }
236
- tcg_ctx->code_gen_buffer_size = size;
237
-
238
-#ifdef __mips__
239
- if (cross_256mb(buf, size)) {
240
- /*
241
- * Try again, with the original still mapped, to avoid re-acquiring
242
- * the same 256mb crossing.
243
- */
244
- size_t size2;
245
- void *buf2 = mmap(NULL, size, prot, flags, -1, 0);
246
- switch ((int)(buf2 != MAP_FAILED)) {
247
- case 1:
248
- if (!cross_256mb(buf2, size)) {
249
- /* Success! Use the new buffer. */
250
- munmap(buf, size);
251
- break;
252
- }
253
- /* Failure. Work with what we had. */
254
- munmap(buf2, size);
255
- /* fallthru */
256
- default:
257
- /* Split the original buffer. Free the smaller half. */
258
- buf2 = split_cross_256mb(buf, size);
259
- size2 = tcg_ctx->code_gen_buffer_size;
260
- if (buf == buf2) {
261
- munmap(buf + size2, size - size2);
262
- } else {
263
- munmap(buf, size - size2);
264
- }
265
- size = size2;
266
- break;
267
- }
268
- buf = buf2;
269
- }
270
-#endif
271
-
272
- /* Request large pages for the buffer. */
273
- qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
274
-
275
- tcg_ctx->code_gen_buffer = buf;
276
- return true;
277
-}
278
-
279
-#ifndef CONFIG_TCG_INTERPRETER
280
-#ifdef CONFIG_POSIX
281
-#include "qemu/memfd.h"
282
-
283
-static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
284
-{
285
- void *buf_rw = NULL, *buf_rx = MAP_FAILED;
286
- int fd = -1;
287
-
288
-#ifdef __mips__
289
- /* Find space for the RX mapping, vs the 256MiB regions. */
290
- if (!alloc_code_gen_buffer_anon(size, PROT_NONE,
291
- MAP_PRIVATE | MAP_ANONYMOUS |
292
- MAP_NORESERVE, errp)) {
293
- return false;
294
- }
295
- /* The size of the mapping may have been adjusted. */
296
- size = tcg_ctx->code_gen_buffer_size;
297
- buf_rx = tcg_ctx->code_gen_buffer;
298
-#endif
299
-
300
- buf_rw = qemu_memfd_alloc("tcg-jit", size, 0, &fd, errp);
301
- if (buf_rw == NULL) {
302
- goto fail;
303
- }
304
-
305
-#ifdef __mips__
306
- void *tmp = mmap(buf_rx, size, PROT_READ | PROT_EXEC,
307
- MAP_SHARED | MAP_FIXED, fd, 0);
308
- if (tmp != buf_rx) {
309
- goto fail_rx;
310
- }
311
-#else
312
- buf_rx = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
313
- if (buf_rx == MAP_FAILED) {
314
- goto fail_rx;
315
- }
316
-#endif
317
-
318
- close(fd);
319
- tcg_ctx->code_gen_buffer = buf_rw;
320
- tcg_ctx->code_gen_buffer_size = size;
321
- tcg_splitwx_diff = buf_rx - buf_rw;
322
-
323
- /* Request large pages for the buffer and the splitwx. */
324
- qemu_madvise(buf_rw, size, QEMU_MADV_HUGEPAGE);
325
- qemu_madvise(buf_rx, size, QEMU_MADV_HUGEPAGE);
326
- return true;
327
-
328
- fail_rx:
329
- error_setg_errno(errp, errno, "failed to map shared memory for execute");
330
- fail:
331
- if (buf_rx != MAP_FAILED) {
332
- munmap(buf_rx, size);
333
- }
334
- if (buf_rw) {
335
- munmap(buf_rw, size);
336
- }
337
- if (fd >= 0) {
338
- close(fd);
339
- }
340
- return false;
341
-}
342
-#endif /* CONFIG_POSIX */
343
-
344
-#ifdef CONFIG_DARWIN
345
-#include <mach/mach.h>
346
-
347
-extern kern_return_t mach_vm_remap(vm_map_t target_task,
348
- mach_vm_address_t *target_address,
349
- mach_vm_size_t size,
350
- mach_vm_offset_t mask,
351
- int flags,
352
- vm_map_t src_task,
353
- mach_vm_address_t src_address,
354
- boolean_t copy,
355
- vm_prot_t *cur_protection,
356
- vm_prot_t *max_protection,
357
- vm_inherit_t inheritance);
358
-
359
-static bool alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
360
-{
361
- kern_return_t ret;
362
- mach_vm_address_t buf_rw, buf_rx;
363
- vm_prot_t cur_prot, max_prot;
364
-
365
- /* Map the read-write portion via normal anon memory. */
366
- if (!alloc_code_gen_buffer_anon(size, PROT_READ | PROT_WRITE,
367
- MAP_PRIVATE | MAP_ANONYMOUS, errp)) {
368
- return false;
369
- }
370
-
371
- buf_rw = (mach_vm_address_t)tcg_ctx->code_gen_buffer;
372
- buf_rx = 0;
373
- ret = mach_vm_remap(mach_task_self(),
374
- &buf_rx,
375
- size,
376
- 0,
377
- VM_FLAGS_ANYWHERE,
378
- mach_task_self(),
379
- buf_rw,
380
- false,
381
- &cur_prot,
382
- &max_prot,
383
- VM_INHERIT_NONE);
384
- if (ret != KERN_SUCCESS) {
385
- /* TODO: Convert "ret" to a human readable error message. */
386
- error_setg(errp, "vm_remap for jit splitwx failed");
387
- munmap((void *)buf_rw, size);
388
- return false;
389
- }
390
-
391
- if (mprotect((void *)buf_rx, size, PROT_READ | PROT_EXEC) != 0) {
392
- error_setg_errno(errp, errno, "mprotect for jit splitwx");
393
- munmap((void *)buf_rx, size);
394
- munmap((void *)buf_rw, size);
395
- return false;
396
- }
397
-
398
- tcg_splitwx_diff = buf_rx - buf_rw;
399
- return true;
400
-}
401
-#endif /* CONFIG_DARWIN */
402
-#endif /* CONFIG_TCG_INTERPRETER */
403
-
404
-static bool alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
405
-{
406
-#ifndef CONFIG_TCG_INTERPRETER
407
-# ifdef CONFIG_DARWIN
408
- return alloc_code_gen_buffer_splitwx_vmremap(size, errp);
409
-# endif
410
-# ifdef CONFIG_POSIX
411
- return alloc_code_gen_buffer_splitwx_memfd(size, errp);
412
-# endif
413
-#endif
414
- error_setg(errp, "jit split-wx not supported");
415
- return false;
416
-}
417
-
418
-static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
419
-{
420
- ERRP_GUARD();
421
- int prot, flags;
422
-
423
- if (splitwx) {
424
- if (alloc_code_gen_buffer_splitwx(size, errp)) {
425
- return true;
426
- }
427
- /*
428
- * If splitwx force-on (1), fail;
429
- * if splitwx default-on (-1), fall through to splitwx off.
430
- */
431
- if (splitwx > 0) {
432
- return false;
433
- }
434
- error_free_or_abort(errp);
435
- }
436
-
437
- prot = PROT_READ | PROT_WRITE | PROT_EXEC;
438
- flags = MAP_PRIVATE | MAP_ANONYMOUS;
439
-#ifdef CONFIG_TCG_INTERPRETER
440
- /* The tcg interpreter does not need execute permission. */
441
- prot = PROT_READ | PROT_WRITE;
442
-#elif defined(CONFIG_DARWIN)
443
- /* Applicable to both iOS and macOS (Apple Silicon). */
444
- if (!splitwx) {
445
- flags |= MAP_JIT;
446
- }
447
-#endif
448
-
449
- return alloc_code_gen_buffer_anon(size, prot, flags, errp);
450
-}
451
-#endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
452
-
453
static bool tb_cmp(const void *ap, const void *bp)
454
{
51
{
455
const TranslationBlock *a = ap;
52
gen_exception(s, s->base.pc_next, EXCP_ADDRESS);
456
@@ -XXX,XX +XXX,XX @@ static void tb_htable_init(void)
53
@@ -XXX,XX +XXX,XX @@ static void gen_exit_tb(DisasContext *s)
457
size. */
54
/* Generate a jump to an immediate address. */
458
void tcg_exec_init(unsigned long tb_size, int splitwx)
55
static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
459
{
56
{
460
- bool ok;
57
- if (unlikely(is_singlestepping(s))) {
461
-
58
+ if (unlikely(s->ss_active)) {
462
tcg_allowed = true;
59
update_cc_op(s);
463
tcg_context_init(&tcg_init_ctx);
60
tcg_gen_movi_i32(QREG_PC, dest);
464
page_init();
61
- gen_singlestep_exception(s);
465
tb_htable_init();
62
+ gen_raise_exception(EXCP_TRACE);
466
-
63
} else if (translator_use_goto_tb(&s->base, dest)) {
467
- ok = alloc_code_gen_buffer(size_code_gen_buffer(tb_size),
64
tcg_gen_goto_tb(n);
468
- splitwx, &error_fatal);
65
tcg_gen_movi_i32(QREG_PC, dest);
469
- assert(ok);
66
@@ -XXX,XX +XXX,XX @@ static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
470
-
67
471
- /* TODO: allocating regions is hand-in-glove with code_gen_buffer. */
68
dc->ss_active = (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS);
472
- tcg_region_init();
69
/* If architectural single step active, limit to 1 */
473
+ tcg_region_init(tb_size, splitwx);
70
- if (is_singlestepping(dc)) {
474
71
+ if (dc->ss_active) {
475
#if defined(CONFIG_SOFTMMU)
72
dc->base.max_insns = 1;
476
/* There's no guest base to take into account, so go ahead and
73
}
477
diff --git a/tcg/region.c b/tcg/region.c
478
index XXXXXXX..XXXXXXX 100644
479
--- a/tcg/region.c
480
+++ b/tcg/region.c
481
@@ -XXX,XX +XXX,XX @@
482
*/
483
484
#include "qemu/osdep.h"
485
+#include "qemu/units.h"
486
+#include "qapi/error.h"
487
#include "exec/exec-all.h"
488
#include "tcg/tcg.h"
489
#if !defined(CONFIG_USER_ONLY)
490
@@ -XXX,XX +XXX,XX @@ static size_t tcg_n_regions(void)
491
}
74
}
492
#endif
75
@@ -XXX,XX +XXX,XX @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
493
76
break;
494
+/*
77
case DISAS_TOO_MANY:
495
+ * Minimum size of the code gen buffer. This number is randomly chosen,
78
update_cc_op(dc);
496
+ * but not so small that we can't have a fair number of TB's live.
79
- if (is_singlestepping(dc)) {
497
+ */
80
+ if (dc->ss_active) {
498
+#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB)
81
tcg_gen_movi_i32(QREG_PC, dc->pc);
499
+
82
- gen_singlestep_exception(dc);
500
+/*
83
+ gen_raise_exception(EXCP_TRACE);
501
+ * Maximum size of the code gen buffer we'd like to use. Unless otherwise
84
} else {
502
+ * indicated, this is constrained by the range of direct branches on the
85
gen_jmp_tb(dc, 0, dc->pc);
503
+ * host cpu, as used by the TCG implementation of goto_tb.
86
}
504
+ */
87
break;
505
+#if defined(__x86_64__)
88
case DISAS_JUMP:
506
+# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
89
/* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */
507
+#elif defined(__sparc__)
90
- if (is_singlestepping(dc)) {
508
+# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
91
- gen_singlestep_exception(dc);
509
+#elif defined(__powerpc64__)
92
+ if (dc->ss_active) {
510
+# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
93
+ gen_raise_exception(EXCP_TRACE);
511
+#elif defined(__powerpc__)
94
} else {
512
+# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
95
tcg_gen_lookup_and_goto_ptr();
513
+#elif defined(__aarch64__)
96
}
514
+# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
97
@@ -XXX,XX +XXX,XX @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
515
+#elif defined(__s390x__)
98
* We updated CC_OP and PC in gen_exit_tb, but also modified
516
+ /* We have a +- 4GB range on the branches; leave some slop. */
99
* other state that may require returning to the main loop.
517
+# define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
100
*/
518
+#elif defined(__mips__)
101
- if (is_singlestepping(dc)) {
519
+ /*
102
- gen_singlestep_exception(dc);
520
+ * We have a 256MB branch region, but leave room to make sure the
103
+ if (dc->ss_active) {
521
+ * main executable is also within that region.
104
+ gen_raise_exception(EXCP_TRACE);
522
+ */
105
} else {
523
+# define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB)
106
tcg_gen_exit_tb(NULL, 0);
524
+#else
107
}
525
+# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
526
+#endif
527
+
528
+#if TCG_TARGET_REG_BITS == 32
529
+#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32 * MiB)
530
+#ifdef CONFIG_USER_ONLY
531
+/*
532
+ * For user mode on smaller 32 bit systems we may run into trouble
533
+ * allocating big chunks of data in the right place. On these systems
534
+ * we utilise a static code generation buffer directly in the binary.
535
+ */
536
+#define USE_STATIC_CODE_GEN_BUFFER
537
+#endif
538
+#else /* TCG_TARGET_REG_BITS == 64 */
539
+#ifdef CONFIG_USER_ONLY
540
+/*
541
+ * As user-mode emulation typically means running multiple instances
542
+ * of the translator don't go too nuts with our default code gen
543
+ * buffer lest we make things too hard for the OS.
544
+ */
545
+#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (128 * MiB)
546
+#else
547
+/*
548
+ * We expect most system emulation to run one or two guests per host.
549
+ * Users running large scale system emulation may want to tweak their
550
+ * runtime setup via the tb-size control on the command line.
551
+ */
552
+#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (1 * GiB)
553
+#endif
554
+#endif
555
+
556
+#define DEFAULT_CODE_GEN_BUFFER_SIZE \
557
+ (DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \
558
+ ? DEFAULT_CODE_GEN_BUFFER_SIZE_1 : MAX_CODE_GEN_BUFFER_SIZE)
559
+
560
+static size_t size_code_gen_buffer(size_t tb_size)
561
+{
562
+ /* Size the buffer. */
563
+ if (tb_size == 0) {
564
+ size_t phys_mem = qemu_get_host_physmem();
565
+ if (phys_mem == 0) {
566
+ tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
567
+ } else {
568
+ tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, phys_mem / 8);
569
+ }
570
+ }
571
+ if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
572
+ tb_size = MIN_CODE_GEN_BUFFER_SIZE;
573
+ }
574
+ if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) {
575
+ tb_size = MAX_CODE_GEN_BUFFER_SIZE;
576
+ }
577
+ return tb_size;
578
+}
579
+
580
+#ifdef __mips__
581
+/*
582
+ * In order to use J and JAL within the code_gen_buffer, we require
583
+ * that the buffer not cross a 256MB boundary.
584
+ */
585
+static inline bool cross_256mb(void *addr, size_t size)
586
+{
587
+ return ((uintptr_t)addr ^ ((uintptr_t)addr + size)) & ~0x0ffffffful;
588
+}
589
+
590
+/*
591
+ * We weren't able to allocate a buffer without crossing that boundary,
592
+ * so make do with the larger portion of the buffer that doesn't cross.
593
+ * Returns the new base of the buffer, and adjusts code_gen_buffer_size.
594
+ */
595
+static inline void *split_cross_256mb(void *buf1, size_t size1)
596
+{
597
+ void *buf2 = (void *)(((uintptr_t)buf1 + size1) & ~0x0ffffffful);
598
+ size_t size2 = buf1 + size1 - buf2;
599
+
600
+ size1 = buf2 - buf1;
601
+ if (size1 < size2) {
602
+ size1 = size2;
603
+ buf1 = buf2;
604
+ }
605
+
606
+ tcg_ctx->code_gen_buffer_size = size1;
607
+ return buf1;
608
+}
609
+#endif
610
+
611
+#ifdef USE_STATIC_CODE_GEN_BUFFER
612
+static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
613
+ __attribute__((aligned(CODE_GEN_ALIGN)));
614
+
615
+static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
616
+{
617
+ void *buf, *end;
618
+ size_t size;
619
+
620
+ if (splitwx > 0) {
621
+ error_setg(errp, "jit split-wx not supported");
622
+ return false;
623
+ }
624
+
625
+ /* page-align the beginning and end of the buffer */
626
+ buf = static_code_gen_buffer;
627
+ end = static_code_gen_buffer + sizeof(static_code_gen_buffer);
628
+ buf = QEMU_ALIGN_PTR_UP(buf, qemu_real_host_page_size);
629
+ end = QEMU_ALIGN_PTR_DOWN(end, qemu_real_host_page_size);
630
+
631
+ size = end - buf;
632
+
633
+ /* Honor a command-line option limiting the size of the buffer. */
634
+ if (size > tb_size) {
635
+ size = QEMU_ALIGN_DOWN(tb_size, qemu_real_host_page_size);
636
+ }
637
+ tcg_ctx->code_gen_buffer_size = size;
638
+
639
+#ifdef __mips__
640
+ if (cross_256mb(buf, size)) {
641
+ buf = split_cross_256mb(buf, size);
642
+ size = tcg_ctx->code_gen_buffer_size;
643
+ }
644
+#endif
645
+
646
+ if (qemu_mprotect_rwx(buf, size)) {
647
+ error_setg_errno(errp, errno, "mprotect of jit buffer");
648
+ return false;
649
+ }
650
+ qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
651
+
652
+ tcg_ctx->code_gen_buffer = buf;
653
+ return true;
654
+}
655
+#elif defined(_WIN32)
656
+static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
657
+{
658
+ void *buf;
659
+
660
+ if (splitwx > 0) {
661
+ error_setg(errp, "jit split-wx not supported");
662
+ return false;
663
+ }
664
+
665
+ buf = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT,
666
+ PAGE_EXECUTE_READWRITE);
667
+ if (buf == NULL) {
668
+ error_setg_win32(errp, GetLastError(),
669
+ "allocate %zu bytes for jit buffer", size);
670
+ return false;
671
+ }
672
+
673
+ tcg_ctx->code_gen_buffer = buf;
674
+ tcg_ctx->code_gen_buffer_size = size;
675
+ return true;
676
+}
677
+#else
678
+static bool alloc_code_gen_buffer_anon(size_t size, int prot,
679
+ int flags, Error **errp)
680
+{
681
+ void *buf;
682
+
683
+ buf = mmap(NULL, size, prot, flags, -1, 0);
684
+ if (buf == MAP_FAILED) {
685
+ error_setg_errno(errp, errno,
686
+ "allocate %zu bytes for jit buffer", size);
687
+ return false;
688
+ }
689
+ tcg_ctx->code_gen_buffer_size = size;
690
+
691
+#ifdef __mips__
692
+ if (cross_256mb(buf, size)) {
693
+ /*
694
+ * Try again, with the original still mapped, to avoid re-acquiring
695
+ * the same 256mb crossing.
696
+ */
697
+ size_t size2;
698
+ void *buf2 = mmap(NULL, size, prot, flags, -1, 0);
699
+ switch ((int)(buf2 != MAP_FAILED)) {
700
+ case 1:
701
+ if (!cross_256mb(buf2, size)) {
702
+ /* Success! Use the new buffer. */
703
+ munmap(buf, size);
704
+ break;
705
+ }
706
+ /* Failure. Work with what we had. */
707
+ munmap(buf2, size);
708
+ /* fallthru */
709
+ default:
710
+ /* Split the original buffer. Free the smaller half. */
711
+ buf2 = split_cross_256mb(buf, size);
712
+ size2 = tcg_ctx->code_gen_buffer_size;
713
+ if (buf == buf2) {
714
+ munmap(buf + size2, size - size2);
715
+ } else {
716
+ munmap(buf, size - size2);
717
+ }
718
+ size = size2;
719
+ break;
720
+ }
721
+ buf = buf2;
722
+ }
723
+#endif
724
+
725
+ /* Request large pages for the buffer. */
726
+ qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
727
+
728
+ tcg_ctx->code_gen_buffer = buf;
729
+ return true;
730
+}
731
+
732
+#ifndef CONFIG_TCG_INTERPRETER
733
+#ifdef CONFIG_POSIX
734
+#include "qemu/memfd.h"
735
+
736
+static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
737
+{
738
+ void *buf_rw = NULL, *buf_rx = MAP_FAILED;
739
+ int fd = -1;
740
+
741
+#ifdef __mips__
742
+ /* Find space for the RX mapping, vs the 256MiB regions. */
743
+ if (!alloc_code_gen_buffer_anon(size, PROT_NONE,
744
+ MAP_PRIVATE | MAP_ANONYMOUS |
745
+ MAP_NORESERVE, errp)) {
746
+ return false;
747
+ }
748
+ /* The size of the mapping may have been adjusted. */
749
+ size = tcg_ctx->code_gen_buffer_size;
750
+ buf_rx = tcg_ctx->code_gen_buffer;
751
+#endif
752
+
753
+ buf_rw = qemu_memfd_alloc("tcg-jit", size, 0, &fd, errp);
754
+ if (buf_rw == NULL) {
755
+ goto fail;
756
+ }
757
+
758
+#ifdef __mips__
759
+ void *tmp = mmap(buf_rx, size, PROT_READ | PROT_EXEC,
760
+ MAP_SHARED | MAP_FIXED, fd, 0);
761
+ if (tmp != buf_rx) {
762
+ goto fail_rx;
763
+ }
764
+#else
765
+ buf_rx = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
766
+ if (buf_rx == MAP_FAILED) {
767
+ goto fail_rx;
768
+ }
769
+#endif
770
+
771
+ close(fd);
772
+ tcg_ctx->code_gen_buffer = buf_rw;
773
+ tcg_ctx->code_gen_buffer_size = size;
774
+ tcg_splitwx_diff = buf_rx - buf_rw;
775
+
776
+ /* Request large pages for the buffer and the splitwx. */
777
+ qemu_madvise(buf_rw, size, QEMU_MADV_HUGEPAGE);
778
+ qemu_madvise(buf_rx, size, QEMU_MADV_HUGEPAGE);
779
+ return true;
780
+
781
+ fail_rx:
782
+ error_setg_errno(errp, errno, "failed to map shared memory for execute");
783
+ fail:
784
+ if (buf_rx != MAP_FAILED) {
785
+ munmap(buf_rx, size);
786
+ }
787
+ if (buf_rw) {
788
+ munmap(buf_rw, size);
789
+ }
790
+ if (fd >= 0) {
791
+ close(fd);
792
+ }
793
+ return false;
794
+}
795
+#endif /* CONFIG_POSIX */
796
+
797
+#ifdef CONFIG_DARWIN
798
+#include <mach/mach.h>
799
+
800
+extern kern_return_t mach_vm_remap(vm_map_t target_task,
801
+ mach_vm_address_t *target_address,
802
+ mach_vm_size_t size,
803
+ mach_vm_offset_t mask,
804
+ int flags,
805
+ vm_map_t src_task,
806
+ mach_vm_address_t src_address,
807
+ boolean_t copy,
808
+ vm_prot_t *cur_protection,
809
+ vm_prot_t *max_protection,
810
+ vm_inherit_t inheritance);
811
+
812
+static bool alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
813
+{
814
+ kern_return_t ret;
815
+ mach_vm_address_t buf_rw, buf_rx;
816
+ vm_prot_t cur_prot, max_prot;
817
+
818
+ /* Map the read-write portion via normal anon memory. */
819
+ if (!alloc_code_gen_buffer_anon(size, PROT_READ | PROT_WRITE,
820
+ MAP_PRIVATE | MAP_ANONYMOUS, errp)) {
821
+ return false;
822
+ }
823
+
824
+ buf_rw = (mach_vm_address_t)tcg_ctx->code_gen_buffer;
825
+ buf_rx = 0;
826
+ ret = mach_vm_remap(mach_task_self(),
827
+ &buf_rx,
828
+ size,
829
+ 0,
830
+ VM_FLAGS_ANYWHERE,
831
+ mach_task_self(),
832
+ buf_rw,
833
+ false,
834
+ &cur_prot,
835
+ &max_prot,
836
+ VM_INHERIT_NONE);
837
+ if (ret != KERN_SUCCESS) {
838
+ /* TODO: Convert "ret" to a human readable error message. */
839
+ error_setg(errp, "vm_remap for jit splitwx failed");
840
+ munmap((void *)buf_rw, size);
841
+ return false;
842
+ }
843
+
844
+ if (mprotect((void *)buf_rx, size, PROT_READ | PROT_EXEC) != 0) {
845
+ error_setg_errno(errp, errno, "mprotect for jit splitwx");
846
+ munmap((void *)buf_rx, size);
847
+ munmap((void *)buf_rw, size);
848
+ return false;
849
+ }
850
+
851
+ tcg_splitwx_diff = buf_rx - buf_rw;
852
+ return true;
853
+}
854
+#endif /* CONFIG_DARWIN */
855
+#endif /* CONFIG_TCG_INTERPRETER */
856
+
857
+static bool alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
858
+{
859
+#ifndef CONFIG_TCG_INTERPRETER
860
+# ifdef CONFIG_DARWIN
861
+ return alloc_code_gen_buffer_splitwx_vmremap(size, errp);
862
+# endif
863
+# ifdef CONFIG_POSIX
864
+ return alloc_code_gen_buffer_splitwx_memfd(size, errp);
865
+# endif
866
+#endif
867
+ error_setg(errp, "jit split-wx not supported");
868
+ return false;
869
+}
870
+
871
+static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
872
+{
873
+ ERRP_GUARD();
874
+ int prot, flags;
875
+
876
+ if (splitwx) {
877
+ if (alloc_code_gen_buffer_splitwx(size, errp)) {
878
+ return true;
879
+ }
880
+ /*
881
+ * If splitwx force-on (1), fail;
882
+ * if splitwx default-on (-1), fall through to splitwx off.
883
+ */
884
+ if (splitwx > 0) {
885
+ return false;
886
+ }
887
+ error_free_or_abort(errp);
888
+ }
889
+
890
+ prot = PROT_READ | PROT_WRITE | PROT_EXEC;
891
+ flags = MAP_PRIVATE | MAP_ANONYMOUS;
892
+#ifdef CONFIG_TCG_INTERPRETER
893
+ /* The tcg interpreter does not need execute permission. */
894
+ prot = PROT_READ | PROT_WRITE;
895
+#elif defined(CONFIG_DARWIN)
896
+ /* Applicable to both iOS and macOS (Apple Silicon). */
897
+ if (!splitwx) {
898
+ flags |= MAP_JIT;
899
+ }
900
+#endif
901
+
902
+ return alloc_code_gen_buffer_anon(size, prot, flags, errp);
903
+}
904
+#endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
905
+
906
/*
907
* Initializes region partitioning.
908
*
909
@@ -XXX,XX +XXX,XX @@ static size_t tcg_n_regions(void)
910
* in practice. Multi-threaded guests share most if not all of their translated
911
* code, which makes parallel code generation less appealing than in softmmu.
912
*/
913
-void tcg_region_init(void)
914
+void tcg_region_init(size_t tb_size, int splitwx)
915
{
916
- void *buf = tcg_init_ctx.code_gen_buffer;
917
- void *aligned;
918
- size_t size = tcg_init_ctx.code_gen_buffer_size;
919
- size_t page_size = qemu_real_host_page_size;
920
+ void *buf, *aligned;
921
+ size_t size;
922
+ size_t page_size;
923
size_t region_size;
924
size_t n_regions;
925
size_t i;
926
+ bool ok;
927
928
+ ok = alloc_code_gen_buffer(size_code_gen_buffer(tb_size),
929
+ splitwx, &error_fatal);
930
+ assert(ok);
931
+
932
+ buf = tcg_init_ctx.code_gen_buffer;
933
+ size = tcg_init_ctx.code_gen_buffer_size;
934
+ page_size = qemu_real_host_page_size;
935
n_regions = tcg_n_regions();
936
937
/* The first region will be 'aligned - buf' bytes larger than the others */
938
--
108
--
939
2.25.1
109
2.25.1
940
110
941
111
diff view generated by jsdifflib
1
At some point during the development of tcg_constant_*, I changed
1
We were using singlestep_enabled as a proxy for whether
2
my mind about whether such temps should be able to be passed to
2
translator_use_goto_tb would always return false.
3
tcg_temp_free_*. The final version committed allows this, but the
4
commentary was not updated to match.
5
3
6
Fixes: c0522136adf
7
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
9
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
---
5
---
12
include/tcg/tcg.h | 3 ++-
6
target/microblaze/translate.c | 4 ++--
13
1 file changed, 2 insertions(+), 1 deletion(-)
7
1 file changed, 2 insertions(+), 2 deletions(-)
14
8
15
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
9
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
16
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
17
--- a/include/tcg/tcg.h
11
--- a/target/microblaze/translate.c
18
+++ b/include/tcg/tcg.h
12
+++ b/target/microblaze/translate.c
19
@@ -XXX,XX +XXX,XX @@ TCGv_vec tcg_const_ones_vec_matching(TCGv_vec);
13
@@ -XXX,XX +XXX,XX @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
20
14
break;
21
/*
15
22
* Locate or create a read-only temporary that is a constant.
16
case DISAS_JUMP:
23
- * This kind of temporary need not and should not be freed.
17
- if (dc->jmp_dest != -1 && !cs->singlestep_enabled) {
24
+ * This kind of temporary need not be freed, but for convenience
18
+ if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
25
+ * will be silently ignored by tcg_temp_free_*.
19
/* Direct jump. */
26
*/
20
tcg_gen_discard_i32(cpu_btarget);
27
TCGTemp *tcg_constant_internal(TCGType type, int64_t val);
21
22
@@ -XXX,XX +XXX,XX @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
23
return;
24
}
25
26
- /* Indirect jump (or direct jump w/ singlestep) */
27
+ /* Indirect jump (or direct jump w/ goto_tb disabled) */
28
tcg_gen_mov_i32(cpu_pc, cpu_btarget);
29
tcg_gen_discard_i32(cpu_btarget);
28
30
29
--
31
--
30
2.25.1
32
2.25.1
31
33
32
34
diff view generated by jsdifflib
1
From: "Jose R. Ziviani" <jziviani@suse.de>
1
GDB single-stepping is now handled generically.
2
2
3
Commit 5e8892db93 fixed several function signatures but tcg_out_op for
4
arm is missing. This patch fixes it as well.
5
6
Signed-off-by: Jose R. Ziviani <jziviani@suse.de>
7
Message-Id: <20210610224450.23425-1-jziviani@suse.de>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
---
4
---
10
tcg/arm/tcg-target.c.inc | 3 ++-
5
target/microblaze/translate.c | 14 ++------------
11
1 file changed, 2 insertions(+), 1 deletion(-)
6
1 file changed, 2 insertions(+), 12 deletions(-)
12
7
13
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
8
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
14
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
15
--- a/tcg/arm/tcg-target.c.inc
10
--- a/target/microblaze/translate.c
16
+++ b/tcg/arm/tcg-target.c.inc
11
+++ b/target/microblaze/translate.c
17
@@ -XXX,XX +XXX,XX @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
12
@@ -XXX,XX +XXX,XX @@ static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
18
static void tcg_out_epilogue(TCGContext *s);
13
19
14
static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
20
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
21
- const TCGArg *args, const int *const_args)
22
+ const TCGArg args[TCG_MAX_OP_ARGS],
23
+ const int const_args[TCG_MAX_OP_ARGS])
24
{
15
{
25
TCGArg a0, a1, a2, a3, a4, a5;
16
- if (dc->base.singlestep_enabled) {
26
int c;
17
- TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
18
- tcg_gen_movi_i32(cpu_pc, dest);
19
- gen_helper_raise_exception(cpu_env, tmp);
20
- tcg_temp_free_i32(tmp);
21
- } else if (translator_use_goto_tb(&dc->base, dest)) {
22
+ if (translator_use_goto_tb(&dc->base, dest)) {
23
tcg_gen_goto_tb(n);
24
tcg_gen_movi_i32(cpu_pc, dest);
25
tcg_gen_exit_tb(dc->base.tb, n);
26
@@ -XXX,XX +XXX,XX @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
27
/* Indirect jump (or direct jump w/ goto_tb disabled) */
28
tcg_gen_mov_i32(cpu_pc, cpu_btarget);
29
tcg_gen_discard_i32(cpu_btarget);
30
-
31
- if (unlikely(cs->singlestep_enabled)) {
32
- gen_raise_exception(dc, EXCP_DEBUG);
33
- } else {
34
- tcg_gen_lookup_and_goto_ptr();
35
- }
36
+ tcg_gen_lookup_and_goto_ptr();
37
return;
38
39
default:
27
--
40
--
28
2.25.1
41
2.25.1
29
42
30
43
diff view generated by jsdifflib
1
If qemu_get_host_physmem returns an odd number of pages,
1
As per an ancient comment in mips_tr_translate_insn about the
2
then physmem / 8 will not be a multiple of the page size.
2
expectations of gdb, when restarting the insn in a delay slot
3
we also re-execute the branch. Which means that we are
4
expected to execute two insns in this case.
3
5
4
The following was observed on a gitlab runner:
6
This has been broken since 8b86d6d2580, where we forced max_insns
7
to 1 while single-stepping. This resulted in an exit from the
8
translator loop after the branch but before the delay slot is
9
translated.
5
10
6
ERROR qtest-arm/boot-serial-test - Bail out!
11
Increase the max_insns to 2 for this case. In addition, bypass
7
ERROR:../util/osdep.c:80:qemu_mprotect__osdep: \
12
the end-of-page check, for when the branch itself ends the page.
8
assertion failed: (!(size & ~qemu_real_host_page_mask))
9
13
10
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
12
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
15
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
13
---
16
---
14
tcg/region.c | 47 +++++++++++++++++++++--------------------------
17
target/mips/tcg/translate.c | 25 ++++++++++++++++---------
15
1 file changed, 21 insertions(+), 26 deletions(-)
18
1 file changed, 16 insertions(+), 9 deletions(-)
16
19
17
diff --git a/tcg/region.c b/tcg/region.c
20
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
18
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
19
--- a/tcg/region.c
22
--- a/target/mips/tcg/translate.c
20
+++ b/tcg/region.c
23
+++ b/target/mips/tcg/translate.c
21
@@ -XXX,XX +XXX,XX @@ static size_t tcg_n_regions(size_t tb_size, unsigned max_cpus)
24
@@ -XXX,XX +XXX,XX @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
22
(DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \
25
ctx->default_tcg_memop_mask = (ctx->insn_flags & (ISA_MIPS_R6 |
23
? DEFAULT_CODE_GEN_BUFFER_SIZE_1 : MAX_CODE_GEN_BUFFER_SIZE)
26
INSN_LOONGSON3A)) ? MO_UNALN : MO_ALIGN;
24
27
25
-static size_t size_code_gen_buffer(size_t tb_size)
28
+ /*
26
-{
29
+ * Execute a branch and its delay slot as a single instruction.
27
- /* Size the buffer. */
30
+ * This is what GDB expects and is consistent with what the
28
- if (tb_size == 0) {
31
+ * hardware does (e.g. if a delay slot instruction faults, the
29
- size_t phys_mem = qemu_get_host_physmem();
32
+ * reported PC is the PC of the branch).
30
- if (phys_mem == 0) {
33
+ */
31
- tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
34
+ if (ctx->base.singlestep_enabled && (ctx->hflags & MIPS_HFLAG_BMASK)) {
32
- } else {
35
+ ctx->base.max_insns = 2;
33
- tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, phys_mem / 8);
34
- }
35
- }
36
- if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
37
- tb_size = MIN_CODE_GEN_BUFFER_SIZE;
38
- }
39
- if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) {
40
- tb_size = MAX_CODE_GEN_BUFFER_SIZE;
41
- }
42
- return tb_size;
43
-}
44
-
45
#ifdef __mips__
46
/*
47
* In order to use J and JAL within the code_gen_buffer, we require
48
@@ -XXX,XX +XXX,XX @@ static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
49
*/
50
void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
51
{
52
- size_t page_size;
53
+ const size_t page_size = qemu_real_host_page_size;
54
size_t region_size;
55
size_t i;
56
int have_prot;
57
58
- have_prot = alloc_code_gen_buffer(size_code_gen_buffer(tb_size),
59
- splitwx, &error_fatal);
60
+ /* Size the buffer. */
61
+ if (tb_size == 0) {
62
+ size_t phys_mem = qemu_get_host_physmem();
63
+ if (phys_mem == 0) {
64
+ tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
65
+ } else {
66
+ tb_size = QEMU_ALIGN_DOWN(phys_mem / 8, page_size);
67
+ tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, tb_size);
68
+ }
69
+ }
70
+ if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
71
+ tb_size = MIN_CODE_GEN_BUFFER_SIZE;
72
+ }
73
+ if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) {
74
+ tb_size = MAX_CODE_GEN_BUFFER_SIZE;
75
+ }
36
+ }
76
+
37
+
77
+ have_prot = alloc_code_gen_buffer(tb_size, splitwx, &error_fatal);
38
LOG_DISAS("\ntb %p idx %d hflags %04x\n", ctx->base.tb, ctx->mem_idx,
78
assert(have_prot >= 0);
39
ctx->hflags);
79
40
}
80
/* Request large pages for the buffer and the splitwx. */
41
@@ -XXX,XX +XXX,XX @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
81
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
42
if (ctx->base.is_jmp != DISAS_NEXT) {
82
* As a result of this we might end up with a few extra pages at the end of
43
return;
83
* the buffer; we will assign those to the last region.
44
}
45
+
46
/*
47
- * Execute a branch and its delay slot as a single instruction.
48
- * This is what GDB expects and is consistent with what the
49
- * hardware does (e.g. if a delay slot instruction faults, the
50
- * reported PC is the PC of the branch).
51
+ * End the TB on (most) page crossings.
52
+ * See mips_tr_init_disas_context about single-stepping a branch
53
+ * together with its delay slot.
84
*/
54
*/
85
- region.n = tcg_n_regions(region.total_size, max_cpus);
55
- if (ctx->base.singlestep_enabled &&
86
- page_size = qemu_real_host_page_size;
56
- (ctx->hflags & MIPS_HFLAG_BMASK) == 0) {
87
- region_size = region.total_size / region.n;
57
- ctx->base.is_jmp = DISAS_TOO_MANY;
88
+ region.n = tcg_n_regions(tb_size, max_cpus);
58
- }
89
+ region_size = tb_size / region.n;
59
- if (ctx->base.pc_next - ctx->page_start >= TARGET_PAGE_SIZE) {
90
region_size = QEMU_ALIGN_DOWN(region_size, page_size);
60
+ if (ctx->base.pc_next - ctx->page_start >= TARGET_PAGE_SIZE
91
61
+ && !ctx->base.singlestep_enabled) {
92
/* A region must have at least 2 pages; one code, one guard */
62
ctx->base.is_jmp = DISAS_TOO_MANY;
63
}
64
}
93
--
65
--
94
2.25.1
66
2.25.1
95
67
96
68
diff view generated by jsdifflib
1
Perform both tcg_context_init and tcg_region_init.
1
GDB single-stepping is now handled generically.
2
Do not leave this split to the caller.
3
2
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
5
---
8
include/tcg/tcg.h | 3 +--
6
target/mips/tcg/translate.c | 50 +++++++++++++------------------------
9
tcg/tcg-internal.h | 1 +
7
1 file changed, 18 insertions(+), 32 deletions(-)
10
accel/tcg/translate-all.c | 3 +--
11
tcg/tcg.c | 9 ++++++++-
12
4 files changed, 11 insertions(+), 5 deletions(-)
13
8
14
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
9
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
15
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
16
--- a/include/tcg/tcg.h
11
--- a/target/mips/tcg/translate.c
17
+++ b/include/tcg/tcg.h
12
+++ b/target/mips/tcg/translate.c
18
@@ -XXX,XX +XXX,XX @@ void *tcg_malloc_internal(TCGContext *s, int size);
13
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
19
void tcg_pool_reset(TCGContext *s);
14
tcg_gen_exit_tb(ctx->base.tb, n);
20
TranslationBlock *tcg_tb_alloc(TCGContext *s);
15
} else {
21
16
gen_save_pc(dest);
22
-void tcg_region_init(size_t tb_size, int splitwx);
17
- if (ctx->base.singlestep_enabled) {
23
void tb_destroy(TranslationBlock *tb);
18
- save_cpu_state(ctx, 0);
24
void tcg_region_reset_all(void);
19
- gen_helper_raise_exception_debug(cpu_env);
25
20
- } else {
26
@@ -XXX,XX +XXX,XX @@ static inline void *tcg_malloc(int size)
21
- tcg_gen_lookup_and_goto_ptr();
22
- }
23
+ tcg_gen_lookup_and_goto_ptr();
27
}
24
}
28
}
25
}
29
26
30
-void tcg_context_init(TCGContext *s);
27
@@ -XXX,XX +XXX,XX @@ static void gen_branch(DisasContext *ctx, int insn_bytes)
31
+void tcg_init(size_t tb_size, int splitwx);
28
} else {
32
void tcg_register_thread(void);
29
tcg_gen_mov_tl(cpu_PC, btarget);
33
void tcg_prologue_init(TCGContext *s);
30
}
34
void tcg_func_start(TCGContext *s);
31
- if (ctx->base.singlestep_enabled) {
35
diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h
32
- save_cpu_state(ctx, 0);
36
index XXXXXXX..XXXXXXX 100644
33
- gen_helper_raise_exception_debug(cpu_env);
37
--- a/tcg/tcg-internal.h
34
- }
38
+++ b/tcg/tcg-internal.h
35
tcg_gen_lookup_and_goto_ptr();
39
@@ -XXX,XX +XXX,XX @@
36
break;
40
extern TCGContext **tcg_ctxs;
37
default:
41
extern unsigned int n_tcg_ctxs;
38
@@ -XXX,XX +XXX,XX @@ static void mips_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
42
43
+void tcg_region_init(size_t tb_size, int splitwx);
44
bool tcg_region_alloc(TCGContext *s);
45
void tcg_region_initial_alloc(TCGContext *s);
46
void tcg_region_prologue_set(TCGContext *s);
47
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/accel/tcg/translate-all.c
50
+++ b/accel/tcg/translate-all.c
51
@@ -XXX,XX +XXX,XX @@ static void tb_htable_init(void)
52
void tcg_exec_init(unsigned long tb_size, int splitwx)
53
{
39
{
54
tcg_allowed = true;
40
DisasContext *ctx = container_of(dcbase, DisasContext, base);
55
- tcg_context_init(&tcg_init_ctx);
41
56
page_init();
42
- if (ctx->base.singlestep_enabled && ctx->base.is_jmp != DISAS_NORETURN) {
57
tb_htable_init();
43
- save_cpu_state(ctx, ctx->base.is_jmp != DISAS_EXIT);
58
- tcg_region_init(tb_size, splitwx);
44
- gen_helper_raise_exception_debug(cpu_env);
59
+ tcg_init(tb_size, splitwx);
45
- } else {
60
46
- switch (ctx->base.is_jmp) {
61
#if defined(CONFIG_SOFTMMU)
47
- case DISAS_STOP:
62
/* There's no guest base to take into account, so go ahead and
48
- gen_save_pc(ctx->base.pc_next);
63
diff --git a/tcg/tcg.c b/tcg/tcg.c
49
- tcg_gen_lookup_and_goto_ptr();
64
index XXXXXXX..XXXXXXX 100644
50
- break;
65
--- a/tcg/tcg.c
51
- case DISAS_NEXT:
66
+++ b/tcg/tcg.c
52
- case DISAS_TOO_MANY:
67
@@ -XXX,XX +XXX,XX @@ static void process_op_defs(TCGContext *s);
53
- save_cpu_state(ctx, 0);
68
static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
54
- gen_goto_tb(ctx, 0, ctx->base.pc_next);
69
TCGReg reg, const char *name);
55
- break;
70
56
- case DISAS_EXIT:
71
-void tcg_context_init(TCGContext *s)
57
- tcg_gen_exit_tb(NULL, 0);
72
+static void tcg_context_init(void)
58
- break;
73
{
59
- case DISAS_NORETURN:
74
+ TCGContext *s = &tcg_init_ctx;
60
- break;
75
int op, total_args, n, i;
61
- default:
76
TCGOpDef *def;
62
- g_assert_not_reached();
77
TCGArgConstraint *args_ct;
63
- }
78
@@ -XXX,XX +XXX,XX @@ void tcg_context_init(TCGContext *s)
64
+ switch (ctx->base.is_jmp) {
79
cpu_env = temp_tcgv_ptr(ts);
65
+ case DISAS_STOP:
66
+ gen_save_pc(ctx->base.pc_next);
67
+ tcg_gen_lookup_and_goto_ptr();
68
+ break;
69
+ case DISAS_NEXT:
70
+ case DISAS_TOO_MANY:
71
+ save_cpu_state(ctx, 0);
72
+ gen_goto_tb(ctx, 0, ctx->base.pc_next);
73
+ break;
74
+ case DISAS_EXIT:
75
+ tcg_gen_exit_tb(NULL, 0);
76
+ break;
77
+ case DISAS_NORETURN:
78
+ break;
79
+ default:
80
+ g_assert_not_reached();
81
}
80
}
82
}
81
83
82
+void tcg_init(size_t tb_size, int splitwx)
83
+{
84
+ tcg_context_init();
85
+ tcg_region_init(tb_size, splitwx);
86
+}
87
+
88
/*
89
* Allocate TBs right before their corresponding translated code, making
90
* sure that TBs and code are on different cache lines.
91
--
84
--
92
2.25.1
85
2.25.1
93
86
94
87
diff view generated by jsdifflib
1
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
1
GDB single-stepping is now handled generically.
2
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
2
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
---
5
---
6
accel/tcg/tcg-all.c | 3 ++-
6
target/openrisc/translate.c | 18 +++---------------
7
1 file changed, 2 insertions(+), 1 deletion(-)
7
1 file changed, 3 insertions(+), 15 deletions(-)
8
8
9
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
9
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
10
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
11
--- a/accel/tcg/tcg-all.c
11
--- a/target/openrisc/translate.c
12
+++ b/accel/tcg/tcg-all.c
12
+++ b/target/openrisc/translate.c
13
@@ -XXX,XX +XXX,XX @@
13
@@ -XXX,XX +XXX,XX @@ static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
14
#include "qemu/error-report.h"
14
/* The jump destination is indirect/computed; use jmp_pc. */
15
#include "qemu/accel.h"
15
tcg_gen_mov_tl(cpu_pc, jmp_pc);
16
#include "qapi/qapi-builtin-visit.h"
16
tcg_gen_discard_tl(jmp_pc);
17
+#include "qemu/units.h"
17
- if (unlikely(dc->base.singlestep_enabled)) {
18
#include "internal.h"
18
- gen_exception(dc, EXCP_DEBUG);
19
19
- } else {
20
struct TCGState {
20
- tcg_gen_lookup_and_goto_ptr();
21
@@ -XXX,XX +XXX,XX @@ static int tcg_init_machine(MachineState *ms)
21
- }
22
22
+ tcg_gen_lookup_and_goto_ptr();
23
page_init();
23
break;
24
tb_htable_init();
24
}
25
- tcg_init(s->tb_size * 1024 * 1024, s->splitwx_enabled);
25
/* The jump destination is direct; use jmp_pc_imm.
26
+ tcg_init(s->tb_size * MiB, s->splitwx_enabled);
26
@@ -XXX,XX +XXX,XX @@ static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
27
27
break;
28
#if defined(CONFIG_SOFTMMU)
28
}
29
/*
29
tcg_gen_movi_tl(cpu_pc, jmp_dest);
30
- if (unlikely(dc->base.singlestep_enabled)) {
31
- gen_exception(dc, EXCP_DEBUG);
32
- } else {
33
- tcg_gen_lookup_and_goto_ptr();
34
- }
35
+ tcg_gen_lookup_and_goto_ptr();
36
break;
37
38
case DISAS_EXIT:
39
- if (unlikely(dc->base.singlestep_enabled)) {
40
- gen_exception(dc, EXCP_DEBUG);
41
- } else {
42
- tcg_gen_exit_tb(NULL, 0);
43
- }
44
+ tcg_gen_exit_tb(NULL, 0);
45
break;
46
default:
47
g_assert_not_reached();
30
--
48
--
31
2.25.1
49
2.25.1
32
50
33
51
diff view generated by jsdifflib
1
Do not handle protections on a case-by-case basis in the
1
GDB single-stepping is now handled generically.
2
various alloc_code_gen_buffer instances; do it within a
2
Reuse gen_debug_exception to handle architectural debug exceptions.
3
single loop in tcg_region_init.
4
3
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
5
---
9
tcg/region.c | 45 +++++++++++++++++++++++++++++++--------------
6
target/ppc/translate.c | 38 ++++++++------------------------------
10
1 file changed, 31 insertions(+), 14 deletions(-)
7
1 file changed, 8 insertions(+), 30 deletions(-)
11
8
12
diff --git a/tcg/region.c b/tcg/region.c
9
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
13
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
14
--- a/tcg/region.c
11
--- a/target/ppc/translate.c
15
+++ b/tcg/region.c
12
+++ b/target/ppc/translate.c
16
@@ -XXX,XX +XXX,XX @@ static int alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
13
@@ -XXX,XX +XXX,XX @@
14
15
#define CPU_SINGLE_STEP 0x1
16
#define CPU_BRANCH_STEP 0x2
17
-#define GDBSTUB_SINGLE_STEP 0x4
18
19
/* Include definitions for instructions classes and implementations flags */
20
/* #define PPC_DEBUG_DISAS */
21
@@ -XXX,XX +XXX,XX @@ static uint32_t gen_prep_dbgex(DisasContext *ctx)
22
23
static void gen_debug_exception(DisasContext *ctx)
24
{
25
- gen_helper_raise_exception(cpu_env, tcg_constant_i32(EXCP_DEBUG));
26
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(gen_prep_dbgex(ctx)));
27
ctx->base.is_jmp = DISAS_NORETURN;
28
}
29
30
@@ -XXX,XX +XXX,XX @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
31
32
static void gen_lookup_and_goto_ptr(DisasContext *ctx)
33
{
34
- int sse = ctx->singlestep_enabled;
35
- if (unlikely(sse)) {
36
- if (sse & GDBSTUB_SINGLE_STEP) {
37
- gen_debug_exception(ctx);
38
- } else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) {
39
- gen_helper_raise_exception(cpu_env, tcg_constant_i32(gen_prep_dbgex(ctx)));
40
- } else {
41
- tcg_gen_exit_tb(NULL, 0);
42
- }
43
+ if (unlikely(ctx->singlestep_enabled)) {
44
+ gen_debug_exception(ctx);
45
} else {
46
tcg_gen_lookup_and_goto_ptr();
17
}
47
}
18
#endif
48
@@ -XXX,XX +XXX,XX @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
19
49
ctx->singlestep_enabled = 0;
20
- if (qemu_mprotect_rwx(buf, size)) {
50
if ((hflags >> HFLAGS_SE) & 1) {
21
- error_setg_errno(errp, errno, "mprotect of jit buffer");
51
ctx->singlestep_enabled |= CPU_SINGLE_STEP;
22
- return false;
52
+ ctx->base.max_insns = 1;
53
}
54
if ((hflags >> HFLAGS_BE) & 1) {
55
ctx->singlestep_enabled |= CPU_BRANCH_STEP;
56
}
57
- if (unlikely(ctx->base.singlestep_enabled)) {
58
- ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP;
23
- }
59
- }
24
-
60
-
25
region.start_aligned = buf;
61
- if (ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP)) {
26
region.total_size = size;
62
- ctx->base.max_insns = 1;
27
63
- }
28
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
64
}
29
{
65
30
const size_t page_size = qemu_real_host_page_size;
66
static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs)
31
size_t region_size;
67
@@ -XXX,XX +XXX,XX @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
32
- size_t i;
68
DisasContext *ctx = container_of(dcbase, DisasContext, base);
33
- int have_prot;
69
DisasJumpType is_jmp = ctx->base.is_jmp;
34
+ int have_prot, need_prot;
70
target_ulong nip = ctx->base.pc_next;
35
71
- int sse;
36
/* Size the buffer. */
72
37
if (tb_size == 0) {
73
if (is_jmp == DISAS_NORETURN) {
38
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
74
/* We have already exited the TB. */
39
* Set guard pages in the rw buffer, as that's the one into which
75
@@ -XXX,XX +XXX,XX @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
40
* buffer overruns could occur. Do not set guard pages in the rx
41
* buffer -- let that one use hugepages throughout.
42
+ * Work with the page protections set up with the initial mapping.
43
*/
44
- for (i = 0; i < region.n; i++) {
45
+ need_prot = PAGE_READ | PAGE_WRITE;
46
+#ifndef CONFIG_TCG_INTERPRETER
47
+ if (tcg_splitwx_diff == 0) {
48
+ need_prot |= PAGE_EXEC;
49
+ }
50
+#endif
51
+ for (size_t i = 0, n = region.n; i < n; i++) {
52
void *start, *end;
53
54
tcg_region_bounds(i, &start, &end);
55
+ if (have_prot != need_prot) {
56
+ int rc;
57
58
- /*
59
- * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
60
- * rejects a permission change from RWX -> NONE. Guard pages are
61
- * nice for bug detection but are not essential; ignore any failure.
62
- */
63
- (void)qemu_mprotect_none(end, page_size);
64
+ if (need_prot == (PAGE_READ | PAGE_WRITE | PAGE_EXEC)) {
65
+ rc = qemu_mprotect_rwx(start, end - start);
66
+ } else if (need_prot == (PAGE_READ | PAGE_WRITE)) {
67
+ rc = qemu_mprotect_rw(start, end - start);
68
+ } else {
69
+ g_assert_not_reached();
70
+ }
71
+ if (rc) {
72
+ error_setg_errno(&error_fatal, errno,
73
+ "mprotect of jit buffer");
74
+ }
75
+ }
76
+ if (have_prot != 0) {
77
+ /*
78
+ * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
79
+ * rejects a permission change from RWX -> NONE. Guard pages are
80
+ * nice for bug detection but are not essential; ignore any failure.
81
+ */
82
+ (void)qemu_mprotect_none(end, page_size);
83
+ }
84
}
76
}
85
77
86
tcg_region_trees_init();
78
/* Honor single stepping. */
79
- sse = ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP);
80
- if (unlikely(sse)) {
81
+ if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP)
82
+ && (nip <= 0x100 || nip > 0xf00)) {
83
switch (is_jmp) {
84
case DISAS_TOO_MANY:
85
case DISAS_EXIT_UPDATE:
86
@@ -XXX,XX +XXX,XX @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
87
g_assert_not_reached();
88
}
89
90
- if (sse & GDBSTUB_SINGLE_STEP) {
91
- gen_debug_exception(ctx);
92
- return;
93
- }
94
- /* else CPU_SINGLE_STEP... */
95
- if (nip <= 0x100 || nip > 0xf00) {
96
- gen_helper_raise_exception(cpu_env, tcg_constant_i32(gen_prep_dbgex(ctx)));
97
- return;
98
- }
99
+ gen_debug_exception(ctx);
100
+ return;
101
}
102
103
switch (is_jmp) {
87
--
104
--
88
2.25.1
105
2.25.1
89
106
90
107
diff view generated by jsdifflib
1
Return output buffer and size via output pointer arguments,
1
We have already set DISAS_NORETURN in generate_exception,
2
rather than returning size via tcg_ctx->code_gen_buffer_size.
2
which makes the exit_tb unreachable.
3
3
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
4
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
6
---
8
tcg/region.c | 19 +++++++++----------
7
target/riscv/insn_trans/trans_privileged.c.inc | 6 +-----
9
1 file changed, 9 insertions(+), 10 deletions(-)
8
1 file changed, 1 insertion(+), 5 deletions(-)
10
9
11
diff --git a/tcg/region.c b/tcg/region.c
10
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
12
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
13
--- a/tcg/region.c
12
--- a/target/riscv/insn_trans/trans_privileged.c.inc
14
+++ b/tcg/region.c
13
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
15
@@ -XXX,XX +XXX,XX @@ static inline bool cross_256mb(void *addr, size_t size)
14
@@ -XXX,XX +XXX,XX @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
16
/*
17
* We weren't able to allocate a buffer without crossing that boundary,
18
* so make do with the larger portion of the buffer that doesn't cross.
19
- * Returns the new base of the buffer, and adjusts code_gen_buffer_size.
20
+ * Returns the new base and size of the buffer in *obuf and *osize.
21
*/
22
-static inline void *split_cross_256mb(void *buf1, size_t size1)
23
+static inline void split_cross_256mb(void **obuf, size_t *osize,
24
+ void *buf1, size_t size1)
25
{
15
{
26
void *buf2 = (void *)(((uintptr_t)buf1 + size1) & ~0x0ffffffful);
16
/* always generates U-level ECALL, fixed in do_interrupt handler */
27
size_t size2 = buf1 + size1 - buf2;
17
generate_exception(ctx, RISCV_EXCP_U_ECALL);
28
@@ -XXX,XX +XXX,XX @@ static inline void *split_cross_256mb(void *buf1, size_t size1)
18
- exit_tb(ctx); /* no chaining */
29
buf1 = buf2;
19
- ctx->base.is_jmp = DISAS_NORETURN;
30
}
31
32
- tcg_ctx->code_gen_buffer_size = size1;
33
- return buf1;
34
+ *obuf = buf1;
35
+ *osize = size1;
36
}
37
#endif
38
39
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
40
if (size > tb_size) {
41
size = QEMU_ALIGN_DOWN(tb_size, qemu_real_host_page_size);
42
}
43
- tcg_ctx->code_gen_buffer_size = size;
44
45
#ifdef __mips__
46
if (cross_256mb(buf, size)) {
47
- buf = split_cross_256mb(buf, size);
48
- size = tcg_ctx->code_gen_buffer_size;
49
+ split_cross_256mb(&buf, &size, buf, size);
50
}
51
#endif
52
53
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
54
qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
55
56
tcg_ctx->code_gen_buffer = buf;
57
+ tcg_ctx->code_gen_buffer_size = size;
58
return true;
20
return true;
59
}
21
}
60
#elif defined(_WIN32)
22
61
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_anon(size_t size, int prot,
23
@@ -XXX,XX +XXX,XX @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
62
"allocate %zu bytes for jit buffer", size);
24
post = opcode_at(&ctx->base, post_addr);
63
return false;
64
}
25
}
65
- tcg_ctx->code_gen_buffer_size = size;
26
66
27
- if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) {
67
#ifdef __mips__
28
+ if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) {
68
if (cross_256mb(buf, size)) {
29
generate_exception(ctx, RISCV_EXCP_SEMIHOST);
69
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_anon(size_t size, int prot,
30
} else {
70
/* fallthru */
31
generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
71
default:
32
}
72
/* Split the original buffer. Free the smaller half. */
33
- exit_tb(ctx); /* no chaining */
73
- buf2 = split_cross_256mb(buf, size);
34
- ctx->base.is_jmp = DISAS_NORETURN;
74
- size2 = tcg_ctx->code_gen_buffer_size;
75
+ split_cross_256mb(&buf2, &size2, buf, size);
76
if (buf == buf2) {
77
munmap(buf + size2, size - size2);
78
} else {
79
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_anon(size_t size, int prot,
80
qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
81
82
tcg_ctx->code_gen_buffer = buf;
83
+ tcg_ctx->code_gen_buffer_size = size;
84
return true;
35
return true;
85
}
36
}
86
37
87
--
38
--
88
2.25.1
39
2.25.1
89
40
90
41
diff view generated by jsdifflib
1
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
1
GDB single-stepping is now handled generically, which means
2
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
2
we don't need to do anything in the wrappers.
3
4
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
---
6
---
5
tcg/tcg-internal.h | 37 +++
7
target/riscv/translate.c | 27 +------------------
6
tcg/region.c | 572 +++++++++++++++++++++++++++++++++++++++++++++
8
.../riscv/insn_trans/trans_privileged.c.inc | 4 +--
7
tcg/tcg.c | 547 +------------------------------------------
9
target/riscv/insn_trans/trans_rvi.c.inc | 8 +++---
8
tcg/meson.build | 1 +
10
target/riscv/insn_trans/trans_rvv.c.inc | 2 +-
9
4 files changed, 613 insertions(+), 544 deletions(-)
11
4 files changed, 7 insertions(+), 34 deletions(-)
10
create mode 100644 tcg/tcg-internal.h
11
create mode 100644 tcg/region.c
12
12
13
diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h
13
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
14
new file mode 100644
15
index XXXXXXX..XXXXXXX
16
--- /dev/null
17
+++ b/tcg/tcg-internal.h
18
@@ -XXX,XX +XXX,XX @@
19
+/*
20
+ * Internal declarations for Tiny Code Generator for QEMU
21
+ *
22
+ * Copyright (c) 2008 Fabrice Bellard
23
+ *
24
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
25
+ * of this software and associated documentation files (the "Software"), to deal
26
+ * in the Software without restriction, including without limitation the rights
27
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28
+ * copies of the Software, and to permit persons to whom the Software is
29
+ * furnished to do so, subject to the following conditions:
30
+ *
31
+ * The above copyright notice and this permission notice shall be included in
32
+ * all copies or substantial portions of the Software.
33
+ *
34
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40
+ * THE SOFTWARE.
41
+ */
42
+
43
+#ifndef TCG_INTERNAL_H
44
+#define TCG_INTERNAL_H 1
45
+
46
+#define TCG_HIGHWATER 1024
47
+
48
+extern TCGContext **tcg_ctxs;
49
+extern unsigned int n_tcg_ctxs;
50
+
51
+bool tcg_region_alloc(TCGContext *s);
52
+void tcg_region_initial_alloc(TCGContext *s);
53
+void tcg_region_prologue_set(TCGContext *s);
54
+
55
+#endif /* TCG_INTERNAL_H */
56
diff --git a/tcg/region.c b/tcg/region.c
57
new file mode 100644
58
index XXXXXXX..XXXXXXX
59
--- /dev/null
60
+++ b/tcg/region.c
61
@@ -XXX,XX +XXX,XX @@
62
+/*
63
+ * Memory region management for Tiny Code Generator for QEMU
64
+ *
65
+ * Copyright (c) 2008 Fabrice Bellard
66
+ *
67
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
68
+ * of this software and associated documentation files (the "Software"), to deal
69
+ * in the Software without restriction, including without limitation the rights
70
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71
+ * copies of the Software, and to permit persons to whom the Software is
72
+ * furnished to do so, subject to the following conditions:
73
+ *
74
+ * The above copyright notice and this permission notice shall be included in
75
+ * all copies or substantial portions of the Software.
76
+ *
77
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
79
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
80
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
82
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
83
+ * THE SOFTWARE.
84
+ */
85
+
86
+#include "qemu/osdep.h"
87
+#include "exec/exec-all.h"
88
+#include "tcg/tcg.h"
89
+#if !defined(CONFIG_USER_ONLY)
90
+#include "hw/boards.h"
91
+#endif
92
+#include "tcg-internal.h"
93
+
94
+
95
+struct tcg_region_tree {
96
+ QemuMutex lock;
97
+ GTree *tree;
98
+ /* padding to avoid false sharing is computed at run-time */
99
+};
100
+
101
+/*
102
+ * We divide code_gen_buffer into equally-sized "regions" that TCG threads
103
+ * dynamically allocate from as demand dictates. Given appropriate region
104
+ * sizing, this minimizes flushes even when some TCG threads generate a lot
105
+ * more code than others.
106
+ */
107
+struct tcg_region_state {
108
+ QemuMutex lock;
109
+
110
+ /* fields set at init time */
111
+ void *start;
112
+ void *start_aligned;
113
+ void *end;
114
+ size_t n;
115
+ size_t size; /* size of one region */
116
+ size_t stride; /* .size + guard size */
117
+
118
+ /* fields protected by the lock */
119
+ size_t current; /* current region index */
120
+ size_t agg_size_full; /* aggregate size of full regions */
121
+};
122
+
123
+static struct tcg_region_state region;
124
+
125
+/*
126
+ * This is an array of struct tcg_region_tree's, with padding.
127
+ * We use void * to simplify the computation of region_trees[i]; each
128
+ * struct is found every tree_size bytes.
129
+ */
130
+static void *region_trees;
131
+static size_t tree_size;
132
+
133
+/* compare a pointer @ptr and a tb_tc @s */
134
+static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
135
+{
136
+ if (ptr >= s->ptr + s->size) {
137
+ return 1;
138
+ } else if (ptr < s->ptr) {
139
+ return -1;
140
+ }
141
+ return 0;
142
+}
143
+
144
+static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
145
+{
146
+ const struct tb_tc *a = ap;
147
+ const struct tb_tc *b = bp;
148
+
149
+ /*
150
+ * When both sizes are set, we know this isn't a lookup.
151
+ * This is the most likely case: every TB must be inserted; lookups
152
+ * are a lot less frequent.
153
+ */
154
+ if (likely(a->size && b->size)) {
155
+ if (a->ptr > b->ptr) {
156
+ return 1;
157
+ } else if (a->ptr < b->ptr) {
158
+ return -1;
159
+ }
160
+ /* a->ptr == b->ptr should happen only on deletions */
161
+ g_assert(a->size == b->size);
162
+ return 0;
163
+ }
164
+ /*
165
+ * All lookups have either .size field set to 0.
166
+ * From the glib sources we see that @ap is always the lookup key. However
167
+ * the docs provide no guarantee, so we just mark this case as likely.
168
+ */
169
+ if (likely(a->size == 0)) {
170
+ return ptr_cmp_tb_tc(a->ptr, b);
171
+ }
172
+ return ptr_cmp_tb_tc(b->ptr, a);
173
+}
174
+
175
+static void tcg_region_trees_init(void)
176
+{
177
+ size_t i;
178
+
179
+ tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
180
+ region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
181
+ for (i = 0; i < region.n; i++) {
182
+ struct tcg_region_tree *rt = region_trees + i * tree_size;
183
+
184
+ qemu_mutex_init(&rt->lock);
185
+ rt->tree = g_tree_new(tb_tc_cmp);
186
+ }
187
+}
188
+
189
+static struct tcg_region_tree *tc_ptr_to_region_tree(const void *p)
190
+{
191
+ size_t region_idx;
192
+
193
+ /*
194
+ * Like tcg_splitwx_to_rw, with no assert. The pc may come from
195
+ * a signal handler over which the caller has no control.
196
+ */
197
+ if (!in_code_gen_buffer(p)) {
198
+ p -= tcg_splitwx_diff;
199
+ if (!in_code_gen_buffer(p)) {
200
+ return NULL;
201
+ }
202
+ }
203
+
204
+ if (p < region.start_aligned) {
205
+ region_idx = 0;
206
+ } else {
207
+ ptrdiff_t offset = p - region.start_aligned;
208
+
209
+ if (offset > region.stride * (region.n - 1)) {
210
+ region_idx = region.n - 1;
211
+ } else {
212
+ region_idx = offset / region.stride;
213
+ }
214
+ }
215
+ return region_trees + region_idx * tree_size;
216
+}
217
+
218
+void tcg_tb_insert(TranslationBlock *tb)
219
+{
220
+ struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
221
+
222
+ g_assert(rt != NULL);
223
+ qemu_mutex_lock(&rt->lock);
224
+ g_tree_insert(rt->tree, &tb->tc, tb);
225
+ qemu_mutex_unlock(&rt->lock);
226
+}
227
+
228
+void tcg_tb_remove(TranslationBlock *tb)
229
+{
230
+ struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
231
+
232
+ g_assert(rt != NULL);
233
+ qemu_mutex_lock(&rt->lock);
234
+ g_tree_remove(rt->tree, &tb->tc);
235
+ qemu_mutex_unlock(&rt->lock);
236
+}
237
+
238
+/*
239
+ * Find the TB 'tb' such that
240
+ * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
241
+ * Return NULL if not found.
242
+ */
243
+TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
244
+{
245
+ struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
246
+ TranslationBlock *tb;
247
+ struct tb_tc s = { .ptr = (void *)tc_ptr };
248
+
249
+ if (rt == NULL) {
250
+ return NULL;
251
+ }
252
+
253
+ qemu_mutex_lock(&rt->lock);
254
+ tb = g_tree_lookup(rt->tree, &s);
255
+ qemu_mutex_unlock(&rt->lock);
256
+ return tb;
257
+}
258
+
259
+static void tcg_region_tree_lock_all(void)
260
+{
261
+ size_t i;
262
+
263
+ for (i = 0; i < region.n; i++) {
264
+ struct tcg_region_tree *rt = region_trees + i * tree_size;
265
+
266
+ qemu_mutex_lock(&rt->lock);
267
+ }
268
+}
269
+
270
+static void tcg_region_tree_unlock_all(void)
271
+{
272
+ size_t i;
273
+
274
+ for (i = 0; i < region.n; i++) {
275
+ struct tcg_region_tree *rt = region_trees + i * tree_size;
276
+
277
+ qemu_mutex_unlock(&rt->lock);
278
+ }
279
+}
280
+
281
+void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
282
+{
283
+ size_t i;
284
+
285
+ tcg_region_tree_lock_all();
286
+ for (i = 0; i < region.n; i++) {
287
+ struct tcg_region_tree *rt = region_trees + i * tree_size;
288
+
289
+ g_tree_foreach(rt->tree, func, user_data);
290
+ }
291
+ tcg_region_tree_unlock_all();
292
+}
293
+
294
+size_t tcg_nb_tbs(void)
295
+{
296
+ size_t nb_tbs = 0;
297
+ size_t i;
298
+
299
+ tcg_region_tree_lock_all();
300
+ for (i = 0; i < region.n; i++) {
301
+ struct tcg_region_tree *rt = region_trees + i * tree_size;
302
+
303
+ nb_tbs += g_tree_nnodes(rt->tree);
304
+ }
305
+ tcg_region_tree_unlock_all();
306
+ return nb_tbs;
307
+}
308
+
309
+static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
310
+{
311
+ TranslationBlock *tb = v;
312
+
313
+ tb_destroy(tb);
314
+ return FALSE;
315
+}
316
+
317
+static void tcg_region_tree_reset_all(void)
318
+{
319
+ size_t i;
320
+
321
+ tcg_region_tree_lock_all();
322
+ for (i = 0; i < region.n; i++) {
323
+ struct tcg_region_tree *rt = region_trees + i * tree_size;
324
+
325
+ g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
326
+ /* Increment the refcount first so that destroy acts as a reset */
327
+ g_tree_ref(rt->tree);
328
+ g_tree_destroy(rt->tree);
329
+ }
330
+ tcg_region_tree_unlock_all();
331
+}
332
+
333
+static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
334
+{
335
+ void *start, *end;
336
+
337
+ start = region.start_aligned + curr_region * region.stride;
338
+ end = start + region.size;
339
+
340
+ if (curr_region == 0) {
341
+ start = region.start;
342
+ }
343
+ if (curr_region == region.n - 1) {
344
+ end = region.end;
345
+ }
346
+
347
+ *pstart = start;
348
+ *pend = end;
349
+}
350
+
351
+static void tcg_region_assign(TCGContext *s, size_t curr_region)
352
+{
353
+ void *start, *end;
354
+
355
+ tcg_region_bounds(curr_region, &start, &end);
356
+
357
+ s->code_gen_buffer = start;
358
+ s->code_gen_ptr = start;
359
+ s->code_gen_buffer_size = end - start;
360
+ s->code_gen_highwater = end - TCG_HIGHWATER;
361
+}
362
+
363
+static bool tcg_region_alloc__locked(TCGContext *s)
364
+{
365
+ if (region.current == region.n) {
366
+ return true;
367
+ }
368
+ tcg_region_assign(s, region.current);
369
+ region.current++;
370
+ return false;
371
+}
372
+
373
+/*
374
+ * Request a new region once the one in use has filled up.
375
+ * Returns true on error.
376
+ */
377
+bool tcg_region_alloc(TCGContext *s)
378
+{
379
+ bool err;
380
+ /* read the region size now; alloc__locked will overwrite it on success */
381
+ size_t size_full = s->code_gen_buffer_size;
382
+
383
+ qemu_mutex_lock(&region.lock);
384
+ err = tcg_region_alloc__locked(s);
385
+ if (!err) {
386
+ region.agg_size_full += size_full - TCG_HIGHWATER;
387
+ }
388
+ qemu_mutex_unlock(&region.lock);
389
+ return err;
390
+}
391
+
392
+/*
393
+ * Perform a context's first region allocation.
394
+ * This function does _not_ increment region.agg_size_full.
395
+ */
396
+static void tcg_region_initial_alloc__locked(TCGContext *s)
397
+{
398
+ bool err = tcg_region_alloc__locked(s);
399
+ g_assert(!err);
400
+}
401
+
402
+void tcg_region_initial_alloc(TCGContext *s)
403
+{
404
+ qemu_mutex_lock(&region.lock);
405
+ tcg_region_initial_alloc__locked(s);
406
+ qemu_mutex_unlock(&region.lock);
407
+}
408
+
409
+/* Call from a safe-work context */
410
+void tcg_region_reset_all(void)
411
+{
412
+ unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
413
+ unsigned int i;
414
+
415
+ qemu_mutex_lock(&region.lock);
416
+ region.current = 0;
417
+ region.agg_size_full = 0;
418
+
419
+ for (i = 0; i < n_ctxs; i++) {
420
+ TCGContext *s = qatomic_read(&tcg_ctxs[i]);
421
+ tcg_region_initial_alloc__locked(s);
422
+ }
423
+ qemu_mutex_unlock(&region.lock);
424
+
425
+ tcg_region_tree_reset_all();
426
+}
427
+
428
+#ifdef CONFIG_USER_ONLY
429
+static size_t tcg_n_regions(void)
430
+{
431
+ return 1;
432
+}
433
+#else
434
+/*
435
+ * It is likely that some vCPUs will translate more code than others, so we
436
+ * first try to set more regions than max_cpus, with those regions being of
437
+ * reasonable size. If that's not possible we make do by evenly dividing
438
+ * the code_gen_buffer among the vCPUs.
439
+ */
440
+static size_t tcg_n_regions(void)
441
+{
442
+ size_t i;
443
+
444
+ /* Use a single region if all we have is one vCPU thread */
445
+#if !defined(CONFIG_USER_ONLY)
446
+ MachineState *ms = MACHINE(qdev_get_machine());
447
+ unsigned int max_cpus = ms->smp.max_cpus;
448
+#endif
449
+ if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
450
+ return 1;
451
+ }
452
+
453
+ /* Try to have more regions than max_cpus, with each region being >= 2 MB */
454
+ for (i = 8; i > 0; i--) {
455
+ size_t regions_per_thread = i;
456
+ size_t region_size;
457
+
458
+ region_size = tcg_init_ctx.code_gen_buffer_size;
459
+ region_size /= max_cpus * regions_per_thread;
460
+
461
+ if (region_size >= 2 * 1024u * 1024) {
462
+ return max_cpus * regions_per_thread;
463
+ }
464
+ }
465
+ /* If we can't, then just allocate one region per vCPU thread */
466
+ return max_cpus;
467
+}
468
+#endif
469
+
470
+/*
471
+ * Initializes region partitioning.
472
+ *
473
+ * Called at init time from the parent thread (i.e. the one calling
474
+ * tcg_context_init), after the target's TCG globals have been set.
475
+ *
476
+ * Region partitioning works by splitting code_gen_buffer into separate regions,
477
+ * and then assigning regions to TCG threads so that the threads can translate
478
+ * code in parallel without synchronization.
479
+ *
480
+ * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
481
+ * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
482
+ * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
483
+ * must have been parsed before calling this function, since it calls
484
+ * qemu_tcg_mttcg_enabled().
485
+ *
486
+ * In user-mode we use a single region. Having multiple regions in user-mode
487
+ * is not supported, because the number of vCPU threads (recall that each thread
488
+ * spawned by the guest corresponds to a vCPU thread) is only bounded by the
489
+ * OS, and usually this number is huge (tens of thousands is not uncommon).
490
+ * Thus, given this large bound on the number of vCPU threads and the fact
491
+ * that code_gen_buffer is allocated at compile-time, we cannot guarantee
492
+ * that the availability of at least one region per vCPU thread.
493
+ *
494
+ * However, this user-mode limitation is unlikely to be a significant problem
495
+ * in practice. Multi-threaded guests share most if not all of their translated
496
+ * code, which makes parallel code generation less appealing than in softmmu.
497
+ */
498
+void tcg_region_init(void)
499
+{
500
+ void *buf = tcg_init_ctx.code_gen_buffer;
501
+ void *aligned;
502
+ size_t size = tcg_init_ctx.code_gen_buffer_size;
503
+ size_t page_size = qemu_real_host_page_size;
504
+ size_t region_size;
505
+ size_t n_regions;
506
+ size_t i;
507
+
508
+ n_regions = tcg_n_regions();
509
+
510
+ /* The first region will be 'aligned - buf' bytes larger than the others */
511
+ aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
512
+ g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
513
+ /*
514
+ * Make region_size a multiple of page_size, using aligned as the start.
515
+ * As a result of this we might end up with a few extra pages at the end of
516
+ * the buffer; we will assign those to the last region.
517
+ */
518
+ region_size = (size - (aligned - buf)) / n_regions;
519
+ region_size = QEMU_ALIGN_DOWN(region_size, page_size);
520
+
521
+ /* A region must have at least 2 pages; one code, one guard */
522
+ g_assert(region_size >= 2 * page_size);
523
+
524
+ /* init the region struct */
525
+ qemu_mutex_init(&region.lock);
526
+ region.n = n_regions;
527
+ region.size = region_size - page_size;
528
+ region.stride = region_size;
529
+ region.start = buf;
530
+ region.start_aligned = aligned;
531
+ /* page-align the end, since its last page will be a guard page */
532
+ region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
533
+ /* account for that last guard page */
534
+ region.end -= page_size;
535
+
536
+ /*
537
+ * Set guard pages in the rw buffer, as that's the one into which
538
+ * buffer overruns could occur. Do not set guard pages in the rx
539
+ * buffer -- let that one use hugepages throughout.
540
+ */
541
+ for (i = 0; i < region.n; i++) {
542
+ void *start, *end;
543
+
544
+ tcg_region_bounds(i, &start, &end);
545
+
546
+ /*
547
+ * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
548
+ * rejects a permission change from RWX -> NONE. Guard pages are
549
+ * nice for bug detection but are not essential; ignore any failure.
550
+ */
551
+ (void)qemu_mprotect_none(end, page_size);
552
+ }
553
+
554
+ tcg_region_trees_init();
555
+
556
+ /*
557
+ * Leave the initial context initialized to the first region.
558
+ * This will be the context into which we generate the prologue.
559
+ * It is also the only context for CONFIG_USER_ONLY.
560
+ */
561
+ tcg_region_initial_alloc__locked(&tcg_init_ctx);
562
+}
563
+
564
+void tcg_region_prologue_set(TCGContext *s)
565
+{
566
+ /* Deduct the prologue from the first region. */
567
+ g_assert(region.start == s->code_gen_buffer);
568
+ region.start = s->code_ptr;
569
+
570
+ /* Recompute boundaries of the first region. */
571
+ tcg_region_assign(s, 0);
572
+
573
+ /* Register the balance of the buffer with gdb. */
574
+ tcg_register_jit(tcg_splitwx_to_rx(region.start),
575
+ region.end - region.start);
576
+}
577
+
578
+/*
579
+ * Returns the size (in bytes) of all translated code (i.e. from all regions)
580
+ * currently in the cache.
581
+ * See also: tcg_code_capacity()
582
+ * Do not confuse with tcg_current_code_size(); that one applies to a single
583
+ * TCG context.
584
+ */
585
+size_t tcg_code_size(void)
586
+{
587
+ unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
588
+ unsigned int i;
589
+ size_t total;
590
+
591
+ qemu_mutex_lock(&region.lock);
592
+ total = region.agg_size_full;
593
+ for (i = 0; i < n_ctxs; i++) {
594
+ const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
595
+ size_t size;
596
+
597
+ size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
598
+ g_assert(size <= s->code_gen_buffer_size);
599
+ total += size;
600
+ }
601
+ qemu_mutex_unlock(&region.lock);
602
+ return total;
603
+}
604
+
605
+/*
606
+ * Returns the code capacity (in bytes) of the entire cache, i.e. including all
607
+ * regions.
608
+ * See also: tcg_code_size()
609
+ */
610
+size_t tcg_code_capacity(void)
611
+{
612
+ size_t guard_size, capacity;
613
+
614
+ /* no need for synchronization; these variables are set at init time */
615
+ guard_size = region.stride - region.size;
616
+ capacity = region.end + guard_size - region.start;
617
+ capacity -= region.n * (guard_size + TCG_HIGHWATER);
618
+ return capacity;
619
+}
620
+
621
+size_t tcg_tb_phys_invalidate_count(void)
622
+{
623
+ unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
624
+ unsigned int i;
625
+ size_t total = 0;
626
+
627
+ for (i = 0; i < n_ctxs; i++) {
628
+ const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
629
+
630
+ total += qatomic_read(&s->tb_phys_invalidate_count);
631
+ }
632
+ return total;
633
+}
634
diff --git a/tcg/tcg.c b/tcg/tcg.c
635
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
636
--- a/tcg/tcg.c
15
--- a/target/riscv/translate.c
637
+++ b/tcg/tcg.c
16
+++ b/target/riscv/translate.c
638
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static void generate_exception_mtval(DisasContext *ctx, int excp)
639
18
ctx->base.is_jmp = DISAS_NORETURN;
640
#include "elf.h"
19
}
641
#include "exec/log.h"
20
642
+#include "tcg-internal.h"
21
-static void gen_exception_debug(void)
643
644
/* Forward declarations for functions declared in tcg-target.c.inc and
645
used here. */
646
@@ -XXX,XX +XXX,XX @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
647
static int tcg_out_ldst_finalize(TCGContext *s);
648
#endif
649
650
-#define TCG_HIGHWATER 1024
651
-
652
-static TCGContext **tcg_ctxs;
653
-static unsigned int n_tcg_ctxs;
654
+TCGContext **tcg_ctxs;
655
+unsigned int n_tcg_ctxs;
656
TCGv_env cpu_env = 0;
657
const void *tcg_code_gen_epilogue;
658
uintptr_t tcg_splitwx_diff;
659
@@ -XXX,XX +XXX,XX @@ uintptr_t tcg_splitwx_diff;
660
tcg_prologue_fn *tcg_qemu_tb_exec;
661
#endif
662
663
-struct tcg_region_tree {
664
- QemuMutex lock;
665
- GTree *tree;
666
- /* padding to avoid false sharing is computed at run-time */
667
-};
668
-
669
-/*
670
- * We divide code_gen_buffer into equally-sized "regions" that TCG threads
671
- * dynamically allocate from as demand dictates. Given appropriate region
672
- * sizing, this minimizes flushes even when some TCG threads generate a lot
673
- * more code than others.
674
- */
675
-struct tcg_region_state {
676
- QemuMutex lock;
677
-
678
- /* fields set at init time */
679
- void *start;
680
- void *start_aligned;
681
- void *end;
682
- size_t n;
683
- size_t size; /* size of one region */
684
- size_t stride; /* .size + guard size */
685
-
686
- /* fields protected by the lock */
687
- size_t current; /* current region index */
688
- size_t agg_size_full; /* aggregate size of full regions */
689
-};
690
-
691
-static struct tcg_region_state region;
692
-/*
693
- * This is an array of struct tcg_region_tree's, with padding.
694
- * We use void * to simplify the computation of region_trees[i]; each
695
- * struct is found every tree_size bytes.
696
- */
697
-static void *region_trees;
698
-static size_t tree_size;
699
static TCGRegSet tcg_target_available_regs[TCG_TYPE_COUNT];
700
static TCGRegSet tcg_target_call_clobber_regs;
701
702
@@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef constraint_sets[] = {
703
704
#include "tcg-target.c.inc"
705
706
-/* compare a pointer @ptr and a tb_tc @s */
707
-static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
708
-{
22
-{
709
- if (ptr >= s->ptr + s->size) {
23
- gen_helper_raise_exception(cpu_env, tcg_constant_i32(EXCP_DEBUG));
710
- return 1;
711
- } else if (ptr < s->ptr) {
712
- return -1;
713
- }
714
- return 0;
715
-}
24
-}
716
-
25
-
717
-static gint tb_tc_cmp(gconstpointer ap, gconstpointer bp)
26
-/* Wrapper around tcg_gen_exit_tb that handles single stepping */
27
-static void exit_tb(DisasContext *ctx)
718
-{
28
-{
719
- const struct tb_tc *a = ap;
29
- if (ctx->base.singlestep_enabled) {
720
- const struct tb_tc *b = bp;
30
- gen_exception_debug();
721
-
31
- } else {
722
- /*
32
- tcg_gen_exit_tb(NULL, 0);
723
- * When both sizes are set, we know this isn't a lookup.
724
- * This is the most likely case: every TB must be inserted; lookups
725
- * are a lot less frequent.
726
- */
727
- if (likely(a->size && b->size)) {
728
- if (a->ptr > b->ptr) {
729
- return 1;
730
- } else if (a->ptr < b->ptr) {
731
- return -1;
732
- }
733
- /* a->ptr == b->ptr should happen only on deletions */
734
- g_assert(a->size == b->size);
735
- return 0;
736
- }
737
- /*
738
- * All lookups have either .size field set to 0.
739
- * From the glib sources we see that @ap is always the lookup key. However
740
- * the docs provide no guarantee, so we just mark this case as likely.
741
- */
742
- if (likely(a->size == 0)) {
743
- return ptr_cmp_tb_tc(a->ptr, b);
744
- }
745
- return ptr_cmp_tb_tc(b->ptr, a);
746
-}
747
-
748
-static void tcg_region_trees_init(void)
749
-{
750
- size_t i;
751
-
752
- tree_size = ROUND_UP(sizeof(struct tcg_region_tree), qemu_dcache_linesize);
753
- region_trees = qemu_memalign(qemu_dcache_linesize, region.n * tree_size);
754
- for (i = 0; i < region.n; i++) {
755
- struct tcg_region_tree *rt = region_trees + i * tree_size;
756
-
757
- qemu_mutex_init(&rt->lock);
758
- rt->tree = g_tree_new(tb_tc_cmp);
759
- }
33
- }
760
-}
34
-}
761
-
35
-
762
-static struct tcg_region_tree *tc_ptr_to_region_tree(const void *p)
36
-/* Wrapper around tcg_gen_lookup_and_goto_ptr that handles single stepping */
37
-static void lookup_and_goto_ptr(DisasContext *ctx)
763
-{
38
-{
764
- size_t region_idx;
39
- if (ctx->base.singlestep_enabled) {
765
-
40
- gen_exception_debug();
766
- /*
767
- * Like tcg_splitwx_to_rw, with no assert. The pc may come from
768
- * a signal handler over which the caller has no control.
769
- */
770
- if (!in_code_gen_buffer(p)) {
771
- p -= tcg_splitwx_diff;
772
- if (!in_code_gen_buffer(p)) {
773
- return NULL;
774
- }
775
- }
776
-
777
- if (p < region.start_aligned) {
778
- region_idx = 0;
779
- } else {
41
- } else {
780
- ptrdiff_t offset = p - region.start_aligned;
42
- tcg_gen_lookup_and_goto_ptr();
781
-
782
- if (offset > region.stride * (region.n - 1)) {
783
- region_idx = region.n - 1;
784
- } else {
785
- region_idx = offset / region.stride;
786
- }
787
- }
788
- return region_trees + region_idx * tree_size;
789
-}
790
-
791
-void tcg_tb_insert(TranslationBlock *tb)
792
-{
793
- struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
794
-
795
- g_assert(rt != NULL);
796
- qemu_mutex_lock(&rt->lock);
797
- g_tree_insert(rt->tree, &tb->tc, tb);
798
- qemu_mutex_unlock(&rt->lock);
799
-}
800
-
801
-void tcg_tb_remove(TranslationBlock *tb)
802
-{
803
- struct tcg_region_tree *rt = tc_ptr_to_region_tree(tb->tc.ptr);
804
-
805
- g_assert(rt != NULL);
806
- qemu_mutex_lock(&rt->lock);
807
- g_tree_remove(rt->tree, &tb->tc);
808
- qemu_mutex_unlock(&rt->lock);
809
-}
810
-
811
-/*
812
- * Find the TB 'tb' such that
813
- * tb->tc.ptr <= tc_ptr < tb->tc.ptr + tb->tc.size
814
- * Return NULL if not found.
815
- */
816
-TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
817
-{
818
- struct tcg_region_tree *rt = tc_ptr_to_region_tree((void *)tc_ptr);
819
- TranslationBlock *tb;
820
- struct tb_tc s = { .ptr = (void *)tc_ptr };
821
-
822
- if (rt == NULL) {
823
- return NULL;
824
- }
825
-
826
- qemu_mutex_lock(&rt->lock);
827
- tb = g_tree_lookup(rt->tree, &s);
828
- qemu_mutex_unlock(&rt->lock);
829
- return tb;
830
-}
831
-
832
-static void tcg_region_tree_lock_all(void)
833
-{
834
- size_t i;
835
-
836
- for (i = 0; i < region.n; i++) {
837
- struct tcg_region_tree *rt = region_trees + i * tree_size;
838
-
839
- qemu_mutex_lock(&rt->lock);
840
- }
43
- }
841
-}
44
-}
842
-
45
-
843
-static void tcg_region_tree_unlock_all(void)
46
static void gen_exception_illegal(DisasContext *ctx)
844
-{
47
{
845
- size_t i;
48
generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
49
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
50
tcg_gen_exit_tb(ctx->base.tb, n);
51
} else {
52
tcg_gen_movi_tl(cpu_pc, dest);
53
- lookup_and_goto_ptr(ctx);
54
+ tcg_gen_lookup_and_goto_ptr();
55
}
56
}
57
58
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
59
index XXXXXXX..XXXXXXX 100644
60
--- a/target/riscv/insn_trans/trans_privileged.c.inc
61
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
62
@@ -XXX,XX +XXX,XX @@ static bool trans_sret(DisasContext *ctx, arg_sret *a)
63
64
if (has_ext(ctx, RVS)) {
65
gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
66
- exit_tb(ctx); /* no chaining */
67
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
68
ctx->base.is_jmp = DISAS_NORETURN;
69
} else {
70
return false;
71
@@ -XXX,XX +XXX,XX @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
72
#ifndef CONFIG_USER_ONLY
73
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
74
gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
75
- exit_tb(ctx); /* no chaining */
76
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
77
ctx->base.is_jmp = DISAS_NORETURN;
78
return true;
79
#else
80
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
81
index XXXXXXX..XXXXXXX 100644
82
--- a/target/riscv/insn_trans/trans_rvi.c.inc
83
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
84
@@ -XXX,XX +XXX,XX @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
85
if (a->rd != 0) {
86
tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
87
}
846
-
88
-
847
- for (i = 0; i < region.n; i++) {
89
- /* No chaining with JALR. */
848
- struct tcg_region_tree *rt = region_trees + i * tree_size;
90
- lookup_and_goto_ptr(ctx);
849
-
91
+ tcg_gen_lookup_and_goto_ptr();
850
- qemu_mutex_unlock(&rt->lock);
92
851
- }
93
if (misaligned) {
852
-}
94
gen_set_label(misaligned);
853
-
95
@@ -XXX,XX +XXX,XX @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
854
-void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
96
* however we need to end the translation block
855
-{
97
*/
856
- size_t i;
98
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
857
-
99
- exit_tb(ctx);
858
- tcg_region_tree_lock_all();
100
+ tcg_gen_exit_tb(NULL, 0);
859
- for (i = 0; i < region.n; i++) {
101
ctx->base.is_jmp = DISAS_NORETURN;
860
- struct tcg_region_tree *rt = region_trees + i * tree_size;
102
return true;
861
-
103
}
862
- g_tree_foreach(rt->tree, func, user_data);
104
@@ -XXX,XX +XXX,XX @@ static bool do_csr_post(DisasContext *ctx)
863
- }
864
- tcg_region_tree_unlock_all();
865
-}
866
-
867
-size_t tcg_nb_tbs(void)
868
-{
869
- size_t nb_tbs = 0;
870
- size_t i;
871
-
872
- tcg_region_tree_lock_all();
873
- for (i = 0; i < region.n; i++) {
874
- struct tcg_region_tree *rt = region_trees + i * tree_size;
875
-
876
- nb_tbs += g_tree_nnodes(rt->tree);
877
- }
878
- tcg_region_tree_unlock_all();
879
- return nb_tbs;
880
-}
881
-
882
-static gboolean tcg_region_tree_traverse(gpointer k, gpointer v, gpointer data)
883
-{
884
- TranslationBlock *tb = v;
885
-
886
- tb_destroy(tb);
887
- return FALSE;
888
-}
889
-
890
-static void tcg_region_tree_reset_all(void)
891
-{
892
- size_t i;
893
-
894
- tcg_region_tree_lock_all();
895
- for (i = 0; i < region.n; i++) {
896
- struct tcg_region_tree *rt = region_trees + i * tree_size;
897
-
898
- g_tree_foreach(rt->tree, tcg_region_tree_traverse, NULL);
899
- /* Increment the refcount first so that destroy acts as a reset */
900
- g_tree_ref(rt->tree);
901
- g_tree_destroy(rt->tree);
902
- }
903
- tcg_region_tree_unlock_all();
904
-}
905
-
906
-static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
907
-{
908
- void *start, *end;
909
-
910
- start = region.start_aligned + curr_region * region.stride;
911
- end = start + region.size;
912
-
913
- if (curr_region == 0) {
914
- start = region.start;
915
- }
916
- if (curr_region == region.n - 1) {
917
- end = region.end;
918
- }
919
-
920
- *pstart = start;
921
- *pend = end;
922
-}
923
-
924
-static void tcg_region_assign(TCGContext *s, size_t curr_region)
925
-{
926
- void *start, *end;
927
-
928
- tcg_region_bounds(curr_region, &start, &end);
929
-
930
- s->code_gen_buffer = start;
931
- s->code_gen_ptr = start;
932
- s->code_gen_buffer_size = end - start;
933
- s->code_gen_highwater = end - TCG_HIGHWATER;
934
-}
935
-
936
-static bool tcg_region_alloc__locked(TCGContext *s)
937
-{
938
- if (region.current == region.n) {
939
- return true;
940
- }
941
- tcg_region_assign(s, region.current);
942
- region.current++;
943
- return false;
944
-}
945
-
946
-/*
947
- * Request a new region once the one in use has filled up.
948
- * Returns true on error.
949
- */
950
-static bool tcg_region_alloc(TCGContext *s)
951
-{
952
- bool err;
953
- /* read the region size now; alloc__locked will overwrite it on success */
954
- size_t size_full = s->code_gen_buffer_size;
955
-
956
- qemu_mutex_lock(&region.lock);
957
- err = tcg_region_alloc__locked(s);
958
- if (!err) {
959
- region.agg_size_full += size_full - TCG_HIGHWATER;
960
- }
961
- qemu_mutex_unlock(&region.lock);
962
- return err;
963
-}
964
-
965
-/*
966
- * Perform a context's first region allocation.
967
- * This function does _not_ increment region.agg_size_full.
968
- */
969
-static void tcg_region_initial_alloc__locked(TCGContext *s)
970
-{
971
- bool err = tcg_region_alloc__locked(s);
972
- g_assert(!err);
973
-}
974
-
975
-#ifndef CONFIG_USER_ONLY
976
-static void tcg_region_initial_alloc(TCGContext *s)
977
-{
978
- qemu_mutex_lock(&region.lock);
979
- tcg_region_initial_alloc__locked(s);
980
- qemu_mutex_unlock(&region.lock);
981
-}
982
-#endif
983
-
984
-/* Call from a safe-work context */
985
-void tcg_region_reset_all(void)
986
-{
987
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
988
- unsigned int i;
989
-
990
- qemu_mutex_lock(&region.lock);
991
- region.current = 0;
992
- region.agg_size_full = 0;
993
-
994
- for (i = 0; i < n_ctxs; i++) {
995
- TCGContext *s = qatomic_read(&tcg_ctxs[i]);
996
- tcg_region_initial_alloc__locked(s);
997
- }
998
- qemu_mutex_unlock(&region.lock);
999
-
1000
- tcg_region_tree_reset_all();
1001
-}
1002
-
1003
-#ifdef CONFIG_USER_ONLY
1004
-static size_t tcg_n_regions(void)
1005
-{
1006
- return 1;
1007
-}
1008
-#else
1009
-/*
1010
- * It is likely that some vCPUs will translate more code than others, so we
1011
- * first try to set more regions than max_cpus, with those regions being of
1012
- * reasonable size. If that's not possible we make do by evenly dividing
1013
- * the code_gen_buffer among the vCPUs.
1014
- */
1015
-static size_t tcg_n_regions(void)
1016
-{
1017
- size_t i;
1018
-
1019
- /* Use a single region if all we have is one vCPU thread */
1020
-#if !defined(CONFIG_USER_ONLY)
1021
- MachineState *ms = MACHINE(qdev_get_machine());
1022
- unsigned int max_cpus = ms->smp.max_cpus;
1023
-#endif
1024
- if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) {
1025
- return 1;
1026
- }
1027
-
1028
- /* Try to have more regions than max_cpus, with each region being >= 2 MB */
1029
- for (i = 8; i > 0; i--) {
1030
- size_t regions_per_thread = i;
1031
- size_t region_size;
1032
-
1033
- region_size = tcg_init_ctx.code_gen_buffer_size;
1034
- region_size /= max_cpus * regions_per_thread;
1035
-
1036
- if (region_size >= 2 * 1024u * 1024) {
1037
- return max_cpus * regions_per_thread;
1038
- }
1039
- }
1040
- /* If we can't, then just allocate one region per vCPU thread */
1041
- return max_cpus;
1042
-}
1043
-#endif
1044
-
1045
-/*
1046
- * Initializes region partitioning.
1047
- *
1048
- * Called at init time from the parent thread (i.e. the one calling
1049
- * tcg_context_init), after the target's TCG globals have been set.
1050
- *
1051
- * Region partitioning works by splitting code_gen_buffer into separate regions,
1052
- * and then assigning regions to TCG threads so that the threads can translate
1053
- * code in parallel without synchronization.
1054
- *
1055
- * In softmmu the number of TCG threads is bounded by max_cpus, so we use at
1056
- * least max_cpus regions in MTTCG. In !MTTCG we use a single region.
1057
- * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...])
1058
- * must have been parsed before calling this function, since it calls
1059
- * qemu_tcg_mttcg_enabled().
1060
- *
1061
- * In user-mode we use a single region. Having multiple regions in user-mode
1062
- * is not supported, because the number of vCPU threads (recall that each thread
1063
- * spawned by the guest corresponds to a vCPU thread) is only bounded by the
1064
- * OS, and usually this number is huge (tens of thousands is not uncommon).
1065
- * Thus, given this large bound on the number of vCPU threads and the fact
1066
- * that code_gen_buffer is allocated at compile-time, we cannot guarantee
1067
- * that the availability of at least one region per vCPU thread.
1068
- *
1069
- * However, this user-mode limitation is unlikely to be a significant problem
1070
- * in practice. Multi-threaded guests share most if not all of their translated
1071
- * code, which makes parallel code generation less appealing than in softmmu.
1072
- */
1073
-void tcg_region_init(void)
1074
-{
1075
- void *buf = tcg_init_ctx.code_gen_buffer;
1076
- void *aligned;
1077
- size_t size = tcg_init_ctx.code_gen_buffer_size;
1078
- size_t page_size = qemu_real_host_page_size;
1079
- size_t region_size;
1080
- size_t n_regions;
1081
- size_t i;
1082
-
1083
- n_regions = tcg_n_regions();
1084
-
1085
- /* The first region will be 'aligned - buf' bytes larger than the others */
1086
- aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
1087
- g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
1088
- /*
1089
- * Make region_size a multiple of page_size, using aligned as the start.
1090
- * As a result of this we might end up with a few extra pages at the end of
1091
- * the buffer; we will assign those to the last region.
1092
- */
1093
- region_size = (size - (aligned - buf)) / n_regions;
1094
- region_size = QEMU_ALIGN_DOWN(region_size, page_size);
1095
-
1096
- /* A region must have at least 2 pages; one code, one guard */
1097
- g_assert(region_size >= 2 * page_size);
1098
-
1099
- /* init the region struct */
1100
- qemu_mutex_init(&region.lock);
1101
- region.n = n_regions;
1102
- region.size = region_size - page_size;
1103
- region.stride = region_size;
1104
- region.start = buf;
1105
- region.start_aligned = aligned;
1106
- /* page-align the end, since its last page will be a guard page */
1107
- region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
1108
- /* account for that last guard page */
1109
- region.end -= page_size;
1110
-
1111
- /*
1112
- * Set guard pages in the rw buffer, as that's the one into which
1113
- * buffer overruns could occur. Do not set guard pages in the rx
1114
- * buffer -- let that one use hugepages throughout.
1115
- */
1116
- for (i = 0; i < region.n; i++) {
1117
- void *start, *end;
1118
-
1119
- tcg_region_bounds(i, &start, &end);
1120
-
1121
- /*
1122
- * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect
1123
- * rejects a permission change from RWX -> NONE. Guard pages are
1124
- * nice for bug detection but are not essential; ignore any failure.
1125
- */
1126
- (void)qemu_mprotect_none(end, page_size);
1127
- }
1128
-
1129
- tcg_region_trees_init();
1130
-
1131
- /*
1132
- * Leave the initial context initialized to the first region.
1133
- * This will be the context into which we generate the prologue.
1134
- * It is also the only context for CONFIG_USER_ONLY.
1135
- */
1136
- tcg_region_initial_alloc__locked(&tcg_init_ctx);
1137
-}
1138
-
1139
-static void tcg_region_prologue_set(TCGContext *s)
1140
-{
1141
- /* Deduct the prologue from the first region. */
1142
- g_assert(region.start == s->code_gen_buffer);
1143
- region.start = s->code_ptr;
1144
-
1145
- /* Recompute boundaries of the first region. */
1146
- tcg_region_assign(s, 0);
1147
-
1148
- /* Register the balance of the buffer with gdb. */
1149
- tcg_register_jit(tcg_splitwx_to_rx(region.start),
1150
- region.end - region.start);
1151
-}
1152
-
1153
#ifdef CONFIG_DEBUG_TCG
1154
const void *tcg_splitwx_to_rx(void *rw)
1155
{
105
{
1156
@@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void)
106
/* We may have changed important cpu state -- exit to main loop. */
107
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
108
- exit_tb(ctx);
109
+ tcg_gen_exit_tb(NULL, 0);
110
ctx->base.is_jmp = DISAS_NORETURN;
111
return true;
1157
}
112
}
1158
#endif /* !CONFIG_USER_ONLY */
113
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
1159
1160
-/*
1161
- * Returns the size (in bytes) of all translated code (i.e. from all regions)
1162
- * currently in the cache.
1163
- * See also: tcg_code_capacity()
1164
- * Do not confuse with tcg_current_code_size(); that one applies to a single
1165
- * TCG context.
1166
- */
1167
-size_t tcg_code_size(void)
1168
-{
1169
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
1170
- unsigned int i;
1171
- size_t total;
1172
-
1173
- qemu_mutex_lock(&region.lock);
1174
- total = region.agg_size_full;
1175
- for (i = 0; i < n_ctxs; i++) {
1176
- const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
1177
- size_t size;
1178
-
1179
- size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer;
1180
- g_assert(size <= s->code_gen_buffer_size);
1181
- total += size;
1182
- }
1183
- qemu_mutex_unlock(&region.lock);
1184
- return total;
1185
-}
1186
-
1187
-/*
1188
- * Returns the code capacity (in bytes) of the entire cache, i.e. including all
1189
- * regions.
1190
- * See also: tcg_code_size()
1191
- */
1192
-size_t tcg_code_capacity(void)
1193
-{
1194
- size_t guard_size, capacity;
1195
-
1196
- /* no need for synchronization; these variables are set at init time */
1197
- guard_size = region.stride - region.size;
1198
- capacity = region.end + guard_size - region.start;
1199
- capacity -= region.n * (guard_size + TCG_HIGHWATER);
1200
- return capacity;
1201
-}
1202
-
1203
-size_t tcg_tb_phys_invalidate_count(void)
1204
-{
1205
- unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs);
1206
- unsigned int i;
1207
- size_t total = 0;
1208
-
1209
- for (i = 0; i < n_ctxs; i++) {
1210
- const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
1211
-
1212
- total += qatomic_read(&s->tb_phys_invalidate_count);
1213
- }
1214
- return total;
1215
-}
1216
-
1217
/* pool based memory allocation */
1218
void *tcg_malloc_internal(TCGContext *s, int size)
1219
{
1220
diff --git a/tcg/meson.build b/tcg/meson.build
1221
index XXXXXXX..XXXXXXX 100644
114
index XXXXXXX..XXXXXXX 100644
1222
--- a/tcg/meson.build
115
--- a/target/riscv/insn_trans/trans_rvv.c.inc
1223
+++ b/tcg/meson.build
116
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
1224
@@ -XXX,XX +XXX,XX @@ tcg_ss = ss.source_set()
117
@@ -XXX,XX +XXX,XX @@ static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a)
1225
118
gen_set_gpr(ctx, a->rd, dst);
1226
tcg_ss.add(files(
119
1227
'optimize.c',
120
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
1228
+ 'region.c',
121
- lookup_and_goto_ptr(ctx);
1229
'tcg.c',
122
+ tcg_gen_lookup_and_goto_ptr();
1230
'tcg-common.c',
123
ctx->base.is_jmp = DISAS_NORETURN;
1231
'tcg-op.c',
124
return true;
125
}
1232
--
126
--
1233
2.25.1
127
2.25.1
1234
128
1235
129
diff view generated by jsdifflib
1
For --enable-tcg-interpreter on Windows, we will need this.
1
GDB single-stepping is now handled generically.
2
2
3
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
5
---
8
include/qemu/osdep.h | 1 +
6
target/rx/helper.h | 1 -
9
util/osdep.c | 9 +++++++++
7
target/rx/op_helper.c | 8 --------
10
2 files changed, 10 insertions(+)
8
target/rx/translate.c | 12 ++----------
9
3 files changed, 2 insertions(+), 19 deletions(-)
11
10
12
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
11
diff --git a/target/rx/helper.h b/target/rx/helper.h
13
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
14
--- a/include/qemu/osdep.h
13
--- a/target/rx/helper.h
15
+++ b/include/qemu/osdep.h
14
+++ b/target/rx/helper.h
16
@@ -XXX,XX +XXX,XX @@ void sigaction_invoke(struct sigaction *action,
15
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_1(raise_illegal_instruction, noreturn, env)
17
#endif
16
DEF_HELPER_1(raise_access_fault, noreturn, env)
18
17
DEF_HELPER_1(raise_privilege_violation, noreturn, env)
19
int qemu_madvise(void *addr, size_t len, int advice);
18
DEF_HELPER_1(wait, noreturn, env)
20
+int qemu_mprotect_rw(void *addr, size_t size);
19
-DEF_HELPER_1(debug, noreturn, env)
21
int qemu_mprotect_rwx(void *addr, size_t size);
20
DEF_HELPER_2(rxint, noreturn, env, i32)
22
int qemu_mprotect_none(void *addr, size_t size);
21
DEF_HELPER_1(rxbrk, noreturn, env)
23
22
DEF_HELPER_FLAGS_3(fadd, TCG_CALL_NO_WG, f32, env, f32, f32)
24
diff --git a/util/osdep.c b/util/osdep.c
23
diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c
25
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
26
--- a/util/osdep.c
25
--- a/target/rx/op_helper.c
27
+++ b/util/osdep.c
26
+++ b/target/rx/op_helper.c
28
@@ -XXX,XX +XXX,XX @@ static int qemu_mprotect__osdep(void *addr, size_t size, int prot)
27
@@ -XXX,XX +XXX,XX @@ void QEMU_NORETURN helper_wait(CPURXState *env)
29
#endif
28
raise_exception(env, EXCP_HLT, 0);
30
}
29
}
31
30
32
+int qemu_mprotect_rw(void *addr, size_t size)
31
-void QEMU_NORETURN helper_debug(CPURXState *env)
33
+{
32
-{
34
+#ifdef _WIN32
33
- CPUState *cs = env_cpu(env);
35
+ return qemu_mprotect__osdep(addr, size, PAGE_READWRITE);
34
-
36
+#else
35
- cs->exception_index = EXCP_DEBUG;
37
+ return qemu_mprotect__osdep(addr, size, PROT_READ | PROT_WRITE);
36
- cpu_loop_exit(cs);
38
+#endif
37
-}
39
+}
38
-
40
+
39
void QEMU_NORETURN helper_rxint(CPURXState *env, uint32_t vec)
41
int qemu_mprotect_rwx(void *addr, size_t size)
42
{
40
{
43
#ifdef _WIN32
41
raise_exception(env, 0x100 + vec, 0);
42
diff --git a/target/rx/translate.c b/target/rx/translate.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/target/rx/translate.c
45
+++ b/target/rx/translate.c
46
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
47
tcg_gen_exit_tb(dc->base.tb, n);
48
} else {
49
tcg_gen_movi_i32(cpu_pc, dest);
50
- if (dc->base.singlestep_enabled) {
51
- gen_helper_debug(cpu_env);
52
- } else {
53
- tcg_gen_lookup_and_goto_ptr();
54
- }
55
+ tcg_gen_lookup_and_goto_ptr();
56
}
57
dc->base.is_jmp = DISAS_NORETURN;
58
}
59
@@ -XXX,XX +XXX,XX @@ static void rx_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
60
gen_goto_tb(ctx, 0, dcbase->pc_next);
61
break;
62
case DISAS_JUMP:
63
- if (ctx->base.singlestep_enabled) {
64
- gen_helper_debug(cpu_env);
65
- } else {
66
- tcg_gen_lookup_and_goto_ptr();
67
- }
68
+ tcg_gen_lookup_and_goto_ptr();
69
break;
70
case DISAS_UPDATE:
71
tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
44
--
72
--
45
2.25.1
73
2.25.1
46
74
47
75
diff view generated by jsdifflib
1
These variables belong to the jit side, not the user side.
1
GDB single-stepping is now handled generically.
2
2
3
Since tcg_init_ctx is no longer used outside of tcg/, move
4
the declaration to tcg-internal.h.
5
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
8
Suggested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
---
4
---
11
include/tcg/tcg.h | 1 -
5
target/s390x/tcg/translate.c | 8 ++------
12
tcg/tcg-internal.h | 1 +
6
1 file changed, 2 insertions(+), 6 deletions(-)
13
accel/tcg/translate-all.c | 3 ---
14
tcg/tcg.c | 3 +++
15
4 files changed, 4 insertions(+), 4 deletions(-)
16
7
17
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
8
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
18
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
19
--- a/include/tcg/tcg.h
10
--- a/target/s390x/tcg/translate.c
20
+++ b/include/tcg/tcg.h
11
+++ b/target/s390x/tcg/translate.c
21
@@ -XXX,XX +XXX,XX @@ static inline bool temp_readonly(TCGTemp *ts)
12
@@ -XXX,XX +XXX,XX @@ struct DisasContext {
22
return ts->kind >= TEMP_FIXED;
13
uint64_t pc_tmp;
14
uint32_t ilen;
15
enum cc_op cc_op;
16
- bool do_debug;
17
};
18
19
/* Information carried about a condition to be evaluated. */
20
@@ -XXX,XX +XXX,XX @@ static void s390x_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
21
22
dc->cc_op = CC_OP_DYNAMIC;
23
dc->ex_value = dc->base.tb->cs_base;
24
- dc->do_debug = dc->base.singlestep_enabled;
23
}
25
}
24
26
25
-extern TCGContext tcg_init_ctx;
27
static void s390x_tr_tb_start(DisasContextBase *db, CPUState *cs)
26
extern __thread TCGContext *tcg_ctx;
28
@@ -XXX,XX +XXX,XX @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
27
extern const void *tcg_code_gen_epilogue;
29
/* FALLTHRU */
28
extern uintptr_t tcg_splitwx_diff;
30
case DISAS_PC_CC_UPDATED:
29
diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h
31
/* Exit the TB, either by raising a debug exception or by return. */
30
index XXXXXXX..XXXXXXX 100644
32
- if (dc->do_debug) {
31
--- a/tcg/tcg-internal.h
33
- gen_exception(EXCP_DEBUG);
32
+++ b/tcg/tcg-internal.h
34
- } else if ((dc->base.tb->flags & FLAG_MASK_PER) ||
33
@@ -XXX,XX +XXX,XX @@
35
- dc->base.is_jmp == DISAS_PC_STALE_NOCHAIN) {
34
36
+ if ((dc->base.tb->flags & FLAG_MASK_PER) ||
35
#define TCG_HIGHWATER 1024
37
+ dc->base.is_jmp == DISAS_PC_STALE_NOCHAIN) {
36
38
tcg_gen_exit_tb(NULL, 0);
37
+extern TCGContext tcg_init_ctx;
39
} else {
38
extern TCGContext **tcg_ctxs;
40
tcg_gen_lookup_and_goto_ptr();
39
extern unsigned int tcg_cur_ctxs;
40
extern unsigned int tcg_max_ctxs;
41
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/accel/tcg/translate-all.c
44
+++ b/accel/tcg/translate-all.c
45
@@ -XXX,XX +XXX,XX @@ static int v_l2_levels;
46
47
static void *l1_map[V_L1_MAX_SIZE];
48
49
-/* code generation context */
50
-TCGContext tcg_init_ctx;
51
-__thread TCGContext *tcg_ctx;
52
TBContext tb_ctx;
53
54
static void page_table_config_init(void)
55
diff --git a/tcg/tcg.c b/tcg/tcg.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/tcg/tcg.c
58
+++ b/tcg/tcg.c
59
@@ -XXX,XX +XXX,XX @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct);
60
static int tcg_out_ldst_finalize(TCGContext *s);
61
#endif
62
63
+TCGContext tcg_init_ctx;
64
+__thread TCGContext *tcg_ctx;
65
+
66
TCGContext **tcg_ctxs;
67
unsigned int tcg_cur_ctxs;
68
unsigned int tcg_max_ctxs;
69
--
41
--
70
2.25.1
42
2.25.1
71
43
72
44
diff view generated by jsdifflib
1
There is only one caller, and shortly we will need access
1
GDB single-stepping is now handled generically.
2
to the MachineState, which tcg_init_machine already has.
3
2
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
5
---
8
accel/tcg/internal.h | 2 ++
6
target/sh4/helper.h | 1 -
9
include/sysemu/tcg.h | 2 --
7
target/sh4/op_helper.c | 5 -----
10
accel/tcg/tcg-all.c | 16 +++++++++++++++-
8
target/sh4/translate.c | 14 +++-----------
11
accel/tcg/translate-all.c | 21 ++-------------------
9
3 files changed, 3 insertions(+), 17 deletions(-)
12
bsd-user/main.c | 2 +-
13
5 files changed, 20 insertions(+), 23 deletions(-)
14
10
15
diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h
11
diff --git a/target/sh4/helper.h b/target/sh4/helper.h
16
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
17
--- a/accel/tcg/internal.h
13
--- a/target/sh4/helper.h
18
+++ b/accel/tcg/internal.h
14
+++ b/target/sh4/helper.h
19
@@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc,
15
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_1(raise_illegal_instruction, noreturn, env)
20
int cflags);
16
DEF_HELPER_1(raise_slot_illegal_instruction, noreturn, env)
21
17
DEF_HELPER_1(raise_fpu_disable, noreturn, env)
22
void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
18
DEF_HELPER_1(raise_slot_fpu_disable, noreturn, env)
23
+void page_init(void);
19
-DEF_HELPER_1(debug, noreturn, env)
24
+void tb_htable_init(void);
20
DEF_HELPER_1(sleep, noreturn, env)
25
21
DEF_HELPER_2(trapa, noreturn, env, i32)
26
#endif /* ACCEL_TCG_INTERNAL_H */
22
DEF_HELPER_1(exclusive, noreturn, env)
27
diff --git a/include/sysemu/tcg.h b/include/sysemu/tcg.h
23
diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c
28
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
29
--- a/include/sysemu/tcg.h
25
--- a/target/sh4/op_helper.c
30
+++ b/include/sysemu/tcg.h
26
+++ b/target/sh4/op_helper.c
31
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@ void helper_raise_slot_fpu_disable(CPUSH4State *env)
32
#ifndef SYSEMU_TCG_H
28
raise_exception(env, 0x820, 0);
33
#define SYSEMU_TCG_H
34
35
-void tcg_exec_init(unsigned long tb_size, int splitwx);
36
-
37
#ifdef CONFIG_TCG
38
extern bool tcg_allowed;
39
#define tcg_enabled() (tcg_allowed)
40
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/accel/tcg/tcg-all.c
43
+++ b/accel/tcg/tcg-all.c
44
@@ -XXX,XX +XXX,XX @@
45
#include "qemu/error-report.h"
46
#include "qemu/accel.h"
47
#include "qapi/qapi-builtin-visit.h"
48
+#include "internal.h"
49
50
struct TCGState {
51
AccelState parent_obj;
52
@@ -XXX,XX +XXX,XX @@ static int tcg_init_machine(MachineState *ms)
53
{
54
TCGState *s = TCG_STATE(current_accel());
55
56
- tcg_exec_init(s->tb_size * 1024 * 1024, s->splitwx_enabled);
57
+ tcg_allowed = true;
58
mttcg_enabled = s->mttcg_enabled;
59
+
60
+ page_init();
61
+ tb_htable_init();
62
+ tcg_init(s->tb_size * 1024 * 1024, s->splitwx_enabled);
63
+
64
+#if defined(CONFIG_SOFTMMU)
65
+ /*
66
+ * There's no guest base to take into account, so go ahead and
67
+ * initialize the prologue now.
68
+ */
69
+ tcg_prologue_init(tcg_ctx);
70
+#endif
71
+
72
return 0;
73
}
29
}
74
30
75
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
31
-void helper_debug(CPUSH4State *env)
76
index XXXXXXX..XXXXXXX 100644
77
--- a/accel/tcg/translate-all.c
78
+++ b/accel/tcg/translate-all.c
79
@@ -XXX,XX +XXX,XX @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
80
return false;
81
}
82
83
-static void page_init(void)
84
+void page_init(void)
85
{
86
page_size_init();
87
page_table_config_init();
88
@@ -XXX,XX +XXX,XX @@ static bool tb_cmp(const void *ap, const void *bp)
89
a->page_addr[1] == b->page_addr[1];
90
}
91
92
-static void tb_htable_init(void)
93
+void tb_htable_init(void)
94
{
95
unsigned int mode = QHT_MODE_AUTO_RESIZE;
96
97
qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);
98
}
99
100
-/* Must be called before using the QEMU cpus. 'tb_size' is the size
101
- (in bytes) allocated to the translation buffer. Zero means default
102
- size. */
103
-void tcg_exec_init(unsigned long tb_size, int splitwx)
104
-{
32
-{
105
- tcg_allowed = true;
33
- raise_exception(env, EXCP_DEBUG, 0);
106
- page_init();
107
- tb_htable_init();
108
- tcg_init(tb_size, splitwx);
109
-
110
-#if defined(CONFIG_SOFTMMU)
111
- /* There's no guest base to take into account, so go ahead and
112
- initialize the prologue now. */
113
- tcg_prologue_init(tcg_ctx);
114
-#endif
115
-}
34
-}
116
-
35
-
117
/* call with @p->lock held */
36
void helper_sleep(CPUSH4State *env)
118
static inline void invalidate_page_bitmap(PageDesc *p)
119
{
37
{
120
diff --git a/bsd-user/main.c b/bsd-user/main.c
38
CPUState *cs = env_cpu(env);
39
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
121
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
122
--- a/bsd-user/main.c
41
--- a/target/sh4/translate.c
123
+++ b/bsd-user/main.c
42
+++ b/target/sh4/translate.c
124
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
43
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
125
envlist_free(envlist);
44
tcg_gen_exit_tb(ctx->base.tb, n);
126
45
} else {
127
/*
46
tcg_gen_movi_i32(cpu_pc, dest);
128
- * Now that page sizes are configured in tcg_exec_init() we can do
47
- if (ctx->base.singlestep_enabled) {
129
+ * Now that page sizes are configured we can do
48
- gen_helper_debug(cpu_env);
130
* proper page alignment for guest_base.
49
- } else if (use_exit_tb(ctx)) {
131
*/
50
+ if (use_exit_tb(ctx)) {
132
guest_base = HOST_PAGE_ALIGN(guest_base);
51
tcg_gen_exit_tb(NULL, 0);
52
} else {
53
tcg_gen_lookup_and_goto_ptr();
54
@@ -XXX,XX +XXX,XX @@ static void gen_jump(DisasContext * ctx)
55
     delayed jump as immediate jump are conditinal jumps */
56
    tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc);
57
tcg_gen_discard_i32(cpu_delayed_pc);
58
- if (ctx->base.singlestep_enabled) {
59
- gen_helper_debug(cpu_env);
60
- } else if (use_exit_tb(ctx)) {
61
+ if (use_exit_tb(ctx)) {
62
tcg_gen_exit_tb(NULL, 0);
63
} else {
64
tcg_gen_lookup_and_goto_ptr();
65
@@ -XXX,XX +XXX,XX @@ static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
66
switch (ctx->base.is_jmp) {
67
case DISAS_STOP:
68
gen_save_cpu_state(ctx, true);
69
- if (ctx->base.singlestep_enabled) {
70
- gen_helper_debug(cpu_env);
71
- } else {
72
- tcg_gen_exit_tb(NULL, 0);
73
- }
74
+ tcg_gen_exit_tb(NULL, 0);
75
break;
76
case DISAS_NEXT:
77
case DISAS_TOO_MANY:
133
--
78
--
134
2.25.1
79
2.25.1
135
80
136
81
diff view generated by jsdifflib
1
It consists of one function call and has only one caller.
1
GDB single-stepping is now handled generically.
2
2
3
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
4
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
5
---
8
accel/tcg/translate-all.c | 7 +------
6
target/tricore/helper.h | 1 -
9
1 file changed, 1 insertion(+), 6 deletions(-)
7
target/tricore/op_helper.c | 7 -------
8
target/tricore/translate.c | 14 +-------------
9
3 files changed, 1 insertion(+), 21 deletions(-)
10
10
11
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
11
diff --git a/target/tricore/helper.h b/target/tricore/helper.h
12
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
13
--- a/accel/tcg/translate-all.c
13
--- a/target/tricore/helper.h
14
+++ b/accel/tcg/translate-all.c
14
+++ b/target/tricore/helper.h
15
@@ -XXX,XX +XXX,XX @@ static void page_table_config_init(void)
15
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_2(psw_write, void, env, i32)
16
assert(v_l2_levels >= 0);
16
DEF_HELPER_1(psw_read, i32, env)
17
/* Exceptions */
18
DEF_HELPER_3(raise_exception_sync, noreturn, env, i32, i32)
19
-DEF_HELPER_2(qemu_excp, noreturn, env, i32)
20
diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/target/tricore/op_helper.c
23
+++ b/target/tricore/op_helper.c
24
@@ -XXX,XX +XXX,XX @@ static void raise_exception_sync_helper(CPUTriCoreState *env, uint32_t class,
25
raise_exception_sync_internal(env, class, tin, pc, 0);
17
}
26
}
18
27
19
-static void cpu_gen_init(void)
28
-void helper_qemu_excp(CPUTriCoreState *env, uint32_t excp)
20
-{
29
-{
21
- tcg_context_init(&tcg_init_ctx);
30
- CPUState *cs = env_cpu(env);
31
- cs->exception_index = excp;
32
- cpu_loop_exit(cs);
22
-}
33
-}
23
-
34
-
24
/* Encode VAL as a signed leb128 sequence at P.
35
/* Addressing mode helper */
25
Return P incremented past the encoded value. */
36
26
static uint8_t *encode_sleb128(uint8_t *p, target_long val)
37
static uint16_t reverse16(uint16_t val)
27
@@ -XXX,XX +XXX,XX @@ void tcg_exec_init(unsigned long tb_size, int splitwx)
38
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
28
bool ok;
39
index XXXXXXX..XXXXXXX 100644
29
40
--- a/target/tricore/translate.c
30
tcg_allowed = true;
41
+++ b/target/tricore/translate.c
31
- cpu_gen_init();
42
@@ -XXX,XX +XXX,XX @@ static inline void gen_save_pc(target_ulong pc)
32
+ tcg_context_init(&tcg_init_ctx);
43
tcg_gen_movi_tl(cpu_PC, pc);
33
page_init();
44
}
34
tb_htable_init();
45
46
-static void generate_qemu_excp(DisasContext *ctx, int excp)
47
-{
48
- TCGv_i32 tmp = tcg_const_i32(excp);
49
- gen_helper_qemu_excp(cpu_env, tmp);
50
- ctx->base.is_jmp = DISAS_NORETURN;
51
- tcg_temp_free(tmp);
52
-}
53
-
54
static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
55
{
56
if (translator_use_goto_tb(&ctx->base, dest)) {
57
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
58
tcg_gen_exit_tb(ctx->base.tb, n);
59
} else {
60
gen_save_pc(dest);
61
- if (ctx->base.singlestep_enabled) {
62
- generate_qemu_excp(ctx, EXCP_DEBUG);
63
- } else {
64
- tcg_gen_lookup_and_goto_ptr();
65
- }
66
+ tcg_gen_lookup_and_goto_ptr();
67
}
68
}
35
69
36
--
70
--
37
2.25.1
71
2.25.1
38
72
39
73
diff view generated by jsdifflib
1
Move the call out of the N versions of alloc_code_gen_buffer
1
GDB single-stepping is now handled generically.
2
and into tcg_region_init.
3
2
4
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
4
---
8
tcg/region.c | 14 +++++++-------
5
target/xtensa/translate.c | 25 ++++++++-----------------
9
1 file changed, 7 insertions(+), 7 deletions(-)
6
1 file changed, 8 insertions(+), 17 deletions(-)
10
7
11
diff --git a/tcg/region.c b/tcg/region.c
8
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
12
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
13
--- a/tcg/region.c
10
--- a/target/xtensa/translate.c
14
+++ b/tcg/region.c
11
+++ b/target/xtensa/translate.c
15
@@ -XXX,XX +XXX,XX @@ static int alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
12
@@ -XXX,XX +XXX,XX @@ static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
16
error_setg_errno(errp, errno, "mprotect of jit buffer");
13
if (dc->icount) {
17
return false;
14
tcg_gen_mov_i32(cpu_SR[ICOUNT], dc->next_icount);
18
}
15
}
19
- qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
16
- if (dc->base.singlestep_enabled) {
20
17
- gen_exception(dc, EXCP_DEBUG);
21
region.start_aligned = buf;
18
+ if (dc->op_flags & XTENSA_OP_POSTPROCESS) {
22
region.total_size = size;
19
+ slot = gen_postprocess(dc, slot);
23
@@ -XXX,XX +XXX,XX @@ static int alloc_code_gen_buffer_anon(size_t size, int prot,
20
+ }
21
+ if (slot >= 0) {
22
+ tcg_gen_goto_tb(slot);
23
+ tcg_gen_exit_tb(dc->base.tb, slot);
24
} else {
25
- if (dc->op_flags & XTENSA_OP_POSTPROCESS) {
26
- slot = gen_postprocess(dc, slot);
27
- }
28
- if (slot >= 0) {
29
- tcg_gen_goto_tb(slot);
30
- tcg_gen_exit_tb(dc->base.tb, slot);
31
- } else {
32
- tcg_gen_exit_tb(NULL, 0);
33
- }
34
+ tcg_gen_exit_tb(NULL, 0);
24
}
35
}
25
#endif
36
dc->base.is_jmp = DISAS_NORETURN;
26
37
}
27
- /* Request large pages for the buffer. */
38
@@ -XXX,XX +XXX,XX @@ static void xtensa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
28
- qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
39
case DISAS_NORETURN:
29
-
40
break;
30
region.start_aligned = buf;
41
case DISAS_TOO_MANY:
31
region.total_size = size;
42
- if (dc->base.singlestep_enabled) {
32
return prot;
43
- tcg_gen_movi_i32(cpu_pc, dc->pc);
33
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
44
- gen_exception(dc, EXCP_DEBUG);
34
region.total_size = size;
45
- } else {
35
tcg_splitwx_diff = buf_rx - buf_rw;
46
- gen_jumpi(dc, dc->pc, 0);
36
47
- }
37
- /* Request large pages for the buffer and the splitwx. */
48
+ gen_jumpi(dc, dc->pc, 0);
38
- qemu_madvise(buf_rw, size, QEMU_MADV_HUGEPAGE);
49
break;
39
- qemu_madvise(buf_rx, size, QEMU_MADV_HUGEPAGE);
50
default:
40
return PROT_READ | PROT_WRITE;
51
g_assert_not_reached();
41
42
fail_rx:
43
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
44
splitwx, &error_fatal);
45
assert(have_prot >= 0);
46
47
+ /* Request large pages for the buffer and the splitwx. */
48
+ qemu_madvise(region.start_aligned, region.total_size, QEMU_MADV_HUGEPAGE);
49
+ if (tcg_splitwx_diff) {
50
+ qemu_madvise(region.start_aligned + tcg_splitwx_diff,
51
+ region.total_size, QEMU_MADV_HUGEPAGE);
52
+ }
53
+
54
/*
55
* Make region_size a multiple of page_size, using aligned as the start.
56
* As a result of this we might end up with a few extra pages at the end of
57
--
52
--
58
2.25.1
53
2.25.1
59
54
60
55
diff view generated by jsdifflib
1
This has only one user, but will make more sense after some
1
This reverts commit 1b36e4f5a5de585210ea95f2257839c2312be28f.
2
code motion.
3
2
4
Always leave the tcg_init_ctx initialized to the first region,
3
Despite a comment saying why cpu_common_props cannot be placed in
5
in preparation for tcg_prologue_init(). This also requires
4
a file that is compiled once, it was moved anyway. Revert that.
6
that we don't re-allocate the region for the first cpu, lest
7
we hit the assertion for total number of regions allocated .
8
5
9
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
6
Since then, Property is not defined in hw/core/cpu.h, so it is now
10
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
easier to declare a function to install the properties rather than
8
the Property array itself.
9
10
Cc: Eduardo Habkost <ehabkost@redhat.com>
11
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
---
13
---
13
tcg/tcg.c | 37 ++++++++++++++++++++++---------------
14
include/hw/core/cpu.h | 1 +
14
1 file changed, 22 insertions(+), 15 deletions(-)
15
cpu.c | 21 +++++++++++++++++++++
16
hw/core/cpu-common.c | 17 +----------------
17
3 files changed, 23 insertions(+), 16 deletions(-)
15
18
16
diff --git a/tcg/tcg.c b/tcg/tcg.c
19
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/tcg/tcg.c
21
--- a/include/hw/core/cpu.h
19
+++ b/tcg/tcg.c
22
+++ b/include/hw/core/cpu.h
20
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(void)
23
@@ -XXX,XX +XXX,XX @@ void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...)
21
24
GCC_FMT_ATTR(2, 3);
22
tcg_region_trees_init();
25
23
26
/* $(top_srcdir)/cpu.c */
24
- /* In user-mode we support only one ctx, so do the initial allocation now */
27
+void cpu_class_init_props(DeviceClass *dc);
25
-#ifdef CONFIG_USER_ONLY
28
void cpu_exec_initfn(CPUState *cpu);
26
- tcg_region_initial_alloc__locked(tcg_ctx);
29
void cpu_exec_realizefn(CPUState *cpu, Error **errp);
27
-#endif
30
void cpu_exec_unrealizefn(CPUState *cpu);
31
diff --git a/cpu.c b/cpu.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/cpu.c
34
+++ b/cpu.c
35
@@ -XXX,XX +XXX,XX @@ void cpu_exec_unrealizefn(CPUState *cpu)
36
cpu_list_remove(cpu);
37
}
38
39
+static Property cpu_common_props[] = {
40
+#ifndef CONFIG_USER_ONLY
28
+ /*
41
+ /*
29
+ * Leave the initial context initialized to the first region.
42
+ * Create a memory property for softmmu CPU object,
30
+ * This will be the context into which we generate the prologue.
43
+ * so users can wire up its memory. (This can't go in hw/core/cpu.c
31
+ * It is also the only context for CONFIG_USER_ONLY.
44
+ * because that file is compiled only once for both user-mode
45
+ * and system builds.) The default if no link is set up is to use
46
+ * the system address space.
32
+ */
47
+ */
33
+ tcg_region_initial_alloc__locked(&tcg_init_ctx);
48
+ DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
49
+ MemoryRegion *),
50
+#endif
51
+ DEFINE_PROP_BOOL("start-powered-off", CPUState, start_powered_off, false),
52
+ DEFINE_PROP_END_OF_LIST(),
53
+};
54
+
55
+void cpu_class_init_props(DeviceClass *dc)
56
+{
57
+ device_class_set_props(dc, cpu_common_props);
34
+}
58
+}
35
+
59
+
36
+static void tcg_region_prologue_set(TCGContext *s)
60
void cpu_exec_initfn(CPUState *cpu)
37
+{
61
{
38
+ /* Deduct the prologue from the first region. */
62
cpu->as = NULL;
39
+ g_assert(region.start == s->code_gen_buffer);
63
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
40
+ region.start = s->code_ptr;
64
index XXXXXXX..XXXXXXX 100644
41
+
65
--- a/hw/core/cpu-common.c
42
+ /* Recompute boundaries of the first region. */
66
+++ b/hw/core/cpu-common.c
43
+ tcg_region_assign(s, 0);
67
@@ -XXX,XX +XXX,XX @@ static int64_t cpu_common_get_arch_id(CPUState *cpu)
44
+
68
return cpu->cpu_index;
45
+ /* Register the balance of the buffer with gdb. */
46
+ tcg_register_jit(tcg_splitwx_to_rx(region.start),
47
+ region.end - region.start);
48
}
69
}
49
70
50
#ifdef CONFIG_DEBUG_TCG
71
-static Property cpu_common_props[] = {
51
@@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void)
72
-#ifndef CONFIG_USER_ONLY
52
73
- /* Create a memory property for softmmu CPU object,
53
if (n > 0) {
74
- * so users can wire up its memory. (This can't go in hw/core/cpu.c
54
alloc_tcg_plugin_context(s);
75
- * because that file is compiled only once for both user-mode
55
+ tcg_region_initial_alloc(s);
76
- * and system builds.) The default if no link is set up is to use
56
}
77
- * the system address space.
57
78
- */
58
tcg_ctx = s;
79
- DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
59
- tcg_region_initial_alloc(s);
80
- MemoryRegion *),
60
}
81
-#endif
61
#endif /* !CONFIG_USER_ONLY */
82
- DEFINE_PROP_BOOL("start-powered-off", CPUState, start_powered_off, false),
62
83
- DEFINE_PROP_END_OF_LIST(),
63
@@ -XXX,XX +XXX,XX @@ void tcg_prologue_init(TCGContext *s)
84
-};
85
-
86
static void cpu_class_init(ObjectClass *klass, void *data)
64
{
87
{
65
size_t prologue_size;
88
DeviceClass *dc = DEVICE_CLASS(klass);
66
89
@@ -XXX,XX +XXX,XX @@ static void cpu_class_init(ObjectClass *klass, void *data)
67
- /* Put the prologue at the beginning of code_gen_buffer. */
90
dc->realize = cpu_common_realizefn;
68
- tcg_region_assign(s, 0);
91
dc->unrealize = cpu_common_unrealizefn;
69
s->code_ptr = s->code_gen_ptr;
92
dc->reset = cpu_common_reset;
70
s->code_buf = s->code_gen_ptr;
93
- device_class_set_props(dc, cpu_common_props);
71
s->data_gen_ptr = NULL;
94
+ cpu_class_init_props(dc);
72
@@ -XXX,XX +XXX,XX @@ void tcg_prologue_init(TCGContext *s)
95
/*
73
(uintptr_t)s->code_buf, prologue_size);
96
* Reason: CPUs still need special care by board code: wiring up
74
#endif
97
* IRQs, adding reset handlers, halting non-first CPUs, ...
75
76
- /* Deduct the prologue from the first region. */
77
- region.start = s->code_ptr;
78
-
79
- /* Recompute boundaries of the first region. */
80
- tcg_region_assign(s, 0);
81
-
82
- tcg_register_jit(tcg_splitwx_to_rx(region.start),
83
- region.end - region.start);
84
+ tcg_region_prologue_set(s);
85
86
#ifdef DEBUG_DISAS
87
if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
88
--
98
--
89
2.25.1
99
2.25.1
90
100
91
101
diff view generated by jsdifflib
Deleted patch
1
We shortly want to use tcg_init for something else.
2
Since the hook is called init_machine, match that.
3
1
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
accel/tcg/tcg-all.c | 4 ++--
10
1 file changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/accel/tcg/tcg-all.c
15
+++ b/accel/tcg/tcg-all.c
16
@@ -XXX,XX +XXX,XX @@ static void tcg_accel_instance_init(Object *obj)
17
18
bool mttcg_enabled;
19
20
-static int tcg_init(MachineState *ms)
21
+static int tcg_init_machine(MachineState *ms)
22
{
23
TCGState *s = TCG_STATE(current_accel());
24
25
@@ -XXX,XX +XXX,XX @@ static void tcg_accel_class_init(ObjectClass *oc, void *data)
26
{
27
AccelClass *ac = ACCEL_CLASS(oc);
28
ac->name = "tcg";
29
- ac->init_machine = tcg_init;
30
+ ac->init_machine = tcg_init_machine;
31
ac->allowed = &tcg_allowed;
32
33
object_class_property_add_str(oc, "thread",
34
--
35
2.25.1
36
37
diff view generated by jsdifflib
Deleted patch
1
Remove the ifdef ladder and move each define into the
2
appropriate header file.
3
1
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
8
tcg/aarch64/tcg-target.h | 1 +
9
tcg/arm/tcg-target.h | 1 +
10
tcg/i386/tcg-target.h | 2 ++
11
tcg/mips/tcg-target.h | 6 ++++++
12
tcg/ppc/tcg-target.h | 2 ++
13
tcg/riscv/tcg-target.h | 1 +
14
tcg/s390/tcg-target.h | 3 +++
15
tcg/sparc/tcg-target.h | 1 +
16
tcg/tci/tcg-target.h | 1 +
17
tcg/region.c | 33 +++++----------------------------
18
10 files changed, 23 insertions(+), 28 deletions(-)
19
20
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/tcg/aarch64/tcg-target.h
23
+++ b/tcg/aarch64/tcg-target.h
24
@@ -XXX,XX +XXX,XX @@
25
26
#define TCG_TARGET_INSN_UNIT_SIZE 4
27
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 24
28
+#define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
29
#undef TCG_TARGET_STACK_GROWSUP
30
31
typedef enum {
32
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/tcg/arm/tcg-target.h
35
+++ b/tcg/arm/tcg-target.h
36
@@ -XXX,XX +XXX,XX @@ extern int arm_arch;
37
#undef TCG_TARGET_STACK_GROWSUP
38
#define TCG_TARGET_INSN_UNIT_SIZE 4
39
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 16
40
+#define MAX_CODE_GEN_BUFFER_SIZE UINT32_MAX
41
42
typedef enum {
43
TCG_REG_R0 = 0,
44
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/tcg/i386/tcg-target.h
47
+++ b/tcg/i386/tcg-target.h
48
@@ -XXX,XX +XXX,XX @@
49
#ifdef __x86_64__
50
# define TCG_TARGET_REG_BITS 64
51
# define TCG_TARGET_NB_REGS 32
52
+# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
53
#else
54
# define TCG_TARGET_REG_BITS 32
55
# define TCG_TARGET_NB_REGS 24
56
+# define MAX_CODE_GEN_BUFFER_SIZE UINT32_MAX
57
#endif
58
59
typedef enum {
60
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
61
index XXXXXXX..XXXXXXX 100644
62
--- a/tcg/mips/tcg-target.h
63
+++ b/tcg/mips/tcg-target.h
64
@@ -XXX,XX +XXX,XX @@
65
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 16
66
#define TCG_TARGET_NB_REGS 32
67
68
+/*
69
+ * We have a 256MB branch region, but leave room to make sure the
70
+ * main executable is also within that region.
71
+ */
72
+#define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB)
73
+
74
typedef enum {
75
TCG_REG_ZERO = 0,
76
TCG_REG_AT,
77
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
78
index XXXXXXX..XXXXXXX 100644
79
--- a/tcg/ppc/tcg-target.h
80
+++ b/tcg/ppc/tcg-target.h
81
@@ -XXX,XX +XXX,XX @@
82
83
#ifdef _ARCH_PPC64
84
# define TCG_TARGET_REG_BITS 64
85
+# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
86
#else
87
# define TCG_TARGET_REG_BITS 32
88
+# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
89
#endif
90
91
#define TCG_TARGET_NB_REGS 64
92
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
93
index XXXXXXX..XXXXXXX 100644
94
--- a/tcg/riscv/tcg-target.h
95
+++ b/tcg/riscv/tcg-target.h
96
@@ -XXX,XX +XXX,XX @@
97
#define TCG_TARGET_INSN_UNIT_SIZE 4
98
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 20
99
#define TCG_TARGET_NB_REGS 32
100
+#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
101
102
typedef enum {
103
TCG_REG_ZERO,
104
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
105
index XXXXXXX..XXXXXXX 100644
106
--- a/tcg/s390/tcg-target.h
107
+++ b/tcg/s390/tcg-target.h
108
@@ -XXX,XX +XXX,XX @@
109
#define TCG_TARGET_INSN_UNIT_SIZE 2
110
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 19
111
112
+/* We have a +- 4GB range on the branches; leave some slop. */
113
+#define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
114
+
115
typedef enum TCGReg {
116
TCG_REG_R0 = 0,
117
TCG_REG_R1,
118
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
119
index XXXXXXX..XXXXXXX 100644
120
--- a/tcg/sparc/tcg-target.h
121
+++ b/tcg/sparc/tcg-target.h
122
@@ -XXX,XX +XXX,XX @@
123
#define TCG_TARGET_INSN_UNIT_SIZE 4
124
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 32
125
#define TCG_TARGET_NB_REGS 32
126
+#define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
127
128
typedef enum {
129
TCG_REG_G0 = 0,
130
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
131
index XXXXXXX..XXXXXXX 100644
132
--- a/tcg/tci/tcg-target.h
133
+++ b/tcg/tci/tcg-target.h
134
@@ -XXX,XX +XXX,XX @@
135
#define TCG_TARGET_INTERPRETER 1
136
#define TCG_TARGET_INSN_UNIT_SIZE 1
137
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 32
138
+#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
139
140
#if UINTPTR_MAX == UINT32_MAX
141
# define TCG_TARGET_REG_BITS 32
142
diff --git a/tcg/region.c b/tcg/region.c
143
index XXXXXXX..XXXXXXX 100644
144
--- a/tcg/region.c
145
+++ b/tcg/region.c
146
@@ -XXX,XX +XXX,XX @@ static size_t tcg_n_regions(unsigned max_cpus)
147
/*
148
* Minimum size of the code gen buffer. This number is randomly chosen,
149
* but not so small that we can't have a fair number of TB's live.
150
+ *
151
+ * Maximum size, MAX_CODE_GEN_BUFFER_SIZE, is defined in tcg-target.h.
152
+ * Unless otherwise indicated, this is constrained by the range of
153
+ * direct branches on the host cpu, as used by the TCG implementation
154
+ * of goto_tb.
155
*/
156
#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB)
157
158
-/*
159
- * Maximum size of the code gen buffer we'd like to use. Unless otherwise
160
- * indicated, this is constrained by the range of direct branches on the
161
- * host cpu, as used by the TCG implementation of goto_tb.
162
- */
163
-#if defined(__x86_64__)
164
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
165
-#elif defined(__sparc__)
166
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
167
-#elif defined(__powerpc64__)
168
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
169
-#elif defined(__powerpc__)
170
-# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
171
-#elif defined(__aarch64__)
172
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
173
-#elif defined(__s390x__)
174
- /* We have a +- 4GB range on the branches; leave some slop. */
175
-# define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
176
-#elif defined(__mips__)
177
- /*
178
- * We have a 256MB branch region, but leave room to make sure the
179
- * main executable is also within that region.
180
- */
181
-# define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB)
182
-#else
183
-# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
184
-#endif
185
-
186
#if TCG_TARGET_REG_BITS == 32
187
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32 * MiB)
188
#ifdef CONFIG_USER_ONLY
189
--
190
2.25.1
191
192
diff view generated by jsdifflib
Deleted patch
1
A size is easier to work with than an end point,
2
particularly during initial buffer allocation.
3
1
4
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
8
tcg/region.c | 30 ++++++++++++++++++------------
9
1 file changed, 18 insertions(+), 12 deletions(-)
10
11
diff --git a/tcg/region.c b/tcg/region.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/tcg/region.c
14
+++ b/tcg/region.c
15
@@ -XXX,XX +XXX,XX @@ struct tcg_region_state {
16
/* fields set at init time */
17
void *start;
18
void *start_aligned;
19
- void *end;
20
size_t n;
21
size_t size; /* size of one region */
22
size_t stride; /* .size + guard size */
23
+ size_t total_size; /* size of entire buffer, >= n * stride */
24
25
/* fields protected by the lock */
26
size_t current; /* current region index */
27
@@ -XXX,XX +XXX,XX @@ static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
28
if (curr_region == 0) {
29
start = region.start;
30
}
31
+ /* The final region may have a few extra pages due to earlier rounding. */
32
if (curr_region == region.n - 1) {
33
- end = region.end;
34
+ end = region.start_aligned + region.total_size;
35
}
36
37
*pstart = start;
38
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
39
*/
40
void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
41
{
42
- void *buf, *aligned;
43
- size_t size;
44
+ void *buf, *aligned, *end;
45
+ size_t total_size;
46
size_t page_size;
47
size_t region_size;
48
size_t n_regions;
49
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
50
assert(ok);
51
52
buf = tcg_init_ctx.code_gen_buffer;
53
- size = tcg_init_ctx.code_gen_buffer_size;
54
+ total_size = tcg_init_ctx.code_gen_buffer_size;
55
page_size = qemu_real_host_page_size;
56
n_regions = tcg_n_regions(max_cpus);
57
58
/* The first region will be 'aligned - buf' bytes larger than the others */
59
aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
60
- g_assert(aligned < tcg_init_ctx.code_gen_buffer + size);
61
+ g_assert(aligned < tcg_init_ctx.code_gen_buffer + total_size);
62
+
63
/*
64
* Make region_size a multiple of page_size, using aligned as the start.
65
* As a result of this we might end up with a few extra pages at the end of
66
* the buffer; we will assign those to the last region.
67
*/
68
- region_size = (size - (aligned - buf)) / n_regions;
69
+ region_size = (total_size - (aligned - buf)) / n_regions;
70
region_size = QEMU_ALIGN_DOWN(region_size, page_size);
71
72
/* A region must have at least 2 pages; one code, one guard */
73
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
74
region.start = buf;
75
region.start_aligned = aligned;
76
/* page-align the end, since its last page will be a guard page */
77
- region.end = QEMU_ALIGN_PTR_DOWN(buf + size, page_size);
78
+ end = QEMU_ALIGN_PTR_DOWN(buf + total_size, page_size);
79
/* account for that last guard page */
80
- region.end -= page_size;
81
+ end -= page_size;
82
+ total_size = end - aligned;
83
+ region.total_size = total_size;
84
85
/*
86
* Set guard pages in the rw buffer, as that's the one into which
87
@@ -XXX,XX +XXX,XX @@ void tcg_region_prologue_set(TCGContext *s)
88
89
/* Register the balance of the buffer with gdb. */
90
tcg_register_jit(tcg_splitwx_to_rx(region.start),
91
- region.end - region.start);
92
+ region.start_aligned + region.total_size - region.start);
93
}
94
95
/*
96
@@ -XXX,XX +XXX,XX @@ size_t tcg_code_capacity(void)
97
98
/* no need for synchronization; these variables are set at init time */
99
guard_size = region.stride - region.size;
100
- capacity = region.end + guard_size - region.start;
101
- capacity -= region.n * (guard_size + TCG_HIGHWATER);
102
+ capacity = region.total_size;
103
+ capacity -= (region.n - 1) * guard_size;
104
+ capacity -= region.n * TCG_HIGHWATER;
105
+
106
return capacity;
107
}
108
109
--
110
2.25.1
111
112
diff view generated by jsdifflib
Deleted patch
1
Give the field a name reflecting its actual meaning.
2
1
3
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
4
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
---
7
tcg/region.c | 15 ++++++++-------
8
1 file changed, 8 insertions(+), 7 deletions(-)
9
10
diff --git a/tcg/region.c b/tcg/region.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tcg/region.c
13
+++ b/tcg/region.c
14
@@ -XXX,XX +XXX,XX @@ struct tcg_region_state {
15
QemuMutex lock;
16
17
/* fields set at init time */
18
- void *start;
19
void *start_aligned;
20
+ void *after_prologue;
21
size_t n;
22
size_t size; /* size of one region */
23
size_t stride; /* .size + guard size */
24
@@ -XXX,XX +XXX,XX @@ static void tcg_region_bounds(size_t curr_region, void **pstart, void **pend)
25
end = start + region.size;
26
27
if (curr_region == 0) {
28
- start = region.start;
29
+ start = region.after_prologue;
30
}
31
/* The final region may have a few extra pages due to earlier rounding. */
32
if (curr_region == region.n - 1) {
33
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
34
region.n = n_regions;
35
region.size = region_size - page_size;
36
region.stride = region_size;
37
- region.start = buf;
38
+ region.after_prologue = buf;
39
region.start_aligned = aligned;
40
/* page-align the end, since its last page will be a guard page */
41
end = QEMU_ALIGN_PTR_DOWN(buf + total_size, page_size);
42
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
43
void tcg_region_prologue_set(TCGContext *s)
44
{
45
/* Deduct the prologue from the first region. */
46
- g_assert(region.start == s->code_gen_buffer);
47
- region.start = s->code_ptr;
48
+ g_assert(region.start_aligned == s->code_gen_buffer);
49
+ region.after_prologue = s->code_ptr;
50
51
/* Recompute boundaries of the first region. */
52
tcg_region_assign(s, 0);
53
54
/* Register the balance of the buffer with gdb. */
55
- tcg_register_jit(tcg_splitwx_to_rx(region.start),
56
- region.start_aligned + region.total_size - region.start);
57
+ tcg_register_jit(tcg_splitwx_to_rx(region.after_prologue),
58
+ region.start_aligned + region.total_size -
59
+ region.after_prologue);
60
}
61
62
/*
63
--
64
2.25.1
65
66
diff view generated by jsdifflib
Deleted patch
1
Shortly, the full code_gen_buffer will only be visible
2
to region.c, so move in_code_gen_buffer out-of-line.
3
1
4
Move the debugging versions of tcg_splitwx_to_{rx,rw}
5
to region.c as well, so that the compiler gets to see
6
the implementation of in_code_gen_buffer.
7
8
This leaves exactly one use of in_code_gen_buffer outside
9
of region.c, in cpu_restore_state. Which, being on the
10
exception path, is not performance critical.
11
12
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
13
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
14
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
15
---
16
include/tcg/tcg.h | 11 +----------
17
tcg/region.c | 34 ++++++++++++++++++++++++++++++++++
18
tcg/tcg.c | 23 -----------------------
19
3 files changed, 35 insertions(+), 33 deletions(-)
20
21
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/tcg/tcg.h
24
+++ b/include/tcg/tcg.h
25
@@ -XXX,XX +XXX,XX @@ extern const void *tcg_code_gen_epilogue;
26
extern uintptr_t tcg_splitwx_diff;
27
extern TCGv_env cpu_env;
28
29
-static inline bool in_code_gen_buffer(const void *p)
30
-{
31
- const TCGContext *s = &tcg_init_ctx;
32
- /*
33
- * Much like it is valid to have a pointer to the byte past the
34
- * end of an array (so long as you don't dereference it), allow
35
- * a pointer to the byte past the end of the code gen buffer.
36
- */
37
- return (size_t)(p - s->code_gen_buffer) <= s->code_gen_buffer_size;
38
-}
39
+bool in_code_gen_buffer(const void *p);
40
41
#ifdef CONFIG_DEBUG_TCG
42
const void *tcg_splitwx_to_rx(void *rw);
43
diff --git a/tcg/region.c b/tcg/region.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/tcg/region.c
46
+++ b/tcg/region.c
47
@@ -XXX,XX +XXX,XX @@ static struct tcg_region_state region;
48
static void *region_trees;
49
static size_t tree_size;
50
51
+bool in_code_gen_buffer(const void *p)
52
+{
53
+ const TCGContext *s = &tcg_init_ctx;
54
+ /*
55
+ * Much like it is valid to have a pointer to the byte past the
56
+ * end of an array (so long as you don't dereference it), allow
57
+ * a pointer to the byte past the end of the code gen buffer.
58
+ */
59
+ return (size_t)(p - s->code_gen_buffer) <= s->code_gen_buffer_size;
60
+}
61
+
62
+#ifdef CONFIG_DEBUG_TCG
63
+const void *tcg_splitwx_to_rx(void *rw)
64
+{
65
+ /* Pass NULL pointers unchanged. */
66
+ if (rw) {
67
+ g_assert(in_code_gen_buffer(rw));
68
+ rw += tcg_splitwx_diff;
69
+ }
70
+ return rw;
71
+}
72
+
73
+void *tcg_splitwx_to_rw(const void *rx)
74
+{
75
+ /* Pass NULL pointers unchanged. */
76
+ if (rx) {
77
+ rx -= tcg_splitwx_diff;
78
+ /* Assert that we end with a pointer in the rw region. */
79
+ g_assert(in_code_gen_buffer(rx));
80
+ }
81
+ return (void *)rx;
82
+}
83
+#endif /* CONFIG_DEBUG_TCG */
84
+
85
/* compare a pointer @ptr and a tb_tc @s */
86
static int ptr_cmp_tb_tc(const void *ptr, const struct tb_tc *s)
87
{
88
diff --git a/tcg/tcg.c b/tcg/tcg.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/tcg/tcg.c
91
+++ b/tcg/tcg.c
92
@@ -XXX,XX +XXX,XX @@ static const TCGTargetOpDef constraint_sets[] = {
93
94
#include "tcg-target.c.inc"
95
96
-#ifdef CONFIG_DEBUG_TCG
97
-const void *tcg_splitwx_to_rx(void *rw)
98
-{
99
- /* Pass NULL pointers unchanged. */
100
- if (rw) {
101
- g_assert(in_code_gen_buffer(rw));
102
- rw += tcg_splitwx_diff;
103
- }
104
- return rw;
105
-}
106
-
107
-void *tcg_splitwx_to_rw(const void *rx)
108
-{
109
- /* Pass NULL pointers unchanged. */
110
- if (rx) {
111
- rx -= tcg_splitwx_diff;
112
- /* Assert that we end with a pointer in the rw region. */
113
- g_assert(in_code_gen_buffer(rx));
114
- }
115
- return (void *)rx;
116
-}
117
-#endif /* CONFIG_DEBUG_TCG */
118
-
119
static void alloc_tcg_plugin_context(TCGContext *s)
120
{
121
#ifdef CONFIG_PLUGIN
122
--
123
2.25.1
124
125
diff view generated by jsdifflib
Deleted patch
1
Do not mess around with setting values within tcg_init_ctx.
2
Put the values into 'region' directly, which is where they
3
will live for the lifetime of the program.
4
1
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
tcg/region.c | 64 ++++++++++++++++++++++------------------------------
10
1 file changed, 27 insertions(+), 37 deletions(-)
11
12
diff --git a/tcg/region.c b/tcg/region.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/tcg/region.c
15
+++ b/tcg/region.c
16
@@ -XXX,XX +XXX,XX @@ static size_t tree_size;
17
18
bool in_code_gen_buffer(const void *p)
19
{
20
- const TCGContext *s = &tcg_init_ctx;
21
/*
22
* Much like it is valid to have a pointer to the byte past the
23
* end of an array (so long as you don't dereference it), allow
24
* a pointer to the byte past the end of the code gen buffer.
25
*/
26
- return (size_t)(p - s->code_gen_buffer) <= s->code_gen_buffer_size;
27
+ return (size_t)(p - region.start_aligned) <= region.total_size;
28
}
29
30
#ifdef CONFIG_DEBUG_TCG
31
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
32
}
33
qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
34
35
- tcg_ctx->code_gen_buffer = buf;
36
- tcg_ctx->code_gen_buffer_size = size;
37
+ region.start_aligned = buf;
38
+ region.total_size = size;
39
return true;
40
}
41
#elif defined(_WIN32)
42
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
43
return false;
44
}
45
46
- tcg_ctx->code_gen_buffer = buf;
47
- tcg_ctx->code_gen_buffer_size = size;
48
+ region.start_aligned = buf;
49
+ region.total_size = size;
50
return true;
51
}
52
#else
53
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_anon(size_t size, int prot,
54
/* Request large pages for the buffer. */
55
qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
56
57
- tcg_ctx->code_gen_buffer = buf;
58
- tcg_ctx->code_gen_buffer_size = size;
59
+ region.start_aligned = buf;
60
+ region.total_size = size;
61
return true;
62
}
63
64
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
65
return false;
66
}
67
/* The size of the mapping may have been adjusted. */
68
- size = tcg_ctx->code_gen_buffer_size;
69
- buf_rx = tcg_ctx->code_gen_buffer;
70
+ buf_rx = region.start_aligned;
71
+ size = region.total_size;
72
#endif
73
74
buf_rw = qemu_memfd_alloc("tcg-jit", size, 0, &fd, errp);
75
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
76
#endif
77
78
close(fd);
79
- tcg_ctx->code_gen_buffer = buf_rw;
80
- tcg_ctx->code_gen_buffer_size = size;
81
+ region.start_aligned = buf_rw;
82
+ region.total_size = size;
83
tcg_splitwx_diff = buf_rx - buf_rw;
84
85
/* Request large pages for the buffer and the splitwx. */
86
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
87
return false;
88
}
89
90
- buf_rw = (mach_vm_address_t)tcg_ctx->code_gen_buffer;
91
+ buf_rw = region.start_aligned;
92
buf_rx = 0;
93
ret = mach_vm_remap(mach_task_self(),
94
&buf_rx,
95
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
96
*/
97
void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
98
{
99
- void *buf, *aligned, *end;
100
- size_t total_size;
101
size_t page_size;
102
size_t region_size;
103
- size_t n_regions;
104
size_t i;
105
bool ok;
106
107
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
108
splitwx, &error_fatal);
109
assert(ok);
110
111
- buf = tcg_init_ctx.code_gen_buffer;
112
- total_size = tcg_init_ctx.code_gen_buffer_size;
113
- page_size = qemu_real_host_page_size;
114
- n_regions = tcg_n_regions(total_size, max_cpus);
115
-
116
- /* The first region will be 'aligned - buf' bytes larger than the others */
117
- aligned = QEMU_ALIGN_PTR_UP(buf, page_size);
118
- g_assert(aligned < tcg_init_ctx.code_gen_buffer + total_size);
119
-
120
/*
121
* Make region_size a multiple of page_size, using aligned as the start.
122
* As a result of this we might end up with a few extra pages at the end of
123
* the buffer; we will assign those to the last region.
124
*/
125
- region_size = (total_size - (aligned - buf)) / n_regions;
126
+ region.n = tcg_n_regions(region.total_size, max_cpus);
127
+ page_size = qemu_real_host_page_size;
128
+ region_size = region.total_size / region.n;
129
region_size = QEMU_ALIGN_DOWN(region_size, page_size);
130
131
/* A region must have at least 2 pages; one code, one guard */
132
g_assert(region_size >= 2 * page_size);
133
+ region.stride = region_size;
134
+
135
+ /* Reserve space for guard pages. */
136
+ region.size = region_size - page_size;
137
+ region.total_size -= page_size;
138
+
139
+ /*
140
+ * The first region will be smaller than the others, via the prologue,
141
+ * which has yet to be allocated. For now, the first region begins at
142
+ * the page boundary.
143
+ */
144
+ region.after_prologue = region.start_aligned;
145
146
/* init the region struct */
147
qemu_mutex_init(&region.lock);
148
- region.n = n_regions;
149
- region.size = region_size - page_size;
150
- region.stride = region_size;
151
- region.after_prologue = buf;
152
- region.start_aligned = aligned;
153
- /* page-align the end, since its last page will be a guard page */
154
- end = QEMU_ALIGN_PTR_DOWN(buf + total_size, page_size);
155
- /* account for that last guard page */
156
- end -= page_size;
157
- total_size = end - aligned;
158
- region.total_size = total_size;
159
160
/*
161
* Set guard pages in the rw buffer, as that's the one into which
162
--
163
2.25.1
164
165
diff view generated by jsdifflib
Deleted patch
1
Change the interface from a boolean error indication to a
2
negative error vs a non-negative protection. For the moment
3
this is only interface change, not making use of the new data.
4
1
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Luis Pires <luis.pires@eldorado.org.br>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
tcg/region.c | 63 +++++++++++++++++++++++++++-------------------------
10
1 file changed, 33 insertions(+), 30 deletions(-)
11
12
diff --git a/tcg/region.c b/tcg/region.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/tcg/region.c
15
+++ b/tcg/region.c
16
@@ -XXX,XX +XXX,XX @@ static inline void split_cross_256mb(void **obuf, size_t *osize,
17
static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
18
__attribute__((aligned(CODE_GEN_ALIGN)));
19
20
-static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
21
+static int alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
22
{
23
void *buf, *end;
24
size_t size;
25
26
if (splitwx > 0) {
27
error_setg(errp, "jit split-wx not supported");
28
- return false;
29
+ return -1;
30
}
31
32
/* page-align the beginning and end of the buffer */
33
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
34
35
region.start_aligned = buf;
36
region.total_size = size;
37
- return true;
38
+
39
+ return PROT_READ | PROT_WRITE;
40
}
41
#elif defined(_WIN32)
42
-static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
43
+static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
44
{
45
void *buf;
46
47
if (splitwx > 0) {
48
error_setg(errp, "jit split-wx not supported");
49
- return false;
50
+ return -1;
51
}
52
53
buf = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT,
54
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
55
56
region.start_aligned = buf;
57
region.total_size = size;
58
- return true;
59
+
60
+ return PAGE_READ | PAGE_WRITE | PAGE_EXEC;
61
}
62
#else
63
-static bool alloc_code_gen_buffer_anon(size_t size, int prot,
64
- int flags, Error **errp)
65
+static int alloc_code_gen_buffer_anon(size_t size, int prot,
66
+ int flags, Error **errp)
67
{
68
void *buf;
69
70
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_anon(size_t size, int prot,
71
if (buf == MAP_FAILED) {
72
error_setg_errno(errp, errno,
73
"allocate %zu bytes for jit buffer", size);
74
- return false;
75
+ return -1;
76
}
77
78
#ifdef __mips__
79
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_anon(size_t size, int prot,
80
81
region.start_aligned = buf;
82
region.total_size = size;
83
- return true;
84
+ return prot;
85
}
86
87
#ifndef CONFIG_TCG_INTERPRETER
88
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
89
90
#ifdef __mips__
91
/* Find space for the RX mapping, vs the 256MiB regions. */
92
- if (!alloc_code_gen_buffer_anon(size, PROT_NONE,
93
- MAP_PRIVATE | MAP_ANONYMOUS |
94
- MAP_NORESERVE, errp)) {
95
+ if (alloc_code_gen_buffer_anon(size, PROT_NONE,
96
+ MAP_PRIVATE | MAP_ANONYMOUS |
97
+ MAP_NORESERVE, errp) < 0) {
98
return false;
99
}
100
/* The size of the mapping may have been adjusted. */
101
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
102
/* Request large pages for the buffer and the splitwx. */
103
qemu_madvise(buf_rw, size, QEMU_MADV_HUGEPAGE);
104
qemu_madvise(buf_rx, size, QEMU_MADV_HUGEPAGE);
105
- return true;
106
+ return PROT_READ | PROT_WRITE;
107
108
fail_rx:
109
error_setg_errno(errp, errno, "failed to map shared memory for execute");
110
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
111
if (fd >= 0) {
112
close(fd);
113
}
114
- return false;
115
+ return -1;
116
}
117
#endif /* CONFIG_POSIX */
118
119
@@ -XXX,XX +XXX,XX @@ extern kern_return_t mach_vm_remap(vm_map_t target_task,
120
vm_prot_t *max_protection,
121
vm_inherit_t inheritance);
122
123
-static bool alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
124
+static int alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
125
{
126
kern_return_t ret;
127
mach_vm_address_t buf_rw, buf_rx;
128
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
129
/* Map the read-write portion via normal anon memory. */
130
if (!alloc_code_gen_buffer_anon(size, PROT_READ | PROT_WRITE,
131
MAP_PRIVATE | MAP_ANONYMOUS, errp)) {
132
- return false;
133
+ return -1;
134
}
135
136
buf_rw = region.start_aligned;
137
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
138
/* TODO: Convert "ret" to a human readable error message. */
139
error_setg(errp, "vm_remap for jit splitwx failed");
140
munmap((void *)buf_rw, size);
141
- return false;
142
+ return -1;
143
}
144
145
if (mprotect((void *)buf_rx, size, PROT_READ | PROT_EXEC) != 0) {
146
error_setg_errno(errp, errno, "mprotect for jit splitwx");
147
munmap((void *)buf_rx, size);
148
munmap((void *)buf_rw, size);
149
- return false;
150
+ return -1;
151
}
152
153
tcg_splitwx_diff = buf_rx - buf_rw;
154
- return true;
155
+ return PROT_READ | PROT_WRITE;
156
}
157
#endif /* CONFIG_DARWIN */
158
#endif /* CONFIG_TCG_INTERPRETER */
159
160
-static bool alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
161
+static int alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
162
{
163
#ifndef CONFIG_TCG_INTERPRETER
164
# ifdef CONFIG_DARWIN
165
@@ -XXX,XX +XXX,XX @@ static bool alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
166
# endif
167
#endif
168
error_setg(errp, "jit split-wx not supported");
169
- return false;
170
+ return -1;
171
}
172
173
-static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
174
+static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
175
{
176
ERRP_GUARD();
177
int prot, flags;
178
179
if (splitwx) {
180
- if (alloc_code_gen_buffer_splitwx(size, errp)) {
181
- return true;
182
+ prot = alloc_code_gen_buffer_splitwx(size, errp);
183
+ if (prot >= 0) {
184
+ return prot;
185
}
186
/*
187
* If splitwx force-on (1), fail;
188
* if splitwx default-on (-1), fall through to splitwx off.
189
*/
190
if (splitwx > 0) {
191
- return false;
192
+ return -1;
193
}
194
error_free_or_abort(errp);
195
}
196
@@ -XXX,XX +XXX,XX @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
197
size_t page_size;
198
size_t region_size;
199
size_t i;
200
- bool ok;
201
+ int have_prot;
202
203
- ok = alloc_code_gen_buffer(size_code_gen_buffer(tb_size),
204
- splitwx, &error_fatal);
205
- assert(ok);
206
+ have_prot = alloc_code_gen_buffer(size_code_gen_buffer(tb_size),
207
+ splitwx, &error_fatal);
208
+ assert(have_prot >= 0);
209
210
/*
211
* Make region_size a multiple of page_size, using aligned as the start.
212
--
213
2.25.1
214
215
diff view generated by jsdifflib