1515#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
1616
1717typedef struct rescue_mode_properties {
18+ // The FourCC of the mode we want to set.
19+ // When pairing modes, the UpLoad mode must be the `mode` and the DnLoad mode
20+ // must be the `paired` mode. This is because the validate_mode function
21+ // only examines the `mode` for staging the upload data.
1822 uint32_t mode ;
19- bool dnload ;
20- bool upload ;
23+ // Non-zero if there is a paired mode.
24+ uint32_t paired ;
25+ // Whether the mode support DFU DnLoad or UpLoad or both.
26+ // Element 0 describes the Up- or Dn-Load status of the mode.
27+ // Element 1 describes whether the "paired" mode supports Up- or Dn-Load.
28+ // E.g. OwnerPage0 is paired with OwnerBlock.
29+ uint8_t allow [2 ];
2130} rescue_mode_properties_t ;
2231
32+ // clang-format off
2333static const rescue_mode_properties_t mode_by_altsetting [] = {
24- {kRescueModeFirmware , true, false},
25- {kRescueModeFirmwareSlotB , true, false},
26- {kRescueModeOpenTitanID , false, true},
27- {kRescueModeBootLog , false, true},
28- {kRescueModeBootSvcRsp , true, true},
29- {kRescueModeOwnerPage0 , true, true},
30- //{ kRescueModeOwnerPage1, false, true },
34+ {kRescueModeFirmware , 0 , { kDfuAllowDnLoad , 0 }},
35+ {kRescueModeFirmwareSlotB , 0 , { kDfuAllowDnLoad , 0 }},
36+ {kRescueModeOpenTitanID , 0 , { kDfuAllowUpLoad , 0 }},
37+ {kRescueModeBootLog , 0 , { kDfuAllowUpLoad , 0 }},
38+ {kRescueModeBootSvcRsp , kRescueModeBootSvcReq , { kDfuAllowUpLoad , kDfuAllowDnLoad }},
39+ {kRescueModeOwnerPage0 , kRescueModeOwnerBlock , { kDfuAllowUpLoad , kDfuAllowDnLoad }},
3140};
41+ // clang-format on
3242
33- static rom_error_t validate_mode (uint32_t setting , rescue_state_t * state ) {
43+ static rom_error_t validate_mode (uint32_t setting , dfu_ctx_t * ctx ) {
3444 // Allow the `setting` to be either an index or a FourCC code.
3545 // The the integer value is less than the arraysize, then its clearly an
3646 // index.
@@ -56,38 +66,37 @@ static rom_error_t validate_mode(uint32_t setting, rescue_state_t *state) {
5666 // same target, we handle the "send" services first to stage data into the
5767 // rescue buffer.
5868 const rescue_mode_properties_t * mode = & mode_by_altsetting [setting ];
59- rom_error_t error2 = kErrorOk ;
60- rom_error_t error = rescue_validate_mode (mode -> mode , state );
69+ rom_error_t error = rescue_validate_mode (mode -> mode , & ctx -> state );
6170
62- // If the service exclusively supports either upload or download operation,
63- // report bad mode immediately if a prior error occurred.
64- if (!(mode -> upload && mode -> dnload )) {
65- if (error != kErrorOk ) {
66- return kErrorRescueBadMode ;
71+ uint8_t allow = 0 ;
72+ if (error == kErrorOk ) {
73+ allow = mode -> allow [0 ];
74+ if (allow & kDfuAllowUpLoad ) {
75+ // DFU upload means send to the host. We stage the data that would
76+ // be sent to the rescue buffer.
77+ rescue_send_handler (& ctx -> state );
6778 }
6879 }
6980
70- if (error == kErrorOk && mode -> upload ) {
71- // DFU upload means send to the host. We stage the data that would
72- // be sent to the rescue buffer.
73- rescue_send_handler (state );
74- }
7581 // BootSvc and OwnerPage are also recv (from the host) services. Make sure
7682 // we're set up to process a DFU download for those services.
77- if (mode -> mode == kRescueModeBootSvcRsp ) {
78- error2 = rescue_validate_mode (kRescueModeBootSvcReq , state );
79- } else if (mode -> mode == kRescueModeOwnerPage0 ) {
80- error2 = rescue_validate_mode (kRescueModeOwnerBlock , state );
83+ if (mode -> paired ) {
84+ rom_error_t error2 = rescue_validate_mode (mode -> paired , & ctx -> state );
85+ if (error2 == kErrorOk ) {
86+ allow |= mode -> allow [1 ];
87+ }
8188 }
8289
83- if (error == kErrorOk || error2 == kErrorOk ) {
84- // If either the send or recv mode is ok, then setting the mode is ok.
85- // If only one is Ok, the send or recv handler will report the error when we
86- // try an unauthorized operation.
90+ // If either the send or recv mode is ok, then setting the mode is ok.
91+ // If only one is Ok, the send or recv handler will report the error when we
92+ // try an unauthorized operation.
93+ // If neither is Ok, the report bad mode.
94+ if (allow ) {
95+ ctx -> allow = allow ;
8796 return kErrorOk ;
97+ } else {
98+ return kErrorRescueBadMode ;
8899 }
89- // If neither is Ok, the report bad mode.
90- return kErrorRescueBadMode ;
91100}
92101
93102static rom_error_t dfu_control (dfu_ctx_t * ctx , usb_setup_data_t * setup ) {
@@ -125,8 +134,8 @@ static rom_error_t dfu_control(dfu_ctx_t *ctx, usb_setup_data_t *setup) {
125134 ctx -> dfu_state = tr -> next [setup -> length == 0 ? 0 : 1 ];
126135 // Length is good and the request is either upload/download.
127136 if (setup -> length <= sizeof (ctx -> state .data ) &&
128- (setup -> request == kDfuReqDnLoad ||
129- setup -> request == kDfuReqUpLoad )) {
137+ (( setup -> request == kDfuReqDnLoad && ctx -> allow & kDfuAllowDnLoad ) ||
138+ ( setup -> request == kDfuReqUpLoad && ctx -> allow & kDfuAllowUpLoad ) )) {
130139 if (setup -> request == kDfuReqDnLoad ) {
131140 if (setup -> length == 0 ||
132141 ctx -> state .offset < ctx -> state .flash_limit ) {
@@ -193,7 +202,7 @@ static rom_error_t vendor_request(dfu_ctx_t *ctx, usb_setup_data_t *setup) {
193202 // FourCC from the value and index fields.
194203 case kDfuVendorSetMode : {
195204 uint32_t mode = ((uint32_t )setup -> value << 16 ) | setup -> index ;
196- if (validate_mode (mode , & ctx -> state ) == kErrorOk ) {
205+ if (validate_mode (mode , ctx ) == kErrorOk ) {
197206 dfu_transport_data (ctx , kUsbDirIn , NULL , 0 , 0 );
198207 } else {
199208 return kErrorUsbBadSetup ;
@@ -208,7 +217,7 @@ static rom_error_t vendor_request(dfu_ctx_t *ctx, usb_setup_data_t *setup) {
208217static rom_error_t interface_request (dfu_ctx_t * ctx , usb_setup_data_t * setup ) {
209218 switch (setup -> request ) {
210219 case kUsbSetupReqSetInterface :
211- if (validate_mode (setup -> value , & ctx -> state ) == kErrorOk ) {
220+ if (validate_mode (setup -> value , ctx ) == kErrorOk ) {
212221 // A typical OS USB stack will issue SET_INTERFACE to activate
213222 // AltSetting 0. Since this probably is not real user activity,
214223 // we won't cancel the inactivity deadline for this action when it
@@ -237,7 +246,7 @@ static rom_error_t set_configuration(dfu_ctx_t *ctx) {
237246 ctx -> dfu_error = kDfuErrOk ;
238247 ctx -> dfu_state = kDfuStateIdle ;
239248 ctx -> interface = 0 ;
240- validate_mode (ctx -> interface , & ctx -> state );
249+ validate_mode (ctx -> interface , ctx );
241250 ctx -> ep0 .configuration = ctx -> ep0 .next .configuration ;
242251 return kErrorOk ;
243252}
0 commit comments