summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Moń <desowin@gmail.com>2021-05-20 21:16:46 +0200
committerTomasz Moń <desowin@gmail.com>2021-05-21 18:55:14 +0000
commit00b46267907073eb6d03cbbd3bd58e67b2a5475c (patch)
tree78bef7140ac67a941ab95b651510b0c7c184f25c
parent53886079680d3ff782b778b3d307ce1ff3188075 (diff)
downloadrockbox-00b4626790.tar.gz
rockbox-00b4626790.zip
Sansa Connect: Clear recoverzap parameter
Clearing recoverzap parameter exists the Recovery Mode. This makes it possible to run Rockbox on Sansa Connect without relying on original Linux firmware. Enable write-through cache on flash memory as write-back complicates handling without any real benefits. The flash memory accepts commands as series of writes at predefined addresses, so it is important that the cache does not interfere with the writes. Change-Id: I219f962f20953d84df43012cf16bbb16d673add8
-rw-r--r--bootloader/sansaconnect.c140
-rw-r--r--firmware/target/arm/tms320dm320/boot.lds12
-rw-r--r--firmware/target/arm/tms320dm320/crt0.S6
3 files changed, 149 insertions, 9 deletions
diff --git a/bootloader/sansaconnect.c b/bootloader/sansaconnect.c
index a6559fee55..a87b23745f 100644
--- a/bootloader/sansaconnect.c
+++ b/bootloader/sansaconnect.c
@@ -33,6 +33,144 @@
#include "power.h"
#include "loader_strerror.h"
+#define FLASH_BASE 0x00100000
+#define PARAMETERS_FLASH_OFFSET 0x00010000
+#define PARAMETERS_SIZE_BYTES 0x00010000
+#define PARAMETERS_NUM 32
+
+#define FLASH_WRITE(addr, val) *(volatile uint16_t *)(FLASH_BASE + addr) = val
+#define FLASH_READ(addr) *(volatile uint16_t *)(FLASH_BASE + addr)
+
+#define PARAMETER_TYPE_BINARY 0xF00FB00B
+#define PARAMETER_TYPE_LONGBIN 0xBEADFEAD
+#define PARAMETER_TYPE_STRING 0xBEEFFACE
+
+typedef struct
+{
+ uint32_t magic;
+ char name[60];
+ char value[192];
+} parameter_t;
+
+/* Cache all parameters because parameters are stored on a single erase block */
+static union
+{
+ parameter_t entry[PARAMETERS_NUM];
+ /* raw consists of parameter_t array and bootloader graphics */
+ uint16_t raw[PARAMETERS_SIZE_BYTES/sizeof(uint16_t)];
+} parameters;
+
+static void parameters_load_from_flash(void)
+{
+ uint32_t offset = PARAMETERS_FLASH_OFFSET;
+ uint16_t *dst = parameters.raw;
+
+ while (offset < (PARAMETERS_FLASH_OFFSET + PARAMETERS_SIZE_BYTES))
+ {
+ *dst++ = FLASH_READ(offset);
+ offset += sizeof(uint16_t);
+ }
+}
+
+void parameters_erase(void) __attribute__ ((section(".icode")));
+void parameters_erase(void)
+{
+ uint32_t offset = PARAMETERS_FLASH_OFFSET;
+
+ while (offset < (PARAMETERS_FLASH_OFFSET + PARAMETERS_SIZE_BYTES))
+ {
+ if (FLASH_READ(offset) != 0xFFFF)
+ {
+ /* Found programmed halfword */
+ break;
+ }
+ offset += sizeof(uint16_t);
+ }
+
+ if (offset >= (PARAMETERS_FLASH_OFFSET + PARAMETERS_SIZE_BYTES))
+ {
+ /* Flash is already erased */
+ return;
+ }
+
+ /* Execute Block Erase sequence */
+ FLASH_WRITE(0xAAA, 0xAA);
+ FLASH_WRITE(0x554, 0x55);
+ FLASH_WRITE(0xAAA, 0x80);
+ FLASH_WRITE(0xAAA, 0xAA);
+ FLASH_WRITE(0x554, 0x55);
+ FLASH_WRITE(PARAMETERS_FLASH_OFFSET, 0x30);
+
+ /* Erase finishes once we read 0xFFFF on previously programmed halfword
+ * Typical block erase time is 0.7 s, maximum 15 s. Do not check the
+ * timeout here because we have to wait until the erase finishes as most
+ * of Rockbox bootloader code executes from flash.
+ */
+ do
+ {
+ /* Discard caches to force reads from memory */
+ commit_discard_idcache();
+ }
+ while (FLASH_READ(offset) != 0xFFFF);
+}
+
+void parameters_write_to_flash(void) __attribute__ ((section(".icode")));
+void parameters_write_to_flash(void)
+{
+ uint16_t *src = parameters.raw;
+ uint32_t offset = PARAMETERS_FLASH_OFFSET;
+
+ while (offset < (PARAMETERS_FLASH_OFFSET + PARAMETERS_SIZE_BYTES))
+ {
+ if (FLASH_READ(offset) != *src)
+ {
+ /* Program halfword */
+ FLASH_WRITE(0xAAA, 0xAA);
+ FLASH_WRITE(0x554, 0x55);
+ FLASH_WRITE(0xAAA, 0xA0);
+ FLASH_WRITE(offset, *src);
+
+ /* Word programming time typical is 14 us, maximum 330 us */
+ do
+ {
+ /* Discard caches to force reads from memory */
+ commit_discard_idcache();
+ }
+ while (FLASH_READ(offset) != *src);
+ }
+ offset += sizeof(uint16_t);
+ src++;
+ }
+}
+
+static void clear_recoverzap(void)
+{
+ int i;
+ bool needs_reflash = false;
+
+ parameters_load_from_flash();
+ for (i = 0; i < PARAMETERS_NUM; i++)
+ {
+ if ((parameters.entry[i].magic == PARAMETER_TYPE_STRING) &&
+ (!strcmp("recoverzap", parameters.entry[i].name)))
+ {
+ memset(&parameters.entry[i], 0xFF, sizeof(parameter_t));
+ needs_reflash = true;
+ }
+ }
+
+ if (needs_reflash)
+ {
+ int cpsr = disable_interrupt_save(IRQ_FIQ_STATUS);
+ printf("Erasing OF parameters memory");
+ parameters_erase();
+ printf("Flashing OF parameters");
+ parameters_write_to_flash();
+ printf("Cleared recoverzap parameter");
+ restore_interrupt(cpsr);
+ }
+}
+
extern void show_logo(void);
void main(void)
@@ -69,6 +207,8 @@ void main(void)
printf("Rockbox boot loader");
printf("Version %s", rbversion);
+ clear_recoverzap();
+
ret = storage_init();
if(ret)
printf("SD error: %d", ret);
diff --git a/firmware/target/arm/tms320dm320/boot.lds b/firmware/target/arm/tms320dm320/boot.lds
index c59cc7f514..2db687d533 100644
--- a/firmware/target/arm/tms320dm320/boot.lds
+++ b/firmware/target/arm/tms320dm320/boot.lds
@@ -38,12 +38,12 @@ STARTUP(target/arm/tms320dm320/crt0.o)
#ifdef SANSA_CONNECT
/* Offset in flash from beginning, we don't want overwrite OF bootloader
- due to recovery mode and more importantly - hardware block protection.
- This offset makes Rockbox bootloader a replacement for OF vmlinux.
- In .srr file header add any valid memory address from following
- <0x1000000; 0x1300180) u (0x131EAF4; 0x1420000) u (0x1440000; 0x5000000>
- ensuring that complete bootloader fits in.
- Entry point in .srr file should be equal to _loadaddress. */
+ * due to recovery mode and more importantly - hardware block protection.
+ * Rockbox bootloader is flashed into kernel partition and chainloaded
+ * from OF bootloader via Arbitrary Code Execution exploit. The first
+ * instruction must be position independent as Rockbox bootloader will be
+ * copied to RAM at 0x01000000 and executed from RAM.
+ */
#define FLASHSIZE 0x00400000
#define FLASHMEMORIG 0x00120010
/* Kernel partition is 2 M, srr header is 16 bytes, sig is 2048 bytes */
diff --git a/firmware/target/arm/tms320dm320/crt0.S b/firmware/target/arm/tms320dm320/crt0.S
index 9f2c8dbe04..e57e28a470 100644
--- a/firmware/target/arm/tms320dm320/crt0.S
+++ b/firmware/target/arm/tms320dm320/crt0.S
@@ -201,14 +201,14 @@ _start:
mov r3, #CACHE_NONE
bl map_section
- /* Enable caching for FLASH */
+ /* Enable write-through caching for FLASH */
ldr r0, =_flash_start
ldr r1, =_flash_start
ldr r2, =_flash_sizem
- mov r3, #CACHE_ALL
+ mov r3, #(CACHE_ALL & ~BUFFERED)
bl map_section
- /* Enable caching for RAM */
+ /* Enable write-back caching for RAM */
ldr r0, =_sdram_start
ldr r1, =_sdram_start
ldr r2, =_sdram_sizem