xref: /rk3399_rockchip-uboot/arch/arm/lib/semihosting.c (revision 9be5c661beecdb8a9d90ab4869ddb501b4990dd9)
1261d2760SDarwin Rambo /*
2261d2760SDarwin Rambo  * Copyright 2014 Broadcom Corporation
3261d2760SDarwin Rambo  *
4261d2760SDarwin Rambo  * SPDX-License-Identifier:	GPL-2.0+
5261d2760SDarwin Rambo  */
6261d2760SDarwin Rambo 
7261d2760SDarwin Rambo /*
8261d2760SDarwin Rambo  * Minimal semihosting implementation for reading files into memory. If more
9261d2760SDarwin Rambo  * features like writing files or console output are required they can be
10261d2760SDarwin Rambo  * added later. This code has been tested on arm64/aarch64 fastmodel only.
11261d2760SDarwin Rambo  * An untested placeholder exists for armv7 architectures, but since they
12261d2760SDarwin Rambo  * are commonly available in silicon now, fastmodel usage makes less sense
13261d2760SDarwin Rambo  * for them.
14261d2760SDarwin Rambo  */
15261d2760SDarwin Rambo #include <common.h>
16261d2760SDarwin Rambo #include <asm/semihosting.h>
17261d2760SDarwin Rambo 
18261d2760SDarwin Rambo #define SYSOPEN		0x01
19261d2760SDarwin Rambo #define SYSCLOSE	0x02
20261d2760SDarwin Rambo #define SYSREAD		0x06
21261d2760SDarwin Rambo #define SYSFLEN		0x0C
22261d2760SDarwin Rambo 
23261d2760SDarwin Rambo #define MODE_READ	0x0
24261d2760SDarwin Rambo #define MODE_READBIN	0x1
25261d2760SDarwin Rambo 
26261d2760SDarwin Rambo /*
27261d2760SDarwin Rambo  * Call the handler
28261d2760SDarwin Rambo  */
294e1ef150SLinus Walleij static long smh_trap(unsigned int sysnum, void *addr)
30261d2760SDarwin Rambo {
314e1ef150SLinus Walleij 	register long result asm("r0");
32261d2760SDarwin Rambo #if defined(CONFIG_ARM64)
33261d2760SDarwin Rambo 	asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr));
34261d2760SDarwin Rambo #else
35261d2760SDarwin Rambo 	/* Note - untested placeholder */
36261d2760SDarwin Rambo 	asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr));
37261d2760SDarwin Rambo #endif
38261d2760SDarwin Rambo 	return result;
39261d2760SDarwin Rambo }
40261d2760SDarwin Rambo 
41261d2760SDarwin Rambo /*
42*9be5c661SLinus Walleij  * Open a file on the host. Mode is "r" or "rb" currently. Returns a file
43*9be5c661SLinus Walleij  * descriptor or -1 on error.
44*9be5c661SLinus Walleij  */
45*9be5c661SLinus Walleij static long smh_open(const char *fname, char *modestr)
46*9be5c661SLinus Walleij {
47*9be5c661SLinus Walleij 	long fd;
48*9be5c661SLinus Walleij 	unsigned long mode;
49*9be5c661SLinus Walleij 	struct smh_open_s {
50*9be5c661SLinus Walleij 		const char *fname;
51*9be5c661SLinus Walleij 		unsigned long mode;
52*9be5c661SLinus Walleij 		size_t len;
53*9be5c661SLinus Walleij 	} open;
54*9be5c661SLinus Walleij 
55*9be5c661SLinus Walleij 	debug("%s: file \'%s\', mode \'%s\'\n", __func__, fname, modestr);
56*9be5c661SLinus Walleij 
57*9be5c661SLinus Walleij 	/* Check the file mode */
58*9be5c661SLinus Walleij 	if (!(strcmp(modestr, "r"))) {
59*9be5c661SLinus Walleij 		mode = MODE_READ;
60*9be5c661SLinus Walleij 	} else if (!(strcmp(modestr, "rb"))) {
61*9be5c661SLinus Walleij 		mode = MODE_READBIN;
62*9be5c661SLinus Walleij 	} else {
63*9be5c661SLinus Walleij 		printf("%s: ERROR mode \'%s\' not supported\n", __func__,
64*9be5c661SLinus Walleij 		       modestr);
65*9be5c661SLinus Walleij 		return -1;
66*9be5c661SLinus Walleij 	}
67*9be5c661SLinus Walleij 
68*9be5c661SLinus Walleij 	open.fname = fname;
69*9be5c661SLinus Walleij 	open.len = strlen(fname);
70*9be5c661SLinus Walleij 	open.mode = mode;
71*9be5c661SLinus Walleij 
72*9be5c661SLinus Walleij 	/* Open the file on the host */
73*9be5c661SLinus Walleij 	fd = smh_trap(SYSOPEN, &open);
74*9be5c661SLinus Walleij 	if (fd == -1)
75*9be5c661SLinus Walleij 		printf("%s: ERROR fd %ld for file \'%s\'\n", __func__, fd,
76*9be5c661SLinus Walleij 		       fname);
77*9be5c661SLinus Walleij 
78*9be5c661SLinus Walleij 	return fd;
79*9be5c661SLinus Walleij }
80*9be5c661SLinus Walleij 
81*9be5c661SLinus Walleij /*
82*9be5c661SLinus Walleij  * Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure
83*9be5c661SLinus Walleij  */
84*9be5c661SLinus Walleij static long smh_read(long fd, void *memp, size_t len)
85*9be5c661SLinus Walleij {
86*9be5c661SLinus Walleij 	long ret;
87*9be5c661SLinus Walleij 	struct smh_read_s {
88*9be5c661SLinus Walleij 		long fd;
89*9be5c661SLinus Walleij 		void *memp;
90*9be5c661SLinus Walleij 		size_t len;
91*9be5c661SLinus Walleij 	} read;
92*9be5c661SLinus Walleij 
93*9be5c661SLinus Walleij 	debug("%s: fd %ld, memp %p, len %lu\n", __func__, fd, memp, len);
94*9be5c661SLinus Walleij 
95*9be5c661SLinus Walleij 	read.fd = fd;
96*9be5c661SLinus Walleij 	read.memp = memp;
97*9be5c661SLinus Walleij 	read.len = len;
98*9be5c661SLinus Walleij 
99*9be5c661SLinus Walleij 	ret = smh_trap(SYSREAD, &read);
100*9be5c661SLinus Walleij 	if (ret < 0) {
101*9be5c661SLinus Walleij 		/*
102*9be5c661SLinus Walleij 		 * The ARM handler allows for returning partial lengths,
103*9be5c661SLinus Walleij 		 * but in practice this never happens so rather than create
104*9be5c661SLinus Walleij 		 * hard to maintain partial read loops and such, just fail
105*9be5c661SLinus Walleij 		 * with an error message.
106*9be5c661SLinus Walleij 		 */
107*9be5c661SLinus Walleij 		printf("%s: ERROR ret %ld, fd %ld, len %lu memp %p\n",
108*9be5c661SLinus Walleij 		       __func__, ret, fd, len, memp);
109*9be5c661SLinus Walleij 		return -1;
110*9be5c661SLinus Walleij 	}
111*9be5c661SLinus Walleij 
112*9be5c661SLinus Walleij 	return 0;
113*9be5c661SLinus Walleij }
114*9be5c661SLinus Walleij 
115*9be5c661SLinus Walleij /*
116*9be5c661SLinus Walleij  * Close the file using the file descriptor
117*9be5c661SLinus Walleij  */
118*9be5c661SLinus Walleij static long smh_close(long fd)
119*9be5c661SLinus Walleij {
120*9be5c661SLinus Walleij 	long ret;
121*9be5c661SLinus Walleij 
122*9be5c661SLinus Walleij 	debug("%s: fd %ld\n", __func__, fd);
123*9be5c661SLinus Walleij 
124*9be5c661SLinus Walleij 	ret = smh_trap(SYSCLOSE, &fd);
125*9be5c661SLinus Walleij 	if (ret == -1)
126*9be5c661SLinus Walleij 		printf("%s: ERROR fd %ld\n", __func__, fd);
127*9be5c661SLinus Walleij 
128*9be5c661SLinus Walleij 	return ret;
129*9be5c661SLinus Walleij }
130*9be5c661SLinus Walleij 
131*9be5c661SLinus Walleij /*
132*9be5c661SLinus Walleij  * Get the file length from the file descriptor
133*9be5c661SLinus Walleij  */
134*9be5c661SLinus Walleij static long smh_len_fd(long fd)
135*9be5c661SLinus Walleij {
136*9be5c661SLinus Walleij 	long ret;
137*9be5c661SLinus Walleij 
138*9be5c661SLinus Walleij 	debug("%s: fd %ld\n", __func__, fd);
139*9be5c661SLinus Walleij 
140*9be5c661SLinus Walleij 	ret = smh_trap(SYSFLEN, &fd);
141*9be5c661SLinus Walleij 	if (ret == -1)
142*9be5c661SLinus Walleij 		printf("%s: ERROR ret %ld, fd %ld\n", __func__, ret, fd);
143*9be5c661SLinus Walleij 
144*9be5c661SLinus Walleij 	return ret;
145*9be5c661SLinus Walleij }
146*9be5c661SLinus Walleij 
147*9be5c661SLinus Walleij /*
148261d2760SDarwin Rambo  * Open, load a file into memory, and close it. Check that the available space
149261d2760SDarwin Rambo  * is sufficient to store the entire file. Return the bytes actually read from
150261d2760SDarwin Rambo  * the file as seen by the read function. The verbose flag enables some extra
151261d2760SDarwin Rambo  * printing of successful read status.
152261d2760SDarwin Rambo  */
153261d2760SDarwin Rambo int smh_load(const char *fname, void *memp, int avail, int verbose)
154261d2760SDarwin Rambo {
1554e1ef150SLinus Walleij 	long ret;
1564e1ef150SLinus Walleij 	long fd;
1574e1ef150SLinus Walleij 	size_t len;
158261d2760SDarwin Rambo 
159261d2760SDarwin Rambo 	ret = -1;
160261d2760SDarwin Rambo 
161261d2760SDarwin Rambo 	debug("%s: fname \'%s\', avail %u, memp %p\n", __func__, fname,
162261d2760SDarwin Rambo 	      avail, memp);
163261d2760SDarwin Rambo 
164261d2760SDarwin Rambo 	/* Open the file */
165261d2760SDarwin Rambo 	fd = smh_open(fname, "rb");
166261d2760SDarwin Rambo 	if (fd == -1)
1674e1ef150SLinus Walleij 		return -1;
168261d2760SDarwin Rambo 
169261d2760SDarwin Rambo 	/* Get the file length */
170261d2760SDarwin Rambo 	ret = smh_len_fd(fd);
171261d2760SDarwin Rambo 	if (ret == -1) {
172261d2760SDarwin Rambo 		smh_close(fd);
1734e1ef150SLinus Walleij 		return -1;
174261d2760SDarwin Rambo 	}
175261d2760SDarwin Rambo 
176261d2760SDarwin Rambo 	/* Check that the file will fit in the supplied buffer */
177261d2760SDarwin Rambo 	if (ret > avail) {
1784e1ef150SLinus Walleij 		printf("%s: ERROR ret %ld, avail %u\n", __func__, ret,
179261d2760SDarwin Rambo 		       avail);
180261d2760SDarwin Rambo 		smh_close(fd);
1814e1ef150SLinus Walleij 		return -1;
182261d2760SDarwin Rambo 	}
183261d2760SDarwin Rambo 
184261d2760SDarwin Rambo 	len = ret;
185261d2760SDarwin Rambo 
186261d2760SDarwin Rambo 	/* Read the file into the buffer */
187261d2760SDarwin Rambo 	ret = smh_read(fd, memp, len);
188261d2760SDarwin Rambo 	if (ret == 0) {
189261d2760SDarwin Rambo 		/* Print successful load information if requested */
190261d2760SDarwin Rambo 		if (verbose) {
191261d2760SDarwin Rambo 			printf("\n%s\n", fname);
192261d2760SDarwin Rambo 			printf("    0x%8p dest\n", memp);
1934e1ef150SLinus Walleij 			printf("    0x%08lx size\n", len);
194261d2760SDarwin Rambo 			printf("    0x%08x avail\n", avail);
195261d2760SDarwin Rambo 		}
196261d2760SDarwin Rambo 	}
197261d2760SDarwin Rambo 
198261d2760SDarwin Rambo 	/* Close the file */
199261d2760SDarwin Rambo 	smh_close(fd);
200261d2760SDarwin Rambo 
201261d2760SDarwin Rambo 	return ret;
202261d2760SDarwin Rambo }
203261d2760SDarwin Rambo 
204261d2760SDarwin Rambo /*
205261d2760SDarwin Rambo  * Get the file length from the filename
206261d2760SDarwin Rambo  */
2074e1ef150SLinus Walleij long smh_len(const char *fname)
208261d2760SDarwin Rambo {
2094e1ef150SLinus Walleij 	long ret;
2104e1ef150SLinus Walleij 	long fd;
2114e1ef150SLinus Walleij 	long len;
212261d2760SDarwin Rambo 
213261d2760SDarwin Rambo 	debug("%s: file \'%s\'\n", __func__, fname);
214261d2760SDarwin Rambo 
215261d2760SDarwin Rambo 	/* Open the file */
216261d2760SDarwin Rambo 	fd = smh_open(fname, "rb");
2174e1ef150SLinus Walleij 	if (fd < 0)
218261d2760SDarwin Rambo 		return fd;
219261d2760SDarwin Rambo 
220261d2760SDarwin Rambo 	/* Get the file length */
221261d2760SDarwin Rambo 	len = smh_len_fd(fd);
2224e1ef150SLinus Walleij 	if (len < 0) {
2234e1ef150SLinus Walleij 		smh_close(fd);
2244e1ef150SLinus Walleij 		return len;
2254e1ef150SLinus Walleij 	}
226261d2760SDarwin Rambo 
227261d2760SDarwin Rambo 	/* Close the file */
228261d2760SDarwin Rambo 	ret = smh_close(fd);
2294e1ef150SLinus Walleij 	if (ret < 0)
230261d2760SDarwin Rambo 		return ret;
231261d2760SDarwin Rambo 
2324e1ef150SLinus Walleij 	debug("%s: returning len %ld\n", __func__, len);
233261d2760SDarwin Rambo 
234261d2760SDarwin Rambo 	/* Return the file length (or -1 error indication) */
235261d2760SDarwin Rambo 	return len;
236261d2760SDarwin Rambo }
237