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 */
