@@ -775,6 +775,20 @@ static void ot_flash_update_alerts(OtFlashState *s)
775775 }
776776}
777777
778+ static bool ot_flash_is_backend_writable (const OtFlashState * s )
779+ {
780+ return (s -> blk != NULL ) && blk_is_writable (s -> blk );
781+ }
782+
783+ static bool ot_flash_write_backend (OtFlashState * s , const void * buffer ,
784+ unsigned offset , size_t size )
785+ {
786+ /* NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange) */
787+ return blk_pwrite (s -> blk , (int64_t )(intptr_t )offset , (int64_t )size , buffer ,
788+ (BdrvRequestFlags )0 );
789+ /* NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange) */
790+ }
791+
778792static bool ot_flash_is_disabled (OtFlashState * s )
779793{
780794 return s -> regs [R_DIS ] != OT_MULTIBITBOOL4_FALSE ;
@@ -1026,13 +1040,99 @@ static void ot_flash_op_read(OtFlashState *s)
10261040 }
10271041}
10281042
1043+ static void ot_flash_op_prog (OtFlashState * s )
1044+ {
1045+ if (ot_fifo32_is_empty (& s -> prog_fifo )) {
1046+ xtrace_ot_flash_error ("prog while prog FIFO empty" );
1047+ return ;
1048+ }
1049+
1050+ OtFlashStorage * storage = & s -> flash ;
1051+ uint32_t * dest = s -> op .info_part ? storage -> info : storage -> data ;
1052+
1053+ while (s -> op .remaining ) {
1054+ if (ot_flash_fifo_in_reset (s )) {
1055+ continue ;
1056+ }
1057+ uint32_t word = ot_fifo32_pop (& s -> prog_fifo );
1058+ s -> regs [R_STATUS ] &= ~R_STATUS_PROG_FULL_MASK ;
1059+ ot_flash_update_prog_watermark (s );
1060+ bool fifo_empty = ot_fifo32_is_empty (& s -> prog_fifo );
1061+ if (fifo_empty ) {
1062+ s -> regs [R_STATUS ] |= R_STATUS_PROG_EMPTY_MASK ;
1063+ s -> regs [R_INTR_STATE ] |= INTR_PROG_EMPTY_MASK ;
1064+ ot_flash_update_irqs (s );
1065+ }
1066+
1067+ /* Must calculate next addr before decrementing the remaining count. */
1068+ unsigned address = 0u ;
1069+ if (!s -> op .failed ) {
1070+ address = s -> op .info_part ? ot_flash_next_info_address (s ) :
1071+ ot_flash_next_data_address (s );
1072+ address /= sizeof (uint32_t ); /* convert to word address */
1073+ }
1074+ s -> op .remaining -- ;
1075+
1076+ /*
1077+ * On encountering a multi-word write error, we must continue to empty
1078+ * the prog FIFO regardless, hence we retrieve the word to program
1079+ * before checking for errors.
1080+ */
1081+ trace_ot_flash_op_prog (s -> op .address , s -> op .count , s -> op .remaining ,
1082+ s -> op .failed , fifo_empty );
1083+ if (s -> op .failed ) {
1084+ if (!fifo_empty ) {
1085+ continue ;
1086+ }
1087+ break ;
1088+ }
1089+
1090+ /*
1091+ * Bits cannot be programmed back to 1 once programmed to 0; they must
1092+ * be erased instead.
1093+ */
1094+ g_assert (address <
1095+ ((s -> op .info_part ? storage -> info_size : storage -> data_size ) *
1096+ storage -> bank_count ));
1097+ dest [address ] &= word ;
1098+ trace_ot_flash_prog_word (s -> op .info_part , address , word );
1099+ if (ot_flash_is_backend_writable (s )) {
1100+ uintptr_t dest_offset = (uintptr_t )dest - (uintptr_t )storage -> data ;
1101+ if (ot_flash_write_backend (s , & dest [address ],
1102+ (unsigned )(dest_offset + address ),
1103+ sizeof (uint32_t ))) {
1104+ qemu_log_mask (LOG_GUEST_ERROR ,
1105+ "%s: cannot update flash backend\n" , __func__ );
1106+ ot_flash_set_error (s , R_ERR_CODE_PROG_ERR_MASK ,
1107+ address * sizeof (uint32_t ));
1108+ }
1109+ }
1110+
1111+ if (fifo_empty ) {
1112+ break ;
1113+ }
1114+ }
1115+
1116+ /*
1117+ * If we finished the entire program operation (i.e. no early exit as FIFO
1118+ * is empty), mark the operation as completed.
1119+ */
1120+ if (!s -> op .remaining ) {
1121+ ot_flash_op_complete (s );
1122+ }
1123+ }
1124+
10291125static void ot_flash_op_execute (OtFlashState * s )
10301126{
10311127 switch (s -> op .kind ) {
10321128 case OP_READ :
10331129 trace_ot_flash_op_execute (OP_NAME (s -> op .kind ));
10341130 ot_flash_op_read (s );
10351131 break ;
1132+ case OP_PROG :
1133+ trace_ot_flash_op_execute (OP_NAME (s -> op .kind ));
1134+ ot_flash_op_prog (s );
1135+ break ;
10361136 default :
10371137 xtrace_ot_flash_error ("unsupported" );
10381138 break ;
@@ -1897,12 +1997,6 @@ static const char *ot_flash_hexdump(const uint8_t *buf, size_t size)
18971997
18981998static void ot_flash_load (OtFlashState * s , Error * * errp )
18991999{
1900- /*
1901- * Notes:
1902- * 1. only support read access to the flash backend
1903- * 2. only data partition for now
1904- */
1905-
19062000 OtFlashStorage * flash = & s -> flash ;
19072001 memset (flash , 0 , sizeof (OtFlashStorage ));
19082002
@@ -1925,7 +2019,7 @@ static void ot_flash_load(OtFlashState *s, Error **errp)
19252019 blk_blockalign (s -> blk , sizeof (OtFlashBackendHeader ));
19262020
19272021 int rc ;
1928- // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
2022+ /* NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) */
19292023 rc = blk_pread (s -> blk , 0 , sizeof (* header ), header , 0 );
19302024 if (rc < 0 ) {
19312025 error_setg (errp , "failed to read the flash header content: %d" , rc );
@@ -1979,7 +2073,7 @@ static void ot_flash_load(OtFlashState *s, Error **errp)
19792073 unsigned offset = offsetof(OtFlashBackendHeader , hlength ) +
19802074 sizeof (header -> hlength ) + header -> hlength ;
19812075
1982- // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
2076+ /* NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) */
19832077 rc = blk_pread (s -> blk , (int64_t )offset , flash_size , flash -> storage , 0 );
19842078 if (rc < 0 ) {
19852079 error_setg (errp , "failed to read the initial flash content: %d" ,
@@ -1994,10 +2088,10 @@ static void ot_flash_load(OtFlashState *s, Error **errp)
19942088 size_t debug_trailer_size =
19952089 (size_t )(flash -> bank_count ) * ELFNAME_SIZE * BIN_APP_COUNT ;
19962090 uint8_t * elfnames = blk_blockalign (s -> blk , debug_trailer_size );
1997- // NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange)
2091+ /* NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange) */
19982092 rc = blk_pread (s -> blk , (int64_t )offset + flash_size ,
19992093 (int64_t )debug_trailer_size , elfnames , 0 );
2000- // NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange)
2094+ /* NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange) */
20012095 if (!rc ) {
20022096 const char * elfname = (const char * )elfnames ;
20032097 for (unsigned ix = 0 ; ix < BIN_APP_COUNT ; ix ++ ) {
0 commit comments