]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
500856eb | 2 | /* |
923aa481 | 3 | * (C) Copyright 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com> |
500856eb RJ |
4 | */ |
5 | ||
6 | #include <common.h> | |
7 | #include <linux/types.h> | |
8 | #include <api_public.h> | |
9 | ||
10 | #include "glue.h" | |
11 | ||
12 | static int valid_sig(struct api_signature *sig) | |
13 | { | |
14 | uint32_t checksum; | |
15 | struct api_signature s; | |
16 | ||
17 | if (sig == NULL) | |
18 | return 0; | |
19 | /* | |
20 | * Clear the checksum field (in the local copy) so as to calculate the | |
21 | * CRC with the same initial contents as at the time when the sig was | |
22 | * produced | |
23 | */ | |
24 | s = *sig; | |
25 | s.checksum = 0; | |
26 | ||
27 | checksum = crc32(0, (unsigned char *)&s, sizeof(struct api_signature)); | |
28 | ||
29 | if (checksum != sig->checksum) | |
30 | return 0; | |
31 | ||
32 | return 1; | |
33 | } | |
34 | ||
35 | /* | |
36 | * Searches for the U-Boot API signature | |
37 | * | |
38 | * returns 1/0 depending on found/not found result | |
39 | */ | |
923aa481 RJ |
40 | int api_search_sig(struct api_signature **sig) |
41 | { | |
500856eb | 42 | unsigned char *sp; |
b84d7d8f RJ |
43 | uint32_t search_start = 0; |
44 | uint32_t search_end = 0; | |
500856eb RJ |
45 | |
46 | if (sig == NULL) | |
47 | return 0; | |
48 | ||
b84d7d8f RJ |
49 | if (search_hint == 0) |
50 | search_hint = 255 * 1024 * 1024; | |
500856eb | 51 | |
b84d7d8f RJ |
52 | search_start = search_hint & ~0x000fffff; |
53 | search_end = search_start + API_SEARCH_LEN - API_SIG_MAGLEN; | |
54 | ||
55 | sp = (unsigned char *)search_start; | |
56 | while ((sp + API_SIG_MAGLEN) < (unsigned char *)search_end) { | |
500856eb RJ |
57 | if (!memcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) { |
58 | *sig = (struct api_signature *)sp; | |
59 | if (valid_sig(*sig)) | |
60 | return 1; | |
61 | } | |
62 | sp += API_SIG_MAGLEN; | |
63 | } | |
64 | ||
65 | *sig = NULL; | |
66 | return 0; | |
67 | } | |
68 | ||
69 | /**************************************** | |
70 | * | |
71 | * console | |
72 | * | |
73 | ****************************************/ | |
74 | ||
75 | int ub_getc(void) | |
76 | { | |
77 | int c; | |
78 | ||
78757d52 | 79 | if (!syscall(API_GETC, NULL, &c)) |
500856eb RJ |
80 | return -1; |
81 | ||
82 | return c; | |
83 | } | |
84 | ||
85 | int ub_tstc(void) | |
86 | { | |
87 | int t; | |
88 | ||
78757d52 | 89 | if (!syscall(API_TSTC, NULL, &t)) |
500856eb RJ |
90 | return -1; |
91 | ||
92 | return t; | |
93 | } | |
94 | ||
95 | void ub_putc(char c) | |
96 | { | |
78757d52 | 97 | syscall(API_PUTC, NULL, &c); |
500856eb RJ |
98 | } |
99 | ||
100 | void ub_puts(const char *s) | |
101 | { | |
78757d52 | 102 | syscall(API_PUTS, NULL, s); |
500856eb RJ |
103 | } |
104 | ||
105 | /**************************************** | |
106 | * | |
107 | * system | |
108 | * | |
109 | ****************************************/ | |
110 | ||
111 | void ub_reset(void) | |
112 | { | |
113 | syscall(API_RESET, NULL); | |
114 | } | |
115 | ||
923aa481 | 116 | static struct mem_region mr[UB_MAX_MR]; |
500856eb RJ |
117 | static struct sys_info si; |
118 | ||
119 | struct sys_info * ub_get_sys_info(void) | |
120 | { | |
121 | int err = 0; | |
122 | ||
123 | memset(&si, 0, sizeof(struct sys_info)); | |
124 | si.mr = mr; | |
923aa481 | 125 | si.mr_no = UB_MAX_MR; |
500856eb RJ |
126 | memset(&mr, 0, sizeof(mr)); |
127 | ||
78757d52 | 128 | if (!syscall(API_GET_SYS_INFO, &err, &si)) |
500856eb RJ |
129 | return NULL; |
130 | ||
131 | return ((err) ? NULL : &si); | |
132 | } | |
133 | ||
134 | /**************************************** | |
135 | * | |
136 | * timing | |
137 | * | |
138 | ****************************************/ | |
d3a6532c | 139 | |
500856eb RJ |
140 | void ub_udelay(unsigned long usec) |
141 | { | |
142 | syscall(API_UDELAY, NULL, &usec); | |
143 | } | |
144 | ||
145 | unsigned long ub_get_timer(unsigned long base) | |
146 | { | |
147 | unsigned long cur; | |
148 | ||
149 | if (!syscall(API_GET_TIMER, NULL, &cur, &base)) | |
150 | return 0; | |
151 | ||
152 | return cur; | |
153 | } | |
154 | ||
155 | ||
156 | /**************************************************************************** | |
157 | * | |
158 | * devices | |
159 | * | |
923aa481 | 160 | * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1 |
500856eb RJ |
161 | * |
162 | ***************************************************************************/ | |
163 | ||
923aa481 | 164 | static struct device_info devices[UB_MAX_DEV]; |
500856eb RJ |
165 | |
166 | struct device_info * ub_dev_get(int i) | |
167 | { | |
923aa481 | 168 | return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]); |
500856eb RJ |
169 | } |
170 | ||
171 | /* | |
172 | * Enumerates the devices: fills out device_info elements in the devices[] | |
173 | * array. | |
174 | * | |
175 | * returns: number of devices found | |
176 | */ | |
177 | int ub_dev_enum(void) | |
178 | { | |
179 | struct device_info *di; | |
180 | int n = 0; | |
181 | ||
923aa481 | 182 | memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV); |
500856eb RJ |
183 | di = &devices[0]; |
184 | ||
185 | if (!syscall(API_DEV_ENUM, NULL, di)) | |
186 | return 0; | |
187 | ||
188 | while (di->cookie != NULL) { | |
189 | ||
923aa481 | 190 | if (++n >= UB_MAX_DEV) |
500856eb RJ |
191 | break; |
192 | ||
193 | /* take another device_info */ | |
194 | di++; | |
195 | ||
196 | /* pass on the previous cookie */ | |
197 | di->cookie = devices[n - 1].cookie; | |
198 | ||
199 | if (!syscall(API_DEV_ENUM, NULL, di)) | |
200 | return 0; | |
201 | } | |
202 | ||
203 | return n; | |
204 | } | |
205 | ||
206 | /* | |
207 | * handle: 0-based id of the device | |
208 | * | |
209 | * returns: 0 when OK, err otherwise | |
210 | */ | |
211 | int ub_dev_open(int handle) | |
212 | { | |
213 | struct device_info *di; | |
214 | int err = 0; | |
215 | ||
923aa481 | 216 | if (handle < 0 || handle >= UB_MAX_DEV) |
500856eb RJ |
217 | return API_EINVAL; |
218 | ||
219 | di = &devices[handle]; | |
220 | ||
221 | if (!syscall(API_DEV_OPEN, &err, di)) | |
222 | return -1; | |
223 | ||
224 | return err; | |
225 | } | |
226 | ||
227 | int ub_dev_close(int handle) | |
228 | { | |
229 | struct device_info *di; | |
230 | ||
923aa481 | 231 | if (handle < 0 || handle >= UB_MAX_DEV) |
500856eb RJ |
232 | return API_EINVAL; |
233 | ||
234 | di = &devices[handle]; | |
235 | if (!syscall(API_DEV_CLOSE, NULL, di)) | |
236 | return -1; | |
237 | ||
238 | return 0; | |
239 | } | |
240 | ||
241 | /* | |
242 | * | |
243 | * Validates device for read/write, it has to: | |
244 | * | |
245 | * - have sane handle | |
246 | * - be opened | |
247 | * | |
248 | * returns: 0/1 accordingly | |
249 | */ | |
250 | static int dev_valid(int handle) | |
251 | { | |
923aa481 | 252 | if (handle < 0 || handle >= UB_MAX_DEV) |
500856eb RJ |
253 | return 0; |
254 | ||
255 | if (devices[handle].state != DEV_STA_OPEN) | |
256 | return 0; | |
257 | ||
258 | return 1; | |
259 | } | |
260 | ||
261 | static int dev_stor_valid(int handle) | |
262 | { | |
263 | if (!dev_valid(handle)) | |
264 | return 0; | |
265 | ||
266 | if (!(devices[handle].type & DEV_TYP_STOR)) | |
267 | return 0; | |
268 | ||
269 | return 1; | |
270 | } | |
271 | ||
923aa481 RJ |
272 | int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start, |
273 | lbasize_t *rlen) | |
500856eb RJ |
274 | { |
275 | struct device_info *di; | |
276 | lbasize_t act_len; | |
277 | int err = 0; | |
278 | ||
279 | if (!dev_stor_valid(handle)) | |
280 | return API_ENODEV; | |
281 | ||
282 | di = &devices[handle]; | |
283 | if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len)) | |
923aa481 | 284 | return API_ESYSC; |
500856eb | 285 | |
923aa481 RJ |
286 | if (!err && rlen) |
287 | *rlen = act_len; | |
500856eb | 288 | |
923aa481 | 289 | return err; |
500856eb RJ |
290 | } |
291 | ||
292 | static int dev_net_valid(int handle) | |
293 | { | |
294 | if (!dev_valid(handle)) | |
295 | return 0; | |
296 | ||
297 | if (devices[handle].type != DEV_TYP_NET) | |
298 | return 0; | |
299 | ||
300 | return 1; | |
301 | } | |
302 | ||
923aa481 | 303 | int ub_dev_recv(int handle, void *buf, int len, int *rlen) |
500856eb RJ |
304 | { |
305 | struct device_info *di; | |
306 | int err = 0, act_len; | |
307 | ||
308 | if (!dev_net_valid(handle)) | |
309 | return API_ENODEV; | |
310 | ||
311 | di = &devices[handle]; | |
312 | if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len)) | |
923aa481 | 313 | return API_ESYSC; |
500856eb | 314 | |
923aa481 RJ |
315 | if (!err && rlen) |
316 | *rlen = act_len; | |
500856eb | 317 | |
923aa481 | 318 | return (err); |
500856eb RJ |
319 | } |
320 | ||
321 | int ub_dev_send(int handle, void *buf, int len) | |
322 | { | |
323 | struct device_info *di; | |
324 | int err = 0; | |
325 | ||
326 | if (!dev_net_valid(handle)) | |
327 | return API_ENODEV; | |
328 | ||
329 | di = &devices[handle]; | |
330 | if (!syscall(API_DEV_WRITE, &err, di, buf, &len)) | |
923aa481 | 331 | return API_ESYSC; |
500856eb RJ |
332 | |
333 | return err; | |
334 | } | |
335 | ||
336 | /**************************************** | |
337 | * | |
338 | * env vars | |
339 | * | |
340 | ****************************************/ | |
341 | ||
342 | char * ub_env_get(const char *name) | |
343 | { | |
344 | char *value; | |
345 | ||
78757d52 | 346 | if (!syscall(API_ENV_GET, NULL, name, &value)) |
500856eb RJ |
347 | return NULL; |
348 | ||
349 | return value; | |
350 | } | |
351 | ||
352 | void ub_env_set(const char *name, char *value) | |
353 | { | |
78757d52 | 354 | syscall(API_ENV_SET, NULL, name, value); |
500856eb RJ |
355 | } |
356 | ||
500856eb RJ |
357 | static char env_name[256]; |
358 | ||
359 | const char * ub_env_enum(const char *last) | |
360 | { | |
361 | const char *env, *str; | |
362 | int i; | |
363 | ||
364 | env = NULL; | |
365 | ||
366 | /* | |
367 | * It's OK to pass only the name piece as last (and not the whole | |
368 | * 'name=val' string), since the API_ENUM_ENV call uses envmatch() | |
369 | * internally, which handles such case | |
370 | */ | |
78757d52 | 371 | if (!syscall(API_ENV_ENUM, NULL, last, &env)) |
500856eb RJ |
372 | return NULL; |
373 | ||
374 | if (!env) | |
375 | /* no more env. variables to enumerate */ | |
376 | return NULL; | |
377 | ||
378 | /* next enumerated env var */ | |
379 | memset(env_name, 0, 256); | |
380 | for (i = 0, str = env; *str != '=' && *str != '\0';) | |
381 | env_name[i++] = *str++; | |
382 | ||
383 | env_name[i] = '\0'; | |
384 | ||
385 | return env_name; | |
386 | } | |
a2a5729f CLC |
387 | |
388 | /**************************************** | |
389 | * | |
390 | * display | |
391 | * | |
392 | ****************************************/ | |
393 | ||
394 | int ub_display_get_info(int type, struct display_info *di) | |
395 | { | |
396 | int err = 0; | |
397 | ||
78757d52 | 398 | if (!syscall(API_DISPLAY_GET_INFO, &err, type, di)) |
a2a5729f CLC |
399 | return API_ESYSC; |
400 | ||
401 | return err; | |
402 | } | |
403 | ||
404 | int ub_display_draw_bitmap(ulong bitmap, int x, int y) | |
405 | { | |
406 | int err = 0; | |
407 | ||
408 | if (!syscall(API_DISPLAY_DRAW_BITMAP, &err, bitmap, x, y)) | |
409 | return API_ESYSC; | |
410 | ||
411 | return err; | |
412 | } | |
413 | ||
414 | void ub_display_clear(void) | |
415 | { | |
416 | syscall(API_DISPLAY_CLEAR, NULL); | |
417 | } | |
7e3e2056 RC |
418 | |
419 | __weak void *memcpy(void *dest, const void *src, size_t size) | |
420 | { | |
421 | unsigned char *dptr = dest; | |
422 | const unsigned char *ptr = src; | |
423 | const unsigned char *end = src + size; | |
424 | ||
425 | while (ptr < end) | |
426 | *dptr++ = *ptr++; | |
427 | ||
428 | return dest; | |
429 | } |