* [PATCH v5 00/23] add LVZ support for TCG
@ 2026-10-09 3:04 SignKirigami
2026-10-09 3:04 ` [PATCH v5 01/23] target/loongarch: select sys state by VM level SignKirigami
` (22 more replies)
0 siblings, 23 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami
This patch implements Loongson VirtualiZation (LVZ) extension support
for LoongArch's TCG target. With this patch, it is now possible to start
a nested KVM-accelerated virtual machine on a TCG-emulated virtual machine.
SignKirigami (23):
target/loongarch: select sys state by VM level
target/loongarch: add get_sys() helper
target/loongarch: add LVZ feature switcher
target/loongarch: add LVZ CSR metadata
target/loongarch: add vm level 1 definition
target/loongarch: add definition about guest mmu_idx
target/loongarch: add LVZ guest interrupt state
target/loongarch: add LVZ guest timer
target/loongarch: handle return to guest in ertn
target/loongarch: handle LVZ exception and vm_exit
target/loongarch: add host TLBRet and handle
target/loongarch: add gid management functions
target/loongarch: add LVZ parameters to TLB functions
target/loongarch: add LVZ to TLB functions
target/loongarch: add LVZ to invtlb
target/loongarch: add LVZ to ptw
target/loongarch: add LVZ migration state
target/loongarch: add gcsr instructions and vm level 1 csr management
target/loongarch: add LVZ CSRs
target/loongarch: translate LVZ guest TLB instructions
target/loongarch: translate LVZ guest traps and HVC
target/loongarch: initialize CSR related to LVZ
target/loongarch: exit to vm level 0 for fpd, sxd and asxd of vm level
0
target/loongarch/cpu-csr.h | 38 ++
target/loongarch/cpu-mmu.h | 36 +-
target/loongarch/cpu.c | 87 +++-
target/loongarch/cpu.h | 105 ++++-
target/loongarch/cpu_helper.c | 73 ++--
target/loongarch/csr.c | 102 ++---
target/loongarch/csr.h | 1 +
target/loongarch/disas.c | 15 +
target/loongarch/insns.decode | 14 +
target/loongarch/internals.h | 4 +-
target/loongarch/machine.c | 104 +++++
target/loongarch/tcg/csr_helper.c | 131 ++++--
target/loongarch/tcg/helper.h | 49 ++-
.../tcg/insn_trans/trans_extra.c.inc | 5 +
.../tcg/insn_trans/trans_privileged.c.inc | 290 +++++++++++--
target/loongarch/tcg/op_helper.c | 37 ++
target/loongarch/tcg/tcg_cpu.c | 94 +++--
target/loongarch/tcg/tcg_loongarch.h | 3 +-
target/loongarch/tcg/tlb_helper.c | 395 ++++++++++++------
target/loongarch/tcg/translate.c | 3 +
target/loongarch/translate.h | 1 +
21 files changed, 1245 insertions(+), 342 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v5 01/23] target/loongarch: select sys state by VM level
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
@ 2026-10-09 3:04 ` SignKirigami
2026-10-10 3:21 ` Bibo Mao
2026-10-09 3:04 ` [PATCH v5 02/23] target/loongarch: add get_sys() helper SignKirigami
` (21 subsequent siblings)
22 siblings, 1 reply; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami
Define VM_LEVEL0 and VM_LEVELS for the available VM levels. Replace
set_sys_state(), which accepted a CPUSysState pointer, with set_sys(),
which selects a state by VM level. There is no function change in this
patch.
---
target/loongarch/cpu.c | 4 ++--
target/loongarch/cpu.h | 7 +++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 54c2699897..6c6e1d81b8 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -298,7 +298,7 @@ static void loongarch_la464_initfn(Object *obj)
uint32_t data = 0, field;
int i;
- set_sys_state(env, &env->sys_states[0]);
+ set_sys(env, VM_LEVEL0);
for (i = 0; i < 21; i++) {
env->cpucfg[i] = 0x0;
}
@@ -428,7 +428,7 @@ static void loongarch_la132_initfn(Object *obj)
uint32_t data = 0;
int i;
- set_sys_state(env, &env->sys_states[0]);
+ set_sys(env, VM_LEVEL0);
for (i = 0; i < 21; i++) {
env->cpucfg[i] = 0x0;
}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index c592f69885..391445f614 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -321,6 +321,9 @@ typedef struct CPUTimerState {
CPUState *cs;
} CPUTimerState;
+#define VM_LEVEL0 0
+#define VM_LEVELS 1
+
#define CPU_VENDOR_LOONGSON "Loongson"
#define CPU_MODEL_3A5000 "3A5000"
#define CPU_MODEL_1C101 "1C101"
@@ -507,9 +510,9 @@ static inline CPUSysState *env_sys(CPULoongArchState *env)
return env->sys_state;
}
-static inline void set_sys_state(CPULoongArchState *env, CPUSysState *sys)
+static inline void set_sys(CPULoongArchState *env, int vm_level)
{
- env->sys_state = sys;
+ env->sys_state = &env->sys_states[vm_level];
}
static inline CPUTimerState *env_timer(CPULoongArchState *env)
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 02/23] target/loongarch: add get_sys() helper
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
2026-10-09 3:04 ` [PATCH v5 01/23] target/loongarch: select sys state by VM level SignKirigami
@ 2026-10-09 3:04 ` SignKirigami
2026-10-10 3:21 ` Bibo Mao
2026-10-09 3:04 ` [PATCH v5 03/23] target/loongarch: add LVZ feature switcher SignKirigami
` (20 subsequent siblings)
22 siblings, 1 reply; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add get_sys() to retrieve a CPUSysState by VM level. Use it to access
the host state in CPU reset path to handle possible reset requests under
vm_level 1.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.c | 2 +-
target/loongarch/cpu.h | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 6c6e1d81b8..e1245235be 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -621,7 +621,7 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
CPUState *cs = CPU(obj);
LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(obj);
CPULoongArchState *env = cpu_env(cs);
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, VM_LEVEL0);
if (lacc->parent_phases.hold) {
lacc->parent_phases.hold(obj, type);
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 391445f614..c0edcc9065 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -515,6 +515,11 @@ static inline void set_sys(CPULoongArchState *env, int vm_level)
env->sys_state = &env->sys_states[vm_level];
}
+static inline CPUSysState *get_sys(CPULoongArchState *env, int vm_level)
+{
+ return &env->sys_states[vm_level];
+}
+
static inline CPUTimerState *env_timer(CPULoongArchState *env)
{
return &env->sys_states[0].timer_state;
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 03/23] target/loongarch: add LVZ feature switcher
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
2026-10-09 3:04 ` [PATCH v5 01/23] target/loongarch: select sys state by VM level SignKirigami
2026-10-09 3:04 ` [PATCH v5 02/23] target/loongarch: add get_sys() helper SignKirigami
@ 2026-10-09 3:04 ` SignKirigami
2026-10-10 3:20 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 04/23] target/loongarch: add LVZ CSR metadata SignKirigami
` (19 subsequent siblings)
22 siblings, 1 reply; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add LVZ property and AVAIL_LVZ macro based on cpucfg.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.c | 33 +++++++++++++++++++++++++++++++--
target/loongarch/cpu.h | 6 ++++++
target/loongarch/translate.h | 1 +
3 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index e1245235be..664763137d 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -267,11 +267,33 @@ static void loongarch_set_ptw(Object *obj, bool value, Error **errp)
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, HPTW, value);
}
+static bool loongarch_get_lvz(Object *obj, Error **errp)
+{
+ return LOONGARCH_CPU(obj)->lvz != ON_OFF_AUTO_OFF;
+}
+
+static void loongarch_set_lvz(Object *obj, bool value, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu->lvz = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+
+ if (kvm_enabled()) {
+ /* lvz can not be only enabled in kvm mode currently */
+ return;
+ }
+
+ cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LVZ, value);
+ cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LVZ_VER,
+ value ? 1 : 0);
+}
+
static void loongarch_cpu_post_init(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
cpu->lbt = ON_OFF_AUTO_OFF;
+ cpu->lvz = ON_OFF_AUTO_AUTO;
cpu->pmu = ON_OFF_AUTO_OFF;
cpu->lsx = ON_OFF_AUTO_AUTO;
cpu->lasx = ON_OFF_AUTO_AUTO;
@@ -283,6 +305,9 @@ static void loongarch_cpu_post_init(Object *obj)
loongarch_set_msgint);
object_property_add_bool(obj, "ptw", loongarch_get_ptw,
loongarch_set_ptw);
+ object_property_add_bool(obj, "lvz", loongarch_get_lvz,
+ loongarch_set_lvz);
+
/* lbt is enabled only in kvm mode, not supported in tcg mode */
if (kvm_enabled()) {
@@ -336,8 +361,12 @@ static void loongarch_la464_initfn(Object *obj)
data = FIELD_DP32(data, CPUCFG2, FP_SP, 1);
data = FIELD_DP32(data, CPUCFG2, FP_DP, 1);
data = FIELD_DP32(data, CPUCFG2, FP_VER, 1);
- data = FIELD_DP32(data, CPUCFG2, LSX, 1),
- data = FIELD_DP32(data, CPUCFG2, LASX, 1),
+ data = FIELD_DP32(data, CPUCFG2, LSX, 1);
+ data = FIELD_DP32(data, CPUCFG2, LASX, 1);
+ if (tcg_enabled()) {
+ data = FIELD_DP32(data, CPUCFG2, LVZ, 1);
+ data = FIELD_DP32(data, CPUCFG2, LVZ_VER, 1);
+ }
data = FIELD_DP32(data, CPUCFG2, LLFTP, 1);
data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1);
data = FIELD_DP32(data, CPUCFG2, LSPW, 1);
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index c0edcc9065..918378ee9a 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -460,6 +460,7 @@ struct ArchCPU {
CPULoongArchState env;
uint32_t phy_id;
OnOffAuto lbt;
+ OnOffAuto lvz;
OnOffAuto pmu;
OnOffAuto ptw;
OnOffAuto lsx;
@@ -520,6 +521,11 @@ static inline CPUSysState *get_sys(CPULoongArchState *env, int vm_level)
return &env->sys_states[vm_level];
}
+static inline bool cpu_has_lvz(CPULoongArchState *env)
+{
+ return FIELD_EX32(env->cpucfg[2], CPUCFG2, LVZ);
+}
+
static inline CPUTimerState *env_timer(CPULoongArchState *env)
{
return &env->sys_states[0].timer_state;
diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h
index 8aa8325dc6..a7c165982c 100644
--- a/target/loongarch/translate.h
+++ b/target/loongarch/translate.h
@@ -24,6 +24,7 @@
#define avail_FP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP))
#define avail_FP_SP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_SP))
#define avail_FP_DP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_DP))
+#define avail_LVZ(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LVZ))
#define avail_LSPW(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSPW))
#define avail_LAM(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM))
#define avail_LAM_BH(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM_BH))
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 04/23] target/loongarch: add LVZ CSR metadata
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (2 preceding siblings ...)
2026-10-09 3:04 ` [PATCH v5 03/23] target/loongarch: add LVZ feature switcher SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 05/23] target/loongarch: add vm level 1 definition SignKirigami
` (18 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add LVZ host and guest CSR access metadata to the existing CSR table. Mark
guest read-only and unavailable CSRs for later LVZ instruction translation.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu-csr.h | 38 ++++++++++++++
target/loongarch/cpu.h | 6 +++
target/loongarch/csr.c | 102 ++++++++++++++++++++-----------------
target/loongarch/csr.h | 1 +
target/loongarch/disas.c | 5 ++
5 files changed, 104 insertions(+), 48 deletions(-)
diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
index d860417af2..e0061e57c3 100644
--- a/target/loongarch/cpu-csr.h
+++ b/target/loongarch/cpu-csr.h
@@ -224,4 +224,42 @@ FIELD(CSR_DBG, ECODE, 16, 6)
#define LOONGARCH_CSR_DERA 0x501 /* Debug era */
#define LOONGARCH_CSR_DSAVE 0x502 /* Debug save */
+/* LVZ (LoongArch Virtualization) CSRs */
+#define LOONGARCH_CSR_GTLBC 0x15 /* Guest TLB control */
+FIELD(CSR_GTLBC, GMTLBSZ, 0, 6)
+FIELD(CSR_GTLBC, USETGID, 12, 1)
+FIELD(CSR_GTLBC, TOTI, 13, 1)
+FIELD(CSR_GTLBC, TGID, 16, 8)
+
+#define LOONGARCH_CSR_GSTAT 0x50 /* Guest status */
+FIELD(CSR_GSTAT, VM, 0, 1)
+FIELD(CSR_GSTAT, PVM, 1, 1)
+FIELD(CSR_GSTAT, GIDBITS, 4, 6)
+FIELD(CSR_GSTAT, GID, 16, 8)
+
+#define LOONGARCH_CSR_GCFG 0x51 /* Guest config */
+FIELD(CSR_GCFG, MATP, 0, 4)
+FIELD(CSR_GCFG, MATC, 4, 2)
+FIELD(CSR_GCFG, TOPIP, 6, 1)
+FIELD(CSR_GCFG, TOPI, 7, 1)
+FIELD(CSR_GCFG, TOTIP, 8, 1)
+FIELD(CSR_GCFG, TOTI, 9, 1)
+FIELD(CSR_GCFG, TOEP, 10, 1)
+FIELD(CSR_GCFG, TOE, 11, 1)
+FIELD(CSR_GCFG, TOPP, 12, 1)
+FIELD(CSR_GCFG, TOP, 13, 1)
+FIELD(CSR_GCFG, TOHUP, 14, 1)
+FIELD(CSR_GCFG, TOHU, 15, 1)
+FIELD(CSR_GCFG, TOCIP, 16, 4)
+FIELD(CSR_GCFG, TOCI, 20, 2)
+FIELD(CSR_GCFG, GPMP, 23, 1)
+FIELD(CSR_GCFG, GPMNUM, 24, 3)
+
+#define LOONGARCH_CSR_GINTC 0x52 /* Guest interrupt config */
+FIELD(CSR_GINTC, HWIS, 0, 8)
+FIELD(CSR_GINTC, HWIP, 8, 8)
+FIELD(CSR_GINTC, HWIC, 16, 8)
+
+#define LOONGARCH_CSR_GCNTC 0x53 /* Guest counter compensation */
+
#endif /* LOONGARCH_CPU_CSR_H */
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 918378ee9a..0b7d63d8f3 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -255,6 +255,7 @@ FIELD(TLB_MISC, E, 0, 1)
FIELD(TLB_MISC, ASID, 1, 10)
FIELD(TLB_MISC, VPPN, 13, 35)
FIELD(TLB_MISC, PS, 48, 6)
+FIELD(TLB_MISC, GID, 54, 8)
/*Msg interrupt registers */
#define N_MSGIS 4
@@ -381,6 +382,10 @@ typedef struct CPUSysState {
uint64_t CSR_DBG;
uint64_t CSR_DERA;
uint64_t CSR_DSAVE;
+ uint64_t CSR_GCFG;
+ uint64_t CSR_GINTC;
+ uint64_t CSR_GCNTC;
+ uint64_t CSR_GTLBC;
/* Msg interrupt registers */
uint64_t CSR_MSGIS[N_MSGIS];
uint64_t CSR_MSGIR;
@@ -389,6 +394,7 @@ typedef struct CPUSysState {
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
+ uint64_t CSR_GSTAT;
uint64_t CSR_ASID;
uint64_t CSR_PRCFG1;
uint64_t CSR_PRCFG2;
diff --git a/target/loongarch/csr.c b/target/loongarch/csr.c
index d2ac39dee9..1ca9e9580e 100644
--- a/target/loongarch/csr.c
+++ b/target/loongarch/csr.c
@@ -13,15 +13,16 @@
.flags = FL, .readfn = RD, .writefn = WR \
}
-#define CSR_OFF_ARRAY(NAME, N) \
- [LOONGARCH_CSR_##NAME(N)] = { \
- .name = (stringify(NAME##N)), \
- .offset = CSR_OFFSET(CSR_##NAME[N]), \
- .flags = CSRFL_BASIC, .readfn = NULL, .writefn = NULL \
- }
+#define CSR_OFF_ARRAY_FLAGS(NAME, N, FL) \
+ [LOONGARCH_CSR_##NAME(N)] = { \
+ .name = (stringify(NAME##N)), \
+ .offset = CSR_OFFSET(CSR_##NAME[N]), \
+ .flags = FL \
+ }
#define CSR_OFF_FLAGS(NAME, FL) CSR_OFF_FUNCS(NAME, FL, NULL, NULL)
#define CSR_OFF(NAME) CSR_OFF_FLAGS(NAME, CSRFL_BASIC)
+#define CSR_OFF_ARRAY(NAME, N) CSR_OFF_ARRAY_FLAGS(NAME, N, CSRFL_BASIC)
static CSRInfo csr_info[] = {
CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB),
@@ -71,9 +72,14 @@ static CSRInfo csr_info[] = {
CSR_OFF_FLAGS(TVAL, CSRFL_READONLY | CSRFL_IO),
CSR_OFF(CNTC),
CSR_OFF_FLAGS(TICLR, CSRFL_IO),
+ CSR_OFF_FLAGS(GTLBC, CSRFL_GSPR),
+ CSR_OFF_FLAGS(GSTAT, CSRFL_GSPR),
+ CSR_OFF_FLAGS(GCFG, CSRFL_GSPR),
+ CSR_OFF_FLAGS(GINTC, CSRFL_IO | CSRFL_GSPR),
+ CSR_OFF_FLAGS(GCNTC, CSRFL_GSPR),
CSR_OFF(LLBCTL),
- CSR_OFF(IMPCTL1),
- CSR_OFF(IMPCTL2),
+ CSR_OFF_FLAGS(IMPCTL1, CSRFL_GSPR),
+ CSR_OFF_FLAGS(IMPCTL2, CSRFL_GSPR),
CSR_OFF(TLBRENTRY),
CSR_OFF(TLBRBADV),
CSR_OFF(TLBRERA),
@@ -87,46 +93,46 @@ static CSRInfo csr_info[] = {
CSR_OFF_ARRAY(DMW, 1),
CSR_OFF_ARRAY(DMW, 2),
CSR_OFF_ARRAY(DMW, 3),
- CSR_OFF_ARRAY(PERFCTRL, 0),
- CSR_OFF_ARRAY(PERFCNTR, 0),
- CSR_OFF_ARRAY(PERFCTRL, 1),
- CSR_OFF_ARRAY(PERFCNTR, 1),
- CSR_OFF_ARRAY(PERFCTRL, 2),
- CSR_OFF_ARRAY(PERFCNTR, 2),
- CSR_OFF_ARRAY(PERFCTRL, 3),
- CSR_OFF_ARRAY(PERFCNTR, 3),
- CSR_OFF_ARRAY(PERFCTRL, 4),
- CSR_OFF_ARRAY(PERFCNTR, 4),
- CSR_OFF_ARRAY(PERFCTRL, 5),
- CSR_OFF_ARRAY(PERFCNTR, 5),
- CSR_OFF_ARRAY(PERFCTRL, 6),
- CSR_OFF_ARRAY(PERFCNTR, 6),
- CSR_OFF_ARRAY(PERFCTRL, 7),
- CSR_OFF_ARRAY(PERFCNTR, 7),
- CSR_OFF_ARRAY(PERFCTRL, 8),
- CSR_OFF_ARRAY(PERFCNTR, 8),
- CSR_OFF_ARRAY(PERFCTRL, 9),
- CSR_OFF_ARRAY(PERFCNTR, 9),
- CSR_OFF_ARRAY(PERFCTRL, 10),
- CSR_OFF_ARRAY(PERFCNTR, 10),
- CSR_OFF_ARRAY(PERFCTRL, 11),
- CSR_OFF_ARRAY(PERFCNTR, 11),
- CSR_OFF_ARRAY(PERFCTRL, 12),
- CSR_OFF_ARRAY(PERFCNTR, 12),
- CSR_OFF_ARRAY(PERFCTRL, 13),
- CSR_OFF_ARRAY(PERFCNTR, 13),
- CSR_OFF_ARRAY(PERFCTRL, 14),
- CSR_OFF_ARRAY(PERFCNTR, 14),
- CSR_OFF_ARRAY(PERFCTRL, 15),
- CSR_OFF_ARRAY(PERFCNTR, 15),
- CSR_OFF(DBG),
- CSR_OFF(DERA),
- CSR_OFF(DSAVE),
- CSR_OFF_ARRAY(MSGIS, 0),
- CSR_OFF_ARRAY(MSGIS, 1),
- CSR_OFF_ARRAY(MSGIS, 2),
- CSR_OFF_ARRAY(MSGIS, 3),
- CSR_OFF(MSGIR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 0, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 0, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 1, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 1, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 2, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 2, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 3, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 3, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 4, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 4, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 5, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 5, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 6, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 6, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 7, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 7, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 8, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 8, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 9, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 9, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 10, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 10, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 11, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 11, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 12, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 12, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 13, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 13, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 14, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 14, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCTRL, 15, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(PERFCNTR, 15, CSRFL_GSPR),
+ CSR_OFF_FLAGS(DBG, CSRFL_GSPR),
+ CSR_OFF_FLAGS(DERA, CSRFL_GSPR),
+ CSR_OFF_FLAGS(DSAVE, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(MSGIS, 0, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(MSGIS, 1, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(MSGIS, 2, CSRFL_GSPR),
+ CSR_OFF_ARRAY_FLAGS(MSGIS, 3, CSRFL_GSPR),
+ CSR_OFF_FLAGS(MSGIR, CSRFL_GSPR),
};
CSRInfo *get_csr(unsigned int csr_num)
diff --git a/target/loongarch/csr.h b/target/loongarch/csr.h
index c2b6b882bc..393ac09b61 100644
--- a/target/loongarch/csr.h
+++ b/target/loongarch/csr.h
@@ -20,6 +20,7 @@ enum {
CSRFL_IO = (1 << 2),
CSRFL_UNUSED = (1 << 3),
CSRFL_BASIC = (1 << 4),
+ CSRFL_GSPR = (1 << 5),
};
typedef struct {
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 928b8b94c2..03d1e560dd 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -87,6 +87,11 @@ static const char * const csr_names[] = {
CSR_NAME(TVAL),
CSR_NAME(CNTC),
CSR_NAME(TICLR),
+ CSR_NAME(GTLBC),
+ CSR_NAME(GSTAT),
+ CSR_NAME(GCFG),
+ CSR_NAME(GINTC),
+ CSR_NAME(GCNTC),
CSR_NAME(LLBCTL),
CSR_NAME(IMPCTL1),
CSR_NAME(IMPCTL2),
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 05/23] target/loongarch: add vm level 1 definition
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (3 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 04/23] target/loongarch: add LVZ CSR metadata SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 06/23] target/loongarch: add definition about guest mmu_idx SignKirigami
` (17 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add VM_LEVEL1 macro, env_vm_level() and trigger_vm_exit() functions, preparing
for later interrupt virtualization.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.h | 24 ++++++++++++++++++++++--
target/loongarch/tcg/tcg_cpu.c | 3 +++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 0b7d63d8f3..183210efd8 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -323,7 +323,8 @@ typedef struct CPUTimerState {
} CPUTimerState;
#define VM_LEVEL0 0
-#define VM_LEVELS 1
+#define VM_LEVEL1 1
+#define VM_LEVELS 2
#define CPU_VENDOR_LOONGSON "Loongson"
#define CPU_MODEL_3A5000 "3A5000"
@@ -434,7 +435,7 @@ typedef struct CPUArchState {
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
- CPUSysState sys_states[1];
+ CPUSysState sys_states[VM_LEVELS];
uint32_t cpucfg[21];
uint32_t pv_features;
uint64_t vendor_id;
@@ -446,6 +447,7 @@ typedef struct CPUArchState {
uint32_t mp_state;
#endif
CPUSysState *sys_state;
+ bool vm_exit;
} CPULoongArchState;
typedef struct LoongArchCPUTopo {
@@ -517,6 +519,11 @@ static inline CPUSysState *env_sys(CPULoongArchState *env)
return env->sys_state;
}
+static inline int env_vm_level(CPULoongArchState *env)
+{
+ return env_sys(env) - env->sys_states;
+}
+
static inline void set_sys(CPULoongArchState *env, int vm_level)
{
env->sys_state = &env->sys_states[vm_level];
@@ -532,6 +539,18 @@ static inline bool cpu_has_lvz(CPULoongArchState *env)
return FIELD_EX32(env->cpucfg[2], CPUCFG2, LVZ);
}
+static inline void trigger_vm_exit(CPULoongArchState *env)
+{
+ CPUSysState *host = get_sys(env, VM_LEVEL0);
+
+ if (env_vm_level(env) != VM_LEVEL1) {
+ return;
+ }
+
+ host->CSR_GSTAT = FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, PVM, 1);
+ env->vm_exit = true;
+}
+
static inline CPUTimerState *env_timer(CPULoongArchState *env)
{
return &env->sys_states[0].timer_state;
@@ -572,6 +591,7 @@ static inline void set_pc(CPULoongArchState *env, uint64_t value)
#define HW_FLAGS_CRMD_PG R_CSR_CRMD_PG_MASK /* 0x10 */
#define HW_FLAGS_VA32 0x20
#define HW_FLAGS_EUEN_ASXE 0x40
+#define HW_FLAGS_GUEST_MODE 0x80
#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index 4b1d44a164..14fa5f5809 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -279,6 +279,9 @@ static TCGTBCPUState loongarch_get_tb_cpu_state(CPUState *cs)
uint32_t flags;
flags = sys->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK);
+ if (env_vm_level(env) == VM_LEVEL1) {
+ flags |= HW_FLAGS_GUEST_MODE;
+ }
flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE;
flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE;
flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_ASXE;
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 06/23] target/loongarch: add definition about guest mmu_idx
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (4 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 05/23] target/loongarch: add vm level 1 definition SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-10 3:36 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 07/23] target/loongarch: add LVZ guest interrupt state SignKirigami
` (16 subsequent siblings)
22 siblings, 1 reply; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add MMU_GUEST_IDX and MMU_GUEST_DA_IDX. Provide is_guest_mmu idx() and
mmu_idx_to_plv to calculate plv with new mmu_idx.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.h | 18 ++++++++++++++++++
.../tcg/insn_trans/trans_privileged.c.inc | 2 +-
target/loongarch/tcg/tcg_cpu.c | 7 +++++++
target/loongarch/tcg/translate.c | 3 +++
4 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 183210efd8..9eea1badaf 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -513,6 +513,24 @@ struct LoongArchCPUClass {
#define MMU_KERNEL_IDX MMU_PLV_KERNEL
#define MMU_USER_IDX MMU_PLV_USER
#define MMU_DA_IDX 4
+#define MMU_GUEST_IDX 5
+#define MMU_GUEST_DA_IDX 9
+
+static inline bool is_guest_mmu_idx(int mmu_idx)
+{
+ return mmu_idx >= MMU_GUEST_IDX;
+}
+
+static inline int mmu_idx_to_plv(int mmu_idx)
+{
+ if (mmu_idx == MMU_DA_IDX || mmu_idx == MMU_GUEST_DA_IDX) {
+ return 0;
+ }
+ if (is_guest_mmu_idx(mmu_idx)) {
+ return mmu_idx - MMU_GUEST_IDX;
+ }
+ return mmu_idx;
+}
static inline CPUSysState *env_sys(CPULoongArchState *env)
{
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 6728ce5ec9..7ee3bb8e27 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -249,7 +249,7 @@ TRANS64(iocsrwr_d, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_d)
static void check_mmu_idx(DisasContext *ctx)
{
- if (ctx->mem_idx != MMU_DA_IDX) {
+ if (ctx->mem_idx != MMU_DA_IDX && ctx->mem_idx != MMU_GUEST_DA_IDX) {
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
}
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index 14fa5f5809..b60d9e7cf8 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -309,6 +309,13 @@ static int loongarch_cpu_mmu_index(CPUState *cs, bool ifetch)
CPULoongArchState *env = cpu_env(cs);
CPUSysState *sys = env_sys(env);
+ if (env_vm_level(env) == VM_LEVEL1) {
+ if (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PG)) {
+ return MMU_GUEST_IDX + FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PLV);
+ }
+ return MMU_GUEST_DA_IDX;
+ }
+
if (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PG)) {
return FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PLV);
}
diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c
index 124dce6269..4ab06b48da 100644
--- a/target/loongarch/tcg/translate.c
+++ b/target/loongarch/tcg/translate.c
@@ -129,6 +129,9 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
} else {
ctx->mem_idx = MMU_DA_IDX;
}
+ if (ctx->base.tb->flags & HW_FLAGS_GUEST_MODE) {
+ ctx->mem_idx += MMU_GUEST_IDX;
+ }
/* Bound the number of insns to execute to those left on the page. */
bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 07/23] target/loongarch: add LVZ guest interrupt state
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (5 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 06/23] target/loongarch: add definition about guest mmu_idx SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-10 4:03 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 08/23] target/loongarch: add LVZ guest timer SignKirigami
` (15 subsequent siblings)
22 siblings, 1 reply; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Route configured hardware interrupts into the guest CSR bank, track guest
interrupt requests separately, and expose guest pending and enable checks
to the TCG runtime.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.c | 35 +++++++++++++++++++--------
target/loongarch/cpu.h | 3 +++
target/loongarch/internals.h | 4 ++--
target/loongarch/tcg/csr_helper.c | 2 +-
target/loongarch/tcg/tcg_cpu.c | 39 ++++++++++++++++++++++---------
5 files changed, 59 insertions(+), 24 deletions(-)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 664763137d..5cef63a778 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -58,16 +58,20 @@ static vaddr loongarch_cpu_get_pc(CPUState *cs)
#ifndef CONFIG_USER_ONLY
#include "hw/loongarch/virt.h"
-void loongarch_cpu_update_irq(LoongArchCPU *cpu)
+void loongarch_cpu_update_irq(LoongArchCPU *cpu, int vm_level)
{
CPULoongArchState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
+ int interrupt = vm_level ? CPU_INTERRUPT_GUEST : CPU_INTERRUPT_HARD;
+ if (vm_level == VM_LEVEL1 && env_vm_level(env) != VM_LEVEL1) {
+ return;
+ }
if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ cpu_interrupt(cs, interrupt);
} else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+ cpu_reset_interrupt(cs, interrupt);
}
}
@@ -75,21 +79,28 @@ static void loongarch_cpu_self_set_irq(CPUState *cs, run_on_cpu_data data)
{
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = cpu_env(cs);
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys;
+ int vm_level = 0;
int irq, level;
irq = data.host_int & ~BIT(31);
level = (data.host_int >> 31) & 1;
+ if (irq >= N_IRQS) {
+ irq -= N_IRQS;
+ vm_level = 1;
+ }
+ sys = get_sys(env, vm_level);
sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, irq, 1, level != 0);
- loongarch_cpu_update_irq(cpu);
+ loongarch_cpu_update_irq(cpu, vm_level);
}
void loongarch_cpu_set_irq(void *opaque, int irq, int level)
{
LoongArchCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
+ CPULoongArchState *env = cpu_env(cs);
- if (irq < 0 || irq >= N_IRQS) {
+ if (irq < 0 || irq >= (cpu_has_lvz(env) ? N_VIRQS : N_IRQS)) {
return;
}
@@ -103,11 +114,11 @@ void loongarch_cpu_set_irq(void *opaque, int irq, int level)
}
/* Check if there is pending and not masked out interrupt */
-bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
+bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env, int vm_level)
{
uint32_t pending;
uint32_t status;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
pending = FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS);
status = FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, LIE);
@@ -122,7 +133,11 @@ bool loongarch_cpu_has_work(CPUState *cs)
bool has_work = false;
if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD) &&
- cpu_loongarch_hw_interrupts_pending(cpu_env(cs))) {
+ cpu_loongarch_hw_interrupts_pending(cpu_env(cs), VM_LEVEL0)) {
+ has_work = true;
+ }
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_GUEST) &&
+ cpu_loongarch_hw_interrupts_pending(cpu_env(cs), VM_LEVEL1)) {
has_work = true;
}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 9eea1badaf..8939dbc748 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -20,6 +20,8 @@
#include "cpu-csr.h"
#include "cpu-qom.h"
+#define CPU_INTERRUPT_GUEST CPU_INTERRUPT_TGT_EXT_0
+
#define FCSR0_M1 0x1f /* FCSR1 mask, Enables */
#define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */
#define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */
@@ -242,6 +244,7 @@ extern const char * const fregnames[32];
#define IRQ_TIMER 11
#define IRQ_IPI 12
#define INT_DMSI 14
+#define N_VIRQS (N_IRQS * 2)
#define MAX_PERF_EVENTS 16
#define LOONGARCH_STLB 2048 /* 2048 STLB */
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index ff956823fd..c11cefc4ee 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -31,7 +31,7 @@ void restore_fp_status(CPULoongArchState *env);
#ifndef CONFIG_USER_ONLY
extern const VMStateDescription vmstate_loongarch_cpu;
-void loongarch_cpu_update_irq(LoongArchCPU *cpu);
+void loongarch_cpu_update_irq(LoongArchCPU *cpu, int vm_level);
void loongarch_cpu_set_irq(void *opaque, int irq, int level);
void cpu_loongarch_timer_cb(void *opaque);
@@ -39,7 +39,7 @@ uint64_t cpu_loongarch_get_timer_counter(CPUTimerState *timer);
uint64_t cpu_loongarch_get_timer_ticks(CPUTimerState *timer);
void cpu_loongarch_set_timer_config(CPUTimerState *timer, uint64_t value);
bool loongarch_cpu_has_work(CPUState *cs);
-bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env);
+bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env, int vm_level);
#endif /* !CONFIG_USER_ONLY */
uint64_t read_fcc(CPULoongArchState *env);
diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c
index 1a6919417f..ecfba63228 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -111,7 +111,7 @@ target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
*/
if (sys->CSR_ESTAT != old_v) {
bql_lock();
- loongarch_cpu_update_irq(env_archcpu(env));
+ loongarch_cpu_update_irq(env_archcpu(env), false);
bql_unlock();
}
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index b60d9e7cf8..101fe6fc7a 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -238,30 +238,47 @@ static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
}
}
-static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
+static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env, int vm_level)
{
bool ret = 0;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
+ CPUSysState *host = get_sys(env, VM_LEVEL0);
ret = (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, IE) &&
- !(FIELD_EX64(sys->CSR_DBG, CSR_DBG, DST)));
+ !(FIELD_EX64(host->CSR_DBG, CSR_DBG, DST)));
return ret;
}
static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
+ CPULoongArchState *env = cpu_env(cs);
+ bool has_interrupt = false;
+
if (interrupt_request & CPU_INTERRUPT_HARD) {
- CPULoongArchState *env = cpu_env(cs);
-
- if (cpu_loongarch_hw_interrupts_enabled(env) &&
- cpu_loongarch_hw_interrupts_pending(env)) {
- /* Raise it */
- cs->exception_index = EXCCODE_INT;
- loongarch_cpu_do_interrupt(cs);
- return true;
+
+ if (cpu_loongarch_hw_interrupts_enabled(env, VM_LEVEL0) &&
+ cpu_loongarch_hw_interrupts_pending(env, VM_LEVEL0)) {
+ if (env_vm_level(env) != VM_LEVEL0) {
+ trigger_vm_exit(env);
+ }
+ has_interrupt = true;
}
+ } else if (interrupt_request & CPU_INTERRUPT_GUEST) {
+ if (cpu_loongarch_hw_interrupts_enabled(env, VM_LEVEL1) &&
+ cpu_loongarch_hw_interrupts_pending(env, VM_LEVEL1) &&
+ env_vm_level(env) == VM_LEVEL1) {
+ has_interrupt = true;
+ }
+ }
+
+ if (has_interrupt) {
+ /* Raise it */
+ cs->exception_index = EXCCODE_INT;
+ loongarch_cpu_do_interrupt(cs);
+ return true;
}
+
return false;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 08/23] target/loongarch: add LVZ guest timer
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (6 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 07/23] target/loongarch: add LVZ guest interrupt state SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-10 4:07 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 09/23] target/loongarch: handle return to guest in ertn SignKirigami
` (14 subsequent siblings)
22 siblings, 1 reply; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add a separate guest timer and IRQ_VTIMER.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.c | 8 +++++++-
target/loongarch/cpu.h | 6 ++++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 5cef63a778..8e759a2987 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -770,7 +770,7 @@ static void loongarch_cpu_init(Object *obj)
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
#ifdef CONFIG_TCG
CPULoongArchState *env = &cpu->env;
- CPUTimerState *timer;
+ CPUTimerState *timer, *guest_timer;
#endif
qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
@@ -778,8 +778,14 @@ static void loongarch_cpu_init(Object *obj)
timer = env_timer(env);
timer->irq = IRQ_TIMER;
timer->cs = CPU(obj);
+ guest_timer = env_guest_timer(env);
+ guest_timer->irq = IRQ_VTIMER;
+ guest_timer->cs = CPU(obj);
+
timer_init_ns(&timer->timer, QEMU_CLOCK_VIRTUAL,
&cpu_loongarch_timer_cb, timer);
+ timer_init_ns(&guest_timer->timer, QEMU_CLOCK_VIRTUAL,
+ &cpu_loongarch_timer_cb, guest_timer);
#endif
#endif
}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 8939dbc748..ba28d80272 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -245,6 +245,7 @@ extern const char * const fregnames[32];
#define IRQ_IPI 12
#define INT_DMSI 14
#define N_VIRQS (N_IRQS * 2)
+#define IRQ_VTIMER (N_IRQS + IRQ_TIMER)
#define MAX_PERF_EVENTS 16
#define LOONGARCH_STLB 2048 /* 2048 STLB */
@@ -577,6 +578,11 @@ static inline CPUTimerState *env_timer(CPULoongArchState *env)
return &env->sys_states[0].timer_state;
}
+static inline CPUTimerState *env_guest_timer(CPULoongArchState *env)
+{
+ return &env->sys_states[1].timer_state;
+}
+
static inline bool is_la64(CPULoongArchState *env)
{
return FIELD_EX32(env->cpucfg[1], CPUCFG1, ARCH) == CPUCFG1_ARCH_LA64;
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 09/23] target/loongarch: handle return to guest in ertn
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (7 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 08/23] target/loongarch: add LVZ guest timer SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 10/23] target/loongarch: handle LVZ exception and vm_exit SignKirigami
` (13 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add will_return_to_guest() function, and handle process of return to guest at
end of helper_ertn().
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.h | 8 ++++++++
target/loongarch/tcg/op_helper.c | 14 ++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ba28d80272..891eea47bd 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -573,6 +573,14 @@ static inline void trigger_vm_exit(CPULoongArchState *env)
env->vm_exit = true;
}
+static inline bool will_return_to_guest(CPULoongArchState *env)
+{
+ if (!cpu_has_lvz(env) || env_vm_level(env) == VM_LEVEL1) {
+ return false;
+ }
+ return FIELD_EX64(get_sys(env, VM_LEVEL0)->CSR_GSTAT, CSR_GSTAT, PVM);
+}
+
static inline CPUTimerState *env_timer(CPULoongArchState *env)
{
return &env->sys_states[0].timer_state;
diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c
index f98fe4d4a1..3035dfa08d 100644
--- a/target/loongarch/tcg/op_helper.c
+++ b/target/loongarch/tcg/op_helper.c
@@ -12,6 +12,7 @@
#include "exec/helper-proto.h"
#include "accel/tcg/cpu-ldst.h"
#include "internals.h"
+#include "qemu/main-loop.h"
#include "qemu/crc32c.h"
#include <zlib.h> /* for crc32 */
#include "cpu-csr.h"
@@ -90,6 +91,8 @@ void helper_ertn(CPULoongArchState *env)
{
uint64_t csr_pplv, csr_pie;
CPUSysState *sys = env_sys(env);
+ CPUSysState *host = get_sys(env, VM_LEVEL0);
+ CPUSysState *guest = get_sys(env, VM_LEVEL1);
if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
csr_pplv = FIELD_EX64(sys->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV);
@@ -113,6 +116,17 @@ void helper_ertn(CPULoongArchState *env)
sys->CSR_CRMD = FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, IE, csr_pie);
env->lladdr = 1;
+ if (will_return_to_guest(env)) {
+ host->CSR_GSTAT = FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, VM, 1);
+ set_sys(env, VM_LEVEL1);
+ bql_lock();
+ if (FIELD_EX64(guest->CSR_ESTAT, CSR_ESTAT, IS)) {
+ cpu_interrupt(env_cpu(env), CPU_INTERRUPT_GUEST);
+ } else {
+ cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_GUEST);
+ }
+ bql_unlock();
+ }
}
void helper_idle(CPULoongArchState *env)
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 10/23] target/loongarch: handle LVZ exception and vm_exit
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (8 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 09/23] target/loongarch: handle return to guest in ertn SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 11/23] target/loongarch: add host TLBRet and handle SignKirigami
` (12 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add EXCCODE_GSPR and EXCCODE_HVC macros. Execute real vm exit at end of
loongarch_cpu_do_interrupt().
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.h | 2 ++
target/loongarch/tcg/tcg_cpu.c | 28 ++++++++++++++++++++--------
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 891eea47bd..3e3ae2bfa7 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -95,6 +95,8 @@ FIELD(FCSR0, CAUSE, 24, 5)
#define EXCCODE_WPEM EXCODE(19, 1)
#define EXCCODE_BTD EXCODE(20, 0)
#define EXCCODE_BTE EXCODE(21, 0)
+#define EXCCODE_GSPR EXCODE(22, 0)
+#define EXCCODE_HVC EXCODE(23, 0)
#define EXCCODE_DBP EXCODE(26, 0) /* Reserved subcode used for debug */
/* cpucfg[0] bits */
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index 101fe6fc7a..6f1ba12edb 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -44,6 +44,8 @@ static const struct TypeExcp excp_names[] = {
{EXCCODE_BCE, "Bound Check Exception"},
{EXCCODE_SXD, "128 bit vector instructions Disable exception"},
{EXCCODE_ASXD, "256 bit vector instructions Disable exception"},
+ {EXCCODE_GSPR, "Guest Sensitive and Privileged Resources"},
+ {EXCCODE_HVC, "Hypervisor call"},
{EXCP_HLT, "EXCP_HLT"},
};
@@ -78,9 +80,11 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
static void loongarch_cpu_do_interrupt(CPUState *cs)
{
CPULoongArchState *env = cpu_env(cs);
- CPUSysState *sys = env_sys(env);
bool update_badinstr = 1;
int cause = -1;
+ bool real_guest = !env->vm_exit && env_vm_level(env);
+ CPUSysState *sys = get_sys(env, real_guest);
+ CPUSysState *host = get_sys(env, VM_LEVEL0);
bool tlbfill = FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
uint32_t vec_size = FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, VS);
uint64_t last_pc = env->pc;
@@ -96,17 +100,17 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
switch (cs->exception_index) {
case EXCCODE_DBP:
- sys->CSR_DBG = FIELD_DP64(sys->CSR_DBG, CSR_DBG, DCL, 1);
- sys->CSR_DBG = FIELD_DP64(sys->CSR_DBG, CSR_DBG, ECODE, 0xC);
+ host->CSR_DBG = FIELD_DP64(sys->CSR_DBG, CSR_DBG, DCL, 1);
+ host->CSR_DBG = FIELD_DP64(sys->CSR_DBG, CSR_DBG, ECODE, 0xC);
goto set_DERA;
set_DERA:
- sys->CSR_DERA = env->pc;
- sys->CSR_DBG = FIELD_DP64(sys->CSR_DBG, CSR_DBG, DST, 1);
- set_pc(env, sys->CSR_EENTRY + 0x480);
+ host->CSR_DERA = env->pc;
+ host->CSR_DBG = FIELD_DP64(sys->CSR_DBG, CSR_DBG, DST, 1);
+ set_pc(env, host->CSR_EENTRY + 0x480);
break;
case EXCCODE_INT:
- if (FIELD_EX64(sys->CSR_DBG, CSR_DBG, DST)) {
- sys->CSR_DBG = FIELD_DP64(sys->CSR_DBG, CSR_DBG, DEI, 1);
+ if (FIELD_EX64(host->CSR_DBG, CSR_DBG, DST)) {
+ host->CSR_DBG = FIELD_DP64(host->CSR_DBG, CSR_DBG, DEI, 1);
goto set_DERA;
}
QEMU_FALLTHROUGH;
@@ -117,6 +121,8 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
update_badinstr = 0;
break;
case EXCCODE_BCE:
+ case EXCCODE_GSPR:
+ case EXCCODE_HVC:
sys->CSR_BADV = env->pc;
QEMU_FALLTHROUGH;
case EXCCODE_SYS:
@@ -218,6 +224,12 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
qemu_plugin_vcpu_exception_cb(cs, last_pc);
}
cs->exception_index = -1;
+ if (env->vm_exit) {
+ host->CSR_GSTAT = FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, VM, 0);
+ set_sys(env, VM_LEVEL0);
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_GUEST);
+ }
+ env->vm_exit = false;
}
static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 11/23] target/loongarch: add host TLBRet and handle
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (9 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 10/23] target/loongarch: handle LVZ exception and vm_exit SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 12/23] target/loongarch: add gid management functions SignKirigami
` (11 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add host value in enum TLBRet, and use it in raise_mmu_exception().
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu-mmu.h | 8 ++++++++
target/loongarch/tcg/tlb_helper.c | 18 ++++++++++++++++--
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
index 54fb732d62..2b46e481bd 100644
--- a/target/loongarch/cpu-mmu.h
+++ b/target/loongarch/cpu-mmu.h
@@ -17,6 +17,14 @@ typedef enum TLBRet {
TLBRET_RI,
TLBRET_XI,
TLBRET_PE,
+ TLBRET_HOST_MATCH,
+ TLBRET_HOST_BADADDR,
+ TLBRET_HOST_NOMATCH,
+ TLBRET_HOST_INVALID,
+ TLBRET_HOST_DIRTY,
+ TLBRET_HOST_RI,
+ TLBRET_HOST_XI,
+ TLBRET_HOST_PE,
} TLBRet;
typedef struct MMUContext {
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 40cc076424..d1f1d233fd 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -49,15 +49,24 @@ static void raise_mmu_exception(CPULoongArchState *env, vaddr address,
MMUAccessType access_type, TLBRet tlb_error)
{
CPUState *cs = env_cpu(env);
- CPUSysState *sys = env_sys(env);
+ bool real_guest;
+
+ if (env_vm_level(env) == VM_LEVEL1 && tlb_error > TLBRET_HOST_MATCH) {
+ trigger_vm_exit(env);
+ }
+
+ real_guest = !env->vm_exit && env_vm_level(env);
+ CPUSysState *sys = get_sys(env, real_guest);
switch (tlb_error) {
default:
case TLBRET_BADADDR:
+ case TLBRET_HOST_BADADDR:
cs->exception_index = access_type == MMU_INST_FETCH
? EXCCODE_ADEF : EXCCODE_ADEM;
break;
case TLBRET_NOMATCH:
+ case TLBRET_HOST_NOMATCH:
/* No TLB match for a mapped address */
if (access_type == MMU_DATA_LOAD) {
cs->exception_index = EXCCODE_PIL;
@@ -69,6 +78,7 @@ static void raise_mmu_exception(CPULoongArchState *env, vaddr address,
sys->CSR_TLBRERA = FIELD_DP64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 1);
break;
case TLBRET_INVALID:
+ case TLBRET_HOST_INVALID:
/* TLB match with no valid bit */
if (access_type == MMU_DATA_LOAD) {
cs->exception_index = EXCCODE_PIL;
@@ -79,24 +89,28 @@ static void raise_mmu_exception(CPULoongArchState *env, vaddr address,
}
break;
case TLBRET_DIRTY:
+ case TLBRET_HOST_DIRTY:
/* TLB match but 'D' bit is cleared */
cs->exception_index = EXCCODE_PME;
break;
case TLBRET_XI:
+ case TLBRET_HOST_XI:
/* Execute-Inhibit Exception */
cs->exception_index = EXCCODE_PNX;
break;
case TLBRET_RI:
+ case TLBRET_HOST_RI:
/* Read-Inhibit Exception */
cs->exception_index = EXCCODE_PNR;
break;
case TLBRET_PE:
+ case TLBRET_HOST_PE:
/* Privileged Exception */
cs->exception_index = EXCCODE_PPI;
break;
}
- if (tlb_error == TLBRET_NOMATCH) {
+ if (tlb_error == TLBRET_NOMATCH || tlb_error == TLBRET_HOST_NOMATCH) {
sys->CSR_TLBRBADV = address;
if (is_la64(env)) {
sys->CSR_TLBREHI = FIELD_DP64(sys->CSR_TLBREHI, CSR_TLBREHI_64,
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 12/23] target/loongarch: add gid management functions
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (10 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 11/23] target/loongarch: add host TLBRet and handle SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-10 9:00 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 13/23] target/loongarch: add LVZ parameters to TLB functions SignKirigami
` (10 subsequent siblings)
22 siblings, 1 reply; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add get_gid(), get_tgid() and tlb_entry_matches_gid(), to get and use gid in
lvz functions.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.h | 21 +++++++++++++++++++++
target/loongarch/tcg/tlb_helper.c | 5 +++++
2 files changed, 26 insertions(+)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 3e3ae2bfa7..a42c5fe170 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -583,6 +583,27 @@ static inline bool will_return_to_guest(CPULoongArchState *env)
return FIELD_EX64(get_sys(env, VM_LEVEL0)->CSR_GSTAT, CSR_GSTAT, PVM);
}
+static inline uint8_t get_gid(CPULoongArchState *env)
+{
+ return FIELD_EX64(get_sys(env, VM_LEVEL0)->CSR_GSTAT, CSR_GSTAT, GID);
+}
+
+static inline uint8_t get_tgid(CPULoongArchState *env)
+{
+ CPUSysState *host = get_sys(env, VM_LEVEL0);
+
+ if (env_vm_level(env) == VM_LEVEL1) {
+ return get_gid(env);
+ }
+
+ if (FIELD_EX64(host->CSR_GTLBC, CSR_GTLBC, USETGID)) {
+ return FIELD_EX64(host->CSR_GTLBC, CSR_GTLBC, TGID);
+ } else if (will_return_to_guest(env)) {
+ return get_gid(env);
+ }
+ return 0;
+}
+
static inline CPUTimerState *env_timer(CPULoongArchState *env)
{
return &env->sys_states[0].timer_state;
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index d1f1d233fd..821aa26328 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -35,6 +35,11 @@ static bool tlb_match_asid(bool global, int asid, int tlb_asid)
return !global && tlb_asid == asid;
}
+static inline bool tlb_entry_matches_gid(const LoongArchTLB *tlb, uint8_t gid)
+{
+ return FIELD_EX64(tlb->tlb_misc, TLB_MISC, GID) == gid;
+}
+
bool check_ps(CPULoongArchState *env, uint8_t tlb_ps)
{
CPUSysState *sys = env_sys(env);
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 13/23] target/loongarch: add LVZ parameters to TLB functions
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (11 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 12/23] target/loongarch: add gid management functions SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 14/23] target/loongarch: add LVZ " SignKirigami
` (9 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add parameters related to LVZ (mainly vm_level) to statements and definitions
of TLB, so that LVZ patches to TLB can be divided into parts later.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu-mmu.h | 24 ++--
target/loongarch/cpu_helper.c | 40 +++---
target/loongarch/tcg/helper.h | 22 +--
.../tcg/insn_trans/trans_privileged.c.inc | 48 ++++---
target/loongarch/tcg/tcg_loongarch.h | 3 +-
target/loongarch/tcg/tlb_helper.c | 133 ++++++++++--------
6 files changed, 153 insertions(+), 117 deletions(-)
diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
index 2b46e481bd..4d76d96ee5 100644
--- a/target/loongarch/cpu-mmu.h
+++ b/target/loongarch/cpu-mmu.h
@@ -38,18 +38,19 @@ typedef struct MMUContext {
uint64_t pte_buddy[2];
} MMUContext;
-static inline bool cpu_has_ptw(CPULoongArchState *env)
+static inline bool cpu_has_ptw(CPULoongArchState *env, int vm_level)
{
CPUSysState *sys = env_sys(env);
return !!FIELD_EX64(sys->CSR_PWCH, CSR_PWCH, HPTW_EN);
}
-static inline bool pte_present(CPULoongArchState *env, uint64_t entry)
+static inline bool pte_present(CPULoongArchState *env, uint64_t entry,
+ int vm_level)
{
uint8_t present;
- if (cpu_has_ptw(env)) {
+ if (cpu_has_ptw(env, vm_level)) {
present = FIELD_EX64(entry, TLBENTRY, P);
} else {
present = FIELD_EX64(entry, TLBENTRY, V);
@@ -58,11 +59,12 @@ static inline bool pte_present(CPULoongArchState *env, uint64_t entry)
return !!present;
}
-static inline bool pte_write(CPULoongArchState *env, uint64_t entry)
+static inline bool pte_write(CPULoongArchState *env, uint64_t entry,
+ int vm_level)
{
uint8_t writable;
- if (cpu_has_ptw(env)) {
+ if (cpu_has_ptw(env, vm_level)) {
writable = FIELD_EX64(entry, TLBENTRY, W);
} else {
writable = FIELD_EX64(entry, TLBENTRY, D);
@@ -99,14 +101,18 @@ static inline bool pte_dirty(uint64_t entry)
bool check_ps(CPULoongArchState *ent, uint8_t ps);
TLBRet loongarch_check_pte(CPULoongArchState *env, MMUContext *context,
- MMUAccessType access_type, int mmu_idx);
+ MMUAccessType access_type, int mmu_idx, int vm_level);
TLBRet get_physical_address(CPULoongArchState *env, MMUContext *context,
MMUAccessType access_type, int mmu_idx,
- int is_debug);
+ int is_debug, uintptr_t retaddr);
TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext *context,
- int access_type, int mmu_idx, int debug);
+ int access_type, int mmu_idx, int debug, int vm_level,
+ uintptr_t retaddr);
void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
- uint64_t *dir_width, unsigned int level);
+ uint64_t *dir_width, unsigned int level, int vm_level);
+TLBRet loongarch_map_address(CPULoongArchState *env, MMUContext *context,
+ MMUAccessType access_type, int mmu_idx,
+ int is_debug, int vm_level, uintptr_t retaddr);
hwaddr loongarch_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
uint64_t loongarch_palen_mask(CPULoongArchState *env);
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 123cad3d93..8eabb4a9dc 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -19,7 +19,7 @@
#include "tcg/tcg_loongarch.h"
void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
- uint64_t *dir_width, unsigned int level)
+ uint64_t *dir_width, unsigned int level, int vm_level)
{
CPUSysState *sys = env_sys(env);
@@ -49,7 +49,7 @@ void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
}
TLBRet loongarch_check_pte(CPULoongArchState *env, MMUContext *context,
- MMUAccessType access_type, int mmu_idx)
+ MMUAccessType access_type, int mmu_idx, int vm_level)
{
uint64_t plv = mmu_idx;
uint64_t tlb_entry, tlb_ppn;
@@ -58,8 +58,8 @@ TLBRet loongarch_check_pte(CPULoongArchState *env, MMUContext *context,
tlb_entry = context->pte;
tlb_ps = context->ps;
- tlb_v = pte_present(env, tlb_entry);
- tlb_d = pte_write(env, tlb_entry);
+ tlb_v = pte_present(env, tlb_entry, vm_level);
+ tlb_d = pte_write(env, tlb_entry, vm_level);
tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV);
if (is_la64(env)) {
tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN);
@@ -147,7 +147,8 @@ static MemTxResult loongarch_cmpxchg_phys(CPUState *cs, hwaddr phys,
}
TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext *context,
- int access_type, int mmu_idx, int debug)
+ int access_type, int mmu_idx, int debug, int vm_level,
+ uintptr_t retaddr)
{
const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
CPUState *cs = env_cpu(env);
@@ -170,7 +171,7 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext *context,
base &= palen_mask;
for (level = 4; level >= 0; level--) {
- get_dir_base_width(env, &dir_base, &dir_width, level);
+ get_dir_base_width(env, &dir_base, &dir_width, level, vm_level);
if (dir_width == 0) {
continue;
@@ -208,7 +209,7 @@ restart:
context->pte_buddy[index] = base;
context->pte_buddy[1 - index] = base + BIT_ULL(dir_base);
base += (BIT_ULL(dir_base) & address);
- } else if (cpu_has_ptw(env)) {
+ } else if (cpu_has_ptw(env, vm_level)) {
uint64_t val;
index &= 1;
@@ -220,7 +221,7 @@ restart:
context->ps = dir_base;
context->pte = base;
- ret = loongarch_check_pte(env, context, access_type, mmu_idx);
+ ret = loongarch_check_pte(env, context, access_type, mmu_idx, vm_level);
if (debug) {
return ret;
}
@@ -231,7 +232,7 @@ restart:
* Need atomic compchxg operation with pte update, other vCPUs may
* update pte at the same time.
*/
- if (ret == TLBRET_MATCH && cpu_has_ptw(env)) {
+ if (ret == TLBRET_MATCH && cpu_has_ptw(env, vm_level)) {
if (access_type == MMU_DATA_STORE && pte_dirty(base)) {
return ret;
}
@@ -273,15 +274,15 @@ restart:
return ret;
}
-static TLBRet loongarch_map_address(CPULoongArchState *env,
- MMUContext *context,
- MMUAccessType access_type, int mmu_idx,
- int is_debug)
+TLBRet loongarch_map_address(CPULoongArchState *env, MMUContext *context,
+ MMUAccessType access_type, int mmu_idx,
+ int is_debug, int vm_level, uintptr_t retaddr)
{
TLBRet ret;
if (tcg_enabled()) {
- ret = loongarch_get_addr_from_tlb(env, context, access_type, mmu_idx);
+ ret = loongarch_get_addr_from_tlb(env, context, access_type, mmu_idx,
+ vm_level);
if (ret != TLBRET_NOMATCH) {
return ret;
}
@@ -293,7 +294,8 @@ static TLBRet loongarch_map_address(CPULoongArchState *env,
* legal mapping, even if the mapping is not yet in TLB. return 0 if
* there is a valid map, else none zero.
*/
- return loongarch_ptw(env, context, access_type, mmu_idx, is_debug);
+ return loongarch_ptw(env, context, access_type, mmu_idx, is_debug,
+ vm_level, retaddr);
}
return TLBRET_NOMATCH;
@@ -312,10 +314,11 @@ static hwaddr dmw_va2pa(CPULoongArchState *env, vaddr va, uint64_t dmw)
TLBRet get_physical_address(CPULoongArchState *env, MMUContext *context,
MMUAccessType access_type, int mmu_idx,
- int is_debug)
+ int is_debug, uintptr_t retaddr)
{
int user_mode = mmu_idx == MMU_USER_IDX;
int kernel_mode = mmu_idx == MMU_KERNEL_IDX;
+ int vm_level = env_vm_level(env);
uint32_t plv, base_c, base_v;
int64_t addr_high;
CPUSysState *sys = env_sys(env);
@@ -360,7 +363,8 @@ TLBRet get_physical_address(CPULoongArchState *env, MMUContext *context,
}
/* Mapped address */
- return loongarch_map_address(env, context, access_type, mmu_idx, is_debug);
+ return loongarch_map_address(env, context, access_type, mmu_idx, is_debug,
+ vm_level, retaddr);
}
hwaddr loongarch_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
@@ -370,7 +374,7 @@ hwaddr loongarch_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
context.addr = addr;
if (get_physical_address(env, &context, MMU_DATA_LOAD,
- cpu_mmu_index(cs, false), 1) != TLBRET_MATCH) {
+ cpu_mmu_index(cs, false), 1, 0) != TLBRET_MATCH) {
return -1;
}
return context.physical;
diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h
index e76c73c775..a27b80b087 100644
--- a/target/loongarch/tcg/helper.h
+++ b/target/loongarch/tcg/helper.h
@@ -114,17 +114,17 @@ DEF_HELPER_3(iocsrwr_w, void, env, tl, tl)
DEF_HELPER_3(iocsrwr_d, void, env, tl, tl)
/* TLB helper */
-DEF_HELPER_1(tlbwr, void, env)
-DEF_HELPER_1(tlbfill, void, env)
-DEF_HELPER_1(tlbsrch, void, env)
-DEF_HELPER_1(tlbrd, void, env)
-DEF_HELPER_1(tlbclr, void, env)
-DEF_HELPER_1(tlbflush, void, env)
-DEF_HELPER_1(invtlb_all, void, env)
-DEF_HELPER_2(invtlb_all_g, void, env, i32)
-DEF_HELPER_2(invtlb_all_asid, void, env, tl)
-DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl)
-DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl)
+DEF_HELPER_2(tlbwr, void, env, i32)
+DEF_HELPER_2(tlbfill, void, env, i32)
+DEF_HELPER_2(tlbsrch, void, env, i32)
+DEF_HELPER_2(tlbrd, void, env, i32)
+DEF_HELPER_2(tlbclr, void, env, i32)
+DEF_HELPER_2(tlbflush, void, env, i32)
+DEF_HELPER_4(invtlb_all, void, env, tl, i32, i32)
+DEF_HELPER_4(invtlb_all_g, void, env, tl, i32, i32)
+DEF_HELPER_3(invtlb_all_asid, void, env, tl, i32)
+DEF_HELPER_4(invtlb_page_asid, void, env, tl, tl, i32)
+DEF_HELPER_4(invtlb_page_asid_or_g, void, env, tl, tl, i32)
DEF_HELPER_4(lddir, tl, env, tl, i32, i32)
DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 7ee3bb8e27..493ed7f24b 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -260,7 +260,8 @@ static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a)
if (check_plv(ctx)) {
return false;
}
- gen_helper_tlbsrch(tcg_env);
+ gen_helper_tlbsrch(tcg_env,
+ tcg_constant_i32(is_guest_mmu_idx(ctx->mem_idx)));
return true;
}
@@ -269,7 +270,8 @@ static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a)
if (check_plv(ctx)) {
return false;
}
- gen_helper_tlbrd(tcg_env);
+ gen_helper_tlbrd(tcg_env,
+ tcg_constant_i32(is_guest_mmu_idx(ctx->mem_idx)));
return true;
}
@@ -278,7 +280,8 @@ static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
if (check_plv(ctx)) {
return false;
}
- gen_helper_tlbwr(tcg_env);
+ gen_helper_tlbwr(tcg_env,
+ tcg_constant_i32(is_guest_mmu_idx(ctx->mem_idx)));
check_mmu_idx(ctx);
return true;
}
@@ -288,7 +291,8 @@ static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a)
if (check_plv(ctx)) {
return false;
}
- gen_helper_tlbfill(tcg_env);
+ gen_helper_tlbfill(tcg_env,
+ tcg_constant_i32(is_guest_mmu_idx(ctx->mem_idx)));
check_mmu_idx(ctx);
return true;
}
@@ -298,7 +302,8 @@ static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
if (check_plv(ctx)) {
return false;
}
- gen_helper_tlbclr(tcg_env);
+ gen_helper_tlbclr(tcg_env,
+ tcg_constant_i32(is_guest_mmu_idx(ctx->mem_idx)));
check_mmu_idx(ctx);
return true;
}
@@ -308,7 +313,8 @@ static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
if (check_plv(ctx)) {
return false;
}
- gen_helper_tlbflush(tcg_env);
+ gen_helper_tlbflush(tcg_env,
+ tcg_constant_i32(is_guest_mmu_idx(ctx->mem_idx)));
check_mmu_idx(ctx);
return true;
}
@@ -323,24 +329,28 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
}
switch (a->imm) {
- case 0:
- case 1:
- gen_helper_invtlb_all(tcg_env);
+ case 0x0:
+ case 0x1:
+ gen_helper_invtlb_all(tcg_env, rj, tcg_constant_i32(a->imm),
+ tcg_constant_i32(0));
break;
- case 2:
- gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(1));
+ case 0x2:
+ gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(1),
+ tcg_constant_i32(0));
break;
- case 3:
- gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(0));
+ case 0x3:
+ gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(0),
+ tcg_constant_i32(0));
break;
- case 4:
- gen_helper_invtlb_all_asid(tcg_env, rj);
+ case 0x4:
+ gen_helper_invtlb_all_asid(tcg_env, rj, tcg_constant_i32(0));
break;
- case 5:
- gen_helper_invtlb_page_asid(tcg_env, rj, rk);
+ case 0x5:
+ gen_helper_invtlb_page_asid(tcg_env, rj, rk, tcg_constant_i32(0));
break;
- case 6:
- gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk);
+ case 0x6:
+ gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk,
+ tcg_constant_i32(0));
break;
default:
return false;
diff --git a/target/loongarch/tcg/tcg_loongarch.h b/target/loongarch/tcg/tcg_loongarch.h
index 7fb627f2d6..6c0080c2b3 100644
--- a/target/loongarch/tcg/tcg_loongarch.h
+++ b/target/loongarch/tcg/tcg_loongarch.h
@@ -18,6 +18,7 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
TLBRet loongarch_get_addr_from_tlb(CPULoongArchState *env,
MMUContext *context,
- MMUAccessType access_type, int mmu_idx);
+ MMUAccessType access_type, int mmu_idx,
+ int vm_level);
#endif /* TARGET_LOONGARCH_TCG_LOONGARCH_H */
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 821aa26328..aabb463e4d 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -132,7 +132,7 @@ static void raise_mmu_exception(CPULoongArchState *env, vaddr address,
}
}
-static void invalidate_tlb_entry(CPULoongArchState *env, int index)
+static void invalidate_tlb_entry(CPULoongArchState *env, int index, int vm_level)
{
target_ulong addr, mask, pagesize;
uint8_t tlb_ps;
@@ -147,20 +147,20 @@ static void invalidate_tlb_entry(CPULoongArchState *env, int index)
addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask;
addr = sextract64(addr, 0, TARGET_VIRT_ADDR_SPACE_BITS);
- tlb_v = pte_present(env, tlb->tlb_entry0);
+ tlb_v = pte_present(env, tlb->tlb_entry0, vm_level);
if (tlb_v) {
tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize,
idxmap, TARGET_LONG_BITS);
}
- tlb_v = pte_present(env, tlb->tlb_entry1);
+ tlb_v = pte_present(env, tlb->tlb_entry1, vm_level);
if (tlb_v) {
tlb_flush_range_by_mmuidx(env_cpu(env), addr + pagesize, pagesize,
idxmap, TARGET_LONG_BITS);
}
}
-static void invalidate_tlb(CPULoongArchState *env, int index)
+static void invalidate_tlb(CPULoongArchState *env, int index, int vm_level)
{
LoongArchTLB *tlb;
uint16_t csr_asid, tlb_asid, tlb_g;
@@ -181,11 +181,12 @@ static void invalidate_tlb(CPULoongArchState *env, int index)
if (tlb_g == 0 && tlb_asid != csr_asid) {
return;
}
- invalidate_tlb_entry(env, index);
+ invalidate_tlb_entry(env, index, vm_level);
}
/* Prepare tlb entry information in software PTW mode */
-static void sptw_prepare_context(CPULoongArchState *env, MMUContext *context)
+static void sptw_prepare_context(CPULoongArchState *env, MMUContext *context,
+ int vm_level)
{
uint64_t lo0, lo1, csr_vppn;
uint8_t csr_ps;
@@ -218,7 +219,7 @@ static void sptw_prepare_context(CPULoongArchState *env, MMUContext *context)
}
static void fill_tlb_entry(CPULoongArchState *env, LoongArchTLB *tlb,
- MMUContext *context)
+ MMUContext *context, int vm_level)
{
uint64_t lo0, lo1, csr_vppn;
uint16_t csr_asid;
@@ -257,9 +258,11 @@ static uint32_t get_random_tlb(uint32_t low, uint32_t high)
* field in tlb entry contains bit[47:13], so need adjust.
* virt_vpn = vaddr[47:13]
*/
-static const LoongArchTLB *
-loongarch_tlb_search_cb(CPULoongArchState *env, vaddr vaddr,
- int csr_asid, tlb_match func)
+
+static const LoongArchTLB *loongarch_tlb_search_cb(CPULoongArchState *env,
+ vaddr vaddr, int csr_asid,
+ tlb_match func, int vm_level,
+ uint8_t gid)
{
const LoongArchTLB *tlb;
uint16_t tlb_asid, stlb_idx;
@@ -311,7 +314,7 @@ loongarch_tlb_search_cb(CPULoongArchState *env, vaddr vaddr,
}
static bool loongarch_tlb_search(CPULoongArchState *env, vaddr vaddr,
- int *index)
+ int *index, int vm_level, uint8_t gid)
{
int csr_asid;
tlb_match func;
@@ -320,7 +323,7 @@ static bool loongarch_tlb_search(CPULoongArchState *env, vaddr vaddr,
func = tlb_match_any;
csr_asid = FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID);
- tlb = loongarch_tlb_search_cb(env, vaddr, csr_asid, func);
+ tlb = loongarch_tlb_search_cb(env, vaddr, csr_asid, func, vm_level, gid);
if (tlb) {
*index = tlb - env->tlb;
return true;
@@ -329,15 +332,17 @@ static bool loongarch_tlb_search(CPULoongArchState *env, vaddr vaddr,
return false;
}
-void helper_tlbsrch(CPULoongArchState *env)
+void helper_tlbsrch(CPULoongArchState *env, uint32_t vm_level)
{
int index, match;
CPUSysState *sys = env_sys(env);
if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
- match = loongarch_tlb_search(env, sys->CSR_TLBREHI, &index);
+ match = loongarch_tlb_search(env, sys->CSR_TLBREHI,
+ &index, vm_level, get_tgid(env));
} else {
- match = loongarch_tlb_search(env, sys->CSR_TLBEHI, &index);
+ match = loongarch_tlb_search(env, sys->CSR_TLBEHI,
+ &index, vm_level, get_tgid(env));
}
if (match) {
@@ -349,7 +354,7 @@ void helper_tlbsrch(CPULoongArchState *env)
sys->CSR_TLBIDX = FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, NE, 1);
}
-void helper_tlbrd(CPULoongArchState *env)
+void helper_tlbrd(CPULoongArchState *env, uint32_t vm_level)
{
LoongArchTLB *tlb;
int index;
@@ -382,18 +387,18 @@ void helper_tlbrd(CPULoongArchState *env)
}
static void update_tlb_index(CPULoongArchState *env, MMUContext *context,
- int index)
+ int index, int vm_level)
{
LoongArchTLB *old, new = {};
bool skip_inv = false, tlb_v0, tlb_v1;
old = env->tlb + index;
- fill_tlb_entry(env, &new, context);
+ fill_tlb_entry(env, &new, context, vm_level);
/* Check whether ASID/VPPN is the same */
if (old->tlb_misc == new.tlb_misc) {
/* Check whether both even/odd pages is the same or invalid */
- tlb_v0 = pte_present(env, old->tlb_entry0);
- tlb_v1 = pte_present(env, old->tlb_entry1);
+ tlb_v0 = pte_present(env, old->tlb_entry0, vm_level);
+ tlb_v1 = pte_present(env, old->tlb_entry1, vm_level);
if ((!tlb_v0 || new.tlb_entry0 == old->tlb_entry0) &&
(!tlb_v1 || new.tlb_entry1 == old->tlb_entry1)) {
skip_inv = true;
@@ -402,29 +407,29 @@ static void update_tlb_index(CPULoongArchState *env, MMUContext *context,
/* flush tlb before updating the entry */
if (!skip_inv) {
- invalidate_tlb(env, index);
+ invalidate_tlb(env, index, vm_level);
}
*old = new;
}
-void helper_tlbwr(CPULoongArchState *env)
+void helper_tlbwr(CPULoongArchState *env, uint32_t vm_level)
{
CPUSysState *sys = env_sys(env);
int index = FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX);
MMUContext context;
if (FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, NE)) {
- invalidate_tlb(env, index);
+ invalidate_tlb(env, index, vm_level);
return;
}
- sptw_prepare_context(env, &context);
- update_tlb_index(env, &context, index);
+ sptw_prepare_context(env, &context, vm_level);
+ update_tlb_index(env, &context, index, vm_level);
}
static int get_tlb_random_index(CPULoongArchState *env, vaddr addr,
- int pagesize)
+ int pagesize, int vm_level)
{
uint64_t address;
int index, set, i, stlb_idx;
@@ -488,7 +493,7 @@ static int get_tlb_random_index(CPULoongArchState *env, vaddr addr,
return index;
}
-void helper_tlbfill(CPULoongArchState *env)
+void helper_tlbfill(CPULoongArchState *env, uint32_t vm_level)
{
vaddr entryhi;
int index, pagesize;
@@ -505,13 +510,13 @@ void helper_tlbfill(CPULoongArchState *env)
pagesize = FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, PS);
}
- sptw_prepare_context(env, &context);
- index = get_tlb_random_index(env, entryhi, pagesize);
- invalidate_tlb(env, index);
- fill_tlb_entry(env, env->tlb + index, &context);
+ sptw_prepare_context(env, &context, vm_level);
+ index = get_tlb_random_index(env, entryhi, pagesize, vm_level);
+ invalidate_tlb(env, index, vm_level);
+ fill_tlb_entry(env, env->tlb + index, &context, vm_level);
}
-void helper_tlbclr(CPULoongArchState *env)
+void helper_tlbclr(CPULoongArchState *env, uint32_t vm_level)
{
LoongArchTLB *tlb;
int i, index;
@@ -546,7 +551,7 @@ void helper_tlbclr(CPULoongArchState *env)
tlb_flush(env_cpu(env));
}
-void helper_tlbflush(CPULoongArchState *env)
+void helper_tlbflush(CPULoongArchState *env, uint32_t vm_level)
{
int i, index;
CPUSysState *sys = env_sys(env);
@@ -571,7 +576,8 @@ void helper_tlbflush(CPULoongArchState *env)
tlb_flush(env_cpu(env));
}
-void helper_invtlb_all(CPULoongArchState *env)
+void helper_invtlb_all(CPULoongArchState *env, target_ulong info, uint32_t op,
+ uint32_t to_guest)
{
for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc,
@@ -580,7 +586,8 @@ void helper_invtlb_all(CPULoongArchState *env)
tlb_flush(env_cpu(env));
}
-void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g)
+void helper_invtlb_all_g(CPULoongArchState *env, target_ulong info, uint32_t g,
+ uint32_t to_guest)
{
for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
LoongArchTLB *tlb = &env->tlb[i];
@@ -593,7 +600,8 @@ void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g)
tlb_flush(env_cpu(env));
}
-void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info)
+void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info,
+ uint32_t to_guest)
{
uint16_t asid = info & R_CSR_ASID_ASID_MASK;
@@ -610,43 +618,45 @@ void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info)
}
void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info,
- target_ulong addr)
+ target_ulong addr, uint32_t to_guest)
{
int asid = info & 0x3ff;
const LoongArchTLB *tlb;
tlb_match func;
func = tlb_match_asid;
- tlb = loongarch_tlb_search_cb(env, addr, asid, func);
+ tlb = loongarch_tlb_search_cb(env, addr, asid, func, to_guest, 0);
if (tlb) {
- invalidate_tlb(env, tlb - env->tlb);
+ invalidate_tlb(env, tlb - env->tlb, to_guest);
}
}
-void helper_invtlb_page_asid_or_g(CPULoongArchState *env,
- target_ulong info, target_ulong addr)
+void helper_invtlb_page_asid_or_g(CPULoongArchState *env, target_ulong info,
+ target_ulong addr, uint32_t to_guest)
{
int asid = info & 0x3ff;
const LoongArchTLB *tlb;
tlb_match func;
func = tlb_match_any;
- tlb = loongarch_tlb_search_cb(env, addr, asid, func);
+ tlb = loongarch_tlb_search_cb(env, addr, asid, func,
+ to_guest, 0);
if (tlb) {
- invalidate_tlb(env, tlb - env->tlb);
+ invalidate_tlb(env, tlb - env->tlb, to_guest);
}
}
-static void ptw_update_tlb(CPULoongArchState *env, MMUContext *context)
+static void ptw_update_tlb(CPULoongArchState *env, MMUContext *context,
+ int vm_level)
{
int index;
index = context->tlb_index;
if (index < 0) {
- index = get_tlb_random_index(env, context->addr, context->ps);
+ index = get_tlb_random_index(env, context->addr, context->ps, vm_level);
}
- update_tlb_index(env, context, index);
+ update_tlb_index(env, context, index, vm_level);
}
bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
@@ -655,6 +665,7 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
{
CPULoongArchState *env = cpu_env(cs);
hwaddr physical;
+ int vm_level = env_vm_level(env);
int prot;
MMUContext context;
TLBRet ret;
@@ -662,9 +673,9 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
/* Data access */
context.addr = address;
context.tlb_index = -1;
- ret = get_physical_address(env, &context, access_type, mmu_idx, 0);
+ ret = get_physical_address(env, &context, access_type, mmu_idx, 0, retaddr);
if (ret == TLBRET_MATCH && context.mmu_index != MMU_DA_IDX
- && cpu_has_ptw(env)) {
+ && cpu_has_ptw(env, vm_level)) {
bool need_update = true;
if (access_type == MMU_DATA_STORE && pte_dirty(context.pte)) {
@@ -688,15 +699,15 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
}
}
- if (ret != TLBRET_MATCH && cpu_has_ptw(env)) {
+ if (ret != TLBRET_MATCH && cpu_has_ptw(env, vm_level)) {
/* Take HW PTW if TLB missed or bit P is zero */
if (ret == TLBRET_NOMATCH || ret == TLBRET_INVALID) {
- ret = loongarch_ptw(env, &context, access_type, mmu_idx, 0);
+ ret = loongarch_ptw(env, &context, access_type, mmu_idx, 0, vm_level, retaddr);
if (ret == TLBRET_MATCH) {
- ptw_update_tlb(env, &context);
+ ptw_update_tlb(env, &context, vm_level);
}
} else if (context.tlb_index >= 0) {
- invalidate_tlb(env, context.tlb_index);
+ invalidate_tlb(env, context.tlb_index, vm_level);
}
}
@@ -770,7 +781,8 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
badvaddr = sys->CSR_TLBRBADV;
base = base & palen_mask;
- get_dir_base_width(env, &dir_base, &dir_width, level);
+ get_dir_base_width(env, &dir_base, &dir_width, level,
+ env_vm_level(env));
index = (badvaddr >> dir_base) & ((1 << dir_width) - 1);
phys = base | index << 3;
val = address_space_ldq_le(cs->as, phys, MEMTXATTRS_UNSPECIFIED, NULL);
@@ -808,7 +820,8 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
* Move HGLOBAL bit to GLOBAL bit.
*/
get_dir_base_width(env, &dir_base, &dir_width,
- FIELD_EX64(base, TLBENTRY, LEVEL));
+ FIELD_EX64(base, TLBENTRY, LEVEL),
+ env_vm_level(env));
base = FIELD_DP64(base, TLBENTRY, LEVEL, 0);
base = FIELD_DP64(base, TLBENTRY, HUGE, 0);
@@ -859,7 +872,7 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
static TLBRet loongarch_map_tlb_entry(CPULoongArchState *env,
MMUContext *context,
MMUAccessType access_type, int index,
- int mmu_idx)
+ int mmu_idx, int vm_level)
{
const LoongArchTLB *tlb = &env->tlb[index];
uint8_t tlb_ps, n;
@@ -869,19 +882,21 @@ static TLBRet loongarch_map_tlb_entry(CPULoongArchState *env,
context->pte = n ? tlb->tlb_entry1 : tlb->tlb_entry0;
context->ps = tlb_ps;
context->tlb_index = index;
- return loongarch_check_pte(env, context, access_type, mmu_idx);
+ return loongarch_check_pte(env, context, access_type, mmu_idx, vm_level);
}
TLBRet loongarch_get_addr_from_tlb(CPULoongArchState *env,
MMUContext *context,
- MMUAccessType access_type, int mmu_idx)
+ MMUAccessType access_type, int mmu_idx,
+ int vm_level)
{
int index, match;
- match = loongarch_tlb_search(env, context->addr, &index);
+ match = loongarch_tlb_search(env, context->addr, &index,
+ vm_level, get_tgid(env));
if (match) {
return loongarch_map_tlb_entry(env, context, access_type, index,
- mmu_idx);
+ mmu_idx, vm_level);
}
return TLBRET_NOMATCH;
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 14/23] target/loongarch: add LVZ to TLB functions
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (12 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 13/23] target/loongarch: add LVZ parameters to TLB functions SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 15/23] target/loongarch: add LVZ to invtlb SignKirigami
` (8 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add LVZ to most TLB handler, except invtlb and ptw.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu-mmu.h | 2 +
target/loongarch/cpu.h | 1 +
target/loongarch/cpu_helper.c | 10 +--
target/loongarch/tcg/tlb_helper.c | 132 ++++++++++++++++++++++++------
4 files changed, 115 insertions(+), 30 deletions(-)
diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
index 4d76d96ee5..29b0c109fb 100644
--- a/target/loongarch/cpu-mmu.h
+++ b/target/loongarch/cpu-mmu.h
@@ -110,6 +110,8 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext *context,
uintptr_t retaddr);
void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
uint64_t *dir_width, unsigned int level, int vm_level);
+hwaddr loongarch_get_host_address(CPULoongArchState *env, hwaddr gpa,
+ uintptr_t retaddr);
TLBRet loongarch_map_address(CPULoongArchState *env, MMUContext *context,
MMUAccessType access_type, int mmu_idx,
int is_debug, int vm_level, uintptr_t retaddr);
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index a42c5fe170..995e8f5a7f 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -262,6 +262,7 @@ FIELD(TLB_MISC, ASID, 1, 10)
FIELD(TLB_MISC, VPPN, 13, 35)
FIELD(TLB_MISC, PS, 48, 6)
FIELD(TLB_MISC, GID, 54, 8)
+FIELD(TLB_MISC, VM_LEVEL, 62, 1)
/*Msg interrupt registers */
#define N_MSGIS 4
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 8eabb4a9dc..23d26385c6 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -21,7 +21,7 @@
void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
uint64_t *dir_width, unsigned int level, int vm_level)
{
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
switch (level) {
case 1:
@@ -51,7 +51,7 @@ void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
TLBRet loongarch_check_pte(CPULoongArchState *env, MMUContext *context,
MMUAccessType access_type, int mmu_idx, int vm_level)
{
- uint64_t plv = mmu_idx;
+ uint64_t plv = mmu_idx_to_plv(mmu_idx);
uint64_t tlb_entry, tlb_ppn;
uint8_t tlb_ps, tlb_plv, tlb_nx, tlb_nr, tlb_rplv;
bool tlb_v, tlb_d;
@@ -316,12 +316,12 @@ TLBRet get_physical_address(CPULoongArchState *env, MMUContext *context,
MMUAccessType access_type, int mmu_idx,
int is_debug, uintptr_t retaddr)
{
- int user_mode = mmu_idx == MMU_USER_IDX;
- int kernel_mode = mmu_idx == MMU_KERNEL_IDX;
+ int user_mode = mmu_idx_to_plv(mmu_idx) == MMU_USER_IDX;
+ int kernel_mode = mmu_idx_to_plv(mmu_idx) == MMU_KERNEL_IDX;
int vm_level = env_vm_level(env);
uint32_t plv, base_c, base_v;
int64_t addr_high;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
uint8_t da = FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, DA);
uint8_t pg = FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PG);
vaddr address;
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index aabb463e4d..60c7193283 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -18,6 +18,8 @@
#include "exec/target_page.h"
#include "accel/tcg/cpu-ldst.h"
#include "accel/tcg/cpu-loop.h"
+#include "accel/tcg/probe.h"
+#include "exec/tlb-flags.h"
#include "exec/log.h"
#include "cpu-csr.h"
#include "tcg/tcg_loongarch.h"
@@ -40,9 +42,15 @@ static inline bool tlb_entry_matches_gid(const LoongArchTLB *tlb, uint8_t gid)
return FIELD_EX64(tlb->tlb_misc, TLB_MISC, GID) == gid;
}
+static inline bool tlb_entry_matches_vm_level(const LoongArchTLB *tlb,
+ uint8_t vm_level)
+{
+ return FIELD_EX64(tlb->tlb_misc, TLB_MISC, VM_LEVEL) == vm_level;
+}
+
bool check_ps(CPULoongArchState *env, uint8_t tlb_ps)
{
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, VM_LEVEL0);
if (tlb_ps >= 64) {
return false;
@@ -137,7 +145,9 @@ static void invalidate_tlb_entry(CPULoongArchState *env, int index, int vm_level
target_ulong addr, mask, pagesize;
uint8_t tlb_ps;
LoongArchTLB *tlb = &env->tlb[index];
- int idxmap = BIT(MMU_KERNEL_IDX) | BIT(MMU_USER_IDX);
+ int bit_offset = vm_level ? MMU_GUEST_IDX : 0;
+ int idxmap = (BIT(MMU_KERNEL_IDX + bit_offset)
+ | BIT(MMU_USER_IDX + bit_offset));
uint64_t tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
bool tlb_v;
@@ -165,7 +175,7 @@ static void invalidate_tlb(CPULoongArchState *env, int index, int vm_level)
LoongArchTLB *tlb;
uint16_t csr_asid, tlb_asid, tlb_g;
uint8_t tlb_e;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
csr_asid = FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID);
tlb = &env->tlb[index];
@@ -190,7 +200,7 @@ static void sptw_prepare_context(CPULoongArchState *env, MMUContext *context,
{
uint64_t lo0, lo1, csr_vppn;
uint8_t csr_ps;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
csr_ps = FIELD_EX64(sys->CSR_TLBREHI, CSR_TLBREHI, PS);
@@ -224,7 +234,7 @@ static void fill_tlb_entry(CPULoongArchState *env, LoongArchTLB *tlb,
uint64_t lo0, lo1, csr_vppn;
uint16_t csr_asid;
uint8_t csr_ps;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
csr_vppn = context->addr >> R_TLB_MISC_VPPN_SHIFT;
csr_ps = context->ps;
@@ -237,6 +247,8 @@ static void fill_tlb_entry(CPULoongArchState *env, LoongArchTLB *tlb,
tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1);
csr_asid = FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID);
tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid);
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, GID, get_tgid(env));
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VM_LEVEL, vm_level);
tlb->tlb_entry0 = lo0;
tlb->tlb_entry1 = lo1;
@@ -270,7 +282,7 @@ static const LoongArchTLB *loongarch_tlb_search_cb(CPULoongArchState *env,
bool tlb_g;
int i, compare_shift;
uint64_t vpn, tlb_vppn;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
stlb_ps = FIELD_EX64(sys->CSR_STLBPS, CSR_STLBPS, PS);
vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1);
@@ -287,6 +299,8 @@ static const LoongArchTLB *loongarch_tlb_search_cb(CPULoongArchState *env,
tlb_g = !!FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
if (func(tlb_g, csr_asid, tlb_asid) &&
+ tlb_entry_matches_gid(tlb, gid) &&
+ tlb_entry_matches_vm_level(tlb, vm_level) &&
(vpn == (tlb_vppn >> compare_shift))) {
return tlb;
}
@@ -305,6 +319,8 @@ static const LoongArchTLB *loongarch_tlb_search_cb(CPULoongArchState *env,
compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1);
if (func(tlb_g, csr_asid, tlb_asid) &&
+ tlb_entry_matches_gid(tlb, gid) &&
+ tlb_entry_matches_vm_level(tlb, vm_level) &&
(vpn == (tlb_vppn >> compare_shift))) {
return tlb;
}
@@ -319,7 +335,7 @@ static bool loongarch_tlb_search(CPULoongArchState *env, vaddr vaddr,
int csr_asid;
tlb_match func;
const LoongArchTLB *tlb;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
func = tlb_match_any;
csr_asid = FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID);
@@ -335,7 +351,7 @@ static bool loongarch_tlb_search(CPULoongArchState *env, vaddr vaddr,
void helper_tlbsrch(CPULoongArchState *env, uint32_t vm_level)
{
int index, match;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
match = loongarch_tlb_search(env, sys->CSR_TLBREHI,
@@ -359,7 +375,7 @@ void helper_tlbrd(CPULoongArchState *env, uint32_t vm_level)
LoongArchTLB *tlb;
int index;
uint8_t tlb_ps, tlb_e;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
index = FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX);
tlb = &env->tlb[index];
@@ -415,7 +431,7 @@ static void update_tlb_index(CPULoongArchState *env, MMUContext *context,
void helper_tlbwr(CPULoongArchState *env, uint32_t vm_level)
{
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
int index = FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX);
MMUContext context;
@@ -436,7 +452,7 @@ static int get_tlb_random_index(CPULoongArchState *env, vaddr addr,
uint16_t asid, tlb_asid, stlb_ps;
LoongArchTLB *tlb;
uint8_t tlb_e, tlb_g;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
/* Validity of stlb_ps is checked in helper_csrwr_stlbps() */
stlb_ps = FIELD_EX64(sys->CSR_STLBPS, CSR_STLBPS, PS);
@@ -456,7 +472,8 @@ static int get_tlb_random_index(CPULoongArchState *env, vaddr addr,
tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
- if (tlb_g == 0 && asid != tlb_asid) {
+ if (tlb_g == 0 && asid != tlb_asid &&
+ tlb_entry_matches_gid(tlb, get_tgid(env))) {
set = i;
}
}
@@ -480,7 +497,8 @@ static int get_tlb_random_index(CPULoongArchState *env, vaddr addr,
tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
- if (tlb_g == 0 && asid != tlb_asid) {
+ if (tlb_g == 0 && asid != tlb_asid &&
+ tlb_entry_matches_gid(tlb, get_tgid(env))) {
index = i;
}
}
@@ -498,7 +516,7 @@ void helper_tlbfill(CPULoongArchState *env, uint32_t vm_level)
vaddr entryhi;
int index, pagesize;
MMUContext context;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
entryhi = sys->CSR_TLBREHI;
@@ -521,7 +539,7 @@ void helper_tlbclr(CPULoongArchState *env, uint32_t vm_level)
LoongArchTLB *tlb;
int i, index;
uint16_t csr_asid, tlb_asid, tlb_g;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
csr_asid = FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID);
index = FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX);
@@ -532,7 +550,8 @@ void helper_tlbclr(CPULoongArchState *env, uint32_t vm_level)
tlb = &env->tlb[i * 256 + (index % 256)];
tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
- if (!tlb_g && tlb_asid == csr_asid) {
+ if (!tlb_g && tlb_asid == csr_asid &&
+ tlb_entry_matches_gid(tlb, get_tgid(env))) {
tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
}
}
@@ -542,7 +561,8 @@ void helper_tlbclr(CPULoongArchState *env, uint32_t vm_level)
tlb = &env->tlb[i];
tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
- if (!tlb_g && tlb_asid == csr_asid) {
+ if (!tlb_g && tlb_asid == csr_asid &&
+ tlb_entry_matches_gid(tlb, get_tgid(env))) {
tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
}
}
@@ -554,7 +574,7 @@ void helper_tlbclr(CPULoongArchState *env, uint32_t vm_level)
void helper_tlbflush(CPULoongArchState *env, uint32_t vm_level)
{
int i, index;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
index = FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX);
@@ -659,15 +679,25 @@ static void ptw_update_tlb(CPULoongArchState *env, MMUContext *context,
update_tlb_index(env, context, index, vm_level);
}
+static TLBRet loongarch_map_host_address(CPULoongArchState *env, MMUContext *context,
+ MMUAccessType access_type, uintptr_t retaddr)
+{
+ TLBRet ret;
+
+ ret = loongarch_map_address(env, context, access_type, MMU_KERNEL_IDX,
+ false, false, retaddr);
+ return TLBRET_HOST_MATCH + ret;
+}
+
bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
{
CPULoongArchState *env = cpu_env(cs);
- hwaddr physical;
int vm_level = env_vm_level(env);
- int prot;
- MMUContext context;
+ hwaddr physical;
+ int prot, host_prot;
+ MMUContext context, host_context;
TLBRet ret;
/* Data access */
@@ -714,12 +744,30 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
if (ret == TLBRET_MATCH) {
physical = context.physical;
prot = context.prot;
+ if (vm_level) {
+ host_context.addr = physical;
+ host_context.tlb_index = -1;
+ ret = loongarch_map_host_address(env, &host_context, access_type,
+ retaddr);
+ if (ret != TLBRET_HOST_MATCH) {
+ if (probe) {
+ return false;
+ }
+ raise_mmu_exception(env, physical, access_type, ret);
+ cpu_loop_exit_restore(cs, retaddr);
+ return false;
+ }
+ physical = host_context.physical;
+ host_prot = host_context.prot;
+ prot &= host_prot;
+ }
tlb_set_page(cs, address & TARGET_PAGE_MASK,
physical & TARGET_PAGE_MASK, prot,
mmu_idx, TARGET_PAGE_SIZE);
qemu_log_mask(CPU_LOG_MMU,
"%s address=%" VADDR_PRIx " physical " HWADDR_FMT_plx
- " prot %d\n", __func__, address, physical, prot);
+ " prot %d guest %d\n", __func__, address, physical,
+ prot, is_guest_mmu_idx(mmu_idx));
return true;
} else {
qemu_log_mask(CPU_LOG_MMU,
@@ -748,6 +796,31 @@ static inline uint64_t loongarch_sanitize_hw_pte(CPULoongArchState *env,
return (pte & ~ppn_mask) | ((pte & ppn_mask) & palen_mask);
}
+hwaddr loongarch_get_host_address(CPULoongArchState *env, hwaddr gpa,
+ uintptr_t retaddr)
+{
+ MMUContext host_context;
+ TLBRet ret;
+ CPUTLBEntryFull *full;
+ int flags = probe_access_full_mmu(env, gpa, 1, MMU_DATA_LOAD,
+ MMU_KERNEL_IDX + MMU_GUEST_IDX, NULL, &full);
+ if (!(flags & TLB_INVALID_MASK)) {
+ return (full->phys_addr & TARGET_PAGE_MASK) | (gpa & ~TARGET_PAGE_MASK);
+ }
+
+ host_context.addr = gpa;
+ host_context.tlb_index = -1;
+ ret = loongarch_map_host_address(env, &host_context, MMU_DATA_LOAD,
+ retaddr);
+
+ if (ret != TLBRET_HOST_MATCH) {
+ raise_mmu_exception(env, gpa, MMU_DATA_LOAD, ret);
+ cpu_loop_exit_restore(env_cpu(env), retaddr);
+ }
+
+ return host_context.physical;
+}
+
target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
uint32_t level, uint32_t mem_idx)
{
@@ -785,7 +858,12 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
env_vm_level(env));
index = (badvaddr >> dir_base) & ((1 << dir_width) - 1);
phys = base | index << 3;
- val = address_space_ldq_le(cs->as, phys, MEMTXATTRS_UNSPECIFIED, NULL);
+ val = address_space_ldq_le(
+ cs->as,
+ env_vm_level(env) == VM_LEVEL1 ?
+ loongarch_get_host_address(env, phys, GETPC()) :
+ phys,
+ MEMTXATTRS_UNSPECIFIED, NULL);
return val & palen_mask;
}
@@ -855,8 +933,12 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
ptoffset0 = ptindex << 3;
ptoffset1 = (ptindex + 1) << 3;
phys = base | (odd ? ptoffset1 : ptoffset0);
- pte_raw = address_space_ldq_le(cs->as, phys,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ pte_raw = address_space_ldq_le(
+ cs->as,
+ env_vm_level(env) == VM_LEVEL1 ?
+ loongarch_get_host_address(env, phys, GETPC()) :
+ phys,
+ MEMTXATTRS_UNSPECIFIED, NULL);
tmp0 = loongarch_sanitize_hw_pte(env, pte_raw);
ps = ptbase;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 15/23] target/loongarch: add LVZ to invtlb
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (13 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 14/23] target/loongarch: add LVZ " SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 16/23] target/loongarch: add LVZ to ptw SignKirigami
` (7 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add op 0x9, 0xa-0xf to instruction invtlb to support vm level 1.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
.../tcg/insn_trans/trans_privileged.c.inc | 34 +++++++++++++
target/loongarch/tcg/tlb_helper.c | 51 ++++++++++++++++---
2 files changed, 77 insertions(+), 8 deletions(-)
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 493ed7f24b..00e8f61e42 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -328,6 +328,10 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
return false;
}
+ if (!avail_LVZ(ctx) && a->imm > 0x6) {
+ return false;
+ }
+
switch (a->imm) {
case 0x0:
case 0x1:
@@ -352,6 +356,36 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk,
tcg_constant_i32(0));
break;
+ case 0x9:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ //TODO: refine 0x9-0x16
+ gen_helper_invtlb_all(tcg_env, rj, tcg_constant_i32(0),
+ tcg_constant_i32(0));
+ break;
+ case 0xa:
+ gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(1),
+ tcg_constant_i32(1));
+ break;
+ case 0xb:
+ gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(0),
+ tcg_constant_i32(1));
+ break;
+ case 0xc:
+ gen_helper_invtlb_all_asid(tcg_env, rj, tcg_constant_i32(1));
+ break;
+ case 0xd:
+ gen_helper_invtlb_page_asid(tcg_env, rj, rk, tcg_constant_i32(1));
+ break;
+ case 0xe:
+ gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk,
+ tcg_constant_i32(1));
+ break;
default:
return false;
}
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 60c7193283..c02b7c2472 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -599,9 +599,18 @@ void helper_tlbflush(CPULoongArchState *env, uint32_t vm_level)
void helper_invtlb_all(CPULoongArchState *env, target_ulong info, uint32_t op,
uint32_t to_guest)
{
+ uint16_t gid = to_guest ? (info & 0xff) : get_tgid(env);
+
+ if (to_guest && env_vm_level(env) == VM_LEVEL1) {
+ do_raise_exception(env, EXCCODE_IPE, GETPC());
+ }
+
+ to_guest |= env_vm_level(env) == VM_LEVEL1;
+
for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
- env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc,
- TLB_MISC, E, 0);
+ LoongArchTLB *tlb = &env->tlb[i];
+ if ((op == 0 && to_guest == 0) || tlb_entry_matches_gid(tlb, gid))
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
}
tlb_flush(env_cpu(env));
}
@@ -609,11 +618,19 @@ void helper_invtlb_all(CPULoongArchState *env, target_ulong info, uint32_t op,
void helper_invtlb_all_g(CPULoongArchState *env, target_ulong info, uint32_t g,
uint32_t to_guest)
{
+ uint16_t gid = to_guest ? (info & 0xff) : get_tgid(env);
+
+ if (to_guest && env_vm_level(env) == VM_LEVEL1) {
+ do_raise_exception(env, EXCCODE_IPE, GETPC());
+ }
+
+ to_guest |= env_vm_level(env) == VM_LEVEL1;
+
for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
LoongArchTLB *tlb = &env->tlb[i];
uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
- if (tlb_g == g) {
+ if (tlb_g == g && tlb_entry_matches_gid(tlb, gid)) {
tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
}
}
@@ -624,13 +641,19 @@ void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info,
uint32_t to_guest)
{
uint16_t asid = info & R_CSR_ASID_ASID_MASK;
+ uint16_t gid = to_guest ? ((info >> 16) & 0xff) : get_tgid(env);
+
+ if (to_guest) {
+ do_raise_exception(env, EXCCODE_IPE, GETPC());
+ }
+ to_guest |= env_vm_level(env);
for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
LoongArchTLB *tlb = &env->tlb[i];
uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
- if (!tlb_g && (tlb_asid == asid)) {
+ if (!tlb_g && tlb_asid == asid && tlb_entry_matches_gid(tlb, gid)) {
tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
}
}
@@ -640,12 +663,19 @@ void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info,
void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info,
target_ulong addr, uint32_t to_guest)
{
- int asid = info & 0x3ff;
+
+ uint16_t asid = info & R_CSR_ASID_ASID_MASK;
+ uint16_t gid = to_guest ? ((info >> 16) & 0xff) : get_tgid(env);
const LoongArchTLB *tlb;
tlb_match func;
+ if (to_guest && env_vm_level(env)) {
+ do_raise_exception(env, EXCCODE_IPE, GETPC());
+ }
+ to_guest |= env_vm_level(env);
+
func = tlb_match_asid;
- tlb = loongarch_tlb_search_cb(env, addr, asid, func, to_guest, 0);
+ tlb = loongarch_tlb_search_cb(env, addr, asid, func, to_guest, gid);
if (tlb) {
invalidate_tlb(env, tlb - env->tlb, to_guest);
}
@@ -654,13 +684,18 @@ void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info,
void helper_invtlb_page_asid_or_g(CPULoongArchState *env, target_ulong info,
target_ulong addr, uint32_t to_guest)
{
- int asid = info & 0x3ff;
+ uint16_t asid = info & R_CSR_ASID_ASID_MASK;
+ uint16_t gid = to_guest ? ((info >> 16) & 0xff) : get_tgid(env);
const LoongArchTLB *tlb;
tlb_match func;
func = tlb_match_any;
+ if (to_guest) {
+ do_raise_exception(env, EXCCODE_IPE, GETPC());
+ }
+ to_guest |= env_vm_level(env);
tlb = loongarch_tlb_search_cb(env, addr, asid, func,
- to_guest, 0);
+ to_guest, gid);
if (tlb) {
invalidate_tlb(env, tlb - env->tlb, to_guest);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 16/23] target/loongarch: add LVZ to ptw
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (14 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 15/23] target/loongarch: add LVZ to invtlb SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 17/23] target/loongarch: add LVZ migration state SignKirigami
` (6 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add function loongarch_try_ptw() and use it in both vm level 0 and 1 address
mapping.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu-mmu.h | 2 +-
target/loongarch/cpu_helper.c | 23 ++++++---
target/loongarch/tcg/tlb_helper.c | 82 +++++++++++++++++--------------
3 files changed, 64 insertions(+), 43 deletions(-)
diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
index 29b0c109fb..bad05a5a9c 100644
--- a/target/loongarch/cpu-mmu.h
+++ b/target/loongarch/cpu-mmu.h
@@ -40,7 +40,7 @@ typedef struct MMUContext {
static inline bool cpu_has_ptw(CPULoongArchState *env, int vm_level)
{
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
return !!FIELD_EX64(sys->CSR_PWCH, CSR_PWCH, HPTW_EN);
}
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 23d26385c6..4ba991aaff 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -160,7 +160,7 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext *context,
vaddr address;
TLBRet ret;
MemTxResult ret1;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
address = context->addr;
if ((address >> 63) & 0x1) {
@@ -180,7 +180,10 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext *context,
/* get next level page directory */
index = (address >> dir_base) & ((1 << dir_width) - 1);
phys = base | index << 3;
- base = address_space_ldq_le(cs->as, phys, attrs, NULL);
+ base = address_space_ldq_le(
+ cs->as,
+ vm_level ? loongarch_get_host_address(env, phys, retaddr) : phys,
+ attrs, NULL);
if (level) {
if (FIELD_EX64(base, TLBENTRY, HUGE)) {
/* base is a huge pte */
@@ -214,8 +217,11 @@ restart:
index &= 1;
context->pte_buddy[index] = base;
- val = address_space_ldq_le(cs->as, phys + 8 * (1 - 2 * index),
- attrs, NULL);
+ val = address_space_ldq_le(
+ cs->as,
+ (vm_level ? loongarch_get_host_address(env, phys, retaddr) : phys) +
+ 8 * (1 - 2 * index),
+ attrs, NULL);
context->pte_buddy[1 - index] = val;
}
@@ -245,10 +251,15 @@ restart:
if (access_type == MMU_DATA_STORE) {
base = pte_mkdirty(base);
}
- ret1 = loongarch_cmpxchg_phys(cs, phys, pte, base);
+ ret1 = loongarch_cmpxchg_phys(
+ cs, vm_level ? loongarch_get_host_address(env, phys, retaddr) : phys,
+ pte, base);
/* PTE updated by other CPU, reload PTE entry */
if (ret1 == MEMTX_DECODE_ERROR) {
- base = address_space_ldq_le(cs->as, phys, attrs, NULL);
+ base = address_space_ldq_le(
+ cs->as,
+ vm_level ? loongarch_get_host_address(env, phys, retaddr) : phys,
+ attrs, NULL);
goto restart;
}
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index c02b7c2472..41d6138828 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -724,6 +724,46 @@ static TLBRet loongarch_map_host_address(CPULoongArchState *env, MMUContext *con
return TLBRET_HOST_MATCH + ret;
}
+static void loongarch_try_ptw(CPULoongArchState *env, MMUContext *context,
+ MMUAccessType access_type, int mmu_index,
+ TLBRet *status, bool guest, uintptr_t retaddr)
+{
+ if ((*status == TLBRET_MATCH || *status == TLBRET_HOST_MATCH) &&
+ context->mmu_index != MMU_DA_IDX &&
+ context->mmu_index != MMU_GUEST_DA_IDX && cpu_has_ptw(env, guest)) {
+ bool need_update = true;
+
+ if (access_type == MMU_DATA_STORE && pte_dirty(context->pte)) {
+ need_update = false;
+ } else if (access_type != MMU_DATA_STORE && pte_access(context->pte)) {
+ need_update = false;
+ }
+
+ if (need_update) {
+ *status = (env_vm_level(env) == VM_LEVEL1 &&
+ !guest) ?
+ TLBRET_HOST_NOMATCH : TLBRET_NOMATCH;
+ }
+ }
+
+ if (*status != TLBRET_MATCH && *status != TLBRET_HOST_MATCH &&
+ cpu_has_ptw(env, guest)) {
+ if (*status == TLBRET_NOMATCH || *status == TLBRET_INVALID ||
+ *status == TLBRET_HOST_NOMATCH || *status == TLBRET_HOST_INVALID) {
+ *status = ((env_vm_level(env) == VM_LEVEL1 &&
+ !guest) ?
+ TLBRET_HOST_MATCH : TLBRET_MATCH) +
+ loongarch_ptw(env, context, access_type, mmu_index, 0,
+ guest, retaddr);
+ if (*status == TLBRET_MATCH || *status == TLBRET_HOST_MATCH) {
+ ptw_update_tlb(env, context, guest);
+ }
+ } else if (context->tlb_index >= 0) {
+ invalidate_tlb(env, context->tlb_index, guest);
+ }
+ }
+}
+
bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
@@ -739,42 +779,8 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
context.addr = address;
context.tlb_index = -1;
ret = get_physical_address(env, &context, access_type, mmu_idx, 0, retaddr);
- if (ret == TLBRET_MATCH && context.mmu_index != MMU_DA_IDX
- && cpu_has_ptw(env, vm_level)) {
- bool need_update = true;
-
- if (access_type == MMU_DATA_STORE && pte_dirty(context.pte)) {
- need_update = false;
- } else if (access_type != MMU_DATA_STORE && pte_access(context.pte)) {
- need_update = false;
-
- /*
- * FIXME: should context.prot be set without PAGE_WRITE with
- * pte_write(context.pte) && !pte_dirty(context.pte)??
- *
- * Otherwise there will be no loongarch_cpu_tlb_fill() function call
- * for MMU_DATA_STORE access_type in future since QEMU TLB with
- * prot PAGE_WRITE is added already
- */
- }
-
- if (need_update) {
- /* Need update bit A/D in PTE entry, take PTW again */
- ret = TLBRET_NOMATCH;
- }
- }
-
- if (ret != TLBRET_MATCH && cpu_has_ptw(env, vm_level)) {
- /* Take HW PTW if TLB missed or bit P is zero */
- if (ret == TLBRET_NOMATCH || ret == TLBRET_INVALID) {
- ret = loongarch_ptw(env, &context, access_type, mmu_idx, 0, vm_level, retaddr);
- if (ret == TLBRET_MATCH) {
- ptw_update_tlb(env, &context, vm_level);
- }
- } else if (context.tlb_index >= 0) {
- invalidate_tlb(env, context.tlb_index, vm_level);
- }
- }
+ loongarch_try_ptw(env, &context, access_type, mmu_idx, &ret, vm_level,
+ retaddr);
if (ret == TLBRET_MATCH) {
physical = context.physical;
@@ -784,6 +790,8 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
host_context.tlb_index = -1;
ret = loongarch_map_host_address(env, &host_context, access_type,
retaddr);
+ loongarch_try_ptw(env, &host_context, access_type, MMU_KERNEL_IDX,
+ &ret, false, retaddr);
if (ret != TLBRET_HOST_MATCH) {
if (probe) {
return false;
@@ -847,6 +855,8 @@ hwaddr loongarch_get_host_address(CPULoongArchState *env, hwaddr gpa,
host_context.tlb_index = -1;
ret = loongarch_map_host_address(env, &host_context, MMU_DATA_LOAD,
retaddr);
+ loongarch_try_ptw(env, &host_context, MMU_DATA_LOAD, MMU_KERNEL_IDX,
+ &ret, false, retaddr);
if (ret != TLBRET_HOST_MATCH) {
raise_mmu_exception(env, gpa, MMU_DATA_LOAD, ret);
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 17/23] target/loongarch: add LVZ migration state
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (15 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 16/23] target/loongarch: add LVZ to ptw SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 18/23] target/loongarch: add gcsr instructions and vm level 1 csr management SignKirigami
` (5 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Migrate the host LVZ controls, guest CSR and TLB banks, and restore the
active VM level, guest timer and interrupt request after loading state.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/machine.c | 104 +++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index 931a5ca5ba..7c14f7d92e 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -7,6 +7,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "internals.h"
#include "migration/vmstate.h"
#include "system/tcg.h"
#include "vec.h"
@@ -205,13 +206,115 @@ static const VMStateDescription vmstate_tlb = {
VMSTATE_END_OF_LIST()
}
};
+
+static const VMStateDescription vmstate_lvz_sys = {
+ .name = "cpu/lvz-sys",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(CSR_CRMD, CPUSysState),
+ VMSTATE_UINT64(CSR_PRMD, CPUSysState),
+ VMSTATE_UINT64(CSR_EUEN, CPUSysState),
+ VMSTATE_UINT64(CSR_MISC, CPUSysState),
+ VMSTATE_UINT64(CSR_ECFG, CPUSysState),
+ VMSTATE_UINT64(CSR_ESTAT, CPUSysState),
+ VMSTATE_UINT64(CSR_ERA, CPUSysState),
+ VMSTATE_UINT64(CSR_BADV, CPUSysState),
+ VMSTATE_UINT64(CSR_BADI, CPUSysState),
+ VMSTATE_UINT64(CSR_EENTRY, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBIDX, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBEHI, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBELO0, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBELO1, CPUSysState),
+ VMSTATE_UINT64(CSR_ASID, CPUSysState),
+ VMSTATE_UINT64(CSR_PGDL, CPUSysState),
+ VMSTATE_UINT64(CSR_PGDH, CPUSysState),
+ VMSTATE_UINT64(CSR_PGD, CPUSysState),
+ VMSTATE_UINT64(CSR_PWCL, CPUSysState),
+ VMSTATE_UINT64(CSR_PWCH, CPUSysState),
+ VMSTATE_UINT64(CSR_STLBPS, CPUSysState),
+ VMSTATE_UINT64(CSR_RVACFG, CPUSysState),
+ VMSTATE_UINT64(CSR_CPUID, CPUSysState),
+ VMSTATE_UINT64(CSR_PRCFG1, CPUSysState),
+ VMSTATE_UINT64(CSR_PRCFG2, CPUSysState),
+ VMSTATE_UINT64(CSR_PRCFG3, CPUSysState),
+ VMSTATE_UINT64_ARRAY(CSR_SAVE, CPUSysState, 16),
+ VMSTATE_UINT64(CSR_TID, CPUSysState),
+ VMSTATE_UINT64(CSR_TCFG, CPUSysState),
+ VMSTATE_UINT64(CSR_TVAL, CPUSysState),
+ VMSTATE_UINT64(CSR_CNTC, CPUSysState),
+ VMSTATE_UINT64(CSR_TICLR, CPUSysState),
+ VMSTATE_UINT64(CSR_LLBCTL, CPUSysState),
+ VMSTATE_UINT64(CSR_IMPCTL1, CPUSysState),
+ VMSTATE_UINT64(CSR_IMPCTL2, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBRENTRY, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBRBADV, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBRERA, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBRSAVE, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBRELO0, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBRELO1, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBREHI, CPUSysState),
+ VMSTATE_UINT64(CSR_TLBRPRMD, CPUSysState),
+ VMSTATE_UINT64(CSR_MERRCTL, CPUSysState),
+ VMSTATE_UINT64(CSR_MERRINFO1, CPUSysState),
+ VMSTATE_UINT64(CSR_MERRINFO2, CPUSysState),
+ VMSTATE_UINT64(CSR_MERRENTRY, CPUSysState),
+ VMSTATE_UINT64(CSR_MERRERA, CPUSysState),
+ VMSTATE_UINT64(CSR_MERRSAVE, CPUSysState),
+ VMSTATE_UINT64(CSR_CTAG, CPUSysState),
+ VMSTATE_UINT64_ARRAY(CSR_DMW, CPUSysState, 4),
+ VMSTATE_UINT64(CSR_DBG, CPUSysState),
+ VMSTATE_UINT64(CSR_DERA, CPUSysState),
+ VMSTATE_UINT64(CSR_DSAVE, CPUSysState),
+ VMSTATE_UINT64(CSR_GSTAT, CPUSysState),
+ VMSTATE_UINT64(CSR_GCFG, CPUSysState),
+ VMSTATE_UINT64(CSR_GINTC, CPUSysState),
+ VMSTATE_UINT64(CSR_GCNTC, CPUSysState),
+ VMSTATE_UINT64(CSR_GTLBC, CPUSysState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool lvz_needed(void *opaque)
+{
+ LoongArchCPU *cpu = opaque;
+ return FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, LVZ);
+}
+
+static const VMStateDescription vmstate_lvz = {
+ .name = "cpu/lvz",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = lvz_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(env.sys_states[0].CSR_GSTAT, LoongArchCPU),
+ VMSTATE_UINT64(env.sys_states[0].CSR_GCFG, LoongArchCPU),
+ VMSTATE_UINT64(env.sys_states[0].CSR_GINTC, LoongArchCPU),
+ VMSTATE_UINT64(env.sys_states[0].CSR_GCNTC, LoongArchCPU),
+ VMSTATE_UINT64(env.sys_states[0].CSR_GTLBC, LoongArchCPU),
+ VMSTATE_STRUCT(env.sys_states[1], LoongArchCPU, 0,
+ vmstate_lvz_sys, CPUSysState),
+ VMSTATE_END_OF_LIST()
+ },
+};
#endif
+static int loongarch_cpu_post_load(void *opaque, int version_id)
+{
+ LoongArchCPU *cpu = opaque;
+ CPULoongArchState *env = &cpu->env;
+ CPUSysState *host = get_sys(env, VM_LEVEL0);
+ bool guest = FIELD_EX64(host->CSR_GSTAT, CSR_GSTAT, VM);
+ set_sys(env, guest);
+ return 0;
+}
+
/* LoongArch CPU state */
const VMStateDescription vmstate_loongarch_cpu = {
.name = "cpu",
.version_id = 4,
.minimum_version_id = 4,
+ .post_load = loongarch_cpu_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT64_ARRAY(env.gpr, LoongArchCPU, 32),
VMSTATE_UINT64(env.pc, LoongArchCPU),
@@ -285,6 +388,7 @@ const VMStateDescription vmstate_loongarch_cpu = {
&vmstate_lasx,
#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
&vmstate_tlb,
+ &vmstate_lvz,
#endif
&vmstate_lbt,
&vmstate_msgint,
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 18/23] target/loongarch: add gcsr instructions and vm level 1 csr management
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (16 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 17/23] target/loongarch: add LVZ migration state SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 19/23] target/loongarch: add LVZ CSRs SignKirigami
` (4 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add gcsrrd, gcsrwr and gcsrxchg. Make all csr helper be used by both vm level
0 and 1.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/disas.c | 3 +
target/loongarch/insns.decode | 6 +
target/loongarch/tcg/csr_helper.c | 78 +++++++-----
target/loongarch/tcg/helper.h | 22 ++--
.../tcg/insn_trans/trans_privileged.c.inc | 111 ++++++++++++++----
5 files changed, 161 insertions(+), 59 deletions(-)
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 03d1e560dd..2436c9eec3 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -682,6 +682,9 @@ INSN(bgeu, rr_offs)
INSN(csrrd, r_csr)
INSN(csrwr, r_csr)
INSN(csrxchg, rr_csr)
+INSN(gcsrrd, r_csr)
+INSN(gcsrwr, r_csr)
+INSN(gcsrxchg, rr_csr)
INSN(iocsrrd_b, rr)
INSN(iocsrrd_h, rr)
INSN(iocsrrd_w, rr)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 3089d42044..4612af9433 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -493,6 +493,12 @@ bgeu 0110 11 ................ ..... ..... @rr_offs16
csrxchg 0000 0100 .............. ..... ..... @rr_csr
}
+{
+ gcsrrd 0000 0101 .............. 00000 ..... @r_csr
+ gcsrwr 0000 0101 .............. 00001 ..... @r_csr
+ gcsrxchg 0000 0101 .............. ..... ..... @rr_csr
+}
+
iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr
iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr
iocsrrd_w 0000 01100100 10000 00010 ..... ..... @rr
diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c
index ecfba63228..7ef0032f5d 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -18,9 +18,10 @@
#include "cpu-csr.h"
#include "cpu-mmu.h"
-target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_stlbps(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
{
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
int64_t old_v = sys->CSR_STLBPS;
/*
@@ -40,10 +41,10 @@ target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val)
return old_v;
}
-target_ulong helper_csrrd_pgd(CPULoongArchState *env)
+target_ulong helper_csrrd_pgd(CPULoongArchState *env, uint32_t vm_level)
{
int64_t v;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
if (sys->CSR_TLBRERA & 0x1) {
v = sys->CSR_TLBRBADV;
@@ -60,25 +61,30 @@ target_ulong helper_csrrd_pgd(CPULoongArchState *env)
return v;
}
-target_ulong helper_csrrd_cpuid(CPULoongArchState *env)
+target_ulong helper_csrrd_cpuid(CPULoongArchState *env, uint32_t vm_level)
{
LoongArchCPU *lac = env_archcpu(env);
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
+
+ if (vm_level) {
+ return sys->CSR_CPUID;
+ }
sys->CSR_CPUID = CPU(lac)->cpu_index;
return sys->CSR_CPUID;
}
-target_ulong helper_csrrd_tval(CPULoongArchState *env)
+target_ulong helper_csrrd_tval(CPULoongArchState *env, uint32_t vm_level)
{
- return cpu_loongarch_get_timer_ticks(env_timer(env));
+ CPUTimerState *timer = vm_level ? env_guest_timer(env) : env_timer(env);
+ return cpu_loongarch_get_timer_ticks(timer);
}
-target_ulong helper_csrrd_msgir(CPULoongArchState *env)
+target_ulong helper_csrrd_msgir(CPULoongArchState *env, uint32_t vm_level)
{
int irq, new;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
irq = find_first_bit((unsigned long *)sys->CSR_MSGIS, 256);
if (irq < 256) {
@@ -97,13 +103,23 @@ target_ulong helper_csrrd_msgir(CPULoongArchState *env)
return irq;
}
-target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_estat(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
{
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
int64_t old_v = sys->CSR_ESTAT;
- /* Only IS[1:0] can be written */
+ /* When guest = 0, only IS[1:0] can be written.
+ * When guest = 1, ecode and esubcode of
+ * VM_LEVEL1 can be written by VM_LEVEL0.
+ */
sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 0, 2, val);
+ if (vm_level) {
+ sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 2, 11,
+ extract64(val, 2, 11));
+ sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 16, 15,
+ extract64(val, 16, 15));
+ }
/*
* Software interrupts (SWI0/SWI1) are latched in CSR.ESTAT.IS[1:0].
* Make sure the CPU interrupt request state tracks the pending bits,
@@ -111,16 +127,17 @@ target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
*/
if (sys->CSR_ESTAT != old_v) {
bql_lock();
- loongarch_cpu_update_irq(env_archcpu(env), false);
+ loongarch_cpu_update_irq(env_archcpu(env), vm_level);
bql_unlock();
}
return old_v;
}
-target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_asid(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
{
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
int64_t old_v = sys->CSR_ASID;
/* Only ASID filed of CSR_ASID can be written */
@@ -131,9 +148,10 @@ target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val)
return old_v;
}
-target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_tcfg(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
{
- CPUTimerState *timer = env_timer(env);
+ CPUTimerState *timer = vm_level ? env_guest_timer(env) : env_timer(env);
CPUSysState *sys = container_of(timer, CPUSysState, timer_state);
int64_t old_v = sys->CSR_TCFG;
@@ -142,9 +160,10 @@ target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val)
return old_v;
}
-target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_ticlr(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
{
- CPUTimerState *timer = env_timer(env);
+ CPUTimerState *timer = vm_level ? env_guest_timer(env) : env_timer(env);
int64_t old_v = 0;
if (val & 0x1) {
@@ -155,10 +174,11 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
return old_v;
}
-target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_pwcl(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
{
uint8_t shift, ptbase;
- CPUSysState *sys = env_sys(env);
+ CPUSysState *sys = get_sys(env, vm_level);
int64_t old_v = sys->CSR_PWCL;
/*
@@ -180,18 +200,20 @@ target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val)
return old_v;
}
-target_ulong helper_csrwr_pwch(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_pwch(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
{
- uint8_t has_ptw;
- CPUSysState *sys = env_sys(env);
+ uint8_t host_has_ptw;
+ CPUSysState *sys = get_sys(env, vm_level);
int64_t old_v = sys->CSR_PWCH;
val = FIELD_DP64(val, CSR_PWCH, RESERVE, 0);
- has_ptw = FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW);
- if (!has_ptw) {
+ //TODO: host can't read guest cpucfg
+ host_has_ptw = FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW);
+ if (!host_has_ptw) {
val = FIELD_DP64(val, CSR_PWCH, HPTW_EN, 0);
}
sys->CSR_PWCH = val;
return old_v;
- }
+}
diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h
index a27b80b087..bce5f46dc2 100644
--- a/target/loongarch/tcg/helper.h
+++ b/target/loongarch/tcg/helper.h
@@ -93,17 +93,17 @@ DEF_HELPER_1(rdtime_d, i64, env)
#ifndef CONFIG_USER_ONLY
/* CSRs helper */
-DEF_HELPER_1(csrrd_pgd, i64, env)
-DEF_HELPER_1(csrrd_cpuid, i64, env)
-DEF_HELPER_1(csrrd_tval, i64, env)
-DEF_HELPER_1(csrrd_msgir, i64, env)
-DEF_HELPER_2(csrwr_stlbps, i64, env, tl)
-DEF_HELPER_2(csrwr_estat, i64, env, tl)
-DEF_HELPER_2(csrwr_asid, i64, env, tl)
-DEF_HELPER_2(csrwr_tcfg, i64, env, tl)
-DEF_HELPER_2(csrwr_ticlr, i64, env, tl)
-DEF_HELPER_2(csrwr_pwcl, i64, env, tl)
-DEF_HELPER_2(csrwr_pwch, i64, env, tl)
+DEF_HELPER_2(csrrd_pgd, i64, env, i32)
+DEF_HELPER_2(csrrd_cpuid, i64, env, i32)
+DEF_HELPER_2(csrrd_tval, i64, env, i32)
+DEF_HELPER_2(csrrd_msgir, i64, env, i32)
+DEF_HELPER_3(csrwr_stlbps, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_estat, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_asid, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_tcfg, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_ticlr, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_pwcl, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_pwch, i64, env, tl, i32)
DEF_HELPER_2(iocsrrd_b, i64, env, tl)
DEF_HELPER_2(iocsrrd_h, i64, env, tl)
DEF_HELPER_2(iocsrrd_w, i64, env, tl)
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 00e8f61e42..139dbd6e2a 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -39,11 +39,14 @@ GEN_FALSE_TRANS(lddir)
GEN_FALSE_TRANS(ertn)
GEN_FALSE_TRANS(dbcl)
GEN_FALSE_TRANS(idle)
+GEN_FALSE_TRANS(gcsrrd)
+GEN_FALSE_TRANS(gcsrwr)
+GEN_FALSE_TRANS(gcsrxchg)
#else
-typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
-typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src);
+typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env, TCGv_i32 vm_level);
+typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src, TCGv_i32 vm_level);
static bool check_plv(DisasContext *ctx)
{
@@ -88,10 +91,14 @@ void loongarch_csr_translate_init(void)
}
#undef SET_CSR_FUNC
-static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
+static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr,
+ bool write, int vm_level)
{
if ((csr->flags & CSRFL_READONLY) && write) {
- return false;
+ /* host writes guest read-only CSRs is allowed */
+ if (is_guest_mmu_idx(ctx->mem_idx) || vm_level == VM_LEVEL0) {
+ return false;
+ }
}
if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) {
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
@@ -101,7 +108,7 @@ static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
return true;
}
-static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
+static bool trans_csrrd_impl(DisasContext *ctx, arg_r_csr *a, int vm_level)
{
TCGv dest;
const CSRInfo *csr;
@@ -116,21 +123,29 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
/* CSR is undefined: read as 0. */
dest = tcg_constant_tl(0);
} else {
- check_csr_flags(ctx, csr, false);
- dest = gpr_dst(ctx, a->rd, EXT_NONE);
- readfn = (GenCSRRead)csr->readfn;
- if (readfn) {
- readfn(dest, tcg_env);
+ check_csr_flags(ctx, csr, false, vm_level);
+ if (vm_level && (csr->flags & CSRFL_GSPR)) {
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
+ dest = tcg_constant_tl(0);
} else {
- offset = get_csr_offset(csr, 0);
- tcg_gen_ld_tl(dest, tcg_env, offset);
+ dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ readfn = (GenCSRRead)csr->readfn;
+ if (readfn) {
+ readfn(dest, tcg_env, tcg_constant_i32(vm_level));
+ } else {
+ offset = get_csr_offset(csr, vm_level);
+ tcg_gen_ld_tl(dest, tcg_env, offset);
+ }
}
}
gen_set_gpr(a->rd, dest, EXT_NONE);
return true;
}
-static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
+static bool trans_csrwr_impl(DisasContext *ctx, arg_r_csr *a, int vm_level)
{
TCGv dest, src1;
const CSRInfo *csr;
@@ -146,18 +161,26 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
return true;
}
- if (!check_csr_flags(ctx, csr, true)) {
+ if (!check_csr_flags(ctx, csr, true, vm_level)) {
/* CSR is readonly: trap. */
return false;
}
+ if (vm_level && (csr->flags & CSRFL_GSPR)) {
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
+ gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+ return true;
+ }
src1 = gpr_src(ctx, a->rd, EXT_NONE);
writefn = (GenCSRWrite)csr->writefn;
if (writefn) {
dest = gpr_dst(ctx, a->rd, EXT_NONE);
- writefn(dest, tcg_env, src1);
+ writefn(dest, tcg_env, src1, tcg_constant_i32(vm_level));
} else {
dest = tcg_temp_new();
- offset = get_csr_offset(csr, 0);
+ offset = get_csr_offset(csr, vm_level);
tcg_gen_ld_tl(dest, tcg_env, offset);
tcg_gen_st_tl(src1, tcg_env, offset);
}
@@ -165,7 +188,7 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
return true;
}
-static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
+static bool trans_csrxchg_impl(DisasContext *ctx, arg_rr_csr *a, int vm_level)
{
TCGv src1, mask, oldv, newv, temp;
const CSRInfo *csr;
@@ -182,11 +205,20 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
return true;
}
- if (!check_csr_flags(ctx, csr, true)) {
+ if (!check_csr_flags(ctx, csr, true, vm_level)) {
/* CSR is readonly: trap. */
return false;
}
+ if (vm_level && (csr->flags & CSRFL_GSPR)) {
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
+ gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+ return true;
+ }
+
/* So far only readonly csrs have readfn. */
assert(csr->readfn == NULL);
@@ -196,7 +228,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
newv = tcg_temp_new();
temp = tcg_temp_new();
- offset = get_csr_offset(csr, 0);
+ offset = get_csr_offset(csr, vm_level);
tcg_gen_ld_tl(oldv, tcg_env, offset);
tcg_gen_and_tl(newv, src1, mask);
tcg_gen_andc_tl(temp, oldv, mask);
@@ -204,7 +236,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
writefn = (GenCSRWrite)csr->writefn;
if (writefn) {
- writefn(oldv, tcg_env, newv);
+ writefn(oldv, tcg_env, newv, tcg_constant_i32(vm_level));
} else {
tcg_gen_st_tl(newv, tcg_env, offset);
}
@@ -212,6 +244,45 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
return true;
}
+static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
+{
+ return trans_csrrd_impl(ctx, a, is_guest_mmu_idx(ctx->mem_idx));
+}
+
+static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
+{
+ return trans_csrwr_impl(ctx, a, is_guest_mmu_idx(ctx->mem_idx));
+}
+
+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
+{
+ return trans_csrxchg_impl(ctx, a, is_guest_mmu_idx(ctx->mem_idx));
+}
+
+static bool trans_gcsrrd(DisasContext *ctx, arg_gcsrrd *a)
+{
+ if (!avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ return trans_csrrd_impl(ctx, a, VM_LEVEL1);
+}
+
+static bool trans_gcsrwr(DisasContext *ctx, arg_gcsrwr *a)
+{
+ if (!avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ return trans_csrwr_impl(ctx, a, VM_LEVEL1);
+}
+
+static bool trans_gcsrxchg(DisasContext *ctx, arg_gcsrxchg *a)
+{
+ if (!avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ return trans_csrxchg_impl(ctx, a, VM_LEVEL1);
+}
+
static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a,
void (*func)(TCGv, TCGv_ptr, TCGv))
{
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 19/23] target/loongarch: add LVZ CSRs
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (17 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 18/23] target/loongarch: add gcsr instructions and vm level 1 csr management SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 20/23] target/loongarch: translate LVZ guest TLB instructions SignKirigami
` (3 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Add gstat, gtlbc and gintc definitions and corresponding helpers.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/tcg/csr_helper.c | 53 +++++++++++++++++++
target/loongarch/tcg/helper.h | 3 ++
.../tcg/insn_trans/trans_privileged.c.inc | 3 ++
3 files changed, 59 insertions(+)
diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c
index 7ef0032f5d..f113097046 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -217,3 +217,56 @@ target_ulong helper_csrwr_pwch(CPULoongArchState *env,
sys->CSR_PWCH = val;
return old_v;
}
+
+target_ulong helper_csrwr_gstat(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
+{
+ CPUSysState *sys = get_sys(env, VM_LEVEL0);
+ int64_t old_v = sys->CSR_GSTAT;
+ uint8_t old_gid = FIELD_EX64(sys->CSR_GSTAT, CSR_GSTAT, GID);
+
+ sys->CSR_GSTAT = FIELD_DP64(sys->CSR_GSTAT, CSR_GSTAT, PVM,
+ FIELD_EX64(val, CSR_GSTAT, PVM));
+ sys->CSR_GSTAT = FIELD_DP64(sys->CSR_GSTAT, CSR_GSTAT, GID,
+ FIELD_EX64(val, CSR_GSTAT, GID));
+
+ if (old_gid != FIELD_EX64(sys->CSR_GSTAT, CSR_GSTAT, GID)) {
+ tlb_flush(env_cpu(env));
+ }
+
+ return old_v;
+}
+
+target_ulong helper_csrwr_gtlbc(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
+{
+ CPUSysState *sys = get_sys(env, VM_LEVEL0);
+ int64_t old_v = sys->CSR_GTLBC;
+ uint8_t old_use_tgid = FIELD_EX64(old_v, CSR_GTLBC, USETGID);
+ uint8_t old_tgid = FIELD_EX64(old_v, CSR_GTLBC, TGID);
+
+ sys->CSR_GTLBC = val;
+ if (old_use_tgid != FIELD_EX64(sys->CSR_GTLBC, CSR_GTLBC, USETGID) ||
+ old_tgid != FIELD_EX64(sys->CSR_GTLBC, CSR_GTLBC, TGID)) {
+ tlb_flush(env_cpu(env));
+ }
+
+ return old_v;
+}
+
+target_ulong helper_csrwr_gintc(CPULoongArchState *env,
+ target_ulong val, uint32_t vm_level)
+{
+ CPUSysState *host = get_sys(env, VM_LEVEL0);
+ CPUSysState *guest = get_sys(env, VM_LEVEL1);
+ int64_t old_v = host->CSR_GINTC;
+ uint8_t hwis = FIELD_EX64(val, CSR_GINTC, HWIS);
+ /* TODO: hwip and hwic support */
+
+ host->CSR_GINTC = val & 0xffff00;
+ guest->CSR_ESTAT = deposit64(guest->CSR_ESTAT, 2, 8,
+ hwis);
+
+ return old_v;
+}
+
diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h
index bce5f46dc2..84eaee208c 100644
--- a/target/loongarch/tcg/helper.h
+++ b/target/loongarch/tcg/helper.h
@@ -104,6 +104,9 @@ DEF_HELPER_3(csrwr_tcfg, i64, env, tl, i32)
DEF_HELPER_3(csrwr_ticlr, i64, env, tl, i32)
DEF_HELPER_3(csrwr_pwcl, i64, env, tl, i32)
DEF_HELPER_3(csrwr_pwch, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_gstat, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_gtlbc, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_gintc, i64, env, tl, i32)
DEF_HELPER_2(iocsrrd_b, i64, env, tl)
DEF_HELPER_2(iocsrrd_h, i64, env, tl)
DEF_HELPER_2(iocsrrd_w, i64, env, tl)
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 139dbd6e2a..37b7ef13dc 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -88,6 +88,9 @@ void loongarch_csr_translate_init(void)
SET_CSR_FUNC(TVAL, gen_helper_csrrd_tval, NULL);
SET_CSR_FUNC(TICLR, NULL, gen_helper_csrwr_ticlr);
SET_CSR_FUNC(MSGIR, gen_helper_csrrd_msgir, NULL);
+ SET_CSR_FUNC(GSTAT, NULL, gen_helper_csrwr_gstat);
+ SET_CSR_FUNC(GTLBC, NULL, gen_helper_csrwr_gtlbc);
+ SET_CSR_FUNC(GINTC, NULL, gen_helper_csrwr_gintc);
}
#undef SET_CSR_FUNC
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 20/23] target/loongarch: translate LVZ guest TLB instructions
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (18 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 19/23] target/loongarch: add LVZ CSRs SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 21/23] target/loongarch: translate LVZ guest traps and HVC SignKirigami
` (2 subsequent siblings)
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Decode, disassemble and translate GTLBSRCH, GTLBRD, GTLBWR, GTLBFILL,
GTLBCLR and GTLBFLUSH for host LVZ execution.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/disas.c | 6 ++
target/loongarch/insns.decode | 7 +++
.../tcg/insn_trans/trans_privileged.c.inc | 60 +++++++++++++++++++
3 files changed, 73 insertions(+)
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 2436c9eec3..6425dea17c 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -700,6 +700,12 @@ INSN(tlbfill, empty)
INSN(tlbclr, empty)
INSN(tlbflush, empty)
INSN(invtlb, i_rr)
+INSN(gtlbclr, empty)
+INSN(gtlbflush, empty)
+INSN(gtlbsrch, empty)
+INSN(gtlbrd, empty)
+INSN(gtlbwr, empty)
+INSN(gtlbfill, empty)
INSN(cacop, cop_r_i)
INSN(lddir, rr_i)
INSN(ldpte, j_i)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 4612af9433..cbcc30c31f 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -499,6 +499,13 @@ bgeu 0110 11 ................ ..... ..... @rr_offs16
gcsrxchg 0000 0101 .............. ..... ..... @rr_csr
}
+gtlbclr 0000 01100100 10000 01000 00000 00001 @empty
+gtlbflush 0000 01100100 10000 01001 00000 00001 @empty
+gtlbsrch 0000 01100100 10000 01010 00000 00001 @empty
+gtlbrd 0000 01100100 10000 01011 00000 00001 @empty
+gtlbwr 0000 01100100 10000 01100 00000 00001 @empty
+gtlbfill 0000 01100100 10000 01101 00000 00001 @empty
+
iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr
iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr
iocsrrd_w 0000 01100100 10000 00010 ..... ..... @rr
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 37b7ef13dc..ae481aa83f 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -42,6 +42,12 @@ GEN_FALSE_TRANS(idle)
GEN_FALSE_TRANS(gcsrrd)
GEN_FALSE_TRANS(gcsrwr)
GEN_FALSE_TRANS(gcsrxchg)
+GEN_FALSE_TRANS(gtlbclr)
+GEN_FALSE_TRANS(gtlbflush)
+GEN_FALSE_TRANS(gtlbsrch)
+GEN_FALSE_TRANS(gtlbrd)
+GEN_FALSE_TRANS(gtlbwr)
+GEN_FALSE_TRANS(gtlbfill)
#else
@@ -339,6 +345,15 @@ static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a)
return true;
}
+static bool trans_gtlbsrch(DisasContext *ctx, arg_gtlbsrch *a)
+{
+ if (check_plv(ctx) || !avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ gen_helper_tlbsrch(tcg_env, tcg_constant_i32(1));
+ return true;
+}
+
static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a)
{
if (check_plv(ctx)) {
@@ -393,6 +408,51 @@ static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
return true;
}
+static bool trans_gtlbrd(DisasContext *ctx, arg_gtlbrd *a)
+{
+ if (check_plv(ctx) || !avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ gen_helper_tlbrd(tcg_env, tcg_constant_i32(1));
+ return true;
+}
+
+static bool trans_gtlbwr(DisasContext *ctx, arg_gtlbwr *a)
+{
+ if (check_plv(ctx) || !avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ gen_helper_tlbwr(tcg_env, tcg_constant_i32(1));
+ return true;
+}
+
+static bool trans_gtlbfill(DisasContext *ctx, arg_gtlbfill *a)
+{
+ if (check_plv(ctx) || !avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ gen_helper_tlbfill(tcg_env, tcg_constant_i32(1));
+ return true;
+}
+
+static bool trans_gtlbclr(DisasContext *ctx, arg_gtlbclr *a)
+{
+ if (check_plv(ctx) || !avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ gen_helper_tlbclr(tcg_env, tcg_constant_i32(1));
+ return true;
+}
+
+static bool trans_gtlbflush(DisasContext *ctx, arg_gtlbflush *a)
+{
+ if (check_plv(ctx) || !avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+ gen_helper_tlbflush(tcg_env, tcg_constant_i32(1));
+ return true;
+}
+
static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
{
TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 21/23] target/loongarch: translate LVZ guest traps and HVC
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (19 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 20/23] target/loongarch: translate LVZ guest TLB instructions SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 22/23] target/loongarch: initialize CSR related to LVZ SignKirigami
2026-10-09 3:05 ` [PATCH v5 23/23] target/loongarch: exit to vm level 0 for fpd, sxd and asxd of vm level 0 SignKirigami
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Raise GSPR when a guest accesses IOCSR, debug, idle and cpucfg resources,
and decode HVC for guest PLV0.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/disas.c | 1 +
target/loongarch/insns.decode | 1 +
target/loongarch/tcg/helper.h | 2 +-
| 5 +++
.../tcg/insn_trans/trans_privileged.c.inc | 32 +++++++++++++++++++
target/loongarch/tcg/op_helper.c | 3 ++
6 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 6425dea17c..7d47fc0151 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -706,6 +706,7 @@ INSN(gtlbsrch, empty)
INSN(gtlbrd, empty)
INSN(gtlbwr, empty)
INSN(gtlbfill, empty)
+INSN(hvcl, i)
INSN(cacop, cop_r_i)
INSN(lddir, rr_i)
INSN(ldpte, j_i)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index cbcc30c31f..b40fabe9d7 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -505,6 +505,7 @@ gtlbsrch 0000 01100100 10000 01010 00000 00001 @empty
gtlbrd 0000 01100100 10000 01011 00000 00001 @empty
gtlbwr 0000 01100100 10000 01100 00000 00001 @empty
gtlbfill 0000 01100100 10000 01101 00000 00001 @empty
+hvcl 0000 0000 0010 1011 1 ............... @i15
iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr
iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr
diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h
index 84eaee208c..be1573af9d 100644
--- a/target/loongarch/tcg/helper.h
+++ b/target/loongarch/tcg/helper.h
@@ -10,7 +10,7 @@ DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl)
DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl)
DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl)
-DEF_HELPER_FLAGS_2(cpucfg, TCG_CALL_NO_RWG_SE, tl, env, tl)
+DEF_HELPER_FLAGS_2(cpucfg, TCG_CALL_NO_WG_SE, tl, env, tl)
/* Floating-point helper */
DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_WG, i64, env, i64, i64)
--git a/target/loongarch/tcg/insn_trans/trans_extra.c.inc b/target/loongarch/tcg/insn_trans/trans_extra.c.inc
index 655dce329e..275755a1f0 100644
--- a/target/loongarch/tcg/insn_trans/trans_extra.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_extra.c.inc
@@ -82,6 +82,11 @@ static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a)
static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a)
{
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
+
TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index ae481aa83f..bd50e91422 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -48,6 +48,7 @@ GEN_FALSE_TRANS(gtlbsrch)
GEN_FALSE_TRANS(gtlbrd)
GEN_FALSE_TRANS(gtlbwr)
GEN_FALSE_TRANS(gtlbfill)
+GEN_FALSE_TRANS(hvcl)
#else
@@ -301,6 +302,10 @@ static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a,
if (check_plv(ctx)) {
return false;
}
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
func(dest, tcg_env, src1);
return true;
}
@@ -314,6 +319,10 @@ static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a,
if (check_plv(ctx)) {
return false;
}
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
func(tcg_env, addr, val);
return true;
}
@@ -584,6 +593,10 @@ static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a)
if (check_plv(ctx)) {
return false;
}
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
generate_exception(ctx, EXCCODE_DBP);
return true;
}
@@ -594,9 +607,28 @@ static bool trans_idle(DisasContext *ctx, arg_idle *a)
return false;
}
+ if (is_guest_mmu_idx(ctx->mem_idx)) {
+ generate_exception(ctx, EXCCODE_GSPR);
+ return true;
+ }
+
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
gen_helper_idle(tcg_env);
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}
+
+static bool trans_hvcl(DisasContext *ctx, arg_hvcl *a)
+{
+ if (!avail_LVZ(ctx) || !is_guest_mmu_idx(ctx->mem_idx)) {
+ return false;
+ }
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+
+ generate_exception(ctx, EXCCODE_HVC);
+ return true;
+}
#endif
diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c
index 3035dfa08d..e2fe4b212f 100644
--- a/target/loongarch/tcg/op_helper.c
+++ b/target/loongarch/tcg/op_helper.c
@@ -20,6 +20,9 @@
/* Exceptions helpers */
void helper_raise_exception(CPULoongArchState *env, uint32_t exception)
{
+ if (exception == EXCCODE_GSPR || exception == EXCCODE_HVC) {
+ trigger_vm_exit(env);
+ }
do_raise_exception(env, exception, GETPC());
}
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 22/23] target/loongarch: initialize CSR related to LVZ
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (20 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 21/23] target/loongarch: translate LVZ guest traps and HVC SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
2026-10-09 3:05 ` [PATCH v5 23/23] target/loongarch: exit to vm level 0 for fpd, sxd and asxd of vm level 0 SignKirigami
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami, Hengyu Yu
Initialize CSR.GSTAT.GIDBITS and GCSR.ASID.ASIDBITS at cpu init function.
Signed-off-by: SignKirigami <prcups@krgm.moe>
Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
---
target/loongarch/cpu.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 8e759a2987..1522e64b9c 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -334,7 +334,7 @@ static void loongarch_la464_initfn(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
CPULoongArchState *env = &cpu->env;
- CPUSysState *sys;
+ CPUSysState *sys, *guest;
uint32_t data = 0, field;
int i;
@@ -448,6 +448,9 @@ static void loongarch_la464_initfn(Object *obj)
sys = env_sys(env);
sys->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa);
+ sys->CSR_GSTAT = FIELD_DP64(0, CSR_GSTAT, GIDBITS, 8);
+ guest = get_sys(env, VM_LEVEL1);
+ guest->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa);
sys->CSR_PRCFG1 = FIELD_DP64(sys->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM, 8);
sys->CSR_PRCFG1 = FIELD_DP64(sys->CSR_PRCFG1, CSR_PRCFG1, TIMER_BITS, 0x2f);
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v5 23/23] target/loongarch: exit to vm level 0 for fpd, sxd and asxd of vm level 0
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
` (21 preceding siblings ...)
2026-10-09 3:05 ` [PATCH v5 22/23] target/loongarch: initialize CSR related to LVZ SignKirigami
@ 2026-10-09 3:05 ` SignKirigami
22 siblings, 0 replies; 31+ messages in thread
From: SignKirigami @ 2026-10-09 3:05 UTC (permalink / raw)
To: qemu-devel; +Cc: Bibo Mao, SignKirigami
When vm level 0 fpe, sxe and asxe is set to 0, although on vm level 1 these
are enabled, in TCGTBCPUState flags corresponding bit should not be set, and
when handling exceptions, executing trigger_vm_exit() in this situation.
Signed-off-by: SignKirigami <prcups@krgm.moe>
---
target/loongarch/tcg/op_helper.c | 20 ++++++++++++++++++++
target/loongarch/tcg/tcg_cpu.c | 17 ++++++++++++-----
2 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c
index e2fe4b212f..a24a9b8b6a 100644
--- a/target/loongarch/tcg/op_helper.c
+++ b/target/loongarch/tcg/op_helper.c
@@ -20,9 +20,29 @@
/* Exceptions helpers */
void helper_raise_exception(CPULoongArchState *env, uint32_t exception)
{
+ CPUSysState *host;
+ int vm_exit = 0;
+
if (exception == EXCCODE_GSPR || exception == EXCCODE_HVC) {
+ vm_exit = 1;
+ } else if (env_vm_level(env)) {
+ host = get_sys(env, VM_LEVEL0);
+ if (exception == EXCCODE_FPD &&
+ FIELD_EX64(host->CSR_EUEN, CSR_EUEN, FPE) == 0) {
+ vm_exit = 1;
+ } else if (exception == EXCCODE_SXD &&
+ FIELD_EX64(host->CSR_EUEN, CSR_EUEN, SXE) == 0) {
+ vm_exit = 1;
+ }
+ if (exception == EXCCODE_ASXD &&
+ FIELD_EX64(host->CSR_EUEN, CSR_EUEN, ASXE) == 0) {
+ vm_exit = 1;
+ }
+ }
+ if (vm_exit) {
trigger_vm_exit(env);
}
+
do_raise_exception(env, exception, GETPC());
}
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index 6f1ba12edb..f70efaad78 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -304,16 +304,23 @@ static vaddr loongarch_pointer_wrap(CPUState *cs, int mmu_idx,
static TCGTBCPUState loongarch_get_tb_cpu_state(CPUState *cs)
{
CPULoongArchState *env = cpu_env(cs);
- CPUSysState *sys = env_sys(env);
- uint32_t flags;
+ CPUSysState *sys = env_sys(env), *host;
+ uint32_t flags, fpe, sxe, asxe;
flags = sys->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK);
+ fpe = FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, FPE);
+ sxe = FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, SXE);
+ asxe = FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, ASXE);
if (env_vm_level(env) == VM_LEVEL1) {
flags |= HW_FLAGS_GUEST_MODE;
+ host = get_sys(env, VM_LEVEL0);
+ fpe &= FIELD_EX64(host->CSR_EUEN, CSR_EUEN, FPE);
+ sxe &= FIELD_EX64(host->CSR_EUEN, CSR_EUEN, SXE);
+ asxe &= FIELD_EX64(host->CSR_EUEN, CSR_EUEN, ASXE);
}
- flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE;
- flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE;
- flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_ASXE;
+ flags |= fpe * HW_FLAGS_EUEN_FPE;
+ flags |= sxe * HW_FLAGS_EUEN_SXE;
+ flags |= asxe * HW_FLAGS_EUEN_ASXE;
flags |= is_va32(env) * HW_FLAGS_VA32;
return (TCGTBCPUState){ .pc = env->pc, .flags = flags };
--
2.55.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v5 03/23] target/loongarch: add LVZ feature switcher
2026-10-09 3:04 ` [PATCH v5 03/23] target/loongarch: add LVZ feature switcher SignKirigami
@ 2026-10-10 3:20 ` Bibo Mao
0 siblings, 0 replies; 31+ messages in thread
From: Bibo Mao @ 2026-10-10 3:20 UTC (permalink / raw)
To: SignKirigami, qemu-devel; +Cc: Hengyu Yu
On 2026/10/9 上午11:04, SignKirigami wrote:
> Add LVZ property and AVAIL_LVZ macro based on cpucfg.
>
> Signed-off-by: SignKirigami <prcups@krgm.moe>
> Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
> ---
> target/loongarch/cpu.c | 33 +++++++++++++++++++++++++++++++--
> target/loongarch/cpu.h | 6 ++++++
> target/loongarch/translate.h | 1 +
> 3 files changed, 38 insertions(+), 2 deletions(-)
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index e1245235be..664763137d 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -267,11 +267,33 @@ static void loongarch_set_ptw(Object *obj, bool value, Error **errp)
> cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, HPTW, value);
> }
>
> +static bool loongarch_get_lvz(Object *obj, Error **errp)
> +{
> + return LOONGARCH_CPU(obj)->lvz != ON_OFF_AUTO_OFF;
> +}
> +
> +static void loongarch_set_lvz(Object *obj, bool value, Error **errp)
> +{
> + LoongArchCPU *cpu = LOONGARCH_CPU(obj);
> +
> + cpu->lvz = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
> +
> + if (kvm_enabled()) {
> + /* lvz can not be only enabled in kvm mode currently */
> + return;
> + }
This can be removed if tcg_enabled() is added lvz option.
> +
> + cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LVZ, value);
> + cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LVZ_VER,
> + value ? 1 : 0);
> +}
> +
> static void loongarch_cpu_post_init(Object *obj)
> {
> LoongArchCPU *cpu = LOONGARCH_CPU(obj);
>
> cpu->lbt = ON_OFF_AUTO_OFF;
> + cpu->lvz = ON_OFF_AUTO_AUTO;
> cpu->pmu = ON_OFF_AUTO_OFF;
> cpu->lsx = ON_OFF_AUTO_AUTO;
> cpu->lasx = ON_OFF_AUTO_AUTO;
> @@ -283,6 +305,9 @@ static void loongarch_cpu_post_init(Object *obj)
> loongarch_set_msgint);
> object_property_add_bool(obj, "ptw", loongarch_get_ptw,
> loongarch_set_ptw);
> + object_property_add_bool(obj, "lvz", loongarch_get_lvz,
> + loongarch_set_lvz);
> +
how about adding if (tcg_enabled()) with lvz property.
> /* lbt is enabled only in kvm mode, not supported in tcg mode */
>
> if (kvm_enabled()) {
> @@ -336,8 +361,12 @@ static void loongarch_la464_initfn(Object *obj)
> data = FIELD_DP32(data, CPUCFG2, FP_SP, 1);
> data = FIELD_DP32(data, CPUCFG2, FP_DP, 1);
> data = FIELD_DP32(data, CPUCFG2, FP_VER, 1);
> - data = FIELD_DP32(data, CPUCFG2, LSX, 1),
> - data = FIELD_DP32(data, CPUCFG2, LASX, 1),
> + data = FIELD_DP32(data, CPUCFG2, LSX, 1);
> + data = FIELD_DP32(data, CPUCFG2, LASX, 1);
Good catch, thanks for change , with ; :=)
The others look good to me.
Regards
Bibo Mao
> + if (tcg_enabled()) {
> + data = FIELD_DP32(data, CPUCFG2, LVZ, 1);
> + data = FIELD_DP32(data, CPUCFG2, LVZ_VER, 1);
> + }
> data = FIELD_DP32(data, CPUCFG2, LLFTP, 1);
> data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1);
> data = FIELD_DP32(data, CPUCFG2, LSPW, 1);
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index c0edcc9065..918378ee9a 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -460,6 +460,7 @@ struct ArchCPU {
> CPULoongArchState env;
> uint32_t phy_id;
> OnOffAuto lbt;
> + OnOffAuto lvz;
> OnOffAuto pmu;
> OnOffAuto ptw;
> OnOffAuto lsx;
> @@ -520,6 +521,11 @@ static inline CPUSysState *get_sys(CPULoongArchState *env, int vm_level)
> return &env->sys_states[vm_level];
> }
>
> +static inline bool cpu_has_lvz(CPULoongArchState *env)
> +{
> + return FIELD_EX32(env->cpucfg[2], CPUCFG2, LVZ);
> +}
> +
> static inline CPUTimerState *env_timer(CPULoongArchState *env)
> {
> return &env->sys_states[0].timer_state;
> diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h
> index 8aa8325dc6..a7c165982c 100644
> --- a/target/loongarch/translate.h
> +++ b/target/loongarch/translate.h
> @@ -24,6 +24,7 @@
> #define avail_FP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP))
> #define avail_FP_SP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_SP))
> #define avail_FP_DP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_DP))
> +#define avail_LVZ(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LVZ))
> #define avail_LSPW(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSPW))
> #define avail_LAM(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM))
> #define avail_LAM_BH(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM_BH))
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v5 01/23] target/loongarch: select sys state by VM level
2026-10-09 3:04 ` [PATCH v5 01/23] target/loongarch: select sys state by VM level SignKirigami
@ 2026-10-10 3:21 ` Bibo Mao
0 siblings, 0 replies; 31+ messages in thread
From: Bibo Mao @ 2026-10-10 3:21 UTC (permalink / raw)
To: SignKirigami, qemu-devel
On 2026/10/9 上午11:04, SignKirigami wrote:
> Define VM_LEVEL0 and VM_LEVELS for the available VM levels. Replace
> set_sys_state(), which accepted a CPUSysState pointer, with set_sys(),
> which selects a state by VM level. There is no function change in this
> patch.
> ---
> target/loongarch/cpu.c | 4 ++--
> target/loongarch/cpu.h | 7 +++++--
> 2 files changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 54c2699897..6c6e1d81b8 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -298,7 +298,7 @@ static void loongarch_la464_initfn(Object *obj)
> uint32_t data = 0, field;
> int i;
>
> - set_sys_state(env, &env->sys_states[0]);
> + set_sys(env, VM_LEVEL0);
> for (i = 0; i < 21; i++) {
> env->cpucfg[i] = 0x0;
> }
> @@ -428,7 +428,7 @@ static void loongarch_la132_initfn(Object *obj)
> uint32_t data = 0;
> int i;
>
> - set_sys_state(env, &env->sys_states[0]);
> + set_sys(env, VM_LEVEL0);
> for (i = 0; i < 21; i++) {
> env->cpucfg[i] = 0x0;
> }
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index c592f69885..391445f614 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -321,6 +321,9 @@ typedef struct CPUTimerState {
> CPUState *cs;
> } CPUTimerState;
>
> +#define VM_LEVEL0 0
> +#define VM_LEVELS 1
> +
> #define CPU_VENDOR_LOONGSON "Loongson"
> #define CPU_MODEL_3A5000 "3A5000"
> #define CPU_MODEL_1C101 "1C101"
> @@ -507,9 +510,9 @@ static inline CPUSysState *env_sys(CPULoongArchState *env)
> return env->sys_state;
> }
>
> -static inline void set_sys_state(CPULoongArchState *env, CPUSysState *sys)
> +static inline void set_sys(CPULoongArchState *env, int vm_level)
> {
> - env->sys_state = sys;
> + env->sys_state = &env->sys_states[vm_level];
> }
>
> static inline CPUTimerState *env_timer(CPULoongArchState *env)
>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v5 02/23] target/loongarch: add get_sys() helper
2026-10-09 3:04 ` [PATCH v5 02/23] target/loongarch: add get_sys() helper SignKirigami
@ 2026-10-10 3:21 ` Bibo Mao
0 siblings, 0 replies; 31+ messages in thread
From: Bibo Mao @ 2026-10-10 3:21 UTC (permalink / raw)
To: SignKirigami, qemu-devel; +Cc: Hengyu Yu
On 2026/10/9 上午11:04, SignKirigami wrote:
> Add get_sys() to retrieve a CPUSysState by VM level. Use it to access
> the host state in CPU reset path to handle possible reset requests under
> vm_level 1.
>
> Signed-off-by: SignKirigami <prcups@krgm.moe>
> Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
> ---
> target/loongarch/cpu.c | 2 +-
> target/loongarch/cpu.h | 5 +++++
> 2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 6c6e1d81b8..e1245235be 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -621,7 +621,7 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
> CPUState *cs = CPU(obj);
> LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(obj);
> CPULoongArchState *env = cpu_env(cs);
> - CPUSysState *sys = env_sys(env);
> + CPUSysState *sys = get_sys(env, VM_LEVEL0);
>
> if (lacc->parent_phases.hold) {
> lacc->parent_phases.hold(obj, type);
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 391445f614..c0edcc9065 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -515,6 +515,11 @@ static inline void set_sys(CPULoongArchState *env, int vm_level)
> env->sys_state = &env->sys_states[vm_level];
> }
>
> +static inline CPUSysState *get_sys(CPULoongArchState *env, int vm_level)
> +{
> + return &env->sys_states[vm_level];
> +}
> +
> static inline CPUTimerState *env_timer(CPULoongArchState *env)
> {
> return &env->sys_states[0].timer_state;
>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v5 06/23] target/loongarch: add definition about guest mmu_idx
2026-10-09 3:05 ` [PATCH v5 06/23] target/loongarch: add definition about guest mmu_idx SignKirigami
@ 2026-10-10 3:36 ` Bibo Mao
0 siblings, 0 replies; 31+ messages in thread
From: Bibo Mao @ 2026-10-10 3:36 UTC (permalink / raw)
To: SignKirigami, qemu-devel; +Cc: Hengyu Yu
On 2026/10/9 上午11:05, SignKirigami wrote:
> Add MMU_GUEST_IDX and MMU_GUEST_DA_IDX. Provide is_guest_mmu idx() and
> mmu_idx_to_plv to calculate plv with new mmu_idx.
>
> Signed-off-by: SignKirigami <prcups@krgm.moe>
> Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
> ---
> target/loongarch/cpu.h | 18 ++++++++++++++++++
> .../tcg/insn_trans/trans_privileged.c.inc | 2 +-
> target/loongarch/tcg/tcg_cpu.c | 7 +++++++
> target/loongarch/tcg/translate.c | 3 +++
> 4 files changed, 29 insertions(+), 1 deletion(-)
>
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 183210efd8..9eea1badaf 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -513,6 +513,24 @@ struct LoongArchCPUClass {
> #define MMU_KERNEL_IDX MMU_PLV_KERNEL
> #define MMU_USER_IDX MMU_PLV_USER
> #define MMU_DA_IDX 4
> +#define MMU_GUEST_IDX 5
> +#define MMU_GUEST_DA_IDX 9
how about replace constant 9 with (MMU_DA_IDX + MMU_GUEST_DA_IDX).
> +
> +static inline bool is_guest_mmu_idx(int mmu_idx)
> +{
> + return mmu_idx >= MMU_GUEST_IDX;
> +}
> +
> +static inline int mmu_idx_to_plv(int mmu_idx)
> +{
> + if (mmu_idx == MMU_DA_IDX || mmu_idx == MMU_GUEST_DA_IDX) {
> + return 0;
> + }
> + if (is_guest_mmu_idx(mmu_idx)) {
> + return mmu_idx - MMU_GUEST_IDX;
> + }
> + return mmu_idx;
> +}
>
> static inline CPUSysState *env_sys(CPULoongArchState *env)
> {
> diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
> index 6728ce5ec9..7ee3bb8e27 100644
> --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
> +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
> @@ -249,7 +249,7 @@ TRANS64(iocsrwr_d, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_d)
>
> static void check_mmu_idx(DisasContext *ctx)
> {
> - if (ctx->mem_idx != MMU_DA_IDX) {
> + if (ctx->mem_idx != MMU_DA_IDX && ctx->mem_idx != MMU_GUEST_DA_IDX) {
> tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
> ctx->base.is_jmp = DISAS_EXIT;
> }
> diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
> index 14fa5f5809..b60d9e7cf8 100644
> --- a/target/loongarch/tcg/tcg_cpu.c
> +++ b/target/loongarch/tcg/tcg_cpu.c
> @@ -309,6 +309,13 @@ static int loongarch_cpu_mmu_index(CPUState *cs, bool ifetch)
> CPULoongArchState *env = cpu_env(cs);
> CPUSysState *sys = env_sys(env);
>
> + if (env_vm_level(env) == VM_LEVEL1) {
> + if (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PG)) {
> + return MMU_GUEST_IDX + FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PLV);
> + }
> + return MMU_GUEST_DA_IDX;
> + }
> +
> if (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PG)) {
> return FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PLV);
> }
> diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c
> index 124dce6269..4ab06b48da 100644
> --- a/target/loongarch/tcg/translate.c
> +++ b/target/loongarch/tcg/translate.c
> @@ -129,6 +129,9 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
> } else {
> ctx->mem_idx = MMU_DA_IDX;
> }
> + if (ctx->base.tb->flags & HW_FLAGS_GUEST_MODE) {
> + ctx->mem_idx += MMU_GUEST_IDX;
> + }
>
> /* Bound the number of insns to execute to those left on the page. */
> bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v5 07/23] target/loongarch: add LVZ guest interrupt state
2026-10-09 3:05 ` [PATCH v5 07/23] target/loongarch: add LVZ guest interrupt state SignKirigami
@ 2026-10-10 4:03 ` Bibo Mao
0 siblings, 0 replies; 31+ messages in thread
From: Bibo Mao @ 2026-10-10 4:03 UTC (permalink / raw)
To: SignKirigami, qemu-devel; +Cc: Hengyu Yu
On 2026/10/9 上午11:05, SignKirigami wrote:
> Route configured hardware interrupts into the guest CSR bank, track guest
> interrupt requests separately, and expose guest pending and enable checks
> to the TCG runtime.
>
> Signed-off-by: SignKirigami <prcups@krgm.moe>
> Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
> ---
> target/loongarch/cpu.c | 35 +++++++++++++++++++--------
> target/loongarch/cpu.h | 3 +++
> target/loongarch/internals.h | 4 ++--
> target/loongarch/tcg/csr_helper.c | 2 +-
> target/loongarch/tcg/tcg_cpu.c | 39 ++++++++++++++++++++++---------
> 5 files changed, 59 insertions(+), 24 deletions(-)
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 664763137d..5cef63a778 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -58,16 +58,20 @@ static vaddr loongarch_cpu_get_pc(CPUState *cs)
> #ifndef CONFIG_USER_ONLY
> #include "hw/loongarch/virt.h"
>
> -void loongarch_cpu_update_irq(LoongArchCPU *cpu)
> +void loongarch_cpu_update_irq(LoongArchCPU *cpu, int vm_level)
> {
> CPULoongArchState *env = &cpu->env;
> CPUState *cs = CPU(cpu);
> - CPUSysState *sys = env_sys(env);
> + CPUSysState *sys = get_sys(env, vm_level);
> + int interrupt = vm_level ? CPU_INTERRUPT_GUEST : CPU_INTERRUPT_HARD;
>
> + if (vm_level == VM_LEVEL1 && env_vm_level(env) != VM_LEVEL1) {
> + return;
> + }
> if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) {
> - cpu_interrupt(cs, CPU_INTERRUPT_HARD);
> + cpu_interrupt(cs, interrupt);
> } else {
> - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
> + cpu_reset_interrupt(cs, interrupt);
> }
> }
>
> @@ -75,21 +79,28 @@ static void loongarch_cpu_self_set_irq(CPUState *cs, run_on_cpu_data data)
> {
> LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> CPULoongArchState *env = cpu_env(cs);
> - CPUSysState *sys = env_sys(env);
> + CPUSysState *sys;
> + int vm_level = 0;
> int irq, level;
>
> irq = data.host_int & ~BIT(31);
> level = (data.host_int >> 31) & 1;
> + if (irq >= N_IRQS) {
> + irq -= N_IRQS;
> + vm_level = 1;
> + }
> + sys = get_sys(env, vm_level);
> sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, irq, 1, level != 0);
> - loongarch_cpu_update_irq(cpu);
> + loongarch_cpu_update_irq(cpu, vm_level);
> }
>
> void loongarch_cpu_set_irq(void *opaque, int irq, int level)
> {
> LoongArchCPU *cpu = opaque;
> CPUState *cs = CPU(cpu);
> + CPULoongArchState *env = cpu_env(cs);
>
> - if (irq < 0 || irq >= N_IRQS) {
> + if (irq < 0 || irq >= (cpu_has_lvz(env) ? N_VIRQS : N_IRQS)) {
> return;
> }
>
> @@ -103,11 +114,11 @@ void loongarch_cpu_set_irq(void *opaque, int irq, int level)
> }
>
> /* Check if there is pending and not masked out interrupt */
> -bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
> +bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env, int vm_level)
> {
> uint32_t pending;
> uint32_t status;
> - CPUSysState *sys = env_sys(env);
> + CPUSysState *sys = get_sys(env, vm_level);
>
> pending = FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS);
> status = FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, LIE);
> @@ -122,7 +133,11 @@ bool loongarch_cpu_has_work(CPUState *cs)
> bool has_work = false;
>
> if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD) &&
> - cpu_loongarch_hw_interrupts_pending(cpu_env(cs))) {
> + cpu_loongarch_hw_interrupts_pending(cpu_env(cs), VM_LEVEL0)) {
> + has_work = true;
> + }
> + if (cpu_test_interrupt(cs, CPU_INTERRUPT_GUEST) &&
> + cpu_loongarch_hw_interrupts_pending(cpu_env(cs), VM_LEVEL1)) {
> has_work = true;
> }
>
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 9eea1badaf..8939dbc748 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -20,6 +20,8 @@
> #include "cpu-csr.h"
> #include "cpu-qom.h"
>
> +#define CPU_INTERRUPT_GUEST CPU_INTERRUPT_TGT_EXT_0
> +
> #define FCSR0_M1 0x1f /* FCSR1 mask, Enables */
> #define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */
> #define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */
> @@ -242,6 +244,7 @@ extern const char * const fregnames[32];
> #define IRQ_TIMER 11
> #define IRQ_IPI 12
> #define INT_DMSI 14
> +#define N_VIRQS (N_IRQS * 2)
>
> #define MAX_PERF_EVENTS 16
> #define LOONGARCH_STLB 2048 /* 2048 STLB */
> diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
> index ff956823fd..c11cefc4ee 100644
> --- a/target/loongarch/internals.h
> +++ b/target/loongarch/internals.h
> @@ -31,7 +31,7 @@ void restore_fp_status(CPULoongArchState *env);
> #ifndef CONFIG_USER_ONLY
> extern const VMStateDescription vmstate_loongarch_cpu;
>
> -void loongarch_cpu_update_irq(LoongArchCPU *cpu);
> +void loongarch_cpu_update_irq(LoongArchCPU *cpu, int vm_level);
> void loongarch_cpu_set_irq(void *opaque, int irq, int level);
>
> void cpu_loongarch_timer_cb(void *opaque);
> @@ -39,7 +39,7 @@ uint64_t cpu_loongarch_get_timer_counter(CPUTimerState *timer);
> uint64_t cpu_loongarch_get_timer_ticks(CPUTimerState *timer);
> void cpu_loongarch_set_timer_config(CPUTimerState *timer, uint64_t value);
> bool loongarch_cpu_has_work(CPUState *cs);
> -bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env);
> +bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env, int vm_level);
> #endif /* !CONFIG_USER_ONLY */
>
> uint64_t read_fcc(CPULoongArchState *env);
> diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c
> index 1a6919417f..ecfba63228 100644
> --- a/target/loongarch/tcg/csr_helper.c
> +++ b/target/loongarch/tcg/csr_helper.c
> @@ -111,7 +111,7 @@ target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
> */
> if (sys->CSR_ESTAT != old_v) {
> bql_lock();
> - loongarch_cpu_update_irq(env_archcpu(env));
> + loongarch_cpu_update_irq(env_archcpu(env), false);
why is it false, I think it should be current VM_LEVEL.
> bql_unlock();
> }
>
> diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
> index b60d9e7cf8..101fe6fc7a 100644
> --- a/target/loongarch/tcg/tcg_cpu.c
> +++ b/target/loongarch/tcg/tcg_cpu.c
> @@ -238,30 +238,47 @@ static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
> }
> }
>
> -static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
> +static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env, int vm_level)
> {
> bool ret = 0;
> - CPUSysState *sys = env_sys(env);
> + CPUSysState *sys = get_sys(env, vm_level);
> + CPUSysState *host = get_sys(env, VM_LEVEL0);
>
> ret = (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, IE) &&
> - !(FIELD_EX64(sys->CSR_DBG, CSR_DBG, DST)));
> + !(FIELD_EX64(host->CSR_DBG, CSR_DBG, DST)));
why checking CSR_DBG of host here, it is a little strange.
Regards
Bibo Mao
>
> return ret;
> }
>
> static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
> {
> + CPULoongArchState *env = cpu_env(cs);
> + bool has_interrupt = false;
> +
> if (interrupt_request & CPU_INTERRUPT_HARD) {
> - CPULoongArchState *env = cpu_env(cs);
> -
> - if (cpu_loongarch_hw_interrupts_enabled(env) &&
> - cpu_loongarch_hw_interrupts_pending(env)) {
> - /* Raise it */
> - cs->exception_index = EXCCODE_INT;
> - loongarch_cpu_do_interrupt(cs);
> - return true;
> +
> + if (cpu_loongarch_hw_interrupts_enabled(env, VM_LEVEL0) &&
> + cpu_loongarch_hw_interrupts_pending(env, VM_LEVEL0)) {
> + if (env_vm_level(env) != VM_LEVEL0) {
> + trigger_vm_exit(env);
> + }
> + has_interrupt = true;
> }
> + } else if (interrupt_request & CPU_INTERRUPT_GUEST) {
> + if (cpu_loongarch_hw_interrupts_enabled(env, VM_LEVEL1) &&
> + cpu_loongarch_hw_interrupts_pending(env, VM_LEVEL1) &&
> + env_vm_level(env) == VM_LEVEL1) {
> + has_interrupt = true;
> + }
> + }
> +
> + if (has_interrupt) {
> + /* Raise it */
> + cs->exception_index = EXCCODE_INT;
> + loongarch_cpu_do_interrupt(cs);
> + return true;
> }
> +
> return false;
> }
>
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v5 08/23] target/loongarch: add LVZ guest timer
2026-10-09 3:05 ` [PATCH v5 08/23] target/loongarch: add LVZ guest timer SignKirigami
@ 2026-10-10 4:07 ` Bibo Mao
0 siblings, 0 replies; 31+ messages in thread
From: Bibo Mao @ 2026-10-10 4:07 UTC (permalink / raw)
To: SignKirigami, qemu-devel; +Cc: Hengyu Yu
On 2026/10/9 上午11:05, SignKirigami wrote:
> Add a separate guest timer and IRQ_VTIMER.
>
> Signed-off-by: SignKirigami <prcups@krgm.moe>
> Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
> ---
> target/loongarch/cpu.c | 8 +++++++-
> target/loongarch/cpu.h | 6 ++++++
> 2 files changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 5cef63a778..8e759a2987 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -770,7 +770,7 @@ static void loongarch_cpu_init(Object *obj)
> LoongArchCPU *cpu = LOONGARCH_CPU(obj);
> #ifdef CONFIG_TCG
> CPULoongArchState *env = &cpu->env;
> - CPUTimerState *timer;
> + CPUTimerState *timer, *guest_timer;
> #endif
>
> qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
If cpu_has_lvz(), I think here N_IRQS should be N_VIRQS.
> @@ -778,8 +778,14 @@ static void loongarch_cpu_init(Object *obj)
> timer = env_timer(env);
> timer->irq = IRQ_TIMER;
> timer->cs = CPU(obj);
> + guest_timer = env_guest_timer(env);
> + guest_timer->irq = IRQ_VTIMER;
> + guest_timer->cs = CPU(obj);
> +
> timer_init_ns(&timer->timer, QEMU_CLOCK_VIRTUAL,
> &cpu_loongarch_timer_cb, timer);
> + timer_init_ns(&guest_timer->timer, QEMU_CLOCK_VIRTUAL,
> + &cpu_loongarch_timer_cb, guest_timer);
Had better add cpu_has_lvz() when create guest timer.
Regards
Bibo Mao
> #endif
> #endif
> }
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 8939dbc748..ba28d80272 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -245,6 +245,7 @@ extern const char * const fregnames[32];
> #define IRQ_IPI 12
> #define INT_DMSI 14
> #define N_VIRQS (N_IRQS * 2)
> +#define IRQ_VTIMER (N_IRQS + IRQ_TIMER)
>
> #define MAX_PERF_EVENTS 16
> #define LOONGARCH_STLB 2048 /* 2048 STLB */
> @@ -577,6 +578,11 @@ static inline CPUTimerState *env_timer(CPULoongArchState *env)
> return &env->sys_states[0].timer_state;
> }
>
> +static inline CPUTimerState *env_guest_timer(CPULoongArchState *env)
> +{
> + return &env->sys_states[1].timer_state;
> +}
> +
> static inline bool is_la64(CPULoongArchState *env)
> {
> return FIELD_EX32(env->cpucfg[1], CPUCFG1, ARCH) == CPUCFG1_ARCH_LA64;
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v5 12/23] target/loongarch: add gid management functions
2026-10-09 3:05 ` [PATCH v5 12/23] target/loongarch: add gid management functions SignKirigami
@ 2026-10-10 9:00 ` Bibo Mao
0 siblings, 0 replies; 31+ messages in thread
From: Bibo Mao @ 2026-10-10 9:00 UTC (permalink / raw)
To: SignKirigami, qemu-devel; +Cc: Hengyu Yu
On 2026/10/9 上午11:05, SignKirigami wrote:
> Add get_gid(), get_tgid() and tlb_entry_matches_gid(), to get and use gid in
> lvz functions.
>
> Signed-off-by: SignKirigami <prcups@krgm.moe>
> Signed-off-by: Hengyu Yu <yuhengyu25@mails.ucas.ac.cn>
> ---
> target/loongarch/cpu.h | 21 +++++++++++++++++++++
> target/loongarch/tcg/tlb_helper.c | 5 +++++
> 2 files changed, 26 insertions(+)
>
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 3e3ae2bfa7..a42c5fe170 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -583,6 +583,27 @@ static inline bool will_return_to_guest(CPULoongArchState *env)
> return FIELD_EX64(get_sys(env, VM_LEVEL0)->CSR_GSTAT, CSR_GSTAT, PVM);
> }
>
> +static inline uint8_t get_gid(CPULoongArchState *env)
> +{
> + return FIELD_EX64(get_sys(env, VM_LEVEL0)->CSR_GSTAT, CSR_GSTAT, GID);
> +}
> +
> +static inline uint8_t get_tgid(CPULoongArchState *env)
> +{
> + CPUSysState *host = get_sys(env, VM_LEVEL0);
> +
> + if (env_vm_level(env) == VM_LEVEL1) {
> + return get_gid(env);
> + }
> +
> + if (FIELD_EX64(host->CSR_GTLBC, CSR_GTLBC, USETGID)) {
> + return FIELD_EX64(host->CSR_GTLBC, CSR_GTLBC, TGID);
> + } else if (will_return_to_guest(env)) {
> + return get_gid(env);
> + }why there is such checking with tgid()?, I think it is simple to come
from TGID field of CSR_GTLBC even in host mode, such as:
return FIELD_EX64(host->CSR_GTLBC, CSR_GTLBC, TGID);
Regards
Bibo Mao
> + return 0;
> +}
> +
> static inline CPUTimerState *env_timer(CPULoongArchState *env)
> {
> return &env->sys_states[0].timer_state;
> diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
> index d1f1d233fd..821aa26328 100644
> --- a/target/loongarch/tcg/tlb_helper.c
> +++ b/target/loongarch/tcg/tlb_helper.c
> @@ -35,6 +35,11 @@ static bool tlb_match_asid(bool global, int asid, int tlb_asid)
> return !global && tlb_asid == asid;
> }
>
> +static inline bool tlb_entry_matches_gid(const LoongArchTLB *tlb, uint8_t gid)
> +{
> + return FIELD_EX64(tlb->tlb_misc, TLB_MISC, GID) == gid;
> +}
> +
> bool check_ps(CPULoongArchState *env, uint8_t tlb_ps)
> {
> CPUSysState *sys = env_sys(env);
>
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2026-10-10 8:59 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-09 3:04 [PATCH v5 00/23] add LVZ support for TCG SignKirigami
2026-10-09 3:04 ` [PATCH v5 01/23] target/loongarch: select sys state by VM level SignKirigami
2026-10-10 3:21 ` Bibo Mao
2026-10-09 3:04 ` [PATCH v5 02/23] target/loongarch: add get_sys() helper SignKirigami
2026-10-10 3:21 ` Bibo Mao
2026-10-09 3:04 ` [PATCH v5 03/23] target/loongarch: add LVZ feature switcher SignKirigami
2026-10-10 3:20 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 04/23] target/loongarch: add LVZ CSR metadata SignKirigami
2026-10-09 3:05 ` [PATCH v5 05/23] target/loongarch: add vm level 1 definition SignKirigami
2026-10-09 3:05 ` [PATCH v5 06/23] target/loongarch: add definition about guest mmu_idx SignKirigami
2026-10-10 3:36 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 07/23] target/loongarch: add LVZ guest interrupt state SignKirigami
2026-10-10 4:03 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 08/23] target/loongarch: add LVZ guest timer SignKirigami
2026-10-10 4:07 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 09/23] target/loongarch: handle return to guest in ertn SignKirigami
2026-10-09 3:05 ` [PATCH v5 10/23] target/loongarch: handle LVZ exception and vm_exit SignKirigami
2026-10-09 3:05 ` [PATCH v5 11/23] target/loongarch: add host TLBRet and handle SignKirigami
2026-10-09 3:05 ` [PATCH v5 12/23] target/loongarch: add gid management functions SignKirigami
2026-10-10 9:00 ` Bibo Mao
2026-10-09 3:05 ` [PATCH v5 13/23] target/loongarch: add LVZ parameters to TLB functions SignKirigami
2026-10-09 3:05 ` [PATCH v5 14/23] target/loongarch: add LVZ " SignKirigami
2026-10-09 3:05 ` [PATCH v5 15/23] target/loongarch: add LVZ to invtlb SignKirigami
2026-10-09 3:05 ` [PATCH v5 16/23] target/loongarch: add LVZ to ptw SignKirigami
2026-10-09 3:05 ` [PATCH v5 17/23] target/loongarch: add LVZ migration state SignKirigami
2026-10-09 3:05 ` [PATCH v5 18/23] target/loongarch: add gcsr instructions and vm level 1 csr management SignKirigami
2026-10-09 3:05 ` [PATCH v5 19/23] target/loongarch: add LVZ CSRs SignKirigami
2026-10-09 3:05 ` [PATCH v5 20/23] target/loongarch: translate LVZ guest TLB instructions SignKirigami
2026-10-09 3:05 ` [PATCH v5 21/23] target/loongarch: translate LVZ guest traps and HVC SignKirigami
2026-10-09 3:05 ` [PATCH v5 22/23] target/loongarch: initialize CSR related to LVZ SignKirigami
2026-10-09 3:05 ` [PATCH v5 23/23] target/loongarch: exit to vm level 0 for fpd, sxd and asxd of vm level 0 SignKirigami
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.