|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 2/7] arm/mpu: Provide access to the MPU region from the C code
Hi Ayan,
> On 9 Apr 2025, at 11:07, Ayan Kumar Halder <ayankuma@xxxxxxx> wrote:
>
>
> On 09/04/2025 09:26, Luca Fancellu wrote:
>> Hi Ayan,
> Hi Luca,
>>
>>>>> The point of the code was to don’t issue an isb() every time we change
>>>>> the selector,
>>>>> of course the code would be easier otherwise, but do we want to do that?
>>>> Not sure if it is beneficial as you would need to use isb() from region16
>>>> onwards.
>>> The isb() is issued only when changing the selector, so when you go from
>>> reading/writing regions
>>> from 0-15 to 16-31 for example, of course there is a case that if you
>>> continuously write on region 15
>>> and 16 you would have to always change the selector, but it’s the less
>>> impact we could have.
>>>
>>> armv8-R is even better since it’s able to address regions from 0 to 23
>>> without flushing the pipeline,
>> ^— aarch32 :)
> Can you point me to the document where you got this info ?
was referring to the r52, of course you are more knowledgeable on the armv8-r
aarch32 part, so ...
>>
>>> so I would say we should exploit this big advantage.
>>>
>>> I’ll send shortly in this thread the code I would use and the code I was
>>> thinking you could use.
>> Here the code I have in mind:
>>
>> static void prepare_selector(uint8_t *sel)
>> {
>> uint8_t cur_sel = *sel;
>> /*
>> * {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;
>> }
>>
>> 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 */
>> }
>> }
>>
>> 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 */
>> }
>> }
> Till here I am fine if you think this is the correct approach for arm64.
Ok
>>
>> Here the code I thought you could add for arm32:
>>
>> static void prepare_selector(uint8_t *sel)
>> {
>> uint8_t cur_sel = *sel;
>>
>> #ifdef CONFIG_ARM_64
>> /*
>> * {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;
>> #else
>> if ( cur_sel > 23 )
>> panic("Armv8-R AArch32 region selector exceeds maximum allowed
>> range!");
> I am not sure about this. See my question before. However ...
>> #endif
>> }
>
> From ARM DDI 0568A.c ID110520
>
> E2.2.3 HPRBAR<n> - Provides access to the base addresses for the first 32
> defined EL2 MPU regions.
>
> E2.2.6 HPRLAR<n> - Provides access to the limit addresses for the first 32
> defined EL2 MPU regions.
>
> I understand that HPRSELR is not used when directly accessing the above two
> registers. Thus, this function will be a nop for Arm32. Please let me know if
> I am mistaken.
yes you are right, you can decide if doing something or not in that function,
you don’t need to change the selector.
>
>>
>> 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);
>> #ifdef CONFIG_ARM_32
>> GENERATE_READ_PR_REG_CASE(16, pr_read);
>> GENERATE_READ_PR_REG_CASE(17, pr_read);
>> GENERATE_READ_PR_REG_CASE(18, pr_read);
>> GENERATE_READ_PR_REG_CASE(19, pr_read);
>> GENERATE_READ_PR_REG_CASE(20, pr_read);
>> GENERATE_READ_PR_REG_CASE(21, pr_read);
>> GENERATE_READ_PR_REG_CASE(22, pr_read);
>> GENERATE_READ_PR_REG_CASE(23, pr_read);
> At least 32 regions are directly accessible, thus thisn should go till 31
> (0-31). Same ..
yeah you can add until the 31st here and ...
>> #endif
>> default:
>> BUG(); /* Can't happen */
>> }
>> }
>>
>> 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);
>> #ifdef CONFIG_ARM_32
>> GENERATE_WRITE_PR_REG_CASE(16, pr_write);
>> GENERATE_WRITE_PR_REG_CASE(17, pr_write);
>> GENERATE_WRITE_PR_REG_CASE(18, pr_write);
>> GENERATE_WRITE_PR_REG_CASE(19, pr_write);
>> GENERATE_WRITE_PR_REG_CASE(20, pr_write);
>> GENERATE_WRITE_PR_REG_CASE(21, pr_write);
>> GENERATE_WRITE_PR_REG_CASE(22, pr_write);
>> GENERATE_WRITE_PR_REG_CASE(23, pr_write);
> for here.
also here.
So I guess we are aligned for this patch right? I will update this patch as the
code above and you
will modify the code for arm32 to support the direct access up to 32 region. Ok?
Cheers,
Luca
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |