@@ -467,9 +467,41 @@
/* EL2 MPU Protection Region Base Address Register encode */
#define PRBAR_EL2 S3_4_C6_C8_0
+#define PRBAR0_EL2 S3_4_C6_C8_0
+#define PRBAR1_EL2 S3_4_C6_C8_4
+#define PRBAR2_EL2 S3_4_C6_C9_0
+#define PRBAR3_EL2 S3_4_C6_C9_4
+#define PRBAR4_EL2 S3_4_C6_C10_0
+#define PRBAR5_EL2 S3_4_C6_C10_4
+#define PRBAR6_EL2 S3_4_C6_C11_0
+#define PRBAR7_EL2 S3_4_C6_C11_4
+#define PRBAR8_EL2 S3_4_C6_C12_0
+#define PRBAR9_EL2 S3_4_C6_C12_4
+#define PRBAR10_EL2 S3_4_C6_C13_0
+#define PRBAR11_EL2 S3_4_C6_C13_4
+#define PRBAR12_EL2 S3_4_C6_C14_0
+#define PRBAR13_EL2 S3_4_C6_C14_4
+#define PRBAR14_EL2 S3_4_C6_C15_0
+#define PRBAR15_EL2 S3_4_C6_C15_4
/* EL2 MPU Protection Region Limit Address Register encode */
#define PRLAR_EL2 S3_4_C6_C8_1
+#define PRLAR0_EL2 S3_4_C6_C8_1
+#define PRLAR1_EL2 S3_4_C6_C8_5
+#define PRLAR2_EL2 S3_4_C6_C9_1
+#define PRLAR3_EL2 S3_4_C6_C9_5
+#define PRLAR4_EL2 S3_4_C6_C10_1
+#define PRLAR5_EL2 S3_4_C6_C10_5
+#define PRLAR6_EL2 S3_4_C6_C11_1
+#define PRLAR7_EL2 S3_4_C6_C11_5
+#define PRLAR8_EL2 S3_4_C6_C12_1
+#define PRLAR9_EL2 S3_4_C6_C12_5
+#define PRLAR10_EL2 S3_4_C6_C13_1
+#define PRLAR11_EL2 S3_4_C6_C13_5
+#define PRLAR12_EL2 S3_4_C6_C14_1
+#define PRLAR13_EL2 S3_4_C6_C14_5
+#define PRLAR14_EL2 S3_4_C6_C15_1
+#define PRLAR15_EL2 S3_4_C6_C15_5
/* MPU Protection Region Selection Register encode */
#define PRSELR_EL2 S3_4_C6_C2_1
@@ -39,6 +39,23 @@ uint8_t __ro_after_init max_xen_mpumap;
*/
static DECLARE_BITMAP(xen_mpumap_mask, ARM_MAX_MPU_MEMORY_REGIONS);
+/* Write a MPU protection region */
+#define WRITE_PROTECTION_REGION(pr, prbar_el2, prlar_el2) ({ \
+ const pr_t *_pr = pr; \
+ \
+ WRITE_SYSREG(_pr->prbar.bits, prbar_el2); \
+ WRITE_SYSREG(_pr->prlar.bits, prlar_el2); \
+})
+
+/* Read a MPU protection region */
+#define READ_PROTECTION_REGION(prbar_el2, prlar_el2) ({ \
+ pr_t _pr; \
+ \
+ _pr.prbar.bits = READ_SYSREG(prbar_el2); \
+ _pr.prlar.bits = READ_SYSREG(prlar_el2); \
+ _pr; \
+})
+
void __init setup_mm_mappings(unsigned long boot_phys_offset)
{
unsigned int nr_regions = REGION_UART_SEL, i = 0;
@@ -57,6 +74,162 @@ void __init setup_mm_mappings(unsigned long boot_phys_offset)
set_bit(i, xen_mpumap_mask);
}
+/*
+ * 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 PRBAR0_EL2 and PRLAR0_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
+ */
+/*
+ * Read EL2 MPU Protection Region.
+ *
+ * @pr_read: mpu protection region returned by read op.
+ * @sel: mpu protection region selector
+ */
+static 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.
+ */
+ WRITE_SYSREG(sel, PRSELR_EL2);
+ isb();
+
+ switch ( sel & 0x0f )
+ {
+ case 0:
+ *pr_read = READ_PROTECTION_REGION(PRBAR0_EL2, PRLAR0_EL2);
+ break;
+ case 1:
+ *pr_read = READ_PROTECTION_REGION(PRBAR1_EL2, PRLAR1_EL2);
+ break;
+ case 2:
+ *pr_read = READ_PROTECTION_REGION(PRBAR2_EL2, PRLAR2_EL2);
+ break;
+ case 3:
+ *pr_read = READ_PROTECTION_REGION(PRBAR3_EL2, PRLAR3_EL2);
+ break;
+ case 4:
+ *pr_read = READ_PROTECTION_REGION(PRBAR4_EL2, PRLAR4_EL2);
+ break;
+ case 5:
+ *pr_read = READ_PROTECTION_REGION(PRBAR5_EL2, PRLAR5_EL2);
+ break;
+ case 6:
+ *pr_read = READ_PROTECTION_REGION(PRBAR6_EL2, PRLAR6_EL2);
+ break;
+ case 7:
+ *pr_read = READ_PROTECTION_REGION(PRBAR7_EL2, PRLAR7_EL2);
+ break;
+ case 8:
+ *pr_read = READ_PROTECTION_REGION(PRBAR8_EL2, PRLAR8_EL2);
+ break;
+ case 9:
+ *pr_read = READ_PROTECTION_REGION(PRBAR9_EL2, PRLAR9_EL2);
+ break;
+ case 10:
+ *pr_read = READ_PROTECTION_REGION(PRBAR10_EL2, PRLAR10_EL2);
+ break;
+ case 11:
+ *pr_read = READ_PROTECTION_REGION(PRBAR11_EL2, PRLAR11_EL2);
+ break;
+ case 12:
+ *pr_read = READ_PROTECTION_REGION(PRBAR12_EL2, PRLAR12_EL2);
+ break;
+ case 13:
+ *pr_read = READ_PROTECTION_REGION(PRBAR13_EL2, PRLAR13_EL2);
+ break;
+ case 14:
+ *pr_read = READ_PROTECTION_REGION(PRBAR14_EL2, PRLAR14_EL2);
+ break;
+ case 15:
+ *pr_read = READ_PROTECTION_REGION(PRBAR15_EL2, PRLAR15_EL2);
+ break;
+ default:
+ panic("Unsupported selector %u\n", sel);
+ }
+}
+
+/*
+ * Write EL2 MPU Protection Region.
+ *
+ * @pr_write: const mpu protection region passed through write op.
+ * @sel: mpu protection region selector
+ */
+static 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.
+ */
+ WRITE_SYSREG(sel, PRSELR_EL2);
+ isb();
+
+ switch ( sel & 0x0f )
+ {
+ case 0:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR0_EL2, PRLAR0_EL2);
+ break;
+ case 1:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR1_EL2, PRLAR1_EL2);
+ break;
+ case 2:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR2_EL2, PRLAR2_EL2);
+ break;
+ case 3:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR3_EL2, PRLAR3_EL2);
+ break;
+ case 4:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR4_EL2, PRLAR4_EL2);
+ break;
+ case 5:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR5_EL2, PRLAR5_EL2);
+ break;
+ case 6:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR6_EL2, PRLAR6_EL2);
+ break;
+ case 7:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR7_EL2, PRLAR7_EL2);
+ break;
+ case 8:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR8_EL2, PRLAR8_EL2);
+ break;
+ case 9:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR9_EL2, PRLAR9_EL2);
+ break;
+ case 10:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR10_EL2, PRLAR10_EL2);
+ break;
+ case 11:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR11_EL2, PRLAR11_EL2);
+ break;
+ case 12:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR12_EL2, PRLAR12_EL2);
+ break;
+ case 13:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR13_EL2, PRLAR13_EL2);
+ break;
+ case 14:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR14_EL2, PRLAR14_EL2);
+ break;
+ case 15:
+ WRITE_PROTECTION_REGION(pr_write, PRBAR15_EL2, PRLAR15_EL2);
+ break;
+ default:
+ panic("Unsupported selector %u\n", sel);
+ }
+}
+
/*
* Local variables:
* mode: C