Split RX and RW regions for separate pmp entries
v2 cover Split RX and RW regions for separate pmp entries
This is second installment of the patch series sent earlier with the subject: Split region permissions into M-mode and SU-mode. The version 2 was recently posted, for which below is the link:
http://lists.infradead.org/pipermail/opensbi/2023-January/004127.html
This patch series splits the RX (text and read-only data) and RW data regions so that each can have its independent pmp entries with correct permissions. The linker script provides a new symbol _fw_rw_offset that marks the beginning of the RW section. It also ensures that the split is a power-of-2 as required by pmp.
This lays ground work for enforcing the permissions from M-mode.
New in v2:
* Added a check if fw_rw_offset is a power of w
* Added a check if fw_start and fw_rw_offset are aligned
Himanshu Chauhan (5):
firmware: Split RO/RX and RW sections
firmware: Move dynsym and reladyn sections to RX section
firmware: Add RW section offset in scratch
lib: sbi: Print the RW section offset
Add two entries:
firmware/fw_base.S | 5 +++++ firmware/fw_base.ldS | 43 ++++++++++++++++++++++++--------------- include/sbi/sbi_scratch.h | 24 +++++++++++++--------- lib/sbi/sbi_domain.c | 23 +++++++++++++++++++-- lib/sbi/sbi_init.c | 1 + 5 files changed, 68 insertions(+), 28 deletions(-)
Signature · 1 line
2.39.0
PATCH v2 1/5 firmware: Split RO/RX and RW sections
Split the RO/RX and RW sections so that they can have independent pmp entries with required permissions. The split size is ensured to be a power-of-2 as required by pmp.
_fw_rw_offset symbol marks the beginning of the data section.
--- firmware/fw_base.ldS | 8 ++++++++ 1 file changed, 8 insertions(+)
firmware/fw_base.ldS +8 -0
@@ -42,6 +42,14 @@ . = ALIGN(0x1000); /* Ensure next section is page aligned */ + /* + * PMP regions must be to be power-of-2. RO/RW will have separate + * regions, so ensure that the split is power-of-2. + */ + . = ALIGN(1 << LOG2CEIL(SIZEOF(.rodata) + SIZEOF(.text))); + + PROVIDE(_fw_rw_offset = (. - _fw_start)); + /* Beginning of the read-write data sections */ .data :
Signature · 1 line
2.39.0
PATCH v2 2/5 firmware: Move dynsym and reladyn sections to RX section
In reply to Himanshu ChauhanCurrently, the dynsym and reladyn sections are under RW data. They are moved to the Read-only/Executable region.
--- firmware/fw_base.ldS | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-)
firmware/fw_base.ldS +22 -19
@@ -30,23 +30,39 @@ /* Beginning of the read-only data sections */ + PROVIDE(_rodata_start = .); + .rodata : { - PROVIDE(_rodata_start = .); *(.rodata .rodata.*) . = ALIGN(8); - PROVIDE(_rodata_end = .); } - /* End of the read-only data sections */ - . = ALIGN(0x1000); /* Ensure next section is page aligned */ + .dynsym : { + PROVIDE(__dyn_sym_start = .); + *(.dynsym) + PROVIDE(__dyn_sym_end = .); + } + + .rela.dyn : { + PROVIDE(__rel_dyn_start = .); + *(.rela*) + . = ALIGN(8); + PROVIDE(__rel_dyn_end = .); + } + + PROVIDE(_rodata_end = .); + + /* End of the read-only data sections */ + /* - * PMP regions must be to be power-of-2. RO/RW will have separate + * PMP regions must be to be power-of-2. RX/RW will have separate * regions, so ensure that the split is power-of-2. */ - . = ALIGN(1 << LOG2CEIL(SIZEOF(.rodata) + SIZEOF(.text))); + . = ALIGN(1 << LOG2CEIL((SIZEOF(.rodata) + SIZEOF(.text) + + SIZEOF(.dynsym) + SIZEOF(.rela.dyn)))); PROVIDE(_fw_rw_offset = (. - _fw_start));
@@ -67,19 +83,6 @@ PROVIDE(_data_end = .); } - .dynsym : { - PROVIDE(__dyn_sym_start = .); - *(.dynsym) - PROVIDE(__dyn_sym_end = .); - } - - .rela.dyn : { - PROVIDE(__rel_dyn_start = .); - *(.rela*) - . = ALIGN(8); - PROVIDE(__rel_dyn_end = .); - } - . = ALIGN(0x1000); /* Ensure next section is page aligned */ .bss :
Signature · 1 line
2.39.0
PATCH v2 3/5 firmware: Add RW section offset in scratch
In reply to Himanshu ChauhanAdd the RW section offset, provided by _fw_rw_offset symbol, to the scratch structure. This will be used to program separate pmp entry for RW section.
--- firmware/fw_base.S | 5 +++++ include/sbi/sbi_scratch.h | 24 ++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-)
firmware/fw_base.S +5 -0
@@ -298,6 +298,11 @@ _scratch_init: sub a5, t3, a4 REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp) REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp) + + /* Store R/W section's offset in scratch space */ + lla a4, _fw_rw_offset + REG_S a4, SBI_SCRATCH_FW_RW_OFFSET(tp) + /* Store next arg1 in scratch space */ MOV_3R s0, a0, s1, a1, s2, a2 call fw_next_arg1
include/sbi/sbi_scratch.h +14 -10
@@ -18,26 +18,28 @@#define SBI_SCRATCH_FW_START_OFFSET (0 * __SIZEOF_POINTER__)/** Offset of fw_size member in sbi_scratch */ #define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__) +/** Offset (in sbi_scratch) of the R/W Offset */ +#define SBI_SCRATCH_FW_RW_OFFSET (2 * __SIZEOF_POINTER__)/** Offset of next_arg1 member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_ARG1_OFFSET (2 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_ARG1_OFFSET (3 * __SIZEOF_POINTER__)/** Offset of next_addr member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_ADDR_OFFSET (3 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_ADDR_OFFSET (4 * __SIZEOF_POINTER__)/** Offset of next_mode member in sbi_scratch */ -#define SBI_SCRATCH_NEXT_MODE_OFFSET (4 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_NEXT_MODE_OFFSET (5 * __SIZEOF_POINTER__)/** Offset of warmboot_addr member in sbi_scratch */ -#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (5 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)/** Offset of platform_addr member in sbi_scratch */ -#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (6 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (7 * __SIZEOF_POINTER__)/** Offset of hartid_to_scratch member in sbi_scratch */ -#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (7 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__)/** Offset of trap_exit member in sbi_scratch */ -#define SBI_SCRATCH_TRAP_EXIT_OFFSET (8 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_TRAP_EXIT_OFFSET (9 * __SIZEOF_POINTER__)/** Offset of tmp0 member in sbi_scratch */ -#define SBI_SCRATCH_TMP0_OFFSET (9 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_TMP0_OFFSET (10 * __SIZEOF_POINTER__)/** Offset of options member in sbi_scratch */ -#define SBI_SCRATCH_OPTIONS_OFFSET (10 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_OPTIONS_OFFSET (11 * __SIZEOF_POINTER__)/** Offset of extra space in sbi_scratch */ -#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (11 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (12 * __SIZEOF_POINTER__)/** Maximum size of sbi_scratch (4KB) */ #define SBI_SCRATCH_SIZE (0x1000)
@@ -53,6 +55,8 @@ struct sbi_scratch {unsigned long fw_start;/** Size (in bytes) of firmware linked to OpenSBI library */ unsigned long fw_size; +/** Offset (in bytes) of the R/W section */ +unsigned long fw_rw_offset;/** Arg1 (or 'a1' register) of next booting stage for this HART */ unsigned long next_arg1;/** Address of next booting stage for this HART */
Signature · 1 line
2.39.0
PATCH v2 4/5 lib: sbi: Print the RW section offset
In reply to Himanshu ChauhanPrint the RW section offset when firmware base and size is being printed.
--- lib/sbi/sbi_init.c | 1 + 1 file changed, 1 insertion(+)
lib/sbi/sbi_init.c +1 -0
@@ -108,6 +108,7 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)sbi_printf ("Firmware Base : 0x%lx\n" , scratch->fw_start);sbi_printf ("Firmware Size : %d KB\n" , (u32)(scratch->fw_size /1024 )); +sbi_printf ("Firmware RW Offset : 0x%lx\n" , scratch->fw_rw_offset);/* SBI details */ sbi_printf("Runtime SBI Version : %d.%d\n",
Signature · 1 line
2.39.0
PATCH v2 5/5 Add two entries:
In reply to Himanshu Chauhan 1. TEXT: fw_start to _fw_rw_offset with RX permissions
2. DATA: _fw_rw_offset to fw_size with RW permissions
These permissions are still not enforced from M-mode but lay the ground work for enforcing them for M-mode. SU-mode don't have any access to these regions.
Sample output:
Domain0 Region01 : 0x0000000080000000-0x000000008001ffff M: (R,X) S/U: () Domain0 Region02 : 0x0000000080020000-0x000000008003ffff M: (R,W) S/U: ()
--- lib/sbi/sbi_domain.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
lib/sbi/sbi_domain.c +21 -2
@@ -637,12 +637,31 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)u32 i;const struct sbi_platform *plat =sbi_platform_ptr (scratch); +if ((scratch->fw_rw_offset & (scratch->fw_rw_offset -1 )) !=0 ) { +sbi_printf ("%s: Firmware read-write offset not a power of 2 (0x%lx)\n" , + __func__, scratch->fw_rw_offset); +return SBI_EINVAL ; + } + +if ((scratch->fw_start & (scratch->fw_rw_offset -1 )) !=0 ) { +sbi_printf ("%s: Firmware start and read-write offset not aligned\n" , + __func__); +return SBI_EINVAL ; + } +/* Root domain firmware memory region */ -sbi_domain_memregion_init (scratch->fw_start, scratch->fw_size, -SBI_DOMAIN_MEMREGION_M_RWX , +sbi_domain_memregion_init (scratch->fw_start, scratch->fw_rw_offset, + (SBI_DOMAIN_MEMREGION_M_READABLE | +SBI_DOMAIN_MEMREGION_M_EXECUTABLE ), &root_fw_region);domain_memregion_initfw (&root_memregs[root_memregs_count++]); +sbi_domain_memregion_init ((scratch->fw_start + scratch->fw_rw_offset), + (scratch->fw_size - scratch->fw_rw_offset), + (SBI_DOMAIN_MEMREGION_M_READABLE | +SBI_DOMAIN_MEMREGION_M_WRITABLE ), + &root_memregs[root_memregs_count++]); +/* Root domain allow everything memory region */ sbi_domain_memregion_init(0, ~0UL, (SBI_DOMAIN_MEMREGION_READABLE |
Signature · 1 line
2.39.0
PATCH v2 5/5 Add two entries:
? 2023-01-18???? 17:07 +0530?Himanshu Chauhan???
Quoted 23 lines
? 1. TEXT:
fw_startto_fw_rw_offsetwith RX permissions ? 2. DATA:_fw_rw_offsettofw_sizewith RW permissionsThese permissions are still not enforced from M-mode but lay the ground work for enforcing them for M-mode. SU-mode don't have any access to these regions.
Sample output:
?Domain0 Region01? : 0x0000000080000000-0x000000008001ffff M: (R,X) S/U: () ?Domain0 Region02? : 0x0000000080020000-0x000000008003ffff M: (R,W) S/U: ()Signed-off-by Himanshu Chauhan <[email protected]>---
?lib/sbi/sbi_domain.c | 23 +++++++++++++++++++++-- ?1 file changed, 21 insertions(+), 2 deletions(-)lib/sbi/sbi_domain.c +0
-0@@ -637,12 +637,31 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) ????????u32 i; ????????const struct sbi_platform *plat = sbi_platform_ptr(scratch);
Quoted 2 lines
?
+???????if ((scratch->fw_rw_offset& (scratch->fw_rw_offset- 1)) != 0) {
This expression is false at scratch-> fw_rw_offset = 0. 0 is not a power of 2.
suggestion:
if ((scratch->fw_rw_offset & (scratch->fw_rw_offset - 1)) != 0 || scratch->fw_rw_offset == 0) {Regards,
Xiang W
Quoted 33 lines
+???????????????sbi_printf("%s: Firmware read-write offset not a power of 2 (0x%lx)\n", +?????????????????????????
__func__,scratch->fw_rw_offset); +???????????????returnSBI_EINVAL;
+???????}lib/sbi/sbi_domain.c +7
-0+ +???????if ((scratch->fw_start & (scratch->fw_rw_offset - 1)) != 0) { +???????????????sbi_printf("%s: Firmware start and read-write offset not aligned\n", +????????????????????????? __func__); +???????????????return SBI_EINVAL; +???????} +????????/* Root domain firmware memory region */ -???????sbi_domain_memregion_init(scratch->fw_start,
scratch->fw_size, -????????????????????????????????SBI_DOMAIN_MEMREGION_M_RWX, +???????sbi_domain_memregion_init(scratch->fw_start,scratch->fw_rw_offset, +???????????????????????????????? (SBI_DOMAIN_MEMREGION_M_READABLE| +?????????????????????????????????SBI_DOMAIN_MEMREGION_M_EXECUTABLE), ?????????????????????????????????&root_fw_region); ????????domain_memregion_initfw(&root_memregs[root_memregs_count++]); ?
+???????sbi_domain_memregion_init((scratch->fw_start +scratch->fw_rw_offset), +???????????????????????????????? (scratch->fw_size-scratch->fw_rw_offset), +???????????????????????????????? (SBI_DOMAIN_MEMREGION_M_READABLE| +?????????????????????????????????SBI_DOMAIN_MEMREGION_M_WRITABLE), +???????????????????????????????? &root_memregs[root_memregs_count++]); +
????????/* Root domain allow everything memory region */ ????????sbi_domain_memregion_init(0, ~0UL, ????????????????????????????????? (SBI_DOMAIN_MEMREGION_READABLE|Signature · 1 line
2.39.0
PATCH v2 5/5 Add two entries:
Quoted 30 lines · Xiang W
? 2023-01-18???? 17:07 +0530?Himanshu Chauhan???
Quoted 23 lines
? 1. TEXT:
fw_startto_fw_rw_offsetwith RX permissions ? 2. DATA:_fw_rw_offsettofw_sizewith RW permissionsThese permissions are still not enforced from M-mode but lay the ground work for enforcing them for M-mode. SU-mode don't have any access to these regions.
Sample output:
?Domain0 Region01? : 0x0000000080000000-0x000000008001ffff M: (R,X) S/U: () ?Domain0 Region02? : 0x0000000080020000-0x000000008003ffff M: (R,W) S/U: ()Signed-off-by Himanshu Chauhan <[email protected]>---
?lib/sbi/sbi_domain.c | 23 +++++++++++++++++++++-- ?1 file changed, 21 insertions(+), 2 deletions(-)lib/sbi/sbi_domain.c +0
-0@@ -637,12 +637,31 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) ????????u32 i; ????????const struct sbi_platform *plat = sbi_platform_ptr(scratch);Quoted 2 lines
?
+???????if ((scratch->fw_rw_offset& (scratch->fw_rw_offset- 1)) != 0) {This expression is false at scratch->
fw_rw_offset= 0. 0 is not a power of 2.
suggestion:
Quoted 1 line
if ((scratch->fw_rw_offset & (scratch->fw_rw_offset - 1)) != 0 || scratch->fw_rw_offset == 0) {fw_rw_offset is provided by the linker. It will fall after text, ro, and symbols and then it is protected by LOG2CEIL. Unless everything is preceding fw_rw_offset is zero, fw_rw_offset can't be zero. So I think this check is safe here.
Regards
Himanshu
Quoted 38 lines
Regards,
Xiang WQuoted 33 lines
+???????????????sbi_printf("%s: Firmware read-write offset not a power of 2 (0x%lx)\n", +?????????????????????????
__func__,scratch->fw_rw_offset); +???????????????returnSBI_EINVAL;
+???????}lib/sbi/sbi_domain.c +7
-0+ +???????if ((scratch->fw_start & (scratch->fw_rw_offset - 1)) != 0) { +???????????????sbi_printf("%s: Firmware start and read-write offset not aligned\n", +????????????????????????? __func__); +???????????????return SBI_EINVAL; +???????} +????????/* Root domain firmware memory region */ -???????sbi_domain_memregion_init(scratch->fw_start,
scratch->fw_size, -????????????????????????????????SBI_DOMAIN_MEMREGION_M_RWX, +???????sbi_domain_memregion_init(scratch->fw_start,scratch->fw_rw_offset, +???????????????????????????????? (SBI_DOMAIN_MEMREGION_M_READABLE| +?????????????????????????????????SBI_DOMAIN_MEMREGION_M_EXECUTABLE), ?????????????????????????????????&root_fw_region); ????????domain_memregion_initfw(&root_memregs[root_memregs_count++]); ?
+???????sbi_domain_memregion_init((scratch->fw_start +scratch->fw_rw_offset), +???????????????????????????????? (scratch->fw_size-scratch->fw_rw_offset), +???????????????????????????????? (SBI_DOMAIN_MEMREGION_M_READABLE| +?????????????????????????????????SBI_DOMAIN_MEMREGION_M_WRITABLE), +???????????????????????????????? &root_memregs[root_memregs_count++]); +
????????/* Root domain allow everything memory region */ ????????sbi_domain_memregion_init(0, ~0UL, ????????????????????????????????? (SBI_DOMAIN_MEMREGION_READABLE|Signature · 1 line
2.39.0
PATCH v2 5/5 Add two entries:
? 2023-01-19???? 08:11 +0530?Himanshu Chauhan???
Quoted 33 lines · Xiang W
Quoted 17 lines
? 2023-01-18???? 17:07 +0530?Himanshu Chauhan???
Quoted 16 lines
? 1. TEXT:
fw_startto_fw_rw_offsetwith RX permissions ? 2. DATA:_fw_rw_offsettofw_sizewith RW permissionsThese permissions are still not enforced from M-mode but lay the ground work for enforcing them for M-mode. SU-mode don't have any access to these regions.
Sample output:
?Domain0 Region01? : 0x0000000080000000-0x000000008001ffff M: (R,X) S/U: () ?Domain0 Region02? : 0x0000000080020000-0x000000008003ffff M: (R,W) S/U: ()Signed-off-by Himanshu Chauhan <[email protected]>---
?lib/sbi/sbi_domain.c | 23 +++++++++++++++++++++-- ?1 file changed, 21 insertions(+), 2 deletions(-)Quoted 14 lines
Quoted 9 lines
lib/sbi/sbi_domain.c +0
-0@@ -637,12 +637,31 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid) ????????u32 i; ????????const struct sbi_platform *plat = sbi_platform_ptr(scratch);?
+???????if ((scratch->fw_rw_offset& (scratch->fw_rw_offset- 1)) != 0) {This expression is false at scratch->
fw_rw_offset= 0.
0 is not a power of 2.
suggestion:
??? if ((scratch->fw_rw_offset& (scratch->fw_rw_offset- 1)) != 0 ||scratch->fw_rw_offset== 0) {
Quoted 3 lines
fw_rw_offsetis provided by the linker. It will fall after text, ro, and symbols and then it is protected by LOG2CEIL. Unless everything is precedingfw_rw_offsetis zero,fw_rw_offsetcan't be zero. So I think this check is safe here.
I know fw_rw_offset is provieded by the linker script. This check prevents linker scripts from being incorrectly modified.
Regards,
Xiang W
Quoted 42 lines
Regards
HimanshuQuoted 38 lines
Regards,
Xiang WQuoted 33 lines
+???????????????sbi_printf("%s: Firmware read-write offset not a power of 2 (0x%lx)\n", +?????????????????????????
__func__,scratch->fw_rw_offset); +???????????????returnSBI_EINVAL;
+???????}lib/sbi/sbi_domain.c +7
-0+ +???????if ((scratch->fw_start & (scratch->fw_rw_offset - 1)) != 0) { +???????????????sbi_printf("%s: Firmware start and read-write offset not aligned\n", +????????????????????????? __func__); +???????????????return SBI_EINVAL; +???????} +????????/* Root domain firmware memory region */ -???????sbi_domain_memregion_init(scratch->fw_start,
scratch->fw_size, -????????????????????????????????SBI_DOMAIN_MEMREGION_M_RWX, +???????sbi_domain_memregion_init(scratch->fw_start,scratch->fw_rw_offset, +???????????????????????????????? (SBI_DOMAIN_MEMREGION_M_READABLE| +?????????????????????????????????SBI_DOMAIN_MEMREGION_M_EXECUTABLE), ?????????????????????????????????&root_fw_region); ????????domain_memregion_initfw(&root_memregs[root_memregs_count++]); ?
+???????sbi_domain_memregion_init((scratch->fw_start +scratch->fw_rw_offset), +???????????????????????????????? (scratch->fw_size-scratch->fw_rw_offset), +???????????????????????????????? (SBI_DOMAIN_MEMREGION_M_READABLE| +?????????????????????????????????SBI_DOMAIN_MEMREGION_M_WRITABLE), +???????????????????????????????? &root_memregs[root_memregs_count++]); +
????????/* Root domain allow everything memory region */ ????????sbi_domain_memregion_init(0, ~0UL, ????????????????????????????????? (SBI_DOMAIN_MEMREGION_READABLE|Signature · 1 line
2.39.0