summaryrefslogtreecommitdiff
path: root/common/load.c
blob: 3a0f8b6a225d9e0da05aaf3b09fa32806dc729e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * load.c - pull the payload into RAM. semihosting is the whole story
 * for now, the bios INT 13h of this loader: the host serves the file,
 * we read it at the fixed address and let the image header place it.
 *
 * Copyright (C) 2026 Bradley Morgan <brads@mainlining.org>
 */

#include <string.h>
#include <sys/types.h>
#include <stdint.h>
#include <debug.h>
#include <semihosting.h>
#include <boot.h>

int tb_load_semihosting(const char *fname, uintptr_t load_addr,
			struct tb_image *img)
{
	long fd, len, 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;
	}

	/* header first so placement is known before the big copy */
	ret = smh_read(fd, (void *)load_addr, 64);
	if (ret != 64) {
		smh_close(fd);
		return -3;
	}

	if (tb_image_setup(load_addr, img)) {
		smh_close(fd);
		return -4;
	}

	if (img->load != load_addr) {
		/* the image wants to sit elsewhere, copy the header there */
		memmove((void *)img->load, (void *)load_addr, 64);
	}

	ret = smh_read(fd, (void *)(img->load + 64), len - 64);
	if (ret != len - 64) {
		smh_close(fd);
		return -5;
	}

	smh_close(fd);
	return 0;
}

/*
 * the initrd path, no header, no placement math, bytes to the
 * address the dtb /chosen already names.
 */
int tb_load_raw(const char *fname, uintptr_t load_addr, size_t *sizep)
{
	long fd, len, 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;
	}

	ret = smh_read(fd, (void *)load_addr, len);
	smh_close(fd);

	if (ret != len)
		return -6;

	if (sizep)
		*sizep = (size_t)len;
	return 0;
}