2012-05-21 16:57:12 -04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <console.h>
|
|
|
|
#include <uart.h>
|
|
|
|
#include <system.h>
|
2012-05-24 13:01:47 -04:00
|
|
|
#include <crc.h>
|
2012-05-21 16:57:12 -04:00
|
|
|
#include <string.h>
|
|
|
|
#include <irq.h>
|
|
|
|
|
2014-02-21 11:55:05 -05:00
|
|
|
#include <generated/mem.h>
|
2013-11-24 13:50:17 -05:00
|
|
|
#include <generated/csr.h>
|
2012-05-21 16:57:12 -04:00
|
|
|
|
2013-04-30 18:12:13 -04:00
|
|
|
#include <net/microudp.h>
|
|
|
|
#include <net/tftp.h>
|
2015-09-28 01:02:13 -04:00
|
|
|
#include "sfl.h"
|
2012-05-21 16:57:12 -04:00
|
|
|
#include "boot.h"
|
|
|
|
|
2013-05-28 10:15:30 -04:00
|
|
|
extern void boot_helper(unsigned int r1, unsigned int r2, unsigned int r3, unsigned int addr);
|
2012-05-21 16:57:12 -04:00
|
|
|
|
2013-05-28 10:15:30 -04:00
|
|
|
static void __attribute__((noreturn)) boot(unsigned int r1, unsigned int r2, unsigned int r3, unsigned int addr)
|
2012-05-21 16:57:12 -04:00
|
|
|
{
|
|
|
|
printf("Executing booted program.\n");
|
|
|
|
uart_sync();
|
|
|
|
irq_setmask(0);
|
|
|
|
irq_setie(0);
|
2014-05-14 09:01:02 -04:00
|
|
|
flush_cpu_icache();
|
2013-05-28 10:15:30 -04:00
|
|
|
boot_helper(r1, r2, r3, addr);
|
2012-05-21 16:57:12 -04:00
|
|
|
while(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_ack(void)
|
|
|
|
{
|
|
|
|
int recognized;
|
|
|
|
static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
|
|
|
|
|
2013-05-13 11:18:30 -04:00
|
|
|
timer0_en_write(0);
|
|
|
|
timer0_reload_write(0);
|
|
|
|
timer0_load_write(identifier_frequency_read()/4);
|
|
|
|
timer0_en_write(1);
|
|
|
|
timer0_update_value_write(1);
|
2012-05-21 16:57:12 -04:00
|
|
|
recognized = 0;
|
2013-05-13 11:18:30 -04:00
|
|
|
while(timer0_value_read()) {
|
2012-05-21 16:57:12 -04:00
|
|
|
if(uart_read_nonblock()) {
|
|
|
|
char c;
|
|
|
|
c = uart_read();
|
|
|
|
if(c == str[recognized]) {
|
|
|
|
recognized++;
|
|
|
|
if(recognized == SFL_MAGIC_LEN)
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
if(c == str[0])
|
|
|
|
recognized = 1;
|
|
|
|
else
|
|
|
|
recognized = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-05-13 11:18:30 -04:00
|
|
|
timer0_update_value_write(1);
|
2012-05-21 16:57:12 -04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_FAILED 5
|
|
|
|
|
|
|
|
void serialboot(void)
|
|
|
|
{
|
|
|
|
struct sfl_frame frame;
|
|
|
|
int failed;
|
|
|
|
unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
|
|
|
|
static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
|
|
|
|
const char *c;
|
|
|
|
|
|
|
|
printf("Booting from serial...\n");
|
|
|
|
|
|
|
|
c = str;
|
|
|
|
while(*c) {
|
|
|
|
uart_write(*c);
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
if(!check_ack()) {
|
|
|
|
printf("Timeout\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
failed = 0;
|
|
|
|
cmdline_adr = initrdstart_adr = initrdend_adr = 0;
|
|
|
|
while(1) {
|
|
|
|
int i;
|
|
|
|
int actualcrc;
|
|
|
|
int goodcrc;
|
|
|
|
|
|
|
|
/* Grab one frame */
|
|
|
|
frame.length = uart_read();
|
|
|
|
frame.crc[0] = uart_read();
|
|
|
|
frame.crc[1] = uart_read();
|
|
|
|
frame.cmd = uart_read();
|
|
|
|
for(i=0;i<frame.length;i++)
|
|
|
|
frame.payload[i] = uart_read();
|
|
|
|
|
|
|
|
/* Check CRC */
|
|
|
|
actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
|
|
|
|
goodcrc = crc16(&frame.cmd, frame.length+1);
|
|
|
|
if(actualcrc != goodcrc) {
|
|
|
|
failed++;
|
|
|
|
if(failed == MAX_FAILED) {
|
|
|
|
printf("Too many consecutive errors, aborting");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uart_write(SFL_ACK_CRCERROR);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CRC OK */
|
|
|
|
switch(frame.cmd) {
|
|
|
|
case SFL_CMD_ABORT:
|
|
|
|
failed = 0;
|
|
|
|
uart_write(SFL_ACK_SUCCESS);
|
|
|
|
return;
|
|
|
|
case SFL_CMD_LOAD: {
|
|
|
|
char *writepointer;
|
|
|
|
|
|
|
|
failed = 0;
|
|
|
|
writepointer = (char *)(
|
|
|
|
((unsigned int)frame.payload[0] << 24)
|
|
|
|
|((unsigned int)frame.payload[1] << 16)
|
|
|
|
|((unsigned int)frame.payload[2] << 8)
|
|
|
|
|((unsigned int)frame.payload[3] << 0));
|
|
|
|
for(i=4;i<frame.length;i++)
|
|
|
|
*(writepointer++) = frame.payload[i];
|
|
|
|
uart_write(SFL_ACK_SUCCESS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SFL_CMD_JUMP: {
|
|
|
|
unsigned int addr;
|
|
|
|
|
|
|
|
failed = 0;
|
|
|
|
addr = ((unsigned int)frame.payload[0] << 24)
|
|
|
|
|((unsigned int)frame.payload[1] << 16)
|
|
|
|
|((unsigned int)frame.payload[2] << 8)
|
|
|
|
|((unsigned int)frame.payload[3] << 0);
|
|
|
|
uart_write(SFL_ACK_SUCCESS);
|
2013-05-28 10:15:30 -04:00
|
|
|
boot(cmdline_adr, initrdstart_adr, initrdend_adr, addr);
|
2012-05-21 16:57:12 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SFL_CMD_CMDLINE:
|
|
|
|
failed = 0;
|
|
|
|
cmdline_adr = ((unsigned int)frame.payload[0] << 24)
|
|
|
|
|((unsigned int)frame.payload[1] << 16)
|
|
|
|
|((unsigned int)frame.payload[2] << 8)
|
|
|
|
|((unsigned int)frame.payload[3] << 0);
|
|
|
|
uart_write(SFL_ACK_SUCCESS);
|
|
|
|
break;
|
|
|
|
case SFL_CMD_INITRDSTART:
|
|
|
|
failed = 0;
|
|
|
|
initrdstart_adr = ((unsigned int)frame.payload[0] << 24)
|
|
|
|
|((unsigned int)frame.payload[1] << 16)
|
|
|
|
|((unsigned int)frame.payload[2] << 8)
|
|
|
|
|((unsigned int)frame.payload[3] << 0);
|
|
|
|
uart_write(SFL_ACK_SUCCESS);
|
|
|
|
break;
|
|
|
|
case SFL_CMD_INITRDEND:
|
|
|
|
failed = 0;
|
|
|
|
initrdend_adr = ((unsigned int)frame.payload[0] << 24)
|
|
|
|
|((unsigned int)frame.payload[1] << 16)
|
|
|
|
|((unsigned int)frame.payload[2] << 8)
|
|
|
|
|((unsigned int)frame.payload[3] << 0);
|
|
|
|
uart_write(SFL_ACK_SUCCESS);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
failed++;
|
|
|
|
if(failed == MAX_FAILED) {
|
|
|
|
printf("Too many consecutive errors, aborting");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uart_write(SFL_ACK_UNKNOWN);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-02 06:25:59 -05:00
|
|
|
#ifdef CSR_ETHMAC_BASE
|
2013-11-24 17:50:09 -05:00
|
|
|
|
2012-05-21 16:57:12 -04:00
|
|
|
#define LOCALIP1 192
|
|
|
|
#define LOCALIP2 168
|
|
|
|
#define LOCALIP3 0
|
|
|
|
#define LOCALIP4 42
|
|
|
|
#define REMOTEIP1 192
|
|
|
|
#define REMOTEIP2 168
|
|
|
|
#define REMOTEIP3 0
|
|
|
|
#define REMOTEIP4 14
|
|
|
|
|
|
|
|
static int tftp_get_v(unsigned int ip, const char *filename, char *buffer)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = tftp_get(ip, filename, buffer);
|
|
|
|
if(r > 0)
|
|
|
|
printf("Successfully downloaded %d bytes from %s over TFTP\n", r, filename);
|
|
|
|
else
|
|
|
|
printf("Unable to download %s over TFTP\n", filename);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-06-01 11:20:40 -04:00
|
|
|
static const unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00};
|
|
|
|
|
2012-05-21 16:57:12 -04:00
|
|
|
void netboot(void)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
|
|
|
|
unsigned int ip;
|
|
|
|
|
|
|
|
printf("Booting from network...\n");
|
|
|
|
printf("Local IP : %d.%d.%d.%d\n", LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4);
|
|
|
|
printf("Remote IP: %d.%d.%d.%d\n", REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
|
|
|
|
|
|
|
|
ip = IPTOINT(REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
|
|
|
|
|
|
|
|
microudp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4));
|
|
|
|
|
2015-03-21 16:00:12 -04:00
|
|
|
if(tftp_get_v(ip, "boot.bin", (void *)MAIN_RAM_BASE) <= 0) {
|
2012-05-21 16:57:12 -04:00
|
|
|
printf("Network boot failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-21 16:00:12 -04:00
|
|
|
cmdline_adr = MAIN_RAM_BASE+0x1000000;
|
2012-05-21 16:57:12 -04:00
|
|
|
size = tftp_get_v(ip, "cmdline.txt", (void *)cmdline_adr);
|
|
|
|
if(size <= 0) {
|
|
|
|
printf("No command line parameters found\n");
|
|
|
|
cmdline_adr = 0;
|
|
|
|
} else
|
|
|
|
*((char *)(cmdline_adr+size)) = 0x00;
|
|
|
|
|
2015-03-21 16:00:12 -04:00
|
|
|
initrdstart_adr = MAIN_RAM_BASE+0x1002000;
|
2012-05-21 16:57:12 -04:00
|
|
|
size = tftp_get_v(ip, "initrd.bin", (void *)initrdstart_adr);
|
|
|
|
if(size <= 0) {
|
|
|
|
printf("No initial ramdisk found\n");
|
|
|
|
initrdstart_adr = 0;
|
|
|
|
initrdend_adr = 0;
|
|
|
|
} else
|
|
|
|
initrdend_adr = initrdstart_adr + size;
|
|
|
|
|
2015-03-21 16:00:12 -04:00
|
|
|
boot(cmdline_adr, initrdstart_adr, initrdend_adr, MAIN_RAM_BASE);
|
2012-05-21 16:57:12 -04:00
|
|
|
}
|
|
|
|
|
2013-11-24 17:50:09 -05:00
|
|
|
#endif
|
|
|
|
|
2014-02-21 11:55:05 -05:00
|
|
|
#ifdef FLASH_BOOT_ADDRESS
|
2012-05-21 16:57:12 -04:00
|
|
|
void flashboot(void)
|
|
|
|
{
|
|
|
|
unsigned int *flashbase;
|
|
|
|
unsigned int length;
|
|
|
|
unsigned int crc;
|
|
|
|
unsigned int got_crc;
|
|
|
|
|
|
|
|
printf("Booting from flash...\n");
|
2014-02-21 11:55:05 -05:00
|
|
|
flashbase = (unsigned int *)FLASH_BOOT_ADDRESS;
|
2012-05-21 16:57:12 -04:00
|
|
|
length = *flashbase++;
|
|
|
|
crc = *flashbase++;
|
|
|
|
if((length < 32) || (length > 4*1024*1024)) {
|
2013-06-01 11:20:40 -04:00
|
|
|
printf("Error: Invalid flash boot image length 0x%08x\n", length);
|
2012-05-21 16:57:12 -04:00
|
|
|
return;
|
|
|
|
}
|
2014-11-20 19:47:11 -05:00
|
|
|
|
2012-05-21 16:57:12 -04:00
|
|
|
printf("Loading %d bytes from flash...\n", length);
|
2015-03-21 16:00:12 -04:00
|
|
|
memcpy((void *)MAIN_RAM_BASE, flashbase, length);
|
|
|
|
got_crc = crc32((unsigned char *)MAIN_RAM_BASE, length);
|
2012-05-21 16:57:12 -04:00
|
|
|
if(crc != got_crc) {
|
|
|
|
printf("CRC failed (expected %08x, got %08x)\n", crc, got_crc);
|
|
|
|
return;
|
|
|
|
}
|
2015-03-21 16:00:12 -04:00
|
|
|
boot(0, 0, 0, MAIN_RAM_BASE);
|
2012-05-21 16:57:12 -04:00
|
|
|
}
|
2014-02-21 11:55:05 -05:00
|
|
|
#endif
|
2015-07-14 11:33:24 -04:00
|
|
|
|
|
|
|
#ifdef ROM_BOOT_ADDRESS
|
|
|
|
/* When firmware is small enough, it can be interesting to run code from an
|
|
|
|
embedded blockram memory (faster and not impacted by memory controller
|
|
|
|
activity). Define ROM_BOOT_ADDRESS for that and initialize the blockram
|
|
|
|
with the firmware data. */
|
|
|
|
void romboot(void)
|
|
|
|
{
|
|
|
|
boot(0, 0, 0, ROM_BOOT_ADDRESS);
|
|
|
|
}
|
|
|
|
#endif
|