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