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