From nobody Fri Dec 19 14:32:20 2025 Delivered-To: importer@patchew.org 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=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=pass; 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=pass(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1580586533519535.2526039957211; Sat, 1 Feb 2020 11:48:53 -0800 (PST) Received: from localhost ([::1]:50058 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ixylA-0004AW-F4 for importer@patchew.org; Sat, 01 Feb 2020 14:48:52 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:58861) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ixySp-0007nE-1G for qemu-devel@nongnu.org; Sat, 01 Feb 2020 14:29:57 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ixySn-0006zV-85 for qemu-devel@nongnu.org; Sat, 01 Feb 2020 14:29:54 -0500 Received: from mail-pl1-x642.google.com ([2607:f8b0:4864:20::642]:32876) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ixySn-0006yq-0L for qemu-devel@nongnu.org; Sat, 01 Feb 2020 14:29:53 -0500 Received: by mail-pl1-x642.google.com with SMTP id ay11so4185563plb.0 for ; Sat, 01 Feb 2020 11:29:52 -0800 (PST) Received: from localhost.localdomain (97-126-123-70.tukw.qwest.net. [97.126.123.70]) by smtp.gmail.com with ESMTPSA id l7sm3668509pga.27.2020.02.01.11.29.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 01 Feb 2020 11:29:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=D7t2ViJaEx2/xVLIPebZKCECTUtY8kzuVl1NGNJav/g=; b=OuWDXYKr3MOu4zrxtxMQ6LduS03zVJ45QLQgHq8Fd67uVq3guWSFLRFKRJi2eu561d ZD7ZriYtRFBLQAzwR6dHAbN0Dlqihgj/xmO522oVL1QxDMo4PPIUGB7WWEp+WSR0ibjO nWdk/u3C3v+E++tX/CwDjlzVNyaBFvs6ZzYOid9aFRAqrGMpkvw5FDwr9VaA9UpV76k5 cOLerm96Id1oc1RrWSwJj7EWCMTU/PjPTOWeqI/2+hIU3lCGr8oBofYvOUbIDZe89c/2 Qf22yKo0tamHBlfD7pSDNClRds92Jk1rdUD7AI+j5e3rs0c4vVqVmqmMNXrl6oNK1WrG 2yBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=D7t2ViJaEx2/xVLIPebZKCECTUtY8kzuVl1NGNJav/g=; b=Ujem6S/8GxkQYVffRrZlrWxi2dUkgvkyNMpfDn6dqCKonmAS56si+zo5sQDyMQNaNk BwvlTU41OzuUUci5Y9jUstuTAb4hUAuu3IP9sOQqSpjEYpBdUbGSGce+iAabebEzUYiN w0G+zGuSHwoyt1sOr6jun2XQsT0lBtWfGPmpbwY4CA4LWC7fNF6YWKI4HXSTV2E1Y3LC +OZ4iF+sRLVfCZFzPmP3Q7ByOAMAy5AAyKLz5foNLV7nY6ZZpj2E7RiFc2PtRbITqIw8 e7gDjkNlLmdNuESqXhtteYP7c4uW8vRedgFJV8r5YYr5ChV7+HlY3NE+ubjmHOy2S3I7 OUtg== X-Gm-Message-State: APjAAAVY81eTviqEo9bD7oWX4nsTjFFlT0/0RPeCuEWf7gRP5jH1o288 34nMLEV9DpW6m/Zgwjvj6I2HfWbmkAk= X-Google-Smtp-Source: APXvYqwpIixpXCY8OkGJbC1DZudYTqzpbN4iCYkEjvtQ78Q9EY/1WLi1Fh9liqnD4Z5ySSkzABLEpQ== X-Received: by 2002:a17:90a:d103:: with SMTP id l3mr20733093pju.116.1580585391411; Sat, 01 Feb 2020 11:29:51 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Subject: [PATCH v6 28/41] target/arm: Add VHE system register redirection and aliasing Date: Sat, 1 Feb 2020 11:29:03 -0800 Message-Id: <20200201192916.31796-29-richard.henderson@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200201192916.31796-1-richard.henderson@linaro.org> References: <20200201192916.31796-1-richard.henderson@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::642 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @linaro.org) Content-Type: text/plain; charset="utf-8" Several of the EL1/0 registers are redirected to the EL2 version when in EL2 and HCR_EL2.E2H is set. Many of these registers have side effects. Link together the two ARMCPRegInfo structures after they have been properly instantiated. Install common dispatch routines to all of the relevant registers. The same set of registers that are redirected also have additional EL12/EL02 aliases created to access the original register that was redirected. Omit the generic timer registers from redirection here, because we'll need multiple kinds of redirection from both EL0 and EL2. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- v5: Drop unioning in ARMCPRegInfo with bank_fieldoffsets[]. v6: Adjust spelling of new_reg access adjustment (pmm). --- target/arm/cpu.h | 13 ++++ target/arm/helper.c | 162 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ded1e8e0a8..d091a7e2e8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2576,6 +2576,19 @@ struct ARMCPRegInfo { * fieldoffset is 0 then no reset will be done. */ CPResetFn *resetfn; + + /* + * "Original" writefn and readfn. + * For ARMv8.1-VHE register aliases, we overwrite the read/write + * accessor functions of various EL1/EL0 to perform the runtime + * check for which sysreg should actually be modified, and then + * forwards the operation. Before overwriting the accessors, + * the original function is copied here, so that accesses that + * really do go to the EL1/EL0 version proceed normally. + * (The corresponding EL2 register is linked via opaque.) + */ + CPReadFn *orig_readfn; + CPWriteFn *orig_writefn; }; =20 /* Macros which are lvalues for the field in CPUARMState for the diff --git a/target/arm/helper.c b/target/arm/helper.c index 2aa04d0613..8f7620f243 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5358,6 +5358,158 @@ static const ARMCPRegInfo el3_cp_reginfo[] =3D { REGINFO_SENTINEL }; =20 +#ifndef CONFIG_USER_ONLY +/* Test if system register redirection is to occur in the current state. = */ +static bool redirect_for_e2h(CPUARMState *env) +{ + return arm_current_el(env) =3D=3D 2 && (arm_hcr_el2_eff(env) & HCR_E2H= ); +} + +static uint64_t el2_e2h_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + CPReadFn *readfn; + + if (redirect_for_e2h(env)) { + /* Switch to the saved EL2 version of the register. */ + ri =3D ri->opaque; + readfn =3D ri->readfn; + } else { + readfn =3D ri->orig_readfn; + } + if (readfn =3D=3D NULL) { + readfn =3D raw_read; + } + return readfn(env, ri); +} + +static void el2_e2h_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + CPWriteFn *writefn; + + if (redirect_for_e2h(env)) { + /* Switch to the saved EL2 version of the register. */ + ri =3D ri->opaque; + writefn =3D ri->writefn; + } else { + writefn =3D ri->orig_writefn; + } + if (writefn =3D=3D NULL) { + writefn =3D raw_write; + } + writefn(env, ri, value); +} + +static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) +{ + struct E2HAlias { + uint32_t src_key, dst_key, new_key; + const char *src_name, *dst_name, *new_name; + bool (*feature)(const ARMISARegisters *id); + }; + +#define K(op0, op1, crn, crm, op2) \ + ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2) + + static const struct E2HAlias aliases[] =3D { + { K(3, 0, 1, 0, 0), K(3, 4, 1, 0, 0), K(3, 5, 1, 0, 0), + "SCTLR", "SCTLR_EL2", "SCTLR_EL12" }, + { K(3, 0, 1, 0, 2), K(3, 4, 1, 1, 2), K(3, 5, 1, 0, 2), + "CPACR", "CPTR_EL2", "CPACR_EL12" }, + { K(3, 0, 2, 0, 0), K(3, 4, 2, 0, 0), K(3, 5, 2, 0, 0), + "TTBR0_EL1", "TTBR0_EL2", "TTBR0_EL12" }, + { K(3, 0, 2, 0, 1), K(3, 4, 2, 0, 1), K(3, 5, 2, 0, 1), + "TTBR1_EL1", "TTBR1_EL2", "TTBR1_EL12" }, + { K(3, 0, 2, 0, 2), K(3, 4, 2, 0, 2), K(3, 5, 2, 0, 2), + "TCR_EL1", "TCR_EL2", "TCR_EL12" }, + { K(3, 0, 4, 0, 0), K(3, 4, 4, 0, 0), K(3, 5, 4, 0, 0), + "SPSR_EL1", "SPSR_EL2", "SPSR_EL12" }, + { K(3, 0, 4, 0, 1), K(3, 4, 4, 0, 1), K(3, 5, 4, 0, 1), + "ELR_EL1", "ELR_EL2", "ELR_EL12" }, + { K(3, 0, 5, 1, 0), K(3, 4, 5, 1, 0), K(3, 5, 5, 1, 0), + "AFSR0_EL1", "AFSR0_EL2", "AFSR0_EL12" }, + { K(3, 0, 5, 1, 1), K(3, 4, 5, 1, 1), K(3, 5, 5, 1, 1), + "AFSR1_EL1", "AFSR1_EL2", "AFSR1_EL12" }, + { K(3, 0, 5, 2, 0), K(3, 4, 5, 2, 0), K(3, 5, 5, 2, 0), + "ESR_EL1", "ESR_EL2", "ESR_EL12" }, + { K(3, 0, 6, 0, 0), K(3, 4, 6, 0, 0), K(3, 5, 6, 0, 0), + "FAR_EL1", "FAR_EL2", "FAR_EL12" }, + { K(3, 0, 10, 2, 0), K(3, 4, 10, 2, 0), K(3, 5, 10, 2, 0), + "MAIR_EL1", "MAIR_EL2", "MAIR_EL12" }, + { K(3, 0, 10, 3, 0), K(3, 4, 10, 3, 0), K(3, 5, 10, 3, 0), + "AMAIR0", "AMAIR_EL2", "AMAIR_EL12" }, + { K(3, 0, 12, 0, 0), K(3, 4, 12, 0, 0), K(3, 5, 12, 0, 0), + "VBAR", "VBAR_EL2", "VBAR_EL12" }, + { K(3, 0, 13, 0, 1), K(3, 4, 13, 0, 1), K(3, 5, 13, 0, 1), + "CONTEXTIDR_EL1", "CONTEXTIDR_EL2", "CONTEXTIDR_EL12" }, + { K(3, 0, 14, 1, 0), K(3, 4, 14, 1, 0), K(3, 5, 14, 1, 0), + "CNTKCTL", "CNTHCTL_EL2", "CNTKCTL_EL12" }, + + /* + * Note that redirection of ZCR is mentioned in the description + * of ZCR_EL2, and aliasing in the description of ZCR_EL1, but + * not in the summary table. + */ + { K(3, 0, 1, 2, 0), K(3, 4, 1, 2, 0), K(3, 5, 1, 2, 0), + "ZCR_EL1", "ZCR_EL2", "ZCR_EL12", isar_feature_aa64_sve }, + + /* TODO: ARMv8.2-SPE -- PMSCR_EL2 */ + /* TODO: ARMv8.4-Trace -- TRFCR_EL2 */ + }; +#undef K + + size_t i; + + for (i =3D 0; i < ARRAY_SIZE(aliases); i++) { + const struct E2HAlias *a =3D &aliases[i]; + ARMCPRegInfo *src_reg, *dst_reg; + + if (a->feature && !a->feature(&cpu->isar)) { + continue; + } + + src_reg =3D g_hash_table_lookup(cpu->cp_regs, &a->src_key); + dst_reg =3D g_hash_table_lookup(cpu->cp_regs, &a->dst_key); + g_assert(src_reg !=3D NULL); + g_assert(dst_reg !=3D NULL); + + /* Cross-compare names to detect typos in the keys. */ + g_assert(strcmp(src_reg->name, a->src_name) =3D=3D 0); + g_assert(strcmp(dst_reg->name, a->dst_name) =3D=3D 0); + + /* None of the core system registers use opaque; we will. */ + g_assert(src_reg->opaque =3D=3D NULL); + + /* Create alias before redirection so we dup the right data. */ + if (a->new_key) { + ARMCPRegInfo *new_reg =3D g_memdup(src_reg, sizeof(ARMCPRegInf= o)); + uint32_t *new_key =3D g_memdup(&a->new_key, sizeof(uint32_t)); + bool ok; + + new_reg->name =3D a->new_name; + new_reg->type |=3D ARM_CP_ALIAS; + /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ + new_reg->access &=3D PL2_RW | PL3_RW; + + ok =3D g_hash_table_insert(cpu->cp_regs, new_key, new_reg); + g_assert(ok); + } + + src_reg->opaque =3D dst_reg; + src_reg->orig_readfn =3D src_reg->readfn ?: raw_read; + src_reg->orig_writefn =3D src_reg->writefn ?: raw_write; + if (!src_reg->raw_readfn) { + src_reg->raw_readfn =3D raw_read; + } + if (!src_reg->raw_writefn) { + src_reg->raw_writefn =3D raw_write; + } + src_reg->readfn =3D el2_e2h_read; + src_reg->writefn =3D el2_e2h_write; + } +} +#endif + static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo = *ri, bool isread) { @@ -7291,6 +7443,16 @@ void register_cp_regs_for_features(ARMCPU *cpu) : cpu_isar_feature(aa32_predinv, cpu)) { define_arm_cp_regs(cpu, predinv_reginfo); } + +#ifndef CONFIG_USER_ONLY + /* + * Register redirections and aliases must be done last, + * after the registers from the other extensions have been defined. + */ + if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu= )) { + define_arm_vh_e2h_redirects_aliases(cpu); + } +#endif } =20 void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) --=20 2.20.1