]> git.sur5r.net Git - u-boot/blob - arch/arm/lib/semihosting.c
Merge branch 'master' of git://git.denx.de/u-boot
[u-boot] / arch / arm / lib / semihosting.c
1 /*
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  */
29 static 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  */
47 int 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  */
99 int 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  */
134 int 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  */
174 int 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  */
192 int 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  */
210 int 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 }