spl: Add semihosting boot method

This adds a boot method for loading the next stage from the host. It is
mostly modeled off of spl_load_image_ext. I am not really sure why/how
spl_load_image_fat uses three different methods to load the image, but
the simple case seems to work OK for now.

To control the presence of this boot method, we add a config symbol.
While we're at it, we update the original semihosting config symbol.

I think semihosting has some advantages of other forms of JTAG boot.
Common other ways to boot from JTAG include:

- Implementing DDR initialization through JTAG (typically with dozens of
  lines of TCL) and then loading U-Boot. The DDR initialization
  typically uses hard-coded register writes, and is not easily adapted
  to different boards. BOOT_DEVICE_SMH allows booting with SPL,
  leveraging U-Boot's existing DDR initialization code. This is the
  method used by NXP's CodeWarrior IDE on Layerscape processors (see
  AN12270).
- Loading a bootloader into SDRAM, waiting for it to initialize DDR, and
  then loading U-Boot. This is tricky, because the debugger must stop the
  boot after the bootloader has completed its work. Trying to load
  U-Boot too early can cause failure to boot. This is the method used by
  Xilinx with its Zynq(MP) processors.
- Loading SPL with BOOT_DEVICE_RAM and breaking before SPL loads the
  image to load U-Boot at the appropriate place. This can be a bit
  tricky, because the load address is dependent on the header size. An
  elf with symbols must also be used in order to stop at the appropriate
  point. BOOT_DEVICE_SMH can be viewed as an extension of this process,
  where SPL automatically stops and tells the host where to place the
  image.

Signed-off-by: Sean Anderson <sean.anderson@seco.com>
This commit is contained in:
Sean Anderson 2022-03-22 16:59:19 -04:00 committed by Tom Rini
parent 12a05b3bcd
commit 8e1c9fe243
5 changed files with 96 additions and 5 deletions

View File

@ -403,11 +403,29 @@ config ARM_SMCCC
firmware (for example, PSCI) according to SMCCC.
config SEMIHOSTING
bool "support boot from semihosting"
bool "Support ARM semihosting"
help
In emulated environments, semihosting is a way for
the hosted environment to call out to the emulator to
retrieve files from the host machine.
Semihosting is a method for a target to communicate with a host
debugger. It uses special instructions which the debugger will trap
on and interpret. This allows U-Boot to read/write files, print to
the console, and execute arbitrary commands on the host system.
Enabling this option will add support for reading and writing files
on the host system. If you don't have a debugger attached then trying
to do this will likely cause U-Boot to hang. Say 'n' if you are unsure.
config SPL_SEMIHOSTING
bool "Support ARM semihosting in SPL"
depends on SPL
help
Semihosting is a method for a target to communicate with a host
debugger. It uses special instructions which the debugger will trap
on and interpret. This allows U-Boot to read/write files, print to
the console, and execute arbitrary commands on the host system.
Enabling this option will add support for reading and writing files
on the host system. If you don't have a debugger attached then trying
to do this will likely cause U-Boot to hang. Say 'n' if you are unsure.
config SYS_THUMB_BUILD
bool "Build U-Boot using the Thumb instruction set"

View File

@ -30,6 +30,7 @@ enum {
BOOT_DEVICE_DFU,
BOOT_DEVICE_XIP,
BOOT_DEVICE_BOOTROM,
BOOT_DEVICE_SMH,
BOOT_DEVICE_NONE
};
#endif

View File

@ -46,7 +46,7 @@ else
obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMSET) += memset.o
obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o
endif
obj-$(CONFIG_SEMIHOSTING) += semihosting.o
obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += semihosting.o
obj-y += bdinfo.o
obj-y += sections.o

View File

@ -28,6 +28,7 @@ obj-$(CONFIG_$(SPL_TPL_)USB_STORAGE) += spl_usb.o
obj-$(CONFIG_$(SPL_TPL_)FS_FAT) += spl_fat.o
obj-$(CONFIG_$(SPL_TPL_)FS_EXT4) += spl_ext.o
obj-$(CONFIG_$(SPL_TPL_)SATA) += spl_sata.o
obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += spl_semihosting.o
obj-$(CONFIG_$(SPL_TPL_)DFU) += spl_dfu.o
obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o
obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o

View File

@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
*/
#include <common.h>
#include <image.h>
#include <log.h>
#include <semihosting.h>
#include <spl.h>
static int smh_read_full(long fd, void *memp, size_t len)
{
long read;
read = smh_read(fd, memp, len);
if (read < 0)
return read;
if (read != len)
return -EIO;
return 0;
}
static int spl_smh_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME;
int ret;
long fd, len;
struct image_header *header =
spl_get_load_buffer(-sizeof(*header), sizeof(*header));
fd = smh_open(filename, MODE_READ | MODE_BINARY);
if (fd < 0) {
log_debug("could not open %s: %ld\n", filename, fd);
return fd;
}
ret = smh_flen(fd);
if (ret < 0) {
log_debug("could not get length of image: %d\n", ret);
goto out;
}
len = ret;
ret = smh_read_full(fd, header, sizeof(struct image_header));
if (ret) {
log_debug("could not read image header: %d\n", ret);
goto out;
}
ret = spl_parse_image_header(spl_image, bootdev, header);
if (ret) {
log_debug("failed to parse image header: %d\n", ret);
goto out;
}
ret = smh_seek(fd, 0);
if (ret) {
log_debug("could not seek to start of image: %d\n", ret);
goto out;
}
ret = smh_read_full(fd, (void *)spl_image->load_addr, len);
if (ret)
log_debug("could not read %s: %d\n", filename, ret);
out:
smh_close(fd);
return ret;
}
SPL_LOAD_IMAGE_METHOD("SEMIHOSTING", 0, BOOT_DEVICE_SMH, spl_smh_load_image);