glue.c revision 177108
119304Speter/*-
219304Speter * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
319304Speter * All rights reserved.
419304Speter *
519304Speter * Redistribution and use in source and binary forms, with or without
619304Speter * modification, are permitted provided that the following conditions
719304Speter * are met:
819304Speter * 1. Redistributions of source code must retain the above copyright
919304Speter *    notice, this list of conditions and the following disclaimer.
1019304Speter * 2. Redistributions in binary form must reproduce the above copyright
1119304Speter *    notice, this list of conditions and the following disclaimer in the
1219304Speter *    documentation and/or other materials provided with the distribution.
13254225Speter *
1419304Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1519304Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1619304Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1719304Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1819304Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1919304Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2019304Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2119304Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2219304Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2319304Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2419304Speter * SUCH DAMAGE.
2519304Speter */
2619304Speter
2719304Speter#include <sys/cdefs.h>
2819304Speter__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/glue.c 177108 2008-03-12 16:01:34Z raj $");
2919304Speter
3019304Speter#include <stand.h>
3119304Speter#include "api_public.h"
3219304Speter#include "glue.h"
3319304Speter
3419304Speter#define DEBUG
3519304Speter#undef DEBUG
3619304Speter
37254225Speter#ifdef DEBUG
3819304Speter#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
3919304Speter#else
4019304Speter#define debugf(fmt, args...)
4119304Speter#endif
4219304Speter
4319304Speter/* Some random address used by U-Boot. */
4419304Speterextern long		uboot_address;
4519304Speter
4619304Speter/* crc32 stuff stolen from lib/libdisk/write_ia64_disk.c */
4719304Speterstatic uint32_t crc32_tab[] = {
4819304Speter	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
4919304Speter	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
5019304Speter	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
5119304Speter	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
5219304Speter	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
5319304Speter	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
5419304Speter	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
5519304Speter	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
5619304Speter	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
5719304Speter	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
5819304Speter	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
5919304Speter	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
60254225Speter	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
61254225Speter	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
62254225Speter	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
63254225Speter	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
64254225Speter	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
6519304Speter	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
6619304Speter	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
6719304Speter	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
6819304Speter	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
6919304Speter	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
7019304Speter	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
7119304Speter	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
7219304Speter	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
7319304Speter	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
7419304Speter	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
7519304Speter	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
7619304Speter	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
7719304Speter	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
7819304Speter	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
7919304Speter	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
8019304Speter	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
8119304Speter	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
8219304Speter	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
8319304Speter	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
8419304Speter	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
85254225Speter	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
8619304Speter	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
8719304Speter	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
8819304Speter	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
8919304Speter	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
9019304Speter	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
9119304Speter};
9219304Speter
9319304Speterstatic uint32_t
9419304Spetercrc32(const void *buf, size_t size)
95254225Speter{
96254225Speter	const uint8_t *p;
9719304Speter	uint32_t crc;
9819304Speter
9919304Speter	p = buf;
10019304Speter	crc = ~0U;
10119304Speter
10219304Speter	while (size--)
10319304Speter		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
10419304Speter
10519304Speter	return (crc ^ ~0U);
10619304Speter}
10719304Speter
10819304Speter
10919304Speterstatic int valid_sig(struct api_signature *sig)
11019304Speter{
11119304Speter	uint32_t checksum;
11219304Speter	struct api_signature s;
11319304Speter
11419304Speter	if (sig == NULL)
11519304Speter		return (0);
116254225Speter	/*
11719304Speter	 * Clear the checksum field (in the local copy) so as to calculate the
11819304Speter	 * CRC with the same initial contents as at the time when the sig was
119254225Speter	 * produced
120254225Speter	 */
12119304Speter	s = *sig;
12219304Speter	s.checksum = 0;
12319304Speter
12419304Speter	checksum = crc32((void *)&s, sizeof(struct api_signature));
12519304Speter
12619304Speter	if (checksum != sig->checksum)
12719304Speter		return (0);
12819304Speter
12919304Speter	return (1);
130}
131
132/*
133 * Searches for the U-Boot API signature
134 *
135 * returns 1/0 depending on found/not found result
136 */
137int api_search_sig(struct api_signature **sig) {
138
139	unsigned char *sp, *spend;
140
141	if (sig == NULL)
142		return (0);
143
144	if (uboot_address == 0)
145		uboot_address = 255 * 1024 * 1024;
146
147	sp = (void *)(uboot_address & ~0x000fffff);
148	spend = sp + 0x00100000 - API_SIG_MAGLEN;
149	while (sp < spend) {
150		if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
151			*sig = (struct api_signature *)sp;
152			if (valid_sig(*sig))
153				return (1);
154		}
155		sp += API_SIG_MAGLEN;
156	}
157
158	*sig = NULL;
159	return (0);
160}
161
162/****************************************
163 *
164 * console
165 *
166 ****************************************/
167
168int ub_getc(void)
169{
170	int c;
171
172	if (!syscall(API_GETC, NULL, (uint32_t)&c))
173		return (-1);
174
175	return c;
176}
177
178int ub_tstc(void)
179{
180	int t;
181
182	if (!syscall(API_TSTC, NULL, (uint32_t)&t))
183		return (-1);
184
185	return t;
186}
187
188void ub_putc(char c)
189{
190	syscall(API_PUTC, NULL, (uint32_t)&c);
191}
192
193void ub_puts(const char *s)
194{
195	syscall(API_PUTS, NULL, (uint32_t)s);
196}
197
198/****************************************
199 *
200 * system
201 *
202 ****************************************/
203
204void ub_reset(void)
205{
206	syscall(API_RESET, NULL);
207}
208
209
210#define MR_MAX 5
211static struct mem_region mr[MR_MAX];
212static struct sys_info si;
213
214struct sys_info * ub_get_sys_info(void)
215{
216	int err = 0;
217
218	memset(&si, 0, sizeof(struct sys_info));
219	si.mr = mr;
220	si.mr_no = MR_MAX;
221	memset(&mr, 0, sizeof(mr));
222
223	if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
224		return (NULL);
225
226	return ((err) ? NULL : &si);
227}
228
229
230/****************************************
231 *
232 * timing
233 *
234 ****************************************/
235
236void ub_udelay(unsigned long usec)
237{
238
239	syscall(API_UDELAY, NULL, &usec);
240}
241
242unsigned long ub_get_timer(unsigned long base)
243{
244	unsigned long cur;
245
246	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
247		return (0);
248
249	return (cur);
250}
251
252
253/****************************************************************************
254 *
255 * devices
256 *
257 * Devices are identified by handles: numbers 0, 1, 2, ..., MAX_DEVS-1
258 *
259 ***************************************************************************/
260
261#define MAX_DEVS 6
262
263static struct device_info devices[MAX_DEVS];
264
265struct device_info * ub_dev_get(int i)
266{
267	return ((i < 0 || i >= MAX_DEVS) ? NULL : &devices[i]);
268}
269
270/*
271 * Enumerates the devices: fills out device_info elements in the devices[]
272 * array.
273 *
274 * returns:		number of devices found
275 */
276int ub_dev_enum(void)
277{
278	struct device_info *di;
279	int n = 0;
280
281	memset(&devices, 0, sizeof(struct device_info) * MAX_DEVS);
282	di = &devices[0];
283
284	if (!syscall(API_DEV_ENUM, NULL, di))
285		return (0);
286
287	while (di->cookie != NULL) {
288
289		if (++n >= MAX_DEVS)
290			break;
291
292		/* take another device_info */
293		di++;
294
295		/* pass on the previous cookie */
296		di->cookie = devices[n - 1].cookie;
297
298		if (!syscall(API_DEV_ENUM, NULL, di))
299			return 0;
300	}
301
302	return (n);
303}
304
305
306/*
307 * handle:	0-based id of the device
308 *
309 * returns:	0 when OK, err otherwise
310 */
311int ub_dev_open(int handle)
312{
313	struct device_info *di;
314	int err = 0;
315
316	if (handle < 0 || handle >= MAX_DEVS)
317		return (API_EINVAL);
318
319	di = &devices[handle];
320	if (!syscall(API_DEV_OPEN, &err, di))
321		return (-1);
322
323	return (err);
324}
325
326int ub_dev_close(int handle)
327{
328	struct device_info *di;
329
330	if (handle < 0 || handle >= MAX_DEVS)
331		return (API_EINVAL);
332
333	di = &devices[handle];
334	if (!syscall(API_DEV_CLOSE, NULL, di))
335		return (-1);
336
337	return (0);
338}
339
340/*
341 * Validates device for read/write, it has to:
342 *
343 * - have sane handle
344 * - be opened
345 *
346 * returns:	0/1 accordingly
347 */
348static int dev_valid(int handle)
349{
350
351	if (handle < 0 || handle >= MAX_DEVS)
352		return (0);
353
354	if (devices[handle].state != DEV_STA_OPEN)
355		return (0);
356
357	return (1);
358}
359
360static int dev_stor_valid(int handle)
361{
362
363	if (!dev_valid(handle))
364		return (0);
365
366	if (!(devices[handle].type & DEV_TYP_STOR))
367		return (0);
368
369	return (1);
370}
371
372int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start)
373{
374	struct device_info *di;
375	lbasize_t act_len;
376	int err = 0;
377
378	if (!dev_stor_valid(handle))
379		return (API_ENODEV);
380
381	di = &devices[handle];
382	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
383		return (-1);
384
385	if (err)
386		return (err);
387
388	if (act_len != len)
389		return (API_EIO);
390
391	return (0);
392}
393
394static int dev_net_valid(int handle)
395{
396
397	if (!dev_valid(handle))
398		return (0);
399
400	if (devices[handle].type != DEV_TYP_NET)
401		return (0);
402
403	return (1);
404}
405
406int ub_dev_recv(int handle, void *buf, int len)
407{
408	struct device_info *di;
409	int err = 0, act_len;
410
411	if (!dev_net_valid(handle))
412		return (API_ENODEV);
413
414	di = &devices[handle];
415	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
416		return (-1);
417
418	if (err)
419		return (-1);
420
421	return (act_len);
422}
423
424int ub_dev_send(int handle, void *buf, int len)
425{
426	struct device_info *di;
427	int err = 0;
428
429	if (!dev_net_valid(handle))
430		return (API_ENODEV);
431
432	di = &devices[handle];
433	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
434		return (-1);
435
436	return (err);
437}
438
439/****************************************
440 *
441 * env vars
442 *
443 ****************************************/
444
445char * ub_env_get(const char *name)
446{
447	char *value;
448
449	if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
450		return (NULL);
451
452	return (value);
453}
454
455void ub_env_set(const char *name, char *value)
456{
457
458	syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
459}
460
461
462static char env_name[256];
463
464const char * ub_env_enum(const char *last)
465{
466	const char *env, *str;
467	int i;
468
469	env = NULL;
470
471	/*
472	 * It's OK to pass only the name piece as last (and not the whole
473	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
474	 * internally, which handles such case
475	 */
476	if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
477		return (NULL);
478
479	if (!env)
480		/* no more env. variables to enumerate */
481		return (NULL);
482#if 0
483	if (last && strncmp(env, last, strlen(last)) == 0);
484		/* error, trying to enumerate non existing env. variable */
485		return NULL;
486#endif
487
488	/* next enumerated env var */
489	memset(env_name, 0, 256);
490	for (i = 0, str = env; *str != '=' && *str != '\0';)
491		env_name[i++] = *str++;
492
493	env_name[i] = '\0';
494
495	return (env_name);
496}
497