@@ -755,6 +755,7 @@ struct OtFlashState {
755755 OtFlashStorage flash ;
756756
757757 BlockBackend * blk ; /* Flash backend */
758+ bool no_mem_prot ; /* Flag to disable mem protection features */
758759};
759760
760761static void ot_flash_update_irqs (OtFlashState * s )
@@ -923,6 +924,121 @@ static void ot_flash_op_complete(OtFlashState *s)
923924 ot_flash_update_irqs (s );
924925}
925926
927+ static uint32_t ot_flash_get_info_page_cfg_reg (
928+ unsigned bank , unsigned info_partition , unsigned page )
929+ {
930+ switch (bank ) {
931+ case 0u :
932+ switch (info_partition ) {
933+ case 0u :
934+ return R_BANK0_INFO0_PAGE_CFG_0 + page ;
935+ case 1u :
936+ return R_BANK0_INFO1_PAGE_CFG ;
937+ case 2u :
938+ return R_BANK0_INFO2_PAGE_CFG_0 + page ;
939+ default :
940+ qemu_log_mask (LOG_GUEST_ERROR , "%s: invalid info partition: %u\n" ,
941+ __func__ , info_partition );
942+ return 0u ;
943+ }
944+ case 1u :
945+ switch (info_partition ) {
946+ case 0u :
947+ return R_BANK1_INFO0_PAGE_CFG_0 + page ;
948+ case 1u :
949+ return R_BANK1_INFO1_PAGE_CFG ;
950+ case 2u :
951+ return R_BANK1_INFO2_PAGE_CFG_0 + page ;
952+ default :
953+ qemu_log_mask (LOG_GUEST_ERROR , "%s: invalid info partition: %u\n" ,
954+ __func__ , info_partition );
955+ return 0u ;
956+ }
957+ default :
958+ qemu_log_mask (LOG_GUEST_ERROR , "%s: invalid bank: %d\n" , __func__ ,
959+ bank );
960+ return 0u ;
961+ }
962+ }
963+
964+ static bool
965+ ot_flash_info_page_cfg_op_enabled (OtFlashState * s , uint32_t info_page_cfg_reg )
966+ {
967+ unsigned en_field ;
968+ switch (s -> op .kind ) {
969+ case OP_READ :
970+ en_field = SHARED_FIELD_EX32 (s -> regs [info_page_cfg_reg ],
971+ BANK_INFO_PAGE_CFG_RD_EN );
972+ break ;
973+ case OP_PROG :
974+ en_field = SHARED_FIELD_EX32 (s -> regs [info_page_cfg_reg ],
975+ BANK_INFO_PAGE_CFG_PROG_EN );
976+ break ;
977+ case OP_ERASE :
978+ en_field = SHARED_FIELD_EX32 (s -> regs [info_page_cfg_reg ],
979+ BANK_INFO_PAGE_CFG_ERASE_EN );
980+ break ;
981+ case OP_NONE :
982+ xtrace_ot_flash_error ("cannot check mp without operation" );
983+ return false;
984+ default :
985+ xtrace_ot_flash_error ("unsupported operation?" );
986+ return false;
987+ }
988+ return en_field == OT_MULTIBITBOOL4_TRUE ;
989+ }
990+
991+ static bool
992+ ot_flash_mp_region_cfg_op_enabled (OtFlashState * s , uint32_t mp_cfg_reg )
993+ {
994+ unsigned en_field ;
995+ switch (s -> op .kind ) {
996+ case OP_READ :
997+ en_field = SHARED_FIELD_EX32 (s -> regs [mp_cfg_reg ], MP_REGION_CFG_RD_EN );
998+ break ;
999+ case OP_PROG :
1000+ en_field =
1001+ SHARED_FIELD_EX32 (s -> regs [mp_cfg_reg ], MP_REGION_CFG_PROG_EN );
1002+ break ;
1003+ case OP_ERASE :
1004+ en_field =
1005+ SHARED_FIELD_EX32 (s -> regs [mp_cfg_reg ], MP_REGION_CFG_ERASE_EN );
1006+ break ;
1007+ case OP_NONE :
1008+ xtrace_ot_flash_error ("cannot check mp without operation" );
1009+ return false;
1010+ default :
1011+ xtrace_ot_flash_error ("unsupported operation?" );
1012+ return false;
1013+ }
1014+ return en_field == OT_MULTIBITBOOL4_TRUE ;
1015+ }
1016+
1017+ static bool ot_flash_default_region_cfg_op_enabled (OtFlashState * s )
1018+ {
1019+ unsigned en_field ;
1020+ switch (s -> op .kind ) {
1021+ case OP_READ :
1022+ en_field = FIELD_EX32 (s -> regs [R_DEFAULT_REGION ], DEFAULT_REGION , RD_EN );
1023+ break ;
1024+ case OP_PROG :
1025+ en_field =
1026+ FIELD_EX32 (s -> regs [R_DEFAULT_REGION ], DEFAULT_REGION , PROG_EN );
1027+ break ;
1028+ case OP_ERASE :
1029+ en_field =
1030+ FIELD_EX32 (s -> regs [R_DEFAULT_REGION ], DEFAULT_REGION , ERASE_EN );
1031+ break ;
1032+ case OP_NONE :
1033+ xtrace_ot_flash_error ("cannot check mp without operation" );
1034+ return false;
1035+ default :
1036+ xtrace_ot_flash_error ("unsupported operation?" );
1037+ return false;
1038+ }
1039+ return en_field == OT_MULTIBITBOOL4_TRUE ;
1040+ }
1041+
9261042static bool ot_flash_can_erase_bank (const OtFlashState * s , unsigned bank )
9271043{
9281044 switch (bank ) {
@@ -987,6 +1103,35 @@ static unsigned ot_flash_next_info_address(OtFlashState *s)
9871103 unsigned address = address_in_bank + bank_offset + info_part_offset ;
9881104 trace_ot_flash_info_part (s -> op .address , s -> op .count , s -> op .remaining , bank ,
9891105 info_partition , address );
1106+ if (s -> no_mem_prot ||
1107+ (s -> op .kind == OP_ERASE && s -> op .erase_sel == ERASE_SEL_BANK )) {
1108+ return address ;
1109+ }
1110+
1111+ /* Check the matching info partition page config register */
1112+ unsigned page = address_in_bank / BYTES_PER_PAGE ;
1113+ uint32_t info_page_cfg_reg =
1114+ ot_flash_get_info_page_cfg_reg (bank , info_partition , page );
1115+ if (!info_page_cfg_reg ) {
1116+ ot_flash_set_error (s , R_ERR_CODE_MP_ERR_MASK , op_address );
1117+ s -> op .failed = true;
1118+ return address ;
1119+ }
1120+ if (SHARED_FIELD_EX32 (s -> regs [info_page_cfg_reg ], BANK_INFO_PAGE_CFG_EN ) !=
1121+ OT_MULTIBITBOOL4_TRUE ) {
1122+ return address ; /* page config is disabled; so access is permitted. */
1123+ }
1124+ if (!ot_flash_info_page_cfg_op_enabled (s , info_page_cfg_reg )) {
1125+ qemu_log_mask (LOG_GUEST_ERROR ,
1126+ "%s: operation %s on info page %u in partition %u of "
1127+ "bank %u is disabled by page config\n" ,
1128+ __func__ , OP_NAME (s -> op .kind ), page , bank ,
1129+ info_partition );
1130+ ot_flash_set_error (s , R_ERR_CODE_MP_ERR_MASK , op_address );
1131+ s -> op .failed = true;
1132+ return address ;
1133+ }
1134+
9901135 return address ;
9911136}
9921137
@@ -1008,6 +1153,68 @@ static unsigned ot_flash_next_data_address(OtFlashState *s)
10081153 }
10091154 trace_ot_flash_data_part (s -> op .address , s -> op .count , s -> op .remaining , bank ,
10101155 address );
1156+
1157+ if (s -> no_mem_prot ||
1158+ (s -> op .kind == OP_ERASE && s -> op .erase_sel == ERASE_SEL_BANK )) {
1159+ return address ;
1160+ }
1161+
1162+ /*
1163+ * Check through the memory protection regions 0->9, and see if the current
1164+ * page falls within a region. If so, and it is enabled, apply its perms.
1165+ * Otherwise apply the default region's permissions. Note that MP region
1166+ * page indexes are cumulative across banks.
1167+ *
1168+ * If any two MP regions overlap, the lower index region has priority.
1169+ */
1170+ unsigned page = address / BYTES_PER_PAGE ;
1171+ bool matching_region_found = false;
1172+ for (unsigned region = 0u ; region < NUM_REGIONS ; region ++ ) {
1173+ /* Ignore disabled regions */
1174+ unsigned r_region_cfg = R_MP_REGION_CFG_0 + region ;
1175+ if (SHARED_FIELD_EX32 (s -> regs [r_region_cfg ], MP_REGION_CFG_EN ) !=
1176+ OT_MULTIBITBOOL4_TRUE ) {
1177+ continue ;
1178+ }
1179+
1180+ /*
1181+ * Check if the current flash word falls in this region.
1182+ * Size is inclusive at the base, but exclusive at (base+size).
1183+ */
1184+ unsigned r_region = R_MP_REGION_0 + region ;
1185+ unsigned region_base_page =
1186+ SHARED_FIELD_EX32 (s -> regs [r_region ], MP_REGION_BASE );
1187+ unsigned region_size =
1188+ SHARED_FIELD_EX32 (s -> regs [r_region ], MP_REGION_SIZE );
1189+ if (page < region_base_page ||
1190+ page >= (region_base_page + region_size )) {
1191+ continue ;
1192+ }
1193+ matching_region_found = true;
1194+
1195+ /* Page does fall in this region, so check if enabled for operation. */
1196+ if (!ot_flash_mp_region_cfg_op_enabled (s , r_region_cfg )) {
1197+ qemu_log_mask (LOG_GUEST_ERROR ,
1198+ "%s: operation %s on page %u of data partition in "
1199+ "bank %u is disabled by MP region %u\n" ,
1200+ __func__ , OP_NAME (s -> op .kind ), page , bank , region );
1201+ ot_flash_set_error (s , R_ERR_CODE_MP_ERR_MASK , address );
1202+ s -> op .failed = true;
1203+ return address ;
1204+ }
1205+ break ;
1206+ }
1207+
1208+ /* If page not in any region, apply the default region's permissions. */
1209+ if (!matching_region_found && !ot_flash_default_region_cfg_op_enabled (s )) {
1210+ qemu_log_mask (LOG_GUEST_ERROR ,
1211+ "%s: operation %s on page %u of data partition in bank "
1212+ "%u is disabled by default region\n" ,
1213+ __func__ , OP_NAME (s -> op .kind ), page , bank );
1214+ ot_flash_set_error (s , R_ERR_CODE_MP_ERR_MASK , address );
1215+ s -> op .failed = true;
1216+ return address ;
1217+ }
10111218 return address ;
10121219}
10131220
@@ -2002,6 +2209,9 @@ static void ot_flash_csrs_write(void *opaque, hwaddr addr, uint64_t val64,
20022209
20032210static Property ot_flash_properties [] = {
20042211 DEFINE_PROP_DRIVE ("drive" , OtFlashState , blk ),
2212+ /* Optionally disable memory protection, as searching for valid memory
2213+ regions and checking their config can slow down regular operation. */
2214+ DEFINE_PROP_BOOL ("no-mem-prot" , OtFlashState , no_mem_prot , false),
20052215 DEFINE_PROP_END_OF_LIST (),
20062216};
20072217
0 commit comments