diff options
Diffstat (limited to 'common/load.c')
| -rw-r--r-- | common/load.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/common/load.c b/common/load.c new file mode 100644 index 0000000..4669c0b --- /dev/null +++ b/common/load.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * load.c - pull the payload into RAM. semihosting is the qemu path, + * flash and block devices follow the same shape once they exist. + * + * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org> + */ + +#include <string.h> +#include <sys/types.h> +#include <stdint.h> +#include <semihosting.h> +#include <boot.h> + +/* + * load fname into mem_base. the header decides the real placement, so + * we read the whole file first and let tb_image_setup place it. + */ +int tb_load_semihosting(const char *fname, uintptr_t load_addr, + uintptr_t mem_base, uint32 mem_size, + struct tb_image *img) +{ + struct Image_header *ih = (struct Image_header *)load_addr; + long fd; + long len; + long ret; + + fd = smh_open(fname, MODE_READ | MODE_BINARY); + if (fd < 0) + return fd; + + len = smh_flen(fd); + if (len < 0) { + smh_close(fd); + return len; + } + + if ((uint32)len > mem_size) { + smh_close(fd); + return -2; + } + + /* header first so placement is known before the big copy */ + ret = smh_read(fd, (void *)load_addr, sizeof(*ih)); + if (ret != sizeof(*ih)) { + smh_close(fd); + return -3; + } + + if (tb_image_setup(load_addr, mem_base, mem_size, img)) { + smh_close(fd); + return -4; + } + + if (img->load != load_addr) { + /* the image wants to sit elsewhere, copy it there */ + memmove((void *)img->load, (void *)load_addr, + sizeof(*ih)); + } + + ret = smh_read(fd, (void *)(img->load + sizeof(*ih)), + len - sizeof(*ih)); + if (ret != len - sizeof(*ih)) { + smh_close(fd); + return -5; + } + + smh_close(fd); + return 0; +} |
