From 8335f13fb15080852bf1928ad669b98f7e4c51ea Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Thu, 11 Jul 2019 10:14:27 +0200 Subject: [PATCH] bios/boot: rework netboot/flashboot for VexRiscv in linux variant Get rid of NETBOOT_LINUX_VEXRISCV/FLASHBOOT_LINUX_VEXRISCV defines and use information about CPU_TYPE and CPU_VARIANT instead. Use common kernel/rootfs/device tree/emulator images layout when booting over network and from flash. --- litex/soc/software/bios/boot.c | 189 ++++++++++++++++++++++----------- 1 file changed, 125 insertions(+), 64 deletions(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index be7c9278..b79eed90 100644 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -224,55 +224,73 @@ const char *filename, char *buffer) static const unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00}; -void netboot(void) +#define ROOTFS_IMAGE_RAM_OFFSET 0x00800000 +#define DEVICE_TREE_IMAGE_RAM_OFFSET 0x01000000 +#define EMULATOR_IMAGE_RAM_OFFSET 0x02000000 + +#if defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX) +static int try_get_kernel_rootfs_dtb_emulator(unsigned int ip, unsigned short tftp_port) { - int size; - unsigned int ip; unsigned long tftp_dst_addr; - unsigned short tftp_port; - - 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)); - - tftp_port = TFTP_SERVER_PORT; - printf("Fetching from: UDP/%d\n", tftp_port); + int size; -#ifdef NETBOOT_LINUX_VEXRISCV tftp_dst_addr = MAIN_RAM_BASE; size = tftp_get_v(ip, tftp_port, "Image", (void *)tftp_dst_addr); if (size <= 0) { printf("Network boot failed\n"); - return; + return 0; } - tftp_dst_addr = MAIN_RAM_BASE + 0x00800000; + tftp_dst_addr = MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET; size = tftp_get_v(ip, tftp_port, "rootfs.cpio", (void *)tftp_dst_addr); if(size <= 0) { printf("No rootfs.cpio found\n"); - return; + return 0; } - tftp_dst_addr = MAIN_RAM_BASE + 0x01000000; + tftp_dst_addr = MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET; size = tftp_get_v(ip, tftp_port, "rv32.dtb", (void *)tftp_dst_addr); if(size <= 0) { printf("No rv32.dtb found\n"); - return; + return 0; } - tftp_dst_addr = EMULATOR_RAM_BASE; + tftp_dst_addr = MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET; size = tftp_get_v(ip, tftp_port, "emulator.bin", (void *)tftp_dst_addr); if(size <= 0) { printf("No emulator.bin found\n"); - return; + return 0; } - boot(0, 0, 0, EMULATOR_RAM_BASE); -#else + return 1; +} +#endif + +void netboot(void) +{ + int size; + unsigned int ip; + unsigned long tftp_dst_addr; + unsigned short tftp_port; + + 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)); + + tftp_port = TFTP_SERVER_PORT; + printf("Fetching from: UDP/%d\n", tftp_port); + +#if defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX) + if(try_get_kernel_rootfs_dtb_emulator(ip, tftp_port)) + { + boot(0, 0, 0, MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); + return; + } +#endif tftp_dst_addr = MAIN_RAM_BASE; size = tftp_get_v(ip, tftp_port, "boot.bin", (void *)tftp_dst_addr); if (size <= 0) { @@ -281,34 +299,10 @@ void netboot(void) } boot(0, 0, 0, MAIN_RAM_BASE); -#endif - } #endif -#ifdef FLASHBOOT_LINUX_VEXRISCV - -/* TODO: add configurable flash mapping, improve integration */ - -void flashboot(void) -{ - printf("Loading Image from flash...\n"); - memcpy((void *)MAIN_RAM_BASE + 0x00000000, (void *)0x50400000, 0x400000); - - printf("Loading rootfs.cpio from flash...\n"); - memcpy((void *)MAIN_RAM_BASE + 0x00800000, (void *)0x50800000, 0x700000); - - printf("Loading rv32.dtb from flash...\n"); - memcpy((void *)MAIN_RAM_BASE + 0x01000000, (void *)0x50f00000, 0x001000); - - printf("Loading emulator.bin from flash...\n"); - memcpy((void *)EMULATOR_RAM_BASE + 0x00000000, (void *)0x50f80000, 0x004000); - - boot(0, 0, 0, EMULATOR_RAM_BASE); -} -#else - #ifdef FLASH_BOOT_ADDRESS /* On systems with exernal SDRAM we copy out of the SPI flash into the SDRAM @@ -321,38 +315,105 @@ void flashboot(void) #define FIRMWARE_BASE_ADDRESS (FLASH_BOOT_ADDRESS + 2 * sizeof(unsigned int)) #endif -void flashboot(void) +static unsigned int check_image_in_flash(unsigned int *base_address) { - unsigned int *flashbase; unsigned int length; unsigned int crc; unsigned int got_crc; - printf("Booting from flash...\n"); - flashbase = (unsigned int *)FLASH_BOOT_ADDRESS; - length = *flashbase++; - crc = *flashbase++; + length = *base_address++; if((length < 32) || (length > 4*1024*1024)) { - printf("Error: Invalid flash boot image length 0x%08x\n", length); + printf("Error: Invalid image length 0x%08x\n", length); + return 0; + } + + crc = *base_address++; + got_crc = crc32((unsigned char *)base_address, length); + if(crc != got_crc) { + printf("CRC failed (expected %08x, got %08x)\n", crc, got_crc); + return 0; + } + + return length; +} + +#if defined(MAIN_RAM_BASE) && defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX) +static int copy_image_from_flash_to_ram(unsigned int *flash_address, unsigned int *ram_address) +{ + unsigned int length; + + length = check_image_in_flash(flash_address); + if(length > 0) { + // skip length and crc + memcpy((void *)ram_address, (void *)(flash_address + 2), length); + return 1; + } + + return 0; +} +#endif + +#define KERNEL_IMAGE_FLASH_OFFSET 0x00000000 // 0MB +#define ROOTFS_IMAGE_FLASH_OFFSET 0x00400000 // 4MB +#define DEVICE_TREE_IMAGE_FLASH_OFFSET 0x00B00000 // 11MB +#define EMULATOR_IMAGE_FLASH_OFFSET 0x00B01000 // 11MB + 4KB + +void flashboot(void) +{ + unsigned int length; + +#if defined(MAIN_RAM_BASE) && defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX) + unsigned int result; + + printf("Loading emulator.bin from flash...\n"); + result = copy_image_from_flash_to_ram( + (unsigned int *)(FLASH_BOOT_ADDRESS + EMULATOR_IMAGE_FLASH_OFFSET), + (unsigned int *)(MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET)); + + if(result) { + printf("Loading Image from flash...\n"); + result &= copy_image_from_flash_to_ram( + (unsigned int *)FLASH_BOOT_ADDRESS + KERNEL_IMAGE_FLASH_OFFSET, + (unsigned int *)MAIN_RAM_BASE); + } + + if(result) { + printf("Loading rootfs.cpio from flash...\n"); + result &= copy_image_from_flash_to_ram( + (unsigned int *)(FLASH_BOOT_ADDRESS + ROOTFS_IMAGE_FLASH_OFFSET), + (unsigned int *)(MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET)); + } + + if(result) { + printf("Loading rv32.dtb from flash...\n"); + result &= copy_image_from_flash_to_ram( + (unsigned int *)(FLASH_BOOT_ADDRESS + DEVICE_TREE_IMAGE_FLASH_OFFSET), + (unsigned int *)(MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET)); + } + + if(result) { + boot(0, 0, 0, MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET); + return; + } +#endif + + printf("Booting from flash...\n"); + length = check_image_in_flash((unsigned int *)FLASH_BOOT_ADDRESS); + if(!length) + { return; } #ifdef MAIN_RAM_BASE printf("Loading %d bytes from flash...\n", length); - memcpy((void *)MAIN_RAM_BASE, flashbase, length); + // skip length and crc + memcpy((void *)MAIN_RAM_BASE, (unsigned int *)(FLASH_BOOT_ADDRESS + 2 * sizeof(unsigned int)), length); #endif - got_crc = crc32((unsigned char *)FIRMWARE_BASE_ADDRESS, length); - if(crc != got_crc) { - printf("CRC failed (expected %08x, got %08x)\n", crc, got_crc); - return; - } boot(0, 0, 0, FIRMWARE_BASE_ADDRESS); } #endif -#endif - #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 -- 2.30.2