From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740302153383.3543140039769; Wed, 26 Aug 2026 03:31:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuX-0001wP-9h; Wed, 26 Aug 2026 06:31:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuM-0001tw-QK for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:02 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuJ-0003K6-Vm for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:02 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 9018B7A17; Wed, 26 Aug 2026 16:00:54 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 01/14] target/loongarch: Define LVZ CSR fields Date: Wed, 26 Aug 2026 18:30:05 +0800 Message-ID: <4e393c8c6f5d7d42ede6fa65fc94753bd8b14c17.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740304790158500 Content-Type: text/plain; charset="utf-8" Add LVZ CSR number and bit-field definitions for guest status, configuration, interrupt, timer and guest TLB registers, preparing the architectural constants needed by later LVZ CPU state, CSR and TCG implementation patches. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu Reviewed-by: Bibo Mao --- target/loongarch/cpu-csr.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h index d860417af2..438da43a79 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 */ =20 +/* LVZ (LoongArch Virtualization) CSRs */ +#define LOONGARCH_CSR_GSTAT 0x50 /* Guest status */ +FIELD(CSR_GSTAT, VM, 0, 1) +FIELD(CSR_GSTAT, PVM, 1, 1) +FIELD(CSR_GSTAT, GIDBIT, 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 */ + +#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) + #endif /* LOONGARCH_CPU_CSR_H */ --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740325776500.37393324073264; Wed, 26 Aug 2026 03:32:05 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuQ-0001va-Ac; Wed, 26 Aug 2026 06:31:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuL-0001th-Nm for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:01 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuJ-0003KW-8u for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:01 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 41F97D069; Wed, 26 Aug 2026 16:00:55 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 02/14] target/loongarch: Add LVZ CPU state definitions Date: Wed, 26 Aug 2026 18:30:06 +0800 Message-ID: <17b4c21625c92521c49585de983babc0400b4836.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740327971158500 Content-Type: text/plain; charset="utf-8" Add host and guest system-state banks, LVZ exception and MMU indices, CPU and translation state, and helpers for selecting a VM-level CSR bank. Read host ERA and BADV explicitly when generating ELF core notes so the result does not depend on the currently selected guest state. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/arch_dump.c | 6 ++-- target/loongarch/cpu.c | 4 +-- target/loongarch/cpu.h | 64 ++++++++++++++++++++++++++++++++++-- target/loongarch/translate.h | 2 ++ 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/target/loongarch/arch_dump.c b/target/loongarch/arch_dump.c index 9d84faef96..711b23257b 100644 --- a/target/loongarch/arch_dump.c +++ b/target/loongarch/arch_dump.c @@ -116,7 +116,7 @@ int loongarch_cpu_write_elf64_note(WriteCoreDumpFunctio= n f, CPUState *cs, { struct loongarch_note note; CPULoongArchState *env =3D &LOONGARCH_CPU(cs)->env; - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); int ret, i; =20 loongarch_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, @@ -127,8 +127,8 @@ int loongarch_cpu_write_elf64_note(WriteCoreDumpFunctio= n f, CPUState *cs, for (i =3D 0; i < 32; ++i) { note.prstatus.pr_reg.gpr[i] =3D cpu_to_dump64(s, env->gpr[i]); } - note.prstatus.pr_reg.csr_era =3D cpu_to_dump64(s, sys->CSR_ERA); - note.prstatus.pr_reg.csr_badv =3D cpu_to_dump64(s, sys->CSR_BADV); + note.prstatus.pr_reg.csr_era =3D cpu_to_dump64(s, host->CSR_ERA); + note.prstatus.pr_reg.csr_badv =3D cpu_to_dump64(s, host->CSR_BADV); ret =3D f(¬e, LOONGARCH_PRSTATUS_NOTE_SIZE, s); if (ret < 0) { return -1; diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index fb03424ffa..2f7692dc93 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -282,7 +282,7 @@ static void loongarch_la464_initfn(Object *obj) uint32_t data =3D 0, field; int i; =20 - set_sys_state(env, &env->sys_states[0]); + set_sys(env, LOONGARCH_VM_LEVEL_HOST); for (i =3D 0; i < 21; i++) { env->cpucfg[i] =3D 0x0; } @@ -412,7 +412,7 @@ static void loongarch_la132_initfn(Object *obj) uint32_t data =3D 0; int i; =20 - set_sys_state(env, &env->sys_states[0]); + set_sys(env, LOONGARCH_VM_LEVEL_HOST); for (i =3D 0; i < 21; i++) { env->cpucfg[i] =3D 0x0; } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index ad30c73167..be982b7695 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -20,6 +20,8 @@ #include "cpu-csr.h" #include "cpu-qom.h" =20 +#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 */ @@ -93,6 +95,10 @@ 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_GCSC EXCODE(24, 0) +#define EXCCODE_GCHC EXCODE(25, 0) #define EXCCODE_DBP EXCODE(26, 0) /* Reserved subcode use= d for debug */ =20 /* cpucfg[0] bits */ @@ -255,6 +261,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) =20 /*Msg interrupt registers */ #define N_MSGIS 4 @@ -314,6 +321,10 @@ typedef struct LoongArchBT { uint32_t ftop; } lbt_t; =20 +#define LOONGARCH_VM_LEVEL_HOST 0 +#define LOONGARCH_VM_LEVEL_GUEST 1 +#define LOONGARCH_VM_LEVELS 2 + #define CPU_VENDOR_LOONGSON "Loongson" #define CPU_MODEL_3A5000 "3A5000" #define CPU_MODEL_1C101 "1C101" @@ -375,10 +386,18 @@ typedef struct CPUSysState { uint64_t CSR_DBG; uint64_t CSR_DERA; uint64_t CSR_DSAVE; + uint64_t CSR_GSTAT; + 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; uint64_t CSR_MSGIE; +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) + LoongArchTLB tlb[LOONGARCH_TLB_MAX]; +#endif } CPUSysState; =20 typedef struct CPUArchState { @@ -394,7 +413,7 @@ typedef struct CPUArchState { uint32_t pv_features; uint64_t vendor_id; uint64_t cpu_id; - CPUSysState sys_states[1]; + CPUSysState sys_states[LOONGARCH_VM_LEVELS]; =20 struct { uint64_t guest_addr; @@ -419,6 +438,7 @@ typedef struct CPUArchState { uint32_t mp_state; #endif CPUSysState *sys_state; + bool vm_exit; } CPULoongArchState; =20 typedef struct LoongArchCPUTopo { @@ -438,8 +458,10 @@ struct ArchCPU { =20 CPULoongArchState env; QEMUTimer timer; + QEMUTimer guest_timer; uint32_t phy_id; OnOffAuto lbt; + OnOffAuto lvz; OnOffAuto pmu; OnOffAuto ptw; OnOffAuto lsx; @@ -484,15 +506,44 @@ 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 >=3D MMU_GUEST_IDX; +} + +static inline int mmu_idx_to_plv(int mmu_idx) +{ + if (mmu_idx =3D=3D MMU_DA_IDX || mmu_idx =3D=3D MMU_GUEST_DA_IDX) { + return 0; + } + if (is_guest_mmu_idx(mmu_idx)) { + return mmu_idx - MMU_GUEST_IDX; + } + return mmu_idx; +} =20 static inline CPUSysState *env_sys(CPULoongArchState *env) { return env->sys_state; } =20 -static inline void set_sys_state(CPULoongArchState *env, CPUSysState *sys) +static inline CPUSysState *get_sys(CPULoongArchState *env, int vm_level) +{ + return &env->sys_states[vm_level]; +} + +static inline void set_sys(CPULoongArchState *env, int vm_level) { - env->sys_state =3D sys; + env->sys_state =3D get_sys(env, vm_level); +} + +static inline int env_vm_level(CPULoongArchState *env) +{ + return env_sys(env) =3D=3D get_sys(env, LOONGARCH_VM_LEVEL_GUEST) ? + LOONGARCH_VM_LEVEL_GUEST : LOONGARCH_VM_LEVEL_HOST; } =20 static inline bool is_la64(CPULoongArchState *env) @@ -530,6 +581,13 @@ static inline void set_pc(CPULoongArchState *env, uint= 64_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 + +bool has_lvz_capability(CPULoongArchState *env); +bool will_return_to_guest(CPULoongArchState *env); +uint8_t get_gid(CPULoongArchState *env); +uint8_t get_tgid(CPULoongArchState *env); +void trigger_vm_exit(CPULoongArchState *env); =20 #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU =20 diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index 8aa8325dc6..257c3bbddd 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)) @@ -66,6 +67,7 @@ typedef struct DisasContext { TCGv zero; bool la64; /* LoongArch64 mode */ bool va32; /* 32-bit virtual address */ + bool guest_mode; uint32_t cpucfg1; uint32_t cpucfg2; uint32_t cpucfg3; --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740308378544.3579689213357; Wed, 26 Aug 2026 03:31:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuV-0001wN-68; Wed, 26 Aug 2026 06:31:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuN-0001uJ-9e for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:03 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuJ-0003LG-Lj for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:03 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id EC0B1D0CE; Wed, 26 Aug 2026 16:00:55 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 03/14] target/loongarch: Add LVZ CSR metadata Date: Wed, 26 Aug 2026 18:30:07 +0800 Message-ID: <2c261c4b32b901a077952757d7228570a822e592.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UPPERCASE_50_75=0.008 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740310976158500 Content-Type: text/plain; charset="utf-8" Add LVZ host and guest CSR access metadata to the existing CSR table. Keep one shared register description and calculate the host or guest bank offset at translation time instead of duplicating CSRInfo entries. Mark guest read-only, sensitive and unavailable CSRs for later LVZ instruction translation. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu.c | 3 +- target/loongarch/csr.c | 108 +++++++++--------- target/loongarch/csr.h | 2 + .../tcg/insn_trans/trans_extra.c.inc | 2 +- .../tcg/insn_trans/trans_privileged.c.inc | 6 +- 5 files changed, 65 insertions(+), 56 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 2f7692dc93..0f6a211949 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -783,7 +783,8 @@ static void loongarch_cpu_dump_csr(CPUState *cs, FILE *= f) qemu_fprintf(f, " CSR%03d:", col); } =20 - addr =3D (void *)env + get_csr_offset(csr_info, 0); + addr =3D (void *)env + get_csr_offset(csr_info, + LOONGARCH_VM_LEVEL_HOST); qemu_fprintf(f, " %s ", csr_info->name); len =3D strlen(csr_info->name); for (; len < 6; len++) { diff --git a/target/loongarch/csr.c b/target/loongarch/csr.c index 309b826ca9..fa018a4582 100644 --- a/target/loongarch/csr.c +++ b/target/loongarch/csr.c @@ -13,15 +13,16 @@ .flags =3D FL, .readfn =3D RD, .writefn =3D WR \ } =20 -#define CSR_OFF_ARRAY(NAME, N) \ +#define CSR_OFF_ARRAY_FLAGS(NAME, N, FL) \ [LOONGARCH_CSR_##NAME(N)] =3D { \ .name =3D (stringify(NAME##N)), \ .offset =3D CSR_OFFSET(CSR_##NAME[N]), \ - .flags =3D CSRFL_BASIC, .readfn =3D NULL, .writefn =3D NULL = \ + .flags =3D FL \ } =20 #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) =20 static CSRInfo csr_info[] =3D { CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB), @@ -35,6 +36,7 @@ static CSRInfo csr_info[] =3D { CSR_OFF_FLAGS(BADI, CSRFL_READONLY), CSR_OFF(EENTRY), CSR_OFF(TLBIDX), + CSR_OFF_FLAGS(GTLBC, CSRFL_GSPR), CSR_OFF(TLBEHI), CSR_OFF(TLBELO0), CSR_OFF(TLBELO1), @@ -71,9 +73,13 @@ static CSRInfo csr_info[] =3D { CSR_OFF_FLAGS(TVAL, CSRFL_READONLY | CSRFL_IO), CSR_OFF(CNTC), CSR_OFF_FLAGS(TICLR, CSRFL_IO), + 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), @@ -82,57 +88,57 @@ static CSRInfo csr_info[] =3D { CSR_OFF(TLBRELO1), CSR_OFF(TLBREHI), CSR_OFF(TLBRPRMD), - CSR_OFF(MERRCTL), - CSR_OFF(MERRINFO1), - CSR_OFF(MERRINFO2), - CSR_OFF(MERRENTRY), - CSR_OFF(MERRERA), - CSR_OFF(MERRSAVE), - CSR_OFF(CTAG), + CSR_OFF_FLAGS(MERRCTL, CSRFL_GSPR), + CSR_OFF_FLAGS(MERRINFO1, CSRFL_GSPR), + CSR_OFF_FLAGS(MERRINFO2, CSRFL_GSPR), + CSR_OFF_FLAGS(MERRENTRY, CSRFL_GSPR), + CSR_OFF_FLAGS(MERRERA, CSRFL_GSPR), + CSR_OFF_FLAGS(MERRSAVE, CSRFL_GSPR), + CSR_OFF_FLAGS(CTAG, CSRFL_GSPR), CSR_OFF_ARRAY(DMW, 0), 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_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 0, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 1, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 1, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 2, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 2, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 3, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 3, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 4, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 4, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 5, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 5, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 6, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 6, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 7, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 7, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 8, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 8, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 9, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 9, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 10, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 10, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 11, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 11, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 12, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 12, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 13, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 13, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 14, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 14, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCTRL, 15, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(PERFCNTR, 15, CSRFL_GUEST_INVALID), + 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_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(MSGIS, 1, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(MSGIS, 2, CSRFL_GUEST_INVALID), + CSR_OFF_ARRAY_FLAGS(MSGIS, 3, CSRFL_GUEST_INVALID), + CSR_OFF_FLAGS(MSGIR, CSRFL_GUEST_INVALID), }; =20 CSRInfo *get_csr(unsigned int csr_num) diff --git a/target/loongarch/csr.h b/target/loongarch/csr.h index c2b6b882bc..647695e248 100644 --- a/target/loongarch/csr.h +++ b/target/loongarch/csr.h @@ -20,6 +20,8 @@ enum { CSRFL_IO =3D (1 << 2), CSRFL_UNUSED =3D (1 << 3), CSRFL_BASIC =3D (1 << 4), + CSRFL_GSPR =3D (1 << 5), + CSRFL_GUEST_INVALID =3D (1 << 6), }; =20 typedef struct { diff --git a/target/loongarch/tcg/insn_trans/trans_extra.c.inc b/target/loo= ngarch/tcg/insn_trans/trans_extra.c.inc index 655dce329e..e69384497f 100644 --- a/target/loongarch/tcg/insn_trans/trans_extra.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_extra.c.inc @@ -55,7 +55,7 @@ static bool gen_rdtime(DisasContext *ctx, arg_rr *a, tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32); } =20 - offset =3D CPU_CSR_OFFSET(CSR_TID, 0); + offset =3D CPU_CSR_OFFSET(CSR_TID, LOONGARCH_VM_LEVEL_HOST); tcg_gen_ld_i64(dst2, tcg_env, offset); =20 return true; diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/targe= t/loongarch/tcg/insn_trans/trans_privileged.c.inc index 6728ce5ec9..bcfc977990 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -122,7 +122,7 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) if (readfn) { readfn(dest, tcg_env); } else { - offset =3D get_csr_offset(csr, 0); + offset =3D get_csr_offset(csr, LOONGARCH_VM_LEVEL_HOST); tcg_gen_ld_tl(dest, tcg_env, offset); } } @@ -157,7 +157,7 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) writefn(dest, tcg_env, src1); } else { dest =3D tcg_temp_new(); - offset =3D get_csr_offset(csr, 0); + offset =3D get_csr_offset(csr, LOONGARCH_VM_LEVEL_HOST); tcg_gen_ld_tl(dest, tcg_env, offset); tcg_gen_st_tl(src1, tcg_env, offset); } @@ -196,7 +196,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxch= g *a) newv =3D tcg_temp_new(); temp =3D tcg_temp_new(); =20 - offset =3D get_csr_offset(csr, 0); + offset =3D get_csr_offset(csr, LOONGARCH_VM_LEVEL_HOST); tcg_gen_ld_tl(oldv, tcg_env, offset); tcg_gen_and_tl(newv, src1, mask); tcg_gen_andc_tl(temp, oldv, mask); --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740360860432.1709209175665; Wed, 26 Aug 2026 03:32:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAua-0001xJ-Pp; Wed, 26 Aug 2026 06:31:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuN-0001uU-Jf for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:03 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuK-0003MD-Dc for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:03 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id A2AA7DF9A; Wed, 26 Aug 2026 16:00:56 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 04/14] target/loongarch: Add LVZ CPU model support Date: Wed, 26 Aug 2026 18:30:08 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740362089158500 Content-Type: text/plain; charset="utf-8" Add the LVZ CPU property and initialize the host and guest state banks for the LA464 model. Reset always returns to the host CSR and TLB bank and initializes the implemented guest ID width. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu.c | 145 +++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 55 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 0f6a211949..c5c7f3e0e3 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -114,12 +114,12 @@ static void loongarch_la464_init_csr(DeviceState *dev) static bool initialized; LoongArchCPU *cpu =3D LOONGARCH_CPU(dev); CPULoongArchState *env =3D &cpu->env; - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); int i, num; =20 if (!initialized) { initialized =3D true; - num =3D FIELD_EX64(sys->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM); + num =3D FIELD_EX64(host->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM); for (i =3D num; i < 16; i++) { set_csr_flag(LOONGARCH_CSR_SAVE(i), CSRFL_UNUSED); } @@ -251,11 +251,32 @@ static void loongarch_set_ptw(Object *obj, bool value= , Error **errp) cpu->env.cpucfg[2] =3D FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, HPTW, v= alue); } =20 +static bool loongarch_get_lvz(Object *obj, Error **errp) +{ + return LOONGARCH_CPU(obj)->lvz !=3D ON_OFF_AUTO_OFF; +} + +static void loongarch_set_lvz(Object *obj, bool value, Error **errp) +{ + LoongArchCPU *cpu =3D LOONGARCH_CPU(obj); + + cpu->lvz =3D value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; + + if (kvm_enabled()) { + return; + } + + cpu->env.cpucfg[2] =3D FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LVZ, va= lue); + cpu->env.cpucfg[2] =3D FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LVZ_VER, + value ? 1 : 0); +} + static void loongarch_cpu_post_init(Object *obj) { LoongArchCPU *cpu =3D LOONGARCH_CPU(obj); =20 cpu->lbt =3D ON_OFF_AUTO_OFF; + cpu->lvz =3D ON_OFF_AUTO_AUTO; cpu->pmu =3D ON_OFF_AUTO_OFF; cpu->lsx =3D ON_OFF_AUTO_AUTO; cpu->lasx =3D ON_OFF_AUTO_AUTO; @@ -267,6 +288,8 @@ 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 */ =20 if (kvm_enabled()) { @@ -278,7 +301,8 @@ static void loongarch_la464_initfn(Object *obj) { LoongArchCPU *cpu =3D LOONGARCH_CPU(obj); CPULoongArchState *env =3D &cpu->env; - CPUSysState *sys; + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + CPUSysState *guest =3D get_sys(env, LOONGARCH_VM_LEVEL_GUEST); uint32_t data =3D 0, field; int i; =20 @@ -322,6 +346,8 @@ static void loongarch_la464_initfn(Object *obj) data =3D FIELD_DP32(data, CPUCFG2, FP_VER, 1); data =3D FIELD_DP32(data, CPUCFG2, LSX, 1), data =3D FIELD_DP32(data, CPUCFG2, LASX, 1), + data =3D FIELD_DP32(data, CPUCFG2, LVZ, 1); + data =3D FIELD_DP32(data, CPUCFG2, LVZ_VER, 1); data =3D FIELD_DP32(data, CPUCFG2, LLFTP, 1); data =3D FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1); data =3D FIELD_DP32(data, CPUCFG2, LSPW, 1); @@ -386,19 +412,19 @@ static void loongarch_la464_initfn(Object *obj) data =3D FIELD_DP32(data, CPUCFG20, L3IU_SIZE, 6); env->cpucfg[20] =3D data; =20 - sys =3D env_sys(env); - sys->CSR_ASID =3D FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); + host->CSR_ASID =3D FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); + guest->CSR_ASID =3D host->CSR_ASID; =20 - sys->CSR_PRCFG1 =3D FIELD_DP64(sys->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM, = 8); - sys->CSR_PRCFG1 =3D FIELD_DP64(sys->CSR_PRCFG1, CSR_PRCFG1, TIMER_BITS= , 0x2f); - sys->CSR_PRCFG1 =3D FIELD_DP64(sys->CSR_PRCFG1, CSR_PRCFG1, VSMAX, 7); + host->CSR_PRCFG1 =3D FIELD_DP64(host->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM= , 8); + host->CSR_PRCFG1 =3D FIELD_DP64(host->CSR_PRCFG1, CSR_PRCFG1, TIMER_BI= TS, 0x2f); + host->CSR_PRCFG1 =3D FIELD_DP64(host->CSR_PRCFG1, CSR_PRCFG1, VSMAX, 7= ); =20 - sys->CSR_PRCFG2 =3D 0x3ffff000; + host->CSR_PRCFG2 =3D 0x3ffff000; =20 - sys->CSR_PRCFG3 =3D FIELD_DP64(sys->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, = 2); - sys->CSR_PRCFG3 =3D FIELD_DP64(sys->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY= , 63); - sys->CSR_PRCFG3 =3D FIELD_DP64(sys->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS,= 7); - sys->CSR_PRCFG3 =3D FIELD_DP64(sys->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS,= 8); + host->CSR_PRCFG3 =3D FIELD_DP64(host->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE= , 2); + host->CSR_PRCFG3 =3D FIELD_DP64(host->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENT= RY, 63); + host->CSR_PRCFG3 =3D FIELD_DP64(host->CSR_PRCFG3, CSR_PRCFG3, STLB_WAY= S, 7); + host->CSR_PRCFG3 =3D FIELD_DP64(host->CSR_PRCFG3, CSR_PRCFG3, STLB_SET= S, 8); =20 cpu->msgint =3D ON_OFF_AUTO_OFF; cpu->ptw =3D ON_OFF_AUTO_OFF; @@ -439,6 +465,7 @@ static void loongarch_la132_initfn(Object *obj) data =3D FIELD_DP32(data, CPUCFG1, CRC, 1); env->cpucfg[1] =3D data; cpu->msgint =3D ON_OFF_AUTO_OFF; + cpu->lvz =3D ON_OFF_AUTO_OFF; cpu->ptw =3D ON_OFF_AUTO_OFF; } =20 @@ -600,7 +627,7 @@ static void loongarch_cpu_reset_hold(Object *obj, Reset= Type type) CPUState *cs =3D CPU(obj); LoongArchCPUClass *lacc =3D LOONGARCH_CPU_GET_CLASS(obj); CPULoongArchState *env =3D cpu_env(cs); - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); =20 if (lacc->parent_phases.hold) { lacc->parent_phases.hold(obj, type); @@ -624,61 +651,69 @@ static void loongarch_cpu_reset_hold(Object *obj, Res= etType type) =20 int n; /* Set csr registers value after reset, see the manual 6.4. */ - sys->CSR_CRMD =3D FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, PLV, 0); - sys->CSR_CRMD =3D FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, IE, 0); - sys->CSR_CRMD =3D FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, DA, 1); - sys->CSR_CRMD =3D FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, PG, 0); - sys->CSR_CRMD =3D FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, DATF, 0); - sys->CSR_CRMD =3D FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, DATM, 0); - - sys->CSR_EUEN =3D FIELD_DP64(sys->CSR_EUEN, CSR_EUEN, FPE, 0); - sys->CSR_EUEN =3D FIELD_DP64(sys->CSR_EUEN, CSR_EUEN, SXE, 0); - sys->CSR_EUEN =3D FIELD_DP64(sys->CSR_EUEN, CSR_EUEN, ASXE, 0); - sys->CSR_EUEN =3D FIELD_DP64(sys->CSR_EUEN, CSR_EUEN, BTE, 0); - - sys->CSR_MISC =3D 0; - - sys->CSR_ECFG =3D FIELD_DP64(sys->CSR_ECFG, CSR_ECFG, VS, 0); - sys->CSR_ECFG =3D FIELD_DP64(sys->CSR_ECFG, CSR_ECFG, LIE, 0); - - sys->CSR_ESTAT =3D sys->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2)); - sys->CSR_RVACFG =3D FIELD_DP64(sys->CSR_RVACFG, CSR_RVACFG, RBITS, 0); - sys->CSR_CPUID =3D cs->cpu_index; - sys->CSR_TCFG =3D FIELD_DP64(sys->CSR_TCFG, CSR_TCFG, EN, 0); - sys->CSR_LLBCTL =3D FIELD_DP64(sys->CSR_LLBCTL, CSR_LLBCTL, KLO, 0); - sys->CSR_TLBRERA =3D FIELD_DP64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR,= 0); - sys->CSR_MERRCTL =3D FIELD_DP64(sys->CSR_MERRCTL, CSR_MERRCTL, ISMERR,= 0); - sys->CSR_TID =3D cs->cpu_index; + host->CSR_CRMD =3D FIELD_DP64(host->CSR_CRMD, CSR_CRMD, PLV, 0); + host->CSR_CRMD =3D FIELD_DP64(host->CSR_CRMD, CSR_CRMD, IE, 0); + host->CSR_CRMD =3D FIELD_DP64(host->CSR_CRMD, CSR_CRMD, DA, 1); + host->CSR_CRMD =3D FIELD_DP64(host->CSR_CRMD, CSR_CRMD, PG, 0); + host->CSR_CRMD =3D FIELD_DP64(host->CSR_CRMD, CSR_CRMD, DATF, 0); + host->CSR_CRMD =3D FIELD_DP64(host->CSR_CRMD, CSR_CRMD, DATM, 0); + + host->CSR_EUEN =3D FIELD_DP64(host->CSR_EUEN, CSR_EUEN, FPE, 0); + host->CSR_EUEN =3D FIELD_DP64(host->CSR_EUEN, CSR_EUEN, SXE, 0); + host->CSR_EUEN =3D FIELD_DP64(host->CSR_EUEN, CSR_EUEN, ASXE, 0); + host->CSR_EUEN =3D FIELD_DP64(host->CSR_EUEN, CSR_EUEN, BTE, 0); + + host->CSR_MISC =3D 0; + + host->CSR_ECFG =3D FIELD_DP64(host->CSR_ECFG, CSR_ECFG, VS, 0); + host->CSR_ECFG =3D FIELD_DP64(host->CSR_ECFG, CSR_ECFG, LIE, 0); + + host->CSR_ESTAT =3D host->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2)); + host->CSR_RVACFG =3D FIELD_DP64(host->CSR_RVACFG, CSR_RVACFG, RBITS, 0= ); + host->CSR_CPUID =3D cs->cpu_index; + host->CSR_TCFG =3D FIELD_DP64(host->CSR_TCFG, CSR_TCFG, EN, 0); + host->CSR_LLBCTL =3D FIELD_DP64(host->CSR_LLBCTL, CSR_LLBCTL, KLO, 0); + host->CSR_TLBRERA =3D FIELD_DP64(host->CSR_TLBRERA, CSR_TLBRERA, ISTLB= R, 0); + host->CSR_MERRCTL =3D FIELD_DP64(host->CSR_MERRCTL, CSR_MERRCTL, ISMER= R, 0); + host->CSR_TID =3D cs->cpu_index; + host->CSR_GSTAT =3D 0; + host->CSR_GCFG =3D 0; + host->CSR_GINTC =3D 0; + host->CSR_GCNTC =3D 0; + host->CSR_GTLBC =3D 0; /* * Workaround for edk2-stable202408, CSR PGD register is set only if * its value is equal to zero for boot cpu, it causes reboot issue. * * Here clear CSR registers relative with TLB. */ - sys->CSR_PGDH =3D 0; - sys->CSR_PGDL =3D 0; - sys->CSR_PWCH =3D 0; - sys->CSR_EENTRY =3D 0; - sys->CSR_TLBRENTRY =3D 0; - sys->CSR_MERRENTRY =3D 0; + host->CSR_PGDH =3D 0; + host->CSR_PGDL =3D 0; + host->CSR_PWCH =3D 0; + host->CSR_EENTRY =3D 0; + host->CSR_TLBRENTRY =3D 0; + host->CSR_MERRENTRY =3D 0; /* set CSR_PWCL.PTBASE and CSR_STLBPS.PS bits from CSR_PRCFG2 */ - if (sys->CSR_PRCFG2 =3D=3D 0) { - sys->CSR_PRCFG2 =3D 0x3fffff000; + if (host->CSR_PRCFG2 =3D=3D 0) { + host->CSR_PRCFG2 =3D 0x3fffff000; } - tlb_ps =3D ctz32(sys->CSR_PRCFG2); - sys->CSR_STLBPS =3D FIELD_DP64(sys->CSR_STLBPS, CSR_STLBPS, PS, tlb_ps= ); - sys->CSR_PWCL =3D FIELD_DP64(sys->CSR_PWCL, CSR_PWCL, PTBASE, tlb_ps); + tlb_ps =3D ctz32(host->CSR_PRCFG2); + host->CSR_STLBPS =3D FIELD_DP64(host->CSR_STLBPS, CSR_STLBPS, PS, tlb_= ps); + host->CSR_PWCL =3D FIELD_DP64(host->CSR_PWCL, CSR_PWCL, PTBASE, tlb_ps= ); for (n =3D 0; n < 4; n++) { - sys->CSR_DMW[n] =3D FIELD_DP64(sys->CSR_DMW[n], CSR_DMW, PLV0, 0); - sys->CSR_DMW[n] =3D FIELD_DP64(sys->CSR_DMW[n], CSR_DMW, PLV1, 0); - sys->CSR_DMW[n] =3D FIELD_DP64(sys->CSR_DMW[n], CSR_DMW, PLV2, 0); - sys->CSR_DMW[n] =3D FIELD_DP64(sys->CSR_DMW[n], CSR_DMW, PLV3, 0); + host->CSR_DMW[n] =3D FIELD_DP64(host->CSR_DMW[n], CSR_DMW, PLV0, 0= ); + host->CSR_DMW[n] =3D FIELD_DP64(host->CSR_DMW[n], CSR_DMW, PLV1, 0= ); + host->CSR_DMW[n] =3D FIELD_DP64(host->CSR_DMW[n], CSR_DMW, PLV2, 0= ); + host->CSR_DMW[n] =3D FIELD_DP64(host->CSR_DMW[n], CSR_DMW, PLV3, 0= ); + } + if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LVZ)) { + host->CSR_GSTAT =3D FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, GIDBIT= , 8); } =20 #ifndef CONFIG_USER_ONLY env->pc =3D 0x1c000000; #ifdef CONFIG_TCG - memset(env->tlb, 0, sizeof(env->tlb)); + memset(host->tlb, 0, sizeof(host->tlb)); #endif if (kvm_enabled()) { kvm_arch_reset_vcpu(cs); --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740301696433.4446135511049; Wed, 26 Aug 2026 03:31:41 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAul-00021X-Lh; Wed, 26 Aug 2026 06:31:28 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuO-0001ug-F6 for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:04 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuM-0003NH-FC for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:04 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 59333DFA5; Wed, 26 Aug 2026 16:00:57 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 05/14] target/loongarch: Add LVZ guest interrupt state Date: Wed, 26 Aug 2026 18:30:09 +0800 Message-ID: <32e816aa68489d4e6b0b2b24e99a6c8a4e3469bf.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740304532158500 Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Hengyu Yu --- target/loongarch/cpu.c | 43 +++++++++++++++++++++++++--------- target/loongarch/internals.h | 4 +++- target/loongarch/tcg/tcg_cpu.c | 36 +++++++++++++++++++--------- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index c5c7f3e0e3..b12e8944de 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -57,41 +57,57 @@ static vaddr loongarch_cpu_get_pc(CPUState *cs) #ifndef CONFIG_USER_ONLY #include "hw/loongarch/virt.h" =20 -void loongarch_cpu_set_irq(void *opaque, int irq, int level) +void loongarch_cpu_set_irq_impl(void *opaque, int irq, int level, + bool guest) { LoongArchCPU *cpu =3D opaque; CPULoongArchState *env =3D &cpu->env; CPUState *cs =3D CPU(cpu); - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); + int interrupt =3D guest ? CPU_INTERRUPT_GUEST : CPU_INTERRUPT_HARD; =20 if (irq < 0 || irq >=3D N_IRQS) { return; } =20 - if (kvm_enabled()) { + if (!guest && kvm_enabled()) { kvm_loongarch_set_interrupt(cpu, irq, level); } else if (tcg_enabled()) { + if (!guest && irq >=3D 2 && irq < 10 && + (FIELD_EX64(sys->CSR_GINTC, CSR_GINTC, HWIP) & + BIT(irq - 2))) { + loongarch_cpu_set_irq_impl(opaque, irq, level, true); + return; + } sys->CSR_ESTAT =3D deposit64(sys->CSR_ESTAT, irq, 1, level !=3D 0); - if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + if (!guest || env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) { + cpu_interrupt(cs, interrupt); + } else { + cpu_reset_interrupt(cs, interrupt); + } } } } =20 +void loongarch_cpu_set_irq(void *opaque, int irq, int level) +{ + loongarch_cpu_set_irq_impl(opaque, irq, level, false); +} + /* 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, bool gues= t) { uint32_t pending; uint32_t status; - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); =20 pending =3D FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS); - status =3D FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, LIE); + status =3D FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, LIE); =20 return (pending & status) !=3D 0; } + #endif =20 #ifndef CONFIG_USER_ONLY @@ -100,7 +116,12 @@ bool loongarch_cpu_has_work(CPUState *cs) bool has_work =3D false; =20 if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD) && - cpu_loongarch_hw_interrupts_pending(cpu_env(cs))) { + cpu_loongarch_hw_interrupts_pending(cpu_env(cs), false)) { + has_work =3D true; + } + + if (cpu_test_interrupt(cs, CPU_INTERRUPT_GUEST) && + cpu_loongarch_hw_interrupts_pending(cpu_env(cs), true)) { has_work =3D true; } =20 diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index e01dbed40f..a23b0d3d58 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -32,6 +32,8 @@ void restore_fp_status(CPULoongArchState *env); extern const VMStateDescription vmstate_loongarch_cpu; =20 void loongarch_cpu_set_irq(void *opaque, int irq, int level); +void loongarch_cpu_set_irq_impl(void *opaque, int irq, int level, + bool guest); =20 void loongarch_constant_timer_cb(void *opaque); uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu); @@ -39,7 +41,7 @@ uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArch= CPU *cpu); void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, 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, bool gues= t); #endif /* !CONFIG_USER_ONLY */ =20 uint64_t read_fcc(CPULoongArchState *env); diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c index 4b1d44a164..e84ef5f305 100644 --- a/target/loongarch/tcg/tcg_cpu.c +++ b/target/loongarch/tcg/tcg_cpu.c @@ -238,29 +238,43 @@ static void loongarch_cpu_do_transaction_failed(CPUSt= ate *cs, hwaddr physaddr, } } =20 -static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *= env) +static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *= env, bool guest) { bool ret =3D 0; - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); =20 ret =3D (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, IE) && - !(FIELD_EX64(sys->CSR_DBG, CSR_DBG, DST))); + !(FIELD_EX64(host->CSR_DBG, CSR_DBG, DST))); =20 return ret; } =20 static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_reque= st) { + CPULoongArchState *env =3D cpu_env(cs); + bool has_interrupt =3D false; + if (interrupt_request & CPU_INTERRUPT_HARD) { - CPULoongArchState *env =3D cpu_env(cs); - - if (cpu_loongarch_hw_interrupts_enabled(env) && - cpu_loongarch_hw_interrupts_pending(env)) { - /* Raise it */ - cs->exception_index =3D EXCCODE_INT; - loongarch_cpu_do_interrupt(cs); - return true; + if (cpu_loongarch_hw_interrupts_enabled(env, false) && + cpu_loongarch_hw_interrupts_pending(env, false)) { + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + trigger_vm_exit(env); + } + has_interrupt =3D true; } + } else if (interrupt_request & CPU_INTERRUPT_GUEST) { + if (cpu_loongarch_hw_interrupts_enabled(env, true) && + cpu_loongarch_hw_interrupts_pending(env, true) && + env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + has_interrupt =3D true; + } + } + if (has_interrupt) { + /* Raise it */ + cs->exception_index =3D EXCCODE_INT; + loongarch_cpu_do_interrupt(cs); + return true; } return false; } --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740348963337.05480376942535; Wed, 26 Aug 2026 03:32:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuo-000265-2G; Wed, 26 Aug 2026 06:31:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuO-0001uh-K8 for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:04 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuM-0003NM-Hp for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:04 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 0C58CDF9B; Wed, 26 Aug 2026 16:00:57 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 06/14] target/loongarch: Add LVZ guest timer support Date: Wed, 26 Aug 2026 18:30:10 +0800 Message-ID: <0de498ed984527f0c4e86a18295c12354f81ebdf.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740350013158500 Content-Type: text/plain; charset="utf-8" Add a separate guest constant timer, preserve its remaining ticks across VM exits, and provide TVAL and TCFG helpers for accesses to the guest CSR bank. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu.c | 2 + target/loongarch/internals.h | 6 ++- target/loongarch/tcg/constant_timer.c | 67 ++++++++++++++++++++++----- target/loongarch/tcg/csr_helper.c | 22 ++++++++- target/loongarch/tcg/helper.h | 2 + 5 files changed, 84 insertions(+), 15 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index b12e8944de..ff36294aa5 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -795,6 +795,8 @@ static void loongarch_cpu_init(Object *obj) #ifdef CONFIG_TCG timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL, &loongarch_constant_timer_cb, cpu); + timer_init_ns(&cpu->guest_timer, QEMU_CLOCK_VIRTUAL, + &loongarch_constant_timer_cb_guest, cpu); #endif #endif } diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index a23b0d3d58..8ae3507c71 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -36,10 +36,12 @@ void loongarch_cpu_set_irq_impl(void *opaque, int irq, = int level, bool guest); =20 void loongarch_constant_timer_cb(void *opaque); +void loongarch_constant_timer_cb_guest(void *opaque); uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu); -uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu); +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu, bool gu= est); +void cpu_loongarch_set_guest_timer(LoongArchCPU *cpu, bool on); void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, - uint64_t value); + uint64_t value, bool guest); bool loongarch_cpu_has_work(CPUState *cs); bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env, bool gues= t); #endif /* !CONFIG_USER_ONLY */ diff --git a/target/loongarch/tcg/constant_timer.c b/target/loongarch/tcg/c= onstant_timer.c index f56e76d482..a341f48489 100644 --- a/target/loongarch/tcg/constant_timer.c +++ b/target/loongarch/tcg/constant_timer.c @@ -20,47 +20,92 @@ uint64_t cpu_loongarch_get_constant_timer_counter(Loong= ArchCPU *cpu) return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD; } =20 -uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu) +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu, bool gu= est) { + CPULoongArchState *env =3D &cpu->env; uint64_t now, expire; + CPUSysState *sys =3D get_sys(env, guest); + + if (guest && env_vm_level(env) !=3D LOONGARCH_VM_LEVEL_GUEST) { + return sys->CSR_TVAL; + } =20 now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - expire =3D timer_expire_time_ns(&cpu->timer); + expire =3D timer_expire_time_ns(guest ? &cpu->guest_timer : &cpu->time= r); =20 return (expire - now) / TIMER_PERIOD; } =20 void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, - uint64_t value) + uint64_t value, bool guest) { CPULoongArchState *env =3D &cpu->env; - CPUSysState *sys =3D env_sys(env); uint64_t now, next; + CPUSysState *sys =3D get_sys(env, guest); + QEMUTimer *timer =3D guest ? &cpu->guest_timer : &cpu->timer; =20 sys->CSR_TCFG =3D value; + if (guest && env_vm_level(env) !=3D LOONGARCH_VM_LEVEL_GUEST) { + return; + } + if (value & CONSTANT_TIMER_ENABLE) { now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); next =3D now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; - timer_mod(&cpu->timer, next); + timer_mod(timer, next); } else { - timer_del(&cpu->timer); + timer_del(timer); } } =20 -void loongarch_constant_timer_cb(void *opaque) +void cpu_loongarch_set_guest_timer(LoongArchCPU *cpu, bool on) { - LoongArchCPU *cpu =3D opaque; CPULoongArchState *env =3D &cpu->env; - CPUSysState *sys =3D env_sys(env); + CPUSysState *guest =3D get_sys(env, LOONGARCH_VM_LEVEL_GUEST); + uint64_t now, next, ticks; + + if (!(guest->CSR_TCFG & CONSTANT_TIMER_ENABLE)) { + return; + } + + if (on) { + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ticks =3D guest->CSR_TVAL ? guest->CSR_TVAL : + (guest->CSR_TCFG & CONSTANT_TIMER_TICK_M= ASK); + guest->CSR_TVAL =3D 0; + next =3D now + ticks * TIMER_PERIOD; + timer_mod(&cpu->guest_timer, next); + } else { + guest->CSR_TVAL =3D cpu_loongarch_get_constant_timer_ticks(cpu, tr= ue); + timer_del(&cpu->guest_timer); + } +} + +static void loongarch_constant_timer_cb_impl(void *opaque, bool guest) +{ + LoongArchCPU *cpu =3D opaque; + CPULoongArchState *env =3D &cpu->env; + CPUSysState *sys =3D get_sys(env, guest); + QEMUTimer *timer =3D guest ? &cpu->guest_timer : &cpu->timer; uint64_t now, next; =20 if (FIELD_EX64(sys->CSR_TCFG, CSR_TCFG, PERIODIC)) { now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); next =3D now + (sys->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_= PERIOD; - timer_mod(&cpu->timer, next); + timer_mod(timer, next); } else { sys->CSR_TCFG =3D FIELD_DP64(sys->CSR_TCFG, CSR_TCFG, EN, 0); } =20 - loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); + loongarch_cpu_set_irq_impl(opaque, IRQ_TIMER, 1, guest); +} + +void loongarch_constant_timer_cb(void *opaque) +{ + loongarch_constant_timer_cb_impl(opaque, false); +} + +void loongarch_constant_timer_cb_guest(void *opaque) +{ + loongarch_constant_timer_cb_impl(opaque, true); } diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_h= elper.c index 7dc33bc180..fa75508244 100644 --- a/target/loongarch/tcg/csr_helper.c +++ b/target/loongarch/tcg/csr_helper.c @@ -74,7 +74,14 @@ target_ulong helper_csrrd_tval(CPULoongArchState *env) { LoongArchCPU *cpu =3D env_archcpu(env); =20 - return cpu_loongarch_get_constant_timer_ticks(cpu); + return cpu_loongarch_get_constant_timer_ticks(cpu, false); +} + +target_ulong helper_gcsrrd_tval(CPULoongArchState *env) +{ + LoongArchCPU *cpu =3D env_archcpu(env); + + return cpu_loongarch_get_constant_timer_ticks(cpu, true); } =20 target_ulong helper_csrrd_msgir(CPULoongArchState *env) @@ -129,7 +136,18 @@ target_ulong helper_csrwr_tcfg(CPULoongArchState *env,= target_ulong val) CPUSysState *sys =3D env_sys(env); int64_t old_v =3D sys->CSR_TCFG; =20 - cpu_loongarch_store_constant_timer_config(cpu, val); + cpu_loongarch_store_constant_timer_config(cpu, val, false); + + return old_v; +} + +target_ulong helper_gcsrwr_tcfg(CPULoongArchState *env, target_ulong val) +{ + LoongArchCPU *cpu =3D env_archcpu(env); + CPUSysState *guest =3D get_sys(env, LOONGARCH_VM_LEVEL_GUEST); + int64_t old_v =3D guest->CSR_TCFG; + + cpu_loongarch_store_constant_timer_config(cpu, val, true); =20 return old_v; } diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h index 8a6c62f116..a003266827 100644 --- a/target/loongarch/tcg/helper.h +++ b/target/loongarch/tcg/helper.h @@ -100,11 +100,13 @@ DEF_HELPER_1(rdtime_d, i64, env) DEF_HELPER_1(csrrd_pgd, i64, env) DEF_HELPER_1(csrrd_cpuid, i64, env) DEF_HELPER_1(csrrd_tval, i64, env) +DEF_HELPER_1(gcsrrd_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(gcsrwr_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) --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178774030883487.58027791710595; Wed, 26 Aug 2026 03:31:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAue-000215-0S; Wed, 26 Aug 2026 06:31:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuP-0001v9-8Q for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:05 -0400 Received: from krgm.moe ([103.47.186.116]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuN-0003NU-3H for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:04 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id B41DDDFA6; Wed, 26 Aug 2026 16:00:58 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 07/14] target/loongarch: Add LVZ VM entry and exception handling Date: Wed, 26 Aug 2026 18:30:11 +0800 Message-ID: <3470bfa14e997c73d106a796205b3f0030b2f41c.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=103.47.186.116; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 1 X-Spam_score: 0.1 X-Spam_bar: / X-Spam_report: (0.1 / 5.0 requ) BAYES_00=-1.9, DOS_RCVD_IP_TWICE_B=1.999, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740311221158500 Content-Type: text/plain; charset="utf-8" Enter guest mode when ERTN restores GSTAT.PVM, and return to the host CSR bank for guest-sensitive, hypercall and host interrupt exits. Select the exception CSR bank before updating state and expose guest mode in TCG flags and MMU indices. Bound-check exceptions update the currently active CSR bank. HVC is available only to guest PLV0. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu.c | 50 ++++++++++++++++++++++++++++++++ target/loongarch/tcg/helper.h | 2 +- target/loongarch/tcg/op_helper.c | 22 ++++++++++++++ target/loongarch/tcg/tcg_cpu.c | 46 ++++++++++++++++++++++------- 4 files changed, 109 insertions(+), 11 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index ff36294aa5..4b0acc7135 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -129,6 +129,56 @@ bool loongarch_cpu_has_work(CPUState *cs) } #endif /* !CONFIG_USER_ONLY */ =20 +uint8_t get_tgid(CPULoongArchState *env) +{ + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + 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; +} + +bool will_return_to_guest(CPULoongArchState *env) +{ + if (!has_lvz_capability(env) || + env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + return false; + } + return FIELD_EX64(get_sys(env, LOONGARCH_VM_LEVEL_HOST)->CSR_GSTAT, + CSR_GSTAT, PVM); +} + +bool has_lvz_capability(CPULoongArchState *env) +{ + return FIELD_EX32(env->cpucfg[2], CPUCFG2, LVZ); +} + +uint8_t get_gid(CPULoongArchState *env) +{ + return FIELD_EX64(get_sys(env, LOONGARCH_VM_LEVEL_HOST)->CSR_GSTAT, + CSR_GSTAT, GID); +} + +void trigger_vm_exit(CPULoongArchState *env) +{ + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + + if (env_vm_level(env) !=3D LOONGARCH_VM_LEVEL_GUEST) { + return; + } + + cpu_loongarch_set_guest_timer(env_archcpu(env), false); + host->CSR_GSTAT =3D FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, PVM, 1); + env->vm_exit =3D true; +} + static void loongarch_la464_init_csr(DeviceState *dev) { #ifndef CONFIG_USER_ONLY diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h index a003266827..b87de15a99 100644 --- a/target/loongarch/tcg/helper.h +++ b/target/loongarch/tcg/helper.h @@ -14,7 +14,7 @@ DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, t= l, tl) =20 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) =20 /* Floating-point helper */ DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_WG, i64, env, i64, i64) diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_hel= per.c index e63ac66daa..11d204c61c 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 /* for crc32 */ #include "cpu-csr.h" @@ -19,6 +20,9 @@ /* Exceptions helpers */ void helper_raise_exception(CPULoongArchState *env, uint32_t exception) { + if (exception =3D=3D EXCCODE_GSPR || exception =3D=3D EXCCODE_HVC) { + trigger_vm_exit(env); + } do_raise_exception(env, exception, GETPC()); } =20 @@ -85,6 +89,10 @@ target_ulong helper_crc32c(target_ulong val, target_ulon= g m, uint64_t sz) =20 target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) { + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + trigger_vm_exit(env); + do_raise_exception(env, EXCCODE_GSPR, GETPC()); + } return rj >=3D ARRAY_SIZE(env->cpucfg) ? 0 : env->cpucfg[rj]; } =20 @@ -111,6 +119,8 @@ void helper_ertn(CPULoongArchState *env) { uint64_t csr_pplv, csr_pie; CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + CPUSysState *guest =3D get_sys(env, LOONGARCH_VM_LEVEL_GUEST); =20 if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { csr_pplv =3D FIELD_EX64(sys->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV); @@ -134,6 +144,18 @@ void helper_ertn(CPULoongArchState *env) sys->CSR_CRMD =3D FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, IE, csr_pie); =20 env->lladdr =3D 1; + if (will_return_to_guest(env)) { + host->CSR_GSTAT =3D FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, VM, 1); + set_sys(env, LOONGARCH_VM_LEVEL_GUEST); + cpu_loongarch_set_guest_timer(env_archcpu(env), true); + 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(); + } } =20 void helper_idle(CPULoongArchState *env) diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c index e84ef5f305..6af885cda1 100644 --- a/target/loongarch/tcg/tcg_cpu.c +++ b/target/loongarch/tcg/tcg_cpu.c @@ -44,6 +44,10 @@ static const struct TypeExcp excp_names[] =3D { {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"}, + {EXCCODE_GCSC, "Guest CSR visited by Software"}, + {EXCCODE_GCHC, "Guest CSR visited by Hardware"}, {EXCP_HLT, "EXCP_HLT"}, }; =20 @@ -78,9 +82,11 @@ void G_NORETURN do_raise_exception(CPULoongArchState *en= v, static void loongarch_cpu_do_interrupt(CPUState *cs) { CPULoongArchState *env =3D cpu_env(cs); - CPUSysState *sys =3D env_sys(env); bool update_badinstr =3D 1; int cause =3D -1; + bool real_guest =3D !env->vm_exit && env_vm_level(env); + CPUSysState *sys =3D get_sys(env, real_guest); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); bool tlbfill =3D FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR); uint32_t vec_size =3D FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, VS); uint64_t last_pc =3D env->pc; @@ -96,17 +102,17 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) =20 switch (cs->exception_index) { case EXCCODE_DBP: - sys->CSR_DBG =3D FIELD_DP64(sys->CSR_DBG, CSR_DBG, DCL, 1); - sys->CSR_DBG =3D FIELD_DP64(sys->CSR_DBG, CSR_DBG, ECODE, 0xC); + host->CSR_DBG =3D FIELD_DP64(host->CSR_DBG, CSR_DBG, DCL, 1); + host->CSR_DBG =3D FIELD_DP64(host->CSR_DBG, CSR_DBG, ECODE, 0xC); goto set_DERA; set_DERA: - sys->CSR_DERA =3D env->pc; - sys->CSR_DBG =3D FIELD_DP64(sys->CSR_DBG, CSR_DBG, DST, 1); - set_pc(env, sys->CSR_EENTRY + 0x480); + host->CSR_DERA =3D env->pc; + host->CSR_DBG =3D FIELD_DP64(host->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 =3D FIELD_DP64(sys->CSR_DBG, CSR_DBG, DEI, 1); + if (FIELD_EX64(host->CSR_DBG, CSR_DBG, DST)) { + host->CSR_DBG =3D FIELD_DP64(host->CSR_DBG, CSR_DBG, DEI, 1); goto set_DERA; } QEMU_FALLTHROUGH; @@ -117,6 +123,10 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) update_badinstr =3D 0; break; case EXCCODE_BCE: + case EXCCODE_GSPR: + case EXCCODE_GCHC: + case EXCCODE_GCSC: + case EXCCODE_HVC: sys->CSR_BADV =3D env->pc; QEMU_FALLTHROUGH; case EXCCODE_SYS: @@ -218,6 +228,12 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) qemu_plugin_vcpu_exception_cb(cs, last_pc); } cs->exception_index =3D -1; + if (env->vm_exit) { + host->CSR_GSTAT =3D FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, VM, 0); + set_sys(env, LOONGARCH_VM_LEVEL_HOST); + cpu_reset_interrupt(cs, CPU_INTERRUPT_GUEST); + } + env->vm_exit =3D false; } =20 static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physa= ddr, @@ -228,9 +244,9 @@ static void loongarch_cpu_do_transaction_failed(CPUStat= e *cs, hwaddr physaddr, uintptr_t retaddr) { CPULoongArchState *env =3D cpu_env(cs); - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); =20 - sys->CSR_BADV =3D addr; + host->CSR_BADV =3D addr; if (access_type =3D=3D MMU_INST_FETCH) { do_raise_exception(env, EXCCODE_ADEF, retaddr); } else { @@ -293,6 +309,9 @@ static TCGTBCPUState loongarch_get_tb_cpu_state(CPUStat= e *cs) uint32_t flags; =20 flags =3D sys->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + flags |=3D HW_FLAGS_GUEST_MODE; + } flags |=3D FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FP= E; flags |=3D FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SX= E; flags |=3D FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_A= SXE; @@ -320,6 +339,13 @@ static int loongarch_cpu_mmu_index(CPUState *cs, bool = ifetch) CPULoongArchState *env =3D cpu_env(cs); CPUSysState *sys =3D env_sys(env); =20 + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + 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); } --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740363332728.1312418714131; Wed, 26 Aug 2026 03:32:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuq-00026D-8a; Wed, 26 Aug 2026 06:31:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuP-0001vM-M2 for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:06 -0400 Received: from krgm.moe ([103.47.186.116]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuN-0003NV-Bk for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:05 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 6A83CDFAE; Wed, 26 Aug 2026 16:00:59 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 08/14] target/loongarch: Add LVZ guest CSR helpers Date: Wed, 26 Aug 2026 18:30:12 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=103.47.186.116; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 1 X-Spam_score: 0.1 X-Spam_bar: / X-Spam_report: (0.1 / 5.0 requ) BAYES_00=-1.9, DOS_RCVD_IP_TWICE_B=1.999, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740363979158500 Content-Type: text/plain; charset="utf-8" Add helper behavior for guest PGD, ESTAT, ASID and timer interrupt clearing, and for the host LVZ control CSRs. Synchronize injected and currently pending passthrough interrupts into the guest ESTAT value whenever GINTC changes. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/tcg/csr_helper.c | 226 +++++++++++++++++++++++++----- target/loongarch/tcg/helper.h | 10 ++ 2 files changed, 203 insertions(+), 33 deletions(-) diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_h= elper.c index fa75508244..ba30060ba4 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" =20 -target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val) +static target_ulong helper_csrwr_stlbps_impl(CPULoongArchState *env, + target_ulong val, bool guest) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); int64_t old_v =3D sys->CSR_STLBPS; =20 /* @@ -40,10 +41,21 @@ target_ulong helper_csrwr_stlbps(CPULoongArchState *env= , target_ulong val) return old_v; } =20 -target_ulong helper_csrrd_pgd(CPULoongArchState *env) +target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_stlbps_impl(env, val, false); +} + +target_ulong helper_gcsrwr_stlbps(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_stlbps_impl(env, val, true); +} + +static target_ulong helper_csrrd_pgd_impl(CPULoongArchState *env, + bool guest) { int64_t v; - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); =20 if (sys->CSR_TLBRERA & 0x1) { v =3D sys->CSR_TLBRBADV; @@ -60,6 +72,16 @@ target_ulong helper_csrrd_pgd(CPULoongArchState *env) return v; } =20 +target_ulong helper_csrrd_pgd(CPULoongArchState *env) +{ + return helper_csrrd_pgd_impl(env, false); +} + +target_ulong helper_gcsrrd_pgd(CPULoongArchState *env) +{ + return helper_csrrd_pgd_impl(env, true); +} + target_ulong helper_csrrd_cpuid(CPULoongArchState *env) { LoongArchCPU *lac =3D env_archcpu(env); @@ -70,18 +92,22 @@ target_ulong helper_csrrd_cpuid(CPULoongArchState *env) return sys->CSR_CPUID; } =20 -target_ulong helper_csrrd_tval(CPULoongArchState *env) +static target_ulong helper_csrrd_tval_impl(CPULoongArchState *env, + bool guest) { LoongArchCPU *cpu =3D env_archcpu(env); =20 - return cpu_loongarch_get_constant_timer_ticks(cpu, false); + return cpu_loongarch_get_constant_timer_ticks(cpu, guest); } =20 -target_ulong helper_gcsrrd_tval(CPULoongArchState *env) +target_ulong helper_csrrd_tval(CPULoongArchState *env) { - LoongArchCPU *cpu =3D env_archcpu(env); + return helper_csrrd_tval_impl(env, false); +} =20 - return cpu_loongarch_get_constant_timer_ticks(cpu, true); +target_ulong helper_gcsrrd_tval(CPULoongArchState *env) +{ + return helper_csrrd_tval_impl(env, true); } =20 target_ulong helper_csrrd_msgir(CPULoongArchState *env) @@ -106,20 +132,45 @@ target_ulong helper_csrrd_msgir(CPULoongArchState *en= v) return irq; } =20 -target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) +static target_ulong helper_csrwr_estat_impl(CPULoongArchState *env, + target_ulong val, bool guest) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); int64_t old_v =3D sys->CSR_ESTAT; =20 /* Only IS[1:0] can be written */ sys->CSR_ESTAT =3D deposit64(sys->CSR_ESTAT, 0, 2, val); + if (guest && env_vm_level(env) !=3D LOONGARCH_VM_LEVEL_GUEST) { + sys->CSR_ESTAT =3D deposit64(sys->CSR_ESTAT, 2, 11, + extract64(val, 2, 11)); + if (extract64(val, 2, 8) & + FIELD_EX64(host->CSR_GINTC, CSR_GINTC, HWIC)) { + host->CSR_ESTAT =3D deposit64(host->CSR_ESTAT, 2, 8, + extract64(host->CSR_ESTAT, 2, 8) & + ~extract64(val, 2, 8)); + } + sys->CSR_ESTAT =3D deposit64(sys->CSR_ESTAT, 16, 15, + extract64(val, 16, 15)); + } =20 return old_v; } =20 -target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) +target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) { - CPUSysState *sys =3D env_sys(env); + return helper_csrwr_estat_impl(env, val, false); +} + +target_ulong helper_gcsrwr_estat(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_estat_impl(env, val, true); +} + +static target_ulong helper_csrwr_asid_impl(CPULoongArchState *env, + target_ulong val, bool guest) +{ + CPUSysState *sys =3D get_sys(env, guest); int64_t old_v =3D sys->CSR_ASID; =20 /* Only ASID filed of CSR_ASID can be written */ @@ -130,45 +181,132 @@ target_ulong helper_csrwr_asid(CPULoongArchState *en= v, target_ulong val) return old_v; } =20 -target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) +target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_asid_impl(env, val, false); +} + +target_ulong helper_gcsrwr_asid(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_asid_impl(env, val, true); +} + +static target_ulong helper_csrwr_tcfg_impl(CPULoongArchState *env, + target_ulong val, bool guest) { LoongArchCPU *cpu =3D env_archcpu(env); - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); int64_t old_v =3D sys->CSR_TCFG; =20 - cpu_loongarch_store_constant_timer_config(cpu, val, false); + cpu_loongarch_store_constant_timer_config(cpu, val, guest); =20 return old_v; } =20 -target_ulong helper_gcsrwr_tcfg(CPULoongArchState *env, target_ulong val) +target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) { - LoongArchCPU *cpu =3D env_archcpu(env); - CPUSysState *guest =3D get_sys(env, LOONGARCH_VM_LEVEL_GUEST); - int64_t old_v =3D guest->CSR_TCFG; - - cpu_loongarch_store_constant_timer_config(cpu, val, true); + return helper_csrwr_tcfg_impl(env, val, false); +} =20 - return old_v; +target_ulong helper_gcsrwr_tcfg(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_tcfg_impl(env, val, true); } =20 -target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) +static target_ulong helper_csrwr_ticlr_impl(CPULoongArchState *env, + target_ulong val, bool guest) { LoongArchCPU *cpu =3D env_archcpu(env); int64_t old_v =3D 0; =20 if (val & 0x1) { bql_lock(); - loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); + loongarch_cpu_set_irq_impl(cpu, IRQ_TIMER, 0, guest); bql_unlock(); } return old_v; } =20 -target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val) +target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_ticlr_impl(env, val, false); +} + +target_ulong helper_gcsrwr_ticlr(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_ticlr_impl(env, val, true); +} + +target_ulong helper_csrwr_gstat(CPULoongArchState *env, target_ulong val) +{ + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + int64_t old_v =3D host->CSR_GSTAT; + uint8_t old_gid =3D FIELD_EX64(host->CSR_GSTAT, CSR_GSTAT, GID); + + host->CSR_GSTAT =3D FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, PVM, + FIELD_EX64(val, CSR_GSTAT, PVM)); + host->CSR_GSTAT =3D FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, GID, + FIELD_EX64(val, CSR_GSTAT, GID)); + + if (old_gid !=3D FIELD_EX64(host->CSR_GSTAT, CSR_GSTAT, GID)) { + tlb_flush(env_cpu(env)); + } + + return old_v; +} + +target_ulong helper_csrwr_gtlbc(CPULoongArchState *env, target_ulong val) +{ + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + int64_t old_v =3D host->CSR_GTLBC; + uint8_t old_use_tgid =3D FIELD_EX64(old_v, CSR_GTLBC, USETGID); + uint8_t old_tgid =3D FIELD_EX64(old_v, CSR_GTLBC, TGID); + + host->CSR_GTLBC =3D val; + if (old_use_tgid !=3D FIELD_EX64(host->CSR_GTLBC, CSR_GTLBC, USETGID) = || + old_tgid !=3D FIELD_EX64(host->CSR_GTLBC, CSR_GTLBC, TGID)) { + tlb_flush(env_cpu(env)); + } + + return old_v; +} + +target_ulong helper_csrwr_gintc(CPULoongArchState *env, target_ulong val) +{ + CPUState *cs =3D env_cpu(env); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + CPUSysState *guest =3D get_sys(env, LOONGARCH_VM_LEVEL_GUEST); + int64_t old_v =3D host->CSR_GINTC; + uint8_t hwis =3D FIELD_EX64(val, CSR_GINTC, HWIS); + uint8_t hwip =3D FIELD_EX64(val, CSR_GINTC, HWIP); + uint8_t pending =3D extract64(host->CSR_ESTAT, 2, 8); + + host->CSR_GINTC =3D val & 0xffff00; + guest->CSR_ESTAT =3D deposit64(guest->CSR_ESTAT, 2, 8, + hwis | (pending & hwip)); + + bql_lock(); + if (FIELD_EX64(host->CSR_ESTAT, CSR_ESTAT, IS) & ~(hwip << 2)) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST && + FIELD_EX64(guest->CSR_ESTAT, CSR_ESTAT, IS)) { + cpu_interrupt(cs, CPU_INTERRUPT_GUEST); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_GUEST); + } + bql_unlock(); + + return old_v; +} + +static target_ulong helper_csrwr_pwcl_impl(CPULoongArchState *env, + target_ulong val, bool guest) { uint8_t shift, ptbase; - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); int64_t old_v =3D sys->CSR_PWCL; =20 /* @@ -190,18 +328,40 @@ target_ulong helper_csrwr_pwcl(CPULoongArchState *env= , target_ulong val) return old_v; } =20 -target_ulong helper_csrwr_pwch(CPULoongArchState *env, target_ulong val) +target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val) { - uint8_t has_ptw; - CPUSysState *sys =3D env_sys(env); + return helper_csrwr_pwcl_impl(env, val, false); +} + +target_ulong helper_gcsrwr_pwcl(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_pwcl_impl(env, val, true); +} + +static target_ulong helper_csrwr_pwch_impl(CPULoongArchState *env, + target_ulong val, bool guest) +{ + uint8_t host_has_ptw; + CPUSysState *sys =3D get_sys(env, guest); int64_t old_v =3D sys->CSR_PWCH; =20 val =3D FIELD_DP64(val, CSR_PWCH, RESERVE, 0); - has_ptw =3D FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW); - if (!has_ptw) { + //TODO: host can't read guest cpucfg + host_has_ptw =3D FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW); + if (!host_has_ptw) { val =3D FIELD_DP64(val, CSR_PWCH, HPTW_EN, 0); } =20 sys->CSR_PWCH =3D val; return old_v; - } +} + +target_ulong helper_csrwr_pwch(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_pwch_impl(env, val, false); +} + +target_ulong helper_gcsrwr_pwch(CPULoongArchState *env, target_ulong val) +{ + return helper_csrwr_pwch_impl(env, val, true); +} diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h index b87de15a99..8e0ddd8693 100644 --- a/target/loongarch/tcg/helper.h +++ b/target/loongarch/tcg/helper.h @@ -98,18 +98,28 @@ DEF_HELPER_1(rdtime_d, i64, env) #ifndef CONFIG_USER_ONLY /* CSRs helper */ DEF_HELPER_1(csrrd_pgd, i64, env) +DEF_HELPER_1(gcsrrd_pgd, i64, env) DEF_HELPER_1(csrrd_cpuid, i64, env) DEF_HELPER_1(csrrd_tval, i64, env) DEF_HELPER_1(gcsrrd_tval, i64, env) DEF_HELPER_1(csrrd_msgir, i64, env) DEF_HELPER_2(csrwr_stlbps, i64, env, tl) +DEF_HELPER_2(gcsrwr_stlbps, i64, env, tl) DEF_HELPER_2(csrwr_estat, i64, env, tl) +DEF_HELPER_2(gcsrwr_estat, i64, env, tl) DEF_HELPER_2(csrwr_asid, i64, env, tl) +DEF_HELPER_2(gcsrwr_asid, i64, env, tl) DEF_HELPER_2(csrwr_tcfg, i64, env, tl) DEF_HELPER_2(gcsrwr_tcfg, i64, env, tl) DEF_HELPER_2(csrwr_ticlr, i64, env, tl) +DEF_HELPER_2(gcsrwr_ticlr, i64, env, tl) +DEF_HELPER_2(csrwr_gstat, i64, env, tl) +DEF_HELPER_2(csrwr_gtlbc, i64, env, tl) +DEF_HELPER_2(csrwr_gintc, i64, env, tl) DEF_HELPER_2(csrwr_pwcl, i64, env, tl) +DEF_HELPER_2(gcsrwr_pwcl, i64, env, tl) DEF_HELPER_2(csrwr_pwch, i64, env, tl) +DEF_HELPER_2(gcsrwr_pwch, i64, env, tl) DEF_HELPER_2(iocsrrd_b, i64, env, tl) DEF_HELPER_2(iocsrrd_h, i64, env, tl) DEF_HELPER_2(iocsrrd_w, i64, env, tl) --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740371634204.36108461012327; Wed, 26 Aug 2026 03:32:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAun-00025B-Ft; Wed, 26 Aug 2026 06:31:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuP-0001vN-TM for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:06 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuN-0003OA-VO for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:05 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 225D0DFBC; Wed, 26 Aug 2026 16:01:00 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 09/14] target/loongarch: Add LVZ migration state Date: Wed, 26 Aug 2026 18:30:13 +0800 Message-ID: <4d53d7db40dd8da468539c6c0c900e2722669381.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740372111158501 Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Hengyu Yu --- target/loongarch/machine.c | 111 ++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c index 931a5ca5ba..2bf2475748 100644 --- a/target/loongarch/machine.c +++ b/target/loongarch/machine.c @@ -7,6 +7,7 @@ =20 #include "qemu/osdep.h" #include "cpu.h" +#include "internals.h" #include "migration/vmstate.h" #include "system/tcg.h" #include "vec.h" @@ -200,18 +201,125 @@ static const VMStateDescription vmstate_tlb =3D { .minimum_version_id =3D 0, .needed =3D tlb_needed, .fields =3D (const VMStateField[]) { - VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX, + VMSTATE_STRUCT_ARRAY(env.sys_states[0].tlb, LoongArchCPU, + LOONGARCH_TLB_MAX, 0, vmstate_tlb_entry, LoongArchTLB), VMSTATE_END_OF_LIST() } }; + +static const VMStateDescription vmstate_lvz_sys =3D { + .name =3D "cpu/lvz-sys", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (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 =3D opaque; + + return FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, LVZ); +} + +static const VMStateDescription vmstate_lvz =3D { + .name =3D "cpu/lvz", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D lvz_needed, + .fields =3D (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_STRUCT_ARRAY(env.sys_states[1].tlb, LoongArchCPU, + LOONGARCH_TLB_MAX, + 0, vmstate_tlb_entry, LoongArchTLB), + VMSTATE_END_OF_LIST() + }, +}; #endif =20 +static int loongarch_cpu_post_load(void *opaque, int version_id) +{ + LoongArchCPU *cpu =3D opaque; + CPULoongArchState *env =3D &cpu->env; + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); + bool guest =3D FIELD_EX64(host->CSR_GSTAT, CSR_GSTAT, VM); + set_sys(env, guest); + return 0; +} + /* LoongArch CPU state */ const VMStateDescription vmstate_loongarch_cpu =3D { .name =3D "cpu", .version_id =3D 4, .minimum_version_id =3D 4, + .post_load =3D loongarch_cpu_post_load, .fields =3D (const VMStateField[]) { VMSTATE_UINT64_ARRAY(env.gpr, LoongArchCPU, 32), VMSTATE_UINT64(env.pc, LoongArchCPU), @@ -285,6 +393,7 @@ const VMStateDescription vmstate_loongarch_cpu =3D { &vmstate_lasx, #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) &vmstate_tlb, + &vmstate_lvz, #endif &vmstate_lbt, &vmstate_msgint, --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740360019487.31176076881036; Wed, 26 Aug 2026 03:32:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuq-00026E-9X; Wed, 26 Aug 2026 06:31:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuS-0001wQ-JL for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:10 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuN-0003Nt-JO for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:08 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id C9C5DDFB0; Wed, 26 Aug 2026 16:01:00 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 10/14] target/loongarch: Add LVZ MMU and PTW support Date: Wed, 26 Aug 2026 18:30:14 +0800 Message-ID: <6ef84c2ef4c2669703e107107d7e8c89ec46577f.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740362109158500 Content-Type: text/plain; charset="utf-8" Implement LVZ address translation with separate host and guest TLB banks, GID matching, guest TLB helpers, LVZ-aware INVT LB handling, two-stage translation and guest-mode hardware PTW updates through the host mapping. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu-mmu.h | 38 +- target/loongarch/cpu_helper.c | 84 +-- target/loongarch/tcg/helper.h | 22 +- .../tcg/insn_trans/trans_privileged.c.inc | 78 ++- target/loongarch/tcg/tcg_loongarch.h | 3 +- target/loongarch/tcg/tlb_helper.c | 486 ++++++++++++------ 6 files changed, 470 insertions(+), 241 deletions(-) diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h index 54fb732d62..c7f83f17de 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; =20 typedef struct MMUContext { @@ -30,18 +38,19 @@ typedef struct MMUContext { uint64_t pte_buddy[2]; } MMUContext; =20 -static inline bool cpu_has_ptw(CPULoongArchState *env) +static inline bool cpu_has_ptw(CPULoongArchState *env, bool guest) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); =20 return !!FIELD_EX64(sys->CSR_PWCH, CSR_PWCH, HPTW_EN); } =20 -static inline bool pte_present(CPULoongArchState *env, uint64_t entry) +static inline bool pte_present(CPULoongArchState *env, uint64_t entry, + bool guest) { uint8_t present; =20 - if (cpu_has_ptw(env)) { + if (cpu_has_ptw(env, guest)) { present =3D FIELD_EX64(entry, TLBENTRY, P); } else { present =3D FIELD_EX64(entry, TLBENTRY, V); @@ -50,11 +59,12 @@ static inline bool pte_present(CPULoongArchState *env, = uint64_t entry) return !!present; } =20 -static inline bool pte_write(CPULoongArchState *env, uint64_t entry) +static inline bool pte_write(CPULoongArchState *env, uint64_t entry, + bool guest) { uint8_t writable; =20 - if (cpu_has_ptw(env)) { + if (cpu_has_ptw(env, guest)) { writable =3D FIELD_EX64(entry, TLBENTRY, W); } else { writable =3D FIELD_EX64(entry, TLBENTRY, D); @@ -91,14 +101,22 @@ static inline bool pte_dirty(uint64_t entry) =20 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, bool gu= est); 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, bool guest, + 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, bool gues= t); +hwaddr loongarch_get_host_address(CPULoongArchState *env, hwaddr gpa, + uintptr_t retaddr); +TLBRet loongarch_map_host_address(CPULoongArchState *env, MMUContext *cont= ext, + MMUAccessType access_type, uintptr_t ret= addr); +TLBRet loongarch_map_address(CPULoongArchState *env, MMUContext *context, + MMUAccessType access_type, int mmu_idx, + int is_debug, bool guest, uintptr_t retaddr); hwaddr loongarch_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); uint64_t loongarch_palen_mask(CPULoongArchState *env); =20 diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 123cad3d93..a0aa8c2062 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -18,10 +18,11 @@ #include "cpu-mmu.h" #include "tcg/tcg_loongarch.h" =20 -void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, - uint64_t *dir_width, unsigned int level) +static void get_dir_base_width_csr(CPULoongArchState *env, uint64_t *dir_b= ase, + uint64_t *dir_width, unsigned int level, + bool guest) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); =20 switch (level) { case 1: @@ -48,18 +49,24 @@ void get_dir_base_width(CPULoongArchState *env, uint64_= t *dir_base, } } =20 +void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, + uint64_t *dir_width, unsigned int level, bool gues= t) +{ + get_dir_base_width_csr(env, dir_base, dir_width, level, guest); +} + TLBRet loongarch_check_pte(CPULoongArchState *env, MMUContext *context, - MMUAccessType access_type, int mmu_idx) + MMUAccessType access_type, int mmu_idx, bool gu= est) { - uint64_t plv =3D mmu_idx; + uint64_t plv =3D 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; =20 tlb_entry =3D context->pte; tlb_ps =3D context->ps; - tlb_v =3D pte_present(env, tlb_entry); - tlb_d =3D pte_write(env, tlb_entry); + tlb_v =3D pte_present(env, tlb_entry, guest); + tlb_d =3D pte_write(env, tlb_entry, guest); tlb_plv =3D FIELD_EX64(tlb_entry, TLBENTRY, PLV); if (is_la64(env)) { tlb_ppn =3D FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); @@ -101,7 +108,7 @@ TLBRet loongarch_check_pte(CPULoongArchState *env, MMUC= ontext *context, context->physical =3D (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | (context->addr & MAKE_64BIT_MASK(0, tlb_ps)); context->prot =3D PAGE_READ; - context->mmu_index =3D tlb_plv; + context->mmu_index =3D mmu_idx; if (tlb_d) { context->prot |=3D PAGE_WRITE; } @@ -147,7 +154,8 @@ static MemTxResult loongarch_cmpxchg_phys(CPUState *cs,= hwaddr phys, } =20 TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext *context, - int access_type, int mmu_idx, int debug) + int access_type, int mmu_idx, int debug, bool guest, + uintptr_t retaddr) { const MemTxAttrs attrs =3D MEMTXATTRS_UNSPECIFIED; CPUState *cs =3D env_cpu(env); @@ -159,7 +167,7 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext= *context, vaddr address; TLBRet ret; MemTxResult ret1; - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); =20 address =3D context->addr; if ((address >> 63) & 0x1) { @@ -170,7 +178,7 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext= *context, base &=3D palen_mask; =20 for (level =3D 4; level >=3D 0; level--) { - get_dir_base_width(env, &dir_base, &dir_width, level); + get_dir_base_width(env, &dir_base, &dir_width, level, guest); =20 if (dir_width =3D=3D 0) { continue; @@ -179,7 +187,10 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContex= t *context, /* get next level page directory */ index =3D (address >> dir_base) & ((1 << dir_width) - 1); phys =3D base | index << 3; - base =3D address_space_ldq_le(cs->as, phys, attrs, NULL); + base =3D address_space_ldq_le( + cs->as, + guest ? loongarch_get_host_address(env, phys, retaddr) : phys, + attrs, NULL); if (level) { if (FIELD_EX64(base, TLBENTRY, HUGE)) { /* base is a huge pte */ @@ -208,19 +219,22 @@ restart: context->pte_buddy[index] =3D base; context->pte_buddy[1 - index] =3D base + BIT_ULL(dir_base); base +=3D (BIT_ULL(dir_base) & address); - } else if (cpu_has_ptw(env)) { + } else if (cpu_has_ptw(env, guest)) { uint64_t val; =20 index &=3D 1; context->pte_buddy[index] =3D base; - val =3D address_space_ldq_le(cs->as, phys + 8 * (1 - 2 * index), - attrs, NULL); + val =3D address_space_ldq_le( + cs->as, + (guest ? loongarch_get_host_address(env, phys, retaddr) : phys= ) + + 8 * (1 - 2 * index), + attrs, NULL); context->pte_buddy[1 - index] =3D val; } =20 context->ps =3D dir_base; context->pte =3D base; - ret =3D loongarch_check_pte(env, context, access_type, mmu_idx); + ret =3D loongarch_check_pte(env, context, access_type, mmu_idx, guest); if (debug) { return ret; } @@ -231,7 +245,7 @@ restart: * Need atomic compchxg operation with pte update, other vCPUs may * update pte at the same time. */ - if (ret =3D=3D TLBRET_MATCH && cpu_has_ptw(env)) { + if (ret =3D=3D TLBRET_MATCH && cpu_has_ptw(env, guest)) { if (access_type =3D=3D MMU_DATA_STORE && pte_dirty(base)) { return ret; } @@ -244,10 +258,15 @@ restart: if (access_type =3D=3D MMU_DATA_STORE) { base =3D pte_mkdirty(base); } - ret1 =3D loongarch_cmpxchg_phys(cs, phys, pte, base); + ret1 =3D loongarch_cmpxchg_phys( + cs, guest ? loongarch_get_host_address(env, phys, retaddr) : p= hys, + pte, base); /* PTE updated by other CPU, reload PTE entry */ if (ret1 =3D=3D MEMTX_DECODE_ERROR) { - base =3D address_space_ldq_le(cs->as, phys, attrs, NULL); + base =3D address_space_ldq_le( + cs->as, + guest ? loongarch_get_host_address(env, phys, retaddr) : p= hys, + attrs, NULL); goto restart; } =20 @@ -273,15 +292,15 @@ restart: return ret; } =20 -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, bool guest, uintptr_t retaddr) { TLBRet ret; =20 if (tcg_enabled()) { - ret =3D loongarch_get_addr_from_tlb(env, context, access_type, mmu= _idx); + ret =3D loongarch_get_addr_from_tlb(env, context, access_type, mmu= _idx, + guest); if (ret !=3D TLBRET_NOMATCH) { return ret; } @@ -293,7 +312,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, + guest, retaddr); } =20 return TLBRET_NOMATCH; @@ -312,13 +332,14 @@ static hwaddr dmw_va2pa(CPULoongArchState *env, vaddr= va, uint64_t dmw) =20 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 =3D mmu_idx =3D=3D MMU_USER_IDX; - int kernel_mode =3D mmu_idx =3D=3D MMU_KERNEL_IDX; + bool guest =3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; + CPUSysState *sys =3D get_sys(env, guest); + int user_mode =3D mmu_idx_to_plv(mmu_idx) =3D=3D MMU_USER_IDX; + int kernel_mode =3D mmu_idx_to_plv(mmu_idx) =3D=3D MMU_KERNEL_IDX; uint32_t plv, base_c, base_v; int64_t addr_high; - CPUSysState *sys =3D env_sys(env); uint8_t da =3D FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, DA); uint8_t pg =3D FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PG); vaddr address; @@ -360,7 +381,8 @@ TLBRet get_physical_address(CPULoongArchState *env, MMU= Context *context, } =20 /* Mapped address */ - return loongarch_map_address(env, context, access_type, mmu_idx, is_de= bug); + return loongarch_map_address(env, context, access_type, mmu_idx, is_de= bug, + guest, retaddr); } =20 hwaddr loongarch_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr) @@ -370,7 +392,7 @@ hwaddr loongarch_cpu_get_phys_addr_debug(CPUState *cs, = vaddr addr) =20 context.addr =3D addr; if (get_physical_address(env, &context, MMU_DATA_LOAD, - cpu_mmu_index(cs, false), 1) !=3D TLBRET_MATC= H) { + cpu_mmu_index(cs, false), 1, 0) !=3D TLBRET_M= ATCH) { return -1; } return context.physical; diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h index 8e0ddd8693..0e87181deb 100644 --- a/target/loongarch/tcg/helper.h +++ b/target/loongarch/tcg/helper.h @@ -130,17 +130,17 @@ DEF_HELPER_3(iocsrwr_w, void, env, tl, tl) DEF_HELPER_3(iocsrwr_d, void, env, tl, tl) =20 /* 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) =20 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/targe= t/loongarch/tcg/insn_trans/trans_privileged.c.inc index bcfc977990..abedb132b9 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_iocsr= wr_d) =20 static void check_mmu_idx(DisasContext *ctx) { - if (ctx->mem_idx !=3D MMU_DA_IDX) { + if (ctx->mem_idx !=3D MMU_DA_IDX && ctx->mem_idx !=3D MMU_GUEST_DA_IDX= ) { tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4); ctx->base.is_jmp =3D DISAS_EXIT; } @@ -260,7 +260,7 @@ static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrc= h *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbsrch(tcg_env); + gen_helper_tlbsrch(tcg_env, tcg_constant_i32(ctx->guest_mode)); return true; } =20 @@ -269,7 +269,7 @@ 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(ctx->guest_mode)); return true; } =20 @@ -278,7 +278,7 @@ 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(ctx->guest_mode)); check_mmu_idx(ctx); return true; } @@ -288,7 +288,7 @@ static bool trans_tlbfill(DisasContext *ctx, arg_tlbfil= l *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbfill(tcg_env); + gen_helper_tlbfill(tcg_env, tcg_constant_i32(ctx->guest_mode)); check_mmu_idx(ctx); return true; } @@ -298,7 +298,7 @@ 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(ctx->guest_mode)); check_mmu_idx(ctx); return true; } @@ -308,7 +308,7 @@ static bool trans_tlbflush(DisasContext *ctx, arg_tlbfl= ush *a) if (check_plv(ctx)) { return false; } - gen_helper_tlbflush(tcg_env); + gen_helper_tlbflush(tcg_env, tcg_constant_i32(ctx->guest_mode)); check_mmu_idx(ctx); return true; } @@ -322,25 +322,63 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtl= b *a) return false; } =20 + if (!avail_LVZ(ctx) && a->imm > 0x6) { + return false; + } + 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 0x2: + gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(1), + tcg_constant_i32(0)); + break; + case 0x3: + gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(0), + tcg_constant_i32(0)); + break; + case 0x4: + gen_helper_invtlb_all_asid(tcg_env, rj, tcg_constant_i32(0)); + break; + case 0x5: + gen_helper_invtlb_page_asid(tcg_env, rj, rk, tcg_constant_i32(0)); + break; + case 0x6: + 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 2: - gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(1)); + case 0xa: + gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(1), + tcg_constant_i32(1)); break; - case 3: - gen_helper_invtlb_all_g(tcg_env, tcg_constant_i32(0)); + case 0xb: + gen_helper_invtlb_all_g(tcg_env, rj, tcg_constant_i32(0), + tcg_constant_i32(1)); break; - case 4: - gen_helper_invtlb_all_asid(tcg_env, rj); + case 0xc: + gen_helper_invtlb_all_asid(tcg_env, rj, tcg_constant_i32(1)); break; - case 5: - gen_helper_invtlb_page_asid(tcg_env, rj, rk); + case 0xd: + gen_helper_invtlb_page_asid(tcg_env, rj, rk, tcg_constant_i32(1)); break; - case 6: - gen_helper_invtlb_page_asid_or_g(tcg_env, rj, rk); + 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/tcg_loongarch.h b/target/loongarch/tcg/tc= g_loongarch.h index 7fb627f2d6..5acaf49d47 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, =20 TLBRet loongarch_get_addr_from_tlb(CPULoongArchState *env, MMUContext *context, - MMUAccessType access_type, int mmu_idx); + MMUAccessType access_type, int mmu_idx, + bool guest); =20 #endif /* TARGET_LOONGARCH_TCG_LOONGARCH_H */ diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_h= elper.c index a4b90beca6..776626072d 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -8,7 +8,6 @@ =20 #include "qemu/osdep.h" #include "qemu/guest-random.h" - #include "cpu.h" #include "cpu-mmu.h" #include "internals.h" @@ -18,6 +17,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" @@ -35,29 +36,49 @@ static bool tlb_match_asid(bool global, int asid, int t= lb_asid) return !global && tlb_asid =3D=3D asid; } =20 +static inline bool tlb_entry_matches_gid(LoongArchTLB *tlb, uint8_t gid) +{ + return FIELD_EX64(tlb->tlb_misc, TLB_MISC, GID) =3D=3D gid; +} + +static inline LoongArchTLB *tlb_bank(CPULoongArchState *env, bool guest) +{ + return get_sys(env, guest)->tlb; +} + bool check_ps(CPULoongArchState *env, uint8_t tlb_ps) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D get_sys(env, LOONGARCH_VM_LEVEL_HOST); =20 if (tlb_ps >=3D 64) { return false; } - return BIT_ULL(tlb_ps) & (sys->CSR_PRCFG2); + return BIT_ULL(tlb_ps) & (host->CSR_PRCFG2); } =20 static void raise_mmu_exception(CPULoongArchState *env, vaddr address, MMUAccessType access_type, TLBRet tlb_erro= r) { CPUState *cs =3D env_cpu(env); - CPUSysState *sys =3D env_sys(env); + bool real_guest; + + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST && + tlb_error > TLBRET_HOST_MATCH) { + trigger_vm_exit(env); + } + + real_guest =3D !env->vm_exit && env_vm_level(env); + CPUSysState *sys =3D get_sys(env, real_guest); =20 switch (tlb_error) { default: case TLBRET_BADADDR: + case TLBRET_HOST_BADADDR: cs->exception_index =3D access_type =3D=3D 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 =3D=3D MMU_DATA_LOAD) { cs->exception_index =3D EXCCODE_PIL; @@ -69,6 +90,7 @@ static void raise_mmu_exception(CPULoongArchState *env, v= addr address, sys->CSR_TLBRERA =3D FIELD_DP64(sys->CSR_TLBRERA, CSR_TLBRERA, IST= LBR, 1); break; case TLBRET_INVALID: + case TLBRET_HOST_INVALID: /* TLB match with no valid bit */ if (access_type =3D=3D MMU_DATA_LOAD) { cs->exception_index =3D EXCCODE_PIL; @@ -79,24 +101,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 =3D EXCCODE_PME; break; case TLBRET_XI: + case TLBRET_HOST_XI: /* Execute-Inhibit Exception */ cs->exception_index =3D EXCCODE_PNX; break; case TLBRET_RI: + case TLBRET_HOST_RI: /* Read-Inhibit Exception */ cs->exception_index =3D EXCCODE_PNR; break; case TLBRET_PE: + case TLBRET_HOST_PE: /* Privileged Exception */ cs->exception_index =3D EXCCODE_PPI; break; } =20 - if (tlb_error =3D=3D TLBRET_NOMATCH) { + if (tlb_error =3D=3D TLBRET_NOMATCH || tlb_error =3D=3D TLBRET_HOST_NO= MATCH) { sys->CSR_TLBRBADV =3D address; if (is_la64(env)) { sys->CSR_TLBREHI =3D FIELD_DP64(sys->CSR_TLBREHI, CSR_TLBREHI_= 64, @@ -110,15 +136,19 @@ static void raise_mmu_exception(CPULoongArchState *en= v, vaddr address, sys->CSR_BADV =3D address; } sys->CSR_TLBEHI =3D address & (TARGET_PAGE_MASK << 1); - } + } } =20 -static void invalidate_tlb_entry(CPULoongArchState *env, int index) +static void invalidate_tlb_entry(CPULoongArchState *env, int index, bool g= uest) { target_ulong addr, mask, pagesize; uint8_t tlb_ps; - LoongArchTLB *tlb =3D &env->tlb[index]; - int idxmap =3D BIT(MMU_KERNEL_IDX) | BIT(MMU_USER_IDX); + LoongArchTLB *tlb =3D &tlb_bank(env, guest)[index]; + int idxmap =3D guest ? (BIT(MMU_GUEST_IDX) | BIT(MMU_GUEST_IDX + 1) | + BIT(MMU_GUEST_IDX + 2) | BIT(MMU_GUEST_IDX + 3) | + BIT(MMU_GUEST_DA_IDX)) : + (BIT(MMU_KERNEL_IDX) | BIT(MMU_USER_IDX) | + BIT(MMU_DA_IDX)); uint64_t tlb_vppn =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); bool tlb_v; =20 @@ -128,28 +158,27 @@ static void invalidate_tlb_entry(CPULoongArchState *e= nv, int index) addr =3D (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask; addr =3D sextract64(addr, 0, TARGET_VIRT_ADDR_SPACE_BITS); =20 - tlb_v =3D pte_present(env, tlb->tlb_entry0); + tlb_v =3D pte_present(env, tlb->tlb_entry0, guest); if (tlb_v) { tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize, idxmap, TARGET_LONG_BITS); } =20 - tlb_v =3D pte_present(env, tlb->tlb_entry1); + tlb_v =3D pte_present(env, tlb->tlb_entry1, guest); if (tlb_v) { tlb_flush_range_by_mmuidx(env_cpu(env), addr + pagesize, pagesize, idxmap, TARGET_LONG_BITS); } } =20 -static void invalidate_tlb(CPULoongArchState *env, int index) +static void invalidate_tlb(CPULoongArchState *env, int index, bool guest) { - LoongArchTLB *tlb; + LoongArchTLB *tlb =3D &tlb_bank(env, guest)[index]; + CPUSysState *sys =3D get_sys(env, guest); uint16_t csr_asid, tlb_asid, tlb_g; uint8_t tlb_e; - CPUSysState *sys =3D env_sys(env); =20 csr_asid =3D FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID); - tlb =3D &env->tlb[index]; tlb_e =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); if (!tlb_e) { return; @@ -158,19 +187,19 @@ static void invalidate_tlb(CPULoongArchState *env, in= t index) tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); tlb_asid =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); tlb_g =3D FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); - /* QEMU TLB is flushed when asid is changed */ if (tlb_g =3D=3D 0 && tlb_asid !=3D csr_asid) { return; } - invalidate_tlb_entry(env, index); + invalidate_tlb_entry(env, index, guest); } =20 /* Prepare tlb entry information in software PTW mode */ -static void sptw_prepare_context(CPULoongArchState *env, MMUContext *conte= xt) +static void sptw_prepare_context(CPULoongArchState *env, MMUContext *conte= xt, + bool guest) { + CPUSysState *sys =3D get_sys(env, guest); uint64_t lo0, lo1, csr_vppn; uint8_t csr_ps; - CPUSysState *sys =3D env_sys(env); =20 if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { csr_ps =3D FIELD_EX64(sys->CSR_TLBREHI, CSR_TLBREHI, PS); @@ -199,24 +228,24 @@ static void sptw_prepare_context(CPULoongArchState *e= nv, MMUContext *context) } =20 static void fill_tlb_entry(CPULoongArchState *env, LoongArchTLB *tlb, - MMUContext *context) + MMUContext *context, bool guest) { + CPUSysState *sys =3D get_sys(env, guest); uint64_t lo0, lo1, csr_vppn; uint16_t csr_asid; uint8_t csr_ps; - CPUSysState *sys =3D env_sys(env); =20 csr_vppn =3D context->addr >> R_TLB_MISC_VPPN_SHIFT; csr_ps =3D context->ps; lo0 =3D context->pte_buddy[0]; lo1 =3D context->pte_buddy[1]; =20 - /* Store page size in field PS */ tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, csr_ps); tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn); tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1); csr_asid =3D FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID); tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid); + tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, GID, get_tgid(en= v)); =20 tlb->tlb_entry0 =3D lo0; tlb->tlb_entry1 =3D lo1; @@ -240,24 +269,24 @@ static uint32_t get_random_tlb(uint32_t low, uint32_t= high) */ static LoongArchTLB *loongarch_tlb_search_cb(CPULoongArchState *env, vaddr vaddr, int csr_asid, - tlb_match func) + tlb_match func, bool guest, + uint8_t gid) { + CPUSysState *sys =3D get_sys(env, guest); LoongArchTLB *tlb; uint16_t tlb_asid, stlb_idx; uint8_t tlb_e, tlb_ps, stlb_ps; bool tlb_g; int i, compare_shift; uint64_t vpn, tlb_vppn; - CPUSysState *sys =3D env_sys(env); =20 stlb_ps =3D FIELD_EX64(sys->CSR_STLBPS, CSR_STLBPS, PS); vpn =3D (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1); - stlb_idx =3D vpn & 0xff; /* VA[25:15] <=3D=3D> TLBIDX.index for 16KiB = Page */ + stlb_idx =3D vpn & 0xff; compare_shift =3D stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; =20 - /* Search STLB */ for (i =3D 0; i < 8; ++i) { - tlb =3D &env->tlb[i * 256 + stlb_idx]; + tlb =3D &tlb_bank(env, guest)[i * 256 + stlb_idx]; tlb_e =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); if (tlb_e) { tlb_vppn =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); @@ -265,15 +294,15 @@ static LoongArchTLB *loongarch_tlb_search_cb(CPULoong= ArchState *env, tlb_g =3D !!FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); =20 if (func(tlb_g, csr_asid, tlb_asid) && + tlb_entry_matches_gid(tlb, gid) && (vpn =3D=3D (tlb_vppn >> compare_shift))) { return tlb; } } } =20 - /* Search MTLB */ for (i =3D LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) { - tlb =3D &env->tlb[i]; + tlb =3D &tlb_bank(env, guest)[i]; tlb_e =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); if (tlb_e) { tlb_vppn =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); @@ -283,6 +312,7 @@ static LoongArchTLB *loongarch_tlb_search_cb(CPULoongAr= chState *env, compare_shift =3D tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; vpn =3D (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1); if (func(tlb_g, csr_asid, tlb_asid) && + tlb_entry_matches_gid(tlb, gid) && (vpn =3D=3D (tlb_vppn >> compare_shift))) { return tlb; } @@ -292,35 +322,36 @@ static LoongArchTLB *loongarch_tlb_search_cb(CPULoong= ArchState *env, } =20 static bool loongarch_tlb_search(CPULoongArchState *env, vaddr vaddr, - int *index) + int *index, bool guest, uint8_t gid) { - int csr_asid; - tlb_match func; + CPUSysState *sys =3D get_sys(env, guest); LoongArchTLB *tlb; - CPUSysState *sys =3D env_sys(env); =20 - func =3D tlb_match_any; - csr_asid =3D FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID); - tlb =3D loongarch_tlb_search_cb(env, vaddr, csr_asid, func); + tlb =3D loongarch_tlb_search_cb(env, vaddr, + FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID= ), + tlb_match_any, guest, gid); if (tlb) { - *index =3D tlb - env->tlb; + *index =3D tlb - tlb_bank(env, guest); return true; } =20 return false; } =20 -void helper_tlbsrch(CPULoongArchState *env) +void helper_tlbsrch(CPULoongArchState *env, uint32_t guest) { + CPUSysState *sys =3D get_sys(env, guest); int index, match; - CPUSysState *sys =3D env_sys(env); + vaddr search_ehi; =20 if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { - match =3D loongarch_tlb_search(env, sys->CSR_TLBREHI, &index); + search_ehi =3D sys->CSR_TLBREHI; } else { - match =3D loongarch_tlb_search(env, sys->CSR_TLBEHI, &index); + search_ehi =3D sys->CSR_TLBEHI; } =20 + match =3D loongarch_tlb_search(env, search_ehi, &index, guest, + get_tgid(env)); if (match) { sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX,= index); sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, NE, 0); @@ -330,20 +361,19 @@ void helper_tlbsrch(CPULoongArchState *env) sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, NE, 1); } =20 -void helper_tlbrd(CPULoongArchState *env) +void helper_tlbrd(CPULoongArchState *env, uint32_t guest) { + CPUSysState *sys =3D get_sys(env, guest); LoongArchTLB *tlb; int index; uint8_t tlb_ps, tlb_e; - CPUSysState *sys =3D env_sys(env); =20 index =3D FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX); - tlb =3D &env->tlb[index]; + tlb =3D &tlb_bank(env, guest)[index]; tlb_ps =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); tlb_e =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); =20 if (!tlb_e) { - /* Invalid TLB entry */ sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, NE, 1); sys->CSR_ASID =3D FIELD_DP64(sys->CSR_ASID, CSR_ASID, ASID, 0); sys->CSR_TLBEHI =3D 0; @@ -351,79 +381,73 @@ void helper_tlbrd(CPULoongArchState *env) sys->CSR_TLBELO1 =3D 0; sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, PS, 0); } else { - /* Valid TLB entry */ sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, NE, 0); sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, - PS, (tlb_ps & 0x3f)); + PS, tlb_ps & 0x3f); sys->CSR_TLBEHI =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN) << - R_TLB_MISC_VPPN_SHIFT; + R_TLB_MISC_VPPN_SHIFT; sys->CSR_TLBELO0 =3D tlb->tlb_entry0; sys->CSR_TLBELO1 =3D tlb->tlb_entry1; } } =20 static void update_tlb_index(CPULoongArchState *env, MMUContext *context, - int index) + int index, bool guest) { LoongArchTLB *old, new =3D {}; bool skip_inv =3D false, tlb_v0, tlb_v1; =20 - old =3D env->tlb + index; - fill_tlb_entry(env, &new, context); - /* Check whether ASID/VPPN is the same */ + old =3D tlb_bank(env, guest) + index; + fill_tlb_entry(env, &new, context, guest); if (old->tlb_misc =3D=3D new.tlb_misc) { - /* Check whether both even/odd pages is the same or invalid */ - tlb_v0 =3D pte_present(env, old->tlb_entry0); - tlb_v1 =3D pte_present(env, old->tlb_entry1); + tlb_v0 =3D pte_present(env, old->tlb_entry0, guest); + tlb_v1 =3D pte_present(env, old->tlb_entry1, guest); if ((!tlb_v0 || new.tlb_entry0 =3D=3D old->tlb_entry0) && (!tlb_v1 || new.tlb_entry1 =3D=3D old->tlb_entry1)) { skip_inv =3D true; } } =20 - /* flush tlb before updating the entry */ if (!skip_inv) { - invalidate_tlb(env, index); + invalidate_tlb(env, index, guest); } =20 *old =3D new; } =20 -void helper_tlbwr(CPULoongArchState *env) +void helper_tlbwr(CPULoongArchState *env, uint32_t guest) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D get_sys(env, guest); int index =3D FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX); MMUContext context; =20 if (FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, NE)) { - invalidate_tlb(env, index); + invalidate_tlb(env, index, guest); return; } =20 - sptw_prepare_context(env, &context); - update_tlb_index(env, &context, index); + sptw_prepare_context(env, &context, guest); + update_tlb_index(env, &context, index, guest); } =20 static int get_tlb_random_index(CPULoongArchState *env, vaddr addr, - int pagesize) + int pagesize, bool guest) { + CPUSysState *sys =3D get_sys(env, guest); uint64_t address; int index, set, i, stlb_idx; uint16_t asid, tlb_asid, stlb_ps; LoongArchTLB *tlb; uint8_t tlb_e, tlb_g; - CPUSysState *sys =3D env_sys(env); =20 - /* Validity of stlb_ps is checked in helper_csrwr_stlbps() */ stlb_ps =3D FIELD_EX64(sys->CSR_STLBPS, CSR_STLBPS, PS); asid =3D FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID); if (pagesize =3D=3D stlb_ps) { - /* Only write into STLB bits [47:13] */ address =3D addr & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_64_VPPN_SHIFT); set =3D -1; - stlb_idx =3D (address >> (stlb_ps + 1)) & 0xff; /* [0,255] */ + stlb_idx =3D (address >> (stlb_ps + 1)) & 0xff; for (i =3D 0; i < 8; ++i) { - tlb =3D &env->tlb[i * 256 + stlb_idx]; + tlb =3D &tlb_bank(env, guest)[i * 256 + stlb_idx]; tlb_e =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); if (!tlb_e) { set =3D i; @@ -432,21 +456,20 @@ static int get_tlb_random_index(CPULoongArchState *en= v, vaddr addr, =20 tlb_asid =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); tlb_g =3D FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); - if (tlb_g =3D=3D 0 && asid !=3D tlb_asid) { + if (tlb_g =3D=3D 0 && asid !=3D tlb_asid && + tlb_entry_matches_gid(tlb, get_tgid(env))) { set =3D i; } } =20 - /* Choose one set randomly */ if (set < 0) { set =3D get_random_tlb(0, 7); } index =3D set * 256 + stlb_idx; } else { - /* Only write into MTLB */ index =3D -1; for (i =3D LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { - tlb =3D &env->tlb[i]; + tlb =3D &tlb_bank(env, guest)[i]; tlb_e =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); =20 if (!tlb_e) { @@ -456,7 +479,8 @@ static int get_tlb_random_index(CPULoongArchState *env,= vaddr addr, =20 tlb_asid =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); tlb_g =3D FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); - if (tlb_g =3D=3D 0 && asid !=3D tlb_asid) { + if (tlb_g =3D=3D 0 && asid !=3D tlb_asid && + tlb_entry_matches_gid(tlb, get_tgid(env))) { index =3D i; } } @@ -469,56 +493,54 @@ static int get_tlb_random_index(CPULoongArchState *en= v, vaddr addr, return index; } =20 -void helper_tlbfill(CPULoongArchState *env) +void helper_tlbfill(CPULoongArchState *env, uint32_t guest) { + CPUSysState *sys =3D get_sys(env, guest); vaddr entryhi; int index, pagesize; MMUContext context; - CPUSysState *sys =3D env_sys(env); =20 if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { entryhi =3D sys->CSR_TLBREHI; - /* Validity of pagesize is checked in helper_ldpte() */ pagesize =3D FIELD_EX64(sys->CSR_TLBREHI, CSR_TLBREHI, PS); } else { entryhi =3D sys->CSR_TLBEHI; - /* Validity of pagesize is checked in helper_tlbrd() */ pagesize =3D FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, PS); } =20 - sptw_prepare_context(env, &context); - index =3D get_tlb_random_index(env, entryhi, pagesize); - invalidate_tlb(env, index); - fill_tlb_entry(env, env->tlb + index, &context); + sptw_prepare_context(env, &context, guest); + index =3D get_tlb_random_index(env, entryhi, pagesize, guest); + invalidate_tlb(env, index, guest); + fill_tlb_entry(env, tlb_bank(env, guest) + index, &context, guest); } =20 -void helper_tlbclr(CPULoongArchState *env) +void helper_tlbclr(CPULoongArchState *env, uint32_t guest) { + CPUSysState *sys =3D get_sys(env, guest); LoongArchTLB *tlb; int i, index; uint16_t csr_asid, tlb_asid, tlb_g; - CPUSysState *sys =3D env_sys(env); =20 csr_asid =3D FIELD_EX64(sys->CSR_ASID, CSR_ASID, ASID); index =3D FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX); =20 if (index < LOONGARCH_STLB) { - /* STLB. One line per operation */ for (i =3D 0; i < 8; i++) { - tlb =3D &env->tlb[i * 256 + (index % 256)]; + tlb =3D &tlb_bank(env, guest)[i * 256 + (index % 256)]; tlb_asid =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); tlb_g =3D FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); - if (!tlb_g && tlb_asid =3D=3D csr_asid) { + if (!tlb_g && tlb_asid =3D=3D csr_asid && + tlb_entry_matches_gid(tlb, get_tgid(env))) { tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0= ); } } } else if (index < LOONGARCH_TLB_MAX) { - /* All MTLB entries */ for (i =3D LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { - tlb =3D &env->tlb[i]; + tlb =3D &tlb_bank(env, guest)[i]; tlb_asid =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); tlb_g =3D FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); - if (!tlb_g && tlb_asid =3D=3D csr_asid) { + if (!tlb_g && tlb_asid =3D=3D csr_asid && + tlb_entry_matches_gid(tlb, get_tgid(env))) { tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0= ); } } @@ -527,63 +549,97 @@ void helper_tlbclr(CPULoongArchState *env) tlb_flush(env_cpu(env)); } =20 -void helper_tlbflush(CPULoongArchState *env) +void helper_tlbflush(CPULoongArchState *env, uint32_t guest) { + CPUSysState *sys =3D get_sys(env, guest); int i, index; - CPUSysState *sys =3D env_sys(env); =20 index =3D FIELD_EX64(sys->CSR_TLBIDX, CSR_TLBIDX, INDEX); =20 if (index < LOONGARCH_STLB) { - /* STLB. One line per operation */ for (i =3D 0; i < 8; i++) { int s_idx =3D i * 256 + (index % 256); - env->tlb[s_idx].tlb_misc =3D FIELD_DP64(env->tlb[s_idx].tlb_mi= sc, - TLB_MISC, E, 0); + LoongArchTLB *tlb =3D &tlb_bank(env, guest)[s_idx]; + + tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); } } else if (index < LOONGARCH_TLB_MAX) { - /* All MTLB entries */ for (i =3D LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) { - env->tlb[i].tlb_misc =3D FIELD_DP64(env->tlb[i].tlb_misc, - TLB_MISC, E, 0); + LoongArchTLB *tlb =3D &tlb_bank(env, guest)[i]; + + tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); } } =20 tlb_flush(env_cpu(env)); } =20 -void helper_invtlb_all(CPULoongArchState *env) +void helper_invtlb_all(CPULoongArchState *env, target_ulong info, uint32_t= op, + uint32_t to_guest) { + uint16_t gid =3D to_guest ? (info & 0xff) : get_tgid(env); + + if (to_guest && env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + do_raise_exception(env, EXCCODE_IPE, GETPC()); + } + + to_guest |=3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; + for (int i =3D 0; i < LOONGARCH_TLB_MAX; i++) { - env->tlb[i].tlb_misc =3D FIELD_DP64(env->tlb[i].tlb_misc, - TLB_MISC, E, 0); + LoongArchTLB *tlb =3D &tlb_bank(env, false)[i]; + LoongArchTLB *gtlb =3D &tlb_bank(env, true)[i]; + + if (!to_guest && (op =3D=3D 0 || tlb_entry_matches_gid(tlb, 0))) { + tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); + } + if ((!to_guest && op =3D=3D 0) || + (to_guest && tlb_entry_matches_gid(gtlb, gid))) { + gtlb->tlb_misc =3D FIELD_DP64(gtlb->tlb_misc, TLB_MISC, E, 0); + } } tlb_flush(env_cpu(env)); } =20 -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) { + uint16_t gid =3D to_guest ? (info & 0xff) : get_tgid(env); + + if (to_guest && env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + do_raise_exception(env, EXCCODE_IPE, GETPC()); + } + + to_guest |=3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; + for (int i =3D 0; i < LOONGARCH_TLB_MAX; i++) { - LoongArchTLB *tlb =3D &env->tlb[i]; + LoongArchTLB *tlb =3D &tlb_bank(env, to_guest)[i]; uint8_t tlb_g =3D FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); =20 - if (tlb_g =3D=3D g) { + if (tlb_g =3D=3D g && tlb_entry_matches_gid(tlb, gid)) { tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); } } tlb_flush(env_cpu(env)); } =20 -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 =3D info & R_CSR_ASID_ASID_MASK; + uint16_t gid =3D to_guest ? ((info >> 16) & 0xff) : get_tgid(env); + + if (to_guest && env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + do_raise_exception(env, EXCCODE_IPE, GETPC()); + } + + to_guest |=3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; =20 for (int i =3D 0; i < LOONGARCH_TLB_MAX; i++) { - LoongArchTLB *tlb =3D &env->tlb[i]; + LoongArchTLB *tlb =3D &tlb_bank(env, to_guest)[i]; uint8_t tlb_g =3D FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); uint16_t tlb_asid =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); =20 - if (!tlb_g && (tlb_asid =3D=3D asid)) { + if (!tlb_g && tlb_asid =3D=3D asid && tlb_entry_matches_gid(tlb, g= id)) { tlb->tlb_misc =3D FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0); } } @@ -591,105 +647,159 @@ void helper_invtlb_all_asid(CPULoongArchState *env,= target_ulong info) } =20 void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info, - target_ulong addr) + target_ulong addr, uint32_t to_guest) { - int asid =3D info & 0x3ff; + uint16_t asid =3D info & R_CSR_ASID_ASID_MASK; + uint16_t gid =3D to_guest ? ((info >> 16) & 0xff) : get_tgid(env); LoongArchTLB *tlb; - tlb_match func; + int index; + + if (to_guest && env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + do_raise_exception(env, EXCCODE_IPE, GETPC()); + } + to_guest |=3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; =20 - func =3D tlb_match_asid; - tlb =3D loongarch_tlb_search_cb(env, addr, asid, func); + tlb =3D loongarch_tlb_search_cb(env, addr, asid, tlb_match_asid, + to_guest, gid); if (tlb) { - invalidate_tlb(env, tlb - env->tlb); + index =3D tlb - tlb_bank(env, to_guest); + invalidate_tlb(env, index, to_guest); } } =20 -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 inf= o, + target_ulong addr, uint32_t to_guest) { - int asid =3D info & 0x3ff; + uint16_t asid =3D info & R_CSR_ASID_ASID_MASK; + uint16_t gid =3D to_guest ? ((info >> 16) & 0xff) : get_tgid(env); LoongArchTLB *tlb; - tlb_match func; + int index; + + if (to_guest && env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + do_raise_exception(env, EXCCODE_IPE, GETPC()); + } + + to_guest |=3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; =20 - func =3D tlb_match_any; - tlb =3D loongarch_tlb_search_cb(env, addr, asid, func); + tlb =3D loongarch_tlb_search_cb(env, addr, asid, tlb_match_any, + to_guest, gid); if (tlb) { - invalidate_tlb(env, tlb - env->tlb); + index =3D tlb - tlb_bank(env, to_guest); + invalidate_tlb(env, index, to_guest); } } =20 -static void ptw_update_tlb(CPULoongArchState *env, MMUContext *context) +static void ptw_update_tlb(CPULoongArchState *env, MMUContext *context, + bool guest) { int index; =20 index =3D context->tlb_index; if (index < 0) { - index =3D get_tlb_random_index(env, context->addr, context->ps); + index =3D get_tlb_random_index(env, context->addr, context->ps, gu= est); } =20 - update_tlb_index(env, context, index); + update_tlb_index(env, context, index, guest); } =20 -bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) +TLBRet loongarch_map_host_address(CPULoongArchState *env, MMUContext *cont= ext, + MMUAccessType access_type, uintptr_t ret= addr) { - CPULoongArchState *env =3D cpu_env(cs); - hwaddr physical; - int prot; - MMUContext context; TLBRet ret; =20 - /* Data access */ - context.addr =3D address; - context.tlb_index =3D -1; - ret =3D get_physical_address(env, &context, access_type, mmu_idx, 0); - if (ret =3D=3D TLBRET_MATCH && context.mmu_index !=3D MMU_DA_IDX - && cpu_has_ptw(env)) { + ret =3D loongarch_map_address(env, context, access_type, MMU_KERNEL_ID= X, + false, false, retaddr); + 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 retadd= r) +{ + if ((*status =3D=3D TLBRET_MATCH || *status =3D=3D TLBRET_HOST_MATCH) = && + context->mmu_index !=3D MMU_DA_IDX && + context->mmu_index !=3D MMU_GUEST_DA_IDX && cpu_has_ptw(env, guest= )) { bool need_update =3D true; =20 - if (access_type =3D=3D MMU_DATA_STORE && pte_dirty(context.pte)) { + if (access_type =3D=3D MMU_DATA_STORE && pte_dirty(context->pte)) { need_update =3D false; - } else if (access_type !=3D MMU_DATA_STORE && pte_access(context.p= te)) { + } else if (access_type !=3D MMU_DATA_STORE && pte_access(context->= pte)) { need_update =3D 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() functio= n call - * for MMU_DATA_STORE access_type in future since QEMU TLB with - * prot PAGE_WRITE is added already - */ } =20 if (need_update) { - /* Need update bit A/D in PTE entry, take PTW again */ - ret =3D TLBRET_NOMATCH; + *status =3D (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST= && + !guest) ? + TLBRET_HOST_NOMATCH : TLBRET_NOMATCH; } } =20 - if (ret !=3D TLBRET_MATCH && cpu_has_ptw(env)) { - /* Take HW PTW if TLB missed or bit P is zero */ - if (ret =3D=3D TLBRET_NOMATCH || ret =3D=3D TLBRET_INVALID) { - ret =3D loongarch_ptw(env, &context, access_type, mmu_idx, 0); - if (ret =3D=3D TLBRET_MATCH) { - ptw_update_tlb(env, &context); + if (*status !=3D TLBRET_MATCH && *status !=3D TLBRET_HOST_MATCH && + cpu_has_ptw(env, guest)) { + if (*status =3D=3D TLBRET_NOMATCH || *status =3D=3D TLBRET_INVALID= || + *status =3D=3D TLBRET_HOST_NOMATCH || *status =3D=3D TLBRET_HO= ST_INVALID) { + *status =3D ((env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUES= T && + !guest) ? + TLBRET_HOST_MATCH : TLBRET_MATCH) + + loongarch_ptw(env, context, access_type, mmu_index, = 0, + guest, retaddr); + if (*status =3D=3D TLBRET_MATCH || *status =3D=3D TLBRET_HOST_= MATCH) { + ptw_update_tlb(env, context, guest); } - } else if (context.tlb_index >=3D 0) { - invalidate_tlb(env, context.tlb_index); + } else if (context->tlb_index >=3D 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) +{ + CPULoongArchState *env =3D cpu_env(cs); + bool guest =3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; + MMUContext host_context; + hwaddr physical; + int prot, host_prot; + MMUContext context; + TLBRet ret; + + /* Data access */ + context.addr =3D address; + context.tlb_index =3D -1; + ret =3D get_physical_address(env, &context, access_type, mmu_idx, 0, r= etaddr); + loongarch_try_ptw(env, &context, access_type, mmu_idx, &ret, guest, + retaddr); =20 if (ret =3D=3D TLBRET_MATCH) { physical =3D context.physical; prot =3D context.prot; + if (guest) { + host_context.addr =3D physical; + host_context.tlb_index =3D -1; + ret =3D 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 !=3D TLBRET_HOST_MATCH) { + if (probe) { + return false; + } + raise_mmu_exception(env, physical, access_type, ret); + cpu_loop_exit_restore(cs, retaddr); + return false; + } + physical =3D host_context.physical; + host_prot =3D host_context.prot; + prot &=3D 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=3D%" 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, @@ -718,6 +828,33 @@ static inline uint64_t loongarch_sanitize_hw_pte(CPULo= ongArchState *env, return (pte & ~ppn_mask) | ((pte & ppn_mask) & palen_mask); } =20 +hwaddr loongarch_get_host_address(CPULoongArchState *env, hwaddr gpa, + uintptr_t retaddr) +{ + MMUContext host_context; + TLBRet ret; + CPUTLBEntryFull *full; + int flags =3D 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 =3D gpa; + host_context.tlb_index =3D -1; + ret =3D 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 !=3D 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) { @@ -751,10 +888,16 @@ target_ulong helper_lddir(CPULoongArchState *env, tar= get_ulong base, =20 badvaddr =3D sys->CSR_TLBRBADV; base =3D 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) =3D=3D LOONGARCH_VM_LEVEL_GUEST); index =3D (badvaddr >> dir_base) & ((1 << dir_width) - 1); phys =3D base | index << 3; - val =3D address_space_ldq_le(cs->as, phys, MEMTXATTRS_UNSPECIFIED, NUL= L); + val =3D address_space_ldq_le( + cs->as, + env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST ? + loongarch_get_host_address(env, phys, GETPC()) : + phys, + MEMTXATTRS_UNSPECIFIED, NULL); =20 return val & palen_mask; } @@ -789,7 +932,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) =3D=3D LOONGARCH_VM_LEVEL_GUE= ST); =20 base =3D FIELD_DP64(base, TLBENTRY, LEVEL, 0); base =3D FIELD_DP64(base, TLBENTRY, HUGE, 0); @@ -823,8 +967,12 @@ void helper_ldpte(CPULoongArchState *env, target_ulong= base, target_ulong odd, ptoffset0 =3D ptindex << 3; ptoffset1 =3D (ptindex + 1) << 3; phys =3D base | (odd ? ptoffset1 : ptoffset0); - pte_raw =3D address_space_ldq_le(cs->as, phys, - MEMTXATTRS_UNSPECIFIED, NULL); + pte_raw =3D address_space_ldq_le( + cs->as, + env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST ? + loongarch_get_host_address(env, phys, GETPC()) : + phys, + MEMTXATTRS_UNSPECIFIED, NULL); tmp0 =3D loongarch_sanitize_hw_pte(env, pte_raw); ps =3D ptbase; } @@ -840,9 +988,9 @@ 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, bool guest) { - LoongArchTLB *tlb =3D &env->tlb[index]; + LoongArchTLB *tlb =3D &tlb_bank(env, guest)[index]; uint8_t tlb_ps, n; =20 tlb_ps =3D FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); @@ -850,19 +998,21 @@ static TLBRet loongarch_map_tlb_entry(CPULoongArchSta= te *env, context->pte =3D n ? tlb->tlb_entry1 : tlb->tlb_entry0; context->ps =3D tlb_ps; context->tlb_index =3D index; - return loongarch_check_pte(env, context, access_type, mmu_idx); + return loongarch_check_pte(env, context, access_type, mmu_idx, guest); } =20 TLBRet loongarch_get_addr_from_tlb(CPULoongArchState *env, MMUContext *context, - MMUAccessType access_type, int mmu_idx) + MMUAccessType access_type, int mmu_idx, + bool guest) { int index, match; =20 - match =3D loongarch_tlb_search(env, context->addr, &index); + match =3D loongarch_tlb_search(env, context->addr, &index, + guest, get_tgid(env)); if (match) { return loongarch_map_tlb_entry(env, context, access_type, index, - mmu_idx); + mmu_idx, guest); } =20 return TLBRET_NOMATCH; --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740371092881.4751269765006; Wed, 26 Aug 2026 03:32:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAun-00024Q-5I; Wed, 26 Aug 2026 06:31:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuR-0001wM-H0 for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:07 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuO-0003OC-2l for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:07 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 9CD02D069; Wed, 26 Aug 2026 16:01:01 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 11/14] target/loongarch: Translate LVZ guest CSR instructions Date: Wed, 26 Aug 2026 18:30:15 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740372140158500 Content-Type: text/plain; charset="utf-8" Decode and translate GCSRRD, GCSRWR and GCSRXCHG, and select the host or guest helper and CSR offset from one shared CSRInfo table. Guest execution of sensitive CSRs raises GSPR without writing an artificial value to the destination register. Host guest-CSR instructions reuse the ordinary CSR translation implementation. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/csr.c | 4 +- target/loongarch/csr.h | 4 +- target/loongarch/disas.c | 8 + target/loongarch/insns.decode | 6 + .../tcg/insn_trans/trans_privileged.c.inc | 218 ++++++++++++++---- target/loongarch/tcg/translate.c | 6 +- 6 files changed, 193 insertions(+), 53 deletions(-) diff --git a/target/loongarch/csr.c b/target/loongarch/csr.c index fa018a4582..928ffeb193 100644 --- a/target/loongarch/csr.c +++ b/target/loongarch/csr.c @@ -10,7 +10,9 @@ [LOONGARCH_CSR_##NAME] =3D { \ .name =3D (stringify(NAME)), \ .offset =3D CSR_OFFSET(CSR_##NAME), \ - .flags =3D FL, .readfn =3D RD, .writefn =3D WR \ + .flags =3D FL, \ + .readfn[LOONGARCH_VM_LEVEL_HOST] =3D RD, \ + .writefn[LOONGARCH_VM_LEVEL_HOST] =3D WR \ } =20 #define CSR_OFF_ARRAY_FLAGS(NAME, N, FL) \ diff --git a/target/loongarch/csr.h b/target/loongarch/csr.h index 647695e248..50f06a359f 100644 --- a/target/loongarch/csr.h +++ b/target/loongarch/csr.h @@ -28,8 +28,8 @@ typedef struct { const char *name; int offset; int flags; - GenCSRFunc readfn; - GenCSRFunc writefn; + GenCSRFunc readfn[LOONGARCH_VM_LEVELS]; + GenCSRFunc writefn[LOONGARCH_VM_LEVELS]; } CSRInfo; =20 CSRInfo *get_csr(unsigned int csr_num); diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 3249ab7ac6..59d6a55c78 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -51,6 +51,7 @@ static const char * const csr_names[] =3D { CSR_NAME(BADI), CSR_NAME(EENTRY), CSR_NAME(TLBIDX), + CSR_NAME(GTLBC), CSR_NAME(TLBEHI), CSR_NAME(TLBELO0), CSR_NAME(TLBELO1), @@ -87,6 +88,10 @@ static const char * const csr_names[] =3D { CSR_NAME(TVAL), CSR_NAME(CNTC), CSR_NAME(TICLR), + CSR_NAME(GSTAT), + CSR_NAME(GCFG), + CSR_NAME(GINTC), + CSR_NAME(GCNTC), CSR_NAME(LLBCTL), CSR_NAME(IMPCTL1), CSR_NAME(IMPCTL2), @@ -698,6 +703,9 @@ INSN(tlbfill, empty) INSN(tlbclr, empty) INSN(tlbflush, empty) INSN(invtlb, i_rr) +INSN(gcsrrd, r_csr) +INSN(gcsrwr, r_csr) +INSN(gcsrxchg, rr_csr) 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 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 } =20 +{ + 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/insn_trans/trans_privileged.c.inc b/targe= t/loongarch/tcg/insn_trans/trans_privileged.c.inc index abedb132b9..117f2c888c 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -39,6 +39,9 @@ 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) =20 #else =20 @@ -54,8 +57,8 @@ static bool check_plv(DisasContext *ctx) return false; } =20 -static bool set_csr_trans_func(unsigned int csr_num, GenCSRRead readfn, - GenCSRWrite writefn) +static bool set_csr_trans_func(unsigned int csr_num, int guest, + GenCSRRead readfn, GenCSRWrite writefn) { CSRInfo *csr; =20 @@ -64,13 +67,17 @@ static bool set_csr_trans_func(unsigned int csr_num, Ge= nCSRRead readfn, return false; } =20 - csr->readfn =3D (GenCSRFunc)readfn; - csr->writefn =3D (GenCSRFunc)writefn; + csr->readfn[guest] =3D (GenCSRFunc)readfn; + csr->writefn[guest] =3D (GenCSRFunc)writefn; return true; } =20 #define SET_CSR_FUNC(NAME, read, write) \ - set_csr_trans_func(LOONGARCH_CSR_##NAME, read, write) + set_csr_trans_func(LOONGARCH_CSR_##NAME, \ + LOONGARCH_VM_LEVEL_HOST, read, write) +#define SET_GCSR_FUNC(NAME, read, write) \ + set_csr_trans_func(LOONGARCH_CSR_##NAME, \ + LOONGARCH_VM_LEVEL_GUEST, read, write) =20 void loongarch_csr_translate_init(void) { @@ -85,12 +92,28 @@ 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); + + SET_GCSR_FUNC(STLBPS, NULL, gen_helper_gcsrwr_stlbps); + SET_GCSR_FUNC(ESTAT, NULL, gen_helper_gcsrwr_estat); + SET_GCSR_FUNC(ASID, NULL, gen_helper_gcsrwr_asid); + SET_GCSR_FUNC(PGD, gen_helper_gcsrrd_pgd, NULL); + SET_GCSR_FUNC(PWCL, NULL, gen_helper_gcsrwr_pwcl); + SET_GCSR_FUNC(PWCH, NULL, gen_helper_gcsrwr_pwch); + SET_GCSR_FUNC(TCFG, NULL, gen_helper_gcsrwr_tcfg); + SET_GCSR_FUNC(TVAL, gen_helper_gcsrrd_tval, NULL); + SET_GCSR_FUNC(TICLR, NULL, gen_helper_gcsrwr_ticlr); } #undef SET_CSR_FUNC +#undef SET_GCSR_FUNC =20 -static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool wr= ite) +static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, + int guest, bool write) { - if ((csr->flags & CSRFL_READONLY) && write) { + if ((guest =3D=3D LOONGARCH_VM_LEVEL_HOST || ctx->guest_mode) && + (csr->flags & CSRFL_READONLY) && write) { return false; } if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) { @@ -101,117 +124,214 @@ static bool check_csr_flags(DisasContext *ctx, cons= t CSRInfo *csr, bool write) return true; } =20 -static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) +static const CSRInfo *get_csr_for_level(unsigned int csr_num, int guest) +{ + const CSRInfo *csr =3D get_csr(csr_num); + + if (csr && guest =3D=3D LOONGARCH_VM_LEVEL_GUEST && + (csr->flags & CSRFL_GUEST_INVALID)) { + return NULL; + } + return csr; +} + +static bool trans_csrrd_impl(DisasContext *ctx, int rd, unsigned int csr_n= um, + int guest) { TCGv dest; const CSRInfo *csr; GenCSRRead readfn; - tcg_target_long offset; =20 - if (check_plv(ctx)) { - return false; - } - csr =3D get_csr(a->csr); + csr =3D get_csr_for_level(csr_num, guest); if (csr =3D=3D NULL) { /* CSR is undefined: read as 0. */ dest =3D tcg_constant_tl(0); } else { - check_csr_flags(ctx, csr, false); - dest =3D gpr_dst(ctx, a->rd, EXT_NONE); - readfn =3D (GenCSRRead)csr->readfn; - if (readfn) { - readfn(dest, tcg_env); + check_csr_flags(ctx, csr, guest, false); + if (guest =3D=3D LOONGARCH_VM_LEVEL_GUEST && + (csr->flags & CSRFL_GSPR)) { + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + return true; + } + dest =3D tcg_constant_tl(0); } else { - offset =3D get_csr_offset(csr, LOONGARCH_VM_LEVEL_HOST); - tcg_gen_ld_tl(dest, tcg_env, offset); + dest =3D gpr_dst(ctx, rd, EXT_NONE); + readfn =3D (GenCSRRead)csr->readfn[guest]; + if (readfn) { + readfn(dest, tcg_env); + } else { + tcg_gen_ld_tl(dest, tcg_env, + get_csr_offset(csr, guest)); + } } } - gen_set_gpr(a->rd, dest, EXT_NONE); + gen_set_gpr(rd, dest, EXT_NONE); return true; } =20 -static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) +static bool trans_csrwr_impl(DisasContext *ctx, int rd, unsigned int csr_n= um, + int guest) { TCGv dest, src1; const CSRInfo *csr; GenCSRWrite writefn; tcg_target_long offset; =20 - if (check_plv(ctx)) { - return false; - } - csr =3D get_csr(a->csr); + csr =3D get_csr_for_level(csr_num, guest); if (csr =3D=3D NULL) { /* CSR is undefined: write ignored, read old_value as 0. */ - gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + gen_set_gpr(rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + if (guest =3D=3D LOONGARCH_VM_LEVEL_GUEST && + (csr->flags & CSRFL_GSPR)) { + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + } else { + gen_set_gpr(rd, tcg_constant_tl(0), EXT_NONE); + } return true; } - if (!check_csr_flags(ctx, csr, true)) { + if (!check_csr_flags(ctx, csr, guest, true)) { /* CSR is readonly: trap. */ return false; } - src1 =3D gpr_src(ctx, a->rd, EXT_NONE); - writefn =3D (GenCSRWrite)csr->writefn; + src1 =3D gpr_src(ctx, rd, EXT_NONE); + writefn =3D (GenCSRWrite)csr->writefn[guest]; if (writefn) { - dest =3D gpr_dst(ctx, a->rd, EXT_NONE); + dest =3D gpr_dst(ctx, rd, EXT_NONE); writefn(dest, tcg_env, src1); } else { dest =3D tcg_temp_new(); - offset =3D get_csr_offset(csr, LOONGARCH_VM_LEVEL_HOST); + offset =3D get_csr_offset(csr, guest); tcg_gen_ld_tl(dest, tcg_env, offset); tcg_gen_st_tl(src1, tcg_env, offset); } - gen_set_gpr(a->rd, dest, EXT_NONE); + gen_set_gpr(rd, dest, EXT_NONE); return true; } =20 -static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) +static bool trans_csrxchg_impl(DisasContext *ctx, int rd, int rj, + unsigned int csr_num, int guest) { TCGv src1, mask, oldv, newv, temp; const CSRInfo *csr; GenCSRWrite writefn; tcg_target_long offset; =20 - if (check_plv(ctx)) { - return false; - } - csr =3D get_csr(a->csr); + csr =3D get_csr_for_level(csr_num, guest); if (csr =3D=3D NULL) { /* CSR is undefined: write ignored, read old_value as 0. */ - gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + gen_set_gpr(rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + if (guest =3D=3D LOONGARCH_VM_LEVEL_GUEST && + (csr->flags & CSRFL_GSPR)) { + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + } else { + gen_set_gpr(rd, tcg_constant_tl(0), EXT_NONE); + } return true; } =20 - if (!check_csr_flags(ctx, csr, true)) { + if (!check_csr_flags(ctx, csr, guest, true)) { /* CSR is readonly: trap. */ return false; } =20 - /* So far only readonly csrs have readfn. */ - assert(csr->readfn =3D=3D NULL); - - src1 =3D gpr_src(ctx, a->rd, EXT_NONE); - mask =3D gpr_src(ctx, a->rj, EXT_NONE); + src1 =3D gpr_src(ctx, rd, EXT_NONE); + mask =3D gpr_src(ctx, rj, EXT_NONE); oldv =3D tcg_temp_new(); newv =3D tcg_temp_new(); temp =3D tcg_temp_new(); + offset =3D get_csr_offset(csr, guest); =20 - offset =3D get_csr_offset(csr, LOONGARCH_VM_LEVEL_HOST); - tcg_gen_ld_tl(oldv, tcg_env, offset); + if (csr->readfn[guest]) { + GenCSRRead readfn =3D (GenCSRRead)csr->readfn[guest]; + readfn(oldv, tcg_env); + } else { + tcg_gen_ld_tl(oldv, tcg_env, offset); + } tcg_gen_and_tl(newv, src1, mask); tcg_gen_andc_tl(temp, oldv, mask); tcg_gen_or_tl(newv, newv, temp); =20 - writefn =3D (GenCSRWrite)csr->writefn; + writefn =3D (GenCSRWrite)csr->writefn[guest]; if (writefn) { writefn(oldv, tcg_env, newv); } else { tcg_gen_st_tl(newv, tcg_env, offset); } - gen_set_gpr(a->rd, oldv, EXT_NONE); + gen_set_gpr(rd, oldv, EXT_NONE); return true; } =20 +static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) +{ + if (check_plv(ctx)) { + return false; + } + return trans_csrrd_impl(ctx, a->rd, a->csr, ctx->guest_mode); +} + +static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) +{ + if (check_plv(ctx)) { + return false; + } + return trans_csrwr_impl(ctx, a->rd, a->csr, ctx->guest_mode); +} + +static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a) +{ + if (check_plv(ctx)) { + return false; + } + return trans_csrxchg_impl(ctx, a->rd, a->rj, a->csr, + ctx->guest_mode); +} + +static bool trans_gcsrrd(DisasContext *ctx, arg_gcsrrd *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx)) { + return false; + } + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + return true; + } + return trans_csrrd_impl(ctx, a->rd, a->csr, + LOONGARCH_VM_LEVEL_GUEST); +} + +static bool trans_gcsrwr(DisasContext *ctx, arg_gcsrwr *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx)) { + return false; + } + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + return true; + } + return trans_csrwr_impl(ctx, a->rd, a->csr, + LOONGARCH_VM_LEVEL_GUEST); +} + +static bool trans_gcsrxchg(DisasContext *ctx, arg_gcsrxchg *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx)) { + return false; + } + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + return true; + } + return trans_csrxchg_impl(ctx, a->rd, a->rj, a->csr, + LOONGARCH_VM_LEVEL_GUEST); +} + static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, void (*func)(TCGv, TCGv_ptr, TCGv)) { diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/transl= ate.c index 124dce6269..15c83ef72d 100644 --- a/target/loongarch/tcg/translate.c +++ b/target/loongarch/tcg/translate.c @@ -122,12 +122,16 @@ static void loongarch_tr_init_disas_context(DisasCont= extBase *dcbase, CPULoongArchState *env =3D cpu_env(cs); DisasContext *ctx =3D container_of(dcbase, DisasContext, base); =20 + ctx->guest_mode =3D (ctx->base.tb->flags & HW_FLAGS_GUEST_MODE) !=3D 0; ctx->page_start =3D ctx->base.pc_first & TARGET_PAGE_MASK; ctx->plv =3D ctx->base.tb->flags & HW_FLAGS_PLV_MASK; if (ctx->base.tb->flags & HW_FLAGS_CRMD_PG) { ctx->mem_idx =3D ctx->plv; + if (ctx->guest_mode) { + ctx->mem_idx +=3D MMU_GUEST_IDX; + } } else { - ctx->mem_idx =3D MMU_DA_IDX; + ctx->mem_idx =3D ctx->guest_mode ? MMU_GUEST_DA_IDX : MMU_DA_IDX; } =20 /* Bound the number of insns to execute to those left on the page. */ --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740323926588.9825244856873; Wed, 26 Aug 2026 03:32:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAur-000275-E7; Wed, 26 Aug 2026 06:31:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAuQ-0001wD-Lm for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:06 -0400 Received: from krgm.moe ([103.47.186.116]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuN-0003OE-W7 for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:06 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 5371B7A15; Wed, 26 Aug 2026 16:01:02 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 12/14] target/loongarch: Translate LVZ guest TLB instructions Date: Wed, 26 Aug 2026 18:30:16 +0800 Message-ID: <82b3c68f23fba6bc33620c4e510d658a358a9425.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=103.47.186.116; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 1 X-Spam_score: 0.1 X-Spam_bar: / X-Spam_report: (0.1 / 5.0 requ) BAYES_00=-1.9, DOS_RCVD_IP_TWICE_B=1.999, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740325820158500 Content-Type: text/plain; charset="utf-8" Decode, disassemble and translate GTLBSRCH, GTLBRD, GTLBWR, GTLBFILL, GTLBCLR and GTLBFLUSH for host LVZ execution. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- 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 59d6a55c78..54c35b8d03 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -706,6 +706,12 @@ INSN(invtlb, i_rr) INSN(gcsrrd, r_csr) INSN(gcsrwr, r_csr) INSN(gcsrxchg, rr_csr) +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 } =20 +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/targe= t/loongarch/tcg/insn_trans/trans_privileged.c.inc index 117f2c888c..fb6318b438 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) =20 #else =20 @@ -384,6 +390,15 @@ static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsr= ch *a) return true; } =20 +static bool trans_gtlbsrch(DisasContext *ctx, arg_gtlbsrch *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) { + 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,15 @@ static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *= a) return true; } =20 +static bool trans_gtlbrd(DisasContext *ctx, arg_gtlbrd *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) { + return false; + } + gen_helper_tlbrd(tcg_env, tcg_constant_i32(1)); + return true; +} + static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) { if (check_plv(ctx)) { @@ -403,6 +427,15 @@ static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *= a) return true; } =20 +static bool trans_gtlbwr(DisasContext *ctx, arg_gtlbwr *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) { + return false; + } + gen_helper_tlbwr(tcg_env, tcg_constant_i32(1)); + return true; +} + static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) { if (check_plv(ctx)) { @@ -413,6 +446,15 @@ static bool trans_tlbfill(DisasContext *ctx, arg_tlbfi= ll *a) return true; } =20 +static bool trans_gtlbfill(DisasContext *ctx, arg_gtlbfill *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) { + return false; + } + gen_helper_tlbfill(tcg_env, tcg_constant_i32(1)); + return true; +} + static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) { if (check_plv(ctx)) { @@ -423,6 +465,15 @@ static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr= *a) return true; } =20 +static bool trans_gtlbclr(DisasContext *ctx, arg_gtlbclr *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) { + return false; + } + gen_helper_tlbclr(tcg_env, tcg_constant_i32(1)); + return true; +} + static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) { if (check_plv(ctx)) { @@ -433,6 +484,15 @@ static bool trans_tlbflush(DisasContext *ctx, arg_tlbf= lush *a) return true; } =20 +static bool trans_gtlbflush(DisasContext *ctx, arg_gtlbflush *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) { + return false; + } + gen_helper_tlbflush(tcg_env, tcg_constant_i32(1)); + return true; +} + static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) { TCGv rj =3D gpr_src(ctx, a->rj, EXT_NONE); --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787740357832754.9353032068136; Wed, 26 Aug 2026 03:32:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAus-00027m-BO; Wed, 26 Aug 2026 06:31:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAua-00020x-80 for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:18 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuY-0003OT-Jy for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:16 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id 052AB7A17; Wed, 26 Aug 2026 16:01:02 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v4 13/14] target/loongarch: Translate LVZ guest traps and HVC Date: Wed, 26 Aug 2026 18:30:17 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740358019158500 Content-Type: text/plain; charset="utf-8" Raise GSPR when a guest accesses IOCSR, debug or idle resources, and decode HVC for guest PLV0. Use the common exception path so trapping instructions do not manufacture destination values or require a helper named after the exception cause. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/disas.c | 1 + target/loongarch/insns.decode | 1 + .../tcg/insn_trans/trans_privileged.c.inc | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 54c35b8d03..82b0bf868f 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -712,6 +712,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 =20 iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/targe= t/loongarch/tcg/insn_trans/trans_privileged.c.inc index fb6318b438..2dedcadfbb 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) =20 #else =20 @@ -347,6 +348,10 @@ static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, if (check_plv(ctx)) { return false; } + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + return true; + } func(dest, tcg_env, src1); return true; } @@ -360,6 +365,10 @@ static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, if (check_plv(ctx)) { return false; } + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + return true; + } func(tcg_env, addr, val); return true; } @@ -624,6 +633,10 @@ static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) if (check_plv(ctx)) { return false; } + if (ctx->guest_mode) { + generate_exception(ctx, EXCCODE_GSPR); + return true; + } generate_exception(ctx, EXCCODE_DBP); return true; } @@ -634,9 +647,28 @@ static bool trans_idle(DisasContext *ctx, arg_idle *a) return false; } =20 + if (ctx->guest_mode) { + 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 =3D DISAS_NORETURN; return true; } + +static bool trans_hvcl(DisasContext *ctx, arg_hvcl *a) +{ + if (!avail_LVZ(ctx) || !ctx->guest_mode) { + return false; + } + if (ctx->plv !=3D MMU_PLV_KERNEL) { + generate_exception(ctx, EXCCODE_IPE); + return true; + } + + generate_exception(ctx, EXCCODE_HVC); + return true; +} #endif --=20 2.55.0 From nobody Sat Sep 26 21:35:33 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=krgm.moe Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178774034382362.11247901268143; Wed, 26 Aug 2026 03:32:23 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAus-00027H-0N; Wed, 26 Aug 2026 06:31:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wzAua-000214-Mp for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:18 -0400 Received: from [2a14:640:1:12b5::1] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wzAuZ-0003Op-3O for qemu-devel@nongnu.org; Wed, 26 Aug 2026 06:31:16 -0400 Received: from yuno-loong (unknown [103.47.186.116]) by krgm.moe (Postfix) with ESMTPSA id AA5ABD0CE; Wed, 26 Aug 2026 16:01:03 +0530 (IST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , numpy1314 Subject: [PATCH v4 14/14] fix(tcg/loongarch): strip flag bits in lddir/ldpte address calculation Date: Wed, 26 Aug 2026 18:30:18 +0800 Message-ID: <372f72246c404586bc810e48862a650b39cc4866.1787739852.git.prcups@krgm.moe> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a14:640:1:12b5::1 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a14:640:1:12b5::1; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1787740346050158500 Content-Type: text/plain; charset="utf-8" helper_lddir and helper_ldpte used TARGET_PHYS_MASK (bits 0-47) when extracting the base address from a directory entry. This retained flag bits (V, D, PLV, MAT, etc.) at positions 0-11, which were then OR'd with the next-level index, producing a wrong physical address whenever the directory entry carried non-zero flags. Fix both helpers to extract only the PPN field (bits 12-47) before computing the address of the next-level page table entry. Signed-off-by: numpy1314 --- target/loongarch/tcg/tlb_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_h= elper.c index 776626072d..d75e20baf0 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -887,7 +887,10 @@ target_ulong helper_lddir(CPULoongArchState *env, targ= et_ulong base, } =20 badvaddr =3D sys->CSR_TLBRBADV; - base =3D base & palen_mask; + /* Extract only the PPN field (bits 12-47) from the directory entry. + * Flag bits (V, D, PLV, MAT, etc.) at positions 0-11 must not + * participate in the next-level address calculation. */ + base =3D (target_ulong)FIELD_EX64(base, TLBENTRY_64, PPN) << TARGET_PA= GE_BITS; get_dir_base_width(env, &dir_base, &dir_width, level, env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST); index =3D (badvaddr >> dir_base) & ((1 << dir_width) - 1); @@ -912,11 +915,9 @@ void helper_ldpte(CPULoongArchState *env, target_ulong= base, target_ulong odd, uint64_t badv; uint64_t ptbase =3D FIELD_EX64(sys->CSR_PWCL, CSR_PWCL, PTBASE); uint64_t ptwidth =3D FIELD_EX64(sys->CSR_PWCL, CSR_PWCL, PTWIDTH); - uint64_t palen_mask =3D loongarch_palen_mask(env); uint64_t dir_base, dir_width; uint8_t ps; =20 - /* * The parameter "base" has only two types, * one is the page table base address, @@ -959,9 +960,8 @@ void helper_ldpte(CPULoongArchState *env, target_ulong = base, target_ulong odd, } } else { badv =3D sys->CSR_TLBRBADV; - - base =3D base & palen_mask; - + /* Strip flag bits (0-11) from base before address calculation. */ + base =3D (target_ulong)FIELD_EX64(base, TLBENTRY_64, PPN) << TARGE= T_PAGE_BITS; ptindex =3D (badv >> ptbase) & ((1 << ptwidth) - 1); ptindex =3D ptindex & ~0x1; /* clear bit 0 */ ptoffset0 =3D ptindex << 3; --=20 2.55.0