1176348Smarcel/*-
2182732Sraj * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3176348Smarcel * All rights reserved.
4176348Smarcel *
5176348Smarcel * Redistribution and use in source and binary forms, with or without
6176348Smarcel * modification, are permitted provided that the following conditions
7176348Smarcel * are met:
8176348Smarcel * 1. Redistributions of source code must retain the above copyright
9176348Smarcel *    notice, this list of conditions and the following disclaimer.
10176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11176348Smarcel *    notice, this list of conditions and the following disclaimer in the
12176348Smarcel *    documentation and/or other materials provided with the distribution.
13176348Smarcel *
14176348Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15176348Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16176348Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17176348Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18176348Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19176348Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20176348Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21176348Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22176348Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23176348Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24176348Smarcel * SUCH DAMAGE.
25176348Smarcel */
26176348Smarcel
27176348Smarcel#include <sys/cdefs.h>
28176348Smarcel__FBSDID("$FreeBSD: stable/11/stand/uboot/lib/glue.c 329175 2018-02-12 17:44:35Z kevans $");
29176348Smarcel
30233287Smarius#include <sys/types.h>
31233287Smarius
32233287Smarius#include <crc32.h>
33176348Smarcel#include <stand.h>
34176348Smarcel#include "api_public.h"
35176481Smarcel#include "glue.h"
36176348Smarcel
37176348Smarcel#ifdef DEBUG
38177152Sobrien#define	debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
39176348Smarcel#else
40177152Sobrien#define	debugf(fmt, args...)
41176348Smarcel#endif
42176348Smarcel
43176481Smarcel/* Some random address used by U-Boot. */
44182732Srajextern long uboot_address;
45176348Smarcel
46177152Sobrienstatic int
47177152Sobrienvalid_sig(struct api_signature *sig)
48176348Smarcel{
49176348Smarcel	uint32_t checksum;
50176348Smarcel	struct api_signature s;
51176348Smarcel
52176348Smarcel	if (sig == NULL)
53177108Sraj		return (0);
54176348Smarcel	/*
55176348Smarcel	 * Clear the checksum field (in the local copy) so as to calculate the
56176348Smarcel	 * CRC with the same initial contents as at the time when the sig was
57176348Smarcel	 * produced
58176348Smarcel	 */
59176348Smarcel	s = *sig;
60176348Smarcel	s.checksum = 0;
61176348Smarcel
62176348Smarcel	checksum = crc32((void *)&s, sizeof(struct api_signature));
63176348Smarcel
64176348Smarcel	if (checksum != sig->checksum)
65177108Sraj		return (0);
66176348Smarcel
67177108Sraj	return (1);
68176348Smarcel}
69176348Smarcel
70176348Smarcel/*
71296564Ssgalabov * Checks to see if API signature's address was given to us as a command line
72296564Ssgalabov * argument by U-Boot.
73296564Ssgalabov *
74296564Ssgalabov * returns 1/0 depending on found/not found result
75296564Ssgalabov */
76296564Ssgalabovint
77296564Ssgalabovapi_parse_cmdline_sig(int argc, char **argv, struct api_signature **sig)
78296564Ssgalabov{
79296564Ssgalabov	unsigned long api_address;
80296564Ssgalabov	int c;
81296564Ssgalabov
82296564Ssgalabov	api_address = 0;
83296564Ssgalabov	opterr = 0;
84296564Ssgalabov	optreset = 1;
85296564Ssgalabov	optind = 1;
86296564Ssgalabov
87296564Ssgalabov	while ((c = getopt (argc, argv, "a:")) != -1)
88296564Ssgalabov		switch (c) {
89296564Ssgalabov		case 'a':
90296564Ssgalabov			api_address = strtoul(optarg, NULL, 16);
91296564Ssgalabov			break;
92296564Ssgalabov		default:
93296564Ssgalabov			break;
94296564Ssgalabov		}
95296564Ssgalabov
96296564Ssgalabov	if (api_address != 0) {
97296564Ssgalabov		*sig = (struct api_signature *)api_address;
98296564Ssgalabov		if (valid_sig(*sig))
99296564Ssgalabov			return (1);
100296564Ssgalabov	}
101296564Ssgalabov
102296564Ssgalabov	return (0);
103296564Ssgalabov}
104296564Ssgalabov
105296564Ssgalabov/*
106176348Smarcel * Searches for the U-Boot API signature
107176348Smarcel *
108176348Smarcel * returns 1/0 depending on found/not found result
109176348Smarcel */
110177152Sobrienint
111177152Sobrienapi_search_sig(struct api_signature **sig)
112177152Sobrien{
113176481Smarcel	unsigned char *sp, *spend;
114176348Smarcel
115176348Smarcel	if (sig == NULL)
116177108Sraj		return (0);
117176348Smarcel
118176481Smarcel	if (uboot_address == 0)
119176481Smarcel		uboot_address = 255 * 1024 * 1024;
120176348Smarcel
121296182Ssgalabov	sp = (void *)(uboot_address & API_SIG_SEARCH_MASK);
122296182Ssgalabov	spend = sp + API_SIG_SEARCH_LEN - API_SIG_MAGLEN;
123296182Ssgalabov
124176481Smarcel	while (sp < spend) {
125176348Smarcel		if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
126176348Smarcel			*sig = (struct api_signature *)sp;
127176348Smarcel			if (valid_sig(*sig))
128177108Sraj				return (1);
129176348Smarcel		}
130176348Smarcel		sp += API_SIG_MAGLEN;
131176348Smarcel	}
132176348Smarcel
133176348Smarcel	*sig = NULL;
134177108Sraj	return (0);
135176348Smarcel}
136176348Smarcel
137176348Smarcel/****************************************
138176348Smarcel *
139176348Smarcel * console
140176348Smarcel *
141176348Smarcel ****************************************/
142176348Smarcel
143177152Sobrienint
144177152Sobrienub_getc(void)
145176348Smarcel{
146176348Smarcel	int c;
147176348Smarcel
148296182Ssgalabov	if (!syscall(API_GETC, NULL, &c))
149177108Sraj		return (-1);
150177108Sraj
151182732Sraj	return (c);
152176348Smarcel}
153176348Smarcel
154177152Sobrienint
155177152Sobrienub_tstc(void)
156176348Smarcel{
157176348Smarcel	int t;
158176348Smarcel
159296182Ssgalabov	if (!syscall(API_TSTC, NULL, &t))
160177108Sraj		return (-1);
161176348Smarcel
162182732Sraj	return (t);
163176348Smarcel}
164176348Smarcel
165177152Sobrienvoid
166296182Ssgalabovub_putc(const char c)
167176348Smarcel{
168177152Sobrien
169296182Ssgalabov	syscall(API_PUTC, NULL, &c);
170176348Smarcel}
171176348Smarcel
172177152Sobrienvoid
173177152Sobrienub_puts(const char *s)
174176348Smarcel{
175177152Sobrien
176296182Ssgalabov	syscall(API_PUTS, NULL, s);
177176348Smarcel}
178176348Smarcel
179176348Smarcel/****************************************
180176348Smarcel *
181176348Smarcel * system
182176348Smarcel *
183176348Smarcel ****************************************/
184176348Smarcel
185177152Sobrienvoid
186177152Sobrienub_reset(void)
187176348Smarcel{
188177152Sobrien
189176348Smarcel	syscall(API_RESET, NULL);
190329175Skevans	while (1);	/* fallback if API_RESET failed */
191329175Skevans	__unreachable();
192176348Smarcel}
193176348Smarcel
194183598Srajstatic struct mem_region mr[UB_MAX_MR];
195176348Smarcelstatic struct sys_info si;
196176348Smarcel
197177152Sobrienstruct sys_info *
198177152Sobrienub_get_sys_info(void)
199176348Smarcel{
200176348Smarcel	int err = 0;
201177152Sobrien
202176348Smarcel	memset(&si, 0, sizeof(struct sys_info));
203176348Smarcel	si.mr = mr;
204183598Sraj	si.mr_no = UB_MAX_MR;
205176348Smarcel	memset(&mr, 0, sizeof(mr));
206177152Sobrien
207296182Ssgalabov	if (!syscall(API_GET_SYS_INFO, &err, &si))
208177108Sraj		return (NULL);
209176348Smarcel
210176348Smarcel	return ((err) ? NULL : &si);
211176348Smarcel}
212176348Smarcel
213176348Smarcel/****************************************
214176348Smarcel *
215176348Smarcel * timing
216176348Smarcel *
217176348Smarcel ****************************************/
218177108Sraj
219177152Sobrienvoid
220177152Sobrienub_udelay(unsigned long usec)
221176348Smarcel{
222177108Sraj
223176348Smarcel	syscall(API_UDELAY, NULL, &usec);
224176348Smarcel}
225176348Smarcel
226177152Sobrienunsigned long
227177152Sobrienub_get_timer(unsigned long base)
228176348Smarcel{
229176348Smarcel	unsigned long cur;
230177152Sobrien
231176348Smarcel	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
232177108Sraj		return (0);
233176348Smarcel
234177108Sraj	return (cur);
235176348Smarcel}
236176348Smarcel
237176348Smarcel/****************************************************************************
238176348Smarcel *
239176348Smarcel * devices
240176348Smarcel *
241183598Sraj * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
242176348Smarcel *
243176348Smarcel ***************************************************************************/
244176348Smarcel
245183598Srajstatic struct device_info devices[UB_MAX_DEV];
246176348Smarcel
247177152Sobrienstruct device_info *
248177152Sobrienub_dev_get(int i)
249176348Smarcel{
250177152Sobrien
251183598Sraj	return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
252176348Smarcel}
253176348Smarcel
254176348Smarcel/*
255176348Smarcel * Enumerates the devices: fills out device_info elements in the devices[]
256176348Smarcel * array.
257176348Smarcel *
258176348Smarcel * returns:		number of devices found
259176348Smarcel */
260177152Sobrienint
261177152Sobrienub_dev_enum(void)
262176348Smarcel{
263176348Smarcel	struct device_info *di;
264176348Smarcel	int n = 0;
265176348Smarcel
266183598Sraj	memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV);
267176348Smarcel	di = &devices[0];
268176348Smarcel
269176348Smarcel	if (!syscall(API_DEV_ENUM, NULL, di))
270177108Sraj		return (0);
271176348Smarcel
272176348Smarcel	while (di->cookie != NULL) {
273176348Smarcel
274183598Sraj		if (++n >= UB_MAX_DEV)
275176348Smarcel			break;
276176348Smarcel
277176348Smarcel		/* take another device_info */
278176348Smarcel		di++;
279176348Smarcel
280176348Smarcel		/* pass on the previous cookie */
281176348Smarcel		di->cookie = devices[n - 1].cookie;
282176348Smarcel
283176348Smarcel		if (!syscall(API_DEV_ENUM, NULL, di))
284182732Sraj			return (0);
285177108Sraj	}
286176348Smarcel
287177108Sraj	return (n);
288176348Smarcel}
289176348Smarcel
290176348Smarcel/*
291176348Smarcel * handle:	0-based id of the device
292176348Smarcel *
293176348Smarcel * returns:	0 when OK, err otherwise
294176348Smarcel */
295177152Sobrienint
296177152Sobrienub_dev_open(int handle)
297176348Smarcel{
298176348Smarcel	struct device_info *di;
299176348Smarcel	int err = 0;
300176348Smarcel
301183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
302177108Sraj		return (API_EINVAL);
303176348Smarcel
304176348Smarcel	di = &devices[handle];
305176348Smarcel	if (!syscall(API_DEV_OPEN, &err, di))
306177108Sraj		return (-1);
307176348Smarcel
308177108Sraj	return (err);
309176348Smarcel}
310176348Smarcel
311177152Sobrienint
312177152Sobrienub_dev_close(int handle)
313176348Smarcel{
314176348Smarcel	struct device_info *di;
315176348Smarcel
316183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
317177108Sraj		return (API_EINVAL);
318176348Smarcel
319176348Smarcel	di = &devices[handle];
320176348Smarcel	if (!syscall(API_DEV_CLOSE, NULL, di))
321177108Sraj		return (-1);
322176348Smarcel
323177108Sraj	return (0);
324176348Smarcel}
325176348Smarcel
326176348Smarcel/*
327176348Smarcel * Validates device for read/write, it has to:
328176348Smarcel *
329176348Smarcel * - have sane handle
330176348Smarcel * - be opened
331176348Smarcel *
332176348Smarcel * returns:	0/1 accordingly
333176348Smarcel */
334177152Sobrienstatic int
335177152Sobriendev_valid(int handle)
336176348Smarcel{
337177108Sraj
338183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
339177108Sraj		return (0);
340176348Smarcel
341176348Smarcel	if (devices[handle].state != DEV_STA_OPEN)
342177108Sraj		return (0);
343176348Smarcel
344177108Sraj	return (1);
345176348Smarcel}
346176348Smarcel
347177152Sobrienstatic int
348177152Sobriendev_stor_valid(int handle)
349176348Smarcel{
350177108Sraj
351176348Smarcel	if (!dev_valid(handle))
352177108Sraj		return (0);
353176348Smarcel
354176348Smarcel	if (!(devices[handle].type & DEV_TYP_STOR))
355177108Sraj		return (0);
356176348Smarcel
357177108Sraj	return (1);
358176348Smarcel}
359176348Smarcel
360177152Sobrienint
361183598Srajub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start,
362183598Sraj    lbasize_t *rlen)
363176348Smarcel{
364176348Smarcel	struct device_info *di;
365176348Smarcel	lbasize_t act_len;
366176348Smarcel	int err = 0;
367176348Smarcel
368176348Smarcel	if (!dev_stor_valid(handle))
369177108Sraj		return (API_ENODEV);
370176348Smarcel
371176348Smarcel	di = &devices[handle];
372176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
373183598Sraj		return (API_ESYSC);
374176348Smarcel
375183598Sraj	if (!err && rlen)
376183598Sraj		*rlen = act_len;
377176348Smarcel
378183598Sraj	return (err);
379176348Smarcel}
380176348Smarcel
381177152Sobrienstatic int
382177152Sobriendev_net_valid(int handle)
383176348Smarcel{
384177108Sraj
385176348Smarcel	if (!dev_valid(handle))
386177108Sraj		return (0);
387176348Smarcel
388176348Smarcel	if (devices[handle].type != DEV_TYP_NET)
389177108Sraj		return (0);
390176348Smarcel
391177108Sraj	return (1);
392176348Smarcel}
393176348Smarcel
394177152Sobrienint
395183598Srajub_dev_recv(int handle, void *buf, int len, int *rlen)
396176348Smarcel{
397176348Smarcel	struct device_info *di;
398176348Smarcel	int err = 0, act_len;
399176348Smarcel
400176348Smarcel	if (!dev_net_valid(handle))
401177108Sraj		return (API_ENODEV);
402176348Smarcel
403176348Smarcel	di = &devices[handle];
404176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
405183598Sraj		return (API_ESYSC);
406176348Smarcel
407183598Sraj	if (!err)
408183598Sraj		*rlen = act_len;
409176348Smarcel
410183598Sraj	return (err);
411176348Smarcel}
412176348Smarcel
413177152Sobrienint
414177152Sobrienub_dev_send(int handle, void *buf, int len)
415176348Smarcel{
416176348Smarcel	struct device_info *di;
417176348Smarcel	int err = 0;
418176348Smarcel
419176348Smarcel	if (!dev_net_valid(handle))
420177108Sraj		return (API_ENODEV);
421176348Smarcel
422176348Smarcel	di = &devices[handle];
423176348Smarcel	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
424183598Sraj		return (API_ESYSC);
425176348Smarcel
426177108Sraj	return (err);
427176348Smarcel}
428176348Smarcel
429185099Srajchar *
430182732Srajub_stor_type(int type)
431182732Sraj{
432182732Sraj
433182732Sraj	if (type & DT_STOR_IDE)
434182732Sraj		return ("IDE");
435182732Sraj
436182732Sraj	if (type & DT_STOR_SCSI)
437182732Sraj		return ("SCSI");
438182732Sraj
439182732Sraj	if (type & DT_STOR_USB)
440182732Sraj		return ("USB");
441182732Sraj
442199193Santoine	if (type & DT_STOR_MMC)
443182732Sraj		return ("MMC");
444182732Sraj
445263052Sian	if (type & DT_STOR_SATA)
446263052Sian		return ("SATA");
447235609Sgber
448182732Sraj	return ("Unknown");
449182732Sraj}
450182732Sraj
451182732Srajchar *
452182732Srajub_mem_type(int flags)
453182732Sraj{
454182732Sraj
455183599Sraj	switch (flags & 0x000F) {
456182732Sraj	case MR_ATTR_FLASH:
457182732Sraj		return ("FLASH");
458182732Sraj	case MR_ATTR_DRAM:
459182732Sraj		return ("DRAM");
460182732Sraj	case MR_ATTR_SRAM:
461182732Sraj		return ("SRAM");
462182732Sraj	default:
463182732Sraj		return ("Unknown");
464182732Sraj	}
465182732Sraj}
466182732Sraj
467182732Srajvoid
468182732Srajub_dump_di(int handle)
469182732Sraj{
470182732Sraj	struct device_info *di = ub_dev_get(handle);
471182732Sraj	int i;
472182732Sraj
473182732Sraj	printf("device info (%d):\n", handle);
474307527Sgonzo	printf("  cookie\t= %p\n", di->cookie);
475182732Sraj	printf("  type\t\t= 0x%08x\n", di->type);
476182732Sraj
477182732Sraj	if (di->type == DEV_TYP_NET) {
478182732Sraj		printf("  hwaddr\t= ");
479182732Sraj		for (i = 0; i < 6; i++)
480182732Sraj			printf("%02x ", di->di_net.hwaddr[i]);
481182732Sraj
482182732Sraj		printf("\n");
483182732Sraj
484182732Sraj	} else if (di->type & DEV_TYP_STOR) {
485182732Sraj		printf("  type\t\t= %s\n", ub_stor_type(di->type));
486182732Sraj		printf("  blk size\t\t= %ld\n", di->di_stor.block_size);
487182732Sraj		printf("  blk count\t\t= %ld\n", di->di_stor.block_count);
488182732Sraj	}
489182732Sraj}
490182732Sraj
491182732Srajvoid
492182732Srajub_dump_si(struct sys_info *si)
493182732Sraj{
494182732Sraj	int i;
495182732Sraj
496182732Sraj	printf("sys info:\n");
497182732Sraj	printf("  clkbus\t= %ld MHz\n", si->clk_bus / 1000 / 1000);
498182732Sraj	printf("  clkcpu\t= %ld MHz\n", si->clk_cpu / 1000 / 1000);
499182732Sraj	printf("  bar\t\t= 0x%08lx\n", si->bar);
500182732Sraj
501182732Sraj	printf("---\n");
502182732Sraj	for (i = 0; i < si->mr_no; i++) {
503182732Sraj		if (si->mr[i].flags == 0)
504182732Sraj			break;
505182732Sraj
506182732Sraj		printf("  start\t= 0x%08lx\n", si->mr[i].start);
507182732Sraj		printf("  size\t= 0x%08lx\n", si->mr[i].size);
508182732Sraj		printf("  type\t= %s\n", ub_mem_type(si->mr[i].flags));
509182732Sraj		printf("---\n");
510182732Sraj	}
511182732Sraj}
512182732Sraj
513176348Smarcel/****************************************
514176348Smarcel *
515176348Smarcel * env vars
516176348Smarcel *
517176348Smarcel ****************************************/
518176348Smarcel
519177152Sobrienchar *
520177152Sobrienub_env_get(const char *name)
521176348Smarcel{
522176348Smarcel	char *value;
523176348Smarcel
524296182Ssgalabov	if (!syscall(API_ENV_GET, NULL, name, &value))
525177108Sraj		return (NULL);
526176348Smarcel
527177108Sraj	return (value);
528176348Smarcel}
529176348Smarcel
530177152Sobrienvoid
531177152Sobrienub_env_set(const char *name, char *value)
532176348Smarcel{
533177108Sraj
534296182Ssgalabov	syscall(API_ENV_SET, NULL, name, value);
535176348Smarcel}
536176348Smarcel
537176348Smarcelstatic char env_name[256];
538176348Smarcel
539177152Sobrienconst char *
540177152Sobrienub_env_enum(const char *last)
541176348Smarcel{
542176348Smarcel	const char *env, *str;
543176348Smarcel	int i;
544176348Smarcel
545176348Smarcel	/*
546176348Smarcel	 * It's OK to pass only the name piece as last (and not the whole
547176348Smarcel	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
548176348Smarcel	 * internally, which handles such case
549176348Smarcel	 */
550200691Smarcel	env = NULL;
551296182Ssgalabov	if (!syscall(API_ENV_ENUM, NULL, last, &env))
552177108Sraj		return (NULL);
553176348Smarcel
554284614Ssobomax	if (env == NULL || last == env)
555176348Smarcel		/* no more env. variables to enumerate */
556177108Sraj		return (NULL);
557176348Smarcel
558176348Smarcel	/* next enumerated env var */
559176348Smarcel	memset(env_name, 0, 256);
560176348Smarcel	for (i = 0, str = env; *str != '=' && *str != '\0';)
561176348Smarcel		env_name[i++] = *str++;
562176348Smarcel
563176348Smarcel	env_name[i] = '\0';
564176348Smarcel
565177108Sraj	return (env_name);
566176348Smarcel}
567