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(¶meters.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