]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - bootrom/bootrom.c
New bootrom
[proxmark3-svn] / bootrom / bootrom.c
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
Impressum, Datenschutz