blob: 34f10b2b5b1b6256781746cd7b7ec5e63c1234d2 [file] [log] [blame]
#include <boot.h>
#include <common.h>
#include <command.h>
#include <init.h>
#include <clock.h>
#include <config.h>
#include <malloc.h>
#include <secure_boot.h>
#include <sha1.h>
#include <rsa_public_key.h>
#include <rsa_verify.h>
#include <xyzModem.h>
#include <mach/comcerto-2000.h>
#include <mach/gpio.h>
#include <asm/io.h>
#include <board_id.h>
#define ULOADER_PART_SIZE 0x20000 /* 128 KB */
#define BAREBOX_PART_SIZE 0x80000
#define BAREBOX_HEADER_SIZE 0x10 /* 16 bytes */
#define BAREBOX_LODING_ADDR \
(COMCERTO_AXI_DDR_BASE + 0x1000000 - BAREBOX_HEADER_SIZE)
#ifdef CONFIG_COMCERTO_NAND_ULOADER
extern int read_nand(ulong src, ulong offset, ulong count);
#endif
#if 0
static int bb_timeout(int timeout)
{
int ret = 1;
int countdown;
uint64_t start, second;
char c;
start = get_time_ns();
second = start;
countdown = timeout;
printf("Press Ctrl-X to interrupt");
printf("\n%2d", countdown--);
do {
if (tstc()) {
c = getc();
/* User can get a barebox prompt by pressing Ctrl-X */
if (c == 24) {
ret = 1;
goto out;
}
}
if (is_timeout(second, SECOND)) {
printf("\b\b%2d", countdown--);
second += SECOND;
}
} while (!is_timeout(start, timeout * SECOND));
ret = 0;
out:
printf("\n");
return ret;
}
#endif
static void bb_go(void *addr)
{
int (*func)(void);
printf("\n## Starting Barebox at 0x%p ...\n", addr);
console_flush();
func = addr;
shutdown_barebox();
func();
/*
* The application returned. Since we have shutdown barebox and
* we know nothing about the state of the cpu/memory we can't
* do anything here.
*/
while (1);
}
#ifdef CONFIG_COMCERTO_ULOADER_UART_DOWNLOAD
static int getcxmodem(void)
{
if (tstc())
return (getc());
return -1;
}
static int load_serial_ymodem(void *dst)
{
int err;
int res;
connection_info_t info;
void *addr = dst;
info.mode = xyzModem_ymodem;
res = xyzModem_stream_open(&info, &err);
if (res) {
printf("%s\n", xyzModem_error(err));
return 1;
}
err = 0;
res = xyzModem_stream_read(addr, 16*1024*1024, &err);
xyzModem_stream_close(&err);
xyzModem_stream_terminate(false, &getcxmodem);
if (err) {
printf("%s\n", xyzModem_error(err));
return 1;
}
printf("## Total Size = %d Bytes\n", res);
return 0;
}
#else /* CONFIG_COMCERTO_ULOADER_UART_DOWNLOAD */
static int load_serial_ymodem(void *dst)
{
printf("YMODEM download not supported\n");
return -1;
}
#endif /* CONFIG_COMCERTO_ULOADER_UART_DOWNLOAD */
static int _verify_image(u8 *image_ptr, u32 max_image_len) {
sha1_context ctx;
const struct rsa_public_key *public_key = NULL;
u8 *sig, hash[20];
u32 image_len, sig_offset;
int board_id;
image_len = _get_le_uint32(image_ptr);
if (image_len > max_image_len) {
printf("ERROR: barebox image verification failed (bad header)\n");
return -1;
}
image_ptr += 4;
sig_offset = _get_le_uint32(image_ptr);
image_ptr += 4;
image_ptr += 8;
sha1_starts(&ctx);
sha1_update(&ctx, image_ptr, image_len);
sha1_finish(&ctx, hash);
image_ptr += sig_offset;
sig = image_ptr;
board_id = get_board_id();
if (rsa_get_public_key(board_id, &public_key) != 0) {
printf("ERROR: could not verify barebox image (no public key)\n");
return -1;
}
return rsa_verify(public_key, sig, 256, hash);
}
static int verify_image(u8 *image_ptr, u32 max_image_len) {
#ifdef CONFIG_FORCE_BAREBOX_AUTH
bool secure_boot = true;
#else
bool secure_boot;
secure_boot_mode_t boot_mode = get_secure_boot_mode();
if (boot_mode == UNKNOWN) {
printf("Error: Unable to determine secure boot mode.\n");
return -1;
}
secure_boot = (boot_mode == SECURE);
#endif
if (secure_boot) {
printf("\nSecure boot detected; verifying Barebox image\n");
if (_verify_image(image_ptr, max_image_len) == 0) {
printf("Barebox image verified!\n");
} else {
printf("ERROR: Barebox image verification failed!\n");
return -1;
}
} else {
printf("Secure boot not enabled; skipping barebox verification.\n");
}
return 0;
}
static int do_bootb_barebox(void)
{
void *src = (void *) (COMCERTO_AXI_EXP_BASE + ULOADER_PART_SIZE); /* Start of NOR + uLdr size(128K) */
void *dst = (void *) BAREBOX_LODING_ADDR;
int count = BAREBOX_PART_SIZE;
int i;
u32 bootopt;
#if 0
int timeout = 1;
if(!secure_boot && bb_timeout(timeout))
return 0;
#endif
#ifdef CONFIG_COMCERTO_NAND_ULOADER
/* this option is used when uloader is in NOR flash or I2C EEPROM and
barebox is in NAND */
printf("\nCopying Bb from NAND\n");
read_nand(BAREBOX_LODING_ADDR, 0x0, BAREBOX_PART_SIZE);
#else
bootopt = ((readl(COMCERTO_GPIO_SYSTEM_CONFIG) >> BOOTSTRAP_BOOT_OPT_SHIFT) & BOOTSTRAP_BOOT_OPT_MASK);
switch(bootopt){
case BOOT_UART:
#define MAX_UART_DOWNLOAD_ATTEMPTS 3
for (i=0; i < MAX_UART_DOWNLOAD_ATTEMPTS; i++) {
printf("\nReady to receive Barebox over UART (bootopt=%d)\n", \
bootopt);
if (load_serial_ymodem((void *) dst)) continue;
if (verify_image(dst, count) == 0)
break;
}
if (i == MAX_UART_DOWNLOAD_ATTEMPTS) return -1;
break;
default:
/*
-With NOR boot the barebox will be loaded from NOR flash.
-With I2C boot the barebox will be loaded either from NOR flash or NAND.
If NAND then this part of code won't be compiled as CONFIG_COMCERTO_NAND_ULOADER
will be selected.
-With other boot option like UART boot, barebox will be loaded from NOR by default
*/
printf("\nCopying Barebox from NOR Flash(bootopt=%d)\n", \
bootopt);
memcpy((void *)dst, (void *)src, count);
if (verify_image(dst, count) == 0) break;
printf("\nTrying secondary partition\n");
src += count;
memcpy((void *)dst, (void *)src, count);
if (verify_image(dst, count) == 0) break;
return -1;
}
#endif
bb_go((void*)(BAREBOX_LODING_ADDR + BAREBOX_HEADER_SIZE));
return -1;
}
late_initcall(do_bootb_barebox);