Closed cjbrigato closed 4 years ago
Inside bootrom/bootrom.c there is these following lines that writes the fullimage.
The 256kb first memory is AT91C_BASE_EFC0
The 256kb second memory is AT91C_BASE_EFC1
As seen in the loops the EFC1 memory bank must be switched to when hitting the 256kb limit.
Also the ending check for flash has finished written (AT91C_MC_FRDY) check must adapt.
I think a u32 bank variable that gets assigned AT91C_BASE_EFC0 / AT91C_BASE_EFC1 should do the trick.
Ref https://github.com/RfidResearchGroup/proxmark3/blob/master/bootrom/bootrom.c#L162-L183
/* Check that the address that we are supposed to write to is within our allowed region */
if (((flash_address + AT91C_IFLASH_PAGE_SIZE - 1) >= end_addr) || (flash_address < start_addr)) {
/* Disallow write */
dont_ack = 1;
reply_old(CMD_NACK, 0, 0, 0, 0, 0);
} else {
uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE;
/* Translate address to flash page and do flash, update here for the 512k part */
AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY |
MC_FLASH_COMMAND_PAGEN(page_n) |
AT91C_MC_FCMD_START_PROG;
}
// Wait until flashing of page finishes
uint32_t sr;
while (!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY));
if (sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) {
dont_ack = 1;
reply_old(CMD_NACK, sr, 0, 0, 0, 0);
}
}
}
FTR here is what I tried:
--- a/common/ldscript.common
+++ b/common/ldscript.common
@@ -20,6 +20,8 @@ MEMORY
osimage : ORIGIN = 0x00102000, LENGTH = 512K - 0x2000 /* Place where the main OS will end up */
ram : ORIGIN = 0x00200000, LENGTH = 64K - 0x20 /* RAM, minus small common area */
commonarea : ORIGIN = 0x00200000 + 64K - 0x20, LENGTH = 0x20 /* Communication between bootloader and main OS */
+ flash0 : ORIGIN = 0x00100000, LENGTH = 256K /* first EFC */
+ flash1 : ORIGIN = 0x00140000, LENGTH = 256K /* second EFC */
}
/* Export some information that can be used from within the firmware */
@@ -29,4 +31,8 @@ _bootrom_start = ORIGIN(bootphase1);
_bootrom_end = ORIGIN(bootphase2) + LENGTH(bootphase2);
_flash_start = ORIGIN(bootphase1);
_flash_end = ORIGIN(osimage) + LENGTH(osimage);
+_flash_efc0_start = ORIGIN(flash0);
+_flash_efc0_length = LENGTH(flash0);
+_flash_efc1_start = ORIGIN(flash1);
+_flash_efc1_length = LENGTH(flash1);
_stack_end = ORIGIN(ram) + LENGTH(ram) - 8;
--- a/bootrom/bootrom.c
+++ b/bootrom/bootrom.c
@@ -11,7 +11,7 @@
struct common_area common_area __attribute__((section(".commonarea")));
unsigned int start_addr, end_addr, bootrom_unlocked;
-extern char _bootrom_start, _bootrom_end, _flash_start, _flash_end;
+extern char _bootrom_start, _bootrom_end, _flash_start, _flash_end, _flash_efc0_length;
extern uint32_t _osimage_entry;
static int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) {
@@ -158,7 +158,7 @@ void UsbPacketReceived(uint8_t *packet, int len) {
}
uint32_t flash_address = arg0 + (0x100 * j);
-
+ uint8_t efc = 0;
/* Check that the address that we are supposed to write to is within our allowed region */
if (((flash_address + AT91C_IFLASH_PAGE_SIZE - 1) >= end_addr) || (flash_address < start_addr)) {
/* Disallow write */
@@ -167,14 +167,26 @@ void UsbPacketReceived(uint8_t *packet, int len) {
} else {
uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE;
/* Translate address to flash page and do flash, update here for the 512k part */
- AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY |
- MC_FLASH_COMMAND_PAGEN(page_n) |
- AT91C_MC_FCMD_START_PROG;
+ if (page_n < (int)&_flash_efc0_length / AT91C_IFLASH_PAGE_SIZE) {
+ AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY |
+ MC_FLASH_COMMAND_PAGEN(page_n) |
+ AT91C_MC_FCMD_START_PROG;
+ } else {
+ efc = 1;
+ page_n -= (int)&_flash_efc0_length / AT91C_IFLASH_PAGE_SIZE;
+ AT91C_BASE_EFC1->EFC_FCR = MC_FLASH_COMMAND_KEY |
+ MC_FLASH_COMMAND_PAGEN(page_n) |
+ AT91C_MC_FCMD_START_PROG;
+ }
}
// Wait until flashing of page finishes
uint32_t sr;
- while (!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY));
+ if (efc == 0) {
+ while (!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY));
+ } else {
+ while (!((sr = AT91C_BASE_EFC1->EFC_FSR) & AT91C_MC_FRDY));
+ }
if (sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) {
dont_ack = 1;
reply_old(CMD_NACK, sr, 0, 0, 0, 0);
But nothing got written in the second half of mem.
Did you flash bootrom? since you change the linker data?
And did you compile with HAS_512_FLASH flag ?
Did you flash bootrom? since you change the linker data?
I changed linker data AND bootrom.c so yes of course I flashed the bootloader :)
And did you compile with HAS_512_FLASH flag ?
Yeah well I just did
--- a/client/flash.c
+++ b/client/flash.c
@@ -12,11 +12,7 @@
#define FLASH_START 0x100000
-#ifdef HAS_512_FLASH
# define FLASH_SIZE (512*1024)
-#else
-# define FLASH_SIZE (256*1024)
-#endif
#define FLASH_END (FLASH_START + FLASH_SIZE)
#define BOOTLOADER_SIZE 0x2000
Plus a bunch of stupid stuffs in the OS to reach the 256k limit
what happend?
As I told above, nothing got written in the second half of mem. (I dumped it with jtag to see what happened)
well... it works when jta openocd does it... So we can't be too off from a solution.
but it did not brick the device ? well at least it is a good start x)
I'm at the same point as @doegox (with slightly different code). The flashing seems to work properly (using the second bank register), but the app is unresponsive. It does not brick the device, I can reflash a < 256K firmware and it works again. So definitely the good direction
I think this is win:
--= Nonvolatile Program Memory Size: 512K bytes, Used: 273063 bytes (52%) Free: 251225 bytes (48%)
The trick was to write to memory mapped buffer but above 256K. Seems there is one memory mapped buffer per bank/controller.
I'll cleanup & push (probably tomorrow though)
I was / still am confuse where the temporary mem buffer were stored from there the arm flashes its memory. So there was two of them. cool.
It's a write memory mapper buffer. When you write to those address, it instead goes to a special memory inside the flash controller. You have 256 bytes (that's why the loop is 64*4 bytes). But it is per controller.
Can you all smell this? Well kids, this is how a damn good week for rdv40 firmware power leveling actually smells.
Wohoooo! well done @slurdge !!
Go go go! This week was a pretty damn good proxmark week!
happily closing this one, big thanks to @slurdge !
Is your feature request related to a problem? Please describe. HAS_512_FLASH was made to get access to the full 512KB of at91sam7s512 flash. Unfortunately it right now only feature a short road into bricking your device.
Describe the solution you'd like Make it work and permit to flash > 256KB / 512 "blocks" with neither the frustrating "Not contained in PHDR" insult nor a bricked device as result.
Describe alternatives you've considered Apple Pies, but yield absolutely no comparable result, nor anything closely related to a surprise birthday in Las Vegas.
Additional context Everything is said, so the issue is created as a reminder and enforcer. Thanks to @doegox and his https://github.com/RfidResearchGroup/proxmark3/issues/257#issuecomment-512150861