software/bios/boot: Allow frame reception to time out during serial boot and do some cleanup/add comments.
Allowing the serial boot to time out during frame reception allows doing test on the Host side to calibrate the minimum inter-frame delay and maximum payload length. In the future, we should probably compute the CRC directly during frame reception and do the mempcpy of frame N during the reception of frame N+1 to avoid these inter-frame constraints.
This commit is contained in:
parent
5a35aa9df6
commit
80cb53fb04
|
@ -1,4 +1,4 @@
|
||||||
// This file is Copyright (c) 2014-2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
// This file is Copyright (c) 2014-2021 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
|
// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
|
||||||
// This file is Copyright (c) 2018 Ewen McNeill <ewen@naos.co.nz>
|
// This file is Copyright (c) 2018 Ewen McNeill <ewen@naos.co.nz>
|
||||||
// This file is Copyright (c) 2018 Felix Held <felix-github@felixheld.de>
|
// This file is Copyright (c) 2018 Felix Held <felix-github@felixheld.de>
|
||||||
|
@ -104,20 +104,27 @@ void romboot(void)
|
||||||
|
|
||||||
#ifdef CSR_UART_BASE
|
#ifdef CSR_UART_BASE
|
||||||
|
|
||||||
static int check_ack(void)
|
#define ACK_TIMEOUT_DELAY CONFIG_CLOCK_FREQUENCY/4
|
||||||
{
|
#define CMD_TIMEOUT_DELAY CONFIG_CLOCK_FREQUENCY/16
|
||||||
int recognized;
|
|
||||||
static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
|
|
||||||
|
|
||||||
|
static void timer0_load(unsigned int value) {
|
||||||
timer0_en_write(0);
|
timer0_en_write(0);
|
||||||
timer0_reload_write(0);
|
timer0_reload_write(0);
|
||||||
#ifndef CONFIG_DISABLE_DELAYS
|
#ifndef CONFIG_DISABLE_DELAYS
|
||||||
timer0_load_write(CONFIG_CLOCK_FREQUENCY/4);
|
timer0_load_write(value);
|
||||||
#else
|
#else
|
||||||
timer0_load_write(0);
|
timer0_load_write(0);
|
||||||
#endif
|
#endif
|
||||||
timer0_en_write(1);
|
timer0_en_write(1);
|
||||||
timer0_update_value_write(1);
|
timer0_update_value_write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_ack(void)
|
||||||
|
{
|
||||||
|
int recognized;
|
||||||
|
static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
|
||||||
|
|
||||||
|
timer0_load(ACK_TIMEOUT_DELAY);
|
||||||
recognized = 0;
|
recognized = 0;
|
||||||
while(timer0_value_read()) {
|
while(timer0_value_read()) {
|
||||||
if(uart_read_nonblock()) {
|
if(uart_read_nonblock()) {
|
||||||
|
@ -144,18 +151,18 @@ static int check_ack(void)
|
||||||
static uint32_t get_uint32(unsigned char* data)
|
static uint32_t get_uint32(unsigned char* data)
|
||||||
{
|
{
|
||||||
return ((uint32_t) data[0] << 24) |
|
return ((uint32_t) data[0] << 24) |
|
||||||
((uint32_t) data[1] << 16) |
|
((uint32_t) data[1] << 16) |
|
||||||
((uint32_t) data[2] << 8) |
|
((uint32_t) data[2] << 8) |
|
||||||
(uint32_t) data[3];
|
(uint32_t) data[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_FAILED 5
|
#define MAX_FAILURES 256
|
||||||
|
|
||||||
/* Returns 1 if other boot methods should be tried */
|
/* Returns 1 if other boot methods should be tried */
|
||||||
int serialboot(void)
|
int serialboot(void)
|
||||||
{
|
{
|
||||||
struct sfl_frame frame;
|
struct sfl_frame frame;
|
||||||
int failed;
|
int failures;
|
||||||
static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
|
static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
|
||||||
const char *c;
|
const char *c;
|
||||||
int ack_status;
|
int ack_status;
|
||||||
|
@ -163,7 +170,7 @@ int serialboot(void)
|
||||||
printf("Booting from serial...\n");
|
printf("Booting from serial...\n");
|
||||||
printf("Press Q or ESC to abort boot completely.\n");
|
printf("Press Q or ESC to abort boot completely.\n");
|
||||||
|
|
||||||
/* Send the serialboot "magic" request to Host */
|
/* Send the serialboot "magic" request to Host and wait for ACK_OK */
|
||||||
c = str;
|
c = str;
|
||||||
while(*c) {
|
while(*c) {
|
||||||
uart_write(*c);
|
uart_write(*c);
|
||||||
|
@ -178,70 +185,113 @@ int serialboot(void)
|
||||||
printf("Cancelled\n");
|
printf("Cancelled\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Assume ACK_OK */
|
|
||||||
|
|
||||||
failed = 0;
|
/* Assume ACK_OK */
|
||||||
|
failures = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
int i;
|
int i;
|
||||||
int actualcrc;
|
int timeout;
|
||||||
int goodcrc;
|
int computed_crc;
|
||||||
|
int received_crc;
|
||||||
|
|
||||||
/* Get one Frame */
|
/* Get one Frame */
|
||||||
frame.payload_length = uart_read();
|
i = 0;
|
||||||
frame.crc[0] = uart_read();
|
timeout = 1;
|
||||||
frame.crc[1] = uart_read();
|
while((i == 0) || timer0_value_read()) {
|
||||||
frame.cmd = uart_read();
|
if (uart_read_nonblock()) {
|
||||||
for(i=0;i<frame.payload_length;i++)
|
if (i == 0) {
|
||||||
frame.payload[i] = uart_read();
|
timer0_load(CMD_TIMEOUT_DELAY);
|
||||||
|
frame.payload_length = uart_read();
|
||||||
|
}
|
||||||
|
if (i == 1) frame.crc[0] = uart_read();
|
||||||
|
if (i == 2) frame.crc[1] = uart_read();
|
||||||
|
if (i == 3) frame.cmd = uart_read();
|
||||||
|
if (i >= 4) {
|
||||||
|
frame.payload[i-4] = uart_read();
|
||||||
|
if (i == (frame.payload_length + 4 - 1)) {
|
||||||
|
timeout = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
timer0_update_value_write(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check Frame CRC (if CMD has a CRC) */
|
/* Check Timeout */
|
||||||
actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
|
if (timeout) {
|
||||||
goodcrc = crc16(&frame.cmd, frame.payload_length+1);
|
/* Acknowledge the Timeout and continue with a new frame */
|
||||||
if(actualcrc != goodcrc) {
|
uart_write(SFL_ACK_ERROR);
|
||||||
/* Clear out the RX buffer */
|
continue;
|
||||||
while (uart_read_nonblock()) uart_read();
|
}
|
||||||
failed++;
|
|
||||||
if(failed == MAX_FAILED) {
|
/* Check Frame CRC */
|
||||||
|
received_crc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
|
||||||
|
computed_crc = crc16(&frame.cmd, frame.payload_length+1);
|
||||||
|
if(computed_crc != received_crc) {
|
||||||
|
/* Acknowledge the CRC error */
|
||||||
|
uart_write(SFL_ACK_CRCERROR);
|
||||||
|
|
||||||
|
/* Increment failures and exit when max is reached */
|
||||||
|
failures++;
|
||||||
|
if(failures == MAX_FAILURES) {
|
||||||
printf("Too many consecutive errors, aborting");
|
printf("Too many consecutive errors, aborting");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
uart_write(SFL_ACK_CRCERROR);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute Frame CMD */
|
/* Execute Frame CMD */
|
||||||
switch(frame.cmd) {
|
switch(frame.cmd) {
|
||||||
|
/* On SFL_CMD_ABORT ... */
|
||||||
case SFL_CMD_ABORT:
|
case SFL_CMD_ABORT:
|
||||||
failed = 0;
|
/* Reset failures */
|
||||||
|
failures = 0;
|
||||||
|
/* Acknowledge and exit */
|
||||||
uart_write(SFL_ACK_SUCCESS);
|
uart_write(SFL_ACK_SUCCESS);
|
||||||
return 1;
|
return 1;
|
||||||
case SFL_CMD_LOAD: {
|
|
||||||
char *writepointer;
|
|
||||||
|
|
||||||
failed = 0;
|
/* On SFL_CMD_LOAD... */
|
||||||
writepointer = (char *)(uintptr_t) get_uint32(&frame.payload[0]);
|
case SFL_CMD_LOAD: {
|
||||||
for(i=4;i<frame.payload_length;i++)
|
char *load_addr;
|
||||||
*(writepointer++) = frame.payload[i];
|
|
||||||
if (frame.cmd == SFL_CMD_LOAD)
|
/* Reset failures */
|
||||||
uart_write(SFL_ACK_SUCCESS);
|
failures = 0;
|
||||||
|
|
||||||
|
/* Copy payload */
|
||||||
|
load_addr = (char *)(uintptr_t) get_uint32(&frame.payload[0]);
|
||||||
|
memcpy(load_addr, &frame.payload[4], frame.payload_length);
|
||||||
|
|
||||||
|
/* Acknowledge and continue */
|
||||||
|
uart_write(SFL_ACK_SUCCESS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* On SFL_CMD_ABORT ... */
|
||||||
case SFL_CMD_JUMP: {
|
case SFL_CMD_JUMP: {
|
||||||
uint32_t addr;
|
uint32_t jump_addr;
|
||||||
|
|
||||||
failed = 0;
|
/* Reset failures */
|
||||||
addr = get_uint32(&frame.payload[0]);
|
failures = 0;
|
||||||
|
|
||||||
|
/* Acknowledge and jump */
|
||||||
uart_write(SFL_ACK_SUCCESS);
|
uart_write(SFL_ACK_SUCCESS);
|
||||||
boot(0, 0, 0, addr);
|
jump_addr = get_uint32(&frame.payload[0]);
|
||||||
|
boot(0, 0, 0, jump_addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
failed++;
|
/* Increment failures */
|
||||||
if(failed == MAX_FAILED) {
|
failures++;
|
||||||
|
|
||||||
|
/* Acknowledge the UNKNOWN cmd */
|
||||||
|
uart_write(SFL_ACK_UNKNOWN);
|
||||||
|
|
||||||
|
/* Increment failures and exit when max is reached */
|
||||||
|
if(failures == MAX_FAILURES) {
|
||||||
printf("Too many consecutive errors, aborting");
|
printf("Too many consecutive errors, aborting");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
uart_write(SFL_ACK_UNKNOWN);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue