@@ -1284,6 +1284,10 @@ def run_stub(self, stub: StubFlasher | None = None) -> "ESPLoader":
12841284 log .print ("Stub flasher is already running. No upload is necessary." )
12851285 return self .STUB_CLASS (self ) if self .STUB_CLASS is not None else self
12861286
1287+ secure_boot_workflow = (
1288+ self .CHIP_NAME == "ESP32-S3" and self .get_secure_boot_enabled ()
1289+ )
1290+
12871291 # Upload
12881292 log .print ("Uploading stub flasher..." )
12891293 for field in [stub .text , stub .data ]:
@@ -1296,8 +1300,24 @@ def run_stub(self, stub: StubFlasher | None = None) -> "ESPLoader":
12961300 from_offs = seq * self .ESP_RAM_BLOCK
12971301 to_offs = from_offs + self .ESP_RAM_BLOCK
12981302 self .mem_block (field [from_offs :to_offs ], seq )
1303+
12991304 log .print ("Running stub flasher..." )
1300- self .mem_finish (stub .entry )
1305+ if not secure_boot_workflow :
1306+ self .mem_finish (stub .entry )
1307+ else :
1308+ # Bug in ESP32-S3 ROM prevents stub execution if secure boot is enabled
1309+ # Hijack the `read` function in ROM to point to the stub entrypoint
1310+ # got with GDB - p &rom_spiflash_legacy_funcs.read
1311+ rom_spiflash_legacy_funcs_read_ptr = 0x3FCEF688
1312+ self .mem_finish (0 ) # Finish uploading to RAM but don't run the stub yet
1313+ stored_read_pointer = self .read_reg (rom_spiflash_legacy_funcs_read_ptr )
1314+ self .write_reg (rom_spiflash_legacy_funcs_read_ptr , stub .entry )
1315+ self .command ( # Trigger the `read` in ROM to jump to the stub entrypoint
1316+ self .ESP_CMDS ["READ_FLASH_SLOW" ],
1317+ struct .pack ("<II" , 0 , 0 ),
1318+ wait_response = False ,
1319+ )
1320+
13011321 try :
13021322 p = self .read ()
13031323 except StopIteration :
@@ -1309,6 +1329,9 @@ def run_stub(self, stub: StubFlasher | None = None) -> "ESPLoader":
13091329
13101330 if p != b"OHAI" :
13111331 raise FatalError (f"Failed to start stub flasher. Unexpected response: { p } " )
1332+ if secure_boot_workflow :
1333+ # Restore the original `read` function pointer
1334+ self .write_reg (rom_spiflash_legacy_funcs_read_ptr , stored_read_pointer )
13121335 log .stage (finish = True )
13131336 log .print ("Stub flasher running." )
13141337 return self .STUB_CLASS (self ) if self .STUB_CLASS is not None else self
0 commit comments