mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-09 23:53:28 -04:00
rk27xx: pass the NAND bootloader's handoff words to the OF
Before it jumps to an image, the rk27xx NAND bootloader writes three words at the address in RKW header field 0x14: a magic, its version and which copy of the image it loaded. The original firmware never initialises them: it reports the version over USB and counts its own reboots in the third word, and once the count reaches 5 it reboots into a mode the NAND bootloader will not boot. When our bootloader started the OF, nothing wrote them, so the OF ran with whatever was left in DRAM. Field 0x14 of our own images held a constant taken from some other image. Point it at the last 12 bytes of DRAM, which nothing uses before our bootloader runs. load_rkw() in the bootloader now reads the words there before loading an image, and writes them at the address in the loaded image's header when that lies between the image and the bootloader. Started over USB, it passes version 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Change-Id: Ife1d63e361a780c28a9f0626d110552b98bb6b7f
This commit is contained in:
parent
e61aa0cd37
commit
c3a62cee96
3 changed files with 98 additions and 2 deletions
|
|
@ -30,7 +30,9 @@ struct rkw_header_t {
|
|||
uint32_t image_base; /* Base address of the firmware image */
|
||||
uint32_t load_address; /* Load address */
|
||||
uint32_t load_limit; /* End of the firmware image */
|
||||
uint32_t bss_start; /* This is the start of .bss section of the firmware I suppose */
|
||||
uint32_t handoff; /* Where the loader leaves its three handoff
|
||||
* words for the image (see rkw-loader.c)
|
||||
*/
|
||||
uint32_t reserved0; /* reserved - I've seen only zeros in this field so far */
|
||||
uint32_t reserved1; /* reserved - I've seen only zeros in this field so far */
|
||||
uint32_t entry_point; /* Entry point address */
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "config.h"
|
||||
#include "loader_strerror.h"
|
||||
#include "rkw-loader.h"
|
||||
|
|
@ -26,6 +27,82 @@
|
|||
#include "file.h"
|
||||
#include "panic.h"
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
/* Before the NAND bootloader jumps to an image it writes three words at
|
||||
* the address in header field 0x14: a magic, its own version and which
|
||||
* copy of the image it loaded. The OF never initialises them; it reports
|
||||
* the version over USB and counts its reboots in the third word. When we
|
||||
* start the OF ourselves we pass on what the NAND bootloader gave us, so
|
||||
* the OF sees the same as when it is started directly.
|
||||
*/
|
||||
#define RKW_HANDOFF_MAGIC 0x03df479a
|
||||
/* written over the magic once the words have been read */
|
||||
#define RKW_HANDOFF_CONSUMED 0x123456ad
|
||||
|
||||
/* The last 12 bytes of DRAM. tools/rkw.c puts this address in every
|
||||
* Rockbox RKW, so the NAND bootloader leaves our words here.
|
||||
*/
|
||||
#define RKW_HANDOFF_ADDR (0x60000000 + MEMORYSIZE * 0x100000 - 12)
|
||||
#if MEMORYSIZE != 16
|
||||
#error "tools/rkw.c assumes 16 MB of DRAM, update RKW_HANDOFF_ADDR there"
|
||||
#endif
|
||||
|
||||
struct rkw_handoff_t {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t source;
|
||||
};
|
||||
|
||||
/* The NAND bootloader's words, read once: loading an image may overwrite
|
||||
* them, and a reboot keeps DRAM, so they are marked consumed.
|
||||
*/
|
||||
static struct rkw_handoff_t *rkw_own_handoff(void)
|
||||
{
|
||||
static struct rkw_handoff_t own;
|
||||
static bool read_done = false;
|
||||
volatile struct rkw_handoff_t *h =
|
||||
(volatile struct rkw_handoff_t *)RKW_HANDOFF_ADDR;
|
||||
|
||||
if (!read_done)
|
||||
{
|
||||
if (h->magic == RKW_HANDOFF_MAGIC)
|
||||
{
|
||||
own.version = h->version;
|
||||
own.source = h->source;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not started by the NAND bootloader, e.g. over USB */
|
||||
own.version = 0;
|
||||
own.source = 0;
|
||||
}
|
||||
own.magic = RKW_HANDOFF_MAGIC;
|
||||
h->magic = RKW_HANDOFF_CONSUMED;
|
||||
read_done = true;
|
||||
}
|
||||
|
||||
return &own;
|
||||
}
|
||||
|
||||
/* Hand the words on to an image loaded at its own address, when its
|
||||
* header points past the image and below us.
|
||||
*/
|
||||
static void rkw_pass_handoff(const struct rkw_header_t *hdr,
|
||||
const unsigned char *buf, int len,
|
||||
int buffer_size)
|
||||
{
|
||||
uintptr_t addr = hdr->handoff;
|
||||
uintptr_t lo = (uintptr_t)buf + len;
|
||||
uintptr_t hi = (uintptr_t)buf + buffer_size;
|
||||
|
||||
if ((uintptr_t)buf != hdr->load_address || (addr & 3) ||
|
||||
addr < lo || addr > hi - sizeof(struct rkw_handoff_t))
|
||||
return;
|
||||
|
||||
*(struct rkw_handoff_t *)addr = *rkw_own_handoff();
|
||||
}
|
||||
#endif /* BOOTLOADER */
|
||||
|
||||
/* loosely based on load_firmware()
|
||||
* on success we return size of loaded image
|
||||
* on error we return negative value which can be deciphered by means
|
||||
|
|
@ -116,6 +193,11 @@ int load_rkw(unsigned char* buf, const char* firmware, int buffer_size)
|
|||
goto end;
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
/* before the image can overwrite them */
|
||||
rkw_own_handoff();
|
||||
#endif
|
||||
|
||||
/* skip header */
|
||||
lseek(fd, sizeof(rkw_info), SEEK_SET);
|
||||
|
||||
|
|
@ -141,6 +223,10 @@ int load_rkw(unsigned char* buf, const char* firmware, int buffer_size)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
rkw_pass_handoff(&rkw_info, buf, len, buffer_size);
|
||||
#endif
|
||||
|
||||
ret = len;
|
||||
end:
|
||||
close(fd);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue