* Re: [PATCH v2 6/6] mm/mprotect: use huge_ptep_get() for hugetlb
From: David Hildenbrand (Arm) @ 2026-07-02 15:47 UTC (permalink / raw)
To: Dev Jain, muchun.song, osalvador, akpm, ljs, liam
Cc: riel, vbabka, harry, jannh, lance.yang, kas, linux-mm,
linux-kernel, rcampbell, apopple, ziy, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, j-nomura,
nao.horiguchi, ak, mel, pfalcato, jpoimboe, dave.hansen, tglx,
catalin.marinas, will, linux-arm-kernel, ryan.roberts,
anshuman.khandual
In-Reply-To: <20260702051341.126509-7-dev.jain@arm.com>
On 7/2/26 07:13, Dev Jain wrote:
> prot_none_hugetlb_entry() is the hugetlb callback for the early
> mprotect(PROT_NONE) PFN permission walk on x86.
>
> The callback passes the decoded PFN to pfn_modify_allowed(). For a
> hugetlb callback, the pte pointer refers to a hugetlb entry. On
> architectures where hugetlb entries need huge_ptep_get(), reading that
> entry with ptep_get() can make the permission check use the wrong PFN.
>
> Use huge_ptep_get() before decoding the hugetlb PFN.
>
> Currently there is no path which can trigger a bug: huge_ptep_get() is a
> simple ptep_get() for x86, and the prot_none walk occurs only for x86.
>
> So no need to backport - use the correct helper anyways.
>
> Fixes: 42e4089c7890 ("x86/speculation/l1tf: Disallow non privileged high MMIO PROT_NONE mappings")
> Signed-off-by: Dev Jain <dev.jain@arm.com>
> ---
> mm/mprotect.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/mm/mprotect.c b/mm/mprotect.c
> index 9cbf932b028cf..23779632d18bf 100644
> --- a/mm/mprotect.c
> +++ b/mm/mprotect.c
> @@ -699,14 +699,20 @@ static int prot_none_pte_entry(pte_t *pte, unsigned long addr,
> 0 : -EACCES;
> }
>
> +#ifdef CONFIG_HUGETLB_PAGE
> static int prot_none_hugetlb_entry(pte_t *pte, unsigned long hmask,
> unsigned long addr, unsigned long next,
> struct mm_walk *walk)
> {
> - return pfn_modify_allowed(pte_pfn(ptep_get(pte)),
> + pte_t entry = huge_ptep_get(walk->mm, addr, pte);
Nit: can be const :)
> +
> + return pfn_modify_allowed(pte_pfn(entry),
> *(pgprot_t *)(walk->private)) ?
> 0 : -EACCES;
Indentation is odd.
Can we just make this readable?
if (pfn_modify_allowed ...)
return 0
return -EACCESS;
--
Cheers,
David
^ permalink raw reply
* Re: (subset) [PATCH] mfd: db8500-prcmu: Fold dbx500 header into db8500
From: Lee Jones @ 2026-07-02 15:48 UTC (permalink / raw)
To: Russell King, Ulf Hansson, Michael Turquette, Stephen Boyd,
Brian Masney, Rafael J. Wysocki, Daniel Lezcano, Christian Loehle,
Lee Jones, Liam Girdwood, Mark Brown, Zhang Rui, Lukasz Luba,
Wim Van Sebroeck, Guenter Roeck, Jaroslav Kysela, Takashi Iwai,
Linus Walleij
Cc: linux-arm-kernel, linux-clk, linux-pm, linux-watchdog,
linux-sound, kernel test robot
In-Reply-To: <20260619-mfd-prcmu-merge-headers-v1-1-8ea0ee23b4d6@kernel.org>
On Fri, 19 Jun 2026 22:27:10 +0200, Linus Walleij wrote:
> Move the DBx500 PRCMU definitions into the DB8500 PRCMU
> header and delete the wrapper header.
>
> Convert users of simple PRCMU wrappers to call the DB8500 helpers
> directly.
>
> The dbx500-prcmu.h header was the result of an earlier attempt to
> abstract several DBx5x SoC PRCMU units to use the same abstract
> header. They are deleted from the kernel and this is not just
> causing maintenance burden and build errors.
>
> [...]
Applied, thanks!
[1/1] mfd: db8500-prcmu: Fold dbx500 header into db8500
commit: 6fd345e209284bc939693989bb7144133a8e93fd
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH 09/11] regulator: db8500-prcmu: Remove EPOD regulators
From: Lee Jones @ 2026-07-02 15:51 UTC (permalink / raw)
To: Linus Walleij
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li,
linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-9-eb5e50b1a588@kernel.org>
On Thu, 18 Jun 2026, Linus Walleij wrote:
> Remove the obsolete DB8500 PRCMU regulator drivers.
>
> Drop the regulator build hooks now that EPODs are power domains.
>
> Keep the MFD cell around because a later patch reuses it for a
> small compatibility regulator driver.
>
> Assisted-by: Codex:gpt-5-5
> Signed-off-by: Linus Walleij <linusw@kernel.org>
> ---
> drivers/mfd/db8500-prcmu.c | 239 +---------------
> drivers/regulator/Kconfig | 12 -
> drivers/regulator/Makefile | 2 -
> drivers/regulator/db8500-prcmu.c | 501 ---------------------------------
> drivers/regulator/dbx500-prcmu.c | 155 ----------
> drivers/regulator/dbx500-prcmu.h | 55 ----
> include/linux/regulator/db8500-prcmu.h | 38 ---
> 7 files changed, 1 insertion(+), 1001 deletions(-)
Any deps?
--
Lee Jones
^ permalink raw reply
* [PATCH v8 09/39] drm/display: hdmi-state-helper: Add fallback TMDS rate validation
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Validate the computed TMDS character rate against
connector->hdmi.max_tmds_char_rate when no driver-specific
tmds_char_rate_valid() hook is provided.
This gives HDMI connectors a common fallback for rejecting modes whose
TMDS character rate exceeds the connector limit, while still allowing
drivers with custom validation requirements to implement their own
tmds_char_rate_valid() callback.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index ce17eeefc2da..db76699093e8 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -566,6 +566,9 @@ hdmi_clock_valid(const struct drm_connector *connector,
status = funcs->tmds_char_rate_valid(connector, mode, clock);
if (status != MODE_OK)
return status;
+ } else if (connector->hdmi.max_tmds_char_rate) {
+ if (clock > connector->hdmi.max_tmds_char_rate)
+ return MODE_CLOCK_HIGH;
}
return MODE_OK;
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v3 1/1] reset: imx7: Correct polarity of MIPI CSI resets on i.MX8MQ
From: Philipp Zabel @ 2026-07-02 15:53 UTC (permalink / raw)
To: robby.cai, Frank.Li, s.hauer, festevam
Cc: krzk+dt, andrew.smirnov, kernel, imx, linux-arm-kernel,
linux-kernel, aisheng.dong, guoniu.zhou
In-Reply-To: <20260619073115.3778313-1-robby.cai@oss.nxp.com>
On Fr, 2026-06-19 at 15:31 +0800, robby.cai@oss.nxp.com wrote:
> From: Robby Cai <robby.cai@nxp.com>
>
> On i.MX8MQ, the MIPI CSI reset lines are active-low and not self-clearing.
> Writing '0' asserts reset and it remains asserted until explicitly
> deasserted by software.
>
> This driver previously treated the MIPI CSI reset signals as active-high,
> which led to incorrect reset assert/deassert sequencing. This issue was
> exposed by commit 6d79bb8fd2aa ("media: imx8mq-mipi-csi2: Explicitly
> release reset").
>
> Fix this by reflecting the correct reset polarity and ensuring proper
> reset handling.
[...]
Applied to reset/fixes, thanks!
[1/1] reset: imx7: Correct polarity of MIPI CSI resets on i.MX8MQ
https://git.kernel.org/pub/scm/linux/kernel/git/pza/linux.git/commit/?id=71827776667f
regards
Philipp
^ permalink raw reply
* [PATCH v8 06/39] drm/display: scdc-helper: Add helper to set SCDC version information
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
The HDMI 2.x specs mandate that compliant Sink devices report their SCDC
version in the Sink Version register, which reads as 1 on any
SCDC-capable sink.
There is also a dedicated Source Version register. Writing it is not
compulsory, but the spec advises that compliant Source devices do so, in
which case the value must be 1.
Add drm_scdc_set_source_version() to follow this recommendation. The
Sink Version register is read first, both to log the advertised SCDC
version and to guard against non-conformant devices: a sink reporting
version 0 is either not SCDC-version-aware or broken, so writing the
source version gains nothing and risks upsetting such hardware. In that
case the write is skipped.
The source version is passed as a parameter rather than hardcoded, as
future spec revisions may define additional rules for the allowable
version values. The written value is additionally clamped to the sink's
reported version so the source never advertises a version the sink does
not understand.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/display/drm_scdc_helper.c | 46 ++++++++++++++++++++++++++++++-
include/drm/display/drm_scdc_helper.h | 2 ++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index cb6632346aad..6d804ee19420 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -21,10 +21,11 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <linux/delay.h>
#include <linux/export.h>
#include <linux/i2c.h>
+#include <linux/minmax.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_connector.h>
@@ -270,3 +271,46 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
return true;
}
EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+/**
+ * drm_scdc_set_source_version - set SCDC source version on the sink
+ * @connector: connector
+ * @ver: source version to advertise (per spec, 1)
+ *
+ * Reads the sink version for diagnostics and as a guard, then writes
+ * the source version unless the sink reports version 0.
+ *
+ * Returns:
+ * 0 on success or when skipped; a negative error code when either
+ * the read or the write failed.
+ */
+int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver)
+{
+ u8 sink_ver;
+ int ret;
+
+ ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &sink_ver);
+ if (ret) {
+ drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
+ return ret;
+ }
+
+ drm_scdc_dbg(connector, "Sink reported SCDC ver. %u\n", sink_ver);
+
+ /*
+ * Only advertise our source version to sinks that report a
+ * non-zero sink version. A sink reporting version 0 is either
+ * not SCDC-version-aware or non-conformant; writing the source
+ * version gains nothing and may upset broken hardware.
+ */
+ if (sink_ver) {
+ ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
+ min_t(u8, sink_ver, ver));
+ if (ret)
+ drm_scdc_dbg(connector,
+ "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_scdc_set_source_version);
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..90b0828364c2 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -77,4 +77,6 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector);
bool drm_scdc_set_scrambling(struct drm_connector *connector, bool enable);
bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, bool set);
+int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver);
+
#endif
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v2 1/4] dt-bindings: can: rockchip: add rk3588 CAN-FD compatible
From: Heiko Stübner @ 2026-07-02 16:01 UTC (permalink / raw)
To: Marc Kleine-Budde, linux-can, 1579567540
Cc: Vincent Mailhol, Rob Herring, Krzysztof Kozlowski, kernel,
Conor Dooley, Dmitry Torokhov, Shengjiu Wang, Pengpeng Hou,
Russell King, Eric Biggers, Mario Limonciello, Karl Mehltretter,
Yixun Lan, Stephen Boyd, devicetree, linux-arm-kernel,
linux-rockchip, linux-kernel, Cunhao Lu
In-Reply-To: <tencent_3B2B6003D1DE4FB7A984665A062581766405@qq.com>
Am Donnerstag, 2. Juli 2026, 16:06:51 Mitteleuropäische Sommerzeit schrieb 1579567540@qq.com:
> From: Cunhao Lu <1579567540@qq.com>
>
> RK3588 integrates a Rockchip CAN-FD controller variant that is not
> fully compatible with RK3568v2. The RX FIFO count register field is
> encoded in bits 7:5 on RK3588, while RK3568v2 uses bits 6:4.
>
> Add a dedicated rockchip,rk3588-canfd compatible to describe this
> variant. Do not use rockchip,rk3568v2-canfd as a fallback, because that
> would describe a register layout that does not match the hardware.
>
> Changes in v2:
> - Use enum for the single-compatible entries, as suggested by Krzysztof.
> - Reword the commit message to explain the hardware difference instead
> of referring to Linux driver match data.
>
> Signed-off-by: Cunhao Lu <1579567540@qq.com>
after fixing Krzysztof's comment:
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
and doing dtbscheck of the binding against the dt-patches:
Tested-by: Heiko Stuebner <heiko@sntech.de>
^ permalink raw reply
* Re: [PATCH v2 2/4] can: rockchip: add RK3588 CAN support
From: Heiko Stübner @ 2026-07-02 16:02 UTC (permalink / raw)
To: Marc Kleine-Budde, linux-can, 1579567540
Cc: Vincent Mailhol, Rob Herring, Krzysztof Kozlowski, kernel,
Conor Dooley, Dmitry Torokhov, Shengjiu Wang, Pengpeng Hou,
Russell King, Eric Biggers, Mario Limonciello, Karl Mehltretter,
Yixun Lan, Stephen Boyd, devicetree, linux-arm-kernel,
linux-rockchip, linux-kernel, Cunhao Lu, Heiko Stuebner
In-Reply-To: <tencent_F077D309CDB6CC4802CC086D8009E29BDF06@qq.com>
Am Donnerstag, 2. Juli 2026, 16:06:52 Mitteleuropäische Sommerzeit schrieb 1579567540@qq.com:
> From: Cunhao Lu <1579567540@qq.com>
>
> Add support for the RK3588 CAN controller by introducing a dedicated
> model ID and OF match entry.
>
> The block is closely related to the existing RK3568 variants, but it
> cannot reuse their match data unchanged. In particular, RK3588
> encodes RX_FIFO_CNT in bits 7:5 instead of 6:4, so the RX path needs
> SoC-specific handling.
>
> The RX FIFO count bitfield difference was found by comparing Rockchip's
> vendor kernel 6.1 CAN support for RK3568 and RK3588. Runtime testing on
> RK3588 also confirms that bits 7:5 are needed.
>
> Enable the existing erratum 5 empty-FIFO workaround for RK3588.
> Heiko reproduced erratum 6 on RK3588, so enable that workaround as
> well.
>
> Keep RKCANFD_QUIRK_CANFD_BROKEN enabled for RK3588, so CAN-FD stays
> disabled for now. Local testing did not reproduce the two known CAN-FD
> trigger frames that cause Error Interrupts on RK3568 variants. Instead,
> RK3588 shows a different CAN-FD failure mode: CAN-FD frames without BRS
> work in this setup, but BRS with a data bitrate different from the
> nominal bitrate immediately drives the controller bus-off.
>
> Reported-by: Heiko Stuebner <heiko.stuebner@cherry.de>
> Link: https://lore.kernel.org/lkml/20260630164336.3444550-4-heiko@sntech.de/
I think you might want to drop that above. If anything a Co-developed-by
would be applicable, but from the (small) size of the change, that also
isn't really necessary for me :-)
> Signed-off-by: Cunhao Lu <1579567540@qq.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
^ permalink raw reply
* [PATCH 00/28] KVM: arm64: Add support for FEAT_NV2p1 and FEAT_NV3
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
This series adds support for two extensions targeting Nested Virt on
arm64:
- FEAT_NV2p1 is effectively a bug fix for two registers (CNTHCTL_EL2
and CPTR_EL2) that are missing stateful bits when accessed from EL1
in a NV configuration. When this is present, the hypervisor can
avoid a bunch of traps.
- FEAT_NV3 is much more ambitious, and changes the way ERET behaves in
a NV environment. By moving EL1 accesses to HCR_EL2 from memory (via
VNCR) to a dedicated register (NVHCR_EL2), the HW can detect whether
the guest is performing an ERET for itself (NVHCR_EL2.TGE==1) or to
its own guest (NVHCR_EL2.TGE==0). In the former case, ERET is done
directly, and no trap occurs. Similar optimisations are available
for a class of TLBI instructions.
The whole thing has been tested on an FVP model, and shown measurable
improvements for an L1 guest (about 1.5% fewer instructions).
Given that this isn't very convincing on its own, I have built an
approximate emulation of FEAT_NV3 that L1 (and deeper levels) can use
on actual production hardware. For these deeper levels, the numbers
are in the double digit of percentage point reduction (those
interested can look at the patches in the kvm-arm64/nv3 branch in my
tree).
Does it make NV better? Yes!
Does it make NV good? Get real!
Anyway, patches on top of -rc1 plus the current state of kvmarm/fixes.
Marc Zyngier (28):
arm64: sysreg: Emit RESx/UNKN values for Mapping definitions
arm64: Update ID_AA64MMFR4_EL1 description to 2026-03 JSON release
KVM: arm64: Merge guest's HCRX_EL2 using NV_HCRX_GUEST_EXCLUDE
KVM: arm64: Drop __HCRX_EL2_* masks
KVM: arm64: Plumb HCRX_EL2.SRMASKEn in HCRX_EL2 sanitisation
KVM: arm64: Classify CPTR_EL2 as a SR_LOC_SPECIAL register
KVM: arm64: Don't evaluate HCR_EL2.NV on ERET fast path
arm64: Add ARM64_HAS_NV2P1 capability
KVM: arm64: Relax CPTR_EL2 handling when FEAT_NV2p1 is present
KVM: arm64: Relax CNTHCTL_EL2 handling when FEAT_NV2p1 is present
KVM: arm64: Expose FEAT_NV2p1 to NV guests
arm64: Add FEAT_NV2p1 detection
arm64: sysreg: Add NVHCR_EL2 description as a mirror of HCR_EL2
arm64: sysreg: Add HCRX_EL2 bits related to FEAT_NV3
arm64: Add ARM64_HAS_NV3 capability
KVM: arm64: Split NV-specific exit fixups from the non-NV handling
KVM: arm64: Add NV3 control bits to HCRX_EL2 sanitisation
KVM: arm64: Add kvm_has_nv{2,3}() predicates
KVM: arm64: Make HCR_EL2 a non-VNCR register
KVM: arm64: Add sanitisation for NVHCR_EL2
KVM: arm64: Add NVHCR_EL2 handling to the sysreg array
KVM: arm64: Add routing for NVHCR_EL2 trap
KVM: arm64: Add NVHCR_EL2 context switching
KVM: arm64: Engage NV3 ERET trap elision
KVM: arm64: Engage NV3 TLBI trap elision
KVM: arm64: Add FEAT_NV3 detection
KVM: arm64: Expose FEAT_NV3 to guests
arm64: Add override for ID_AA64MMFR4_EL1.NV_frac
arch/arm64/include/asm/cpufeature.h | 1 +
arch/arm64/include/asm/kvm_arm.h | 15 ------
arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++-
arch/arm64/include/asm/kvm_host.h | 3 +-
arch/arm64/include/asm/vncr_mapping.h | 2 +-
arch/arm64/kernel/cpufeature.c | 18 ++++++-
arch/arm64/kernel/image-vars.h | 1 +
arch/arm64/kernel/pi/idreg-override.c | 10 ++++
arch/arm64/kvm/arch_timer.c | 10 +++-
arch/arm64/kvm/config.c | 25 +++++++++-
arch/arm64/kvm/emulate-nested.c | 16 ++++--
arch/arm64/kvm/hyp/include/hyp/switch.h | 27 ++++++++--
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 11 +++++
arch/arm64/kvm/hyp/vhe/switch.c | 44 +++++++++++++----
arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 21 +++++---
arch/arm64/kvm/nested.c | 14 +++++-
arch/arm64/kvm/sys_regs.c | 57 ++++++++++++++++++++--
arch/arm64/tools/cpucaps | 2 +
arch/arm64/tools/gen-sysreg.awk | 14 ++++--
arch/arm64/tools/sysreg | 42 ++++++++++++++--
20 files changed, 313 insertions(+), 61 deletions(-)
--
2.47.3
^ permalink raw reply
* [PATCH 01/28] arm64: sysreg: Emit RESx/UNKN values for Mapping definitions
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
The sysreg file is using the Mapping qualifier to indicate that
a given encoding is only a mapping to a particular register.
As a result, we don't output any definition, and instead expect
the canonical definitions to be used.
This works rather well for individual fields, but creates problems
for macros that refer to more generic classes of bits such as RESx.
Relax the above rule by emitting the RESx and UNKN values for Mapping
qualifiers as well.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/tools/gen-sysreg.awk | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk
index 86860ab672dc7..d7f7ceb768fe5 100755
--- a/arch/arm64/tools/gen-sysreg.awk
+++ b/arch/arm64/tools/gen-sysreg.awk
@@ -228,7 +228,7 @@ $1 == "EndSysreg" && block_current() == "Sysreg" {
}
# Currently this is effectivey a comment, in future we may want to emit
-# defines for the fields.
+# defines for the fields. "Mapping" does emit the RESx/UNKN definitions.
($1 == "Fields" || $1 == "Mapping") && block_current() == "Sysreg" {
expect_fields(2)
@@ -239,9 +239,15 @@ $1 == "EndSysreg" && block_current() == "Sysreg" {
print ""
next_bit = -1
- res0 = null
- res1 = null
- unkn = null
+ if ($1 == "Mapping") {
+ res0 = $2 "_RES0"
+ res1 = $2 "_RES1"
+ unkn = $2 "_UNKN"
+ } else {
+ res0 = null
+ res1 = null
+ unkn = null
+ }
next
}
--
2.47.3
^ permalink raw reply related
* [PATCH 04/28] KVM: arm64: Drop __HCRX_EL2_* masks
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
The __HCRX_EL2_* masks are a leftover from a time where we didn't
have much sanitisation for the system registers. Since we are now
in a better place, rely on the existing checks to detect unhandled
bits in HCRX_EL2.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_arm.h | 15 ---------------
arch/arm64/kvm/config.c | 3 +--
arch/arm64/kvm/emulate-nested.c | 5 -----
3 files changed, 1 insertion(+), 22 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 3f9233b5a1308..f6cd851047947 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -287,21 +287,6 @@
GENMASK(19, 18) | \
GENMASK(15, 0))
-/*
- * Polarity masks for HCRX_EL2, limited to the bits that we know about
- * at this point in time. It doesn't mean that we actually *handle*
- * them, but that at least those that are not advertised to a guest
- * will be RES0 for that guest.
- */
-#define __HCRX_EL2_MASK (BIT_ULL(6))
-#define __HCRX_EL2_nMASK (GENMASK_ULL(24, 14) | \
- GENMASK_ULL(11, 7) | \
- GENMASK_ULL(5, 0))
-#define __HCRX_EL2_RES0 ~(__HCRX_EL2_nMASK | __HCRX_EL2_MASK)
-#define __HCRX_EL2_RES1 ~(__HCRX_EL2_nMASK | \
- __HCRX_EL2_MASK | \
- __HCRX_EL2_RES0)
-
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
#define HPFAR_MASK (~UL(0xf))
/*
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 0622162b089e5..16d8148dc3f12 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -933,7 +933,7 @@ static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
};
-static const DECLARE_FEAT_MAP(hcrx_desc, __HCRX_EL2,
+static const DECLARE_FEAT_MAP(hcrx_desc, HCRX_EL2,
hcrx_feat_map, FEAT_HCX);
static const struct reg_bits_to_feat_map hcr_feat_map[] = {
@@ -1579,7 +1579,6 @@ struct resx get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg)
break;
case HCRX_EL2:
resx = compute_reg_resx_bits(kvm, &hcrx_desc, 0, 0);
- resx.res1 |= __HCRX_EL2_RES1;
break;
case HCR_EL2:
resx = compute_reg_resx_bits(kvm, &hcr_desc, 0, 0);
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 3c82f392845d1..b7f3d86a94031 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2320,7 +2320,6 @@ int __init populate_nv_trap_config(void)
BUILD_BUG_ON(__NR_CGT_GROUP_IDS__ > BIT(TC_CGT_BITS));
BUILD_BUG_ON(__NR_FGT_GROUP_IDS__ > BIT(TC_FGT_BITS));
BUILD_BUG_ON(__NR_FG_FILTER_IDS__ > BIT(TC_FGF_BITS));
- BUILD_BUG_ON(__HCRX_EL2_MASK & __HCRX_EL2_nMASK);
for (int i = 0; i < ARRAY_SIZE(encoding_to_cgt); i++) {
const struct encoding_to_trap_config *cgt = &encoding_to_cgt[i];
@@ -2346,10 +2345,6 @@ int __init populate_nv_trap_config(void)
}
}
- if (__HCRX_EL2_RES0 != HCRX_EL2_RES0)
- kvm_info("Sanitised HCR_EL2_RES0 = %016llx, expecting %016llx\n",
- __HCRX_EL2_RES0, HCRX_EL2_RES0);
-
kvm_info("nv: %ld coarse grained trap handlers\n",
ARRAY_SIZE(encoding_to_cgt));
--
2.47.3
^ permalink raw reply related
* [PATCH 03/28] KVM: arm64: Merge guest's HCRX_EL2 using NV_HCRX_GUEST_EXCLUDE
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
The way we merge the guest-provided HCRX_EL2 value with the host's
is bonkers. We try to make it look like the FGT registers by using
positive and negative polarities for traps, but most of these bits
are not strictly about trapping, as they actively change the way
some architectural state is managed.
It would be far better to deal with these bits like we do for
HCR_EL2, by enumerating the list of bits we don't allow the guest
to override. This is simplified by the fact that HCRX_EL2 only
affects EL1, and not EL2.
Re-jig the HCRX_EL2 handling with a macro that list the bits excluded
from the merge (TMEA, PTTWI, EnIDCP128).
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/hyp/include/hyp/switch.h | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 4bf624a49591d..8e5f492f39086 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -325,6 +325,24 @@ static inline void __deactivate_traps_mpam(void)
write_sysreg_s(MPAMHCR_HOST_FLAGS, SYS_MPAMHCR_EL2);
}
+/*
+ * Just like for HCR_EL2, we can't let the guest mess with some of the
+ * basics we rely on in HCRX_EL2. However, the major difference is that
+ * HCRX_EL2 only affects EL1, and never EL2 (sudden outburst of sanity, I
+ * guess). So it is always the guest inflicting it on its own guestx.
+ *
+ * Things we don't want to let the guest control are:
+ *
+ * - TMEA: That's for us to decide how an SEA is routed, not the guest.
+ *
+ * - PTTWI: Similarly, it is for us to decide whether Reduced Coherency for
+ * the PTW is a thing. It really isn't.
+ *
+ * - EnIDCP128: We don't allow IMPDEF sysregs -- full stop.
+ */
+#define NV_HCRX_GUEST_EXCLUDE (HCRX_EL2_TMEA | HCRX_EL2_PTTWI | \
+ HCRX_EL2_EnIDCP128)
+
static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
{
struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
@@ -350,8 +368,8 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
u64 hcrx = vcpu->arch.hcrx_el2;
if (is_nested_ctxt(vcpu)) {
u64 val = __vcpu_sys_reg(vcpu, HCRX_EL2);
- hcrx |= val & __HCRX_EL2_MASK;
- hcrx &= ~(~val & __HCRX_EL2_nMASK);
+ hcrx |= (val & ~NV_HCRX_GUEST_EXCLUDE);
+ hcrx &= ~(~val & ~NV_HCRX_GUEST_EXCLUDE);
}
ctxt_sys_reg(hctxt, HCRX_EL2) = read_sysreg_s(SYS_HCRX_EL2);
--
2.47.3
^ permalink raw reply related
* [PATCH 02/28] arm64: Update ID_AA64MMFR4_EL1 description to 2026-03 JSON release
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
ID_AA64MMFR4_EL1 has gained a few fields and enum values in the past
few months, so resync its definition with the 2026-03 JSON release.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/tools/sysreg | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index bc1788b1662b7..32e2f9856768b 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -2386,17 +2386,40 @@ EndEnum
EndSysreg
Sysreg ID_AA64MMFR4_EL1 3 0 0 7 4
-Res0 63:48
+UnsignedEnum 63:60 MTEFGT
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+UnsignedEnum 59:56 SCRX
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+UnsignedEnum 55:52 TEV
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+UnsignedEnum 51:48 TPS
+ 0b0000 VAL_0000
+ 0b0001 VAL_0001
+ 0b0010 VAL_0010
+EndEnum
UnsignedEnum 47:44 SRMASK
0b0000 NI
0b0001 IMP
+ 0b0010 SRMASK2
+EndEnum
+UnsignedEnum 43:40 TLBID
+ 0b0000 NI
+ 0b0001 IMP
EndEnum
-Res0 43:40
UnsignedEnum 39:36 E3DSE
0b0000 NI
0b0001 IMP
EndEnum
-Res0 35:32
+UnsignedEnum 35:32 EAESR
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
UnsignedEnum 31:28 RMEGDI
0b0000 NI
0b0001 IMP
@@ -2410,6 +2433,7 @@ UnsignedEnum 23:20 NV_frac
0b0000 NV_NV2
0b0001 NV2_ONLY
0b0010 NV2P1
+ 0b0011 NV3
EndEnum
UnsignedEnum 19:16 FGWTE3
0b0000 NI
--
2.47.3
^ permalink raw reply related
* [PATCH 06/28] KVM: arm64: Classify CPTR_EL2 as a SR_LOC_SPECIAL register
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
It may not be obvious unless you look at it closely, but CPTR_EL2
is treated very differently from other registers. It is one the
registers that, despite looking very similar between EL1 and EL2
when E2H==1, have RES0 bits that get in the way.
Make it clear that CPTR_EL2 is odd by classifying it as SR_LOC_SPECIAL,
just like CNTHCTL_EL2 (and for the same reasons). This makes it
possible to use vcpu_read_sys_reg() with it, and will be necessary
once we support FEAT_NV2P1.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_emulate.h | 2 +-
arch/arm64/kvm/sys_regs.c | 20 ++++++++++++++++++--
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 5bf3d7e1d92c7..9831166695186 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -617,7 +617,7 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
*/
static inline u64 vcpu_sanitised_cptr_el2(const struct kvm_vcpu *vcpu)
{
- u64 cptr = __vcpu_sys_reg(vcpu, CPTR_EL2);
+ u64 cptr = vcpu_read_sys_reg(vcpu, CPTR_EL2);
if (!vcpu_el2_e2h_is_set(vcpu))
cptr = translate_cptr_el2_to_cpacr_el1(cptr);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 5d5c579d45790..6b47d936efb32 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -183,8 +183,6 @@ static void locate_register(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg,
switch (reg) {
MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1,
translate_sctlr_el2_to_sctlr_el1 );
- MAPPED_EL2_SYSREG(CPTR_EL2, CPACR_EL1,
- translate_cptr_el2_to_cpacr_el1 );
MAPPED_EL2_SYSREG(TTBR0_EL2, TTBR0_EL1,
translate_ttbr0_el2_to_ttbr0_el1 );
MAPPED_EL2_SYSREG(TTBR1_EL2, TTBR1_EL1, NULL );
@@ -210,6 +208,19 @@ static void locate_register(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg,
loc->loc = ((is_hyp_ctxt(vcpu) && vcpu_el2_e2h_is_set(vcpu)) ?
SR_LOC_SPECIAL : SR_LOC_MEMORY);
break;
+ case CPTR_EL2:
+ /*
+ * CPTR_EL2 is just as special, and needs a certain amount
+ * of handholding. It always lives in memory, due to being
+ * heavily trapped thanks to CPACR_EL1.TCPAC being RES0.
+ * FEAT_NV2p1 fixes this.
+ */
+ locate_mapped_el2_register(vcpu, CPTR_EL2, CPACR_EL1,
+ translate_cptr_el2_to_cpacr_el1,
+ loc);
+ if (is_hyp_ctxt(vcpu) && vcpu_el2_e2h_is_set(vcpu))
+ loc->loc = SR_LOC_SPECIAL;
+ break;
default:
loc->loc = locate_direct_register(vcpu, reg);
}
@@ -314,6 +325,8 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
val &= CNTKCTL_VALID_BITS;
val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS;
return val;
+ case CPTR_EL2:
+ return __vcpu_sys_reg(vcpu, reg);
default:
WARN_ON_ONCE(1);
}
@@ -359,6 +372,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, enum vcpu_sysreg reg)
*/
write_sysreg_el1(val, SYS_CNTKCTL);
break;
+ case CPTR_EL2:
+ write_sysreg_el1(val, SYS_CPACR);
+ break;
default:
WARN_ON_ONCE(1);
}
--
2.47.3
^ permalink raw reply related
* [PATCH 05/28] KVM: arm64: Plumb HCRX_EL2.SRMASKEn in HCRX_EL2 sanitisation
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
HCRX_EL2.SRMASKEn is a new bit enabling FEAT_SRMASK for a guest.
We don't plan to support it any time soon, but it doesn't hurt to
actively document it, specially as we are going to add more bits
we actually care about.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 1 +
arch/arm64/tools/sysreg | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 16d8148dc3f12..8d5e4aacf49c4 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -904,6 +904,7 @@ static const DECLARE_FEAT_MAP_FGT(hdfgwtr2_desc, hdfgwtr2_masks,
static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
+ NEEDS_FEAT(HCRX_EL2_SRMASKEn, FEAT_SRMASK),
NEEDS_FEAT(HCRX_EL2_PACMEn, feat_pauth_lr),
NEEDS_FEAT(HCRX_EL2_EnFPM, FEAT_FPMR),
NEEDS_FEAT(HCRX_EL2_GCSEn, FEAT_GCS),
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 32e2f9856768b..c6e8117a6f9cd 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4545,7 +4545,9 @@ Fields ZCR_ELx
EndSysreg
Sysreg HCRX_EL2 3 4 1 2 2
-Res0 63:25
+Res0 63:27
+Field 26 SRMASKEn
+Res0 25
Field 24 PACMEn
Field 23 EnFPM
Field 22 GCSEn
--
2.47.3
^ permalink raw reply related
* [PATCH 14/28] arm64: sysreg: Add HCRX_EL2 bits related to FEAT_NV3
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
FEAT_NV3 introduces 4 new HCRX_EL2 control bits. Describe them
in the sysreg file.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/tools/sysreg | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 31e4ea455a9ce..afe9337851a2e 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4548,7 +4548,12 @@ Fields ZCR_ELx
EndSysreg
Sysreg HCRX_EL2 3 4 1 2 2
-Res0 63:27
+Res0 63:35
+Field 34 NVnTTLBOS
+Field 33 NVnTTLBIS
+Field 32 NVnTTLB
+Res0 31:28
+Field 27 NVTGE
Field 26 SRMASKEn
Res0 25
Field 24 PACMEn
--
2.47.3
^ permalink raw reply related
* [PATCH 09/28] KVM: arm64: Relax CPTR_EL2 handling when FEAT_NV2p1 is present
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
With FEAT_NV2P1, it is no longer necessary to trap CPTR_EL2 accesses
via CPACR_EL1, as CPACR_EL1.TCPAC is guaranteed to be stateful.
Prevent such trapping and context switch CPACTR_EL1 in NV contexts
when NV2P1 is present.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/hyp/include/hyp/switch.h | 5 +++--
arch/arm64/kvm/hyp/vhe/switch.c | 3 +++
arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 8 +++++---
arch/arm64/kvm/sys_regs.c | 5 ++++-
4 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 8e5f492f39086..7b27296c94607 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -108,9 +108,10 @@ static inline void __activate_cptr_traps_vhe(struct kvm_vcpu *vcpu)
* The architecture is a bit crap (what a surprise): an EL2 guest
* writing to CPTR_EL2 via CPACR_EL1 can't set any of TCPAC or TTA,
* as they are RES0 in the guest's view. To work around it, trap the
- * sucker using the very same bit it can't set...
+ * sucker using the very same bit it can't set. FEAT_NV2p1 fixes it.
*/
- if (vcpu_el2_e2h_is_set(vcpu) && is_hyp_ctxt(vcpu))
+ if (!cpus_have_final_cap(ARM64_HAS_NV2P1) &&
+ vcpu_el2_e2h_is_set(vcpu) && is_hyp_ctxt(vcpu))
val |= CPTR_EL2_TCPAC;
/*
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 3b76e0468317b..361d3f8344dd8 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -441,6 +441,9 @@ static bool kvm_hyp_handle_cpacr_el1(struct kvm_vcpu *vcpu, u64 *exit_code)
u64 esr = kvm_vcpu_get_esr(vcpu);
int rt;
+ if (cpus_have_final_cap(ARM64_HAS_NV2P1))
+ return false;
+
if (!is_hyp_ctxt(vcpu) || esr_sys64_to_sysreg(esr) != SYS_CPACR_EL1)
return false;
diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
index be685b63e8cf2..6f0f046e4ca4e 100644
--- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c
@@ -42,10 +42,12 @@ static void __sysreg_save_vel2_state(struct kvm_vcpu *vcpu)
u64 val;
/*
- * We don't save CPTR_EL2, as accesses to CPACR_EL1
- * are always trapped, ensuring that the in-memory
- * copy is always up-to-date. A small blessing...
+ * Without FEAT_NV2p1, we don't save CPTR_EL2, as accesses
+ * to CPACR_EL1 are always trapped, ensuring that the
+ * in-memory copy is always up-to-date. A small blessing...
*/
+ if (cpus_have_final_cap(ARM64_HAS_NV2P1))
+ __vcpu_assign_sys_reg(vcpu, CPTR_EL2, read_sysreg_el1(SYS_CPACR));
__vcpu_assign_sys_reg(vcpu, SCTLR_EL2, read_sysreg_el1(SYS_SCTLR));
__vcpu_assign_sys_reg(vcpu, TTBR0_EL2, read_sysreg_el1(SYS_TTBR0));
__vcpu_assign_sys_reg(vcpu, TTBR1_EL2, read_sysreg_el1(SYS_TTBR1));
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 6b47d936efb32..1dfc1f88bec82 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -326,7 +326,10 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS;
return val;
case CPTR_EL2:
- return __vcpu_sys_reg(vcpu, reg);
+ if (cpus_have_final_cap(ARM64_HAS_NV2P1))
+ return read_sysreg_el1(SYS_CPACR);
+ else
+ return __vcpu_sys_reg(vcpu, reg);
default:
WARN_ON_ONCE(1);
}
--
2.47.3
^ permalink raw reply related
* [PATCH 18/28] KVM: arm64: Add kvm_has_nv{2,3}() predicates
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
Add a new set of predicates indicating whether VM is capable of
NV2, NV3, and is in a nested NV3 context.
This is going to become useful as we start dealing with a mix of
behaviours (NV2, NV3, NV2 on NV3...).
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_emulate.h | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9831166695186..c562d8171d5e1 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -266,6 +266,26 @@ static inline bool vserror_state_is_nested(struct kvm_vcpu *vcpu)
(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TMEA);
}
+static inline bool kvm_has_nv2(struct kvm *kvm)
+{
+ return (cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) &&
+ kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY));
+}
+
+static inline bool kvm_has_nv3(struct kvm *kvm)
+{
+ return (cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) &&
+ cpus_have_final_cap(ARM64_HAS_NV3) &&
+ kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV3));
+}
+
+static inline bool is_nested_nv3_ctxt(struct kvm_vcpu *vcpu)
+{
+ return (has_vhe() && kvm_has_nv3(vcpu->kvm) && is_nested_ctxt(vcpu) &&
+ (__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_EL2_NV) &&
+ (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_NVTGE));
+}
+
/*
* The layout of SPSR for an AArch32 state is different when observed from an
* AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
--
2.47.3
^ permalink raw reply related
* [PATCH 22/28] KVM: arm64: Add routing for NVHCR_EL2 trap
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
NVHCR_EL2 accesses from EL1 are taken to EL2 when HCRX_EL2.NVTGE==0
and HCR_EL2.NV==1. Describe this in the exception routing tables.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/emulate-nested.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index b7f3d86a94031..f5dc578d8c985 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -90,6 +90,7 @@ enum cgt_group_id {
CGT_HCRX_EnFPM,
CGT_HCRX_TCR2En,
CGT_HCRX_SCTLR2En,
+ CGT_HCRX_nNVTGE,
CGT_CNTHCTL_EL1TVT,
CGT_CNTHCTL_EL1TVCT,
@@ -121,6 +122,8 @@ enum cgt_group_id {
CGT_MDCR_TDE_TDRA,
CGT_MDCR_TDCC_TDE_TDA,
+ CGT_HCR_NV_HCRX_nNVTGE,
+
CGT_ICH_HCR_TC_TDIR,
/*
@@ -413,6 +416,12 @@ static const struct trap_bits coarse_trap_bits[] = {
.mask = HCRX_EL2_SCTLR2En,
.behaviour = BEHAVE_FORWARD_RW,
},
+ [CGT_HCRX_nNVTGE] = {
+ .index = HCRX_EL2,
+ .value = 0,
+ .mask = HCRX_EL2_NVTGE,
+ .behaviour = BEHAVE_FORWARD_RW,
+ },
[CGT_CNTHCTL_EL1TVT] = {
.index = CNTHCTL_EL2,
.value = CNTHCTL_EL1TVT,
@@ -468,6 +477,7 @@ static const enum cgt_group_id *coarse_control_combo[] = {
CGT_HCR_TVM, CGT_HCR_TRVM, CGT_HCRX_SCTLR2En),
MCB(CGT_HCR_TPU_TICAB, CGT_HCR_TPU, CGT_HCR_TICAB),
MCB(CGT_HCR_TPU_TOCU, CGT_HCR_TPU, CGT_HCR_TOCU),
+ MCB(CGT_HCR_NV_HCRX_nNVTGE, CGT_HCR_NV, CGT_HCRX_nNVTGE),
MCB(CGT_HCR_NV1_nNV2_ENSCXT, CGT_HCR_NV1_nNV2, CGT_HCR_ENSCXT),
MCB(CGT_MDCR_TPM_TPMCR, CGT_MDCR_TPM, CGT_MDCR_TPMCR),
MCB(CGT_MDCR_TPM_HPMN, CGT_MDCR_TPM, CGT_MDCR_HPMN),
@@ -853,6 +863,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
SR_TRAP(SYS_SCTLR2_EL2, CGT_HCR_NV),
SR_RANGE_TRAP(SYS_HCR_EL2,
SYS_HCRX_EL2, CGT_HCR_NV),
+ SR_TRAP(SYS_NVHCR_EL2, CGT_HCR_NV_HCRX_nNVTGE),
SR_TRAP(SYS_SMPRIMAP_EL2, CGT_HCR_NV),
SR_TRAP(SYS_SMCR_EL2, CGT_HCR_NV),
SR_RANGE_TRAP(SYS_TTBR0_EL2,
--
2.47.3
^ permalink raw reply related
* [PATCH 25/28] KVM: arm64: Engage NV3 TLBI trap elision
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
Similarly to the ERET elision mechanism, FEAT_NV3 can elide TLBIs
that only affects the guest's S1 translation. Enable this, with the
express condition that the guest isn't NV2 aware, as we otherwise
need to trap these TLBIs to deal with VNCR mappings.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_emulate.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index b32870a5e1236..d6f432b1558f5 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -715,6 +715,15 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
if (cpus_have_final_cap(ARM64_HAS_NV3) &&
vcpu_has_nv(vcpu) && vcpu_el2_e2h_is_set(vcpu)) {
vcpu->arch.hcrx_el2 |= HCRX_EL2_NVTGE;
+
+ /*
+ * If the guest is NV2-capable, then we need to see
+ * all the TLBIs, as configured in HCR_EL2.
+ * Otherwise, relax the TLBI traps to only TGE=0.
+ */
+ if (!kvm_has_nv2(vcpu->kvm))
+ vcpu->arch.hcrx_el2 |= (HCRX_EL2_NVnTTLB |
+ HCRX_EL2_NVnTTLBIS);
}
}
}
--
2.47.3
^ permalink raw reply related
* [PATCH 20/28] KVM: arm64: Add sanitisation for NVHCR_EL2
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
Just like any other VNCR-based register, NVHCR_EL2 requires some
level of sanitisation. Being specified as a live copy of HCR_EL2,
it adopts the exact same format, but depends on FEAT_NV3 instead.
A subtle aspect is that we only want to apply the sanitisation if
FEAT_NV3 is actually present, as the VNCR location is otherwise
used to back accesses to HCR_EL2.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 15 +++++++++++++++
arch/arm64/kvm/nested.c | 4 ++++
2 files changed, 19 insertions(+)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index b9a9d65b973e6..7e86479142723 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1017,6 +1017,9 @@ static const struct reg_bits_to_feat_map hcr_feat_map[] = {
static const DECLARE_FEAT_MAP(hcr_desc, HCR_EL2,
hcr_feat_map, FEAT_AA64EL2);
+static const DECLARE_FEAT_MAP(nvhcr_desc, NVHCR_EL2,
+ hcr_feat_map, FEAT_NV3);
+
static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
NEEDS_FEAT(SCTLR2_EL1_NMEA |
SCTLR2_EL1_EASE,
@@ -1391,6 +1394,7 @@ void __init check_feature_map(void)
check_reg_desc(&hdfgwtr2_desc);
check_reg_desc(&hcrx_desc);
check_reg_desc(&hcr_desc);
+ check_reg_desc(&nvhcr_desc);
check_reg_desc(&sctlr2_desc);
check_reg_desc(&tcr2_el2_desc);
check_reg_desc(&sctlr_el1_desc);
@@ -1590,6 +1594,17 @@ struct resx get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg)
case HCR_EL2:
resx = compute_reg_resx_bits(kvm, &hcr_desc, 0, 0);
break;
+ case NVHCR_EL2:
+ /*
+ * Only apply sanitisation if we do have FEAT_NV3.
+ * Otherwise, the register aliases with HCR_EL2 in VNCR,
+ * and we're better off relying on data transfers between
+ * NVHCR_EL2 and HCR_EL2 to sanitise things.
+ */
+ resx = (kvm_has_nv3(kvm) ?
+ compute_reg_resx_bits(kvm, &nvhcr_desc, 0, 0) :
+ (typeof(resx)){});
+ break;
case SCTLR2_EL1:
case SCTLR2_EL2:
resx = compute_reg_resx_bits(kvm, &sctlr2_desc, 0, 0);
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 9972dea42d12a..c9bf04944f9cb 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1830,6 +1830,10 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
resx = get_reg_fixed_bits(kvm, HCR_EL2);
set_sysreg_masks(kvm, HCR_EL2, resx);
+ /* NVHCR_EL2 */
+ resx = get_reg_fixed_bits(kvm, NVHCR_EL2);
+ set_sysreg_masks(kvm, NVHCR_EL2, resx);
+
/* HCRX_EL2 */
resx = get_reg_fixed_bits(kvm, HCRX_EL2);
set_sysreg_masks(kvm, HCRX_EL2, resx);
--
2.47.3
^ permalink raw reply related
* [PATCH 15/28] arm64: Add ARM64_HAS_NV3 capability
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
As a bunch of KVM code is going to depend on FEAT_NV3 being detected
on the host, add a new capability that will describe it.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/tools/cpucaps | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 242dc211d8efa..7e0414509e89a 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -52,6 +52,7 @@ HAS_LSUI
HAS_MOPS
HAS_NESTED_VIRT
HAS_NV2P1
+HAS_NV3
HAS_BBML2_NOABORT
HAS_PAN
HAS_PMUV3
--
2.47.3
^ permalink raw reply related
* [PATCH 24/28] KVM: arm64: Engage NV3 ERET trap elision
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
When running on NV3 HW, always engage ERET trap elision when running
the L1 context, as there is no benefit in not doing so.
An L1 can itself engage trap elision by setting its own view of
HCRX_EL2.NVTGE==1, which will subsequently be honored.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
arch/arm64/kvm/hyp/vhe/switch.c | 4 ++++
2 files changed, 14 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index c562d8171d5e1..b32870a5e1236 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -706,6 +706,16 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
if (kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_V))
vcpu->arch.hcrx_el2 |= HCRX_EL2_EnASR;
+
+ /*
+ * NV3 is a host-specific extension, and we always use it
+ * when present and that the guest uses NV. It may be be
+ * hidden from the guest though.
+ */
+ if (cpus_have_final_cap(ARM64_HAS_NV3) &&
+ vcpu_has_nv(vcpu) && vcpu_el2_e2h_is_set(vcpu)) {
+ vcpu->arch.hcrx_el2 |= HCRX_EL2_NVTGE;
+ }
}
}
#endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index c5c06ae41b229..f129f22f15618 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -345,6 +345,10 @@ static bool kvm_hyp_handle_eret(struct kvm_vcpu *vcpu, u64 *exit_code)
u64 esr = kvm_vcpu_get_esr(vcpu);
u64 spsr, elr, mode;
+ /* With NV3, the fast path is handled in HW */
+ if (cpus_have_final_cap(ARM64_HAS_NV3) && vcpu_el2_e2h_is_set(vcpu))
+ return false;
+
/*
* Going through the whole put/load motions is a waste of time
* if this is a VHE guest hypervisor returning to its own
--
2.47.3
^ permalink raw reply related
* [PATCH 21/28] KVM: arm64: Add NVHCR_EL2 handling to the sysreg array
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
Expose NVHCR_EL2 to userspace, and treat the direct access as UNDEF,
as that would only outline a bug in our exception routing.
The generic accessors are also updated to deal with the relatively
uncommon location of that register.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/sys_regs.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 9439c5b2b1fe8..0aeb2e736fde3 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -221,6 +221,20 @@ static void locate_register(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg,
if (is_hyp_ctxt(vcpu) && vcpu_el2_e2h_is_set(vcpu))
loc->loc = SR_LOC_SPECIAL;
break;
+ case NVHCR_EL2:
+ /*
+ * Yes, NVHCR_EL2 maps to itself when loaded in nested
+ * context. If you feel like the architecture is double
+ * backing on itself upside down, you're not alone.
+ */
+ WARN_ON_ONCE(!kvm_has_nv3(vcpu->kvm));
+ if (is_hyp_ctxt(vcpu)) {
+ loc->loc = SR_LOC_MEMORY;
+ } else {
+ loc->loc = SR_LOC_LOADED | SR_LOC_MAPPED;
+ loc->map_reg = NVHCR_EL2;
+ }
+ break;
default:
loc->loc = locate_direct_register(vcpu, reg);
}
@@ -260,6 +274,7 @@ static u64 read_sr_from_cpu(enum vcpu_sysreg reg)
case DACR32_EL2: val = read_sysreg_s(SYS_DACR32_EL2); break;
case IFSR32_EL2: val = read_sysreg_s(SYS_IFSR32_EL2); break;
case DBGVCR32_EL2: val = read_sysreg_s(SYS_DBGVCR32_EL2); break;
+ case NVHCR_EL2: val = read_sysreg_s(SYS_NVHCR_EL2); break;
default: WARN_ON_ONCE(1);
}
@@ -298,6 +313,7 @@ static void write_sr_to_cpu(enum vcpu_sysreg reg, u64 val)
case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break;
case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break;
case DBGVCR32_EL2: write_sysreg_s(val, SYS_DBGVCR32_EL2); break;
+ case NVHCR_EL2: write_sysreg_s(val, SYS_NVHCR_EL2); break;
default: WARN_ON_ONCE(1);
}
}
@@ -2861,6 +2877,16 @@ static unsigned int vncr_el2_visibility(const struct kvm_vcpu *vcpu,
return REG_HIDDEN;
}
+static unsigned int nvhcr_el2_visibility(const struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
+{
+ if (el2_visibility(vcpu, rd) == 0 &&
+ kvm_has_feat(vcpu->kvm, ID_AA64MMFR4_EL1, NV_frac, NV3))
+ return 0;
+
+ return REG_HIDDEN;
+}
+
static unsigned int sctlr2_visibility(const struct kvm_vcpu *vcpu,
const struct sys_reg_desc *rd)
{
@@ -3774,6 +3800,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
sve_el2_visibility),
EL2_REG_VNCR(HCRX_EL2, reset_val, 0),
+ EL2_REG_FILTERED(NVHCR_EL2, undef_access, reset_val, 0,
+ nvhcr_el2_visibility),
EL2_REG(TTBR0_EL2, access_rw, reset_val, 0),
EL2_REG(TTBR1_EL2, access_rw, reset_val, 0),
--
2.47.3
^ permalink raw reply related
* [PATCH 23/28] KVM: arm64: Add NVHCR_EL2 context switching
From: Marc Zyngier @ 2026-07-02 16:02 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260702160248.1377250-1-maz@kernel.org>
Since NVHCR_EL2 represents the HCR_EL2 state of the EL1 guest, it
must be dealt with in some particular way:
- for a guest in hyp context (an L1 by definition), NVHCR_EL2 directly
reflects HCR_EL2 as read and written by the guest itself. It must
therefore be eagerly synced back with the emulation code which only
knows about HCR_EL2. This is unconditional if NV3 is available on
the host.
- For an L2 guest, NVHCR_EL2 is controlled by the L1 guest, and we
just context switch it like any other EL1 register. Yes, EL1, as
that's where this thing runs from the PoV of L1. This is conditioned
on the guest using NV3.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 11 +++++++++++
arch/arm64/kvm/hyp/vhe/switch.c | 10 ++++++++--
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index a17cbe7582de9..c382848d31947 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -172,6 +172,10 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
if (ctxt_has_sctlr2(ctxt))
ctxt_sys_reg(ctxt, SCTLR2_EL1) = read_sysreg_el1(SYS_SCTLR2);
+
+ /* Retrieve L2's HCR_EL2, and save it for future use */
+ if (is_nested_nv3_ctxt(ctxt_to_vcpu(ctxt)))
+ ctxt_sys_reg(ctxt, NVHCR_EL2) = read_sysreg_s(SYS_NVHCR_EL2);
}
static inline void __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
@@ -285,6 +289,13 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
if (ctxt_has_sctlr2(ctxt))
write_sysreg_el1(ctxt_sys_reg(ctxt, SCTLR2_EL1), SYS_SCTLR2);
+
+ /*
+ * Publish the L2 view of HCR_EL2 to the HW if L1 is using NV3.
+ * Otherwise, the data is already in place in the L1's own VNCR.
+ */
+ if (is_nested_nv3_ctxt(ctxt_to_vcpu(ctxt)))
+ write_sysreg_s(ctxt_sys_reg(ctxt, NVHCR_EL2), SYS_NVHCR_EL2);
}
/* Read the VCPU state's PSTATE, but translate (v)EL2 to EL1. */
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 05bcf8bf7f978..c5c06ae41b229 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -71,7 +71,10 @@ static u64 __compute_hcr(struct kvm_vcpu *vcpu)
hcr |= HCR_NV1;
/* Publish the guest's view of HCR_EL2 to the HW */
- __vcpu_assign_sys_reg(vcpu, NVHCR_EL2, __vcpu_sys_reg(vcpu, HCR_EL2));
+ if (cpus_have_final_cap(ARM64_HAS_NV3) && vcpu_el2_e2h_is_set(vcpu))
+ write_sysreg_s(__vcpu_sys_reg(vcpu, HCR_EL2), SYS_NVHCR_EL2);
+ else
+ __vcpu_assign_sys_reg(vcpu, NVHCR_EL2, __vcpu_sys_reg(vcpu, HCR_EL2));
/*
* Nothing in HCR_EL2 should impact running in hypervisor
@@ -565,7 +568,10 @@ static void fixup_nv_guest_exit(struct kvm_vcpu *vcpu)
*vcpu_cpsr(vcpu) |= mode;
/* Publish the latest HCR_EL2 to the emulation */
- hcr = __vcpu_sys_reg(vcpu, NVHCR_EL2);
+ hcr = (cpus_have_final_cap(ARM64_HAS_NV3) &&
+ vcpu_el2_e2h_is_set(vcpu)) ?
+ read_sysreg_s(SYS_NVHCR_EL2) :
+ __vcpu_sys_reg(vcpu, NVHCR_EL2);
__vcpu_assign_sys_reg(vcpu, HCR_EL2, hcr);
}
--
2.47.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox