summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/semihosting.h21
-rw-r--r--arch/arm/lib/Makefile1
-rw-r--r--arch/arm/lib/semihosting.c233
-rw-r--r--board/armltd/vexpress64/vexpress64.c101
-rw-r--r--boards.cfg1
-rw-r--r--doc/README.semihosting54
-rw-r--r--include/configs/vexpress_aemv8a.h63
7 files changed, 462 insertions, 12 deletions
diff --git a/arch/arm/include/asm/semihosting.h b/arch/arm/include/asm/semihosting.h
new file mode 100644
index 0000000000..74111dc359
--- /dev/null
+++ b/arch/arm/include/asm/semihosting.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2014 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __SEMIHOSTING_H__
+#define __SEMIHOSTING_H__
+
+/*
+ * ARM semihosting functions for loading images to memory. See the source
+ * code for more information.
+ */
+int smh_load(const char *fname, void *memp, int avail, int verbose);
+int smh_read(int fd, void *memp, int len);
+int smh_open(const char *fname, char *modestr);
+int smh_close(int fd);
+int smh_len_fd(int fd);
+int smh_len(const char *fname);
+
+#endif /* __SEMIHOSTING_H__ */
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 585f1f781b..1ef240047f 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_USE_ARCH_MEMCPY) += memcpy.o
else
obj-$(CONFIG_SPL_FRAMEWORK) += spl.o
endif
+obj-$(CONFIG_SEMIHOSTING) += semihosting.o
obj-y += sections.o
ifdef CONFIG_ARM64
diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c
new file mode 100644
index 0000000000..cb5dc26ac3
--- /dev/null
+++ b/arch/arm/lib/semihosting.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2014 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Minimal semihosting implementation for reading files into memory. If more
+ * features like writing files or console output are required they can be
+ * added later. This code has been tested on arm64/aarch64 fastmodel only.
+ * An untested placeholder exists for armv7 architectures, but since they
+ * are commonly available in silicon now, fastmodel usage makes less sense
+ * for them.
+ */
+#include <common.h>
+#include <asm/semihosting.h>
+
+#define SYSOPEN 0x01
+#define SYSCLOSE 0x02
+#define SYSREAD 0x06
+#define SYSFLEN 0x0C
+
+#define MODE_READ 0x0
+#define MODE_READBIN 0x1
+
+/*
+ * Call the handler
+ */
+static int smh_trap(unsigned int sysnum, void *addr)
+{
+ register int result asm("r0");
+#if defined(CONFIG_ARM64)
+ asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr));
+#else
+ /* Note - untested placeholder */
+ asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr));
+#endif
+ return result;
+}
+
+/*
+ * Open, load a file into memory, and close it. Check that the available space
+ * is sufficient to store the entire file. Return the bytes actually read from
+ * the file as seen by the read function. The verbose flag enables some extra
+ * printing of successful read status.
+ */
+int smh_load(const char *fname, void *memp, int avail, int verbose)
+{
+ int ret, fd, len;
+
+ ret = -1;
+
+ debug("%s: fname \'%s\', avail %u, memp %p\n", __func__, fname,
+ avail, memp);
+
+ /* Open the file */
+ fd = smh_open(fname, "rb");
+ if (fd == -1)
+ return ret;
+
+ /* Get the file length */
+ ret = smh_len_fd(fd);
+ if (ret == -1) {
+ smh_close(fd);
+ return ret;
+ }
+
+ /* Check that the file will fit in the supplied buffer */
+ if (ret > avail) {
+ printf("%s: ERROR ret %d, avail %u\n", __func__, ret,
+ avail);
+ smh_close(fd);
+ return ret;
+ }
+
+ len = ret;
+
+ /* Read the file into the buffer */
+ ret = smh_read(fd, memp, len);
+ if (ret == 0) {
+ /* Print successful load information if requested */
+ if (verbose) {
+ printf("\n%s\n", fname);
+ printf(" 0x%8p dest\n", memp);
+ printf(" 0x%08x size\n", len);
+ printf(" 0x%08x avail\n", avail);
+ }
+ }
+
+ /* Close the file */
+ smh_close(fd);
+
+ return ret;
+}
+
+/*
+ * Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure
+ */
+int smh_read(int fd, void *memp, int len)
+{
+ int ret;
+ struct smh_read_s {
+ int fd;
+ void *memp;
+ int len;
+ } read;
+
+ debug("%s: fd %d, memp %p, len %d\n", __func__, fd, memp, len);
+
+ read.fd = fd;
+ read.memp = memp;
+ read.len = len;
+
+ ret = smh_trap(SYSREAD, &read);
+ if (ret == 0) {
+ return 0;
+ } else {
+ /*
+ * The ARM handler allows for returning partial lengths,
+ * but in practice this never happens so rather than create
+ * hard to maintain partial read loops and such, just fail
+ * with an error message.
+ */
+ printf("%s: ERROR ret %d, fd %d, len %u memp %p\n",
+ __func__, ret, fd, len, memp);
+ }
+ return ret;
+}
+
+/*
+ * Open a file on the host. Mode is "r" or "rb" currently. Returns a file
+ * descriptor or -1 on error.
+ */
+int smh_open(const char *fname, char *modestr)
+{
+ int ret, fd, mode;
+ struct smh_open_s {
+ const char *fname;
+ unsigned int mode;
+ unsigned int len;
+ } open;
+
+ debug("%s: file \'%s\', mode \'%s\'\n", __func__, fname, modestr);
+
+ ret = -1;
+
+ /* Check the file mode */
+ if (!(strcmp(modestr, "r"))) {
+ mode = MODE_READ;
+ } else if (!(strcmp(modestr, "rb"))) {
+ mode = MODE_READBIN;
+ } else {
+ printf("%s: ERROR mode \'%s\' not supported\n", __func__,
+ modestr);
+ return ret;
+ }
+
+ open.fname = fname;
+ open.len = strlen(fname);
+ open.mode = mode;
+
+ /* Open the file on the host */
+ fd = smh_trap(SYSOPEN, &open);
+ if (fd == -1)
+ printf("%s: ERROR fd %d for file \'%s\'\n", __func__, fd,
+ fname);
+
+ return fd;
+}
+
+/*
+ * Close the file using the file descriptor
+ */
+int smh_close(int fd)
+{
+ int ret;
+ long fdlong;
+
+ debug("%s: fd %d\n", __func__, fd);
+
+ fdlong = (long)fd;
+ ret = smh_trap(SYSCLOSE, &fdlong);
+ if (ret == -1)
+ printf("%s: ERROR fd %d\n", __func__, fd);
+
+ return ret;
+}
+
+/*
+ * Get the file length from the file descriptor
+ */
+int smh_len_fd(int fd)
+{
+ int ret;
+ long fdlong;
+
+ debug("%s: fd %d\n", __func__, fd);
+
+ fdlong = (long)fd;
+ ret = smh_trap(SYSFLEN, &fdlong);
+ if (ret == -1)
+ printf("%s: ERROR ret %d\n", __func__, ret);
+
+ return ret;
+}
+
+/*
+ * Get the file length from the filename
+ */
+int smh_len(const char *fname)
+{
+ int ret, fd, len;
+
+ debug("%s: file \'%s\'\n", __func__, fname);
+
+ /* Open the file */
+ fd = smh_open(fname, "rb");
+ if (fd == -1)
+ return fd;
+
+ /* Get the file length */
+ len = smh_len_fd(fd);
+
+ /* Close the file */
+ ret = smh_close(fd);
+ if (ret == -1)
+ return ret;
+
+ debug("%s: returning len %d\n", __func__, len);
+
+ /* Return the file length (or -1 error indication) */
+ return len;
+}
diff --git a/board/armltd/vexpress64/vexpress64.c b/board/armltd/vexpress64/vexpress64.c
index 2ec3bc9835..58973185ec 100644
--- a/board/armltd/vexpress64/vexpress64.c
+++ b/board/armltd/vexpress64/vexpress64.c
@@ -11,6 +11,7 @@
#include <netdev.h>
#include <asm/io.h>
#include <linux/compiler.h>
+#include <asm/semihosting.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -31,11 +32,6 @@ int dram_init(void)
return 0;
}
-int timer_init(void)
-{
- return 0;
-}
-
/*
* Board specific reset that is system reset.
*/
@@ -43,6 +39,101 @@ void reset_cpu(ulong addr)
{
}
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+#ifdef CONFIG_SEMIHOSTING
+ /*
+ * Please refer to doc/README.semihosting for a more complete
+ * description.
+ *
+ * We require that the board include file defines these env variables:
+ * - kernel_name
+ * - kernel_addr_r
+ * - initrd_name
+ * - initrd_addr_r
+ * - fdt_name
+ * - fdt_addr_r
+ *
+ * For the "fdt chosen" startup macro, this code will then define:
+ * - initrd_end (based on initrd_addr_r plus actual initrd_size)
+ *
+ * We will then load the kernel, initrd, and fdt into the specified
+ * locations in memory in a similar way that the ATF fastmodel code
+ * uses semihosting calls to load other boot stages and u-boot itself.
+ */
+
+ /* Env variable strings */
+ char *kernel_name = getenv("kernel_name");
+ char *kernel_addr_str = getenv("kernel_addr_r");
+ char *initrd_name = getenv("initrd_name");
+ char *initrd_addr_str = getenv("initrd_addr_r");
+ char *fdt_name = getenv("fdt_name");
+ char *fdt_addr_str = getenv("fdt_addr_r");
+ char initrd_end_str[64];
+
+ /* Actual addresses converted from env variables */
+ void *kernel_addr_r;
+ void *initrd_addr_r;
+ void *fdt_addr_r;
+
+ /* Actual initrd base and size */
+ unsigned long initrd_base;
+ unsigned long initrd_size;
+
+ /* Space available */
+ int avail;
+
+ /* Make sure the environment variables needed are set */
+ if (!(kernel_addr_str && initrd_addr_str && fdt_addr_str)) {
+ printf("%s: Define {kernel/initrd/fdt}_addr_r\n", __func__);
+ return -1;
+ }
+ if (!(kernel_name && initrd_name && fdt_name)) {
+ printf("%s: Define {kernel/initrd/fdt}_name\n", __func__);
+ return -1;
+ }
+
+ /* Get exact initrd_size */
+ initrd_size = smh_len(initrd_name);
+ if (initrd_size == -1) {
+ printf("%s: Can't get file size for \'%s\'\n", __func__,
+ initrd_name);
+ return -1;
+ }
+
+ /* Set initrd_end */
+ initrd_base = simple_strtoul(initrd_addr_str, NULL, 16);
+ initrd_addr_r = (void *)initrd_base;
+ sprintf(initrd_end_str, "0x%lx", initrd_base + initrd_size - 1);
+ setenv("initrd_end", initrd_end_str);
+
+ /* Load kernel to memory */
+ fdt_addr_r = (void *)simple_strtoul(fdt_addr_str, NULL, 16);
+ kernel_addr_r = (void *)simple_strtoul(kernel_addr_str, NULL, 16);
+
+ /*
+ * The kernel must be lower in memory than fdt and loading the
+ * kernel must not trample the fdt or vice versa.
+ */
+ avail = fdt_addr_r - kernel_addr_r;
+ if (avail < 0) {
+ printf("%s: fdt must be after kernel\n", __func__);
+ return -1;
+ }
+ smh_load(kernel_name, kernel_addr_r, avail, 1);
+
+ /* Load fdt to memory */
+ smh_load(fdt_name, fdt_addr_r, 0x20000, 1);
+
+ /* Load initrd to memory */
+ smh_load(initrd_name, initrd_addr_r, initrd_size, 1);
+
+#endif /* CONFIG_SEMIHOSTING */
+ return 0;
+}
+#endif /* CONFIG_BOARD_LATE_INIT */
+
/*
* Board specific ethernet initialization routine.
*/
diff --git a/boards.cfg b/boards.cfg
index 8e2db8277e..33435deb76 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -44,6 +44,7 @@
###########################################################################################################
Active aarch64 armv8 - armltd vexpress64 vexpress_aemv8a vexpress_aemv8a:ARM64 David Feng <fenghua@phytium.com.cn>
+Active aarch64 armv8 - armltd vexpress64 vexpress_aemv8a_semi vexpress_aemv8a:ARM64,SEMIHOSTING,BASE_FVP Steve Rae <srae@broadcom.com>
Active arc arc700 - synopsys - axs101 - Alexey Brodkin <abrodkin@synopsys.com>
Active arc arc700 - synopsys <none> arcangel4 - Alexey Brodkin <abrodkin@synopsys.com>
Active arc arc700 - synopsys <none> arcangel4-be - Alexey Brodkin <abrodkin@synopsys.com>
diff --git a/doc/README.semihosting b/doc/README.semihosting
new file mode 100644
index 0000000000..7248560780
--- /dev/null
+++ b/doc/README.semihosting
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+Semihosting is ARM's way of having a real or virtual target communicate
+with a host or host debugger for basic operations such as file I/O,
+console I/O, etc. Please see
+http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/Bgbjjgij.html for more information.
+
+For developing on armv8 virtual fastmodel platforms, semihosting is a
+valuable tool since it allows access to image/configuration files before
+eMMC or other NV media are available.
+
+There are two main ARM virtual Fixed Virtual Platform (FVP) models,
+Versatile Express (VE) FVP and BASE FVP (See
+http://www.arm.com/products/tools/models/fast-models/foundation-model.php)
+The initial vexpress64 u-boot board created here runs on the VE virtual
+platform using the license-free Foundation_v8 simulator. Fortunately,
+the Foundation_v8 simulator also supports the BASE_FVP model which
+companies can purchase licenses for and contain much more functionality.
+So we can, in u-boot, run either model by either using the VE FVP (default),
+or turning on CONFIG_BASE_FVP for the more full featured model.
+
+Rather than create a new armv8 board similar to armltd/vexpress64, add
+semihosting calls to the existing one, enabled with CONFIG_SEMIHOSTING
+and CONFIG_BASE_FVP both set. Also reuse the existing board config file
+vexpress_aemv8a.h but differentiate the two models by the presence or
+absence of CONFIG_BASE_FVP. This change is tested and works on both the
+Foundation and Base fastmodel simulators.
+
+The level of semihosting support is minimal, restricted to just what it
+takes to load images to memory. If more semihosting functionality is
+required, such as file seek, outputting strings, reading characters, etc,
+then it can be easily added later.
+
+We require that the board include file define these env variables:
+- kernel_name e.g. "uImage"
+- kernel_addr_r e.g. "0x80000000"
+- initrd_name e.g. "ramdisk.img"
+- initrd_addr_r e.g. "0x88000000"
+- fdt_name e.g. "devtree.dtb"
+- fdt_addr_r e.g. "0x83000000"
+
+Optionally, "fdt_high" and "initrd_high" can be specified as per
+their rules for allowing or preventing copying of these images.
+
+For the "fdt chosen" startup macro, this code will then define:
+- initrd_end (based on retrieving initrd_addr_r plus actual initrd_size)
+
+We will then load the kernel, initrd, and fdt into the specified
+locations in memory in a similar way that the ATF fastmodel code
+uses semihosting calls to load other boot stages and u-boot itself.
diff --git a/include/configs/vexpress_aemv8a.h b/include/configs/vexpress_aemv8a.h
index dff6adcc7c..1905d133e2 100644
--- a/include/configs/vexpress_aemv8a.h
+++ b/include/configs/vexpress_aemv8a.h
@@ -10,9 +10,20 @@
#define DEBUG
+#ifdef CONFIG_BASE_FVP
+#ifndef CONFIG_SEMIHOSTING
+#error CONFIG_BASE_FVP requires CONFIG_SEMIHOSTING
+#endif
+#define CONFIG_BOARD_LATE_INIT
+#define CONFIG_ARMV8_SWITCH_TO_EL1
+#endif
+
#define CONFIG_REMAKE_ELF
+#ifndef CONFIG_BASE_FVP
+/* Base FVP not using GICv3 yet */
#define CONFIG_GICV3
+#endif
/*#define CONFIG_ARMV8_SWITCH_TO_EL1*/
@@ -30,8 +41,14 @@
#define CONFIG_BOOTP_VCI_STRING "U-boot.armv8.vexpress_aemv8a"
/* Link Definitions */
+#ifdef CONFIG_BASE_FVP
+/* ATF loads u-boot here for BASE_FVP model */
+#define CONFIG_SYS_TEXT_BASE 0x88000000
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x03f00000)
+#else
#define CONFIG_SYS_TEXT_BASE 0x80000000
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
+#endif
/* Flat Device Tree Definitions */
#define CONFIG_OF_LIBFDT
@@ -39,7 +56,11 @@
#define CONFIG_DEFAULT_DEVICE_TREE vexpress64
/* SMP Spin Table Definitions */
+#ifdef CONFIG_BASE_FVP
+#define CPU_RELEASE_ADDR (CONFIG_SYS_SDRAM_BASE + 0x03f00000)
+#else
#define CPU_RELEASE_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
+#endif
/* CS register bases for the original memory map. */
#define V2M_PA_CS0 0x00000000
@@ -99,9 +120,15 @@
#define GICD_BASE (0x2f000000)
#define GICR_BASE (0x2f100000)
#else
+
+#ifdef CONFIG_BASE_FVP
+#define GICD_BASE (0x2f000000)
+#define GICC_BASE (0x2c000000)
+#else
#define GICD_BASE (0x2C001000)
#define GICC_BASE (0x2C002000)
#endif
+#endif
#define CONFIG_SYS_MEMTEST_START V2M_BASE
#define CONFIG_SYS_MEMTEST_END (V2M_BASE + 0x80000000)
@@ -121,7 +148,6 @@
#define CONFIG_CONS_INDEX 0
#define CONFIG_BAUDRATE 115200
-#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
#define CONFIG_SYS_SERIAL0 V2M_UART0
#define CONFIG_SYS_SERIAL1 V2M_UART1
@@ -165,17 +191,41 @@
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
/* Initial environment variables */
+#ifdef CONFIG_BASE_FVP
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "kernel_name=uImage\0" \
+ "kernel_addr_r=0x80000000\0" \
+ "initrd_name=ramdisk.img\0" \
+ "initrd_addr_r=0x88000000\0" \
+ "fdt_name=devtree.dtb\0" \
+ "fdt_addr_r=0x83000000\0" \
+ "fdt_high=0xffffffffffffffff\0" \
+ "initrd_high=0xffffffffffffffff\0"
+
+#define CONFIG_BOOTARGS "console=ttyAMA0 earlyprintk=pl011,"\
+ "0x1c090000 debug user_debug=31 "\
+ "loglevel=9"
+
+#define CONFIG_BOOTCOMMAND "fdt addr $fdt_addr_r; fdt resize; " \
+ "fdt chosen $initrd_addr_r $initrd_end; " \
+ "bootm $kernel_addr_r - $fdt_addr_r"
+
+#define CONFIG_BOOTDELAY 1
+
+#else
+
#define CONFIG_EXTRA_ENV_SETTINGS \
- "kernel_addr=0x200000\0" \
- "initrd_addr=0xa00000\0" \
+ "kernel_addr_r=0x200000\0" \
+ "initrd_addr_r=0xa00000\0" \
"initrd_size=0x2000000\0" \
- "fdt_addr=0x100000\0" \
+ "fdt_addr_r=0x100000\0" \
"fdt_high=0xa0000000\0"
#define CONFIG_BOOTARGS "console=ttyAMA0 root=/dev/ram0"
-#define CONFIG_BOOTCOMMAND "bootm $kernel_addr " \
- "$initrd_addr:$initrd_size $fdt_addr"
+#define CONFIG_BOOTCOMMAND "bootm $kernel_addr_r " \
+ "$initrd_addr_r:$initrd_size $fdt_addr_r"
#define CONFIG_BOOTDELAY -1
+#endif
/* Do not preserve environment */
#define CONFIG_ENV_IS_NOWHERE 1
@@ -187,7 +237,6 @@
#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
sizeof(CONFIG_SYS_PROMPT) + 16)
#define CONFIG_SYS_HUSH_PARSER
-#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
#define CONFIG_SYS_LONGHELP
#define CONFIG_CMDLINE_EDITING 1