diff mbox

arm: Add support for semihosting for armv8 fastmodel targets.

Message ID 1394640241-14707-1-git-send-email-drambo@broadcom.com
State New
Headers show

Commit Message

Darwin Rambo March 12, 2014, 4:04 p.m. UTC
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@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

Comments

Tom Rini March 12, 2014, 4:24 p.m. UTC | #1
On Wed, Mar 12, 2014 at 09:04:01AM -0700, Darwin Rambo wrote:

> 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@broadcom.com>

At the high-level, I'm fine with this.  But as an implementation detail
we need to either leverage vexpress_common.h or create a
vexpress_arm64_common.h or something.  There's a lot in common between
these two configs, and some further clean-up we need to do to the first
one anyhow.

Next:
> +#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];

First, we need to document this stuff in a README file as well.  Second,
I'd like to see kernel_addr_r / ramdisk_addr_r / fdt_addr_r used to
match-up with what Dennis Gilmore has been working on to get a common
env working.

[snip]
> +	/* 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);

Is there a reason we can't also get these from the environment?  Or a
limitation of (how we support) the simulator that we don't have
persistent r/w environment right now?

Thanks!
Darwin Rambo March 12, 2014, 4:41 p.m. UTC | #2
On 14-03-12 09:24 AM, Tom Rini wrote:
> On Wed, Mar 12, 2014 at 09:04:01AM -0700, Darwin Rambo wrote:
> 
>> 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@broadcom.com>
> 
> At the high-level, I'm fine with this.  But as an implementation detail
> we need to either leverage vexpress_common.h or create a
> vexpress_arm64_common.h or something.  There's a lot in common between
> these two configs, and some further clean-up we need to do to the first
> one anyhow.
Let me try to digest this to see what is truly common and get back to
you. Thanks.
> 
> Next:
>> +#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];
> 
> First, we need to document this stuff in a README file as well.  Second,
> I'd like to see kernel_addr_r / ramdisk_addr_r / fdt_addr_r used to
> match-up with what Dennis Gilmore has been working on to get a common
> env working.
Okay, thanks.

> 
> [snip]
>> +	/* 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);
> 
> Is there a reason we can't also get these from the environment?  Or a
> limitation of (how we support) the simulator that we don't have
> persistent r/w environment right now?
These names can also come from the environment, there's r/w capability
there, just no physical eMMC. Thanks.

> 
> Thanks!
>
Albert ARIBAUD March 12, 2014, 4:41 p.m. UTC | #3
Hi Darwin,

On Wed, 12 Mar 2014 09:04:01 -0700, Darwin Rambo <drambo@broadcom.com>
wrote:

> 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@broadcom.com>
> ---

If you're only adding semihosting to vexpress_aemv8a, not creating a
new board, then why add a new header file? Can you not just reuse
orextend the existing header file, and make the new entry in
boards.cfg define option CONFIG_SEMIHOSTING instead?  

> 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

> @@ -31,11 +35,6 @@ int dram_init(void)
>  	return 0;
>  }
>  
> -int timer_init(void)
> -{
> -	return 0;
> -}
> -

This removal does not seem to be described in the commit summary.

Amicalement,
Darwin Rambo March 12, 2014, 4:45 p.m. UTC | #4
On 14-03-12 09:41 AM, Albert ARIBAUD wrote:
> Hi Darwin,
> 
> On Wed, 12 Mar 2014 09:04:01 -0700, Darwin Rambo <drambo@broadcom.com>
> wrote:
> 
>> 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@broadcom.com>
>> ---
> 
> If you're only adding semihosting to vexpress_aemv8a, not creating a
> new board, then why add a new header file? Can you not just reuse
> orextend the existing header file, and make the new entry in
> boards.cfg define option CONFIG_SEMIHOSTING instead?  
Good idea, thanks. This meshes well with Tom's recent suggestions.

> 
>> 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
> 
>> @@ -31,11 +35,6 @@ int dram_init(void)
>>  	return 0;
>>  }
>>  
>> -int timer_init(void)
>> -{
>> -	return 0;
>> -}
>> -
> 
> This removal does not seem to be described in the commit summary.
Will fix. Thanks.

> 
> Amicalement,
>
Tom Rini March 12, 2014, 5:18 p.m. UTC | #5
On Wed, Mar 12, 2014 at 09:41:20AM -0700, Darwin Rambo wrote:
> 
> 
> On 14-03-12 09:24 AM, Tom Rini wrote:
> > On Wed, Mar 12, 2014 at 09:04:01AM -0700, Darwin Rambo wrote:
[snip]
> >> +	/* 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);
> > 
> > Is there a reason we can't also get these from the environment?  Or a
> > limitation of (how we support) the simulator that we don't have
> > persistent r/w environment right now?
> These names can also come from the environment, there's r/w capability
> there, just no physical eMMC. Thanks.

I need to play more with the foundation model then, I didn't think we
could talk with the "mmc" or anything on it.  As you've got it coded
now, you can't change what's loaded here :)  But if we can have a
file-backed storage used as the "disk" and keep env there, making this
load files named in the environment and then fw_getenv/setenv can change
the values from Linux too, if we don't boot into a full U-Boot at some
point.
Darwin Rambo March 12, 2014, 5:47 p.m. UTC | #6
On 14-03-12 10:18 AM, Tom Rini wrote:
> On Wed, Mar 12, 2014 at 09:41:20AM -0700, Darwin Rambo wrote:
>>
>>
>> On 14-03-12 09:24 AM, Tom Rini wrote:
>>> On Wed, Mar 12, 2014 at 09:04:01AM -0700, Darwin Rambo wrote:
> [snip]
>>>> +	/* 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);
>>>
>>> Is there a reason we can't also get these from the environment?  Or a
>>> limitation of (how we support) the simulator that we don't have
>>> persistent r/w environment right now?
>> These names can also come from the environment, there's r/w capability
>> there, just no physical eMMC. Thanks.
> 
> I need to play more with the foundation model then, I didn't think we
> could talk with the "mmc" or anything on it.  As you've got it coded
> now, you can't change what's loaded here :)  But if we can have a
> file-backed storage used as the "disk" and keep env there, making this
> load files named in the environment and then fw_getenv/setenv can change
> the values from Linux too, if we don't boot into a full U-Boot at some
> point.
Sorry Tom, what I really meant to say was that with fastmodel, you can
define environment variables at build and run time, but they can't be
saved or viewed as persistent for the next bootup. Semihosting is kind
of a way to get around this lack of persistence since you can load
different image files on different runs. You could even potentially load
an environment file to fake out the eMMC if warranted. By r/w
capability, I meant just for that one instance of execution of u-boot.
But you can potentially access real eMMC on palladium or FPGA for
example, and eMMC would then be persistent in that environment from run
to run. Thanks.
>
diff mbox

Patch

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@phytium.com.cn>
+Active  aarch64     armv8          -           armltd          vexpress64          vexpress_aemv8a_semi                 vexpress_aemv8a_semi:ARM64                                                                                                        Darwin Rambo <drambo@broadcom.com>
 Active  arc         arc700         -           synopsys        <none>              arcangel4                            -                                                                                                                                 Alexey Brodkin <abrodkin@synopsys.com>
 Active  arc         arc700         -           synopsys        -                   axs101                               -                                                                                                                                 Alexey Brodkin <abrodkin@synopsys.com>
 Active  arc         arc700         -           synopsys        <none>              arcangel4-be                         -                                                                                                                                 Alexey Brodkin <abrodkin@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 */