]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/uboot/glue.c
zfs: merge openzfs/zfs@229b9f4ed
[FreeBSD/FreeBSD.git] / stand / uboot / glue.c
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 }