blob: cb5dc26ac3fa283ab58c27c2876cddedc94b0efc [file] [log] [blame]
Darwin Rambod32d4112014-06-09 11:12:59 -07001/*
2 * Copyright 2014 Broadcom Corporation
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7/*
8 * Minimal semihosting implementation for reading files into memory. If more
9 * features like writing files or console output are required they can be
10 * added later. This code has been tested on arm64/aarch64 fastmodel only.
11 * An untested placeholder exists for armv7 architectures, but since they
12 * are commonly available in silicon now, fastmodel usage makes less sense
13 * for them.
14 */
15#include <common.h>
16#include <asm/semihosting.h>
17
18#define SYSOPEN 0x01
19#define SYSCLOSE 0x02
20#define SYSREAD 0x06
21#define SYSFLEN 0x0C
22
23#define MODE_READ 0x0
24#define MODE_READBIN 0x1
25
26/*
27 * Call the handler
28 */
29static int smh_trap(unsigned int sysnum, void *addr)
30{
31 register int result asm("r0");
32#if defined(CONFIG_ARM64)
33 asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr));
34#else
35 /* Note - untested placeholder */
36 asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr));
37#endif
38 return result;
39}
40
41/*
42 * Open, load a file into memory, and close it. Check that the available space
43 * is sufficient to store the entire file. Return the bytes actually read from
44 * the file as seen by the read function. The verbose flag enables some extra
45 * printing of successful read status.
46 */
47int smh_load(const char *fname, void *memp, int avail, int verbose)
48{
49 int ret, fd, len;
50
51 ret = -1;
52
53 debug("%s: fname \'%s\', avail %u, memp %p\n", __func__, fname,
54 avail, memp);
55
56 /* Open the file */
57 fd = smh_open(fname, "rb");
58 if (fd == -1)
59 return ret;
60
61 /* Get the file length */
62 ret = smh_len_fd(fd);
63 if (ret == -1) {
64 smh_close(fd);
65 return ret;
66 }
67
68 /* Check that the file will fit in the supplied buffer */
69 if (ret > avail) {
70 printf("%s: ERROR ret %d, avail %u\n", __func__, ret,
71 avail);
72 smh_close(fd);
73 return ret;
74 }
75
76 len = ret;
77
78 /* Read the file into the buffer */
79 ret = smh_read(fd, memp, len);
80 if (ret == 0) {
81 /* Print successful load information if requested */
82 if (verbose) {
83 printf("\n%s\n", fname);
84 printf(" 0x%8p dest\n", memp);
85 printf(" 0x%08x size\n", len);
86 printf(" 0x%08x avail\n", avail);
87 }
88 }
89
90 /* Close the file */
91 smh_close(fd);
92
93 return ret;
94}
95
96/*
97 * Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure
98 */
99int smh_read(int fd, void *memp, int len)
100{
101 int ret;
102 struct smh_read_s {
103 int fd;
104 void *memp;
105 int len;
106 } read;
107
108 debug("%s: fd %d, memp %p, len %d\n", __func__, fd, memp, len);
109
110 read.fd = fd;
111 read.memp = memp;
112 read.len = len;
113
114 ret = smh_trap(SYSREAD, &read);
115 if (ret == 0) {
116 return 0;
117 } else {
118 /*
119 * The ARM handler allows for returning partial lengths,
120 * but in practice this never happens so rather than create
121 * hard to maintain partial read loops and such, just fail
122 * with an error message.
123 */
124 printf("%s: ERROR ret %d, fd %d, len %u memp %p\n",
125 __func__, ret, fd, len, memp);
126 }
127 return ret;
128}
129
130/*
131 * Open a file on the host. Mode is "r" or "rb" currently. Returns a file
132 * descriptor or -1 on error.
133 */
134int smh_open(const char *fname, char *modestr)
135{
136 int ret, fd, mode;
137 struct smh_open_s {
138 const char *fname;
139 unsigned int mode;
140 unsigned int len;
141 } open;
142
143 debug("%s: file \'%s\', mode \'%s\'\n", __func__, fname, modestr);
144
145 ret = -1;
146
147 /* Check the file mode */
148 if (!(strcmp(modestr, "r"))) {
149 mode = MODE_READ;
150 } else if (!(strcmp(modestr, "rb"))) {
151 mode = MODE_READBIN;
152 } else {
153 printf("%s: ERROR mode \'%s\' not supported\n", __func__,
154 modestr);
155 return ret;
156 }
157
158 open.fname = fname;
159 open.len = strlen(fname);
160 open.mode = mode;
161
162 /* Open the file on the host */
163 fd = smh_trap(SYSOPEN, &open);
164 if (fd == -1)
165 printf("%s: ERROR fd %d for file \'%s\'\n", __func__, fd,
166 fname);
167
168 return fd;
169}
170
171/*
172 * Close the file using the file descriptor
173 */
174int smh_close(int fd)
175{
176 int ret;
177 long fdlong;
178
179 debug("%s: fd %d\n", __func__, fd);
180
181 fdlong = (long)fd;
182 ret = smh_trap(SYSCLOSE, &fdlong);
183 if (ret == -1)
184 printf("%s: ERROR fd %d\n", __func__, fd);
185
186 return ret;
187}
188
189/*
190 * Get the file length from the file descriptor
191 */
192int smh_len_fd(int fd)
193{
194 int ret;
195 long fdlong;
196
197 debug("%s: fd %d\n", __func__, fd);
198
199 fdlong = (long)fd;
200 ret = smh_trap(SYSFLEN, &fdlong);
201 if (ret == -1)
202 printf("%s: ERROR ret %d\n", __func__, ret);
203
204 return ret;
205}
206
207/*
208 * Get the file length from the filename
209 */
210int smh_len(const char *fname)
211{
212 int ret, fd, len;
213
214 debug("%s: file \'%s\'\n", __func__, fname);
215
216 /* Open the file */
217 fd = smh_open(fname, "rb");
218 if (fd == -1)
219 return fd;
220
221 /* Get the file length */
222 len = smh_len_fd(fd);
223
224 /* Close the file */
225 ret = smh_close(fd);
226 if (ret == -1)
227 return ret;
228
229 debug("%s: returning len %d\n", __func__, len);
230
231 /* Return the file length (or -1 error indication) */
232 return len;
233}