New bootrom
authorhenryk@ploetzli.ch <henryk@ploetzli.ch@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Tue, 1 Sep 2009 14:44:38 +0000 (14:44 +0000)
committerhenryk@ploetzli.ch <henryk@ploetzli.ch@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Tue, 1 Sep 2009 14:44:38 +0000 (14:44 +0000)
+ Add common area at end of RAM to communicate between main os and bootrom
+ Lower stack end to make room for common area
+ Implement CMD_DEVICE_INFO in both OS and bootrom to give information about the current state and supported features
+ Allow hands-free firmware update: When CMD_START_FLASH is received over USB in OS mode, the device will reset and enter the bootrom
  Pressing the button in hands-free update mode takes precedence: releasing the button will immediately abort firmware update and
  perform a reset. Do not press the button.
+ Require each flash sequence to be preceded by a CMD_START_FLASH to set up the boundaries for the following flash sequence
  Not compatible with linux flasher before SVN revision 200
  Currently no compatible flasher for Windows. WINDOWS USERS: DO NOT UPDATE YOUR BOOTROM YET
+ Protect bootrom flash area unless magic unlock sequence is given in CMD_START_FLASH

armsrc/appmain.c
armsrc/ldscript
bootrom/Makefile
bootrom/bootrom.c
bootrom/ldscript-flash
common/Makefile.common
common/ldscript.common
include/proxmark3.h

index 72d8789e75af6a10637d82bbc2b401bb83a89371..78ab86912c779eb5b4b2db6cc182f3a4a439fea0 100644 (file)
@@ -13,7 +13,6 @@
 #include "LCD.h"
 #endif
 
-
 //=============================================================================
 // A buffer where we can queue things up to be sent through the FPGA, for
 // any purpose (fake tag, as reader, whatever). We go MSB first, since that
@@ -23,6 +22,7 @@
 BYTE ToSend[256];
 int ToSendMax;
 static int ToSendBit;
+struct common_area common_area __attribute__((section(".commonarea")));
 
 void BufferClear(void)
 {
@@ -669,7 +669,23 @@ void UsbPacketReceived(BYTE *packet, int len)
                                // We're going to reset, and the bootrom will take control.
                        }
                        break;
-
+               case CMD_START_FLASH:
+                       if(common_area.flags.bootrom_present) {
+                               common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE;
+                       }
+                       USB_D_PLUS_PULLUP_OFF();
+                       RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET;
+                       for(;;);
+                       break;
+                       
+               case CMD_DEVICE_INFO: {
+                       UsbCommand c;
+                       c.cmd = CMD_DEVICE_INFO;
+                       c.ext1 = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;
+                       if(common_area.flags.bootrom_present) c.ext1 |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;
+                       UsbSendPacket((BYTE*)&c, sizeof(c));
+               }
+                       break;
                default:
                        DbpString("unknown command");
                        break;
@@ -680,6 +696,14 @@ void AppMain(void)
 {
        memset(BigBuf,0,sizeof(BigBuf));
        SpinDelay(100);
+       
+       if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
+               /* Initialize common area */
+               memset(&common_area, 0, sizeof(common_area));
+               common_area.magic = COMMON_AREA_MAGIC;
+               common_area.version = 1;
+       }
+       common_area.flags.osimage_present = 1;
 
        LED_D_OFF();
        LED_C_OFF();
index 3a01a68fcbd8ecc3d8c252aaa1930573d3482441..a3aedef1113735699f0a21c15fc3127c26febf8d 100644 (file)
@@ -22,4 +22,8 @@ SECTIONS
        __bss_start__ = .;\r
        .bss : { *(.bss) } >ram\r
        __bss_end__ = .;\r
+\r
+       .commonarea (NOLOAD) : {\r
+               *(.commonarea)\r
+       } >commonarea\r
 }\r
index c80b650c670385a291e680226a5d664671a426e7..f88b3cdd2598609f5d5150cf1352cfcac8f658bc 100644 (file)
@@ -5,6 +5,13 @@ ARMSRC = fromflash.c
 THUMBSRC = usb.c bootrom.c\r
 ASMSRC = ram-reset.s flash-reset.s\r
 \r
+## There is a strange bug with the linker: Sometimes it will not emit the glue to call\r
+## BootROM from ARM mode. The symbol is emitted, but the section will be filled with\r
+## zeroes. As a temporary workaround, do not use thumb for the phase 2 bootloader\r
+## -- Henryk Plötz <henryk@ploetzli.ch> 2009-09-01\r
+ARMSRC := $(ARMSRC) $(THUMBSRC)\r
+THUMBSRC := \r
+\r
 # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC\r
 include ../common/Makefile.common\r
 \r
index 2d94f01ae4559d6c56ca7cf8f9bb7ae0716bed4f..c8c695cc9f6c097b4b7b4f70771ff02711e0c7b6 100644 (file)
@@ -1,5 +1,9 @@
 #include <proxmark3.h>\r
 \r
+struct common_area common_area __attribute__((section(".commonarea")));\r
+unsigned int start_addr, end_addr, bootrom_unlocked; \r
+extern char _bootrom_start, _bootrom_end, _flash_start, _flash_end;\r
+\r
 static void ConfigClocks(void)\r
 {\r
     // we are using a 16 MHz crystal as the basis for everything\r
@@ -63,7 +67,7 @@ static void Fatal(void)
 \r
 void UsbPacketReceived(BYTE *packet, int len)\r
 {\r
-    int i;\r
+    int i, dont_ack=0;\r
     UsbCommand *c = (UsbCommand *)packet;\r
     volatile DWORD *p;\r
 \r
@@ -73,38 +77,113 @@ void UsbPacketReceived(BYTE *packet, int len)
 \r
     switch(c->cmd) {\r
         case CMD_DEVICE_INFO:\r
+            dont_ack = 1;\r
+            c->cmd = CMD_DEVICE_INFO;\r
+            c->ext1 = DEVICE_INFO_FLAG_BOOTROM_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM | \r
+                DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH;\r
+            if(common_area.flags.osimage_present) c->ext1 |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT;\r
+            UsbSendPacket(packet, len);\r
             break;\r
 \r
         case CMD_SETUP_WRITE:\r
-            p = (volatile DWORD *)0;\r
+            /* The temporary write buffer of the embedded flash controller is mapped to the\r
+             * whole memory region, only the last 8 bits are decoded.
+             */\r
+            p = (volatile DWORD *)&_flash_start;\r
             for(i = 0; i < 12; i++) {\r
                 p[i+c->ext1] = c->d.asDwords[i];\r
             }\r
             break;\r
 \r
         case CMD_FINISH_WRITE:\r
-            p = (volatile DWORD *)0;\r
+            p = (volatile DWORD *)&_flash_start;\r
             for(i = 0; i < 4; i++) {\r
                 p[i+60] = c->d.asDwords[i];\r
             }\r
 \r
-            MC_FLASH_COMMAND = MC_FLASH_COMMAND_KEY |\r
-                MC_FLASH_COMMAND_PAGEN(c->ext1/FLASH_PAGE_SIZE_BYTES) |\r
-                FCMD_WRITE_PAGE;\r
+            /* Check that the address that we are supposed to write to is within our allowed region */\r
+            if( ((c->ext1+FLASH_PAGE_SIZE_BYTES-1) >= end_addr) || (c->ext1 < start_addr) ) {\r
+                /* Disallow write */\r
+                dont_ack = 1;\r
+                c->cmd = CMD_NACK;\r
+                UsbSendPacket(packet, len);\r
+            } else {\r
+                /* Translate address to flash page and do flash, update here for the 512k part */\r
+                MC_FLASH_COMMAND = MC_FLASH_COMMAND_KEY |\r
+                    MC_FLASH_COMMAND_PAGEN((c->ext1-(int)&_flash_start)/FLASH_PAGE_SIZE_BYTES) |\r
+                    FCMD_WRITE_PAGE;\r
+            }\r
             while(!(MC_FLASH_STATUS & MC_FLASH_STATUS_READY))\r
                 ;\r
             break;\r
 \r
         case CMD_HARDWARE_RESET:\r
+            USB_D_PLUS_PULLUP_OFF();\r
+            RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET;\r
             break;\r
-\r
+        \r
+        case CMD_START_FLASH:\r
+            if(c->ext3 == START_FLASH_MAGIC) bootrom_unlocked = 1;\r
+            else bootrom_unlocked = 0;\r
+            {\r
+                int prot_start = (int)&_bootrom_start;\r
+                int prot_end = (int)&_bootrom_end;\r
+                int allow_start = (int)&_flash_start;\r
+                int allow_end = (int)&_flash_end;\r
+                int cmd_start = c->ext1;\r
+                int cmd_end = c->ext2;\r
+                \r
+                /* Only allow command if the bootrom is unlocked, or the parameters are outside of the protected\r
+                 * bootrom area. In any case they must be within the flash area.
+                 */\r
+                if( (bootrom_unlocked || ((cmd_start >= prot_end) || (cmd_end < prot_start)))\r
+                    && (cmd_start >= allow_start) && (cmd_end <= allow_end) ) {\r
+                    start_addr = cmd_start;\r
+                    end_addr = cmd_end;\r
+                } else {\r
+                    start_addr = end_addr = 0;\r
+                    dont_ack = 1;\r
+                    c->cmd = CMD_NACK;\r
+                    UsbSendPacket(packet, len);\r
+                }\r
+            }\r
+            break;\r
+        \r
         default:\r
             Fatal();\r
             break;\r
     }\r
 \r
-    c->cmd = CMD_ACK;\r
-    UsbSendPacket(packet, len);\r
+    if(!dont_ack) {\r
+        c->cmd = CMD_ACK;\r
+        UsbSendPacket(packet, len);\r
+    }\r
+}\r
+\r
+static void flash_mode(int externally_entered)\r
+{\r
+       start_addr = 0;\r
+       end_addr = 0;\r
+       bootrom_unlocked = 0;\r
+       \r
+       UsbStart();\r
+       for(;;) {\r
+               WDT_HIT();\r
+               \r
+               UsbPoll(TRUE);\r
+               \r
+               if(!externally_entered && !BUTTON_PRESS()) {\r
+                       /* Perform a reset to leave flash mode */\r
+                       USB_D_PLUS_PULLUP_OFF();\r
+                       LED_B_ON();\r
+                       RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET;\r
+                       for(;;);\r
+               }\r
+               if(externally_entered && BUTTON_PRESS()) {\r
+                       /* Let the user's button press override the automatic leave */\r
+                       externally_entered = 0;\r
+               }\r
+       }\r
 }\r
 \r
 extern char _osimage_entry;\r
@@ -153,38 +232,55 @@ void BootROM(void)
     LED_C_ON();\r
     LED_B_OFF();\r
     LED_A_OFF();\r
-\r
-       // if 512K FLASH part - TODO make some defines :)\r
-       if ((DBGU_CIDR | 0xf00) == 0xa00) {\r
-               MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
-                       MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
-               MC_FLASH_MODE1 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
-                       MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
-       } else {\r
-               MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(0) |\r
-                       MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);\r
-       }\r
-\r
-       // Initialize all system clocks\r
+    \r
+    // if 512K FLASH part - TODO make some defines :)\r
+    if ((DBGU_CIDR | 0xf00) == 0xa00) {\r
+           MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
+           MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
+           MC_FLASH_MODE1 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
+           MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
+    } else {\r
+           MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(0) |\r
+           MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);\r
+    }\r
+    \r
+    // Initialize all system clocks\r
     ConfigClocks();\r
-\r
+    \r
     LED_A_ON();\r
-\r
-       if(BUTTON_PRESS()) {\r
-       UsbStart();\r
-       }\r
-\r
-    for(;;) {\r
-        WDT_HIT();\r
-\r
-        UsbPoll(TRUE);\r
-\r
-               if(!BUTTON_PRESS()) {\r
-            USB_D_PLUS_PULLUP_OFF();\r
-            LED_B_ON();\r
-\r
-                       // jump to Flash address of the osimage entry point (LSBit set for thumb mode)\r
-            asm("bx %0\n" : : "r" ( ((int)&_osimage_entry) | 0x1 ) );\r
-        }\r
+    \r
+    int common_area_present = 0;\r
+    switch(RSTC_STATUS & RST_STATUS_TYPE_MASK) {\r
+    case RST_STATUS_TYPE_WATCHDOG:\r
+    case RST_STATUS_TYPE_SOFTWARE:\r
+    case RST_STATUS_TYPE_USER:\r
+           /* In these cases the common_area in RAM should be ok, retain it if it's there */\r
+           if(common_area.magic == COMMON_AREA_MAGIC && common_area.version == 1) {\r
+                   common_area_present = 1;\r
+           }\r
+           break;\r
+    default: /* Otherwise, initialize it from scratch */\r
+           break;\r
+    }\r
+    \r
+    if(!common_area_present){\r
+           /* Common area not ok, initialize it */\r
+           int i; for(i=0; i<sizeof(common_area); i++) { /* Makeshift memset, no need to drag util.c into this */\r
+                   ((char*)&common_area)[i] = 0;\r
+           }\r
+           common_area.magic = COMMON_AREA_MAGIC;\r
+           common_area.version = 1;\r
+           common_area.flags.bootrom_present = 1;\r
+    }\r
+    \r
+    common_area.flags.bootrom_present = 1;\r
+    if(common_area.command == COMMON_AREA_COMMAND_ENTER_FLASH_MODE) {\r
+           common_area.command = COMMON_AREA_COMMAND_NONE;\r
+           flash_mode(1);\r
+    } else if(BUTTON_PRESS()) {\r
+           flash_mode(0);\r
+    } else {\r
+           // jump to Flash address of the osimage entry point (LSBit set for thumb mode)\r
+           asm("bx %0\n" : : "r" ( ((int)&_osimage_entry) | 0x1 ) );\r
     }\r
 }\r
index 142924a8508dc51b35d718d4e94d9bbd19fc0277..777ac8bc04c18fefe3a3c4f2abec041691ba280d 100644 (file)
@@ -45,4 +45,8 @@ SECTIONS
     \r
     . = ALIGN( 32 / 8 );\r
     __bss_end__ = .;\r
+    \r
+    .commonarea (NOLOAD) : {\r
+       *(.commonarea)\r
+    } >commonarea\r
 }\r
index bba99ecd1e01e5766bee1698e71fc9a877c6024b..51d60cce1b03a17c8479d0bf63f58227f26bc33e 100644 (file)
@@ -39,10 +39,11 @@ DETECTED_OS=Windows
 
 endif
 
-CC     = arm-elf-gcc
-AS     = arm-elf-as
-LD     = arm-elf-ld
-OBJCOPY = arm-elf-objcopy
+CROSS   = arm-elf-
+CC     = $(CROSS)gcc
+AS     = $(CROSS)as
+LD     = $(CROSS)ld
+OBJCOPY = $(CROSS)objcopy
 
 OBJDIR = obj
 
@@ -78,8 +79,8 @@ $(VERSIONOBJ): $(OBJDIR)/%.o: %.c $(INCLUDES)
 $(OBJDIR)/%.s19: $(OBJDIR)/%.elf
        $(OBJCOPY) -Osrec --srec-forceS3 --strip-debug --no-change-warnings \
        --change-addresses -0x100000 --change-start 0 \
-       --change-section-address .bss+0 \
-       --change-section-address .data+0 $^ $@
+       --change-section-address .bss+0 --change-section-address .data+0 \
+       --change-section-address .commonarea+0 $^ $@
 
 # version.c should be remade on every compilation
 .PHONY: version.c
index 98161d3ad7455f10ad018db29914ccb7c42eb44d..ea6fe83be4d78567d5b8190ecd9fb4be527c3ca4 100644 (file)
@@ -11,12 +11,15 @@ MEMORY
         bootphase2 : ORIGIN = 0x00100200, LENGTH = 0x2000 - 0x200 /* Main bootloader code, stored in Flash, executed from RAM */
         fpgaimage  : ORIGIN = 0x00102000, LENGTH = 64k - 0x2000 /* Place where the FPGA image will end up */
         osimage    : ORIGIN = 0x00110000, LENGTH = 256K - 64k /* Place where the main OS will end up */
-        ram        : ORIGIN = 0x00200000, LENGTH = 64K
+        ram        : ORIGIN = 0x00200000, LENGTH = 64K - 0x20 /* RAM, minus small common area */
+        commonarea : ORIGIN = 0x00200000 + 64K - 0x20, LENGTH = 0x20 /* Communication between bootloader and main OS */
 }
 
 /* Export some information that can be used from within the firmware */
 _bootphase1_version_pointer = ORIGIN(bootphase1) + LENGTH(bootphase1) - 0x4;
 _osimage_entry = ORIGIN(osimage);
+_bootrom_start = ORIGIN(bootphase1);
+_bootrom_end = ORIGIN(bootphase2) + LENGTH(bootphase2);
 _flash_start = ORIGIN(bootphase1);
 _flash_end = ORIGIN(osimage) + LENGTH(osimage);
 _stack_end = ORIGIN(ram) + LENGTH(ram) - 8;
index 7095fc853a22410400f2522e5297a6325f01c2f7..31c7164249b07dda68c0b2045c7a3e07ab5d7cd2 100644 (file)
@@ -70,4 +70,18 @@ struct version_information {
        char buildtime[30]; /* string with the build time */\r
 } __attribute__((packed));\r
 \r
+#define COMMON_AREA_MAGIC 0x43334d50\r
+#define COMMON_AREA_COMMAND_NONE 0\r
+#define COMMON_AREA_COMMAND_ENTER_FLASH_MODE 1\r
+struct common_area {\r
+       int magic; /* Magic sequence, to distinguish against random uninitialized memory */\r
+       char version; /* Must be 1 */\r
+       char command;\r
+       struct {\r
+               unsigned int bootrom_present:1; /* Set when a bootrom that is capable of parsing the common area is present */\r
+               unsigned int osimage_present:1; /* Set when a osimage that is capable of parsing the common area is present */\r
+       } __attribute__((packed)) flags;\r
+       int arg1, arg2;\r
+} __attribute__((packed));\r
+\r
 #endif\r
Impressum, Datenschutz