1 /*-
2 * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/types.h>
28
29 #include <zlib.h>
30 #include <stand.h>
31 #include "api_public.h"
32 #include "glue.h"
33
34 #ifdef DEBUG
35 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
36 #else
37 #define debugf(fmt, args...)
38 #endif
39
40 /* Some random address used by U-Boot. */
41 extern long uboot_address;
42
43 static int
valid_sig(struct api_signature * sig)44 valid_sig(struct api_signature *sig)
45 {
46 uint32_t checksum;
47 struct api_signature s;
48
49 if (sig == NULL)
50 return (0);
51 /*
52 * Clear the checksum field (in the local copy) so as to calculate the
53 * CRC with the same initial contents as at the time when the sig was
54 * produced
55 */
56 s = *sig;
57 s.checksum = crc32(0, Z_NULL, 0);
58
59 checksum = crc32(s.checksum, (void *)&s, sizeof(struct api_signature));
60
61 if (checksum != sig->checksum)
62 return (0);
63
64 return (1);
65 }
66
67 /*
68 * Checks to see if API signature's address was given to us as a command line
69 * argument by U-Boot.
70 *
71 * returns 1/0 depending on found/not found result
72 */
73 int
api_parse_cmdline_sig(int argc,char ** argv,struct api_signature ** sig)74 api_parse_cmdline_sig(int argc, char **argv, struct api_signature **sig)
75 {
76 unsigned long api_address;
77 int c;
78
79 api_address = 0;
80 opterr = 0;
81 optreset = 1;
82 optind = 1;
83
84 while ((c = getopt (argc, argv, "a:")) != -1)
85 switch (c) {
86 case 'a':
87 api_address = strtoul(optarg, NULL, 16);
88 break;
89 default:
90 break;
91 }
92
93 if (api_address != 0) {
94 *sig = (struct api_signature *)api_address;
95 if (valid_sig(*sig))
96 return (1);
97 }
98
99 return (0);
100 }
101
102 /*
103 * Searches for the U-Boot API signature
104 *
105 * returns 1/0 depending on found/not found result
106 */
107 int
api_search_sig(struct api_signature ** sig)108 api_search_sig(struct api_signature **sig)
109 {
110 unsigned char *sp, *spend;
111
112 if (sig == NULL)
113 return (0);
114
115 if (uboot_address == 0)
116 uboot_address = 255 * 1024 * 1024;
117
118 sp = (void *)(uboot_address & API_SIG_SEARCH_MASK);
119 spend = sp + API_SIG_SEARCH_LEN - API_SIG_MAGLEN;
120
121 while (sp < spend) {
122 if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
123 *sig = (struct api_signature *)sp;
124 if (valid_sig(*sig))
125 return (1);
126 }
127 sp += API_SIG_MAGLEN;
128 }
129
130 *sig = NULL;
131 return (0);
132 }
133
134 /****************************************
135 *
136 * console
137 *
138 ****************************************/
139
140 int
ub_getc(void)141 ub_getc(void)
142 {
143 int c;
144
145 if (!syscall(API_GETC, NULL, &c))
146 return (-1);
147
148 return (c);
149 }
150
151 int
ub_tstc(void)152 ub_tstc(void)
153 {
154 int t;
155
156 if (!syscall(API_TSTC, NULL, &t))
157 return (-1);
158
159 return (t);
160 }
161
162 void
ub_putc(const char c)163 ub_putc(const char c)
164 {
165
166 syscall(API_PUTC, NULL, &c);
167 }
168
169 void
ub_puts(const char * s)170 ub_puts(const char *s)
171 {
172
173 syscall(API_PUTS, NULL, s);
174 }
175
176 /****************************************
177 *
178 * system
179 *
180 ****************************************/
181
182 void
ub_reset(void)183 ub_reset(void)
184 {
185
186 syscall(API_RESET, NULL);
187 while (1); /* fallback if API_RESET failed */
188 __unreachable();
189 }
190
191 static struct mem_region mr[UB_MAX_MR];
192 static struct sys_info si;
193
194 struct sys_info *
ub_get_sys_info(void)195 ub_get_sys_info(void)
196 {
197 int err = 0;
198
199 memset(&si, 0, sizeof(struct sys_info));
200 si.mr = mr;
201 si.mr_no = UB_MAX_MR;
202 memset(&mr, 0, sizeof(mr));
203
204 if (!syscall(API_GET_SYS_INFO, &err, &si))
205 return (NULL);
206
207 return ((err) ? NULL : &si);
208 }
209
210 /****************************************
211 *
212 * timing
213 *
214 ****************************************/
215
216 void
ub_udelay(unsigned long usec)217 ub_udelay(unsigned long usec)
218 {
219
220 syscall(API_UDELAY, NULL, &usec);
221 }
222
223 unsigned long
ub_get_timer(unsigned long base)224 ub_get_timer(unsigned long base)
225 {
226 unsigned long cur;
227
228 if (!syscall(API_GET_TIMER, NULL, &cur, &base))
229 return (0);
230
231 return (cur);
232 }
233
234 /****************************************************************************
235 *
236 * devices
237 *
238 * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
239 *
240 ***************************************************************************/
241
242 static struct device_info devices[UB_MAX_DEV];
243
244 struct device_info *
ub_dev_get(int i)245 ub_dev_get(int i)
246 {
247
248 return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
249 }
250
251 /*
252 * Enumerates the devices: fills out device_info elements in the devices[]
253 * array.
254 *
255 * returns: number of devices found
256 */
257 int
ub_dev_enum(void)258 ub_dev_enum(void)
259 {
260 struct device_info *di;
261 int n = 0;
262
263 memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV);
264 di = &devices[0];
265
266 if (!syscall(API_DEV_ENUM, NULL, di))
267 return (0);
268
269 while (di->cookie != NULL) {
270
271 if (++n >= UB_MAX_DEV)
272 break;
273
274 /* take another device_info */
275 di++;
276
277 /* pass on the previous cookie */
278 di->cookie = devices[n - 1].cookie;
279
280 if (!syscall(API_DEV_ENUM, NULL, di))
281 return (0);
282 }
283
284 return (n);
285 }
286
287 /*
288 * handle: 0-based id of the device
289 *
290 * returns: 0 when OK, err otherwise
291 */
292 int
ub_dev_open(int handle)293 ub_dev_open(int handle)
294 {
295 struct device_info *di;
296 int err = 0;
297
298 if (handle < 0 || handle >= UB_MAX_DEV)
299 return (API_EINVAL);
300
301 di = &devices[handle];
302 if (!syscall(API_DEV_OPEN, &err, di))
303 return (-1);
304
305 return (err);
306 }
307
308 int
ub_dev_close(int handle)309 ub_dev_close(int handle)
310 {
311 struct device_info *di;
312
313 if (handle < 0 || handle >= UB_MAX_DEV)
314 return (API_EINVAL);
315
316 di = &devices[handle];
317 if (!syscall(API_DEV_CLOSE, NULL, di))
318 return (-1);
319
320 return (0);
321 }
322
323 /*
324 * Validates device for read/write, it has to:
325 *
326 * - have sane handle
327 * - be opened
328 *
329 * returns: 0/1 accordingly
330 */
331 static int
dev_valid(int handle)332 dev_valid(int handle)
333 {
334
335 if (handle < 0 || handle >= UB_MAX_DEV)
336 return (0);
337
338 if (devices[handle].state != DEV_STA_OPEN)
339 return (0);
340
341 return (1);
342 }
343
344 static int
dev_stor_valid(int handle)345 dev_stor_valid(int handle)
346 {
347
348 if (!dev_valid(handle))
349 return (0);
350
351 if (!(devices[handle].type & DEV_TYP_STOR))
352 return (0);
353
354 return (1);
355 }
356
357 int
ub_dev_read(int handle,void * buf,lbasize_t len,lbastart_t start,lbasize_t * rlen)358 ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start,
359 lbasize_t *rlen)
360 {
361 struct device_info *di;
362 lbasize_t act_len;
363 int err = 0;
364
365 if (!dev_stor_valid(handle))
366 return (API_ENODEV);
367
368 di = &devices[handle];
369 if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
370 return (API_ESYSC);
371
372 if (!err && rlen)
373 *rlen = act_len;
374
375 return (err);
376 }
377
378 static int
dev_net_valid(int handle)379 dev_net_valid(int handle)
380 {
381
382 if (!dev_valid(handle))
383 return (0);
384
385 if (devices[handle].type != DEV_TYP_NET)
386 return (0);
387
388 return (1);
389 }
390
391 int
ub_dev_recv(int handle,void * buf,int len,int * rlen)392 ub_dev_recv(int handle, void *buf, int len, int *rlen)
393 {
394 struct device_info *di;
395 int err = 0, act_len;
396
397 if (!dev_net_valid(handle))
398 return (API_ENODEV);
399
400 di = &devices[handle];
401 if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
402 return (API_ESYSC);
403
404 if (!err)
405 *rlen = act_len;
406
407 return (err);
408 }
409
410 int
ub_dev_send(int handle,void * buf,int len)411 ub_dev_send(int handle, void *buf, int len)
412 {
413 struct device_info *di;
414 int err = 0;
415
416 if (!dev_net_valid(handle))
417 return (API_ENODEV);
418
419 di = &devices[handle];
420 if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
421 return (API_ESYSC);
422
423 return (err);
424 }
425
426 char *
ub_stor_type(int type)427 ub_stor_type(int type)
428 {
429
430 if (type & DT_STOR_IDE)
431 return ("IDE");
432
433 if (type & DT_STOR_SCSI)
434 return ("SCSI");
435
436 if (type & DT_STOR_USB)
437 return ("USB");
438
439 if (type & DT_STOR_MMC)
440 return ("MMC");
441
442 if (type & DT_STOR_SATA)
443 return ("SATA");
444
445 return ("Unknown");
446 }
447
448 char *
ub_mem_type(int flags)449 ub_mem_type(int flags)
450 {
451
452 switch (flags & 0x000F) {
453 case MR_ATTR_FLASH:
454 return ("FLASH");
455 case MR_ATTR_DRAM:
456 return ("DRAM");
457 case MR_ATTR_SRAM:
458 return ("SRAM");
459 default:
460 return ("Unknown");
461 }
462 }
463
464 void
ub_dump_di(int handle)465 ub_dump_di(int handle)
466 {
467 struct device_info *di = ub_dev_get(handle);
468 int i;
469
470 printf("device info (%d):\n", handle);
471 printf(" cookie\t= %p\n", di->cookie);
472 printf(" type\t\t= 0x%08x\n", di->type);
473
474 if (di->type == DEV_TYP_NET) {
475 printf(" hwaddr\t= ");
476 for (i = 0; i < 6; i++)
477 printf("%02x ", di->di_net.hwaddr[i]);
478
479 printf("\n");
480
481 } else if (di->type & DEV_TYP_STOR) {
482 printf(" type\t\t= %s\n", ub_stor_type(di->type));
483 printf(" blk size\t\t= %ld\n", di->di_stor.block_size);
484 printf(" blk count\t\t= %ld\n", di->di_stor.block_count);
485 }
486 }
487
488 void
ub_dump_si(struct sys_info * si)489 ub_dump_si(struct sys_info *si)
490 {
491 int i;
492
493 printf("sys info:\n");
494 printf(" clkbus\t= %ld MHz\n", si->clk_bus / 1000 / 1000);
495 printf(" clkcpu\t= %ld MHz\n", si->clk_cpu / 1000 / 1000);
496 printf(" bar\t\t= 0x%08lx\n", si->bar);
497
498 printf("---\n");
499 for (i = 0; i < si->mr_no; i++) {
500 if (si->mr[i].flags == 0)
501 break;
502
503 printf(" start\t= 0x%08lx\n", si->mr[i].start);
504 printf(" size\t= 0x%08lx\n", si->mr[i].size);
505 printf(" type\t= %s\n", ub_mem_type(si->mr[i].flags));
506 printf("---\n");
507 }
508 }
509
510 /****************************************
511 *
512 * env vars
513 *
514 ****************************************/
515
516 char *
ub_env_get(const char * name)517 ub_env_get(const char *name)
518 {
519 char *value;
520
521 if (!syscall(API_ENV_GET, NULL, name, &value))
522 return (NULL);
523
524 return (value);
525 }
526
527 void
ub_env_set(const char * name,char * value)528 ub_env_set(const char *name, char *value)
529 {
530
531 syscall(API_ENV_SET, NULL, name, value);
532 }
533
534 static char env_name[256];
535
536 const char *
ub_env_enum(const char * last)537 ub_env_enum(const char *last)
538 {
539 const char *env, *str;
540 int i;
541
542 /*
543 * It's OK to pass only the name piece as last (and not the whole
544 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
545 * internally, which handles such case
546 */
547 env = NULL;
548 if (!syscall(API_ENV_ENUM, NULL, last, &env))
549 return (NULL);
550
551 if (env == NULL || last == env)
552 /* no more env. variables to enumerate */
553 return (NULL);
554
555 /* next enumerated env var */
556 memset(env_name, 0, 256);
557 for (i = 0, str = env; *str != '=' && *str != '\0';)
558 env_name[i++] = *str++;
559
560 env_name[i] = '\0';
561
562 return (env_name);
563 }
564