aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/arch/sandbox/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/arch/sandbox/cpu')
-rw-r--r--roms/u-boot/arch/sandbox/cpu/Makefile32
-rw-r--r--roms/u-boot/arch/sandbox/cpu/cache.c23
-rw-r--r--roms/u-boot/arch/sandbox/cpu/cpu.c343
-rw-r--r--roms/u-boot/arch/sandbox/cpu/eth-raw-os.c295
-rw-r--r--roms/u-boot/arch/sandbox/cpu/os.c956
-rw-r--r--roms/u-boot/arch/sandbox/cpu/sdl.c473
-rw-r--r--roms/u-boot/arch/sandbox/cpu/spl.c94
-rw-r--r--roms/u-boot/arch/sandbox/cpu/start.c511
-rw-r--r--roms/u-boot/arch/sandbox/cpu/state.c432
-rw-r--r--roms/u-boot/arch/sandbox/cpu/u-boot-spl.lds31
-rw-r--r--roms/u-boot/arch/sandbox/cpu/u-boot.lds58
11 files changed, 3248 insertions, 0 deletions
diff --git a/roms/u-boot/arch/sandbox/cpu/Makefile b/roms/u-boot/arch/sandbox/cpu/Makefile
new file mode 100644
index 000000000..de7fe7f39
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/Makefile
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+obj-y := cache.o cpu.o state.o
+extra-y := start.o os.o
+extra-$(CONFIG_SANDBOX_SDL) += sdl.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
+obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o
+
+# os.c is build in the system environment, so needs standard includes
+# CFLAGS_REMOVE_os.o cannot be used to drop header include path
+quiet_cmd_cc_os.o = CC $(quiet_modtag) $@
+cmd_cc_os.o = $(CC) $(filter-out -nostdinc, \
+ $(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $<
+
+$(obj)/os.o: $(src)/os.c FORCE
+ $(call if_changed_dep,cc_os.o)
+$(obj)/sdl.o: $(src)/sdl.c FORCE
+ $(call if_changed_dep,cc_os.o)
+
+# eth-raw-os.c is built in the system env, so needs standard includes
+# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path
+quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag) $@
+cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \
+ $(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $<
+
+$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE
+ $(call if_changed_dep,cc_eth-raw-os.o)
diff --git a/roms/u-boot/arch/sandbox/cpu/cache.c b/roms/u-boot/arch/sandbox/cpu/cache.c
new file mode 100644
index 000000000..46c62c0b4
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/cache.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <asm/state.h>
+
+void flush_cache(unsigned long addr, unsigned long size)
+{
+ /* Clang uses (char *) parameters, GCC (void *) */
+ __builtin___clear_cache((void *)addr, (void *)(addr + size));
+}
+
+void invalidate_icache_all(void)
+{
+ struct sandbox_state *state = state_get_current();
+
+ /* Clang uses (char *) parameters, GCC (void *) */
+ __builtin___clear_cache((void *)state->ram_buf,
+ (void *)(state->ram_buf + state->ram_size));
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/cpu.c b/roms/u-boot/arch/sandbox/cpu/cpu.c
new file mode 100644
index 000000000..48636ab63
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/cpu.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+#include <common.h>
+#include <bootstage.h>
+#include <cpu_func.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/delay.h>
+#include <linux/libfdt.h>
+#include <os.h>
+#include <asm/io.h>
+#include <asm/malloc.h>
+#include <asm/setjmp.h>
+#include <asm/state.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Enable access to PCI memory with map_sysmem() */
+static bool enable_pci_map;
+
+#ifdef CONFIG_PCI
+/* Last device that was mapped into memory, and length of mapping */
+static struct udevice *map_dev;
+unsigned long map_len;
+#endif
+
+void sandbox_exit(void)
+{
+ /* Do this here while it still has an effect */
+ os_fd_restore();
+
+ if (state_uninit())
+ os_exit(2);
+
+ /* This is considered normal termination for now */
+ os_exit(0);
+}
+
+/* delay x useconds */
+void __udelay(unsigned long usec)
+{
+ struct sandbox_state *state = state_get_current();
+
+ if (!state->skip_delays)
+ os_usleep(usec);
+}
+
+int cleanup_before_linux(void)
+{
+ return 0;
+}
+
+int cleanup_before_linux_select(int flags)
+{
+ return 0;
+}
+
+/**
+ * is_in_sandbox_mem() - Checks if a pointer is within sandbox's emulated DRAM
+ *
+ * This provides a way to check if a pointer is owned by sandbox (and is within
+ * its RAM) or not. Sometimes pointers come from a test which conceptually runs
+ * output sandbox, potentially with direct access to the C-library malloc()
+ * function, or the sandbox stack (which is not actually within the emulated
+ * DRAM.
+ *
+ * Such pointers obviously cannot be mapped into sandbox's DRAM, so we must
+ * detect them an process them separately, by recording a mapping to a tag,
+ * which we can use to map back to the pointer later.
+ *
+ * @ptr: Pointer to check
+ * @return true if this is within sandbox emulated DRAM, false if not
+ */
+static bool is_in_sandbox_mem(const void *ptr)
+{
+ return (const uint8_t *)ptr >= gd->arch.ram_buf &&
+ (const uint8_t *)ptr < gd->arch.ram_buf + gd->ram_size;
+}
+
+/**
+ * phys_to_virt() - Converts a sandbox RAM address to a pointer
+ *
+ * Sandbox uses U-Boot addresses from 0 to the size of DRAM. These index into
+ * the emulated DRAM buffer used by sandbox. This function converts such an
+ * address to a pointer into this buffer, which can be used to access the
+ * memory.
+ *
+ * If the address is outside this range, it is assumed to be a tag
+ */
+void *phys_to_virt(phys_addr_t paddr)
+{
+ struct sandbox_mapmem_entry *mentry;
+ struct sandbox_state *state;
+
+ /* If the address is within emulated DRAM, calculate the value */
+ if (paddr < gd->ram_size)
+ return (void *)(gd->arch.ram_buf + paddr);
+
+ /*
+ * Otherwise search out list of tags for the correct pointer previously
+ * created by map_to_sysmem()
+ */
+ state = state_get_current();
+ list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
+ if (mentry->tag == paddr) {
+ debug("%s: Used map from %lx to %p\n", __func__,
+ (ulong)paddr, mentry->ptr);
+ return mentry->ptr;
+ }
+ }
+
+ printf("%s: Cannot map sandbox address %lx (SDRAM from 0 to %lx)\n",
+ __func__, (ulong)paddr, (ulong)gd->ram_size);
+ os_abort();
+
+ /* Not reached */
+ return NULL;
+}
+
+struct sandbox_mapmem_entry *find_tag(const void *ptr)
+{
+ struct sandbox_mapmem_entry *mentry;
+ struct sandbox_state *state = state_get_current();
+
+ list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
+ if (mentry->ptr == ptr) {
+ debug("%s: Used map from %p to %lx\n", __func__, ptr,
+ mentry->tag);
+ return mentry;
+ }
+ }
+ return NULL;
+}
+
+phys_addr_t virt_to_phys(void *ptr)
+{
+ struct sandbox_mapmem_entry *mentry;
+
+ /*
+ * If it is in emulated RAM, don't bother looking for a tag. Just
+ * calculate the pointer using the provides offset into the RAM buffer.
+ */
+ if (is_in_sandbox_mem(ptr))
+ return (phys_addr_t)((uint8_t *)ptr - gd->arch.ram_buf);
+
+ mentry = find_tag(ptr);
+ if (!mentry) {
+ /* Abort so that gdb can be used here */
+ printf("%s: Cannot map sandbox address %p (SDRAM from 0 to %lx)\n",
+ __func__, ptr, (ulong)gd->ram_size);
+ os_abort();
+ }
+ debug("%s: Used map from %p to %lx\n", __func__, ptr, mentry->tag);
+
+ return mentry->tag;
+}
+
+void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SPL_BUILD)
+ unsigned long plen = len;
+ void *ptr;
+
+ map_dev = NULL;
+ if (enable_pci_map && !pci_map_physmem(paddr, &len, &map_dev, &ptr)) {
+ if (plen != len) {
+ printf("%s: Warning: partial map at %x, wanted %lx, got %lx\n",
+ __func__, (uint)paddr, len, plen);
+ }
+ map_len = len;
+ return ptr;
+ }
+#endif
+
+ return phys_to_virt(paddr);
+}
+
+void unmap_physmem(const void *ptr, unsigned long flags)
+{
+#ifdef CONFIG_PCI
+ if (map_dev) {
+ pci_unmap_physmem(ptr, map_len, map_dev);
+ map_dev = NULL;
+ }
+#endif
+}
+
+phys_addr_t map_to_sysmem(const void *ptr)
+{
+ struct sandbox_mapmem_entry *mentry;
+
+ /*
+ * If it is in emulated RAM, don't bother creating a tag. Just return
+ * the offset into the RAM buffer.
+ */
+ if (is_in_sandbox_mem(ptr))
+ return (u8 *)ptr - gd->arch.ram_buf;
+
+ /*
+ * See if there is an existing tag with this pointer. If not, set up a
+ * new one.
+ */
+ mentry = find_tag(ptr);
+ if (!mentry) {
+ struct sandbox_state *state = state_get_current();
+
+ mentry = malloc(sizeof(*mentry));
+ if (!mentry) {
+ printf("%s: Error: Out of memory\n", __func__);
+ os_exit(ENOMEM);
+ }
+ mentry->tag = state->next_tag++;
+ mentry->ptr = (void *)ptr;
+ list_add_tail(&mentry->sibling_node, &state->mapmem_head);
+ debug("%s: Added map from %p to %lx\n", __func__, ptr,
+ (ulong)mentry->tag);
+ }
+
+ /*
+ * Return the tag as the address to use. A later call to map_sysmem()
+ * will return ptr
+ */
+ return mentry->tag;
+}
+
+unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size)
+{
+ struct sandbox_state *state = state_get_current();
+
+ if (!state->allow_memio)
+ return 0;
+
+ switch (size) {
+ case SB_SIZE_8:
+ return *(u8 *)addr;
+ case SB_SIZE_16:
+ return *(u16 *)addr;
+ case SB_SIZE_32:
+ return *(u32 *)addr;
+ case SB_SIZE_64:
+ return *(u64 *)addr;
+ }
+
+ return 0;
+}
+
+void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size)
+{
+ struct sandbox_state *state = state_get_current();
+
+ if (!state->allow_memio)
+ return;
+
+ switch (size) {
+ case SB_SIZE_8:
+ *(u8 *)addr = val;
+ break;
+ case SB_SIZE_16:
+ *(u16 *)addr = val;
+ break;
+ case SB_SIZE_32:
+ *(u32 *)addr = val;
+ break;
+ case SB_SIZE_64:
+ *(u64 *)addr = val;
+ break;
+ }
+}
+
+void sandbox_set_enable_memio(bool enable)
+{
+ struct sandbox_state *state = state_get_current();
+
+ state->allow_memio = enable;
+}
+
+void sandbox_set_enable_pci_map(int enable)
+{
+ enable_pci_map = enable;
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+int sandbox_read_fdt_from_file(void)
+{
+ struct sandbox_state *state = state_get_current();
+ const char *fname = state->fdt_fname;
+ void *blob;
+ loff_t size;
+ int err;
+ int fd;
+
+ blob = map_sysmem(CONFIG_SYS_FDT_LOAD_ADDR, 0);
+ if (!state->fdt_fname) {
+ err = fdt_create_empty_tree(blob, 256);
+ if (!err)
+ goto done;
+ printf("Unable to create empty FDT: %s\n", fdt_strerror(err));
+ return -EINVAL;
+ }
+
+ err = os_get_filesize(fname, &size);
+ if (err < 0) {
+ printf("Failed to file FDT file '%s'\n", fname);
+ return err;
+ }
+ fd = os_open(fname, OS_O_RDONLY);
+ if (fd < 0) {
+ printf("Failed to open FDT file '%s'\n", fname);
+ return -EACCES;
+ }
+ if (os_read(fd, blob, size) != size) {
+ os_close(fd);
+ return -EIO;
+ }
+ os_close(fd);
+
+done:
+ gd->fdt_blob = blob;
+
+ return 0;
+}
+
+ulong timer_get_boot_us(void)
+{
+ static uint64_t base_count;
+ uint64_t count = os_get_nsec();
+
+ if (!base_count)
+ base_count = count;
+
+ return (count - base_count) / 1000;
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/eth-raw-os.c b/roms/u-boot/arch/sandbox/cpu/eth-raw-os.c
new file mode 100644
index 000000000..6a8d80975
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/eth-raw-os.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015-2018 National Instruments
+ * Copyright (c) 2015-2018 Joe Hershberger <joe.hershberger@ni.com>
+ */
+
+#include <asm/eth-raw-os.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+#include <os.h>
+
+struct sandbox_eth_raw_if_nameindex *sandbox_eth_raw_if_nameindex(void)
+{
+ return (struct sandbox_eth_raw_if_nameindex *)if_nameindex();
+}
+
+void sandbox_eth_raw_if_freenameindex(struct sandbox_eth_raw_if_nameindex *ptr)
+{
+ if_freenameindex((struct if_nameindex *)ptr);
+}
+
+int sandbox_eth_raw_os_is_local(const char *ifname)
+{
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ struct ifreq ifr;
+ int ret = 0;
+
+ if (fd < 0)
+ return -errno;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ret = ioctl(fd, SIOCGIFFLAGS, &ifr);
+ if (ret < 0) {
+ ret = -errno;
+ goto out;
+ }
+ ret = !!(ifr.ifr_flags & IFF_LOOPBACK);
+out:
+ os_close(fd);
+ return ret;
+}
+
+int sandbox_eth_raw_os_idx_to_name(struct eth_sandbox_raw_priv *priv)
+{
+ if (!if_indextoname(priv->host_ifindex, priv->host_ifname))
+ return -errno;
+ return 0;
+}
+
+static int _raw_packet_start(struct eth_sandbox_raw_priv *priv,
+ unsigned char *ethmac)
+{
+ struct sockaddr_ll *device;
+ struct packet_mreq mr;
+ int ret;
+ int flags;
+
+ /* Prepare device struct */
+ priv->local_bind_sd = -1;
+ priv->device = malloc(sizeof(struct sockaddr_ll));
+ if (priv->device == NULL)
+ return -ENOMEM;
+ device = priv->device;
+ memset(device, 0, sizeof(struct sockaddr_ll));
+ device->sll_ifindex = if_nametoindex(priv->host_ifname);
+ priv->host_ifindex = device->sll_ifindex;
+ device->sll_family = AF_PACKET;
+ memcpy(device->sll_addr, ethmac, 6);
+ device->sll_halen = htons(6);
+
+ /* Open socket */
+ priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (priv->sd < 0) {
+ printf("Failed to open socket: %d %s\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+ /* Bind to the specified interface */
+ ret = setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE,
+ priv->host_ifname, strlen(priv->host_ifname) + 1);
+ if (ret < 0) {
+ printf("Failed to bind to '%s': %d %s\n", priv->host_ifname,
+ errno, strerror(errno));
+ return -errno;
+ }
+
+ /* Make the socket non-blocking */
+ flags = fcntl(priv->sd, F_GETFL, 0);
+ fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK);
+
+ /* Enable promiscuous mode to receive responses meant for us */
+ mr.mr_ifindex = device->sll_ifindex;
+ mr.mr_type = PACKET_MR_PROMISC;
+ ret = setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
+ &mr, sizeof(mr));
+ if (ret < 0) {
+ struct ifreq ifr;
+
+ printf("Failed to set promiscuous mode: %d %s\n"
+ "Falling back to the old \"flags\" way...\n",
+ errno, strerror(errno));
+ if (strlen(priv->host_ifname) >= IFNAMSIZ) {
+ printf("Interface name %s is too long.\n",
+ priv->host_ifname);
+ return -EINVAL;
+ }
+ strncpy(ifr.ifr_name, priv->host_ifname, IFNAMSIZ);
+ if (ioctl(priv->sd, SIOCGIFFLAGS, &ifr) < 0) {
+ printf("Failed to read flags: %d %s\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+ ifr.ifr_flags |= IFF_PROMISC;
+ if (ioctl(priv->sd, SIOCSIFFLAGS, &ifr) < 0) {
+ printf("Failed to write flags: %d %s\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+static int _local_inet_start(struct eth_sandbox_raw_priv *priv)
+{
+ struct sockaddr_in *device;
+ int ret;
+ int flags;
+ int one = 1;
+
+ /* Prepare device struct */
+ priv->local_bind_sd = -1;
+ priv->local_bind_udp_port = 0;
+ priv->device = malloc(sizeof(struct sockaddr_in));
+ if (priv->device == NULL)
+ return -ENOMEM;
+ device = priv->device;
+ memset(device, 0, sizeof(struct sockaddr_in));
+ device->sin_family = AF_INET;
+ device->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ /**
+ * Open socket
+ * Since we specify UDP here, any incoming ICMP packets will
+ * not be received, so things like ping will not work on this
+ * localhost interface.
+ */
+ priv->sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
+ if (priv->sd < 0) {
+ printf("Failed to open socket: %d %s\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+
+ /* Make the socket non-blocking */
+ flags = fcntl(priv->sd, F_GETFL, 0);
+ fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK);
+
+ /* Include the UDP/IP headers on send and receive */
+ ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one,
+ sizeof(one));
+ if (ret < 0) {
+ printf("Failed to set header include option: %d %s\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+ return 0;
+}
+
+int sandbox_eth_raw_os_start(struct eth_sandbox_raw_priv *priv,
+ unsigned char *ethmac)
+{
+ if (priv->local)
+ return _local_inet_start(priv);
+ else
+ return _raw_packet_start(priv, ethmac);
+}
+
+int sandbox_eth_raw_os_send(void *packet, int length,
+ struct eth_sandbox_raw_priv *priv)
+{
+ int retval;
+ struct udphdr *udph = packet + sizeof(struct iphdr);
+
+ if (priv->sd < 0 || !priv->device)
+ return -EINVAL;
+
+ /*
+ * This block of code came about when testing tftp on the localhost
+ * interface. When using the RAW AF_INET API, the network stack is still
+ * in play responding to incoming traffic based on open "ports". Since
+ * it is raw (at the IP layer, no Ethernet) the network stack tells the
+ * TFTP server that the port it responded to is closed. This causes the
+ * TFTP transfer to be aborted. This block of code inspects the outgoing
+ * packet as formulated by the u-boot network stack to determine the
+ * source port (that the TFTP server will send packets back to) and
+ * opens a typical UDP socket on that port, thus preventing the network
+ * stack from sending that ICMP message claiming that the port has no
+ * bound socket.
+ */
+ if (priv->local && (priv->local_bind_sd == -1 ||
+ priv->local_bind_udp_port != udph->source)) {
+ struct iphdr *iph = packet;
+ struct sockaddr_in addr;
+
+ if (priv->local_bind_sd != -1)
+ os_close(priv->local_bind_sd);
+
+ /* A normal UDP socket is required to bind */
+ priv->local_bind_sd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (priv->local_bind_sd < 0) {
+ printf("Failed to open bind sd: %d %s\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+ priv->local_bind_udp_port = udph->source;
+
+ /**
+ * Bind the UDP port that we intend to use as our source port
+ * so that the kernel will not send an ICMP port unreachable
+ * message to the server
+ */
+ addr.sin_family = AF_INET;
+ addr.sin_port = udph->source;
+ addr.sin_addr.s_addr = iph->saddr;
+ retval = bind(priv->local_bind_sd, (struct sockaddr *)&addr,
+ sizeof(addr));
+ if (retval < 0)
+ printf("Failed to bind: %d %s\n", errno,
+ strerror(errno));
+ }
+
+ retval = sendto(priv->sd, packet, length, 0,
+ (struct sockaddr *)priv->device,
+ sizeof(struct sockaddr_ll));
+ if (retval < 0) {
+ printf("Failed to send packet: %d %s\n", errno,
+ strerror(errno));
+ return -errno;
+ }
+ return retval;
+}
+
+int sandbox_eth_raw_os_recv(void *packet, int *length,
+ const struct eth_sandbox_raw_priv *priv)
+{
+ int retval;
+ int saddr_size;
+
+ if (priv->sd < 0 || !priv->device)
+ return -EINVAL;
+ saddr_size = sizeof(struct sockaddr);
+ retval = recvfrom(priv->sd, packet, 1536, 0,
+ (struct sockaddr *)priv->device,
+ (socklen_t *)&saddr_size);
+ *length = 0;
+ if (retval >= 0) {
+ *length = retval;
+ return 0;
+ }
+ /* The socket is non-blocking, so expect EAGAIN when there is no data */
+ if (errno == EAGAIN)
+ return 0;
+ return -errno;
+}
+
+void sandbox_eth_raw_os_stop(struct eth_sandbox_raw_priv *priv)
+{
+ free(priv->device);
+ priv->device = NULL;
+ os_close(priv->sd);
+ priv->sd = -1;
+ if (priv->local) {
+ if (priv->local_bind_sd != -1)
+ os_close(priv->local_bind_sd);
+ priv->local_bind_sd = -1;
+ priv->local_bind_udp_port = 0;
+ }
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/os.c b/roms/u-boot/arch/sandbox/cpu/os.c
new file mode 100644
index 000000000..0d21827e1
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/os.c
@@ -0,0 +1,956 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <ucontext.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <linux/compiler_attributes.h>
+#include <linux/types.h>
+
+#include <asm/getopt.h>
+#include <asm/sections.h>
+#include <asm/state.h>
+#include <os.h>
+#include <rtc_def.h>
+
+/* Environment variable for time offset */
+#define ENV_TIME_OFFSET "UBOOT_SB_TIME_OFFSET"
+
+/* Operating System Interface */
+
+struct os_mem_hdr {
+ size_t length; /* number of bytes in the block */
+};
+
+ssize_t os_read(int fd, void *buf, size_t count)
+{
+ return read(fd, buf, count);
+}
+
+ssize_t os_write(int fd, const void *buf, size_t count)
+{
+ return write(fd, buf, count);
+}
+
+off_t os_lseek(int fd, off_t offset, int whence)
+{
+ if (whence == OS_SEEK_SET)
+ whence = SEEK_SET;
+ else if (whence == OS_SEEK_CUR)
+ whence = SEEK_CUR;
+ else if (whence == OS_SEEK_END)
+ whence = SEEK_END;
+ else
+ os_exit(1);
+ return lseek(fd, offset, whence);
+}
+
+int os_open(const char *pathname, int os_flags)
+{
+ int flags;
+
+ switch (os_flags & OS_O_MASK) {
+ case OS_O_RDONLY:
+ default:
+ flags = O_RDONLY;
+ break;
+
+ case OS_O_WRONLY:
+ flags = O_WRONLY;
+ break;
+
+ case OS_O_RDWR:
+ flags = O_RDWR;
+ break;
+ }
+
+ if (os_flags & OS_O_CREAT)
+ flags |= O_CREAT;
+ if (os_flags & OS_O_TRUNC)
+ flags |= O_TRUNC;
+ /*
+ * During a cold reset execv() is used to relaunch the U-Boot binary.
+ * We must ensure that all files are closed in this case.
+ */
+ flags |= O_CLOEXEC;
+
+ return open(pathname, flags, 0777);
+}
+
+int os_close(int fd)
+{
+ /* Do not close the console input */
+ if (fd)
+ return close(fd);
+ return -1;
+}
+
+int os_unlink(const char *pathname)
+{
+ return unlink(pathname);
+}
+
+void os_exit(int exit_code)
+{
+ exit(exit_code);
+}
+
+int os_write_file(const char *fname, const void *buf, int size)
+{
+ int fd;
+
+ fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT | OS_O_TRUNC);
+ if (fd < 0) {
+ printf("Cannot open file '%s'\n", fname);
+ return -EIO;
+ }
+ if (os_write(fd, buf, size) != size) {
+ printf("Cannot write to file '%s'\n", fname);
+ os_close(fd);
+ return -EIO;
+ }
+ os_close(fd);
+
+ return 0;
+}
+
+int os_read_file(const char *fname, void **bufp, int *sizep)
+{
+ off_t size;
+ int ret = -EIO;
+ int fd;
+
+ fd = os_open(fname, OS_O_RDONLY);
+ if (fd < 0) {
+ printf("Cannot open file '%s'\n", fname);
+ goto err;
+ }
+ size = os_lseek(fd, 0, OS_SEEK_END);
+ if (size < 0) {
+ printf("Cannot seek to end of file '%s'\n", fname);
+ goto err;
+ }
+ if (os_lseek(fd, 0, OS_SEEK_SET) < 0) {
+ printf("Cannot seek to start of file '%s'\n", fname);
+ goto err;
+ }
+ *bufp = os_malloc(size);
+ if (!*bufp) {
+ printf("Not enough memory to read file '%s'\n", fname);
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (os_read(fd, *bufp, size) != size) {
+ printf("Cannot read from file '%s'\n", fname);
+ goto err;
+ }
+ os_close(fd);
+ *sizep = size;
+
+ return 0;
+err:
+ os_close(fd);
+ return ret;
+}
+
+/* Restore tty state when we exit */
+static struct termios orig_term;
+static bool term_setup;
+static bool term_nonblock;
+
+void os_fd_restore(void)
+{
+ if (term_setup) {
+ int flags;
+
+ tcsetattr(0, TCSANOW, &orig_term);
+ if (term_nonblock) {
+ flags = fcntl(0, F_GETFL, 0);
+ fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
+ }
+ term_setup = false;
+ }
+}
+
+static void os_sigint_handler(int sig)
+{
+ os_fd_restore();
+ signal(SIGINT, SIG_DFL);
+ raise(SIGINT);
+}
+
+static void os_signal_handler(int sig, siginfo_t *info, void *con)
+{
+ ucontext_t __maybe_unused *context = con;
+ unsigned long pc;
+
+#if defined(__x86_64__)
+ pc = context->uc_mcontext.gregs[REG_RIP];
+#elif defined(__aarch64__)
+ pc = context->uc_mcontext.pc;
+#elif defined(__riscv)
+ pc = context->uc_mcontext.__gregs[REG_PC];
+#else
+ const char msg[] =
+ "\nUnsupported architecture, cannot read program counter\n";
+
+ os_write(1, msg, sizeof(msg));
+ pc = 0;
+#endif
+
+ os_signal_action(sig, pc);
+}
+
+int os_setup_signal_handlers(void)
+{
+ struct sigaction act;
+
+ act.sa_sigaction = os_signal_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO | SA_NODEFER;
+ if (sigaction(SIGILL, &act, NULL) ||
+ sigaction(SIGBUS, &act, NULL) ||
+ sigaction(SIGSEGV, &act, NULL))
+ return -1;
+ return 0;
+}
+
+/* Put tty into raw mode so <tab> and <ctrl+c> work */
+void os_tty_raw(int fd, bool allow_sigs)
+{
+ struct termios term;
+ int flags;
+
+ if (term_setup)
+ return;
+
+ /* If not a tty, don't complain */
+ if (tcgetattr(fd, &orig_term))
+ return;
+
+ term = orig_term;
+ term.c_iflag = IGNBRK | IGNPAR;
+ term.c_oflag = OPOST | ONLCR;
+ term.c_cflag = CS8 | CREAD | CLOCAL;
+ term.c_lflag = allow_sigs ? ISIG : 0;
+ if (tcsetattr(fd, TCSANOW, &term))
+ return;
+
+ flags = fcntl(fd, F_GETFL, 0);
+ if (!(flags & O_NONBLOCK)) {
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ return;
+ term_nonblock = true;
+ }
+
+ term_setup = true;
+ atexit(os_fd_restore);
+ signal(SIGINT, os_sigint_handler);
+}
+
+/*
+ * Provide our own malloc so we don't use space in the sandbox ram_buf for
+ * allocations that are internal to sandbox, or need to be done before U-Boot's
+ * malloc() is ready.
+ */
+void *os_malloc(size_t length)
+{
+ int page_size = getpagesize();
+ struct os_mem_hdr *hdr;
+
+ if (!length)
+ return NULL;
+ /*
+ * Use an address that is hopefully available to us so that pointers
+ * to this memory are fairly obvious. If we end up with a different
+ * address, that's fine too.
+ */
+ hdr = mmap((void *)0x10000000, length + page_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (hdr == MAP_FAILED)
+ return NULL;
+ hdr->length = length;
+
+ return (void *)hdr + page_size;
+}
+
+void os_free(void *ptr)
+{
+ int page_size = getpagesize();
+ struct os_mem_hdr *hdr;
+
+ if (ptr) {
+ hdr = ptr - page_size;
+ munmap(hdr, hdr->length + page_size);
+ }
+}
+
+/* These macros are from kernel.h but not accessible in this file */
+#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a) - 1)
+#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+/*
+ * Provide our own malloc so we don't use space in the sandbox ram_buf for
+ * allocations that are internal to sandbox, or need to be done before U-Boot's
+ * malloc() is ready.
+ */
+void *os_realloc(void *ptr, size_t length)
+{
+ int page_size = getpagesize();
+ struct os_mem_hdr *hdr;
+ void *new_ptr;
+
+ /* Reallocating a NULL pointer is just an alloc */
+ if (!ptr)
+ return os_malloc(length);
+
+ /* Changing a length to 0 is just a free */
+ if (length) {
+ os_free(ptr);
+ return NULL;
+ }
+
+ /*
+ * If the new size is the same number of pages as the old, nothing to
+ * do. There isn't much point in shrinking things
+ */
+ hdr = ptr - page_size;
+ if (ALIGN(length, page_size) <= ALIGN(hdr->length, page_size))
+ return ptr;
+
+ /* We have to grow it, so allocate something new */
+ new_ptr = os_malloc(length);
+ memcpy(new_ptr, ptr, hdr->length);
+ os_free(ptr);
+
+ return new_ptr;
+}
+
+void os_usleep(unsigned long usec)
+{
+ usleep(usec);
+}
+
+uint64_t __attribute__((no_instrument_function)) os_get_nsec(void)
+{
+#if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK)
+ struct timespec tp;
+ if (EINVAL == clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ tp.tv_sec = tv.tv_sec;
+ tp.tv_nsec = tv.tv_usec * 1000;
+ }
+ return tp.tv_sec * 1000000000ULL + tp.tv_nsec;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
+#endif
+}
+
+static char *short_opts;
+static struct option *long_opts;
+
+int os_parse_args(struct sandbox_state *state, int argc, char *argv[])
+{
+ struct sandbox_cmdline_option **sb_opt =
+ __u_boot_sandbox_option_start();
+ size_t num_options = __u_boot_sandbox_option_count();
+ size_t i;
+
+ int hidden_short_opt;
+ size_t si;
+
+ int c;
+
+ if (short_opts || long_opts)
+ return 1;
+
+ state->argc = argc;
+ state->argv = argv;
+
+ /* dynamically construct the arguments to the system getopt_long */
+ short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1);
+ long_opts = os_malloc(sizeof(*long_opts) * (num_options + 1));
+ if (!short_opts || !long_opts)
+ return 1;
+
+ /*
+ * getopt_long requires "val" to be unique (since that is what the
+ * func returns), so generate unique values automatically for flags
+ * that don't have a short option. pick 0x100 as that is above the
+ * single byte range (where ASCII/ISO-XXXX-X charsets live).
+ */
+ hidden_short_opt = 0x100;
+ si = 0;
+ for (i = 0; i < num_options; ++i) {
+ long_opts[i].name = sb_opt[i]->flag;
+ long_opts[i].has_arg = sb_opt[i]->has_arg ?
+ required_argument : no_argument;
+ long_opts[i].flag = NULL;
+
+ if (sb_opt[i]->flag_short) {
+ short_opts[si++] = long_opts[i].val = sb_opt[i]->flag_short;
+ if (long_opts[i].has_arg == required_argument)
+ short_opts[si++] = ':';
+ } else
+ long_opts[i].val = sb_opt[i]->flag_short = hidden_short_opt++;
+ }
+ short_opts[si] = '\0';
+
+ /* we need to handle output ourselves since u-boot provides printf */
+ opterr = 0;
+
+ memset(&long_opts[num_options], '\0', sizeof(*long_opts));
+ /*
+ * walk all of the options the user gave us on the command line,
+ * figure out what u-boot option structure they belong to (via
+ * the unique short val key), and call the appropriate callback.
+ */
+ while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
+ for (i = 0; i < num_options; ++i) {
+ if (sb_opt[i]->flag_short == c) {
+ if (sb_opt[i]->callback(state, optarg)) {
+ state->parse_err = sb_opt[i]->flag;
+ return 0;
+ }
+ break;
+ }
+ }
+ if (i == num_options) {
+ /*
+ * store the faulting flag for later display. we have to
+ * store the flag itself as the getopt parsing itself is
+ * tricky: need to handle the following flags (assume all
+ * of the below are unknown):
+ * -a optopt='a' optind=<next>
+ * -abbbb optopt='a' optind=<this>
+ * -aaaaa optopt='a' optind=<this>
+ * --a optopt=0 optind=<this>
+ * as you can see, it is impossible to determine the exact
+ * faulting flag without doing the parsing ourselves, so
+ * we just report the specific flag that failed.
+ */
+ if (optopt) {
+ static char parse_err[3] = { '-', 0, '\0', };
+ parse_err[1] = optopt;
+ state->parse_err = parse_err;
+ } else
+ state->parse_err = argv[optind - 1];
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void os_dirent_free(struct os_dirent_node *node)
+{
+ struct os_dirent_node *next;
+
+ while (node) {
+ next = node->next;
+ os_free(node);
+ node = next;
+ }
+}
+
+int os_dirent_ls(const char *dirname, struct os_dirent_node **headp)
+{
+ struct dirent *entry;
+ struct os_dirent_node *head, *node, *next;
+ struct stat buf;
+ DIR *dir;
+ int ret;
+ char *fname;
+ char *old_fname;
+ int len;
+ int dirlen;
+
+ *headp = NULL;
+ dir = opendir(dirname);
+ if (!dir)
+ return -1;
+
+ /* Create a buffer upfront, with typically sufficient size */
+ dirlen = strlen(dirname) + 2;
+ len = dirlen + 256;
+ fname = os_malloc(len);
+ if (!fname) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ for (node = head = NULL;; node = next) {
+ errno = 0;
+ entry = readdir(dir);
+ if (!entry) {
+ ret = errno;
+ break;
+ }
+ next = os_malloc(sizeof(*node) + strlen(entry->d_name) + 1);
+ if (!next) {
+ os_dirent_free(head);
+ ret = -ENOMEM;
+ goto done;
+ }
+ if (dirlen + strlen(entry->d_name) > len) {
+ len = dirlen + strlen(entry->d_name);
+ old_fname = fname;
+ fname = os_realloc(fname, len);
+ if (!fname) {
+ os_free(old_fname);
+ os_free(next);
+ os_dirent_free(head);
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+ next->next = NULL;
+ strcpy(next->name, entry->d_name);
+ switch (entry->d_type) {
+ case DT_REG:
+ next->type = OS_FILET_REG;
+ break;
+ case DT_DIR:
+ next->type = OS_FILET_DIR;
+ break;
+ case DT_LNK:
+ next->type = OS_FILET_LNK;
+ break;
+ default:
+ next->type = OS_FILET_UNKNOWN;
+ }
+ next->size = 0;
+ snprintf(fname, len, "%s/%s", dirname, next->name);
+ if (!stat(fname, &buf))
+ next->size = buf.st_size;
+ if (node)
+ node->next = next;
+ else
+ head = next;
+ }
+ *headp = head;
+
+done:
+ closedir(dir);
+ os_free(fname);
+ return ret;
+}
+
+const char *os_dirent_typename[OS_FILET_COUNT] = {
+ " ",
+ "SYM",
+ "DIR",
+ "???",
+};
+
+const char *os_dirent_get_typename(enum os_dirent_t type)
+{
+ if (type >= OS_FILET_REG && type < OS_FILET_COUNT)
+ return os_dirent_typename[type];
+
+ return os_dirent_typename[OS_FILET_UNKNOWN];
+}
+
+int os_get_filesize(const char *fname, loff_t *size)
+{
+ struct stat buf;
+ int ret;
+
+ ret = stat(fname, &buf);
+ if (ret)
+ return ret;
+ *size = buf.st_size;
+ return 0;
+}
+
+void os_putc(int ch)
+{
+ putchar(ch);
+}
+
+void os_puts(const char *str)
+{
+ while (*str)
+ os_putc(*str++);
+}
+
+int os_write_ram_buf(const char *fname)
+{
+ struct sandbox_state *state = state_get_current();
+ int fd, ret;
+
+ fd = open(fname, O_CREAT | O_WRONLY, 0777);
+ if (fd < 0)
+ return -ENOENT;
+ ret = write(fd, state->ram_buf, state->ram_size);
+ close(fd);
+ if (ret != state->ram_size)
+ return -EIO;
+
+ return 0;
+}
+
+int os_read_ram_buf(const char *fname)
+{
+ struct sandbox_state *state = state_get_current();
+ int fd, ret;
+ loff_t size;
+
+ ret = os_get_filesize(fname, &size);
+ if (ret < 0)
+ return ret;
+ if (size != state->ram_size)
+ return -ENOSPC;
+ fd = open(fname, O_RDONLY);
+ if (fd < 0)
+ return -ENOENT;
+
+ ret = read(fd, state->ram_buf, state->ram_size);
+ close(fd);
+ if (ret != state->ram_size)
+ return -EIO;
+
+ return 0;
+}
+
+static int make_exec(char *fname, const void *data, int size)
+{
+ int fd;
+
+ strcpy(fname, "/tmp/u-boot.jump.XXXXXX");
+ fd = mkstemp(fname);
+ if (fd < 0)
+ return -ENOENT;
+ if (write(fd, data, size) < 0)
+ return -EIO;
+ close(fd);
+ if (chmod(fname, 0777))
+ return -ENOEXEC;
+
+ return 0;
+}
+
+/**
+ * add_args() - Allocate a new argv with the given args
+ *
+ * This is used to create a new argv array with all the old arguments and some
+ * new ones that are passed in
+ *
+ * @argvp: Returns newly allocated args list
+ * @add_args: Arguments to add, each a string
+ * @count: Number of arguments in @add_args
+ * @return 0 if OK, -ENOMEM if out of memory
+ */
+static int add_args(char ***argvp, char *add_args[], int count)
+{
+ char **argv, **ap;
+ int argc;
+
+ for (argc = 0; (*argvp)[argc]; argc++)
+ ;
+
+ argv = os_malloc((argc + count + 1) * sizeof(char *));
+ if (!argv) {
+ printf("Out of memory for %d argv\n", count);
+ return -ENOMEM;
+ }
+ for (ap = *argvp, argc = 0; *ap; ap++) {
+ char *arg = *ap;
+
+ /* Drop args that we don't want to propagate */
+ if (*arg == '-' && strlen(arg) == 2) {
+ switch (arg[1]) {
+ case 'j':
+ case 'm':
+ ap++;
+ continue;
+ }
+ } else if (!strcmp(arg, "--rm_memory")) {
+ ap++;
+ continue;
+ }
+ argv[argc++] = arg;
+ }
+
+ memcpy(argv + argc, add_args, count * sizeof(char *));
+ argv[argc + count] = NULL;
+
+ *argvp = argv;
+ return 0;
+}
+
+/**
+ * os_jump_to_file() - Jump to a new program
+ *
+ * This saves the memory buffer, sets up arguments to the new process, then
+ * execs it.
+ *
+ * @fname: Filename to exec
+ * @return does not return on success, any return value is an error
+ */
+static int os_jump_to_file(const char *fname, bool delete_it)
+{
+ struct sandbox_state *state = state_get_current();
+ char mem_fname[30];
+ int fd, err;
+ char *extra_args[5];
+ char **argv = state->argv;
+ int argc;
+#ifdef DEBUG
+ int i;
+#endif
+
+ strcpy(mem_fname, "/tmp/u-boot.mem.XXXXXX");
+ fd = mkstemp(mem_fname);
+ if (fd < 0)
+ return -ENOENT;
+ close(fd);
+ err = os_write_ram_buf(mem_fname);
+ if (err)
+ return err;
+
+ os_fd_restore();
+
+ argc = 0;
+ if (delete_it) {
+ extra_args[argc++] = "-j";
+ extra_args[argc++] = (char *)fname;
+ }
+ extra_args[argc++] = "-m";
+ extra_args[argc++] = mem_fname;
+ if (state->ram_buf_rm)
+ extra_args[argc++] = "--rm_memory";
+ err = add_args(&argv, extra_args, argc);
+ if (err)
+ return err;
+ argv[0] = (char *)fname;
+
+#ifdef DEBUG
+ for (i = 0; argv[i]; i++)
+ printf("%d %s\n", i, argv[i]);
+#endif
+
+ if (state_uninit())
+ os_exit(2);
+
+ err = execv(fname, argv);
+ os_free(argv);
+ if (err) {
+ perror("Unable to run image");
+ printf("Image filename '%s'\n", fname);
+ return err;
+ }
+
+ if (delete_it)
+ return unlink(fname);
+
+ return -EFAULT;
+}
+
+int os_jump_to_image(const void *dest, int size)
+{
+ char fname[30];
+ int err;
+
+ err = make_exec(fname, dest, size);
+ if (err)
+ return err;
+
+ return os_jump_to_file(fname, true);
+}
+
+int os_find_u_boot(char *fname, int maxlen, bool use_img)
+{
+ struct sandbox_state *state = state_get_current();
+ const char *progname = state->argv[0];
+ int len = strlen(progname);
+ const char *suffix;
+ char *p;
+ int fd;
+
+ if (len >= maxlen || len < 4)
+ return -ENOSPC;
+
+ strcpy(fname, progname);
+ suffix = fname + len - 4;
+
+ /* If we are TPL, boot to SPL */
+ if (!strcmp(suffix, "-tpl")) {
+ fname[len - 3] = 's';
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+
+ /* Look for 'u-boot-spl' in the spl/ directory */
+ p = strstr(fname, "/spl/");
+ if (p) {
+ p[1] = 's';
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ }
+ return -ENOENT;
+ }
+
+ /* Look for 'u-boot' in the same directory as 'u-boot-spl' */
+ if (!strcmp(suffix, "-spl")) {
+ fname[len - 4] = '\0';
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ }
+
+ /* Look for 'u-boot' in the parent directory of spl/ */
+ p = strstr(fname, "spl/");
+ if (p) {
+ /* Remove the "spl" characters */
+ memmove(p, p + 4, strlen(p + 4) + 1);
+ if (use_img)
+ strcat(p, ".img");
+ fd = os_open(fname, O_RDONLY);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int os_spl_to_uboot(const char *fname)
+{
+ struct sandbox_state *state = state_get_current();
+
+ /* U-Boot will delete ram buffer after read: "--rm_memory"*/
+ state->ram_buf_rm = true;
+
+ return os_jump_to_file(fname, false);
+}
+
+long os_get_time_offset(void)
+{
+ const char *offset;
+
+ offset = getenv(ENV_TIME_OFFSET);
+ if (offset)
+ return strtol(offset, NULL, 0);
+ return 0;
+}
+
+void os_set_time_offset(long offset)
+{
+ char buf[21];
+ int ret;
+
+ snprintf(buf, sizeof(buf), "%ld", offset);
+ ret = setenv(ENV_TIME_OFFSET, buf, true);
+ if (ret)
+ printf("Could not set environment variable %s\n",
+ ENV_TIME_OFFSET);
+}
+
+void os_localtime(struct rtc_time *rt)
+{
+ time_t t = time(NULL);
+ struct tm *tm;
+
+ tm = localtime(&t);
+ rt->tm_sec = tm->tm_sec;
+ rt->tm_min = tm->tm_min;
+ rt->tm_hour = tm->tm_hour;
+ rt->tm_mday = tm->tm_mday;
+ rt->tm_mon = tm->tm_mon + 1;
+ rt->tm_year = tm->tm_year + 1900;
+ rt->tm_wday = tm->tm_wday;
+ rt->tm_yday = tm->tm_yday;
+ rt->tm_isdst = tm->tm_isdst;
+}
+
+void os_abort(void)
+{
+ abort();
+}
+
+int os_mprotect_allow(void *start, size_t len)
+{
+ int page_size = getpagesize();
+
+ /* Move start to the start of a page, len to the end */
+ start = (void *)(((ulong)start) & ~(page_size - 1));
+ len = (len + page_size * 2) & ~(page_size - 1);
+
+ return mprotect(start, len, PROT_READ | PROT_WRITE);
+}
+
+void *os_find_text_base(void)
+{
+ char line[500];
+ void *base = NULL;
+ int len;
+ int fd;
+
+ /*
+ * This code assumes that the first line of /proc/self/maps holds
+ * information about the text, for example:
+ *
+ * 5622d9907000-5622d9a55000 r-xp 00000000 08:01 15067168 u-boot
+ *
+ * The first hex value is assumed to be the address.
+ *
+ * This is tested in Linux 4.15.
+ */
+ fd = open("/proc/self/maps", O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ len = read(fd, line, sizeof(line));
+ if (len > 0) {
+ char *end = memchr(line, '-', len);
+
+ if (end) {
+ uintptr_t addr;
+
+ *end = '\0';
+ if (sscanf(line, "%zx", &addr) == 1)
+ base = (void *)addr;
+ }
+ }
+ close(fd);
+
+ return base;
+}
+
+void os_relaunch(char *argv[])
+{
+ execv(argv[0], argv);
+ os_exit(1);
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/sdl.c b/roms/u-boot/arch/sandbox/cpu/sdl.c
new file mode 100644
index 000000000..8102649be
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/sdl.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2013 Google, Inc
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <linux/input.h>
+#include <SDL2/SDL.h>
+#include <asm/state.h>
+
+/**
+ * struct buf_info - a data buffer holding audio data
+ *
+ * @pos: Current position playing in audio buffer
+ * @size: Size of data in audio buffer (0=empty)
+ * @alloced: Allocated size of audio buffer (max size it can hold)
+ * @data: Audio data
+ */
+struct buf_info {
+ uint pos;
+ uint size;
+ uint alloced;
+ uint8_t *data;
+};
+
+/**
+ * struct sdl_info - Information about our use of the SDL library
+ *
+ * @width: Width of simulated LCD display
+ * @height: Height of simulated LCD display
+ * @vis_width: Visible width (may be larger to allow for scaling up)
+ * @vis_height: Visible height (may be larger to allow for scaling up)
+ * @depth: Depth of the display in bits per pixel (16 or 32)
+ * @pitch: Number of bytes per line of the display
+ * @sample_rate: Current sample rate for audio
+ * @audio_active: true if audio can be used
+ * @inited: true if this module is initialised
+ * @cur_buf: Current audio buffer being used by sandbox_sdl_fill_audio (0 or 1)
+ * @buf: The two available audio buffers. SDL can be reading from one while we
+ * are setting up the next
+ * @running: true if audio is running
+ * @stopping: true if audio will stop once it runs out of data
+ * @texture: SDL texture to use for U-Boot display contents
+ * @renderer: SDL renderer to use
+ */
+static struct sdl_info {
+ int width;
+ int height;
+ int vis_width;
+ int vis_height;
+ int depth;
+ int pitch;
+ uint sample_rate;
+ bool audio_active;
+ bool inited;
+ int cur_buf;
+ struct buf_info buf[2];
+ bool running;
+ bool stopping;
+ SDL_Texture *texture;
+ SDL_Renderer *renderer;
+} sdl;
+
+static void sandbox_sdl_poll_events(void)
+{
+ /*
+ * We don't want to include common.h in this file since it uses
+ * system headers. So add a declation here.
+ */
+ extern void reset_cpu(void);
+ SDL_Event event;
+
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_QUIT:
+ puts("LCD window closed - quitting\n");
+ reset_cpu();
+ break;
+ }
+ }
+}
+
+static int sandbox_sdl_ensure_init(void)
+{
+ if (!sdl.inited) {
+ if (SDL_Init(0) < 0) {
+ printf("Unable to initialise SDL: %s\n",
+ SDL_GetError());
+ return -EIO;
+ }
+
+ atexit(SDL_Quit);
+
+ sdl.inited = true;
+ }
+ return 0;
+}
+
+int sandbox_sdl_init_display(int width, int height, int log2_bpp,
+ bool double_size)
+{
+ struct sandbox_state *state = state_get_current();
+ int err;
+
+ if (!width || !state->show_lcd)
+ return 0;
+ err = sandbox_sdl_ensure_init();
+ if (err)
+ return err;
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
+ printf("Unable to initialise SDL LCD: %s\n", SDL_GetError());
+ return -EPERM;
+ }
+ sdl.width = width;
+ sdl.height = height;
+ if (double_size) {
+ sdl.vis_width = sdl.width * 2;
+ sdl.vis_height = sdl.height * 2;
+ } else {
+ sdl.vis_width = sdl.width;
+ sdl.vis_height = sdl.height;
+ }
+
+ sdl.depth = 1 << log2_bpp;
+ sdl.pitch = sdl.width * sdl.depth / 8;
+ SDL_Window *screen = SDL_CreateWindow("U-Boot", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ sdl.vis_width, sdl.vis_height,
+ SDL_WINDOW_RESIZABLE);
+ if (!screen) {
+ printf("Unable to initialise SDL screen: %s\n",
+ SDL_GetError());
+ return -EIO;
+ }
+ if (log2_bpp != 4 && log2_bpp != 5) {
+ printf("U-Boot SDL does not support depth %d\n", log2_bpp);
+ return -EINVAL;
+ }
+ sdl.renderer = SDL_CreateRenderer(screen, -1,
+ SDL_RENDERER_ACCELERATED |
+ SDL_RENDERER_PRESENTVSYNC);
+ if (!sdl.renderer) {
+ printf("Unable to initialise SDL renderer: %s\n",
+ SDL_GetError());
+ return -EIO;
+ }
+
+ sdl.texture = SDL_CreateTexture(sdl.renderer, log2_bpp == 4 ?
+ SDL_PIXELFORMAT_RGB565 :
+ SDL_PIXELFORMAT_RGB888,
+ SDL_TEXTUREACCESS_STREAMING,
+ width, height);
+ if (!sdl.texture) {
+ printf("Unable to initialise SDL texture: %s\n",
+ SDL_GetError());
+ return -EBADF;
+ }
+ sandbox_sdl_poll_events();
+
+ return 0;
+}
+
+int sandbox_sdl_sync(void *lcd_base)
+{
+ SDL_UpdateTexture(sdl.texture, NULL, lcd_base, sdl.pitch);
+ SDL_RenderCopy(sdl.renderer, sdl.texture, NULL, NULL);
+ SDL_RenderPresent(sdl.renderer);
+ sandbox_sdl_poll_events();
+
+ return 0;
+}
+
+static const unsigned short sdl_to_keycode[SDL_NUM_SCANCODES] = {
+ [SDL_SCANCODE_ESCAPE] = KEY_ESC,
+ [SDL_SCANCODE_1] = KEY_1,
+ [SDL_SCANCODE_2] = KEY_2,
+ [SDL_SCANCODE_3] = KEY_3,
+ [SDL_SCANCODE_4] = KEY_4,
+ [SDL_SCANCODE_5] = KEY_5,
+ [SDL_SCANCODE_6] = KEY_6,
+ [SDL_SCANCODE_7] = KEY_7,
+ [SDL_SCANCODE_8] = KEY_8,
+ [SDL_SCANCODE_9] = KEY_9,
+ [SDL_SCANCODE_0] = KEY_0,
+ [SDL_SCANCODE_MINUS] = KEY_MINUS,
+ [SDL_SCANCODE_EQUALS] = KEY_EQUAL,
+ [SDL_SCANCODE_BACKSPACE] = KEY_BACKSPACE,
+ [SDL_SCANCODE_TAB] = KEY_TAB,
+ [SDL_SCANCODE_Q] = KEY_Q,
+ [SDL_SCANCODE_W] = KEY_W,
+ [SDL_SCANCODE_E] = KEY_E,
+ [SDL_SCANCODE_R] = KEY_R,
+ [SDL_SCANCODE_T] = KEY_T,
+ [SDL_SCANCODE_Y] = KEY_Y,
+ [SDL_SCANCODE_U] = KEY_U,
+ [SDL_SCANCODE_I] = KEY_I,
+ [SDL_SCANCODE_O] = KEY_O,
+ [SDL_SCANCODE_P] = KEY_P,
+ [SDL_SCANCODE_LEFTBRACKET] = KEY_LEFTBRACE,
+ [SDL_SCANCODE_RIGHTBRACKET] = KEY_RIGHTBRACE,
+ [SDL_SCANCODE_RETURN] = KEY_ENTER,
+ [SDL_SCANCODE_LCTRL] = KEY_LEFTCTRL,
+ [SDL_SCANCODE_A] = KEY_A,
+ [SDL_SCANCODE_S] = KEY_S,
+ [SDL_SCANCODE_D] = KEY_D,
+ [SDL_SCANCODE_F] = KEY_F,
+ [SDL_SCANCODE_G] = KEY_G,
+ [SDL_SCANCODE_H] = KEY_H,
+ [SDL_SCANCODE_J] = KEY_J,
+ [SDL_SCANCODE_K] = KEY_K,
+ [SDL_SCANCODE_L] = KEY_L,
+ [SDL_SCANCODE_SEMICOLON] = KEY_SEMICOLON,
+ [SDL_SCANCODE_APOSTROPHE] = KEY_APOSTROPHE,
+ [SDL_SCANCODE_GRAVE] = KEY_GRAVE,
+ [SDL_SCANCODE_LSHIFT] = KEY_LEFTSHIFT,
+ [SDL_SCANCODE_BACKSLASH] = KEY_BACKSLASH,
+ [SDL_SCANCODE_Z] = KEY_Z,
+ [SDL_SCANCODE_X] = KEY_X,
+ [SDL_SCANCODE_C] = KEY_C,
+ [SDL_SCANCODE_V] = KEY_V,
+ [SDL_SCANCODE_B] = KEY_B,
+ [SDL_SCANCODE_N] = KEY_N,
+ [SDL_SCANCODE_M] = KEY_M,
+ [SDL_SCANCODE_COMMA] = KEY_COMMA,
+ [SDL_SCANCODE_PERIOD] = KEY_DOT,
+ [SDL_SCANCODE_SLASH] = KEY_SLASH,
+ [SDL_SCANCODE_RSHIFT] = KEY_RIGHTSHIFT,
+ [SDL_SCANCODE_KP_MULTIPLY] = KEY_KPASTERISK,
+ [SDL_SCANCODE_LALT] = KEY_LEFTALT,
+ [SDL_SCANCODE_SPACE] = KEY_SPACE,
+ [SDL_SCANCODE_CAPSLOCK] = KEY_CAPSLOCK,
+ [SDL_SCANCODE_F1] = KEY_F1,
+ [SDL_SCANCODE_F2] = KEY_F2,
+ [SDL_SCANCODE_F3] = KEY_F3,
+ [SDL_SCANCODE_F4] = KEY_F4,
+ [SDL_SCANCODE_F5] = KEY_F5,
+ [SDL_SCANCODE_F6] = KEY_F6,
+ [SDL_SCANCODE_F7] = KEY_F7,
+ [SDL_SCANCODE_F8] = KEY_F8,
+ [SDL_SCANCODE_F9] = KEY_F9,
+ [SDL_SCANCODE_F10] = KEY_F10,
+ [SDL_SCANCODE_NUMLOCKCLEAR] = KEY_NUMLOCK,
+ [SDL_SCANCODE_SCROLLLOCK] = KEY_SCROLLLOCK,
+ [SDL_SCANCODE_KP_7] = KEY_KP7,
+ [SDL_SCANCODE_KP_8] = KEY_KP8,
+ [SDL_SCANCODE_KP_9] = KEY_KP9,
+ [SDL_SCANCODE_KP_MINUS] = KEY_KPMINUS,
+ [SDL_SCANCODE_KP_4] = KEY_KP4,
+ [SDL_SCANCODE_KP_5] = KEY_KP5,
+ [SDL_SCANCODE_KP_6] = KEY_KP6,
+ [SDL_SCANCODE_KP_PLUS] = KEY_KPPLUS,
+ [SDL_SCANCODE_KP_1] = KEY_KP1,
+ [SDL_SCANCODE_KP_2] = KEY_KP2,
+ [SDL_SCANCODE_KP_3] = KEY_KP3,
+ [SDL_SCANCODE_KP_0] = KEY_KP0,
+ [SDL_SCANCODE_KP_PERIOD] = KEY_KPDOT,
+ /* key 84 does not exist linux_input.h */
+ [SDL_SCANCODE_LANG5] = KEY_ZENKAKUHANKAKU,
+ [SDL_SCANCODE_NONUSBACKSLASH] = KEY_102ND,
+ [SDL_SCANCODE_F11] = KEY_F11,
+ [SDL_SCANCODE_F12] = KEY_F12,
+ [SDL_SCANCODE_INTERNATIONAL1] = KEY_RO,
+ [SDL_SCANCODE_LANG3] = KEY_KATAKANA,
+ [SDL_SCANCODE_LANG4] = KEY_HIRAGANA,
+ [SDL_SCANCODE_INTERNATIONAL4] = KEY_HENKAN,
+ [SDL_SCANCODE_INTERNATIONAL2] = KEY_KATAKANAHIRAGANA,
+ [SDL_SCANCODE_INTERNATIONAL5] = KEY_MUHENKAN,
+ /* [SDL_SCANCODE_INTERNATIONAL5] -> [KEY_KPJPCOMMA] */
+ [SDL_SCANCODE_KP_ENTER] = KEY_KPENTER,
+ [SDL_SCANCODE_RCTRL] = KEY_RIGHTCTRL,
+ [SDL_SCANCODE_KP_DIVIDE] = KEY_KPSLASH,
+ [SDL_SCANCODE_SYSREQ] = KEY_SYSRQ,
+ [SDL_SCANCODE_RALT] = KEY_RIGHTALT,
+ /* KEY_LINEFEED */
+ [SDL_SCANCODE_HOME] = KEY_HOME,
+ [SDL_SCANCODE_UP] = KEY_UP,
+ [SDL_SCANCODE_PAGEUP] = KEY_PAGEUP,
+ [SDL_SCANCODE_LEFT] = KEY_LEFT,
+ [SDL_SCANCODE_RIGHT] = KEY_RIGHT,
+ [SDL_SCANCODE_END] = KEY_END,
+ [SDL_SCANCODE_DOWN] = KEY_DOWN,
+ [SDL_SCANCODE_PAGEDOWN] = KEY_PAGEDOWN,
+ [SDL_SCANCODE_INSERT] = KEY_INSERT,
+ [SDL_SCANCODE_DELETE] = KEY_DELETE,
+ /* KEY_MACRO */
+ [SDL_SCANCODE_MUTE] = KEY_MUTE,
+ [SDL_SCANCODE_VOLUMEDOWN] = KEY_VOLUMEDOWN,
+ [SDL_SCANCODE_VOLUMEUP] = KEY_VOLUMEUP,
+ [SDL_SCANCODE_POWER] = KEY_POWER,
+ [SDL_SCANCODE_KP_EQUALS] = KEY_KPEQUAL,
+ [SDL_SCANCODE_KP_PLUSMINUS] = KEY_KPPLUSMINUS,
+ [SDL_SCANCODE_PAUSE] = KEY_PAUSE,
+ /* KEY_SCALE */
+ [SDL_SCANCODE_KP_COMMA] = KEY_KPCOMMA,
+ [SDL_SCANCODE_LANG1] = KEY_HANGUEL,
+ [SDL_SCANCODE_LANG2] = KEY_HANJA,
+ [SDL_SCANCODE_INTERNATIONAL3] = KEY_YEN,
+ [SDL_SCANCODE_LGUI] = KEY_LEFTMETA,
+ [SDL_SCANCODE_RGUI] = KEY_RIGHTMETA,
+ [SDL_SCANCODE_APPLICATION] = KEY_COMPOSE,
+};
+
+int sandbox_sdl_scan_keys(int key[], int max_keys)
+{
+ const Uint8 *keystate;
+ int num_keys;
+ int i, count;
+
+ sandbox_sdl_poll_events();
+ keystate = SDL_GetKeyboardState(&num_keys);
+ for (i = count = 0; i < num_keys; i++) {
+ if (count < max_keys && keystate[i]) {
+ int keycode = sdl_to_keycode[i];
+
+ if (keycode)
+ key[count++] = keycode;
+ }
+ }
+
+ return count;
+}
+
+int sandbox_sdl_key_pressed(int keycode)
+{
+ int key[8]; /* allow up to 8 keys to be pressed at once */
+ int count;
+ int i;
+
+ count = sandbox_sdl_scan_keys(key, sizeof(key) / sizeof(key[0]));
+ for (i = 0; i < count; i++) {
+ if (key[i] == keycode)
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
+{
+ struct buf_info *buf;
+ int avail;
+ bool have_data = false;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ buf = &sdl.buf[sdl.cur_buf];
+ avail = buf->size - buf->pos;
+ if (avail <= 0) {
+ sdl.cur_buf = 1 - sdl.cur_buf;
+ continue;
+ }
+ if (avail > len)
+ avail = len;
+ have_data = true;
+
+ SDL_MixAudio(stream, buf->data + buf->pos, avail,
+ SDL_MIX_MAXVOLUME);
+ buf->pos += avail;
+ len -= avail;
+
+ /* Move to next buffer if we are at the end */
+ if (buf->pos == buf->size)
+ buf->size = 0;
+ else
+ break;
+ }
+ sdl.stopping = !have_data;
+}
+
+int sandbox_sdl_sound_init(int rate, int channels)
+{
+ SDL_AudioSpec wanted, have;
+ int i;
+
+ if (sandbox_sdl_ensure_init())
+ return -1;
+
+ if (sdl.audio_active)
+ return 0;
+
+ /* Set the audio format */
+ wanted.freq = rate;
+ wanted.format = AUDIO_S16;
+ wanted.channels = channels;
+ wanted.samples = 1024; /* Good low-latency value for callback */
+ wanted.callback = sandbox_sdl_fill_audio;
+ wanted.userdata = NULL;
+
+ for (i = 0; i < 2; i++) {
+ struct buf_info *buf = &sdl.buf[i];
+
+ buf->alloced = sizeof(uint16_t) * wanted.freq * wanted.channels;
+ buf->data = malloc(buf->alloced);
+ if (!buf->data) {
+ printf("%s: Out of memory\n", __func__);
+ if (i == 1)
+ free(sdl.buf[0].data);
+ return -1;
+ }
+ buf->pos = 0;
+ buf->size = 0;
+ }
+
+ if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
+ printf("Unable to initialise SDL audio: %s\n", SDL_GetError());
+ goto err;
+ }
+
+ /* Open the audio device, forcing the desired format */
+ if (SDL_OpenAudio(&wanted, &have) < 0) {
+ printf("Couldn't open audio: %s\n", SDL_GetError());
+ goto err;
+ }
+ if (have.format != wanted.format) {
+ printf("Couldn't select required audio format\n");
+ goto err;
+ }
+ sdl.audio_active = true;
+ sdl.sample_rate = wanted.freq;
+ sdl.cur_buf = 0;
+ sdl.running = false;
+
+ return 0;
+
+err:
+ for (i = 0; i < 2; i++)
+ free(sdl.buf[i].data);
+ return -1;
+}
+
+int sandbox_sdl_sound_play(const void *data, uint size)
+{
+ struct buf_info *buf;
+
+ if (!sdl.audio_active)
+ return 0;
+
+ buf = &sdl.buf[0];
+ if (buf->size)
+ buf = &sdl.buf[1];
+ while (buf->size)
+ usleep(1000);
+
+ if (size > buf->alloced)
+ return -E2BIG;
+
+ memcpy(buf->data, data, size);
+ buf->size = size;
+ buf->pos = 0;
+ if (!sdl.running) {
+ SDL_PauseAudio(0);
+ sdl.running = true;
+ sdl.stopping = false;
+ }
+
+ return 0;
+}
+
+int sandbox_sdl_sound_stop(void)
+{
+ if (sdl.running) {
+ while (!sdl.stopping)
+ SDL_Delay(100);
+
+ SDL_PauseAudio(1);
+ sdl.running = 0;
+ sdl.stopping = false;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/spl.c b/roms/u-boot/arch/sandbox/cpu/spl.c
new file mode 100644
index 000000000..f82b0d3de
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/spl.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2016 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <hang.h>
+#include <init.h>
+#include <log.h>
+#include <os.h>
+#include <spl.h>
+#include <asm/global_data.h>
+#include <asm/spl.h>
+#include <asm/state.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* SPL / TPL init function */
+void board_init_f(ulong flag)
+{
+ struct sandbox_state *state = state_get_current();
+
+ gd->arch.ram_buf = state->ram_buf;
+ gd->ram_size = state->ram_size;
+}
+
+u32 spl_boot_device(void)
+{
+ return BOOT_DEVICE_BOARD;
+}
+
+static int spl_board_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ char fname[256];
+ int ret;
+
+ ret = os_find_u_boot(fname, sizeof(fname), false);
+ if (ret) {
+ printf("(%s not found, error %d)\n", fname, ret);
+ return ret;
+ }
+
+ /*
+ * Set up spl_image to boot from jump_to_image_no_args(). Allocate this
+ * outsdide the RAM buffer (i.e. don't use strdup()).
+ */
+ spl_image->arg = os_malloc(strlen(fname) + 1);
+ if (!spl_image->arg)
+ return log_msg_ret("exec", -ENOMEM);
+ strcpy(spl_image->arg, fname);
+
+ return 0;
+}
+SPL_LOAD_IMAGE_METHOD("sandbox", 9, BOOT_DEVICE_BOARD, spl_board_load_image);
+
+void spl_board_init(void)
+{
+ struct sandbox_state *state = state_get_current();
+
+ preloader_console_init();
+
+ if (state->run_unittests) {
+ struct unit_test *tests = UNIT_TEST_ALL_START();
+ const int count = UNIT_TEST_ALL_COUNT();
+ int ret;
+
+ ret = ut_run_list("spl", NULL, tests, count,
+ state->select_unittests);
+ /* continue execution into U-Boot */
+ }
+}
+
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
+{
+ const char *fname = spl_image->arg;
+
+ if (fname) {
+ os_fd_restore();
+ os_spl_to_uboot(fname);
+ } else {
+ printf("No filename provided for U-Boot\n");
+ }
+ hang();
+}
+
+int handoff_arch_save(struct spl_handoff *ho)
+{
+ ho->arch.magic = TEST_HANDOFF_MAGIC;
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/start.c b/roms/u-boot/arch/sandbox/cpu/start.c
new file mode 100644
index 000000000..6bb94473f
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/start.c
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011-2012 The Chromium OS Authors.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm/root.h>
+#include <efi_loader.h>
+#include <errno.h>
+#include <init.h>
+#include <log.h>
+#include <os.h>
+#include <cli.h>
+#include <sort.h>
+#include <asm/getopt.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/malloc.h>
+#include <asm/sections.h>
+#include <asm/state.h>
+#include <linux/ctype.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char **os_argv;
+
+/* Compare two options so that they can be sorted into alphabetical order */
+static int h_compare_opt(const void *p1, const void *p2)
+{
+ const struct sandbox_cmdline_option *opt1 = p1;
+ const struct sandbox_cmdline_option *opt2 = p2;
+ const char *str1, *str2;
+ char flag1[2], flag2[2];
+
+ opt1 = *(struct sandbox_cmdline_option **)p1;
+ opt2 = *(struct sandbox_cmdline_option **)p2;
+ flag1[1] = '\0';
+ flag2[1] = '\0';
+
+ *flag1 = opt1->flag_short < 0x100 ? opt1->flag_short : '\0';
+ *flag2 = opt2->flag_short < 0x100 ? opt2->flag_short : '\0';
+
+ str1 = *flag1 ? flag1 : opt1->flag;
+ str2 = *flag2 ? flag2 : opt2->flag;
+
+ /*
+ * Force lower-case flags to come before upper-case ones. We only
+ * support upper-case for short flags.
+ */
+ if (isalpha(*str1) && isalpha(*str2) &&
+ tolower(*str1) == tolower(*str2))
+ return isupper(*str1) - isupper(*str2);
+
+ return strcasecmp(str1, str2);
+}
+
+int sandbox_early_getopt_check(void)
+{
+ struct sandbox_state *state = state_get_current();
+ struct sandbox_cmdline_option **sb_opt =
+ __u_boot_sandbox_option_start();
+ size_t num_options = __u_boot_sandbox_option_count();
+ size_t i;
+ int max_arg_len, max_noarg_len;
+ struct sandbox_cmdline_option **sorted_opt;
+ int size;
+
+ /* parse_err will be a string of the faulting option */
+ if (!state->parse_err)
+ return 0;
+
+ if (strcmp(state->parse_err, "help")) {
+ printf("u-boot: error: failed while parsing option: %s\n"
+ "\ttry running with --help for more information.\n",
+ state->parse_err);
+ os_exit(1);
+ }
+
+ printf(
+ "u-boot, a command line test interface to U-Boot\n\n"
+ "Usage: u-boot [options]\n"
+ "Options:\n");
+
+ max_arg_len = 0;
+ for (i = 0; i < num_options; ++i)
+ max_arg_len = max((int)strlen(sb_opt[i]->flag), max_arg_len);
+ max_noarg_len = max_arg_len + 7;
+
+ /* Sort the options */
+ size = sizeof(*sorted_opt) * num_options;
+ sorted_opt = os_malloc(size);
+ if (!sorted_opt) {
+ printf("No memory to sort options\n");
+ os_exit(1);
+ }
+ memcpy(sorted_opt, sb_opt, size);
+ qsort(sorted_opt, num_options, sizeof(*sorted_opt), h_compare_opt);
+
+ for (i = 0; i < num_options; ++i) {
+ struct sandbox_cmdline_option *opt = sorted_opt[i];
+
+ /* first output the short flag if it has one */
+ if (opt->flag_short >= 0x100)
+ printf(" ");
+ else
+ printf(" -%c, ", opt->flag_short);
+
+ /* then the long flag */
+ if (opt->has_arg)
+ printf("--%-*s <arg> ", max_arg_len, opt->flag);
+ else
+ printf("--%-*s", max_noarg_len, opt->flag);
+
+ /* finally the help text */
+ printf(" %s\n", opt->help);
+ }
+
+ os_exit(0);
+}
+
+int misc_init_f(void)
+{
+ return sandbox_early_getopt_check();
+}
+
+static int sandbox_cmdline_cb_help(struct sandbox_state *state, const char *arg)
+{
+ /* just flag to sandbox_early_getopt_check to show usage */
+ return 1;
+}
+SANDBOX_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help");
+
+#ifndef CONFIG_SPL_BUILD
+int sandbox_main_loop_init(void)
+{
+ struct sandbox_state *state = state_get_current();
+
+ /* Execute command if required */
+ if (state->cmd || state->run_distro_boot) {
+ int retval = 0;
+
+ cli_init();
+
+#ifdef CONFIG_CMDLINE
+ if (state->cmd)
+ retval = run_command_list(state->cmd, -1, 0);
+
+ if (state->run_distro_boot)
+ retval = cli_simple_run_command("run distro_bootcmd",
+ 0);
+#endif
+ if (!state->interactive)
+ os_exit(retval);
+ }
+
+ return 0;
+}
+#endif
+
+static int sandbox_cmdline_cb_boot(struct sandbox_state *state,
+ const char *arg)
+{
+ state->run_distro_boot = true;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(boot, 'b', 0, "Run distro boot commands");
+
+static int sandbox_cmdline_cb_command(struct sandbox_state *state,
+ const char *arg)
+{
+ state->cmd = arg;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(command, 'c', 1, "Execute U-Boot command");
+
+static int sandbox_cmdline_cb_fdt(struct sandbox_state *state, const char *arg)
+{
+ state->fdt_fname = arg;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(fdt, 'd', 1, "Specify U-Boot's control FDT");
+
+static int sandbox_cmdline_cb_default_fdt(struct sandbox_state *state,
+ const char *arg)
+{
+ const char *fmt = "%s.dtb";
+ char *fname;
+ int len;
+
+ len = strlen(state->argv[0]) + strlen(fmt) + 1;
+ fname = os_malloc(len);
+ if (!fname)
+ return -ENOMEM;
+ snprintf(fname, len, fmt, state->argv[0]);
+ state->fdt_fname = fname;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(default_fdt, 'D', 0,
+ "Use the default u-boot.dtb control FDT in U-Boot directory");
+
+static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state,
+ const char *arg)
+{
+ const char *fmt = "/arch/sandbox/dts/test.dtb";
+ char *p;
+ char *fname;
+ int len;
+
+ len = strlen(state->argv[0]) + strlen(fmt) + 1;
+ fname = os_malloc(len);
+ if (!fname)
+ return -ENOMEM;
+ strcpy(fname, state->argv[0]);
+ p = strrchr(fname, '/');
+ if (!p)
+ p = fname + strlen(fname);
+ len -= p - fname;
+ snprintf(p, len, fmt);
+ state->fdt_fname = fname;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(test_fdt, 'T', 0,
+ "Use the test.dtb control FDT in U-Boot directory");
+
+static int sandbox_cmdline_cb_interactive(struct sandbox_state *state,
+ const char *arg)
+{
+ state->interactive = true;
+ return 0;
+}
+
+SANDBOX_CMDLINE_OPT_SHORT(interactive, 'i', 0, "Enter interactive mode");
+
+static int sandbox_cmdline_cb_jump(struct sandbox_state *state,
+ const char *arg)
+{
+ /* Remember to delete this U-Boot image later */
+ state->jumped_fname = arg;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(jump, 'j', 1, "Jumped from previous U-Boot");
+
+static int sandbox_cmdline_cb_memory(struct sandbox_state *state,
+ const char *arg)
+{
+ int err;
+
+ /* For now assume we always want to write it */
+ state->write_ram_buf = true;
+ state->ram_buf_fname = arg;
+
+ err = os_read_ram_buf(arg);
+ if (err) {
+ printf("Failed to read RAM buffer '%s': %d\n", arg, err);
+ return err;
+ }
+ state->ram_buf_read = true;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(memory, 'm', 1,
+ "Read/write ram_buf memory contents from file");
+
+static int sandbox_cmdline_cb_rm_memory(struct sandbox_state *state,
+ const char *arg)
+{
+ state->ram_buf_rm = true;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT(rm_memory, 0, "Remove memory file after reading");
+
+static int sandbox_cmdline_cb_state(struct sandbox_state *state,
+ const char *arg)
+{
+ state->state_fname = arg;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(state, 's', 1, "Specify the sandbox state FDT");
+
+static int sandbox_cmdline_cb_read(struct sandbox_state *state,
+ const char *arg)
+{
+ state->read_state = true;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(read, 'r', 0, "Read the state FDT on startup");
+
+static int sandbox_cmdline_cb_write(struct sandbox_state *state,
+ const char *arg)
+{
+ state->write_state = true;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(write, 'w', 0, "Write state FDT on exit");
+
+static int sandbox_cmdline_cb_ignore_missing(struct sandbox_state *state,
+ const char *arg)
+{
+ state->ignore_missing_state_on_read = true;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(ignore_missing, 'n', 0,
+ "Ignore missing state on read");
+
+static int sandbox_cmdline_cb_show_lcd(struct sandbox_state *state,
+ const char *arg)
+{
+ state->show_lcd = true;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(show_lcd, 'l', 0,
+ "Show the sandbox LCD display");
+
+static int sandbox_cmdline_cb_double_lcd(struct sandbox_state *state,
+ const char *arg)
+{
+ state->double_lcd = true;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(double_lcd, 'K', 0,
+ "Double the LCD display size in each direction");
+
+static const char *term_args[STATE_TERM_COUNT] = {
+ "raw-with-sigs",
+ "raw",
+ "cooked",
+};
+
+static int sandbox_cmdline_cb_terminal(struct sandbox_state *state,
+ const char *arg)
+{
+ int i;
+
+ for (i = 0; i < STATE_TERM_COUNT; i++) {
+ if (!strcmp(arg, term_args[i])) {
+ state->term_raw = i;
+ return 0;
+ }
+ }
+
+ printf("Unknown terminal setting '%s' (", arg);
+ for (i = 0; i < STATE_TERM_COUNT; i++)
+ printf("%s%s", i ? ", " : "", term_args[i]);
+ puts(")\n");
+
+ return 1;
+}
+SANDBOX_CMDLINE_OPT_SHORT(terminal, 't', 1,
+ "Set terminal to raw/cooked mode");
+
+static int sandbox_cmdline_cb_verbose(struct sandbox_state *state,
+ const char *arg)
+{
+ state->show_test_output = true;
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(verbose, 'v', 0, "Show test output");
+
+static int sandbox_cmdline_cb_log_level(struct sandbox_state *state,
+ const char *arg)
+{
+ state->default_log_level = simple_strtol(arg, NULL, 10);
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(log_level, 'L', 1,
+ "Set log level (0=panic, 7=debug)");
+
+static int sandbox_cmdline_cb_unittests(struct sandbox_state *state,
+ const char *arg)
+{
+ state->run_unittests = true;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(unittests, 'u', 0, "Run unit tests");
+
+static int sandbox_cmdline_cb_select_unittests(struct sandbox_state *state,
+ const char *arg)
+{
+ state->select_unittests = arg;
+
+ return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(select_unittests, 'k', 1, "Select unit tests to run");
+
+static void setup_ram_buf(struct sandbox_state *state)
+{
+ /* Zero the RAM buffer if we didn't read it, to keep valgrind happy */
+ if (!state->ram_buf_read)
+ memset(state->ram_buf, '\0', state->ram_size);
+
+ gd->arch.ram_buf = state->ram_buf;
+ gd->ram_size = state->ram_size;
+}
+
+void state_show(struct sandbox_state *state)
+{
+ char **p;
+
+ printf("Arguments:\n");
+ for (p = state->argv; *p; p++)
+ printf("%s ", *p);
+ printf("\n");
+}
+
+void __efi_runtime EFIAPI efi_reset_system(
+ enum efi_reset_type reset_type,
+ efi_status_t reset_status,
+ unsigned long data_size, void *reset_data)
+{
+ os_fd_restore();
+ os_relaunch(os_argv);
+}
+
+void sandbox_reset(void)
+{
+ /* Do this here while it still has an effect */
+ os_fd_restore();
+ if (state_uninit())
+ os_exit(2);
+
+ if (dm_uninit())
+ os_exit(2);
+
+ /* Restart U-Boot */
+ os_relaunch(os_argv);
+}
+
+int main(int argc, char *argv[])
+{
+ struct sandbox_state *state;
+ void * text_base;
+ gd_t data;
+ int size;
+ int ret;
+
+ text_base = os_find_text_base();
+
+ /*
+ * Copy argv[] so that we can pass the arguments in the original
+ * sequence when resetting the sandbox.
+ */
+ size = sizeof(char *) * (argc + 1);
+ os_argv = os_malloc(size);
+ if (!os_argv)
+ os_exit(1);
+ memcpy(os_argv, argv, size);
+
+ memset(&data, '\0', sizeof(data));
+ gd = &data;
+ gd->arch.text_base = text_base;
+
+ ret = state_init();
+ if (ret)
+ goto err;
+
+ state = state_get_current();
+ if (os_parse_args(state, argc, argv))
+ return 1;
+
+ /* Remove old memory file if required */
+ if (state->ram_buf_rm && state->ram_buf_fname) {
+ os_unlink(state->ram_buf_fname);
+ state->write_ram_buf = false;
+ state->ram_buf_fname = NULL;
+ }
+
+ ret = sandbox_read_state(state, state->state_fname);
+ if (ret)
+ goto err;
+
+ ret = os_setup_signal_handlers();
+ if (ret)
+ goto err;
+
+#if CONFIG_VAL(SYS_MALLOC_F_LEN)
+ gd->malloc_base = CONFIG_MALLOC_F_ADDR;
+#endif
+#if CONFIG_IS_ENABLED(LOG)
+ gd->default_log_level = state->default_log_level;
+#endif
+ setup_ram_buf(state);
+
+ /*
+ * Set up the relocation offset here, since sandbox symbols are always
+ * relocated by the OS before sandbox is entered.
+ */
+ gd->reloc_off = (ulong)gd->arch.text_base;
+
+ /* sandbox test: log functions called before log_init in board_init_f */
+ log_debug("debug: %s\n", __func__);
+
+ /* Do pre- and post-relocation init */
+ board_init_f(0);
+
+ board_init_r(gd->new_gd, 0);
+
+ /* NOTREACHED - board_init_r() does not return */
+ return 0;
+
+err:
+ printf("Error %d\n", ret);
+ return 1;
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/state.c b/roms/u-boot/arch/sandbox/cpu/state.c
new file mode 100644
index 000000000..f63cfd38e
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/state.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011-2012 The Chromium OS Authors.
+ */
+
+#include <common.h>
+#include <bloblist.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <os.h>
+#include <asm/malloc.h>
+#include <asm/state.h>
+
+/* Main state record for the sandbox */
+static struct sandbox_state main_state;
+static struct sandbox_state *state; /* Pointer to current state record */
+
+static int state_ensure_space(int extra_size)
+{
+ void *blob = state->state_fdt;
+ int used, size, free_bytes;
+ void *buf;
+ int ret;
+
+ used = fdt_off_dt_strings(blob) + fdt_size_dt_strings(blob);
+ size = fdt_totalsize(blob);
+ free_bytes = size - used;
+ if (free_bytes > extra_size)
+ return 0;
+
+ size = used + extra_size;
+ buf = os_malloc(size);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = fdt_open_into(blob, buf, size);
+ if (ret) {
+ os_free(buf);
+ return -EIO;
+ }
+
+ os_free(blob);
+ state->state_fdt = buf;
+ return 0;
+}
+
+static int state_read_file(struct sandbox_state *state, const char *fname)
+{
+ loff_t size;
+ int ret;
+ int fd;
+
+ ret = os_get_filesize(fname, &size);
+ if (ret < 0) {
+ printf("Cannot find sandbox state file '%s'\n", fname);
+ return -ENOENT;
+ }
+ state->state_fdt = os_malloc(size);
+ if (!state->state_fdt) {
+ puts("No memory to read sandbox state\n");
+ return -ENOMEM;
+ }
+ fd = os_open(fname, OS_O_RDONLY);
+ if (fd < 0) {
+ printf("Cannot open sandbox state file '%s'\n", fname);
+ ret = -EPERM;
+ goto err_open;
+ }
+ if (os_read(fd, state->state_fdt, size) != size) {
+ printf("Cannot read sandbox state file '%s'\n", fname);
+ ret = -EIO;
+ goto err_read;
+ }
+ os_close(fd);
+
+ return 0;
+err_read:
+ os_close(fd);
+err_open:
+ os_free(state->state_fdt);
+ state->state_fdt = NULL;
+
+ return ret;
+}
+
+/***
+ * sandbox_read_state_nodes() - Read state associated with a driver
+ *
+ * This looks through all compatible nodes and calls the read function on
+ * each one, to read in the state.
+ *
+ * If nothing is found, it still calls the read function once, to set up a
+ * single global state for that driver.
+ *
+ * @state: Sandbox state
+ * @io: Method to use for reading state
+ * @blob: FDT containing state
+ * @return 0 if OK, -EINVAL if the read function returned failure
+ */
+int sandbox_read_state_nodes(struct sandbox_state *state,
+ struct sandbox_state_io *io, const void *blob)
+{
+ int count;
+ int node;
+ int ret;
+
+ debug(" - read %s\n", io->name);
+ if (!io->read)
+ return 0;
+
+ node = -1;
+ count = 0;
+ while (blob) {
+ node = fdt_node_offset_by_compatible(blob, node, io->compat);
+ if (node < 0)
+ return 0; /* No more */
+ debug(" - read node '%s'\n", fdt_get_name(blob, node, NULL));
+ ret = io->read(blob, node);
+ if (ret) {
+ printf("Unable to read state for '%s'\n", io->compat);
+ return -EINVAL;
+ }
+ count++;
+ }
+
+ /*
+ * If we got no saved state, call the read function once without a
+ * node, to set up the global state.
+ */
+ if (count == 0) {
+ debug(" - read global\n");
+ ret = io->read(NULL, -1);
+ if (ret) {
+ printf("Unable to read global state for '%s'\n",
+ io->name);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int sandbox_read_state(struct sandbox_state *state, const char *fname)
+{
+ struct sandbox_state_io *io;
+ const void *blob;
+ bool got_err;
+ int ret;
+
+ if (state->read_state && fname) {
+ ret = state_read_file(state, fname);
+ if (ret == -ENOENT && state->ignore_missing_state_on_read)
+ ret = 0;
+ if (ret)
+ return ret;
+ }
+
+ /* Call all the state read functions */
+ got_err = false;
+ blob = state->state_fdt;
+ io = ll_entry_start(struct sandbox_state_io, state_io);
+ for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
+ ret = sandbox_read_state_nodes(state, io, blob);
+ if (ret < 0)
+ got_err = true;
+ }
+
+ if (state->read_state && fname) {
+ debug("Read sandbox state from '%s'%s\n", fname,
+ got_err ? " (with errors)" : "");
+ }
+
+ return got_err ? -1 : 0;
+}
+
+/***
+ * sandbox_write_state_node() - Write state associated with a driver
+ *
+ * This calls the write function to write out global state for that driver.
+ *
+ * TODO(sjg@chromium.org): Support writing out state from multiple drivers
+ * of the same time. We don't need this yet,and it will be much easier to
+ * do when driver model is available.
+ *
+ * @state: Sandbox state
+ * @io: Method to use for writing state
+ * @return 0 if OK, -EIO if there is a fatal error (such as out of space
+ * for adding the data), -EINVAL if the write function failed.
+ */
+int sandbox_write_state_node(struct sandbox_state *state,
+ struct sandbox_state_io *io)
+{
+ void *blob;
+ int node;
+ int ret;
+
+ if (!io->write)
+ return 0;
+
+ ret = state_ensure_space(SANDBOX_STATE_MIN_SPACE);
+ if (ret) {
+ printf("Failed to add more space for state\n");
+ return -EIO;
+ }
+
+ /* The blob location can change when the size increases */
+ blob = state->state_fdt;
+ node = fdt_node_offset_by_compatible(blob, -1, io->compat);
+ if (node == -FDT_ERR_NOTFOUND) {
+ node = fdt_add_subnode(blob, 0, io->name);
+ if (node < 0) {
+ printf("Cannot create node '%s': %s\n", io->name,
+ fdt_strerror(node));
+ return -EIO;
+ }
+
+ if (fdt_setprop_string(blob, node, "compatible", io->compat)) {
+ puts("Cannot set compatible\n");
+ return -EIO;
+ }
+ } else if (node < 0) {
+ printf("Cannot access node '%s': %s\n", io->name,
+ fdt_strerror(node));
+ return -EIO;
+ }
+ debug("Write state for '%s' to node %d\n", io->compat, node);
+ ret = io->write(blob, node);
+ if (ret) {
+ printf("Unable to write state for '%s'\n", io->compat);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int sandbox_write_state(struct sandbox_state *state, const char *fname)
+{
+ struct sandbox_state_io *io;
+ bool got_err;
+ int size;
+ int ret;
+ int fd;
+
+ /* Create a state FDT if we don't have one */
+ if (!state->state_fdt) {
+ size = 0x4000;
+ state->state_fdt = os_malloc(size);
+ if (!state->state_fdt) {
+ puts("No memory to create FDT\n");
+ return -ENOMEM;
+ }
+ ret = fdt_create_empty_tree(state->state_fdt, size);
+ if (ret < 0) {
+ printf("Cannot create empty state FDT: %s\n",
+ fdt_strerror(ret));
+ ret = -EIO;
+ goto err_create;
+ }
+ }
+
+ /* Call all the state write funtcions */
+ got_err = false;
+ io = ll_entry_start(struct sandbox_state_io, state_io);
+ ret = 0;
+ for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
+ ret = sandbox_write_state_node(state, io);
+ if (ret == -EIO)
+ break;
+ else if (ret)
+ got_err = true;
+ }
+
+ if (ret == -EIO) {
+ printf("Could not write sandbox state\n");
+ goto err_create;
+ }
+
+ ret = fdt_pack(state->state_fdt);
+ if (ret < 0) {
+ printf("Cannot pack state FDT: %s\n", fdt_strerror(ret));
+ ret = -EINVAL;
+ goto err_create;
+ }
+ size = fdt_totalsize(state->state_fdt);
+ fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT);
+ if (fd < 0) {
+ printf("Cannot open sandbox state file '%s'\n", fname);
+ ret = -EIO;
+ goto err_create;
+ }
+ if (os_write(fd, state->state_fdt, size) != size) {
+ printf("Cannot write sandbox state file '%s'\n", fname);
+ ret = -EIO;
+ goto err_write;
+ }
+ os_close(fd);
+
+ debug("Wrote sandbox state to '%s'%s\n", fname,
+ got_err ? " (with errors)" : "");
+
+ return 0;
+err_write:
+ os_close(fd);
+err_create:
+ os_free(state->state_fdt);
+
+ return ret;
+}
+
+int state_setprop(int node, const char *prop_name, const void *data, int size)
+{
+ void *blob;
+ int len;
+ int ret;
+
+ fdt_getprop(state->state_fdt, node, prop_name, &len);
+
+ /* Add space for the new property, its name and some overhead */
+ ret = state_ensure_space(size - len + strlen(prop_name) + 32);
+ if (ret)
+ return ret;
+
+ /* This should succeed, barring a mutiny */
+ blob = state->state_fdt;
+ ret = fdt_setprop(blob, node, prop_name, data, size);
+ if (ret) {
+ printf("%s: Unable to set property '%s' in node '%s': %s\n",
+ __func__, prop_name, fdt_get_name(blob, node, NULL),
+ fdt_strerror(ret));
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+struct sandbox_state *state_get_current(void)
+{
+ assert(state);
+ return state;
+}
+
+void state_set_skip_delays(bool skip_delays)
+{
+ struct sandbox_state *state = state_get_current();
+
+ state->skip_delays = skip_delays;
+}
+
+bool state_get_skip_delays(void)
+{
+ struct sandbox_state *state = state_get_current();
+
+ return state->skip_delays;
+}
+
+void state_reset_for_test(struct sandbox_state *state)
+{
+ /* No reset yet, so mark it as such. Always allow power reset */
+ state->last_sysreset = SYSRESET_COUNT;
+ state->sysreset_allowed[SYSRESET_POWER_OFF] = true;
+ state->sysreset_allowed[SYSRESET_COLD] = true;
+ state->allow_memio = false;
+
+ memset(&state->wdt, '\0', sizeof(state->wdt));
+ memset(state->spi, '\0', sizeof(state->spi));
+
+ /*
+ * Set up the memory tag list. Use the top of emulated SDRAM for the
+ * first tag number, since that address offset is outside the legal
+ * range, and can be assumed to be a tag.
+ */
+ INIT_LIST_HEAD(&state->mapmem_head);
+ state->next_tag = state->ram_size;
+}
+
+int state_init(void)
+{
+ state = &main_state;
+
+ state->ram_size = CONFIG_SYS_SDRAM_SIZE;
+ state->ram_buf = os_malloc(state->ram_size);
+ if (!state->ram_buf) {
+ printf("Out of memory\n");
+ os_exit(1);
+ }
+
+ state_reset_for_test(state);
+ /*
+ * Example of how to use GPIOs:
+ *
+ * sandbox_gpio_set_direction(170, 0);
+ * sandbox_gpio_set_value(170, 0);
+ */
+ return 0;
+}
+
+int state_uninit(void)
+{
+ int err;
+
+ log_info("Writing sandbox state\n");
+ state = &main_state;
+
+ /* Finish the bloblist, so that it is correct before writing memory */
+ bloblist_finish();
+
+ if (state->write_ram_buf) {
+ err = os_write_ram_buf(state->ram_buf_fname);
+ if (err) {
+ printf("Failed to write RAM buffer\n");
+ return err;
+ }
+ }
+
+ if (state->write_state) {
+ if (sandbox_write_state(state, state->state_fname)) {
+ printf("Failed to write sandbox state\n");
+ return -1;
+ }
+ }
+
+ /* Delete this at the last moment so as not to upset gdb too much */
+ if (state->jumped_fname)
+ os_unlink(state->jumped_fname);
+
+ os_free(state->state_fdt);
+ os_free(state->ram_buf);
+ memset(state, '\0', sizeof(*state));
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/sandbox/cpu/u-boot-spl.lds b/roms/u-boot/arch/sandbox/cpu/u-boot-spl.lds
new file mode 100644
index 000000000..6754f4ef6
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/u-boot-spl.lds
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011-2012 The Chromium OS Authors.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+SECTIONS
+{
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ /* Private data for devices with OF_PLATDATA_RT */
+ . = ALIGN(4);
+ .priv_data : {
+ __priv_data_start = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.priv_data*)))
+ __priv_data_end = .;
+ }
+
+ _u_boot_sandbox_getopt : {
+ *(.u_boot_sandbox_getopt_start)
+ KEEP(*(.u_boot_sandbox_getopt))
+ *(.u_boot_sandbox_getopt_end)
+ }
+}
+
+INSERT AFTER .data;
diff --git a/roms/u-boot/arch/sandbox/cpu/u-boot.lds b/roms/u-boot/arch/sandbox/cpu/u-boot.lds
new file mode 100644
index 000000000..6d710618f
--- /dev/null
+++ b/roms/u-boot/arch/sandbox/cpu/u-boot.lds
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011-2012 The Chromium OS Authors.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+SECTIONS
+{
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ _u_boot_sandbox_getopt : {
+ *(.u_boot_sandbox_getopt_start)
+ *(.u_boot_sandbox_getopt)
+ *(.u_boot_sandbox_getopt_end)
+ }
+
+ .__efi_runtime_start : {
+ *(.__efi_runtime_start)
+ }
+
+ .efi_runtime : {
+ *(efi_runtime_text)
+ *(efi_runtime_data)
+ }
+
+ .__efi_runtime_stop : {
+ *(.__efi_runtime_stop)
+ }
+
+ .efi_runtime_rel_start :
+ {
+ *(.__efi_runtime_rel_start)
+ }
+
+ .efi_runtime_rel : {
+ *(.relefi_runtime_text)
+ *(.relefi_runtime_data)
+ }
+
+ .efi_runtime_rel_stop :
+ {
+ *(.__efi_runtime_rel_stop)
+ }
+
+ .dynsym :
+ {
+ __dyn_sym_start = .;
+ *(.dynsym)
+ __dyn_sym_end = .;
+ }
+}
+
+INSERT BEFORE .data;