[U-Boot] [PATCH] arm: Add support for semihosting for armv8 fastmodel targets.
Darwin Rambo
drambo at broadcom.com
Wed Mar 12 17:04:01 CET 2014
The reason for this change is to be able to use the ARM Trusted Firmware
(ATF) to load the various ATF images, plus u-boot, which can then load
the kernel/ramdisk/dtb with calls to an external host from a standard
fastmodel armv8 board file using semihosting, and then launch the kernel
without a bootwrapper. This gives us a more realistic boot sequence.
Rather than create a new armv8 board similar to armltd/vexpress64, add
semihosting calls to the existing one, enabled with CONFIG_SEMIHOSTING.
Also add a new board config file vexpress_aemv8a_semi.h. This change is
tested and works on the ARM foundation model.
Support for armv7 in fastmodel is less useful due to the wide range of
available silicon but this change contains an untested armv7 placeholder
if desired.
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.
Signed-off-by: Darwin Rambo <drambo at broadcom.com>
---
arch/arm/include/asm/semihosting.h | 21 +++
arch/arm/lib/Makefile | 1 +
arch/arm/lib/semihosting.c | 235 ++++++++++++++++++++++++++++++++
board/armltd/vexpress64/vexpress64.c | 83 ++++++++++-
boards.cfg | 1 +
include/configs/vexpress_aemv8a_semi.h | 112 +++++++++++++++
6 files changed, 448 insertions(+), 5 deletions(-)
create mode 100644 arch/arm/include/asm/semihosting.h
create mode 100644 arch/arm/lib/semihosting.c
create mode 100644 include/configs/vexpress_aemv8a_semi.h
diff --git a/arch/arm/include/asm/semihosting.h b/arch/arm/include/asm/semihosting.h
new file mode 100644
index 0000000..74111dc
--- /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 9fc81cd..0ba929d 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 0000000..d603789
--- /dev/null
+++ b/arch/arm/lib/semihosting.c
@@ -0,0 +1,235 @@
+/*
+ * 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 if this ever happens, it is a bug in the fastmodel
+ * implementation. The Linux fastmodel doesn't show this
+ * issue, and any Windows fastmodel bugs need to be fixed.
+ * So rather than create ugly unmaintainable 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 2ec3bc9..9b64f71 100644
--- a/board/armltd/vexpress64/vexpress64.c
+++ b/board/armltd/vexpress64/vexpress64.c
@@ -12,6 +12,10 @@
#include <asm/io.h>
#include <linux/compiler.h>
+#ifdef CONFIG_SEMIHOSTING
+#include <asm/semihosting.h>
+#endif
+
DECLARE_GLOBAL_DATA_PTR;
int board_init(void)
@@ -31,11 +35,6 @@ int dram_init(void)
return 0;
}
-int timer_init(void)
-{
- return 0;
-}
-
/*
* Board specific reset that is system reset.
*/
@@ -43,6 +42,80 @@ void reset_cpu(ulong addr)
{
}
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+#ifdef CONFIG_SEMIHOSTING
+
+ /*
+ * We require that the board include file defines these env variables:
+ * - kernel_addr
+ * - initrd_addr
+ * - fdt_addr
+ *
+ * For the "fdt chosen" startup macro, this code will then define:
+ * - initrd_end (based on initrd_base 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_addr_str = getenv("kernel_addr");
+ char *initrd_addr_str = getenv("initrd_addr");
+ char *fdt_addr_str = getenv("fdt_addr");
+ char initrd_end_str[64];
+
+ /* Actual addresses converted from env variables */
+ void *kernel_addr;
+ void *initrd_addr;
+ void *fdt_addr;
+
+ /* Actual initrd base and size */
+ unsigned long initrd_base;
+ unsigned long initrd_size;
+
+ /* Make sure the environment variables needed are set */
+ if (!(kernel_addr_str && initrd_addr_str && fdt_addr_str)) {
+ printf
+ ("%s: Please define kernel_addr/initrd_addr/fdt_addr\n",
+ __func__);
+ return -1;
+ }
+
+ /* Get exact initrd_size */
+ initrd_size = smh_len(CONFIG_RDNAME);
+ if (initrd_size == -1) {
+ printf("%s: Can't get file size for \'%s\'\n", __func__,
+ CONFIG_RDNAME);
+ return -1;
+ }
+
+ /* Set initrd_end */
+ initrd_base = simple_strtoul(initrd_addr_str, NULL, 16);
+ initrd_addr = (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 = (void *)simple_strtoul(fdt_addr_str, NULL, 16);
+ kernel_addr = (void *)simple_strtoul(kernel_addr_str, NULL, 16);
+
+ /* Assumes kernel is lower in memory than fdt */
+ smh_load(CONFIG_KNLNAME, kernel_addr, fdt_addr - kernel_addr, 1);
+
+ /* Load fdt to memory */
+ smh_load(CONFIG_FDTNAME, fdt_addr, 0x20000, 1);
+
+ /* Load initrd to memory */
+ smh_load(CONFIG_RDNAME, initrd_addr, 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 a32f46b..db3239f 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -44,6 +44,7 @@
###########################################################################################################
Active aarch64 armv8 - armltd vexpress64 vexpress_aemv8a vexpress_aemv8a:ARM64 David Feng <fenghua at phytium.com.cn>
+Active aarch64 armv8 - armltd vexpress64 vexpress_aemv8a_semi vexpress_aemv8a_semi:ARM64 Darwin Rambo <drambo at broadcom.com>
Active arc arc700 - synopsys <none> arcangel4 - Alexey Brodkin <abrodkin at synopsys.com>
Active arc arc700 - synopsys - axs101 - Alexey Brodkin <abrodkin at synopsys.com>
Active arc arc700 - synopsys <none> arcangel4-be - Alexey Brodkin <abrodkin at synopsys.com>
diff --git a/include/configs/vexpress_aemv8a_semi.h b/include/configs/vexpress_aemv8a_semi.h
new file mode 100644
index 0000000..e81cbc2
--- /dev/null
+++ b/include/configs/vexpress_aemv8a_semi.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2014 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VEXPRESS_AEMV8A_SEMI_H
+#define __VEXPRESS_AEMV8A_SEMI_H
+
+/* #define DEBUG */
+#define CONFIG_SEMIHOSTING
+#define CONFIG_BOARD_LATE_INIT
+#define CONFIG_KNLNAME "uImage"
+#define CONFIG_RDNAME "ramdisk.img"
+#define CONFIG_FDTNAME "devtree.dtb"
+
+#define CONFIG_REMAKE_ELF
+#define CONFIG_ARMV8_SWITCH_TO_EL1
+#define CONFIG_OF_LIBFDT
+#define CONFIG_SYS_NO_FLASH
+#define CONFIG_SUPPORT_RAW_INITRD
+
+/* Cache Definitions */
+#define CONFIG_SYS_DCACHE_OFF
+#define CONFIG_SYS_ICACHE_OFF
+
+/* Link Definitions */
+#define CONFIG_SYS_TEXT_BASE 0x88000000
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x03f00000)
+
+/* Flat Device Tree Definitions */
+#define CONFIG_OF_LIBFDT
+
+/* SMP Spin Table Definitions */
+#define CPU_RELEASE_ADDR (CONFIG_SYS_SDRAM_BASE + 0x03f00000)
+
+/* Generic Timer Definitions */
+#define COUNTER_FREQUENCY (0x1800000) /* 24MHz */
+
+/* Generic Interrupt Controller Definitions */
+#define GICD_BASE (0x2f000000)
+#define GICC_BASE (0x2c000000)
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 128 * 1024)
+
+/* PL011 Serial Configuration */
+#define CONFIG_PL011_SERIAL
+#define CONFIG_PL011_CLOCK (24000000)
+#define CONFIG_PL01x_PORTS {(void *)CONFIG_SYS_SERIAL0}
+#define CONFIG_CONS_INDEX 0
+#define CONFIG_BAUDRATE 115200
+#define CONFIG_SYS_SERIAL0 0x1c090000
+
+/* Command line configuration */
+#define CONFIG_MENU
+#define CONFIG_CMD_BDI
+#define CONFIG_CMD_CACHE
+#define CONFIG_CMD_ENV
+#define CONFIG_CMD_FLASH
+#define CONFIG_CMD_MEMORY
+#define CONFIG_CMD_SAVEENV
+#define CONFIG_CMD_RUN
+#define CONFIG_CMD_ECHO
+#define CONFIG_CMD_SOURCE
+#define CONFIG_CMD_FAT
+#define CONFIG_DOS_PARTITION
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_LOAD_ADDR (PHYS_SDRAM_1)
+
+/* Physical Memory Map */
+#define CONFIG_NR_DRAM_BANKS 1
+
+#define PHYS_SDRAM_1 0x80000000
+#define PHYS_SDRAM_1_SIZE 0x80000000
+
+#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
+
+/* Initial environment variables */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "kernel_addr=0x80000000\0" \
+ "initrd_addr=0x88000000\0" \
+ "fdt_addr=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; fdt resize; " \
+ "fdt chosen $initrd_addr $initrd_end; " \
+ "bootm $kernel_addr - $fdt_addr"
+
+#define CONFIG_BOOTDELAY 1
+
+/* Do not preserve environment */
+#define CONFIG_ENV_IS_NOWHERE 1
+#define CONFIG_ENV_SIZE 0x1000
+
+/* Monitor Command Prompt */
+#define CONFIG_SYS_CBSIZE 512 /* Console I/O Buffer Size */
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
+ sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMDLINE_EDITING 1
+#define CONFIG_SYS_MAXARGS 64 /* max command args */
+
+#endif /* __BCM_ARMV8_FVP_H */
--
1.7.9.5
More information about the U-Boot
mailing list