From: Suzuki K Poulose <suzuki.poulose@arm.com>
On Arm CCA, with RMM-v1.0, all MMIO regions are shared. However, in
the future, an Arm CCA-v1.0 compliant guest may be run in a lesser
privileged partition in the Realm World (with Arm CCA-v1.1 Planes
feature). In this case, some of the MMIO regions may be emulated
by a higher privileged component in the Realm world, i.e, protected.
Thus the guest must decide today, whether a given MMIO region is shared
vs Protected and create the stage1 mapping accordingly. On Arm CCA, this
detection is based on the "IPA State" (RIPAS == RIPAS_IO). Provide a
helper to run this check on a given range of MMIO.
Also, provide a arm64 helper which may be hooked in by other solutions.
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
---
New patch for v5
---
arch/arm64/include/asm/io.h | 8 ++++++++
arch/arm64/include/asm/rsi.h | 2 ++
arch/arm64/include/asm/rsi_cmds.h | 21 +++++++++++++++++++++
arch/arm64/kernel/rsi.c | 26 ++++++++++++++++++++++++++
4 files changed, 57 insertions(+)
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 1ada23a6ec19..cce445ff8e3f 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -17,6 +17,7 @@
#include <asm/early_ioremap.h>
#include <asm/alternative.h>
#include <asm/cpufeature.h>
+#include <asm/rsi.h>
/*
* Generic IO read/write. These perform native-endian accesses.
@@ -318,4 +319,11 @@ extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
unsigned long flags);
#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap
+static inline bool arm64_is_mmio_private(phys_addr_t phys_addr, size_t size)
+{
+ if (unlikely(is_realm_world()))
+ return arm64_is_protected_mmio(phys_addr, size);
+ return false;
+}
+
#endif /* __ASM_IO_H */
diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
index acba065eb00e..42ff93c7b0ba 100644
--- a/arch/arm64/include/asm/rsi.h
+++ b/arch/arm64/include/asm/rsi.h
@@ -14,6 +14,8 @@ DECLARE_STATIC_KEY_FALSE(rsi_present);
void __init arm64_rsi_init(void);
+bool arm64_is_protected_mmio(phys_addr_t base, size_t size);
+
static inline bool is_realm_world(void)
{
return static_branch_unlikely(&rsi_present);
diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index b661331c9204..fdb47f690307 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -45,6 +45,27 @@ static inline unsigned long rsi_get_realm_config(struct realm_config *cfg)
return res.a0;
}
+static inline unsigned long rsi_ipa_state_get(phys_addr_t start,
+ phys_addr_t end,
+ enum ripas *state,
+ phys_addr_t *top)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(SMC_RSI_IPA_STATE_GET,
+ start, end, 0, 0, 0, 0, 0,
+ &res);
+
+ if (res.a0 == RSI_SUCCESS) {
+ if (top)
+ *top = res.a1;
+ if (state)
+ *state = res.a2;
+ }
+
+ return res.a0;
+}
+
static inline unsigned long rsi_set_addr_range_state(phys_addr_t start,
phys_addr_t end,
enum ripas state,
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index a6495a64d9bb..d7bba4cee627 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -66,6 +66,32 @@ static void __init arm64_rsi_setup_memory(void)
}
}
+bool arm64_is_protected_mmio(phys_addr_t base, size_t size)
+{
+ enum ripas ripas;
+ phys_addr_t end, top;
+
+ /* Overflow ? */
+ if (WARN_ON(base + size <= base))
+ return false;
+
+ end = ALIGN(base + size, RSI_GRANULE_SIZE);
+ base = ALIGN_DOWN(base, RSI_GRANULE_SIZE);
+
+ while (base < end) {
+ if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top)))
+ break;
+ if (WARN_ON(top <= base))
+ break;
+ if (ripas != RSI_RIPAS_DEV)
+ break;
+ base = top;
+ }
+
+ return base >= end;
+}
+EXPORT_SYMBOL(arm64_is_protected_mmio);
+
void __init arm64_rsi_init(void)
{
if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
--
2.34.1
On 10/5/24 12:42 AM, Steven Price wrote: > From: Suzuki K Poulose <suzuki.poulose@arm.com> > > On Arm CCA, with RMM-v1.0, all MMIO regions are shared. However, in > the future, an Arm CCA-v1.0 compliant guest may be run in a lesser > privileged partition in the Realm World (with Arm CCA-v1.1 Planes > feature). In this case, some of the MMIO regions may be emulated > by a higher privileged component in the Realm world, i.e, protected. > > Thus the guest must decide today, whether a given MMIO region is shared > vs Protected and create the stage1 mapping accordingly. On Arm CCA, this > detection is based on the "IPA State" (RIPAS == RIPAS_IO). Provide a > helper to run this check on a given range of MMIO. > > Also, provide a arm64 helper which may be hooked in by other solutions. > > Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> > Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> > Signed-off-by: Steven Price <steven.price@arm.com> > --- > New patch for v5 > --- > arch/arm64/include/asm/io.h | 8 ++++++++ > arch/arm64/include/asm/rsi.h | 2 ++ > arch/arm64/include/asm/rsi_cmds.h | 21 +++++++++++++++++++++ > arch/arm64/kernel/rsi.c | 26 ++++++++++++++++++++++++++ > 4 files changed, 57 insertions(+) > With the following nitpick addressed: Reviewed-by: Gavin Shan <gshan@redhat.com> > diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h > index 1ada23a6ec19..cce445ff8e3f 100644 > --- a/arch/arm64/include/asm/io.h > +++ b/arch/arm64/include/asm/io.h > @@ -17,6 +17,7 @@ > #include <asm/early_ioremap.h> > #include <asm/alternative.h> > #include <asm/cpufeature.h> > +#include <asm/rsi.h> > > /* > * Generic IO read/write. These perform native-endian accesses. > @@ -318,4 +319,11 @@ extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size, > unsigned long flags); > #define arch_memremap_can_ram_remap arch_memremap_can_ram_remap > > +static inline bool arm64_is_mmio_private(phys_addr_t phys_addr, size_t size) > +{ > + if (unlikely(is_realm_world())) > + return arm64_is_protected_mmio(phys_addr, size); > + return false; > +} > + The function names (arm64_is_{mmio_private, protected_mmio} are indicators to the MMIO region's state or property. arm64_is_mmio_private() indicates the MMIO region is 'private MMIO' while arm64_is_protected_mmio() indicates the MMIO region is 'protected MMIO'. They are equivalent and it may be worthy to unify the function names (indicators) as below. option#1 option#2 -------- -------- arm64_is_private_mmio arm64_is_protected_mmio __arm64_is_private_mmio __arm64_is_protected_mmio > #endif /* __ASM_IO_H */ > diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h > index acba065eb00e..42ff93c7b0ba 100644 > --- a/arch/arm64/include/asm/rsi.h > +++ b/arch/arm64/include/asm/rsi.h > @@ -14,6 +14,8 @@ DECLARE_STATIC_KEY_FALSE(rsi_present); > > void __init arm64_rsi_init(void); > > +bool arm64_is_protected_mmio(phys_addr_t base, size_t size); > + > static inline bool is_realm_world(void) > { > return static_branch_unlikely(&rsi_present); > diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h > index b661331c9204..fdb47f690307 100644 > --- a/arch/arm64/include/asm/rsi_cmds.h > +++ b/arch/arm64/include/asm/rsi_cmds.h > @@ -45,6 +45,27 @@ static inline unsigned long rsi_get_realm_config(struct realm_config *cfg) > return res.a0; > } > > +static inline unsigned long rsi_ipa_state_get(phys_addr_t start, > + phys_addr_t end, > + enum ripas *state, > + phys_addr_t *top) > +{ > + struct arm_smccc_res res; > + > + arm_smccc_smc(SMC_RSI_IPA_STATE_GET, > + start, end, 0, 0, 0, 0, 0, > + &res); > + > + if (res.a0 == RSI_SUCCESS) { > + if (top) > + *top = res.a1; > + if (state) > + *state = res.a2; > + } > + > + return res.a0; > +} > + > static inline unsigned long rsi_set_addr_range_state(phys_addr_t start, > phys_addr_t end, > enum ripas state, > diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c > index a6495a64d9bb..d7bba4cee627 100644 > --- a/arch/arm64/kernel/rsi.c > +++ b/arch/arm64/kernel/rsi.c > @@ -66,6 +66,32 @@ static void __init arm64_rsi_setup_memory(void) > } > } > > +bool arm64_is_protected_mmio(phys_addr_t base, size_t size) > +{ > + enum ripas ripas; > + phys_addr_t end, top; > + > + /* Overflow ? */ > + if (WARN_ON(base + size <= base)) > + return false; > + > + end = ALIGN(base + size, RSI_GRANULE_SIZE); > + base = ALIGN_DOWN(base, RSI_GRANULE_SIZE); > + > + while (base < end) { > + if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top))) > + break; > + if (WARN_ON(top <= base)) > + break; > + if (ripas != RSI_RIPAS_DEV) > + break; > + base = top; > + } > + > + return base >= end; > +} > +EXPORT_SYMBOL(arm64_is_protected_mmio); > + The function may be worthy to be renamed to __arm64_is_private_mmio, as explained as above. > void __init arm64_rsi_init(void) > { > if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC) Thanks, Gavin
On 08/10/2024 01:24, Gavin Shan wrote: > On 10/5/24 12:42 AM, Steven Price wrote: >> From: Suzuki K Poulose <suzuki.poulose@arm.com> >> >> On Arm CCA, with RMM-v1.0, all MMIO regions are shared. However, in >> the future, an Arm CCA-v1.0 compliant guest may be run in a lesser >> privileged partition in the Realm World (with Arm CCA-v1.1 Planes >> feature). In this case, some of the MMIO regions may be emulated >> by a higher privileged component in the Realm world, i.e, protected. >> >> Thus the guest must decide today, whether a given MMIO region is shared >> vs Protected and create the stage1 mapping accordingly. On Arm CCA, this >> detection is based on the "IPA State" (RIPAS == RIPAS_IO). Provide a >> helper to run this check on a given range of MMIO. >> >> Also, provide a arm64 helper which may be hooked in by other solutions. >> >> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> >> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> >> Signed-off-by: Steven Price <steven.price@arm.com> >> --- >> New patch for v5 >> --- >> arch/arm64/include/asm/io.h | 8 ++++++++ >> arch/arm64/include/asm/rsi.h | 2 ++ >> arch/arm64/include/asm/rsi_cmds.h | 21 +++++++++++++++++++++ >> arch/arm64/kernel/rsi.c | 26 ++++++++++++++++++++++++++ >> 4 files changed, 57 insertions(+) >> > > With the following nitpick addressed: > > Reviewed-by: Gavin Shan <gshan@redhat.com> > >> diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h >> index 1ada23a6ec19..cce445ff8e3f 100644 >> --- a/arch/arm64/include/asm/io.h >> +++ b/arch/arm64/include/asm/io.h >> @@ -17,6 +17,7 @@ >> #include <asm/early_ioremap.h> >> #include <asm/alternative.h> >> #include <asm/cpufeature.h> >> +#include <asm/rsi.h> >> /* >> * Generic IO read/write. These perform native-endian accesses. >> @@ -318,4 +319,11 @@ extern bool >> arch_memremap_can_ram_remap(resource_size_t offset, size_t size, >> unsigned long flags); >> #define arch_memremap_can_ram_remap arch_memremap_can_ram_remap >> +static inline bool arm64_is_mmio_private(phys_addr_t phys_addr, >> size_t size) >> +{ >> + if (unlikely(is_realm_world())) >> + return arm64_is_protected_mmio(phys_addr, size); >> + return false; >> +} >> + > > The function names (arm64_is_{mmio_private, protected_mmio} are > indicators to the > MMIO region's state or property. arm64_is_mmio_private() indicates the > MMIO region > is 'private MMIO' while arm64_is_protected_mmio() indicates the MMIO > region is > 'protected MMIO'. They are equivalent and it may be worthy to unify the > function > names (indicators) as below. > > option#1 option#2 > -------- -------- > arm64_is_private_mmio arm64_is_protected_mmio > __arm64_is_private_mmio __arm64_is_protected_mmio > Very valid point, I think I prefer option #2 here - "protected" is the architectural term in CCA. Thanks, Steve >> #endif /* __ASM_IO_H */ >> diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h >> index acba065eb00e..42ff93c7b0ba 100644 >> --- a/arch/arm64/include/asm/rsi.h >> +++ b/arch/arm64/include/asm/rsi.h >> @@ -14,6 +14,8 @@ DECLARE_STATIC_KEY_FALSE(rsi_present); >> void __init arm64_rsi_init(void); >> +bool arm64_is_protected_mmio(phys_addr_t base, size_t size); >> + >> static inline bool is_realm_world(void) >> { >> return static_branch_unlikely(&rsi_present); >> diff --git a/arch/arm64/include/asm/rsi_cmds.h >> b/arch/arm64/include/asm/rsi_cmds.h >> index b661331c9204..fdb47f690307 100644 >> --- a/arch/arm64/include/asm/rsi_cmds.h >> +++ b/arch/arm64/include/asm/rsi_cmds.h >> @@ -45,6 +45,27 @@ static inline unsigned long >> rsi_get_realm_config(struct realm_config *cfg) >> return res.a0; >> } >> +static inline unsigned long rsi_ipa_state_get(phys_addr_t start, >> + phys_addr_t end, >> + enum ripas *state, >> + phys_addr_t *top) >> +{ >> + struct arm_smccc_res res; >> + >> + arm_smccc_smc(SMC_RSI_IPA_STATE_GET, >> + start, end, 0, 0, 0, 0, 0, >> + &res); >> + >> + if (res.a0 == RSI_SUCCESS) { >> + if (top) >> + *top = res.a1; >> + if (state) >> + *state = res.a2; >> + } >> + >> + return res.a0; >> +} >> + >> static inline unsigned long rsi_set_addr_range_state(phys_addr_t start, >> phys_addr_t end, >> enum ripas state, >> diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c >> index a6495a64d9bb..d7bba4cee627 100644 >> --- a/arch/arm64/kernel/rsi.c >> +++ b/arch/arm64/kernel/rsi.c >> @@ -66,6 +66,32 @@ static void __init arm64_rsi_setup_memory(void) >> } >> } >> +bool arm64_is_protected_mmio(phys_addr_t base, size_t size) >> +{ >> + enum ripas ripas; >> + phys_addr_t end, top; >> + >> + /* Overflow ? */ >> + if (WARN_ON(base + size <= base)) >> + return false; >> + >> + end = ALIGN(base + size, RSI_GRANULE_SIZE); >> + base = ALIGN_DOWN(base, RSI_GRANULE_SIZE); >> + >> + while (base < end) { >> + if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top))) >> + break; >> + if (WARN_ON(top <= base)) >> + break; >> + if (ripas != RSI_RIPAS_DEV) >> + break; >> + base = top; >> + } >> + >> + return base >= end; >> +} >> +EXPORT_SYMBOL(arm64_is_protected_mmio); >> + > > The function may be worthy to be renamed to __arm64_is_private_mmio, as > explained > as above. > >> void __init arm64_rsi_init(void) >> { >> if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC) > > Thanks, > Gavin >
© 2016 - 2024 Red Hat, Inc.