[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v3 2/7] arm/mpu: Provide access to the MPU region from the C code


  • To: Julien Grall <julien@xxxxxxx>
  • From: Luca Fancellu <Luca.Fancellu@xxxxxxx>
  • Date: Mon, 14 Apr 2025 15:07:40 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=2; mx.microsoft.com 1; spf=pass (sender ip is 4.158.2.129) smtp.rcpttodomain=xen.org smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=arm.com; arc=pass (0 oda=1 ltdi=1 spf=[1,1,smtp.mailfrom=arm.com] dkim=[1,1,header.d=arm.com] dmarc=[1,1,header.from=arm.com])
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none
  • Arc-message-signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=HlK/Yp40klvIOQCZp3dUv6AIYU8qiTsge96UMtFKoBE=; b=Hu9uE+5T5WUweSlEurTeJxbNb0mbYposUc2JDJ6Y8hfdQzWab3dYQZ4q/Cd2R4GoS8Zo8b8sGBclWHmgd3N7FoFVCbigoKNMNO5Qth8xIq6oHAp49EfkmfNq2zWnjikKIdn31knaBmQ4ooV0MZzkINHZ6bxKN84fbC4gAgzDtVJrSKMsnO3FmCH1BhXyVHlmaUqieCd97UrG6edgtUrtsDIDcnq7xClzk9ISF+RAoye8skduqzddVKgyyCEss8FKtG1SFlMgnApwlR/utry+YAUC/RnOruTPuJu93hOfTH8pzTRGUi/ncDCdjRGeZvgyuz1Yn6VtGhdUGdKmWuDd+A==
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=HlK/Yp40klvIOQCZp3dUv6AIYU8qiTsge96UMtFKoBE=; b=d8cFZjVd8Z8Ssj4EJ8386Ze7alshguTVoofaCcS6psxAxVY/1A9nOcbXZJ3D15rBgPSU6aaibasiwFGGbmyWMBIQa1YTeIVMujoLIPGuix4L5n0VI+SR59bdZ7WfapJfD5rrbr7naTqFokvRnIH5DHPD4H4YFR/4BkJxAyjmsmHWJfGNDcDGaJ/yL7aca60iJXK9HqX6Gm6qIqJiWIQAxaPOeejQpd1TXkYUMr6hr4qvM8IudZZMhhw1/0DGUleImYsio4aaqoCeXzB77o2NcfDRgPllixpcaCYpCDSIaBjkMk0CIbyJOaLwZhebgv/NSjQHGbw3wZZjAy0wDcV6DQ==
  • Arc-seal: i=2; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=pass; b=LD38OKN8nSf92ahu9KytxkfhQUXfTOdWTEwis0t8SLGMOhaFwHsoJlyJ0aEmLkhKeeUkn8EOGSp9H+WSxHgqsYDLrlmtpu7FAjKVA6rLWLhSIlc6R7lEE7Z4kRxj2NnFCcNYfmdodSNxBQfR/7S+kBzUaqqMjIoGzB1zFkrD5wyLxBB8R8OPIEcQKftbJEXesZZM6t/ZEF2V3A3R7rAUvzQMxW2nkrXrHT+/gOhSSmKHTqCfe7j6TtxmUAs+BqzrCAasOrEnIoRBR7+F6JKf6QZxOwmwFV9DUmzBJw6wVSO1zIrbK+U8VOgnHLAnI+vxnghITa0swyUczw8vWPrdYA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=LtOMoq4WHjNLJygq/DyLW5GAiLvdC1grfFnHL9Ou+mtS+laZKCDUS2uc09hZEuoO4R8Dq80iQ2YcAPtCuLJUHBbKIzBLi6fqG/ynFUU1ksiolQlzfooFz6CRqd/3gw0NrH8akEoNFoS093efDIxQ9CxPRHcQtAGQHpUmROJrd6BvUEhq992/Wucqb/pxQQssa7FWc/BvNLCU3/Y8qGtk/jAaXbHv/dDoR4vz2GMkc+55ZqDQ5QwdoOfoEYvSzg+ZJjZIVoP1ZVM2AF4+sHPFPh4NHlYNgxHTQYrjL6cOUke1t1JbjniNPJ1Ste9WTSvMnXmnGdebTeLQPAQDjL8Vsg==
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Bertrand Marquis <Bertrand.Marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Delivery-date: Mon, 14 Apr 2025 15:08:26 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Thread-index: AQHbqvIQLPZqfCHfmUu6hn1OCHotk7OjDmYAgAA5foA=
  • Thread-topic: [PATCH v3 2/7] arm/mpu: Provide access to the MPU region from the C code

HI Julien,

> On 14 Apr 2025, at 12:41, Julien Grall <julien@xxxxxxx> wrote:
> 
> Hi Luca,
> 
> On 11/04/2025 23:56, Luca Fancellu wrote:
>> Implement some utility function in order to access the MPU regions
>> from the C world.
>> Signed-off-by: Luca Fancellu <luca.fancellu@xxxxxxx>
>> ---
>> v3 changes:
>>  - Moved PRBAR0_EL2/PRLAR0_EL2 to arm64 specific
>>  - Modified prepare_selector() to be easily made a NOP
>>    for Arm32, which can address up to 32 region without
>>    changing selector and it is also its maximum amount
>>    of MPU regions.
>> ---
>> ---
>>  xen/arch/arm/include/asm/arm64/mpu.h |   7 ++
>>  xen/arch/arm/include/asm/mpu.h       |   1 +
>>  xen/arch/arm/include/asm/mpu/mm.h    |  24 +++++
>>  xen/arch/arm/mpu/mm.c                | 125 +++++++++++++++++++++++++++
>>  4 files changed, 157 insertions(+)
>> diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
>> b/xen/arch/arm/include/asm/arm64/mpu.h
>> index 4d2bd7d7877f..b4e1ecdf741d 100644
>> --- a/xen/arch/arm/include/asm/arm64/mpu.h
>> +++ b/xen/arch/arm/include/asm/arm64/mpu.h
>> @@ -8,6 +8,13 @@
>>    #ifndef __ASSEMBLY__
>>  +/*
>> + * The following are needed for the case generators 
>> GENERATE_WRITE_PR_REG_CASE
>> + * and GENERATE_READ_PR_REG_CASE with num==0
>> + */
>> +#define PRBAR0_EL2 PRBAR_EL2
>> +#define PRLAR0_EL2 PRLAR_EL2
> 
> Rather than aliasing, shouldn't we just rename PR{B,L}AR_EL2 to 
> PR{B,L}AR0_EL2? This would the code mixing between the two.

PR{B,L}AR0_ELx does not exists really, the PR{B,L}AR<n>_ELx exists for n=1..15, 
here I’m only using this “alias” for the generator,
but PR{B,L}AR_EL2 are the real register.

> 
>> +
>>  /* Protection Region Base Address Register */
>>  typedef union {
>>      struct __packed {
>> diff --git a/xen/arch/arm/include/asm/mpu.h b/xen/arch/arm/include/asm/mpu.h
>> index e148c705b82c..59ff22c804c1 100644
>> --- a/xen/arch/arm/include/asm/mpu.h
>> +++ b/xen/arch/arm/include/asm/mpu.h
>> @@ -13,6 +13,7 @@
>>  #define MPU_REGION_SHIFT  6
>>  #define MPU_REGION_ALIGN  (_AC(1, UL) << MPU_REGION_SHIFT)
>>  #define MPU_REGION_MASK   (~(MPU_REGION_ALIGN - 1))
>> +#define MPU_REGION_RES0   (0xFFFULL << 52)
>>    #define NUM_MPU_REGIONS_SHIFT   8
>>  #define NUM_MPU_REGIONS         (_AC(1, UL) << NUM_MPU_REGIONS_SHIFT)
>> diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
>> b/xen/arch/arm/include/asm/mpu/mm.h
>> index 86f33d9836b7..5cabe9d111ce 100644
>> --- a/xen/arch/arm/include/asm/mpu/mm.h
>> +++ b/xen/arch/arm/include/asm/mpu/mm.h
>> @@ -8,6 +8,7 @@
>>  #include <xen/page-size.h>
>>  #include <xen/types.h>
>>  #include <asm/mm.h>
>> +#include <asm/mpu.h>
>>    extern struct page_info *frame_table;
>>  @@ -29,6 +30,29 @@ static inline struct page_info *virt_to_page(const void 
>> *v)
>>      return mfn_to_page(mfn);
>>  }
>>  +/* Utility function to be used whenever MPU regions are modified */
>> +static inline void context_sync_mpu(void)
>> +{
>> +    /*
>> +     * ARM DDI 0600B.a, C1.7.1
>> +     * Writes to MPU registers are only guaranteed to be visible following a
>> +     * Context synchronization event and DSB operation.
> 
> I know we discussed about this before. I find odd that the specification says 
> "context synchronization event and DSB operation". At least to me, it implies 
> "isb + dsb" not the other way around. Has this been clarified in newer 
> version of the specification?

unfortunately no, I’m looking into the latest one (Arm® Architecture Reference 
Manual Supplement Armv8, for R-profile AArch64 architecture 0600B.a) but it has 
the same wording, however
I spoke internally with Cortex-R architects and they told me to use DSB+ISB

> 
>> +     */
>> +    dsb(sy);
>> +    isb();
>> +}
>> +
>> +/*
>> + * The following API require context_sync_mpu() after being used to modifiy 
>> MPU
> 
> typo: s/require/requires/ and s/modifiy/modify/
> 
>> + * regions:
>> + *  - write_protection_region
>> + */
>> +
>> +/* Reads the MPU region with index 'sel' from the HW */
>> +extern void read_protection_region(pr_t *pr_read, uint8_t sel);
> 
> I am probably missing something. But don't you have a copy of pr_t in 
> xen_mpumap? If so, can't we use the cached version to avoid accessing the 
> system registers?

This API is meant to read/write registers, last patch uses it to populate 
xen_mpumap, along the tree it is also used in dump_hyp_walk, probably given 
your comment to the
last patch, if we need to update the xen_mpumap from the asm code, this could 
change.

> 
>> +/* Writes the MPU region with index 'sel' to the HW */
>> +extern void write_protection_region(const pr_t *pr_write, uint8_t sel);
>> +
>>  #endif /* __ARM_MPU_MM_H__ */
>>    /*
>> diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
>> index f83ce04fef8a..e522ce53c357 100644
>> --- a/xen/arch/arm/mpu/mm.c
>> +++ b/xen/arch/arm/mpu/mm.c
>> @@ -8,12 +8,30 @@
>>  #include <xen/sizes.h>
>>  #include <xen/types.h>
>>  #include <asm/mpu.h>
>> +#include <asm/mpu/mm.h>
>> +#include <asm/sysregs.h>
>>    struct page_info *frame_table;
>>    /* EL2 Xen MPU memory region mapping table. */
>>  pr_t xen_mpumap[MAX_MPU_REGIONS];
>>  +#define GENERATE_WRITE_PR_REG_CASE(num, pr)                                
>>  \
>> +    case num:                                                               
>> \
>> +    {                                                                       
>> \
>> +        WRITE_SYSREG(pr->prbar.bits & ~MPU_REGION_RES0, PRBAR##num##_EL2);  
>> \
>> +        WRITE_SYSREG(pr->prlar.bits & ~MPU_REGION_RES0, PRLAR##num##_EL2);  
>> \
>> +        break;                                                              
>> \
>> +    }
>> +
>> +#define GENERATE_READ_PR_REG_CASE(num, pr)                      \
>> +    case num:                                                   \
>> +    {                                                           \
>> +        pr->prbar.bits = READ_SYSREG(PRBAR##num##_EL2);         \
>> +        pr->prlar.bits = READ_SYSREG(PRLAR##num##_EL2);         \
>> +        break;                                                  \
>> +    }
>> +
>>  static void __init __maybe_unused build_assertions(void)
>>  {
>>      /*
>> @@ -24,6 +42,113 @@ static void __init __maybe_unused build_assertions(void)
>>      BUILD_BUG_ON(PAGE_SIZE != SZ_4K);
>>  }
>>  +static void prepare_selector(uint8_t *sel)
>> +{
>> +    uint8_t cur_sel = *sel;
> 
> Coding style: Missing newline.

will fix

> 
>> +    /*
>> +     * {read,write}_protection_region works using the direct access to the 
>> 0..15
>> +     * regions, so in order to save the isb() overhead, change the 
>> PRSELR_EL2
>> +     * only when needed, so when the upper 4 bits of the selector will 
>> change.
>> +     */
>> +    cur_sel &= 0xF0U;
>> +    if ( READ_SYSREG(PRSELR_EL2) != cur_sel )
>> +    {
>> +        WRITE_SYSREG(cur_sel, PRSELR_EL2);
>> +        isb();
>> +    }
>> +    *sel = *sel & 0xFU;
>> +}
>> +
>> +/*
>> + * Armv8-R AArch64 at most supports 255 MPU protection regions.
>> + * See section G1.3.18 of the reference manual for Armv8-R AArch64,
>> + * PRBAR<n>_EL2 and PRLAR<n>_EL2 provide access to the EL2 MPU region
>> + * determined by the value of 'n' and PRSELR_EL2.REGION as
>> + * PRSELR_EL2.REGION<7:4>:n(n = 0, 1, 2, ... , 15)
>> + * For example to access regions from 16 to 31 (0b10000 to 0b11111):
>> + * - Set PRSELR_EL2 to 0b1xxxx
>> + * - Region 16 configuration is accessible through PRBAR_EL2 and PRLAR_EL2
>> + * - Region 17 configuration is accessible through PRBAR1_EL2 and PRLAR1_EL2
>> + * - Region 18 configuration is accessible through PRBAR2_EL2 and PRLAR2_EL2
>> + * - ...
>> + * - Region 31 configuration is accessible through PRBAR15_EL2 and 
>> PRLAR15_EL2
>> + */
> 
> I am a bit confused. This function is implemented in the common MPU code. 
> Yet, then comment only refer to 64-bit. Is the code the same on 32-bit? If 
> not, then I think this function wants to be moved in arm64/mpu/

I’ll try to reword the comment removing the arm64-only parts

> 
>> +/*
>> + * Read EL2 MPU Protection Region.
>> + *
>> + * @pr_read: mpu protection region returned by read op.
>> + * @sel: mpu protection region selector
>> + */
> 
> NIT: Usually we add documentation on the prototype in the header and not in 
> the definition.

I’ll change

> 
>> +void read_protection_region(pr_t *pr_read, uint8_t sel)
>> +{
>> +    /*
>> +     * Before accessing EL2 MPU region register PRBAR_EL2/PRLAR_EL2,
>> +     * make sure PRSELR_EL2 is set, as it determines which MPU region
>> +     * is selected.
>> +     */
>> +    prepare_selector(&sel);
>> +
>> +    switch ( sel )
>> +    {
>> +        GENERATE_READ_PR_REG_CASE(0, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(1, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(2, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(3, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(4, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(5, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(6, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(7, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(8, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(9, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(10, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(11, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(12, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(13, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(14, pr_read);
>> +        GENERATE_READ_PR_REG_CASE(15, pr_read);
>> +    default:
>> +        BUG(); /* Can't happen */
>> +    }
>> +}
>> +
>> +/*
>> + * Write EL2 MPU Protection Region.
>> + *
>> + * @pr_write: const mpu protection region passed through write op.
>> + * @sel: mpu protection region selector
>> + */
>> +void write_protection_region(const pr_t *pr_write, uint8_t sel)
>> +{
>> +    /*
>> +     * Before accessing EL2 MPU region register PRBAR_EL2/PRLAR_EL2,
>> +     * make sure PRSELR_EL2 is set, as it determines which MPU region
>> +     * is selected.
>> +     */
>> +    prepare_selector(&sel);
>> +
>> +    switch ( sel )
>> +    {
>> +        GENERATE_WRITE_PR_REG_CASE(0, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(1, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(2, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(3, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(4, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(5, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(6, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(7, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(8, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(9, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(10, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(11, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(12, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(13, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(14, pr_write);
>> +        GENERATE_WRITE_PR_REG_CASE(15, pr_write);
>> +    default:
>> +        BUG(); /* Can't happen */
>> +    }
>> +}
>> +
>>  void __init setup_mm(void)
>>  {
>>      BUG_ON("unimplemented");
> 
> Cheers,
> 
> -- 
> Julien Grall
> 


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.