RfidResearchGroup / proxmark3

Iceman Fork - Proxmark3
http://www.icedev.se
GNU General Public License v3.0
3.65k stars 981 forks source link

[RESUME] Resume and make working the HAS_512_FLASH #267

Closed cjbrigato closed 4 years ago

cjbrigato commented 4 years ago

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

iceman1001 commented 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);
                }
            }
        }
doegox commented 4 years ago

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.

iceman1001 commented 4 years ago

Did you flash bootrom? since you change the linker data?

iceman1001 commented 4 years ago

And did you compile with HAS_512_FLASH flag ?

doegox commented 4 years ago

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

iceman1001 commented 4 years ago

what happend?

doegox commented 4 years ago

As I told above, nothing got written in the second half of mem. (I dumped it with jtag to see what happened)

iceman1001 commented 4 years ago

well... it works when jta openocd does it... So we can't be too off from a solution.

cjbrigato commented 4 years ago

but it did not brick the device ? well at least it is a good start x)

slurdge commented 4 years ago

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

slurdge commented 4 years ago

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.

slurdge commented 4 years ago

I'll cleanup & push (probably tomorrow though)

RfidResearchGroup commented 4 years ago

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.

slurdge commented 4 years ago

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.

cjbrigato commented 4 years ago

Can you all smell this? Well kids, this is how a damn good week for rdv40 firmware power leveling actually smells.

doegox commented 4 years ago

Wohoooo! well done @slurdge !!

RfidResearchGroup commented 4 years ago

Go go go! This week was a pretty damn good proxmark week!

doegox commented 4 years ago

happily closing this one, big thanks to @slurdge !