diff options
29 files changed, 3349 insertions, 1 deletions
diff --git a/flash/README b/flash/README index 304360caba..9f77dd502f 100644 --- a/flash/README +++ b/flash/README @@ -1 +1,7 @@ -Readme +(c) 2003 by Jörg Hohensohn + +Sourcecode for the flash "infrastructure" +Please bear in mind that these are powerful tools, don't fool with them! + +For most up-to-date info about flashing see: +http://rockbox.haxx.se/docs/flash.html diff --git a/flash/bootloader/Makefile b/flash/bootloader/Makefile new file mode 100644 index 0000000000..ae56cf9425 --- /dev/null +++ b/flash/bootloader/Makefile @@ -0,0 +1,78 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +CC = sh-elf-gcc +LD = sh-elf-ld +AR = sh-elf-ar +AS = sh-elf-as +OC = sh-elf-objcopy + +FIRMWARE := ../../firmware +TOOLSDIR=../../tools + +TARGET = bootloader +LDS := $(TARGET).lds + + +ifndef PLATFORM +not_configured: + @echo "No platform given." + @echo "Use make PLATFORM=PLAYER|RECORDER|RECORDER|FM {NO_ROM=1}" +##else +##configured: +## @echo "Building bootloader for platform "$(PLATFORM) +endif + + +INCLUDES= -I$(FIRMWARE)/export -I. -I$(OBJDIR) +DEFINES= -DPLATFORM_$(PLATFORM) + +OBJDIR := . + +CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(DEFINES) +AFLAGS += -small -relax + + +ifdef DEBUG + DEFINES := -DDEBUG + CFLAGS += -g +endif + +SRC := $(wildcard *.c) + +OBJS := $(SRC:%.c=$(OBJDIR)/%.o) + +ifdef NO_ROM +LINKFILE = $(OBJDIR)/no_rom.lds +ORIGIN = 0 +DEFINES += -DNO_ROM +else +LINKFILE = $(OBJDIR)/$(TARGET).lds +ORIGIN = FFFF500 +endif + +$(OBJDIR)/$(TARGET).bin : $(OBJDIR)/$(TARGET).elf + $(OC) -O binary $(OBJDIR)/$(TARGET).elf $(OBJDIR)/$(TARGET).bin + $(TOOLSDIR)/sh2d $(OBJDIR)/$(TARGET).bin -o $(ORIGIN) > $(OBJDIR)/$(TARGET).asm +ifndef NO_ROM + $(TOOLSDIR)/scramble $(OBJDIR)/$(TARGET).bin $(OBJDIR)/$(TARGET).ajz +endif + +$(OBJDIR)/$(TARGET).elf : $(OBJS) + $(CC) -Os -nostdlib -o $(OBJDIR)/$(TARGET).elf -L$(OBJDIR) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/$(TARGET).map + + +clean: + -rm -f \ + $(OBJS) \ + $(OBJDIR)/$(TARGET).asm \ + $(OBJDIR)/$(TARGET).bin \ + $(OBJDIR)/$(TARGET).ajz \ + $(OBJDIR)/$(TARGET).elf \ + $(OBJDIR)/$(TARGET).map diff --git a/flash/bootloader/README b/flash/bootloader/README new file mode 100644 index 0000000000..16c27d9876 --- /dev/null +++ b/flash/bootloader/README @@ -0,0 +1,4 @@ +(c) 2003 by Jörg Hohensohn + +This is the source code for the flash bootloader. +It give the dual boot feature, decompresses one of two software images. diff --git a/flash/bootloader/bootloader.c b/flash/bootloader/bootloader.c new file mode 100644 index 0000000000..7179bbef95 --- /dev/null +++ b/flash/bootloader/bootloader.c @@ -0,0 +1,480 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * 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" +#include "bootloader.h" + + +#ifdef NO_ROM +// start with the vector table +UINT32 vectors[] __attribute__ ((section (".vectors"))) = +{ + (UINT32)_main, // entry point, the copy routine + (UINT32)(end_stack - 1), // initial stack pointer + FLASH_BASE + 0x200, // source of image in flash + (UINT32)total_size, // size of image + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0x03020080 // mask and version (just as a suggestion) +}; +#else +// our binary has to start with a vector to the entry point +tpMain start_vector[] __attribute__ ((section (".startvector"))) = {main}; +#endif + +#ifdef NO_ROM // some code which is only needed for the romless variant +void _main(void) +{ + UINT32* pSrc; + UINT32* pDest; + UINT32* pEnd; +/* + asm volatile ("ldc %0,sr" : : "r"(0xF0)); // disable interrupts + asm volatile ("mov.l @%0,r15" : : "r"(4)); // load stack + asm volatile ("ldc %0,vbr" : : "r"(0)); // load vector base +*/ + // copy everything to IRAM and continue there + pSrc = begin_iramcopy; + pDest = begin_text; + pEnd = pDest + (begin_stack - begin_text); + + do + { + *pDest++ = *pSrc++; + } + while (pDest < pEnd); + + main(); // jump to the real main() +} + + +void BootInit(void) +{ + // inits from the boot ROM, whether they make sense or not + PBDR &= 0xFFBF; // LED off (0x131E) + PBCR2 = 0; // all GPIO + PBIOR |= 0x40; // LED output + PBIOR &= 0xFFF1; // LCD lines input + + // init DRAM like the boot ROM does + PACR2 &= 0xFFFB; + PACR2 |= 0x0008; + CASCR = 0xAF; + BCR |= 0x8000; + WCR1 &= 0xFDFD; + DCR = 0x0E00; + RCR = 0x5AB0; + RTCOR = 0x9605; + RTCSR = 0xA518; +} +#endif // #ifdef NO_ROM + + +int main(void) +{ + int nButton; + + PlatformInit(); // model-specific inits + + nButton = ButtonPressed(); + + if (nButton == 3) + { // F3 means start monitor + MiniMon(); + } + else + { + tImage* pImage; + pImage = GetStartImage(nButton); // which image + DecompressStart(pImage); // move into place and start it + } + + return 0; // I guess we won't return ;-) +} + + +// init code that is specific to certain platform +void PlatformInit(void) +{ +#ifdef NO_ROM + BootInit(); // if not started by boot ROM, we need to init what it did +#endif + +#if defined PLATFORM_PLAYER + BRR1 = 0x0019; // 14400 Baud for monitor + if (FW_VERSION > 451) // "new" Player? + { + PBDR &= ~0x10; // set PB4 to 0 to power-up the harddisk early + PBIOR |= 0x10; // make PB4 an output + } +#elif defined PLATFORM_RECORDER + BRR1 = 0x0002; // 115200 Baud for monitor + if (ReadADC(7) > 0x100) // charger plugged? + { // switch off the HD, else a flat battery may not start + PACR2 &= 0xFBFF; // GPIO for PA5 + PAIOR |= 0x20; // make PA5 an output (low by default) + } +#elif defined PLATFORM_FM + BRR1 = 0x0002; // 115200 Baud for monitor + PBDR |= 0x20; // set PB5 to keep power (fixes the ON-holding problem) + PBIOR |= 0x20; // make PB5 an output + if (ReadADC(0) < 0x1FF) // charger plugged? + { + // how do we switch this off? + } +#endif + + // platform-independent inits + DCR |= 0x1000; // enable burst mode on DRAM + BCR |= 0x2000; // activate Warp mode (simultaneous internal and external mem access) +} + + +// 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; + UINT32* pEnd; + size = (size + 3) / 4; // round up to 32bit-words + pEnd = pDest + size; + + do + { + *pDest++ = *pSrc++; + } + while (pDest < pEnd); + } + } + + 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 ButtonPressed(void) // return 1,2,3 for F1,F2,F3, 0 if none pressed +{ + int value = ReadADC(CHANNEL); + + if (value >= F1_LOWER && value <= F1_UPPER) // in range + return 1; + else if (value >= F2_LOWER && value <= F2_UPPER) // in range + return 2; + else if (value >= F3_LOWER && value <= F3_UPPER) // in range + return 3; + + return 0; +} + + +// Determine the image to be started +tImage* GetStartImage(int nPreferred) +{ + 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 || nPreferred == 1) + { // no second image or overridden: return the first + return pImage1; + } + + return pImage2; // return second image +} + +// diagnostic functions + +void SetLed(BOOL bOn) +{ + if (bOn) + PBDR |= 0x40; + else + PBDR &= ~0x40; +} + + +void UartInit(void) +{ + PBIOR &= 0xFBFF; // input: RXD1 remote pin + PBCR1 |= 0x00A0; // set PB3+PB2 to UART + PBCR1 &= 0xFFAF; // clear bits 6, 4 -> UART + SMR1 = 0x0000; // async format 8N1, baud generator input is CPU clock + SCR1 = 0x0030; // transmit+receive enable + PBCR1 &= 0x00FF; // set bit 12...15 as GPIO + SSR1 &= 0x00BF; // clear bit 6 (RDRF, receive data register full) +} + + +UINT8 UartRead(void) +{ + UINT8 byte; + while (!(SSR1 & SCI_RDRF)); // wait for char to be available + byte = RDR1; + SSR1 &= ~SCI_RDRF; + return byte; +} + + +void UartWrite(UINT8 byte) +{ + while (!(SSR1 & SCI_TDRE)); // wait for transmit buffer empty + TDR1 = byte; + SSR1 &= ~SCI_TDRE; +} + + +// include the mini monitor as a rescue feature, started with F3 +void MiniMon(void) +{ + UINT8 cmd; + UINT32 addr; + UINT32 size; + UINT32 content; + volatile UINT8* paddr = NULL; + volatile UINT8* pflash = NULL; // flash base address + + UartInit(); + + while (1) + { + cmd = UartRead(); + switch (cmd) + { + case BAUDRATE: + content = UartRead(); + UartWrite(cmd); // acknowledge by returning the command value + while (!(SSR1 & SCI_TEND)); // wait for empty shift register, before changing baudrate + BRR1 = content; + break; + + case ADDRESS: + addr = (UartRead() << 24) | (UartRead() << 16) | (UartRead() << 8) | UartRead(); + paddr = (UINT8*)addr; + pflash = (UINT8*)(addr & 0xFFF80000); // round down to 512k align + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_READ: + content = *paddr++; + UartWrite(content); // the content is the ack + break; + + case BYTE_WRITE: + content = UartRead(); + *paddr++ = content; + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_READ16: + size = 16; + while (size--) + { + content = *paddr++; + UartWrite(content); // the content is the ack + } + break; + + case BYTE_WRITE16: + size = 16; + while (size--) + { + content = UartRead(); + *paddr++ = content; + } + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_FLASH: + content = UartRead(); + pflash[0x5555] = 0xAA; // set flash to command mode + pflash[0x2AAA] = 0x55; + pflash[0x5555] = 0xA0; // byte program command + *paddr++ = content; + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_FLASH16: + size = 16; + while (size--) + { + content = UartRead(); + pflash[0x5555] = 0xAA; // set flash to command mode + pflash[0x2AAA] = 0x55; + pflash[0x5555] = 0xA0; // byte program command + *paddr++ = content; + } + UartWrite(cmd); // acknowledge by returning the command value + break; + + case HALFWORD_READ: + content = *(UINT16*)paddr; + paddr += 2; + UartWrite(content >> 8); // highbyte + UartWrite(content & 0xFF); // lowbyte + break; + + case HALFWORD_WRITE: + content = UartRead() << 8 | UartRead(); + *(UINT16*)paddr = content; + paddr += 2; + UartWrite(cmd); // acknowledge by returning the command value + break; + + case EXECUTE: + { + tpFunc pFunc = (tpFunc)paddr; + pFunc(); + UartWrite(cmd); // acknowledge by returning the command value + } + break; + + case VERSION: + UartWrite(1); // return our version number + break; + + default: + { + SetLed(TRUE); + UartWrite(~cmd); // error acknowledge + } + + } // case + } // while (1) +} diff --git a/flash/bootloader/bootloader.h b/flash/bootloader/bootloader.h new file mode 100644 index 0000000000..eee61c4809 --- /dev/null +++ b/flash/bootloader/bootloader.h @@ -0,0 +1,111 @@ +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +// scalar types +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned long UINT32; +typedef int BOOL; + +typedef void(*tpFunc)(void); // type for execute +typedef int(*tpMain)(void); // type for start vector to main() + + +// 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 + + +// resolve platform dependency of F1 button check +#if defined PLATFORM_PLAYER +#define CHANNEL 1 +#define F1_LOWER 0 // this is the "Menu" key +#define F1_UPPER 384 +#define F2_LOWER 1024 // not present +#define F2_UPPER 1024 +#define F3_LOWER 1024 +#define F3_UPPER 1024 +#elif defined PLATFORM_RECORDER +#define CHANNEL 4 +#define F1_LOWER 250 +#define F1_UPPER 499 +#define F2_LOWER 500 +#define F2_UPPER 699 +#define F3_LOWER 900 +#define F3_UPPER 1023 +#elif defined PLATFORM_FM +#define CHANNEL 4 +#define F1_LOWER 150 +#define F1_UPPER 384 +#define F2_LOWER 385 +#define F2_UPPER 544 +#define F3_LOWER 700 +#define F3_UPPER 1023 +#else +#error ("No platform given!") +#endif + +#define FLASH_BASE 0x02000000 // start of the flash memory +#define FW_VERSION *(unsigned short*)(FLASH_BASE + 0xFE) // firmware version + + +// prototypes +void _main(void) __attribute__ ((section (".startup"))); +int main(void); +void PlatformInit(void); +void DramInit(void); +int ucl_nrv2e_decompress_8(const UINT8 *src, UINT8 *dst, UINT32* dst_len); +void DecompressStart(tImage* pImage); +int ReadADC(int channel); +int ButtonPressed(void); +tImage* GetStartImage(int nPreferred); +// test functions +void SetLed(BOOL bOn); +void UartInit(void); +UINT8 UartRead(void); +void UartWrite(UINT8 byte); +void MiniMon(void); + + +// minimon commands +#define BAUDRATE 0x00 // followed by BRR value; response: command byte +#define ADDRESS 0x01 // followed by 4 bytes address; response: command byte +#define BYTE_READ 0x02 // response: 1 byte content +#define BYTE_WRITE 0x03 // followed by 1 byte content; response: command byte +#define BYTE_READ16 0x04 // response: 16 bytes content +#define BYTE_WRITE16 0x05 // followed by 16 bytes; response: command byte +#define BYTE_FLASH 0x06 // followed by 1 byte content; response: command byte +#define BYTE_FLASH16 0x07 // followed by 16 bytes; response: command byte +#define HALFWORD_READ 0x08 // response: 2 byte content +#define HALFWORD_WRITE 0x09 // followed by 2 byte content; response: command byte +#define EXECUTE 0x0A // response: command byte if call returns +#define VERSION 0x0B // response: version + + +// linker symbols +extern UINT32 begin_text[]; +extern UINT32 end_text[]; +extern UINT32 begin_data[]; +extern UINT32 end_data[]; +extern UINT32 begin_bss[]; +extern UINT32 end_bss[]; +extern UINT32 begin_stack[]; +extern UINT32 end_stack[]; +extern UINT32 begin_iramcopy[]; +extern UINT32 total_size[]; diff --git a/flash/bootloader/bootloader.lds b/flash/bootloader/bootloader.lds new file mode 100644 index 0000000000..143d83bdc7 --- /dev/null +++ b/flash/bootloader/bootloader.lds @@ -0,0 +1,34 @@ +OUTPUT_FORMAT(elf32-sh) +INPUT(bootloader.o) + +MEMORY +{ + /* the boot ROM uses IRAM at 400-430, stay away and start at 500 */ + IRAM : ORIGIN = 0x0FFFF500, LENGTH = 0xA00 + /* and leave some room for stack at the end */ +} + +SECTIONS +{ + .startvector : + { + *(.startvector) + . = ALIGN(0x4); + } > IRAM + + .text : + { + *(.text) + . = ALIGN(0x4); + } > IRAM + + .data : + { + *(.data) + } > IRAM + + .bss : + { + *(.bss) + } > IRAM +} diff --git a/flash/bootloader/no_rom.lds b/flash/bootloader/no_rom.lds new file mode 100644 index 0000000000..e65e7fdd3c --- /dev/null +++ b/flash/bootloader/no_rom.lds @@ -0,0 +1,62 @@ +/* This is for the variant without boot ROM, + where the flash ROM is mirrored to address zero */ + +OUTPUT_FORMAT(elf32-sh) +INPUT(bootloader.o) + +MEMORY +{ + IRAM : ORIGIN = 0x0FFFF000, LENGTH = 0x1000 + FLASH : ORIGIN = 0x00000000, LENGTH = 0x40000 +} + +SECTIONS +{ + .vectors : + { + *(.vectors) + . = ALIGN(0x200); + } > FLASH + + .startup : + { + *(.startup) + . = ALIGN(0x4); + _begin_iramcopy = .; + } > FLASH + + .text : AT ( _begin_iramcopy ) + { + _begin_text = .; + *(.text) + . = ALIGN(0x4); + _end_text = .; + } > IRAM + + .data : AT ( _end_text ) + { + _begin_data = .; + *(.data) + . = ALIGN(0x4); + _end_data = .; + } > IRAM + + .bss : AT ( _end_data ) + { + _begin_bss = .; + *(.bss) + . = ALIGN(0x4); + _end_bss = .; + } > IRAM + + .stack : + { + _begin_stack = .; + *(.stack) + . = ALIGN(0x1000); + _end_stack = .; + } > IRAM + + /* size of the program (without vectors) */ + _total_size = SIZEOF(.startup) + SIZEOF(.text) + SIZEOF(.data); +} diff --git a/flash/extract/README b/flash/extract/README new file mode 100644 index 0000000000..b66443aa34 --- /dev/null +++ b/flash/extract/README @@ -0,0 +1,5 @@ +(c) 2003 by Jörg Hohensohn + +This tool extracts the firmware image out of an original Archos ROM dump, +like created with the Rockbox debug->dump feature. +The extracted image can then be used to compose a dual-boot firmware. diff --git a/flash/extract/extract.c b/flash/extract/extract.c new file mode 100644 index 0000000000..31e223a546 --- /dev/null +++ b/flash/extract/extract.c @@ -0,0 +1,140 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2003 by Jörg Hohensohn + * + * Tool to extract the scrambled image out of an Archos flash ROM dump + * + * 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 <stdio.h> +#include <stdlib.h> +#include <memory.h> + +#define UINT8 unsigned char +#define UINT16 unsigned short +#define UINT32 unsigned long + +#define IMAGE_HEADER 0x6000 // a 32 byte header in front of the software image +#define IMAGE_START 0x6020 // software image position in Flash + + +// place a 32 bit value into memory, big endian +void Write32(UINT8* pByte, UINT32 value) +{ + pByte[0] = (UINT8)(value >> 24); + pByte[1] = (UINT8)(value >> 16); + pByte[2] = (UINT8)(value >> 8); + pByte[3] = (UINT8)(value); +} + + +// read a 32 bit value from memory, big endian +UINT32 Read32(UINT8* pByte) +{ + UINT32 value = 0; + + value |= (UINT32)pByte[0] << 24; + value |= (UINT32)pByte[1] << 16; + value |= (UINT32)pByte[2] << 8; + value |= (UINT32)pByte[3]; + + return value; +} + + +// entry point +int main(int argc, char* argv[]) +{ + FILE* pInFile; + FILE* pOutFile; + UINT8 aHeader[6]; + UINT8 aImage[256*1024]; + UINT32 i; + UINT32 uiSize, uiStart; + UINT16 usChecksum = 0; + + if (argc < 2) + { + printf("Extract the software image out of an original Archos Flash ROM dump.\n"); + printf("Result is a scrambled file, use the descramble tool to get the binary,\n"); + printf(" always without the -fm option, even if processing an FM software.\n\n"); + printf("Usage: extract <flash dump file> <output file>\n"); + printf("Example: extract internal_rom_2000000-203FFFF.bin archos.ajz\n"); + exit(0); + } + + pInFile = fopen(argv[1], "rb"); + if (pInFile == NULL) + { + printf("Error opening input file %s\n", argv[1]); + exit(1); + } + + if (fread(aImage, 1, sizeof(aImage), pInFile) != sizeof(aImage)) + { + printf("Error reading input file %s, must be 256kB in size.\n", argv[1]); + fclose(pInFile); + exit(2); + } + fclose(pInFile); + + // find out about the type + uiStart = Read32(aImage + 8); + uiSize = Read32(aImage + 12); // booted ROM image + if (uiStart == 0x02000100 && uiSize > 20000) + { // Player has no loader, starts directly with the image + uiStart = 0x0100; + } + else + { // Recorder / FM / V2 Recorder + uiStart = IMAGE_START; + uiSize = Read32(aImage + IMAGE_HEADER + 4); // size record of header + } + + // sanity check + if (uiSize > sizeof(aImage) - uiStart || uiSize < 40000) + { + printf("Error: Impossible image size &d bytes.\n", uiSize); + exit(3); + } + + // generate checksum + for (i=0; i<uiSize; i++) + usChecksum += aImage[uiStart + i]; + + // make header + Write32(aHeader + 2, usChecksum); // checksum in 5th and 6th byte + Write32(aHeader, uiSize); // size in first 4 bytes + + pOutFile = fopen(argv[2], "wb"); + if (pOutFile == NULL) + { + printf("Error opening output file %s\n", argv[2]); + exit(4); + } + + if (fwrite(aHeader, 1, sizeof(aHeader), pOutFile) != sizeof(aHeader) + || fwrite(aImage + uiStart, 1, uiSize, pOutFile) != uiSize) + { + printf("Write error\n"); + fclose(pOutFile); + exit(5); + } + + fclose(pOutFile); + + return 0; +}
\ No newline at end of file diff --git a/flash/extract/extract.dsp b/flash/extract/extract.dsp new file mode 100644 index 0000000000..e10281a829 --- /dev/null +++ b/flash/extract/extract.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="extract" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=extract - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "extract.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "extract.mak" CFG="extract - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "extract - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "extract - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "extract - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "extract - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "extract - Win32 Release" +# Name "extract - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\extract.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/flash/make_firmware/README b/flash/make_firmware/README new file mode 100644 index 0000000000..7110610284 --- /dev/null +++ b/flash/make_firmware/README @@ -0,0 +1,14 @@ +(c) 2003 by Jörg Hohensohn + +This tool composes a firmware file, out of: +1. Template for the first Flash page +2. Bootloader +3. Archos image +4. Rockbox image + +Use with extreme caution, the components have to match! +The aspects are: +- Model (Player, Recorder, FM, V2) +- boot type (standard boot ROM or ROMless) + +Such a firmware file can then be programmed with "firmware_flash.rock". diff --git a/flash/make_firmware/make_firmware.c b/flash/make_firmware/make_firmware.c new file mode 100644 index 0000000000..220db4e5f1 --- /dev/null +++ b/flash/make_firmware/make_firmware.c @@ -0,0 +1,338 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2003 by Jörg Hohensohn + * + * Autoring tool for the firmware image to be programmed into Flash ROM + * It composes the flash content with header, bootloader and image(s) + * + * 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 <stdio.h> +#include <stdlib.h> +#include <memory.h> +#include <string.h> + +#define UINT8 unsigned char +#define UINT16 unsigned short +#define UINT32 unsigned long +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +// size of one flash sector, the granularity with which it can be erased +#define SECTORSIZE 4096 + +#define BOOTLOAD_DEST 0x0FFFF500 // for the "normal" one +#define BOOTLOAD_SCR 0x02000100 +#define ROCKBOX_DEST 0x09000000 +#define ROCKBOX_EXEC 0x09000200 + + +// place a 32 bit value into memory, big endian +void Write32(UINT8* pByte, UINT32 value) +{ + pByte[0] = (UINT8)(value >> 24); + pByte[1] = (UINT8)(value >> 16); + pByte[2] = (UINT8)(value >> 8); + pByte[3] = (UINT8)(value); +} + + +// read a 32 bit value from memory, big endian +UINT32 Read32(UINT8* pByte) +{ + UINT32 value = 0; + + value |= (UINT32)pByte[0] << 24; + value |= (UINT32)pByte[1] << 16; + value |= (UINT32)pByte[2] << 8; + value |= (UINT32)pByte[3]; + + return value; +} + + +UINT32 CalcCRC32 (const UINT8* buf, UINT32 len) +{ + static const UINT32 crc_table[256] = + { // CRC32 lookup table for polynomial 0x04C11DB7 + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, + 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, + 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, + 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, + 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, + 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, + 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF, + 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, + 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, + 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0, + 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, + 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, + 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, + 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, + 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, + 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, + 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050, + 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, + 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, + 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, + 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, + 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, + 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, + 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9, + 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, + 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, + 0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, + 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71, + 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, + 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, + 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, + 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, + 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, + 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, + 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676, + 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, + 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, + 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 + }; + UINT32 i; + UINT32 crc = 0xffffffff; + + for (i = 0; i < len; i++) + crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf++) & 0xFF]; + + return crc; +} + + +UINT32 PlaceImage(char* filename, UINT32 pos, UINT8* pFirmware, UINT32 limit) +{ + UINT32 size, read; + FILE* pFile; + UINT32 align; + UINT32 flags; + + // magic file header for compressed files + static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a }; + UINT8 ucl_header[26]; + + pFile = fopen(filename, "rb"); // open the current image + if (pFile == NULL) + { + printf("Image file %s not found!\n", filename); + exit(5); + } + + fseek(pFile, 0, SEEK_END); + size = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + + // determine if compressed + flags = 0x00000000; // default: flags for uncompressed + fread(ucl_header, 1, sizeof(ucl_header), pFile); + if (memcmp(magic, ucl_header, sizeof(magic)) == 0) + { + if (ucl_header[12] != 0x2E) // check algorithm + { + printf("UCL compressed files must use algorithm 2e, not %d\n", ucl_header[12]); + printf("Generate with: uclpack --best --2e rockbox.bin %s\n", filename); + exit(6); + } + + size = Read32(ucl_header + 22); // compressed size + if (Read32(ucl_header + 18) > size) // compare with uncompressed size + { // normal case + flags = 0x00000001; // flags for UCL compressed + } + } + else + { + fseek(pFile, 0, SEEK_SET); // go back + } + + if (pos + 16 + size > limit) // enough space for all that? + { + printf("Exceeding maximum image size %d\n", limit); + exit(7); + } + + // write header + align = (pos + 16 + size + SECTORSIZE-1) & ~(SECTORSIZE-1); // round up to next flash sector + Write32(pFirmware + pos, ROCKBOX_DEST); // load address + Write32(pFirmware + pos + 4, align - (pos + 16)); // image size + Write32(pFirmware + pos + 8, ROCKBOX_EXEC); // execution address + Write32(pFirmware + pos + 12, flags); // compressed or not + pos += 16; + + // load image + read = fread(pFirmware + pos, 1, size, pFile); + if (read != size) + { + printf("Read error, expecting %d bytes, got only %d\n", size, read); + exit(8); + } + fclose (pFile); + + pos += size; + + return pos; +} + + +int main(int argc, char* argv[]) +{ + static UINT8 aFirmware[512*1024]; // maximum with exchanged chip + FILE* pFile; + UINT32 size; // size of loaded item + UINT32 pos; // current position in firmware + UINT32 crc32; // checksum of "payload" + BOOL hasBootRom; // flag if regular boot ROM or directly starts from flash + UINT32 template_F8, template_FC; // my platform ID, mask and version + + int i; + + if (argc <= 4) + { + printf("Usage:\n"); + printf("make_firmware <output> <template.bin> <bootloader.ajz> <image1.ucl> {image2.ucl}\n"); + printf("<template.bin> is the original firmware from your box\n"); + printf("<bootloader.ajz> is the scrambled bootloader\n"); + printf("<image1.ucl> is the first image, compressed (recommended) or uncompressed\n"); + printf("<image1.ucl> is the second image, compressed (recommended) or uncompressed\n"); + printf("More images may follow, but keep the flash size in mind!\n"); + printf("Compression must be UCL, algorithm 2e.\n"); + printf("Generated with: uclpack --best --2e rockbox.bin imageN.ucl\n"); + exit(0); + } + + memset(aFirmware, 0xFF, sizeof(aFirmware)); + + /******* process template *******/ + + pFile = fopen(argv[2], "rb"); // open the template + if (pFile == NULL) + { + printf("Template file %s not found!\n", argv[2]); + exit(1); + } + size = fread(aFirmware, 1, 256, pFile); // need only the header + fclose(pFile); + if (size < 256) // need at least the firmware header + { + printf("Template file %s too small, need at least the header!\n", argv[2]); + exit(2); + } + + if (strncmp(aFirmware, "ARCH", 4) == 0) + { + hasBootRom = TRUE; + pos = 256; // place bootloader after this "boot block" + } + else if (Read32(aFirmware) == 0x0200) + { + hasBootRom = FALSE; + pos = 0; // directly start with the bootloader + template_F8 = Read32(aFirmware + 0xF8); // my platform ID and future info + template_FC = Read32(aFirmware + 0xFC); // use mask+version from template + } + else + { + printf("Template file %s invalid!\n", argv[2]); + exit(3); + } + + /******* process bootloader *******/ + + pFile = fopen(argv[3], "rb"); // open the bootloader + if (pFile == NULL) + { + printf("Bootloader file %s not found!\n", argv[3]); + exit(4); + } + if (hasBootRom && fseek(pFile, 6, SEEK_SET)) // skip the ajz header + { + printf("Bootloader file %s too short!\n", argv[3]); + exit(5); + } + + // place bootloader after header + size = fread(aFirmware + pos, 1, sizeof(aFirmware) - pos, pFile); + fclose(pFile); + + if (hasBootRom) + { + Write32(aFirmware + 4, BOOTLOAD_DEST); // boot code destination address + + for (i=0x08; i<=0x28; i+=8) + { + Write32(aFirmware + i, BOOTLOAD_SCR); // boot code source address + Write32(aFirmware + i + 4, size); // boot code size + } + } + else + { + Write32(aFirmware + 0xF8, template_F8); // values from template + Write32(aFirmware + 0xFC, template_FC); // mask and version + } + + size = (size + 3) & ~3; // make shure it's 32 bit aligned + pos += size; // prepare position for first image + + /******* process images *******/ + for (i = 4; i < argc; i++) + { + pos = PlaceImage(argv[i], pos, aFirmware, sizeof(aFirmware)); + + if (i < argc-1) + { // not the last: round up to next flash sector + pos = (pos + SECTORSIZE-1) & ~(SECTORSIZE-1); + } + } + + + /******* append CRC32 checksum *******/ + crc32 = CalcCRC32(aFirmware, pos); + Write32(aFirmware + pos, crc32); + pos += sizeof(crc32); // 4 bytes + + + /******* save result to output file *******/ + + pFile = fopen(argv[1], "wb"); // open the output file + if (pFile == NULL) + { + printf("Output file %s cannot be created!\n", argv[1]); + exit(9); + } + size = fwrite(aFirmware, 1, pos, pFile); + fclose(pFile); + + if (size != pos) + { + printf("Error writing %d bytes to output file %s!\n", pos, argv[1]); + exit(10); + } + + printf("Firmware file generated with %d bytes.\n", pos); + + return 0; +} diff --git a/flash/make_firmware/make_firmware.dsp b/flash/make_firmware/make_firmware.dsp new file mode 100644 index 0000000000..54a6f53671 --- /dev/null +++ b/flash/make_firmware/make_firmware.dsp @@ -0,0 +1,96 @@ +# Microsoft Developer Studio Project File - Name="make_firmware" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=make_firmware - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "make_firmware.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "make_firmware.mak" CFG="make_firmware - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "make_firmware - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "make_firmware - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "make_firmware - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX"stdafx.h" /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "make_firmware - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "make_firmware - Win32 Release" +# Name "make_firmware - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\make_firmware.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# End Target +# End Project diff --git a/flash/minimon/Makefile b/flash/minimon/Makefile new file mode 100644 index 0000000000..57ae13e940 --- /dev/null +++ b/flash/minimon/Makefile @@ -0,0 +1,53 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +CC = sh-elf-gcc +LD = sh-elf-ld +AR = sh-elf-ar +AS = sh-elf-as +OC = sh-elf-objcopy + +FIRMWARE := ../../firmware +TOOLSDIR=../../tools + +TARGET = minimon +LDS := $(TARGET).lds + +INCLUDES= -I$(FIRMWARE)/export -I. -I$(OBJDIR) +OBJDIR := . + +CFLAGS = -fpic -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(DEFINES) +AFLAGS += -small -relax + + +ifdef DEBUG + DEFINES := -DDEBUG + CFLAGS += -g +endif + +SRC := $(wildcard *.c) + +OBJS := $(SRC:%.c=$(OBJDIR)/%.o) + +LINKFILE = $(OBJDIR)/$(TARGET).lds + + +$(OBJDIR)/$(TARGET).bin : $(OBJDIR)/$(TARGET).elf + $(OC) -O binary $(OBJDIR)/$(TARGET).elf $(OBJDIR)/$(TARGET).bin + $(TOOLSDIR)/sh2d $(OBJDIR)/$(TARGET).bin -o 0900000 > $(OBJDIR)/$(TARGET).asm + +$(OBJDIR)/$(TARGET).elf : $(OBJS) + $(CC) -Os -nostdlib -o $(OBJDIR)/$(TARGET).elf -L$(OBJDIR) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/$(TARGET).map + + +clean: + -rm -f $(OBJS) $(OBJDIR)/$(TARGET).asm \ + $(OBJDIR)/$(TARGET).bin \ + $(OBJDIR)/$(TARGET).elf \ + $(OBJDIR)/$(TARGET).map diff --git a/flash/minimon/README b/flash/minimon/README new file mode 100644 index 0000000000..b80edd9689 --- /dev/null +++ b/flash/minimon/README @@ -0,0 +1,6 @@ +(c) 2003 by Jörg Hohensohn + +MiniMon is the tiny but powerful-enough piece of code that can be loaded +with the UART boot mod. +It allows to read and write memory, flash program, execute code. +This is suitable to reflash the box, load Rockbox or the gdb stub, etc. diff --git a/flash/minimon/minimon.c b/flash/minimon/minimon.c new file mode 100644 index 0000000000..e7981f2d09 --- /dev/null +++ b/flash/minimon/minimon.c @@ -0,0 +1,156 @@ +// minimalistic monitor +// to be loaded with the UART boot feature +// capable of reading and writing bytes, commanded by UART + +#include "sh7034.h" +#include "minimon.h" + +// scalar types +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned long UINT32; + +typedef void(*tpFunc)(void); // type for exec +typedef int(*tpMain)(void); // type for start vector to main() + + +// prototypes +int main(void); + +// our binary has to start with a vector to the entry point +tpMain start_vector[] __attribute__ ((section (".startvector"))) = {main}; + + +UINT8 uart_read(void) +{ + UINT8 byte; + while (!(SSR1 & SCI_RDRF)); // wait for char to be available + byte = RDR1; + SSR1 &= ~SCI_RDRF; + return byte; +} + + +void uart_write(UINT8 byte) +{ + while (!(SSR1 & SCI_TDRE)); // wait for transmit buffer empty + TDR1 = byte; + SSR1 &= ~SCI_TDRE; +} + + +int main(void) +{ + UINT8 cmd; + UINT32 addr; + UINT32 size; + UINT32 content; + volatile UINT8* paddr = 0; + volatile UINT8* pflash; // flash base address + + while (1) + { + cmd = uart_read(); + switch (cmd) + { + case BAUDRATE: + content = uart_read(); + uart_write(cmd); // acknowledge by returning the command value + while (!(SSR1 & SCI_TEND)); // wait for empty shift register, before changing baudrate + BRR1 = content; + break; + + case ADDRESS: + addr = (uart_read() << 24) | (uart_read() << 16) | (uart_read() << 8) | uart_read(); + paddr = (UINT8*)addr; + pflash = (UINT8*)(addr & 0xFFF80000); // round down to 512k align + uart_write(cmd); // acknowledge by returning the command value + break; + + case BYTE_READ: + content = *paddr++; + uart_write(content); // the content is the ack + break; + + case BYTE_WRITE: + content = uart_read(); + *paddr++ = content; + uart_write(cmd); // acknowledge by returning the command value + break; + + case BYTE_READ16: + size = 16; + while (size--) + { + content = *paddr++; + uart_write(content); // the content is the ack + } + break; + + case BYTE_WRITE16: + size = 16; + while (size--) + { + content = uart_read(); + *paddr++ = content; + } + uart_write(cmd); // acknowledge by returning the command value + break; + + case BYTE_FLASH: + content = uart_read(); + pflash[0x5555] = 0xAA; // set flash to command mode + pflash[0x2AAA] = 0x55; + pflash[0x5555] = 0xA0; // byte program command + *paddr++ = content; + uart_write(cmd); // acknowledge by returning the command value + break; + + case BYTE_FLASH16: + size = 16; + while (size--) + { + content = uart_read(); + pflash[0x5555] = 0xAA; // set flash to command mode + pflash[0x2AAA] = 0x55; + pflash[0x5555] = 0xA0; // byte program command + *paddr++ = content; + } + uart_write(cmd); // acknowledge by returning the command value + break; + + case HALFWORD_READ: + content = *(UINT16*)paddr; + paddr += 2; + uart_write(content >> 8); // highbyte + uart_write(content & 0xFF); // lowbyte + break; + + case HALFWORD_WRITE: + content = uart_read() << 8 | uart_read(); + *(UINT16*)paddr = content; + paddr += 2; + uart_write(cmd); // acknowledge by returning the command value + break; + + case EXECUTE: + { + tpFunc pFunc = (tpFunc)paddr; + pFunc(); + uart_write(cmd); // acknowledge by returning the command value + } + break; + + + default: + { + volatile UINT16* pPortB = (UINT16*)0x05FFFFC2; + *pPortB |= 1 << 6; // bit 6 is red LED on + uart_write(~cmd); // error acknowledge + } + + } // case + } + + return 0; +} diff --git a/flash/minimon/minimon.h b/flash/minimon/minimon.h new file mode 100644 index 0000000000..b6e9805ecf --- /dev/null +++ b/flash/minimon/minimon.h @@ -0,0 +1,24 @@ +#ifndef _MINIMON_H +#define _MINIMON_H + + +// Commands +// all multibyte values (address, halfwords) are passed as big endian +// (most significant of the bytes first) + +// set the address (all read/write commands will auto-increment it) +#define BAUDRATE 0x00 // followed by BRR value; response: command byte +#define ADDRESS 0x01 // followed by 4 bytes address; response: command byte +#define BYTE_READ 0x02 // response: 1 byte content +#define BYTE_WRITE 0x03 // followed by 1 byte content; response: command byte +#define BYTE_READ16 0x04 // response: 16 bytes content +#define BYTE_WRITE16 0x05 // followed by 16 bytes; response: command byte +#define BYTE_FLASH 0x06 // followed by 1 byte content; response: command byte +#define BYTE_FLASH16 0x07 // followed by 16 bytes; response: command byte +#define HALFWORD_READ 0x08 // response: 2 byte content +#define HALFWORD_WRITE 0x09 // followed by 2 byte content; response: command byte +#define EXECUTE 0x0A // response: command byte if call returns +#define VERSION 0x0B // response: version + + +#endif // _MINIMON_H diff --git a/flash/minimon/minimon.lds b/flash/minimon/minimon.lds new file mode 100644 index 0000000000..dbdbdc3faa --- /dev/null +++ b/flash/minimon/minimon.lds @@ -0,0 +1,60 @@ +OUTPUT_FORMAT(elf32-sh) +INPUT(minimon.o) + +MEMORY +{ + DRAM : ORIGIN = 0x09000000, LENGTH = 0x200000 +} + +SECTIONS +{ + .startvector : + { + *(.startvector) + . = ALIGN(0x4); + } > DRAM + + .got : + { + *(.got) + } > DRAM + + .got.plt : + { + *(.got.plt) + } > DRAM + + .rela.got : + { + *(.rela.got) + } > DRAM + + .text : + { + . = ALIGN(0x200); + *(.entry) + *(.text) + . = ALIGN(0x4); + } > DRAM + + .data : + { + *(.data) + } > DRAM + + .rodata : + { + *(.rodata) + . = ALIGN(0x4); + } > DRAM + + .bss : + { + *(.bss) + } > DRAM + + .stack : + { + *(.stack) + } > DRAM +} diff --git a/flash/uart_boot/README b/flash/uart_boot/README new file mode 100644 index 0000000000..edfa20c121 --- /dev/null +++ b/flash/uart_boot/README @@ -0,0 +1,8 @@ +(c) 2003 by Jörg Hohensohn + +This is the client side for MiniMon, a command line program that communicates with it. +It can be used to reflash a box from ground up, load a program like gdb stub or Rockbox, +and other diagnostics. + +Current implementation is for Windows, but with a different UART implementation +it should work for other platforms (Linux) as well. diff --git a/flash/uart_boot/client.c b/flash/uart_boot/client.c new file mode 100644 index 0000000000..a98edc60cb --- /dev/null +++ b/flash/uart_boot/client.c @@ -0,0 +1,738 @@ +// client.cpp : functions for monitor download and communication. +// + +#include <stdio.h> +#include <stdlib.h> +#include "scalar_types.h" // (U)INT8/16/32 +#include "Uart.h" // platform abstraction for UART +#include "minimon.h" // protocol of my little monitor + +// do the baudrate configuration for the Player +int ConfigFirstlevelPlayer (tUartHandle serial_handle) +{ + UINT32 result_nbr; + + if(!UartConfig(serial_handle, 4800, eMARKPARITY, eTWOSTOPBITS, 8)) + { + UINT32 dwErr = GET_LAST_ERR(); + printf("Error %d setting up COM params for baudrate byte\n", dwErr); + exit(1); + } + + // this will read as 0x19 when viewed with 2300 baud like the player does + result_nbr = UartWrite(serial_handle, (UINT8*)"\x86\xC0", 2); + if (result_nbr != 2) + { + UINT32 dwErr = GET_LAST_ERR(); + printf("Error %d setting up COM params for baudrate byte\n", dwErr); + } + + SLEEP(100); // wait for the chars to be sent, is there a better way? + + // the read 0x19 means 14423 baud with 12 MHz + if(!UartConfig(serial_handle, 14400, eNOPARITY, eONESTOPBIT, 8)) + { + printf("Error setting up COM params for 1st level loader\n"); + exit(1); + } + + return 0; +} + + +// do the baudrate configuration for the Recoder/FM +int ConfigFirstlevelRecorder (tUartHandle serial_handle) +{ + UINT32 result_nbr; + + if(!UartConfig(serial_handle, 4800, eNOPARITY, eTWOSTOPBITS, 8)) + { + UINT32 dwErr = GET_LAST_ERR(); + printf("Error %d setting up COM params for baudrate byte\n", dwErr); + exit(1); + } + + // this will read as 0x08 when viewed with 2120 baud like the recorder does + result_nbr = UartWrite(serial_handle, (UINT8*)"\x00\x00", 2); + if(result_nbr != 2) + { + printf("Error transmitting baudrate byte\n"); + exit(1); + } + + SLEEP(100); // wait for the chars to be sent, is there a better way? + + // the read 0x08 means 38400 baud with 11.0592 MHz + if(!UartConfig(serial_handle, 38400, eNOPARITY, eONESTOPBIT, 8)) + { + UINT32 dwErr = GET_LAST_ERR(); + printf("Error %d setting up COM params for 1st level loader\n", dwErr); + exit(1); + } + + return 0; +} + + +// transfer a byte for the monitor download, with or without acknowledge +int DownloadByte(tUartHandle serial_handle, unsigned char byte, bool bAck) +{ + unsigned char received; + bool bRecorder = true; // false for player + + while (1) + { + UartWrite(serial_handle, &byte, 1); + if (bAck) + { + UartRead(serial_handle, &received, 1); + if (received == byte) + { + UartWrite(serial_handle, (UINT8*)"\x01", 1); // ack success + break; // exit the loop + } + else + { + printf("Error transmitting monitor byte 0x%02X, got 0x%0X\n", byte, received); + UartWrite(serial_handle, (UINT8*)"\x00", 1); // ack fail, try again + } + } + else + break; // no loop + } + return 1; +} + + +// download our little monitor, the box must have been just freshly switched on for this to work +int DownloadMonitor(tUartHandle serial_handle, bool bRecorder, char* szFilename) +{ + FILE* pFile; + size_t filesize; + UINT8 byte; + unsigned i; + + // hard-coded parameters + bool bAck = true; // configure if acknowledged download (without useful for remote pin boot) + UINT32 TargetLoad = 0x0FFFF000; // target load address + + pFile = fopen(szFilename, "rb"); + if (pFile == NULL) + { + printf("\nMonitor file %s not found, exiting\n", szFilename); + exit(1); + } + + // determine file size + fseek(pFile, 0, SEEK_END); + filesize = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + + // This is _really_ tricky! The box expects a BRR value in a nonstandard baudrate, + // which a PC can't generate. I'm using a higher one with some wild settings + // to generate a pulse series that: + // 1) looks like a stable byte when sampled with the nonstandard baudrate + // 2) gives a BRR value to the box which results in a baudrate the PC can also use + if (bRecorder) + { + ConfigFirstlevelRecorder(serial_handle); + } + else + { + ConfigFirstlevelPlayer(serial_handle); + } + + UartWrite(serial_handle, bAck ? (UINT8*)"\x01" : (UINT8*)"\x00", 1); // ACK mode + + // transmit the size, little endian + DownloadByte(serial_handle, (UINT8)( filesize & 0xFF), bAck); + DownloadByte(serial_handle, (UINT8)((filesize>>8) & 0xFF), bAck); + DownloadByte(serial_handle, (UINT8)((filesize>>16) & 0xFF), bAck); + DownloadByte(serial_handle, (UINT8)((filesize>>24) & 0xFF), bAck); + + // transmit the load address, little endian + DownloadByte(serial_handle, (UINT8)( TargetLoad & 0xFF), bAck); + DownloadByte(serial_handle, (UINT8)((TargetLoad>>8) & 0xFF), bAck); + DownloadByte(serial_handle, (UINT8)((TargetLoad>>16) & 0xFF), bAck); + DownloadByte(serial_handle, (UINT8)((TargetLoad>>24) & 0xFF), bAck); + + // transmit the command byte + DownloadByte(serial_handle, 0xFF, bAck); // 0xFF means execute the transferred image + + // transmit the image + for (i=0; i<filesize; i++) + { + fread(&byte, 1, 1, pFile); + DownloadByte(serial_handle, byte, bAck); + } + + fclose (pFile); + + // now the image should have been started, red LED off + + return 0; +} + + +// wait for a fixed string to be received (no foolproof algorithm, +// may overlook if the searched string contains repeatitions) +int WaitForString(tUartHandle serial_handle, char* pszWait) +{ + int i = 0; + unsigned char received; + + while(pszWait[i] != '\0') + { + UartRead(serial_handle, &received, 1); + + printf("%c", received); // debug + + if (received == pszWait[i]) + i++; // continue + else + i=0; // mismatch, start over + } + return 0; +} + + +// send a sting and check the echo +int SendWithEcho(tUartHandle serial_handle, char* pszSend) +{ + int i = 0; + unsigned char received; + + while(pszSend[i] != '\0') + { + UartWrite(serial_handle, (unsigned char*)(pszSend + i), 1); // send char + do + { + UartRead(serial_handle, &received, 1); // receive echo + printf("%c", received); // debug + } + while (received != pszSend[i]); // should normally be equal + i++; // next char + } + return 0; +} + + +// rarely used variant: download our monitor using the built-in Archos monitor +int DownloadArchosMonitor(tUartHandle serial_handle, char* szFilename) +{ + FILE* pFile; + size_t filesize; + UINT8 byte; + UINT16 checksum = 0; + unsigned i; + + // the onboard monitor uses 115200 baud + if(!UartConfig(serial_handle, 115200, eNOPARITY, eONESTOPBIT, 8)) + { + UINT32 dwErr = GET_LAST_ERR(); + printf("Error %d setting up COM params for baudrate %d\n", dwErr, 115200); + exit(1); + } + + // wait for receiving "#SERIAL#" + WaitForString(serial_handle, "#SERIAL#"); + + // send magic "SRL" command to get interactive mode + SendWithEcho(serial_handle, "SRL\r"); + + // wait for menu completion: "ROOT>" at the end + WaitForString(serial_handle, "ROOT>"); + + // send upload command "UP" + SendWithEcho(serial_handle, "UP\r"); + + pFile = fopen(szFilename, "rb"); + if (pFile == NULL) + { + printf("\nMonitor file %s not found, exiting\n", szFilename); + exit(1); + } + + // determine file size + fseek(pFile, 0, SEEK_END); + filesize = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + + // calculate checksum + for (i=0; i<filesize; i++) + { + fread(&byte, 1, 1, pFile); + checksum += byte; + } + fseek(pFile, 0, SEEK_SET); + + // send header + + // size as 32 bit little endian + byte = (UINT8)( filesize & 0xFF); + UartWrite(serial_handle, &byte, 1); + byte = (UINT8)((filesize>>8) & 0xFF); + UartWrite(serial_handle, &byte, 1); + byte = (UINT8)((filesize>>16) & 0xFF); + UartWrite(serial_handle, &byte, 1); + byte = (UINT8)((filesize>>24) & 0xFF); + UartWrite(serial_handle, &byte, 1); + + // checksum as 16 bit little endian + byte = (UINT8)( checksum & 0xFF); + UartWrite(serial_handle, &byte, 1); + byte = (UINT8)((checksum>>8) & 0xFF); + UartWrite(serial_handle, &byte, 1); + + UartWrite(serial_handle, (unsigned char*)"\x00", 1); // kind (3 means flash) + UartWrite(serial_handle, (unsigned char*)"\x00", 1); // ignored byte + + // wait for monitor to accept data + WaitForString(serial_handle, "#OKCTRL#"); + + // transmit the image + for (i=0; i<filesize; i++) + { + fread(&byte, 1, 1, pFile); + UartWrite(serial_handle, &byte, 1); // payload + } + fclose (pFile); + + UartWrite(serial_handle, (unsigned char*)"\x00", 1); // ignored byte + + // wait for menu completion: "ROOT>" at the end + WaitForString(serial_handle, "ROOT>"); + + // send start program command "SPRO" + SendWithEcho(serial_handle, "SPRO\r"); + + SLEEP(100); // wait a little while for startup + + return 0; +} + + +/********** Target functions using the Monitor Protocol **********/ + +// read a byte using the target monitor +UINT8 ReadByte(tUartHandle serial_handle, UINT32 addr) +{ + UINT8 send; + UINT8 received; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error!\n"); + return 1; + } + + // send the read command + send = BYTE_READ; + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + + return received; +} + + +// write a byte using the target monitor +int WriteByte(tUartHandle serial_handle, UINT32 addr, UINT8 byte) +{ + UINT8 send; + UINT8 received; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error, receiced 0x%02X!\n", received); + return 1; + } + + // send the write command + send = BYTE_WRITE; + UartWrite(serial_handle, &send, 1); + + // transmit the data + UartWrite(serial_handle, &byte, 1); + + UartRead(serial_handle, &received, 1); // response + + if (received != BYTE_WRITE) + { + printf("Protocol error!\n"); + return 1; + } + + return 0; +} + + +// read many bytes using the target monitor +int ReadByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer) +{ + UINT8 send, received; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error!\n"); + return 1; + } + + while (size) + { + if (size >= 16) + { // we can use a "burst" command + send = BYTE_READ16; + UartWrite(serial_handle, &send, 1); // send the read command + UartRead(serial_handle, pBuffer, 16); // data response + pBuffer += 16; + size -= 16; + } + else + { // use single byte command + send = BYTE_READ; + UartWrite(serial_handle, &send, 1); // send the read command + UartRead(serial_handle, pBuffer++, 1); // data response + size--; + } + } + + return 0; +} + + +// write many bytes using the target monitor +int WriteByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer) +{ + UINT8 send, received; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error!\n"); + return 1; + } + + while (size) + { + if (size >= 16) + { // we can use a "burst" command + send = BYTE_WRITE16; + UartWrite(serial_handle, &send, 1); // send the write command + UartWrite(serial_handle, pBuffer, 16); // transmit the data + UartRead(serial_handle, &received, 1); // response + if (received != BYTE_WRITE16) + { + printf("Protocol error!\n"); + return 1; + } + pBuffer += 16; + size -= 16; + } + else + { // use single byte command + send = BYTE_WRITE; + UartWrite(serial_handle, &send, 1); // send the write command + UartWrite(serial_handle, pBuffer++, 1); // transmit the data + UartRead(serial_handle, &received, 1); // response + if (received != BYTE_WRITE) + { + printf("Protocol error!\n"); + return 1; + } + size--; + } + } + + return 0; +} + + +// write many bytes using the target monitor +int FlashByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer) +{ + UINT8 send, received; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error!\n"); + return 1; + } + + while (size) + { + if (size >= 16) + { // we can use a "burst" command + send = BYTE_FLASH16; + UartWrite(serial_handle, &send, 1); // send the write command + UartWrite(serial_handle, pBuffer, 16); // transmit the data + UartRead(serial_handle, &received, 1); // response + if (received != BYTE_FLASH16) + { + printf("Protocol error!\n"); + return 1; + } + pBuffer += 16; + size -= 16; + } + else + { // use single byte command + send = BYTE_FLASH; + UartWrite(serial_handle, &send, 1); // send the write command + UartWrite(serial_handle, pBuffer++, 1); // transmit the data + UartRead(serial_handle, &received, 1); // response + if (received != BYTE_FLASH) + { + printf("Protocol error!\n"); + return 1; + } + size--; + } + } + + return 0; +} + + +// read a 16bit halfword using the target monitor +UINT16 ReadHalfword(tUartHandle serial_handle, UINT32 addr) +{ + UINT8 send; + UINT8 received; + UINT16 halfword; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error!\n"); + return 1; + } + + // send the read command + send = HALFWORD_READ; + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + halfword = received << 8; // highbyte + UartRead(serial_handle, &received, 1); + halfword |= received; // lowbyte + + return halfword; +} + + +// write a 16bit halfword using the target monitor +int WriteHalfword(tUartHandle serial_handle, UINT32 addr, UINT16 halfword) +{ + UINT8 send; + UINT8 received; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error!\n"); + return 1; + } + + // send the write command + send = HALFWORD_WRITE; + UartWrite(serial_handle, &send, 1); + + // transmit the data + send = halfword >> 8; // highbyte + UartWrite(serial_handle, &send, 1); + send = halfword & 0xFF; // lowbyte + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + + if (received != HALFWORD_WRITE) + { + printf("Protocol error!\n"); + return 1; + } + + return 0; +} + + +// change baudrate using target monitor +int SetTargetBaudrate(tUartHandle serial_handle, long lClock, long lBaudrate) +{ + UINT8 send; + UINT8 received; + UINT8 brr; + long lBRR; + + lBRR = lClock / lBaudrate; + lBRR = ((lBRR + 16) / 32) - 1; // with rounding + brr = (UINT8)lBRR; + + // send the command + send = BAUDRATE; + UartWrite(serial_handle, &send, 1); + UartWrite(serial_handle, &brr, 1); // send the BRR value + UartRead(serial_handle, &received, 1); // response ack + + if (received != BAUDRATE) + { // bad situation, now we're unclear about the baudrate of the target + printf("Protocol error!\n"); + return 1; + } + + SLEEP(100); // give it some time to settle + + // change our baudrate, too + UartConfig(serial_handle, lBaudrate, eNOPARITY, eONESTOPBIT, 8); + + return 0; +} + + +// call a subroutine using the target monitor +int Execute(tUartHandle serial_handle, UINT32 addr, bool bReturns) +{ + UINT8 send; + UINT8 received; + + // send the address command + send = ADDRESS; + UartWrite(serial_handle, &send, 1); + + // transmit the address, big endian + send = (UINT8)((addr>>24) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>16) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)((addr>>8) & 0xFF); + UartWrite(serial_handle, &send, 1); + send = (UINT8)(addr & 0xFF); + UartWrite(serial_handle, &send, 1); + + UartRead(serial_handle, &received, 1); // response + if (received != ADDRESS) + { + printf("Protocol error!\n"); + return 1; + } + + // send the execute command + send = EXECUTE; + UartWrite(serial_handle, &send, 1); + if (bReturns) + { // we expect the call to return control to minimon + UartRead(serial_handle, &received, 1); // response + + if (received != EXECUTE) + { + printf("Protocol error!\n"); + return 1; + } + } + + return 0; +} + + diff --git a/flash/uart_boot/client.h b/flash/uart_boot/client.h new file mode 100644 index 0000000000..d2ef29aa2e --- /dev/null +++ b/flash/uart_boot/client.h @@ -0,0 +1,21 @@ +#ifndef _CLIENT_H +#define _CLIENT_H + + +// setup function for monitor download +int DownloadMonitor(tUartHandle serial_handle, bool bRecorder, char* szFilename); +int DownloadArchosMonitor(tUartHandle serial_handle, char* szFilename); + +// target functions using the Monitor Protocol +UINT8 ReadByte(tUartHandle serial_handle, UINT32 addr); +int WriteByte(tUartHandle serial_handle, UINT32 addr, UINT8 byte); +int ReadByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer); +int WriteByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer); +int FlashByteMultiple(tUartHandle serial_handle, UINT32 addr, UINT32 size, UINT8* pBuffer); +UINT16 ReadHalfword(tUartHandle serial_handle, UINT32 addr); +int WriteHalfword(tUartHandle serial_handle, UINT32 addr, UINT16 halfword); +int SetTargetBaudrate(tUartHandle serial_handle, long lClock, long lBaudrate); +int Execute(tUartHandle serial_handle, UINT32 addr, bool bReturns); + + +#endif
\ No newline at end of file diff --git a/flash/uart_boot/flash.c b/flash/uart_boot/flash.c new file mode 100644 index 0000000000..f27bb7ec0a --- /dev/null +++ b/flash/uart_boot/flash.c @@ -0,0 +1,77 @@ +// flash.cpp : higher-level functions for flashing the chip +// + +#include "scalar_types.h" // (U)INT8/16/32 +#include "Uart.h" // platform abstraction for UART +#include "client.h" // client functions + + +// read the manufacturer and device ID +int ReadID(tUartHandle serial_handle, UINT32 base, UINT8* pManufacturerID, UINT8* pDeviceID) +{ + base &= 0xFFF80000; // round down to 512k align, to make shure + + WriteByte(serial_handle, base + 0x5555, 0xAA); // enter command mode + WriteByte(serial_handle, base + 0x2AAA, 0x55); + WriteByte(serial_handle, base + 0x5555, 0x90); // ID command + SLEEP(20); // Atmel wants 20ms pause here + + *pManufacturerID = ReadByte(serial_handle, base + 0); + *pDeviceID = ReadByte(serial_handle, base + 1); + + WriteByte(serial_handle, base + 0, 0xF0); // reset flash (back to normal read mode) + SLEEP(20); // Atmel wants 20ms pause here + + return 0; +} + + +// erase the sector which contains the given address +int EraseSector(tUartHandle serial_handle, UINT32 address) +{ + UINT32 base = address & 0xFFF80000; // round down to 512k align + + WriteByte(serial_handle, base + 0x5555, 0xAA); // enter command mode + WriteByte(serial_handle, base + 0x2AAA, 0x55); + WriteByte(serial_handle, base + 0x5555, 0x80); // eraze command + WriteByte(serial_handle, base + 0x5555, 0xAA); // enter command mode + WriteByte(serial_handle, base + 0x2AAA, 0x55); + WriteByte(serial_handle, address, 0x30); // eraze the sector + SLEEP(25); // sector eraze time: 25ms + + return 0; +} + + +// erase the whole flash +int EraseChip(tUartHandle serial_handle, UINT32 base) +{ + base &= 0xFFF80000; // round down to 512k align, to make shure + + WriteByte(serial_handle, base + 0x5555, 0xAA); // enter command mode + WriteByte(serial_handle, base + 0x2AAA, 0x55); + WriteByte(serial_handle, base + 0x5555, 0x80); // eraze command + WriteByte(serial_handle, base + 0x5555, 0xAA); // enter command mode + WriteByte(serial_handle, base + 0x2AAA, 0x55); + WriteByte(serial_handle, base + 0x5555, 0x10); // chip eraze command + SLEEP(100); // chip eraze time: 100ms + + return 0; +} + + +// program a bunch of bytes "by hand" +int ProgramBytes(tUartHandle serial_handle, UINT32 address, UINT8* pData, UINT32 size) +{ + UINT32 base = address & 0xFFF80000; // round down to 512k align + + while (size--) + { + WriteByte(serial_handle, base + 0x5555, 0xAA); // enter command mode + WriteByte(serial_handle, base + 0x2AAA, 0x55); + WriteByte(serial_handle, base + 0x5555, 0xA0); // byte program command + WriteByte(serial_handle, address++, *pData++); + // UART protocol is slow enough such that I don't have to wait 20us here + } + return 0; +}
\ No newline at end of file diff --git a/flash/uart_boot/flash.h b/flash/uart_boot/flash.h new file mode 100644 index 0000000000..70c620108d --- /dev/null +++ b/flash/uart_boot/flash.h @@ -0,0 +1,9 @@ +#ifndef _FLASH_H +#define _FLASH_H + +int ReadID(tUartHandle serial_handle, UINT32 base, UINT8* pManufacturerID, UINT8* pDeviceID); +int EraseSector(tUartHandle serial_handle, UINT32 address); +int EraseChip(tUartHandle serial_handle, UINT32 base); +int ProgramBytes(tUartHandle serial_handle, UINT32 address, UINT8* pData, UINT32 size); + +#endif
\ No newline at end of file diff --git a/flash/uart_boot/minimon.h b/flash/uart_boot/minimon.h new file mode 100644 index 0000000000..51406d4b12 --- /dev/null +++ b/flash/uart_boot/minimon.h @@ -0,0 +1,23 @@ +#ifndef _MINIMON_H +#define _MINIMON_H + + +// Commands +// all multibyte values (address, halfwords) are passed as big endian +// (most significant of the bytes first) + +// set the address (all read/write commands will auto-increment it) +#define BAUDRATE 0x00 // followed by BRR value; response: command byte +#define ADDRESS 0x01 // followed by 4 bytes address; response: command byte +#define BYTE_READ 0x02 // response: 1 byte content +#define BYTE_WRITE 0x03 // followed by 1 byte content; response: command byte +#define BYTE_READ16 0x04 // response: 16 bytes content +#define BYTE_WRITE16 0x05 // followed by 16 bytes; response: command byte +#define BYTE_FLASH 0x06 // followed by 1 byte content; response: command byte +#define BYTE_FLASH16 0x07 // followed by 16 bytes; response: command byte +#define HALFWORD_READ 0x08 // response: 2 byte content +#define HALFWORD_WRITE 0x09 // followed by 2 byte content; response: command byte +#define EXECUTE 0x0A // response: command byte if call returns + + +#endif // _MINIMON_H diff --git a/flash/uart_boot/scalar_types.h b/flash/uart_boot/scalar_types.h new file mode 100644 index 0000000000..88d82c4ec1 --- /dev/null +++ b/flash/uart_boot/scalar_types.h @@ -0,0 +1,44 @@ +// this is meant to resolve platform dependency + +#ifndef _SCALAR_TYPES_H +#define _SCALAR_TYPES_H + + +#ifdef WIN32 +#include <windows.h> +#define SLEEP Sleep +#define GET_LAST_ERR GetLastError +#endif +// ToDo: add stuff for Linux + + + +#ifndef UINT8 +#define UINT8 unsigned char +#endif + +#ifndef UINT16 +#define UINT16 unsigned short +#endif + +#ifndef UINT32 +#define UINT32 unsigned long +#endif + +#ifndef bool +#define bool int +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + + + + + +#endif
\ No newline at end of file diff --git a/flash/uart_boot/uart.h b/flash/uart_boot/uart.h new file mode 100644 index 0000000000..46b082c497 --- /dev/null +++ b/flash/uart_boot/uart.h @@ -0,0 +1,56 @@ +// A general definition for the required UART functionality. +// This will be used to gain platform abstraction. + +#ifndef _UART_H +#define _UART_H + +// data types + +typedef void* tUartHandle; +#define INVALID_UART_HANDLE (tUartHandle)-1 + +typedef enum +{ + eNOPARITY, + eODDPARITY, + eEVENPARITY, + eMARKPARITY, + eSPACEPARITY, +} tParity; + +typedef enum +{ + eONESTOPBIT, + eONE5STOPBITS, + eTWOSTOPBITS, +} tStopBits; + + +// prototypes + +tUartHandle UartOpen( // returns NULL on error + char* szPortName); // COMx for windows + +bool UartConfig( // returns true on success, false on error + tUartHandle handle, // the handle returned from UartOpen() + long lBaudRate, // must be one of the "standard" baudrates + tParity nParity, // what kind of parity + tStopBits nStopBits, // how many stop bits + int nByteSize); // size of the "payload", can be 5 to 8 + +long UartWrite( // returns how much data was actually transmitted + tUartHandle handle, // the handle returned from UartOpen() + unsigned char* pData, // pointer to the data to be transmitted + long lSize); // how many bytes + +long UartRead( // returns how much data was actually received + tUartHandle handle, // the handle returned from UartOpen() + unsigned char* pBuffer, // pointer to the destination + long lSize); // how many bytes to read (pBuffer must have enough room) + + +void UartClose(tUartHandle handle); + + + +#endif // _UART_H
\ No newline at end of file diff --git a/flash/uart_boot/uart_boot.c b/flash/uart_boot/uart_boot.c new file mode 100644 index 0000000000..8110e9b678 --- /dev/null +++ b/flash/uart_boot/uart_boot.c @@ -0,0 +1,337 @@ +// uart_boot.cpp : Defines the entry point for the console application. +// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "scalar_types.h" // (U)INT8/16/32 +#include "Uart.h" // platform abstraction for UART +#include "client.h" // client functions +#include "flash.h" // flash high level functions + +// command line configuration: what shall we do? +struct +{ + char* szPort; // COM port to use + bool bRecorder; // it's a recorder + bool bArchos; // use the Archos monitor to load, instead of UART boot + bool bSpindown; // spindown the harddisk + bool bReadID; // read manufacturer+device ID + char* szFlashfile; // file to be programmed + char* szDumpfile; // file to dump into + char* szExecfile; // file with the executable + bool bTest; // debug action + bool bBlink; // blink red LED + bool bNoDownload; +} gCmd; + + +int ProcessCmdLine(int argc, char* argv[]) +{ + argc--; // exclude our name + argv++; + + memset(&gCmd, 0, sizeof(gCmd)); + + if (argc == 0) + { + printf("Usage: uart_boot [-option {filename}]\n"); + printf(" uses activated UART boot mod, box has to be fresh started\n"); + printf("The order of the options does not matter, one letter is sufficient.\n"); + printf("Possible options are (in the order of later processing):\n"); + printf("-port <name of COM port to use>\n"); + printf("-recorder (this is a recorder/FM, default is player if not specified)\n"); + printf("-archos (use Archos bootloader, this one needs powerup while program waits)\n"); + printf("-nodownload (no MiniMon download, it's already active)\n"); + printf("-spindown (spindown the harddisk, else it stays on by default)\n"); + printf("-id (read manufacturer and device ID of flash, no checks)\n"); + printf("-flash <filename of binary to program into flash>\n"); + printf("-dump <filename to write flash content to>\n"); + printf("-exec <filename of executable for 0x09000000:0x09000200>\n"); + printf("-test (some test action currently under development, don't use!)\n"); + printf("-blink (blink red LED forever, meant as diagnostics)\n"); + printf("\n"); + printf("Examples:\n"); + printf("uart_boot -r -p COM1 -s -f flashfile.bin -d dumpfile.bin\n"); + printf(" recorder on COM1, spindown HD, program and dump (for e.g. offline verify)\n"); + printf("uart_boot -r -p COM2 -e rockbox.bin\n"); + printf(" recorder on COM2, load Rockbox from file and start it\n"); + exit (0); + } + + + while (argc) + { + if (!strncmp("-port", *argv, 2)) + { + gCmd.szPort = *++argv; + if (--argc <= 0 || **argv == '-') + { + printf("No argument given for option %s, aborting.\n", argv[-1]); + exit (-2); + } + } + else if (!strncmp("-recorder", *argv, 2)) + { + gCmd.bRecorder = true; + } + else if (!strncmp("-archos", *argv, 2)) + { + gCmd.bArchos = true; + } + else if (!strncmp("-nodownload", *argv, 2)) + { + gCmd.bNoDownload = true; + } + else if (!strncmp("-spindown", *argv, 2)) + { + gCmd.bSpindown = true; + } + else if (!strncmp("-id", *argv, 2)) + { + gCmd.bReadID = true; + } + else if (!strncmp("-flash", *argv, 2)) + { + gCmd.szFlashfile = *++argv; + if (--argc <= 0 || **argv == '-') + { + printf("No argument given for option %s, aborting.\n", argv[-1]); + exit (-2); + } + } + else if (!strncmp("-dump", *argv, 2)) + { + gCmd.szDumpfile = *++argv; + if (--argc <= 0 || **argv == '-') + { + printf("No argument given for option %s, aborting.\n", argv[-1]); + exit (-3); + } + } + else if (!strncmp("-exec", *argv, 2)) + { + gCmd.szExecfile = *++argv; + if (--argc <= 0 || **argv == '-') + { + printf("No argument given for option %s, aborting.\n", argv[-1]); + exit (-4); + } + } + else if (!strncmp("-test", *argv, 2)) + { + gCmd.bTest = true; + } + else if (!strncmp("-blink", *argv, 2)) + { + gCmd.bBlink = true; + } + else + { + printf("Unknown option %s, aborting. Use 'uart_boot' without options for help.\n", *argv); + exit(-1); + } + + argv++; + argc--; + } + + return 0; +} + + +int main(int argc, char* argv[]) +{ + tUartHandle serial_handle; + UINT16 reg; + FILE* pFile; + size_t size; + UINT8 abFirmware[512*1024]; // blocksize + memset(abFirmware, 0xFF, sizeof(abFirmware)); + + ProcessCmdLine(argc, argv); // what to do + + if (!gCmd.szPort) + { + printf("No serial port given, use 'uart_boot' without parameters for options.\n"); + exit(-1); + } + + serial_handle = UartOpen(gCmd.szPort); // opening serial port + if (serial_handle == NULL) + { + printf("Cannot open port %s\n", gCmd.szPort); + return -1; + } + + if (gCmd.bNoDownload) + { // just set our speed + if (!UartConfig(serial_handle, gCmd.bRecorder ? 115200 : 14400, eNOPARITY, eONESTOPBIT, 8)) + { + printf("Error setting up COM params\n"); + exit(1); + } + } + else + { // download the monitor program + if (gCmd.bArchos) + { + printf("Waiting for box startup to download monitor..."); + DownloadArchosMonitor(serial_handle, "minimon_v2.bin"); // load the monitor image + printf("\b\b\b done.\n"); + } + else + { + printf("Downloading monitor..."); + DownloadMonitor(serial_handle, gCmd.bRecorder, "minimon.bin"); // load the monitor image + // From now on, we can talk to the box. + printf("\b\b\b done.\n"); + + if (gCmd.bRecorder) + { // we can be faster + SetTargetBaudrate(serial_handle, 11059200, 115200); // set to 115200 + } + } + } + + // do the action + + if (gCmd.bSpindown) + { + // spindown the disk (works only for master) + UINT32 ata; // address of ATA_ALT_STATUS + printf("Harddisk spindown..."); + ata = (gCmd.bRecorder && (ReadHalfword(serial_handle, 0x020000FC) & 0x0100)) ? 0x06200206 : 0x06200306; + WriteHalfword(serial_handle, 0x05FFFFCA, 0xBF99); // PACR2 (was 0xFF99) + WriteHalfword(serial_handle, 0x05FFFFC4, 0x0280); // PAIOR (was 0x0000) + WriteHalfword(serial_handle, 0x05FFFFC0, 0xA27F); // PADR (was 0xA0FF) + while (ReadByte(serial_handle, ata) & 0x80); // ATA_ALT_STATUS & STATUS_BSY + WriteByte(serial_handle, 0x06100107, 0xE0); // ATA_COMMAND = CMD_STANDBY_IMMEDIATE; + //while (ReadByte(serial_handle, ata) & 0x80); // ATA_ALT_STATUS & STATUS_BSY + printf("\b\b\b done.\n"); + } + + + if (gCmd.bReadID) + { + UINT8 bMan, bID; + ReadID(serial_handle, 0x02000000, &bMan, &bID); + printf("Manufacturer ID = 0x%02X, Device ID = 0x%02X\n", bMan, bID); + } + + + if (gCmd.szFlashfile) + { + // flash a firmware file + printf("Flashing file %s...", gCmd.szFlashfile); + pFile = fopen(gCmd.szFlashfile, "rb"); + if (pFile == NULL) + { + printf("\nFlash file %s not found, exiting.\n", gCmd.szFlashfile); + return -2; + } + size = fread(abFirmware, 1, sizeof(abFirmware), pFile); + fclose (pFile); + + EraseChip(serial_handle, 0x02000000); + FlashByteMultiple(serial_handle, 0x02000000, size, abFirmware); + printf("\b\b\b done.\n"); + } + + + if (gCmd.szDumpfile) + { + // dump the flash content + printf("Writing flash dump into file %s...", gCmd.szDumpfile); + ReadByteMultiple(serial_handle, 0x02000000, sizeof(abFirmware), abFirmware); + pFile = fopen(gCmd.szDumpfile, "wb"); + if (pFile == NULL) + { + printf("\nDump file %s cannot be opened, exiting.\n", gCmd.szDumpfile); + return -3; + } + fwrite(abFirmware, 1, sizeof(abFirmware), pFile); + fclose (pFile); + printf("\b\b\b done.\n"); + } + + + if (gCmd.szExecfile) + { + UINT32 size; + + printf("Downloading program..."); + + // init the DRAM controller like the flash boot does + reg = ReadHalfword(serial_handle, 0x05FFFFCA); // PACR2 + reg &= 0xFFFB; // PA1 config: /RAS + reg |= 0x0008; + WriteHalfword(serial_handle, 0x05FFFFCA, reg); // PACR2 + reg = 0xAFFF; // CS1, CS3 config: /CASH. /CASL + WriteHalfword(serial_handle, 0x05FFFFEE, reg); // CASCR + reg = ReadHalfword(serial_handle, 0x05FFFFA0); // BCR + reg |= 0x8000; // DRAM enable, default bus + WriteHalfword(serial_handle, 0x05FFFFA0, reg); // BCR + reg = ReadHalfword(serial_handle, 0x05FFFFA2); // WCR1 + reg &= 0xFDFD; // 1-cycle CAS + WriteHalfword(serial_handle, 0x05FFFFA2, reg); // WCR1 + reg = 0x0E00; // CAS 35%, multiplexed, 10 bit row addr. + WriteHalfword(serial_handle, 0x05FFFFA8, reg); // DCR + reg = 0x5AB0; // refresh, 4 cycle waitstate + WriteHalfword(serial_handle, 0x05FFFFAC, reg); // RCR + reg = 0x9605; // refresh constant + WriteHalfword(serial_handle, 0x05FFFFB2, reg); // RTCOR + reg = 0xA518; // phi/32 + WriteHalfword(serial_handle, 0x05FFFFAE, reg); // RTCSR + + + // download Rockbox/gdb + pFile = fopen(gCmd.szExecfile, "rb"); + if (pFile == NULL) + { + printf("\nExecutable file %s cannot be opened, exiting.\n", gCmd.szExecfile); + return -3; + } + + size = fread(abFirmware, 1, sizeof(abFirmware), pFile); + WriteByteMultiple(serial_handle, 0x09000000, size, abFirmware); + fclose (pFile); + printf("\b\b\b done.\n"); + + // start rockbox/gdb + printf("Starting program..."); + Execute(serial_handle, 0x09000200, false); + printf("\b\b\b done.\n"); + } + + + if (gCmd.bTest) + { + // test code: query keypad + while (1) + { + WriteByte(serial_handle, 0x05FFFEE8, 0x24); // ADCSR + while (!(ReadByte(serial_handle, 0x05FFFEE8) & 0x80)); + reg = ReadHalfword(serial_handle, 0x05FFFEE0); // ADDRA + printf("ADC(4): %d\n", reg>>6); + } + } + + + if (gCmd.bBlink) + { + // blinking LED + UINT8 byte; + printf("Flashing red LED forever... (stop with Ctrl-C)\n"); + byte = ReadByte(serial_handle, 0x05FFFFC3); + while (1) + { + byte ^= 0x40; + WriteByte(serial_handle, 0x05FFFFC3, byte); + Sleep(200); + } + } + + return 0; +} + diff --git a/flash/uart_boot/uart_boot.dsp b/flash/uart_boot/uart_boot.dsp new file mode 100644 index 0000000000..4d94c72530 --- /dev/null +++ b/flash/uart_boot/uart_boot.dsp @@ -0,0 +1,130 @@ +# Microsoft Developer Studio Project File - Name="uart_boot" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=uart_boot - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "uart_boot.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "uart_boot.mak" CFG="uart_boot - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "uart_boot - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "uart_boot - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "uart_boot - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "uart_boot - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "uart_boot - Win32 Release" +# Name "uart_boot - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\client.c +# End Source File +# Begin Source File + +SOURCE=.\flash.c +# End Source File +# Begin Source File + +SOURCE=.\uart_boot.c +# End Source File +# Begin Source File + +SOURCE=.\uart_win.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\client.h +# End Source File +# Begin Source File + +SOURCE=.\flash.h +# End Source File +# Begin Source File + +SOURCE=.\minimon.h +# End Source File +# Begin Source File + +SOURCE=.\scalar_types.h +# End Source File +# Begin Source File + +SOURCE=.\uart.h +# End Source File +# End Group +# End Target +# End Project diff --git a/flash/uart_boot/uart_win.c b/flash/uart_boot/uart_win.c new file mode 100644 index 0000000000..243017ac88 --- /dev/null +++ b/flash/uart_boot/uart_win.c @@ -0,0 +1,138 @@ +// UART wrapper implementation for the Win32 platform +// make a new version of this file for different systems, e.g. Linux + +#include <windows.h> +#include "scalar_types.h" // (U)INT8/16/32 +#include "Uart.h" + +// COMx for windows, returns NULL on error +tUartHandle UartOpen(char* szPortName) +{ + HANDLE serial_handle; + DCB dcb; + COMMTIMEOUTS cto = { 0, 0, 0, 0, 0 }; + + memset(&dcb,0,sizeof(dcb)); + + /* -------------------------------------------------------------------- */ + // set DCB to configure the serial port + dcb.DCBlength = sizeof(dcb); + + dcb.fOutxCtsFlow = 0; + dcb.fOutxDsrFlow = 0; + dcb.fDtrControl = DTR_CONTROL_ENABLE; // enable for power + dcb.fDsrSensitivity = 0; + dcb.fRtsControl = RTS_CONTROL_ENABLE; // enable for power + dcb.fOutX = 0; + dcb.fInX = 0; + + /* ----------------- misc parameters ----- */ + dcb.fErrorChar = 0; + dcb.fBinary = 1; + dcb.fNull = 0; + dcb.fAbortOnError = 0; + dcb.wReserved = 0; + dcb.XonLim = 2; + dcb.XoffLim = 4; + dcb.XonChar = 0x13; + dcb.XoffChar = 0x19; + dcb.EvtChar = 0; + + /* ----------------- defaults ----- */ + dcb.BaudRate = 4800; + dcb.Parity = NOPARITY; + dcb.fParity = 0; + dcb.StopBits = ONESTOPBIT; + dcb.ByteSize = 8; + + + /* -------------------------------------------------------------------- */ + // opening serial port + serial_handle = CreateFile(szPortName, GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); + + if (serial_handle == INVALID_HANDLE_VALUE) + { + //printf("Cannot open port \n"); + return NULL; + } + + SetCommMask(serial_handle, 0); + SetCommTimeouts(serial_handle, &cto); + + if(!SetCommState(serial_handle, &dcb)) + { + //printf("Error setting up COM params\n"); + CloseHandle(serial_handle); + return NULL; + } + + return serial_handle; +} + +// returns true on success, false on error +bool UartConfig(tUartHandle handle, long lBaudRate, tParity nParity, tStopBits nStopBits, int nByteSize) +{ + DCB dcb; + + if (!GetCommState (handle, &dcb)) + { + return false; + } + + dcb.BaudRate = lBaudRate; + dcb.Parity = nParity; + dcb.StopBits = nStopBits; + dcb.ByteSize = nByteSize; + + if(!SetCommState(handle, &dcb)) + { + //DWORD dwErr = GetLastError(); + //printf("Error %d setting up COM params for baudrate byte\n", dwErr); + return false; + } + + return true; +} + +// returns how much data was actually transmitted +long UartWrite(tUartHandle handle, unsigned char* pData, long lSize) +{ + BOOL success; + DWORD result_nbr; + + success = WriteFile(handle, pData, lSize, &result_nbr, NULL); + + if(!success) + { + return 0; + } + + return result_nbr; +} + +// returns how much data was actually received +long UartRead(tUartHandle handle, unsigned char* pBuffer, long lSize) +{ + BOOL success; + DWORD read_nbr; + + success = ReadFile(handle, pBuffer, lSize, &read_nbr, NULL); + if(!success) + { + return 0; + } + + return read_nbr; +} + + +void UartClose(tUartHandle handle) +{ + if (handle != NULL) + { + CloseHandle(handle); + } + + return; +} |