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