xref: /freebsd/stand/uboot/glue.c (revision f81cdf24ba5436367377f7c8e8f51f6df2a75ca7)
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
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
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
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
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
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
163 ub_putc(const char c)
164 {
165 
166 	syscall(API_PUTC, NULL, &c);
167 }
168 
169 void
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
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 *
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
217 ub_udelay(unsigned long usec)
218 {
219 
220 	syscall(API_UDELAY, NULL, &usec);
221 }
222 
223 unsigned long
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 *
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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
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 *
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
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 *
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