/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: bootloader.c,v 1.0 2003/07/04 08:20:30 hohensoh Exp $ * * Copyright (C) 2003 by Jörg Hohensohn * * Second-level bootloader, with dual-boot feature by holding F1/Menu * This is the image being descrambled and executed by the boot ROM. * It's task is to copy Rockbox from Flash to DRAM. * The image(s) in flash may optionally be compressed with UCL 2e * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "sh7034.h" #ifndef NULL #define NULL ((void*)0) #endif // scalar types typedef unsigned char UINT8; typedef unsigned short UINT16; typedef unsigned long UINT32; typedef void(*tpFunc)(void); // type for execute typedef int(*tpMain)(void); // type for start vector to main() // resolve platform dependency of F1 button check #if defined PLATFORM_PLAYER #define CHANNEL 1 #define LOWER 0 #define UPPER 384 #elif defined PLATFORM_RECORDER #define CHANNEL 4 #define LOWER 250 #define UPPER 500 #elif defined PLATFORM_FM #define CHANNEL 4 #define LOWER 150 #define UPPER 385 #else #error ("No platform given!") #endif #define FLASH_BASE 0x02000000 // start of the flash memory // structure of an image in the flash typedef struct { UINT32* pDestination; // address to copy it to UINT32 size; // how many bytes of payload (to the next header) tpFunc pExecute; // entry point UINT32 flags; // uncompressed or compressed // end of header, now comes the payload UINT32 image[]; // the binary image starts here // after the payload, the next header may follow, all 0xFF if none } tImage; // flags valid for image header #define IF_NONE 0x00000000 #define IF_UCL_2E 0x00000001 // image is compressed with UCL, algorithm 2e // prototypes int main(void); // our binary has to start with a vector to the entry point tpMain start_vector[] __attribute__ ((section (".startvector"))) = {main}; // Thinned out version of the UCL 2e decompression sourcecode // Original (C) Markus F.X.J Oberhumer under GNU GPL license #define GETBIT(bb, src, ilen) \ (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1) int ucl_nrv2e_decompress_8( const UINT8 *src, UINT8 *dst, UINT32* dst_len) { UINT32 bb = 0; unsigned ilen = 0, olen = 0, last_m_off = 1; for (;;) { unsigned m_off, m_len; while (GETBIT(bb,src,ilen)) { dst[olen++] = src[ilen++]; } m_off = 1; for (;;) { m_off = m_off*2 + GETBIT(bb,src,ilen); if (GETBIT(bb,src,ilen)) break; m_off = (m_off-1)*2 + GETBIT(bb,src,ilen); } if (m_off == 2) { m_off = last_m_off; m_len = GETBIT(bb,src,ilen); } else { m_off = (m_off-3)*256 + src[ilen++]; if (m_off == 0xffffffff) break; m_len = (m_off ^ 0xffffffff) & 1; m_off >>= 1; last_m_off = ++m_off; } if (m_len) m_len = 1 + GETBIT(bb,src,ilen); else if (GETBIT(bb,src,ilen)) m_len = 3 + GETBIT(bb,src,ilen); else { m_len++; do { m_len = m_len*2 + GETBIT(bb,src,ilen); } while (!GETBIT(bb,src,ilen)); m_len += 3; } m_len += (m_off > 0x500); { const UINT8 *m_pos; m_pos = dst + olen - m_off; dst[olen++] = *m_pos++; do dst[olen++] = *m_pos++; while (--m_len > 0); } } *dst_len = olen; return ilen; } // move the image into place and start it void DecompressStart(tImage* pImage) { UINT32* pSrc; UINT32* pDest; pSrc = pImage->image; pDest = pImage->pDestination; if (pSrc != pDest) // if not linked to that flash address { if (pImage->flags & IF_UCL_2E) { // UCL compressed, algorithm 2e UINT32 dst_len; // dummy ucl_nrv2e_decompress_8((UINT8*)pSrc, (UINT8*)pDest, &dst_len); } else { // uncompressed, copy it UINT32 size = pImage->size; size = (size + 3) / 4; // round up to 32bit-words while (size--) { *pDest++ = *pSrc++; } } } pImage->pExecute(); } int ReadADC(int channel) { // after channel 3, the ports wrap and get re-used volatile UINT16* pResult = (UINT16*)(ADDRAH_ADDR + 2 * (channel & 0x03)); int timeout = 266; // conversion takes 266 clock cycles ADCSR = 0x20 | channel; // start single conversion while (((ADCSR & 0x80) == 0) && (--timeout)); // 6 instructions per round return (timeout == 0) ? -1 : *pResult>>6; } // This function is platform-dependent, // until I figure out how to distinguish at runtime. int IsButtonPressed(void) // return if F1/Menu is pressed { int value = ReadADC(CHANNEL); if (value >= LOWER && value <= UPPER) // in range { return 1; } return 0; } // Determine the image to be started tImage* GetStartImage(void) { tImage* pImage1; tImage* pImage2 = NULL; // default to not present UINT32 pos; UINT32* pFlash = (UINT32*)FLASH_BASE; // determine the first image position pos = pFlash[2] + pFlash[3]; // position + size of the bootloader = after it pos = (pos + 3) & ~3; // be shure it's 32 bit aligned pImage1 = (tImage*)pos; if (pImage1->size != 0) { // check for second image pos = (UINT32)(&pImage1->image) + pImage1->size; pImage2 = (tImage*)pos; // does it make sense? (not in FF or 00 erazed space) if (pImage2->pDestination == (void*)0xFFFFFFFF || pImage2->size == 0xFFFFFFFF || pImage2->pExecute == (void*)0xFFFFFFFF || pImage2->flags == 0xFFFFFFFF || pImage2->pDestination == NULL) // size, execute and flags can legally be 0 { pImage2 = NULL; // invalidate } } if (pImage2 == NULL || IsButtonPressed()) { // no second image or overridden: return the first return pImage1; } return pImage2; // return second image } int main(void) { tImage* pImage; DCR |= 0x1000; // enable burst mode on DRAM BCR |= 0x2000; // activate Warp mode (simultaneous internal and external mem access) pImage = GetStartImage(); // which image DecompressStart(pImage); // move into place and start it return 0; // I guess we won't return ;-) }