Hi Ayan,

>>> 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 :)

> 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 */
    }
}

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!");
#endif
}

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);
#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);
#endif
    default:
        BUG(); /* Can't happen */
    }
}

Please let me know your thoughts.

Cheers,
Luca



Reply via email to