From nobody Sun Jul 12 00:33:17 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 1783674125163591.6702930394637; Fri, 10 Jul 2026 02:02:05 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76U-00060H-Lr; Fri, 10 Jul 2026 05:01:02 -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 1wi76K-0005wq-7E for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:55 -0400 Received: from [2400:e920:0:e::2c] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76C-000487-SA for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:47 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id 1FDCE241FC90; Fri, 10 Jul 2026 17:00:35 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 1/8] target/loongarch: Define LVZ CSR fields Date: Fri, 10 Jul 2026 17:00:10 +0800 Message-ID: X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2400:e920:0:e::2c (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=2400:e920:0:e::2c; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674126943158500 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 --- target/loongarch/cpu-csr.h | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h index d860417af2..4b0bb4d2e5 100644 --- a/target/loongarch/cpu-csr.h +++ b/target/loongarch/cpu-csr.h @@ -180,11 +180,13 @@ FIELD(CSR_TLBREHI_64, VPPN, 13, 35) #define LOONGARCH_CSR_TLBRPRMD 0x8f /* TLB refill mode info */ FIELD(CSR_TLBRPRMD, PPLV, 0, 2) FIELD(CSR_TLBRPRMD, PIE, 2, 1) +FIELD(CSR_TLBRPRMD, PGM, 3, 1) FIELD(CSR_TLBRPRMD, PWE, 4, 1) =20 /* Machine Error CSRs */ #define LOONGARCH_CSR_MERRCTL 0x90 /* ERRCTL */ FIELD(CSR_MERRCTL, ISMERR, 0, 1) +FIELD(CSR_MERRCTL, PGM, 5, 1) #define LOONGARCH_CSR_MERRINFO1 0x91 #define LOONGARCH_CSR_MERRINFO2 0x92 #define LOONGARCH_CSR_MERRENTRY 0x93 /* MError exception base */ @@ -224,4 +226,44 @@ 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) + +#define LOONGARCH_CSR_TRGP 0x16 /* Trapped guest physical addres= s */ + #endif /* LOONGARCH_CPU_CSR_H */ --=20 2.52.0 From nobody Sun Jul 12 00:33:17 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 1783674080246214.76294170779897; Fri, 10 Jul 2026 02:01:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76U-000617-SU; Fri, 10 Jul 2026 05:01:02 -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 1wi76I-0005wY-Ot for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:51 -0400 Received: from [2400:e920:0:e::2c] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76C-000489-Ra for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:47 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id 07FE3241FC91; Fri, 10 Jul 2026 17:00:35 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 2/8] target/loongarch: Add LVZ CPU state definitions Date: Fri, 10 Jul 2026 17:00:11 +0800 Message-ID: X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2400:e920:0:e::2c (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=2400:e920:0:e::2c; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674083905158500 Content-Type: text/plain; charset="utf-8" Add VM level constants, guest MMU indices, guest exception and interrupt identifiers, GID storage in TLB entries, LVZ CPU property state, guest timer fields and helper declarations used by later runtime, memory translation and instruction translation patches. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu.h | 62 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index ad30c73167..c151287469 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,19 @@ 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; + uint64_t CSR_TRGP; /* 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 +414,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 +439,7 @@ typedef struct CPUArchState { uint32_t mp_state; #endif CPUSysState *sys_state; + bool vm_exit; } CPULoongArchState; =20 typedef struct LoongArchCPUTopo { @@ -438,8 +459,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,6 +507,24 @@ struct LoongArchCPUClass { #define MMU_KERNEL_IDX MMU_PLV_KERNEL #define MMU_USER_IDX MMU_PLV_USER #define MMU_DA_IDX 4 +#define MMU_GUEST_IDX 5 +#define MMU_GUEST_DA_IDX 9 + +static inline bool is_guest_mmu_idx(int mmu_idx) +{ + return mmu_idx >=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) { @@ -495,6 +536,18 @@ static inline void set_sys_state(CPULoongArchState *en= v, CPUSysState *sys) env->sys_state =3D sys; } =20 +static inline CPUSysState *sys_state_if(CPULoongArchState *env, bool guest) +{ + return &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST : + LOONGARCH_VM_LEVEL_HOST]; +} + +static inline int env_vm_level(CPULoongArchState *env) +{ + return env_sys(env) =3D=3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST] ? + LOONGARCH_VM_LEVEL_GUEST : LOONGARCH_VM_LEVEL_HOST; +} + static inline bool is_la64(CPULoongArchState *env) { return FIELD_EX32(env->cpucfg[1], CPUCFG1, ARCH) =3D=3D CPUCFG1_ARCH_L= A64; @@ -530,6 +583,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 --=20 2.52.0 From nobody Sun Jul 12 00:33:17 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 1783674066046723.657450757098; Fri, 10 Jul 2026 02:01:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76O-0005wl-3C; Fri, 10 Jul 2026 05:00:58 -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 1wi76F-0005wI-AL for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:48 -0400 Received: from [160.191.52.36] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76C-00048E-SR for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:46 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id 9C0D8241FC92; Fri, 10 Jul 2026 17:00:36 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 3/8] target/loongarch: Add LVZ translation context flags Date: Fri, 10 Jul 2026 17:00:12 +0800 Message-ID: <744687087d7285e66b293986c51724caaef55188.1783673526.git.prcups@krgm.moe> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 160.191.52.36 (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=160.191.52.36; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674070152158500 Content-Type: text/plain; charset="utf-8" Add the LVZ availability predicate, guest-mode translation context state and HW_FLAGS_GUEST_MODE translation block flag so later TCG patches can distinguish host and guest execution without mixing translator metadata with instruction behavior. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/translate.h | 2 ++ 1 file changed, 2 insertions(+) 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.52.0 From nobody Sun Jul 12 00:33:17 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 1783674118629706.7921039947262; Fri, 10 Jul 2026 02:01:58 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76W-00063r-Ju; Fri, 10 Jul 2026 05:01:04 -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 1wi76K-0005wr-On for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:55 -0400 Received: from [2400:e920:0:e::2c] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76C-00049H-VH for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:48 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id 88655241FC93; Fri, 10 Jul 2026 17:00:37 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 4/8] target/loongarch: Add LVZ guest CSR tables Date: Fri, 10 Jul 2026 17:00:13 +0800 Message-ID: <0bcc5d30b6495f266413e773a4c1bbe203ac0b68.1783673526.git.prcups@krgm.moe> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2400:e920:0:e::2c (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=2400:e920:0:e::2c; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674122211158500 Content-Type: text/plain; charset="utf-8" Add the guest CSR lookup table and get_gcsr() helper, mark guest read-only registers and guest sensitive privileged resources, and store host and guest CSRInfo offsets relative to CPULoongArchState so CSR access generation can select the host or guest table directly. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu.c | 2 +- target/loongarch/csr.c | 124 +++++++++++++++++- target/loongarch/csr.h | 12 +- .../tcg/insn_trans/trans_extra.c.inc | 2 +- .../tcg/insn_trans/trans_privileged.c.inc | 16 +-- 5 files changed, 133 insertions(+), 23 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index fb03424ffa..492b17e136 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -783,7 +783,7 @@ 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 + csr_info->offset; 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..ed9d25edf2 100644 --- a/target/loongarch/csr.c +++ b/target/loongarch/csr.c @@ -9,19 +9,34 @@ #define CSR_OFF_FUNCS(NAME, FL, RD, WR) \ [LOONGARCH_CSR_##NAME] =3D { \ .name =3D (stringify(NAME)), \ - .offset =3D CSR_OFFSET(CSR_##NAME), \ + .offset =3D CSR_OFFSET(CSR_##NAME, 0), \ .flags =3D FL, .readfn =3D RD, .writefn =3D WR \ } =20 #define CSR_OFF_ARRAY(NAME, N) \ [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 = \ + .offset =3D CSR_OFFSET(CSR_##NAME[N], 0), \ + .flags =3D CSRFL_BASIC, .readfn =3D NULL, .writefn =3D NULL \ } =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 GCSR_OFF_FUNCS(NAME, FL, RD, WR) \ + [LOONGARCH_CSR_##NAME] =3D { \ + .name =3D (stringify(GCSR_##NAME)), \ + .offset =3D CSR_OFFSET(CSR_##NAME, 1), \ + .flags =3D FL, .readfn =3D RD, .writefn =3D WR \ + } +#define GCSR_OFF_ARRAY(NAME, N) \ + [LOONGARCH_CSR_##NAME(N)] =3D { \ + .name =3D (stringify(GCSR_##NAME##N)), \ + .offset =3D CSR_OFFSET(CSR_##NAME[N], 1), \ + .flags =3D CSRFL_BASIC, .readfn =3D NULL, .writefn =3D NULL \ + } +#define GCSR_OFF_FLAGS(NAME, FL) GCSR_OFF_FUNCS(NAME, FL, NULL, NULL) +#define GCSR_OFF(NAME) GCSR_OFF_FLAGS(NAME, CSRFL_BASIC) +#define GCSR_GSPR(NAME) GCSR_OFF_FLAGS(NAME, CSRFL_GSPR) =20 static CSRInfo csr_info[] =3D { CSR_OFF_FLAGS(CRMD, CSRFL_EXITTB), @@ -35,6 +50,8 @@ static CSRInfo csr_info[] =3D { CSR_OFF_FLAGS(BADI, CSRFL_READONLY), CSR_OFF(EENTRY), CSR_OFF(TLBIDX), + CSR_OFF(GTLBC), + CSR_OFF(TRGP), CSR_OFF(TLBEHI), CSR_OFF(TLBELO0), CSR_OFF(TLBELO1), @@ -71,6 +88,10 @@ static CSRInfo csr_info[] =3D { CSR_OFF_FLAGS(TVAL, CSRFL_READONLY | CSRFL_IO), CSR_OFF(CNTC), CSR_OFF_FLAGS(TICLR, CSRFL_IO), + CSR_OFF(GSTAT), + CSR_OFF(GCFG), + CSR_OFF_FLAGS(GINTC, CSRFL_IO), + CSR_OFF(GCNTC), CSR_OFF(LLBCTL), CSR_OFF(IMPCTL1), CSR_OFF(IMPCTL2), @@ -135,6 +156,87 @@ static CSRInfo csr_info[] =3D { CSR_OFF(MSGIR), }; =20 +static CSRInfo gcsr_info[] =3D { + GCSR_OFF_FLAGS(CRMD, CSRFL_EXITTB), + GCSR_OFF(PRMD), + GCSR_OFF_FLAGS(EUEN, CSRFL_EXITTB), + GCSR_OFF_FLAGS(MISC, CSRFL_GUEST_READONLY), + GCSR_OFF(ECFG), + GCSR_OFF_FLAGS(ESTAT, CSRFL_EXITTB), + GCSR_OFF(ERA), + GCSR_OFF(BADV), + GCSR_OFF_FLAGS(BADI, CSRFL_GUEST_READONLY), + GCSR_OFF(EENTRY), + GCSR_OFF(TLBIDX), + GCSR_GSPR(GTLBC), + GCSR_GSPR(TRGP), + GCSR_OFF(TLBEHI), + GCSR_OFF(TLBELO0), + GCSR_OFF(TLBELO1), + GCSR_OFF_FLAGS(ASID, CSRFL_EXITTB), + GCSR_OFF(PGDL), + GCSR_OFF(PGDH), + GCSR_OFF_FLAGS(PGD, CSRFL_GUEST_READONLY), + GCSR_OFF(PWCL), + GCSR_OFF(PWCH), + GCSR_OFF(STLBPS), + GCSR_OFF(RVACFG), + GCSR_OFF_FLAGS(CPUID, CSRFL_GUEST_READONLY), + GCSR_OFF_FLAGS(PRCFG1, CSRFL_GUEST_READONLY), + GCSR_OFF_FLAGS(PRCFG2, CSRFL_GUEST_READONLY), + GCSR_OFF_FLAGS(PRCFG3, CSRFL_GUEST_READONLY), + GCSR_OFF_ARRAY(SAVE, 0), + GCSR_OFF_ARRAY(SAVE, 1), + GCSR_OFF_ARRAY(SAVE, 2), + GCSR_OFF_ARRAY(SAVE, 3), + GCSR_OFF_ARRAY(SAVE, 4), + GCSR_OFF_ARRAY(SAVE, 5), + GCSR_OFF_ARRAY(SAVE, 6), + GCSR_OFF_ARRAY(SAVE, 7), + GCSR_OFF_ARRAY(SAVE, 8), + GCSR_OFF_ARRAY(SAVE, 9), + GCSR_OFF_ARRAY(SAVE, 10), + GCSR_OFF_ARRAY(SAVE, 11), + GCSR_OFF_ARRAY(SAVE, 12), + GCSR_OFF_ARRAY(SAVE, 13), + GCSR_OFF_ARRAY(SAVE, 14), + GCSR_OFF_ARRAY(SAVE, 15), + GCSR_OFF(TID), + GCSR_OFF_FLAGS(TCFG, CSRFL_IO), + GCSR_OFF_FLAGS(TVAL, CSRFL_GUEST_READONLY | CSRFL_IO), + GCSR_OFF(CNTC), + GCSR_OFF_FLAGS(TICLR, CSRFL_IO), + GCSR_GSPR(GSTAT), + GCSR_GSPR(GCFG), + GCSR_GSPR(GINTC), + GCSR_GSPR(GCNTC), + GCSR_OFF(LLBCTL), + GCSR_GSPR(IMPCTL1), + GCSR_GSPR(IMPCTL2), + GCSR_OFF(TLBRENTRY), + GCSR_OFF(TLBRBADV), + GCSR_OFF(TLBRERA), + GCSR_OFF(TLBRSAVE), + GCSR_OFF(TLBRELO0), + GCSR_OFF(TLBRELO1), + GCSR_OFF(TLBREHI), + GCSR_OFF(TLBRPRMD), + GCSR_GSPR(MERRCTL), + GCSR_GSPR(MERRINFO1), + GCSR_GSPR(MERRINFO2), + GCSR_GSPR(MERRENTRY), + GCSR_GSPR(MERRERA), + GCSR_GSPR(MERRSAVE), + GCSR_GSPR(CTAG), + GCSR_OFF_ARRAY(DMW, 0), + GCSR_OFF_ARRAY(DMW, 1), + GCSR_OFF_ARRAY(DMW, 2), + GCSR_OFF_ARRAY(DMW, 3), + GCSR_GSPR(DBG), + GCSR_GSPR(DERA), + GCSR_GSPR(DSAVE), +}; + CSRInfo *get_csr(unsigned int csr_num) { CSRInfo *csr; @@ -151,6 +253,22 @@ CSRInfo *get_csr(unsigned int csr_num) return csr; } =20 +CSRInfo *get_gcsr(unsigned int csr_num) +{ + CSRInfo *csr; + + if (csr_num >=3D ARRAY_SIZE(gcsr_info)) { + return NULL; + } + + csr =3D &gcsr_info[csr_num]; + if (csr->flags =3D=3D 0) { + return NULL; + } + + return csr; +} + bool set_csr_flag(unsigned int csr_num, int flag) { CSRInfo *csr; diff --git a/target/loongarch/csr.h b/target/loongarch/csr.h index c2b6b882bc..c39230f30c 100644 --- a/target/loongarch/csr.h +++ b/target/loongarch/csr.h @@ -8,10 +8,9 @@ =20 #include "cpu-csr.h" =20 -#define CSR_OFFSET(id) offsetof(CPUSysState, id) -#define CPU_CSR_OFFSET(id, vm_level) \ +#define CSR_OFFSET(id, vm_level) \ (offsetof(CPULoongArchState, sys_states[vm_level]) \ - + CSR_OFFSET(id)) + + offsetof(CPUSysState, id)) =20 typedef void (*GenCSRFunc)(void); enum { @@ -20,6 +19,8 @@ enum { CSRFL_IO =3D (1 << 2), CSRFL_UNUSED =3D (1 << 3), CSRFL_BASIC =3D (1 << 4), + CSRFL_GUEST_READONLY =3D (1 << 5), + CSRFL_GSPR =3D (1 << 6), }; =20 typedef struct { @@ -31,9 +32,6 @@ typedef struct { } CSRInfo; =20 CSRInfo *get_csr(unsigned int csr_num); +CSRInfo *get_gcsr(unsigned int csr_num); bool set_csr_flag(unsigned int csr_num, int flag); -static inline unsigned int get_csr_offset(const CSRInfo *csr, int vm_level) -{ - return csr->offset + offsetof(CPULoongArchState, sys_states[vm_level]); -} #endif /* TARGET_LOONGARCH_CSR_H */ 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..5a404632f5 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 CSR_OFFSET(CSR_TID, 0); 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..2094d182ac 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -106,7 +106,6 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) TCGv dest; const CSRInfo *csr; GenCSRRead readfn; - tcg_target_long offset; =20 if (check_plv(ctx)) { return false; @@ -122,8 +121,7 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a) if (readfn) { readfn(dest, tcg_env); } else { - offset =3D get_csr_offset(csr, 0); - tcg_gen_ld_tl(dest, tcg_env, offset); + tcg_gen_ld_tl(dest, tcg_env, csr->offset); } } gen_set_gpr(a->rd, dest, EXT_NONE); @@ -135,7 +133,6 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a) TCGv dest, src1; const CSRInfo *csr; GenCSRWrite writefn; - tcg_target_long offset; =20 if (check_plv(ctx)) { return false; @@ -157,9 +154,8 @@ 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); - tcg_gen_ld_tl(dest, tcg_env, offset); - tcg_gen_st_tl(src1, tcg_env, offset); + tcg_gen_ld_tl(dest, tcg_env, csr->offset); + tcg_gen_st_tl(src1, tcg_env, csr->offset); } gen_set_gpr(a->rd, dest, EXT_NONE); return true; @@ -170,7 +166,6 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxch= g *a) TCGv src1, mask, oldv, newv, temp; const CSRInfo *csr; GenCSRWrite writefn; - tcg_target_long offset; =20 if (check_plv(ctx)) { return false; @@ -196,8 +191,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); - tcg_gen_ld_tl(oldv, tcg_env, offset); + tcg_gen_ld_tl(oldv, tcg_env, csr->offset); tcg_gen_and_tl(newv, src1, mask); tcg_gen_andc_tl(temp, oldv, mask); tcg_gen_or_tl(newv, newv, temp); @@ -206,7 +200,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxch= g *a) if (writefn) { writefn(oldv, tcg_env, newv); } else { - tcg_gen_st_tl(newv, tcg_env, offset); + tcg_gen_st_tl(newv, tcg_env, csr->offset); } gen_set_gpr(a->rd, oldv, EXT_NONE); return true; --=20 2.52.0 From nobody Sun Jul 12 00:33:17 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 17836741950601006.6036461260596; Fri, 10 Jul 2026 02:03:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76X-00066E-GV; Fri, 10 Jul 2026 05:01:05 -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 1wi76M-0005x9-Ty for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:55 -0400 Received: from [160.191.52.36] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76J-0004Bf-1h for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:54 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id 16EE3241FC94; Fri, 10 Jul 2026 17:00:39 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 5/8] target/loongarch: Dump host CSRs with LVZ state Date: Fri, 10 Jul 2026 17:00:14 +0800 Message-ID: <647e3a352d4b0fc41e983d674ab599898275cd07.1783673526.git.prcups@krgm.moe> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 160.191.52.36 (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=160.191.52.36; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674195241158500 Content-Type: text/plain; charset="utf-8" Update LoongArch ELF note generation to read ERA and BADV from the host CSR bank directly, avoiding dependence on the currently selected system state once LVZ adds a separate guest CSR bank. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/arch_dump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/loongarch/arch_dump.c b/target/loongarch/arch_dump.c index 9d84faef96..13472188ae 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 &env->sys_states[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; --=20 2.52.0 From nobody Sun Jul 12 00:33:17 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 1783674179750113.86587193296964; Fri, 10 Jul 2026 02:02:59 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76X-000662-B3; Fri, 10 Jul 2026 05:01:05 -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 1wi76S-00060L-92 for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:01:02 -0400 Received: from [160.191.52.36] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76H-0004Be-HO for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:00:55 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id AC25B241FC95; Fri, 10 Jul 2026 17:00:39 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 6/8] target/loongarch: Add LVZ CPU runtime control Date: Fri, 10 Jul 2026 17:00:15 +0800 Message-ID: <6b2c0a4b5a78df100ea7e36bfa8cfd31e1d6eeb6.1783673526.git.prcups@krgm.moe> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 160.191.52.36 (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=160.191.52.36; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674181846158500 Content-Type: text/plain; charset="utf-8" Wire the LVZ CPU property, VM entry bookkeeping, VM exit trigger, guest interrupt delivery, guest constant timer support and guest CSR helpers into the LoongArch TCG runtime, leaving memory translation and PTW changes for a separate patch. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/cpu.c | 277 +++++++++++++++++++------- target/loongarch/internals.h | 8 +- target/loongarch/machine.c | 125 +++++++++++- target/loongarch/tcg/constant_timer.c | 74 ++++++- target/loongarch/tcg/csr_helper.c | 136 ++++++++++++- target/loongarch/tcg/helper.h | 13 +- target/loongarch/tcg/op_helper.c | 45 ++++- target/loongarch/tcg/tcg_cpu.c | 65 ++++-- 8 files changed, 641 insertions(+), 102 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 492b17e136..093b2a057f 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -62,17 +62,22 @@ void loongarch_cpu_set_irq(void *opaque, int irq, int l= evel) LoongArchCPU *cpu =3D opaque; CPULoongArchState *env =3D &cpu->env; CPUState *cs =3D CPU(cpu); - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; =20 if (irq < 0 || irq >=3D N_IRQS) { return; } =20 + if (FIELD_EX64(host->CSR_GINTC, CSR_GINTC, HWIP) & BIT(irq)) { + loongarch_cpu_set_irq_guest(opaque, irq, level); + return; + } + if (kvm_enabled()) { kvm_loongarch_set_interrupt(cpu, irq, level); } else if (tcg_enabled()) { - sys->CSR_ESTAT =3D deposit64(sys->CSR_ESTAT, irq, 1, level !=3D 0); - if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) { + host->CSR_ESTAT =3D deposit64(host->CSR_ESTAT, irq, 1, level !=3D = 0); + if (FIELD_EX64(host->CSR_ESTAT, CSR_ESTAT, IS)) { cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); @@ -80,18 +85,66 @@ void loongarch_cpu_set_irq(void *opaque, int irq, int l= evel) } } =20 +void loongarch_cpu_set_irq_guest(void *opaque, int irq, int level) +{ + LoongArchCPU *cpu =3D opaque; + CPULoongArchState *env =3D &cpu->env; + CPUState *cs =3D CPU(cpu); + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + + if (irq < 0 || irq >=3D N_IRQS) { + return; + } + + guest->CSR_ESTAT =3D deposit64(guest->CSR_ESTAT, irq, 1, level !=3D 0); + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + if (FIELD_EX64(guest->CSR_ESTAT, CSR_ESTAT, IS)) { + cpu_interrupt(cs, CPU_INTERRUPT_GUEST); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_GUEST); + } + } +} + /* Check if there is pending and not masked out interrupt */ bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env) { uint32_t pending; uint32_t status; - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; =20 - pending =3D FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS); - status =3D FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, LIE); + pending =3D FIELD_EX64(host->CSR_ESTAT, CSR_ESTAT, IS); + status =3D FIELD_EX64(host->CSR_ECFG, CSR_ECFG, LIE); =20 return (pending & status) !=3D 0; } + +static inline bool cpu_loongarch_hw_interrupts_enabled_guest( + CPULoongArchState *env) +{ + return FIELD_EX64(env->sys_states[LOONGARCH_VM_LEVEL_GUEST].CSR_CRMD, + CSR_CRMD, IE); +} + +static inline bool cpu_loongarch_hw_interrupts_pending_guest( + CPULoongArchState *env) +{ + uint32_t pending; + uint32_t status; + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + + pending =3D FIELD_EX64(guest->CSR_ESTAT, CSR_ESTAT, IS); + status =3D FIELD_EX64(guest->CSR_ECFG, CSR_ECFG, LIE); + + return (pending & status) !=3D 0; +} + +bool loongarch_guest_has_interrupt(CPULoongArchState *env) +{ + return env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST && + cpu_loongarch_hw_interrupts_enabled_guest(env) && + cpu_loongarch_hw_interrupts_pending_guest(env); +} #endif =20 #ifndef CONFIG_USER_ONLY @@ -104,22 +157,77 @@ bool loongarch_cpu_has_work(CPUState *cs) has_work =3D true; } =20 + if (cpu_test_interrupt(cs, CPU_INTERRUPT_GUEST) && + loongarch_guest_has_interrupt(cpu_env(cs))) { + has_work =3D true; + } + return has_work; } #endif /* !CONFIG_USER_ONLY */ =20 +uint8_t get_tgid(CPULoongArchState *env) +{ + CPUSysState *host =3D &env->sys_states[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(env->sys_states[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(env->sys_states[LOONGARCH_VM_LEVEL_HOST].CSR_GSTAT, + CSR_GSTAT, GID); +} + +void trigger_vm_exit(CPULoongArchState *env) +{ + CPUSysState *host =3D &env->sys_states[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 static bool initialized; LoongArchCPU *cpu =3D LOONGARCH_CPU(dev); CPULoongArchState *env =3D &cpu->env; - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[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 +359,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 +396,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,11 +409,11 @@ static void loongarch_la464_initfn(Object *obj) { LoongArchCPU *cpu =3D LOONGARCH_CPU(obj); CPULoongArchState *env =3D &cpu->env; - CPUSysState *sys; + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; uint32_t data =3D 0, field; int i; =20 - set_sys_state(env, &env->sys_states[0]); for (i =3D 0; i < 21; i++) { env->cpucfg[i] =3D 0x0; } @@ -322,6 +453,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 +519,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; @@ -412,7 +545,6 @@ static void loongarch_la132_initfn(Object *obj) uint32_t data =3D 0; int i; =20 - set_sys_state(env, &env->sys_states[0]); for (i =3D 0; i < 21; i++) { env->cpucfg[i] =3D 0x0; } @@ -439,6 +571,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 @@ -596,11 +729,10 @@ static void loongarch_host_initfn(Object *obj) =20 static void loongarch_cpu_reset_hold(Object *obj, ResetType type) { - uint8_t tlb_ps; 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 &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; =20 if (lacc->parent_phases.hold) { lacc->parent_phases.hold(obj, type); @@ -622,63 +754,72 @@ static void loongarch_cpu_reset_hold(Object *obj, Res= etType type) #endif env->fcsr0 =3D 0x0; =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; + host->CSR_TRGP =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); - 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); + uint8_t 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 (int n =3D 0; n < 4; n++) { + 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); + } + set_sys_state(env, &env->sys_states[LOONGARCH_VM_LEVEL_HOST]); =20 #ifndef CONFIG_USER_ONLY env->pc =3D 0x1c000000; -#ifdef CONFIG_TCG - memset(env->tlb, 0, sizeof(env->tlb)); +#if defined(CONFIG_TCG) + memset(host->tlb, 0, sizeof(host->tlb)); #endif if (kvm_enabled()) { kvm_arch_reset_vcpu(cs); @@ -739,6 +880,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 e01dbed40f..8a06ab9868 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -32,14 +32,18 @@ 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_guest(void *opaque, int irq, int level); =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 loongarch_guest_has_interrupt(CPULoongArchState *env); #endif /* !CONFIG_USER_ONLY */ =20 uint64_t read_fcc(CPULoongArchState *env); diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c index 931a5ca5ba..f10101d501 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,139 @@ 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_UINT64(CSR_TRGP, 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_UINT64(env.sys_states[0].CSR_TRGP, 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 + +static int loongarch_cpu_post_load(void *opaque, int version_id) +{ + LoongArchCPU *cpu =3D opaque; + CPULoongArchState *env =3D &cpu->env; + bool guest =3D FIELD_EX64(env->sys_states[LOONGARCH_VM_LEVEL_HOST].CSR= _GSTAT, + CSR_GSTAT, VM); + + set_sys_state(env, &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST : + LOONGARCH_VM_LEVEL_HOST]); +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) + if (guest) { + cpu_loongarch_set_guest_timer(cpu, true); + } + if (guest && loongarch_guest_has_interrupt(env)) { + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_GUEST); + } else { + cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_GUEST); + } #endif + return 0; +} =20 /* 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 +407,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, diff --git a/target/loongarch/tcg/constant_timer.c b/target/loongarch/tcg/c= onstant_timer.c index f56e76d482..4d7d4bccbc 100644 --- a/target/loongarch/tcg/constant_timer.c +++ b/target/loongarch/tcg/constant_timer.c @@ -20,30 +20,64 @@ 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 sys_state_if(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 sys_state_if(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(timer); + } +} + +void cpu_loongarch_set_guest_timer(LoongArchCPU *cpu, bool on) +{ + CPULoongArchState *env =3D &cpu->env; + CPUSysState *guest =3D &env->sys_states[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 { - timer_del(&cpu->timer); + guest->CSR_TVAL =3D cpu_loongarch_get_constant_timer_ticks(cpu, tr= ue); + timer_del(&cpu->guest_timer); } } =20 @@ -51,16 +85,36 @@ void loongarch_constant_timer_cb(void *opaque) { LoongArchCPU *cpu =3D opaque; CPULoongArchState *env =3D &cpu->env; - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; uint64_t now, next; =20 - if (FIELD_EX64(sys->CSR_TCFG, CSR_TCFG, PERIODIC)) { + if (FIELD_EX64(host->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; + next =3D now + (host->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * + TIMER_PERIOD; timer_mod(&cpu->timer, next); } else { - sys->CSR_TCFG =3D FIELD_DP64(sys->CSR_TCFG, CSR_TCFG, EN, 0); + host->CSR_TCFG =3D FIELD_DP64(host->CSR_TCFG, CSR_TCFG, EN, 0); } =20 loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); } + +void loongarch_constant_timer_cb_guest(void *opaque) +{ + LoongArchCPU *cpu =3D opaque; + CPULoongArchState *env =3D &cpu->env; + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + uint64_t now, next; + + if (FIELD_EX64(guest->CSR_TCFG, CSR_TCFG, PERIODIC)) { + now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + next =3D now + (guest->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * + TIMER_PERIOD; + timer_mod(&cpu->guest_timer, next); + } else { + guest->CSR_TCFG =3D FIELD_DP64(guest->CSR_TCFG, CSR_TCFG, EN, 0); + } + + loongarch_cpu_set_irq_guest(opaque, IRQ_TIMER, 1); +} diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_h= elper.c index 7dc33bc180..9ddb43222a 100644 --- a/target/loongarch/tcg/csr_helper.c +++ b/target/loongarch/tcg/csr_helper.c @@ -60,6 +60,26 @@ target_ulong helper_csrrd_pgd(CPULoongArchState *env) return v; } =20 +target_ulong helper_gcsrrd_pgd(CPULoongArchState *env) +{ + int64_t v; + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + + if (guest->CSR_TLBRERA & 0x1) { + v =3D guest->CSR_TLBRBADV; + } else { + v =3D guest->CSR_BADV; + } + + if ((v >> 63) & 0x1) { + v =3D guest->CSR_PGDH; + } else { + v =3D guest->CSR_PGDL; + } + + return v; +} + target_ulong helper_csrrd_cpuid(CPULoongArchState *env) { LoongArchCPU *lac =3D env_archcpu(env); @@ -74,7 +94,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) @@ -110,6 +137,29 @@ target_ulong helper_csrwr_estat(CPULoongArchState *env= , target_ulong val) return old_v; } =20 +target_ulong helper_gcsrwr_estat(CPULoongArchState *env, target_ulong val) +{ + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + int64_t old_v =3D guest->CSR_ESTAT; + + guest->CSR_ESTAT =3D deposit64(guest->CSR_ESTAT, 0, 2, val); + if (env_vm_level(env) !=3D LOONGARCH_VM_LEVEL_GUEST) { + guest->CSR_ESTAT =3D deposit64(guest->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)); + } + guest->CSR_ESTAT =3D deposit64(guest->CSR_ESTAT, 16, 15, + extract64(val, 16, 15)); + } + + return old_v; +} + target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) { CPUSysState *sys =3D env_sys(env); @@ -123,13 +173,36 @@ target_ulong helper_csrwr_asid(CPULoongArchState *env= , target_ulong val) return old_v; } =20 +target_ulong helper_gcsrwr_asid(CPULoongArchState *env, target_ulong val) +{ + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + int64_t old_v =3D guest->CSR_ASID; + + guest->CSR_ASID =3D deposit64(guest->CSR_ASID, 0, 10, val); + if (old_v !=3D guest->CSR_ASID) { + tlb_flush(env_cpu(env)); + } + return old_v; +} + target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) { LoongArchCPU *cpu =3D env_archcpu(env); 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 &env->sys_states[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; } @@ -147,6 +220,65 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env= , target_ulong val) return old_v; } =20 +target_ulong helper_gcsrwr_ticlr(CPULoongArchState *env, target_ulong val) +{ + LoongArchCPU *cpu =3D env_archcpu(env); + int64_t old_v =3D 0; + + if (val & 0x1) { + bql_lock(); + loongarch_cpu_set_irq_guest(cpu, IRQ_TIMER, 0); + bql_unlock(); + } + return old_v; +} + +target_ulong helper_csrwr_gstat(CPULoongArchState *env, target_ulong val) +{ + CPUSysState *host =3D &env->sys_states[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 &env->sys_states[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) +{ + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + int64_t old_v =3D host->CSR_GINTC; + + host->CSR_GINTC =3D val & 0xffff00; + guest->CSR_ESTAT =3D deposit64(guest->CSR_ESTAT, 2, 8, extract64(val, = 0, 8)); + + return old_v; +} + target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val) { uint8_t shift, ptbase; diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h index 8a6c62f116..69f6cb352a 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) @@ -98,14 +98,23 @@ 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(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(csrwr_pwch, i64, env, tl) DEF_HELPER_2(iocsrrd_b, i64, env, tl) @@ -134,6 +143,8 @@ DEF_HELPER_4(lddir, tl, env, tl, i32, i32) DEF_HELPER_4(ldpte, void, env, tl, tl, i32) DEF_HELPER_1(ertn, void, env) DEF_HELPER_1(idle, void, env) +DEF_HELPER_2(hvcl, void, env, i32) +DEF_HELPER_1(gspr, void, env) #endif =20 /* LoongArch LSX */ diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_hel= per.c index e63ac66daa..2829929738 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" @@ -46,20 +47,20 @@ target_ulong helper_bitswap(target_ulong v) /* loongarch assert op */ void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong= rk) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; =20 if (rj > rk) { - sys->CSR_BADV =3D rj; + host->CSR_BADV =3D rj; do_raise_exception(env, EXCCODE_BCE, GETPC()); } } =20 void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong= rk) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; =20 if (rj <=3D rk) { - sys->CSR_BADV =3D rj; + host->CSR_BADV =3D rj; do_raise_exception(env, EXCCODE_BCE, GETPC()); } } @@ -85,6 +86,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 +116,7 @@ void helper_ertn(CPULoongArchState *env) { uint64_t csr_pplv, csr_pie; CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; =20 if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { csr_pplv =3D FIELD_EX64(sys->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV); @@ -134,6 +140,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_state(env, &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]); + cpu_loongarch_set_guest_timer(env_archcpu(env), true); + bql_lock(); + if (loongarch_guest_has_interrupt(env)) { + 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) @@ -143,4 +161,23 @@ void helper_idle(CPULoongArchState *env) cs->halted =3D 1; do_raise_exception(env, EXCP_HLT, 0); } + +void helper_hvcl(CPULoongArchState *env, uint32_t code) +{ + (void)code; + + if (env_vm_level(env) !=3D LOONGARCH_VM_LEVEL_GUEST) { + do_raise_exception(env, EXCCODE_INE, GETPC()); + return; + } + + trigger_vm_exit(env); + do_raise_exception(env, EXCCODE_HVC, GETPC()); +} + +void helper_gspr(CPULoongArchState *env) +{ + trigger_vm_exit(env); + do_raise_exception(env, EXCCODE_GSPR, GETPC()); +} #endif diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c index 4b1d44a164..594daa74b2 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 &env->sys_states[real_guest]; + CPUSysState *host =3D &env->sys_states[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_state(env, &env->sys_states[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 &env->sys_states[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 { @@ -241,26 +257,35 @@ static void loongarch_cpu_do_transaction_failed(CPUSt= ate *cs, hwaddr physaddr, static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *= env) { bool ret =3D 0; - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[LOONGARCH_VM_LEVEL_HOST]; =20 - ret =3D (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, IE) && - !(FIELD_EX64(sys->CSR_DBG, CSR_DBG, DST))); + ret =3D (FIELD_EX64(host->CSR_CRMD, CSR_CRMD, IE) && + !(FIELD_EX64(host->CSR_DBG, CSR_DBG, DST))); =20 return ret; } =20 static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_reque= st) { - if (interrupt_request & CPU_INTERRUPT_HARD) { - CPULoongArchState *env =3D cpu_env(cs); + CPULoongArchState *env =3D cpu_env(cs); =20 + if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_loongarch_hw_interrupts_enabled(env) && cpu_loongarch_hw_interrupts_pending(env)) { + if (env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST) { + trigger_vm_exit(env); + } /* Raise it */ cs->exception_index =3D EXCCODE_INT; loongarch_cpu_do_interrupt(cs); return true; } + } else if (interrupt_request & CPU_INTERRUPT_GUEST) { + if (loongarch_guest_has_interrupt(env)) { + cs->exception_index =3D EXCCODE_INT; + loongarch_cpu_do_interrupt(cs); + return true; + } } return false; } @@ -279,6 +304,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; @@ -306,6 +334,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.52.0 From nobody Sun Jul 12 00:33:17 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 1783674111825481.5538096328511; Fri, 10 Jul 2026 02:01:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76W-000646-RW; Fri, 10 Jul 2026 05:01:04 -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 1wi76U-00060T-Ah for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:01:02 -0400 Received: from [2400:e920:0:e::2c] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76M-0004C0-NW for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:01:01 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id 6679C241FC96; Fri, 10 Jul 2026 17:00:40 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 7/8] target/loongarch: Add LVZ MMU and PTW support Date: Fri, 10 Jul 2026 17:00:16 +0800 Message-ID: <90f253fe51aa2dda2b481859eb9b459b03c50498.1783673526.git.prcups@krgm.moe> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 2400:e920:0:e::2c (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=2400:e920:0:e::2c; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674115136158500 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 | 39 +- target/loongarch/cpu_helper.c | 87 ++- target/loongarch/tcg/helper.h | 17 +- .../tcg/insn_trans/trans_privileged.c.inc | 64 +- target/loongarch/tcg/tcg_loongarch.h | 3 +- target/loongarch/tcg/tlb_helper.c | 577 +++++++++++++----- 6 files changed, 563 insertions(+), 224 deletions(-) diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h index 54fb732d62..bc1816cd28 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,20 @@ 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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; =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 +60,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 +102,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..4da5cfbb85 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -18,10 +18,12 @@ #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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; =20 switch (level) { case 1: @@ -48,18 +50,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 +109,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 +155,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 +168,8 @@ TLBRet loongarch_ptw(CPULoongArchState *env, MMUContext= *context, vaddr address; TLBRet ret; MemTxResult ret1; - CPUSysState *sys =3D env_sys(env); + CPUSysState *sys =3D &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; =20 address =3D context->addr; if ((address >> 63) & 0x1) { @@ -170,7 +180,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 +189,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 +221,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 +247,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 +260,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 +294,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 +314,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 +334,15 @@ 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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; + 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 +384,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 +395,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 69f6cb352a..648328a7ef 100644 --- a/target/loongarch/tcg/helper.h +++ b/target/loongarch/tcg/helper.h @@ -133,11 +133,18 @@ 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_4(invtlb_all, void, env, tl, i32, i32) +DEF_HELPER_4(invtlb_all_g, void, env, tl, i32, i32) +DEF_HELPER_3(invtlb_all_asid, void, env, tl, i32) +DEF_HELPER_4(invtlb_page_asid, void, env, tl, tl, i32) +DEF_HELPER_4(invtlb_page_asid_or_g, void, env, tl, tl, i32) + +DEF_HELPER_1(gtlbwr, void, env) +DEF_HELPER_1(gtlbfill, void, env) +DEF_HELPER_1(gtlbsrch, void, env) +DEF_HELPER_1(gtlbrd, void, env) +DEF_HELPER_1(gtlbclr, void, env) +DEF_HELPER_1(gtlbflush, void, env) =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 2094d182ac..48a42779d3 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -316,25 +316,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..ddd152a6b6 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 sys_state_if(env, guest)->tlb; +} + bool check_ps(CPULoongArchState *env, uint8_t tlb_ps) { - CPUSysState *sys =3D env_sys(env); + CPUSysState *host =3D &env->sys_states[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 &env->sys_states[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,28 @@ 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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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 +188,20 @@ 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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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 +230,25 @@ 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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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 +272,25 @@ 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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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 +298,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 +316,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,18 +326,17 @@ 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 &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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 @@ -312,15 +345,18 @@ static bool loongarch_tlb_search(CPULoongArchState *e= nv, vaddr vaddr, =20 void helper_tlbsrch(CPULoongArchState *env) { - int index, match; CPUSysState *sys =3D env_sys(env); + bool guest =3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST; + int index, match; + 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_tgi= d(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 +366,20 @@ void helper_tlbsrch(CPULoongArchState *env) sys->CSR_TLBIDX =3D FIELD_DP64(sys->CSR_TLBIDX, CSR_TLBIDX, NE, 1); } =20 -void helper_tlbrd(CPULoongArchState *env) +static void read_tlb(CPULoongArchState *env, bool guest) { + CPUSysState *sys =3D &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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,39 +387,67 @@ 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 +void helper_tlbrd(CPULoongArchState *env) +{ + read_tlb(env, env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GUEST); +} + +void helper_gtlbsrch(CPULoongArchState *env) +{ + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + int index, match; + vaddr search_ehi; + + if (FIELD_EX64(guest->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + search_ehi =3D guest->CSR_TLBREHI; + } else { + search_ehi =3D guest->CSR_TLBEHI; + } + + match =3D loongarch_tlb_search(env, search_ehi, &index, true, get_tgid= (env)); + if (match) { + guest->CSR_TLBIDX =3D FIELD_DP64(guest->CSR_TLBIDX, CSR_TLBIDX, IN= DEX, + index); + guest->CSR_TLBIDX =3D FIELD_DP64(guest->CSR_TLBIDX, CSR_TLBIDX, NE= , 0); + return; + } + guest->CSR_TLBIDX =3D FIELD_DP64(guest->CSR_TLBIDX, CSR_TLBIDX, NE, 1); +} + +void helper_gtlbrd(CPULoongArchState *env) +{ + read_tlb(env, true); +} + 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; @@ -392,38 +456,53 @@ static void update_tlb_index(CPULoongArchState *env, = MMUContext *context, void helper_tlbwr(CPULoongArchState *env) { CPUSysState *sys =3D env_sys(env); + bool guest =3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_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); +} + +void helper_gtlbwr(CPULoongArchState *env) +{ + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + int index =3D FIELD_EX64(guest->CSR_TLBIDX, CSR_TLBIDX, INDEX); + MMUContext context; + + if (FIELD_EX64(guest->CSR_TLBIDX, CSR_TLBIDX, NE)) { + invalidate_tlb(env, index, true); + return; + } + + sptw_prepare_context(env, &context, true); + update_tlb_index(env, &context, index, true); } =20 static int get_tlb_random_index(CPULoongArchState *env, vaddr addr, - int pagesize) + int pagesize, bool guest) { + CPUSysState *sys =3D &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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 +511,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 +534,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; } } @@ -471,54 +550,75 @@ static int get_tlb_random_index(CPULoongArchState *en= v, vaddr addr, =20 void helper_tlbfill(CPULoongArchState *env) { + CPUSysState *sys =3D env_sys(env); + bool guest =3D env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_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_gtlbfill(CPULoongArchState *env) { + CPUSysState *guest =3D &env->sys_states[LOONGARCH_VM_LEVEL_GUEST]; + vaddr entryhi; + int index, pagesize; + MMUContext context; + + if (FIELD_EX64(guest->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { + entryhi =3D guest->CSR_TLBREHI; + pagesize =3D FIELD_EX64(guest->CSR_TLBREHI, CSR_TLBREHI, PS); + } else { + entryhi =3D guest->CSR_TLBEHI; + pagesize =3D FIELD_EX64(guest->CSR_TLBIDX, CSR_TLBIDX, PS); + } + + sptw_prepare_context(env, &context, true); + index =3D get_tlb_random_index(env, entryhi, pagesize, true); + invalidate_tlb(env, index, true); + fill_tlb_entry(env, tlb_bank(env, true) + index, &context, true); +} + +static void clear_tlb_by_index(CPULoongArchState *env, bool guest) +{ + CPUSysState *sys =3D &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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 +627,118 @@ void helper_tlbclr(CPULoongArchState *env) tlb_flush(env_cpu(env)); } =20 -void helper_tlbflush(CPULoongArchState *env) +void helper_tlbclr(CPULoongArchState *env) +{ + clear_tlb_by_index(env, env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GU= EST); +} + +void helper_gtlbclr(CPULoongArchState *env) { + clear_tlb_by_index(env, true); +} + +static void flush_tlb_by_index(CPULoongArchState *env, bool guest) +{ + CPUSysState *sys =3D &env->sys_states[guest ? LOONGARCH_VM_LEVEL_GUEST= : + LOONGARCH_VM_LEVEL_HOST]; 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_tlbflush(CPULoongArchState *env) +{ + flush_tlb_by_index(env, env_vm_level(env) =3D=3D LOONGARCH_VM_LEVEL_GU= EST); +} + +void helper_gtlbflush(CPULoongArchState *env) { + flush_tlb_by_index(env, true); +} + +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 +746,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; =20 - func =3D tlb_match_asid; - tlb =3D loongarch_tlb_search_cb(env, addr, asid, func); + 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; + + 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; =20 - func =3D tlb_match_any; - tlb =3D loongarch_tlb_search_cb(env, addr, asid, func); + 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; + + 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 +927,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 +987,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 +1031,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 +1066,12 @@ void helper_ldpte(CPULoongArchState *env, target_ulon= g 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 +1087,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 +1097,21 @@ static TLBRet loongarch_map_tlb_entry(CPULoongArchSt= ate *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.52.0 From nobody Sun Jul 12 00:33:17 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 178367416397658.09520972059897; Fri, 10 Jul 2026 02:02:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76W-00063o-DV; Fri, 10 Jul 2026 05:01:04 -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 1wi76U-00060U-B4 for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:01:02 -0400 Received: from [160.191.52.36] (helo=krgm.moe) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wi76M-0004By-Dk for qemu-devel@nongnu.org; Fri, 10 Jul 2026 05:01:00 -0400 Received: from yuno-loong (unknown [IPv6:2400:e920:0:e::2c]) by krgm.moe (Postfix) with ESMTPSA id 1B8BD241FC97; Fri, 10 Jul 2026 17:00:41 +0800 (CST) From: SignKirigami To: qemu-devel@nongnu.org Cc: Bibo Mao , xianglai li , SignKirigami , Hengyu Yu Subject: [PATCH v3 8/8] target/loongarch: Translate LVZ instructions Date: Fri, 10 Jul 2026 17:00:17 +0800 Message-ID: X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 160.191.52.36 (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=160.191.52.36; envelope-from=prcups@krgm.moe; helo=krgm.moe X-Spam_score_int: 22 X-Spam_score: 2.2 X-Spam_bar: ++ X-Spam_report: (2.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_SBL_CSS=3.335, 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: 1783674168565158500 Content-Type: text/plain; charset="utf-8" Add decode, disassembly and TCG translation for LVZ guest CSR access, guest TLB management and hypervisor call instructions, including guest-mode CSR trapping, guest read-only checks and translation context setup using the LVZ infrastructure added by earlier patches. Signed-off-by: SignKirigami Signed-off-by: Hengyu Yu --- target/loongarch/disas.c | 16 + target/loongarch/insns.decode | 14 + .../tcg/insn_trans/trans_privileged.c.inc | 275 +++++++++++++++++- target/loongarch/tcg/translate.c | 6 +- 4 files changed, 303 insertions(+), 8 deletions(-) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 3249ab7ac6..db0e556adb 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -51,6 +51,8 @@ static const char * const csr_names[] =3D { CSR_NAME(BADI), CSR_NAME(EENTRY), CSR_NAME(TLBIDX), + CSR_NAME(GTLBC), + CSR_NAME(TRGP), CSR_NAME(TLBEHI), CSR_NAME(TLBELO0), CSR_NAME(TLBELO1), @@ -87,6 +89,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 +704,16 @@ 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(gtlbclr, empty) +INSN(gtlbflush, empty) +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 3089d42044..b40fabe9d7 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -493,6 +493,20 @@ 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 +} + +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 +hvcl 0000 0000 0010 1011 1 ............... @i15 + 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 48a42779d3..adf088627e 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -39,6 +39,16 @@ 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) +GEN_FALSE_TRANS(gtlbclr) +GEN_FALSE_TRANS(gtlbflush) +GEN_FALSE_TRANS(gtlbsrch) +GEN_FALSE_TRANS(gtlbrd) +GEN_FALSE_TRANS(gtlbwr) +GEN_FALSE_TRANS(gtlbfill) +GEN_FALSE_TRANS(hvcl) =20 #else =20 @@ -69,8 +79,25 @@ static bool set_csr_trans_func(unsigned int csr_num, Gen= CSRRead readfn, return true; } =20 +static bool set_gcsr_trans_func(unsigned int csr_num, GenCSRRead readfn, + GenCSRWrite writefn) +{ + CSRInfo *csr; + + csr =3D get_gcsr(csr_num); + if (!csr) { + return false; + } + + csr->readfn =3D (GenCSRFunc)readfn; + csr->writefn =3D (GenCSRFunc)writefn; + return true; +} + #define SET_CSR_FUNC(NAME, read, write) \ set_csr_trans_func(LOONGARCH_CSR_##NAME, read, write) +#define SET_GCSR_FUNC(NAME, read, write) \ + set_gcsr_trans_func(LOONGARCH_CSR_##NAME, read, write) =20 void loongarch_csr_translate_init(void) { @@ -85,14 +112,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(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(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) { if ((csr->flags & CSRFL_READONLY) && write) { return false; } + if ((csr->flags & CSRFL_GUEST_READONLY) && ctx->guest_mode && write) { + return false; + } if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) { ctx->base.is_jmp =3D DISAS_EXIT_UPDATE; } else if ((csr->flags & CSRFL_EXITTB) && write) { @@ -110,12 +151,17 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd = *a) if (check_plv(ctx)) { return false; } - csr =3D get_csr(a->csr); + csr =3D ctx->guest_mode ? get_gcsr(a->csr) : get_csr(a->csr); if (csr =3D=3D NULL) { /* CSR is undefined: read as 0. */ dest =3D tcg_constant_tl(0); } else { check_csr_flags(ctx, csr, false); + if (ctx->guest_mode && (csr->flags & CSRFL_GSPR)) { + gen_helper_gspr(tcg_env); + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } dest =3D gpr_dst(ctx, a->rd, EXT_NONE); readfn =3D (GenCSRRead)csr->readfn; if (readfn) { @@ -137,12 +183,17 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr = *a) if (check_plv(ctx)) { return false; } - csr =3D get_csr(a->csr); + csr =3D ctx->guest_mode ? get_gcsr(a->csr) : get_csr(a->csr); 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); return true; } + if (ctx->guest_mode && (csr->flags & CSRFL_GSPR)) { + gen_helper_gspr(tcg_env); + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } if (!check_csr_flags(ctx, csr, true)) { /* CSR is readonly: trap. */ return false; @@ -170,20 +221,136 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csr= xchg *a) if (check_plv(ctx)) { return false; } - csr =3D get_csr(a->csr); + csr =3D ctx->guest_mode ? get_gcsr(a->csr) : get_csr(a->csr); 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); return true; } + if (ctx->guest_mode && (csr->flags & CSRFL_GSPR)) { + gen_helper_gspr(tcg_env); + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } =20 if (!check_csr_flags(ctx, csr, 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); + oldv =3D tcg_temp_new(); + newv =3D tcg_temp_new(); + temp =3D tcg_temp_new(); + + if (csr->readfn) { + GenCSRRead readfn =3D (GenCSRRead)csr->readfn; + readfn(oldv, tcg_env); + } else { + tcg_gen_ld_tl(oldv, tcg_env, csr->offset); + } + tcg_gen_and_tl(newv, src1, mask); + tcg_gen_andc_tl(temp, oldv, mask); + tcg_gen_or_tl(newv, newv, temp); + + writefn =3D (GenCSRWrite)csr->writefn; + if (writefn) { + writefn(oldv, tcg_env, newv); + } else { + tcg_gen_st_tl(newv, tcg_env, csr->offset); + } + gen_set_gpr(a->rd, oldv, EXT_NONE); + return true; +} + +static bool trans_gcsrrd(DisasContext *ctx, arg_gcsrrd *a) +{ + TCGv dest; + const CSRInfo *csr; + GenCSRRead readfn; + + if (check_plv(ctx) || !avail_LVZ(ctx)) { + return false; + } + csr =3D get_gcsr(a->csr); + if (csr =3D=3D NULL) { + dest =3D tcg_constant_tl(0); + } else { + dest =3D gpr_dst(ctx, a->rd, EXT_NONE); + if (csr->flags & CSRFL_GSPR) { + tcg_gen_movi_tl(dest, 0); + } else { + readfn =3D (GenCSRRead)csr->readfn; + if (readfn) { + readfn(dest, tcg_env); + } else { + tcg_gen_ld_tl(dest, tcg_env, csr->offset); + } + } + } + gen_set_gpr(a->rd, dest, EXT_NONE); + return true; +} + +static bool trans_gcsrwr(DisasContext *ctx, arg_gcsrwr *a) +{ + TCGv dest, src1; + const CSRInfo *csr; + GenCSRWrite writefn; + + if (check_plv(ctx) || !avail_LVZ(ctx)) { + return false; + } + csr =3D get_gcsr(a->csr); + if (csr =3D=3D NULL) { + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + if (!check_csr_flags(ctx, csr, true)) { + return false; + } + if (csr->flags & CSRFL_GSPR) { + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + + src1 =3D gpr_src(ctx, a->rd, EXT_NONE); + writefn =3D (GenCSRWrite)csr->writefn; + if (writefn) { + dest =3D gpr_dst(ctx, a->rd, EXT_NONE); + writefn(dest, tcg_env, src1); + } else { + dest =3D tcg_temp_new(); + tcg_gen_ld_tl(dest, tcg_env, csr->offset); + tcg_gen_st_tl(src1, tcg_env, csr->offset); + } + gen_set_gpr(a->rd, dest, EXT_NONE); + return true; +} + +static bool trans_gcsrxchg(DisasContext *ctx, arg_gcsrxchg *a) +{ + TCGv src1, mask, oldv, newv, temp; + const CSRInfo *csr; + GenCSRRead readfn; + GenCSRWrite writefn; + + if (check_plv(ctx) || !avail_LVZ(ctx)) { + return false; + } + csr =3D get_gcsr(a->csr); + if (csr =3D=3D NULL) { + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } + if (!check_csr_flags(ctx, csr, true)) { + return false; + } + if (csr->flags & CSRFL_GSPR) { + gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE); + return true; + } =20 src1 =3D gpr_src(ctx, a->rd, EXT_NONE); mask =3D gpr_src(ctx, a->rj, EXT_NONE); @@ -191,7 +358,12 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxc= hg *a) newv =3D tcg_temp_new(); temp =3D tcg_temp_new(); =20 - tcg_gen_ld_tl(oldv, tcg_env, csr->offset); + readfn =3D (GenCSRRead)csr->readfn; + if (readfn) { + readfn(oldv, tcg_env); + } else { + tcg_gen_ld_tl(oldv, tcg_env, csr->offset); + } tcg_gen_and_tl(newv, src1, mask); tcg_gen_andc_tl(temp, oldv, mask); tcg_gen_or_tl(newv, newv, temp); @@ -212,6 +384,11 @@ static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a, TCGv dest =3D gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 =3D gpr_src(ctx, a->rj, EXT_NONE); =20 + if (ctx->guest_mode) { + gen_helper_gspr(tcg_env); + return true; + } + if (check_plv(ctx)) { return false; } @@ -225,6 +402,11 @@ static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, TCGv val =3D gpr_src(ctx, a->rd, EXT_NONE); TCGv addr =3D gpr_src(ctx, a->rj, EXT_NONE); =20 + if (ctx->guest_mode) { + gen_helper_gspr(tcg_env); + return true; + } + if (check_plv(ctx)) { return false; } @@ -243,7 +425,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; } @@ -267,6 +449,24 @@ static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *= 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_gtlbsrch(tcg_env); + return true; +} + +static bool trans_gtlbrd(DisasContext *ctx, arg_gtlbrd *a) +{ + if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) { + return false; + } + gen_helper_gtlbrd(tcg_env); + return true; +} + static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a) { if (check_plv(ctx)) { @@ -277,6 +477,16 @@ 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_gtlbwr(tcg_env); + check_mmu_idx(ctx); + return true; +} + static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a) { if (check_plv(ctx)) { @@ -287,6 +497,16 @@ 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_gtlbfill(tcg_env); + check_mmu_idx(ctx); + return true; +} + static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a) { if (check_plv(ctx)) { @@ -297,6 +517,16 @@ 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_gtlbclr(tcg_env); + check_mmu_idx(ctx); + return true; +} + static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a) { if (check_plv(ctx)) { @@ -307,6 +537,16 @@ 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_gtlbflush(tcg_env); + check_mmu_idx(ctx); + return true; +} + static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a) { TCGv rj =3D gpr_src(ctx, a->rj, EXT_NONE); @@ -438,6 +678,10 @@ static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) if (check_plv(ctx)) { return false; } + if (ctx->guest_mode) { + gen_helper_gspr(tcg_env); + return true; + } generate_exception(ctx, EXCCODE_DBP); return true; } @@ -448,9 +692,26 @@ static bool trans_idle(DisasContext *ctx, arg_idle *a) return false; } =20 + if (ctx->guest_mode) { + gen_helper_gspr(tcg_env); + 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; + } + + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + gen_helper_hvcl(tcg_env, tcg_constant_i32(a->imm)); + ctx->base.is_jmp =3D DISAS_NORETURN; + return true; +} #endif 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.52.0