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. */ 41extern long uboot_address; 42 43static int 44valid_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 */ 73int 74api_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 */ 107int 108api_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 140int 141ub_getc(void) 142{ 143 int c; 144 145 if (!syscall(API_GETC, NULL, &c)) 146 return (-1); 147 148 return (c); 149} 150 151int 152ub_tstc(void) 153{ 154 int t; 155 156 if (!syscall(API_TSTC, NULL, &t)) 157 return (-1); 158 159 return (t); 160} 161 162void 163ub_putc(const char c) 164{ 165 166 syscall(API_PUTC, NULL, &c); 167} 168 169void 170ub_puts(const char *s) 171{ 172 173 syscall(API_PUTS, NULL, s); 174} 175 176/**************************************** 177 * 178 * system 179 * 180 ****************************************/ 181 182void 183ub_reset(void) 184{ 185 186 syscall(API_RESET, NULL); 187 while (1); /* fallback if API_RESET failed */ 188 __unreachable(); 189} 190 191static struct mem_region mr[UB_MAX_MR]; 192static struct sys_info si; 193 194struct sys_info * 195ub_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 216void 217ub_udelay(unsigned long usec) 218{ 219 220 syscall(API_UDELAY, NULL, &usec); 221} 222 223unsigned long 224ub_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 242static struct device_info devices[UB_MAX_DEV]; 243 244struct device_info * 245ub_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 */ 257int 258ub_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 */ 292int 293ub_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 308int 309ub_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 */ 331static int 332dev_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 344static int 345dev_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 357int 358ub_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 378static int 379dev_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 391int 392ub_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 410int 411ub_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 426char * 427ub_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 448char * 449ub_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 464void 465ub_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 488void 489ub_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 516char * 517ub_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 527void 528ub_env_set(const char *name, char *value) 529{ 530 531 syscall(API_ENV_SET, NULL, name, value); 532} 533 534static char env_name[256]; 535 536const char * 537ub_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} 564