1 /* 2 * (C) Copyright 2007 Semihalf 3 * 4 * Written by: Rafal Jaworowski <raj@semihalf.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <config.h> 10 #include <command.h> 11 #include <common.h> 12 #include <malloc.h> 13 #include <environment.h> 14 #include <linux/types.h> 15 #include <api_public.h> 16 17 #include "api_private.h" 18 19 #define DEBUG 20 #undef DEBUG 21 22 /***************************************************************************** 23 * 24 * This is the API core. 25 * 26 * API_ functions are part of U-Boot code and constitute the lowest level 27 * calls: 28 * 29 * - they know what values they need as arguments 30 * - their direct return value pertains to the API_ "shell" itself (0 on 31 * success, some error code otherwise) 32 * - if the call returns a value it is buried within arguments 33 * 34 ****************************************************************************/ 35 36 #ifdef DEBUG 37 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0) 38 #else 39 #define debugf(fmt, args...) 40 #endif 41 42 typedef int (*cfp_t)(va_list argp); 43 44 static int calls_no; 45 46 /* 47 * pseudo signature: 48 * 49 * int API_getc(int *c) 50 */ 51 static int API_getc(va_list ap) 52 { 53 int *c; 54 55 if ((c = (int *)va_arg(ap, uintptr_t)) == NULL) 56 return API_EINVAL; 57 58 *c = getc(); 59 return 0; 60 } 61 62 /* 63 * pseudo signature: 64 * 65 * int API_tstc(int *c) 66 */ 67 static int API_tstc(va_list ap) 68 { 69 int *t; 70 71 if ((t = (int *)va_arg(ap, uintptr_t)) == NULL) 72 return API_EINVAL; 73 74 *t = tstc(); 75 return 0; 76 } 77 78 /* 79 * pseudo signature: 80 * 81 * int API_putc(char *ch) 82 */ 83 static int API_putc(va_list ap) 84 { 85 char *c; 86 87 if ((c = (char *)va_arg(ap, uintptr_t)) == NULL) 88 return API_EINVAL; 89 90 putc(*c); 91 return 0; 92 } 93 94 /* 95 * pseudo signature: 96 * 97 * int API_puts(char **s) 98 */ 99 static int API_puts(va_list ap) 100 { 101 char *s; 102 103 if ((s = (char *)va_arg(ap, uintptr_t)) == NULL) 104 return API_EINVAL; 105 106 puts(s); 107 return 0; 108 } 109 110 /* 111 * pseudo signature: 112 * 113 * int API_reset(void) 114 */ 115 static int API_reset(va_list ap) 116 { 117 do_reset(NULL, 0, 0, NULL); 118 119 /* NOT REACHED */ 120 return 0; 121 } 122 123 /* 124 * pseudo signature: 125 * 126 * int API_get_sys_info(struct sys_info *si) 127 * 128 * fill out the sys_info struct containing selected parameters about the 129 * machine 130 */ 131 static int API_get_sys_info(va_list ap) 132 { 133 struct sys_info *si; 134 135 si = (struct sys_info *)va_arg(ap, uintptr_t); 136 if (si == NULL) 137 return API_ENOMEM; 138 139 return (platform_sys_info(si)) ? 0 : API_ENODEV; 140 } 141 142 /* 143 * pseudo signature: 144 * 145 * int API_udelay(unsigned long *udelay) 146 */ 147 static int API_udelay(va_list ap) 148 { 149 unsigned long *d; 150 151 if ((d = (unsigned long *)va_arg(ap, unsigned long)) == NULL) 152 return API_EINVAL; 153 154 udelay(*d); 155 return 0; 156 } 157 158 /* 159 * pseudo signature: 160 * 161 * int API_get_timer(unsigned long *current, unsigned long *base) 162 */ 163 static int API_get_timer(va_list ap) 164 { 165 unsigned long *base, *cur; 166 167 cur = (unsigned long *)va_arg(ap, unsigned long); 168 if (cur == NULL) 169 return API_EINVAL; 170 171 base = (unsigned long *)va_arg(ap, unsigned long); 172 if (base == NULL) 173 return API_EINVAL; 174 175 *cur = get_timer(*base); 176 return 0; 177 } 178 179 180 /***************************************************************************** 181 * 182 * pseudo signature: 183 * 184 * int API_dev_enum(struct device_info *) 185 * 186 * 187 * cookies uniqely identify the previously enumerated device instance and 188 * provide a hint for what to inspect in current enum iteration: 189 * 190 * - net: ð_device struct address from list pointed to by eth_devices 191 * 192 * - storage: struct blk_desc struct address from &ide_dev_desc[n], 193 * &scsi_dev_desc[n] and similar tables 194 * 195 ****************************************************************************/ 196 197 static int API_dev_enum(va_list ap) 198 { 199 struct device_info *di; 200 201 /* arg is ptr to the device_info struct we are going to fill out */ 202 di = (struct device_info *)va_arg(ap, uintptr_t); 203 if (di == NULL) 204 return API_EINVAL; 205 206 if (di->cookie == NULL) { 207 /* start over - clean up enumeration */ 208 dev_enum_reset(); /* XXX shouldn't the name contain 'stor'? */ 209 debugf("RESTART ENUM\n"); 210 211 /* net device enumeration first */ 212 if (dev_enum_net(di)) 213 return 0; 214 } 215 216 /* 217 * The hidden assumption is there can only be one active network 218 * device and it is identified upon enumeration (re)start, so there's 219 * no point in trying to find network devices in other cases than the 220 * (re)start and hence the 'next' device can only be storage 221 */ 222 if (!dev_enum_storage(di)) 223 /* make sure we mark there are no more devices */ 224 di->cookie = NULL; 225 226 return 0; 227 } 228 229 230 static int API_dev_open(va_list ap) 231 { 232 struct device_info *di; 233 int err = 0; 234 235 /* arg is ptr to the device_info struct */ 236 di = (struct device_info *)va_arg(ap, uintptr_t); 237 if (di == NULL) 238 return API_EINVAL; 239 240 /* Allow only one consumer of the device at a time */ 241 if (di->state == DEV_STA_OPEN) 242 return API_EBUSY; 243 244 if (di->cookie == NULL) 245 return API_ENODEV; 246 247 if (di->type & DEV_TYP_STOR) 248 err = dev_open_stor(di->cookie); 249 250 else if (di->type & DEV_TYP_NET) 251 err = dev_open_net(di->cookie); 252 else 253 err = API_ENODEV; 254 255 if (!err) 256 di->state = DEV_STA_OPEN; 257 258 return err; 259 } 260 261 262 static int API_dev_close(va_list ap) 263 { 264 struct device_info *di; 265 int err = 0; 266 267 /* arg is ptr to the device_info struct */ 268 di = (struct device_info *)va_arg(ap, uintptr_t); 269 if (di == NULL) 270 return API_EINVAL; 271 272 if (di->state == DEV_STA_CLOSED) 273 return 0; 274 275 if (di->cookie == NULL) 276 return API_ENODEV; 277 278 if (di->type & DEV_TYP_STOR) 279 err = dev_close_stor(di->cookie); 280 281 else if (di->type & DEV_TYP_NET) 282 err = dev_close_net(di->cookie); 283 else 284 /* 285 * In case of unknown device we cannot change its state, so 286 * only return error code 287 */ 288 err = API_ENODEV; 289 290 if (!err) 291 di->state = DEV_STA_CLOSED; 292 293 return err; 294 } 295 296 297 /* 298 * Notice: this is for sending network packets only, as U-Boot does not 299 * support writing to storage at the moment (12.2007) 300 * 301 * pseudo signature: 302 * 303 * int API_dev_write( 304 * struct device_info *di, 305 * void *buf, 306 * int *len 307 * ) 308 * 309 * buf: ptr to buffer from where to get the data to send 310 * 311 * len: length of packet to be sent (in bytes) 312 * 313 */ 314 static int API_dev_write(va_list ap) 315 { 316 struct device_info *di; 317 void *buf; 318 int *len; 319 int err = 0; 320 321 /* 1. arg is ptr to the device_info struct */ 322 di = (struct device_info *)va_arg(ap, uintptr_t); 323 if (di == NULL) 324 return API_EINVAL; 325 326 /* XXX should we check if device is open? i.e. the ->state ? */ 327 328 if (di->cookie == NULL) 329 return API_ENODEV; 330 331 /* 2. arg is ptr to buffer from where to get data to write */ 332 buf = (void *)va_arg(ap, uintptr_t); 333 if (buf == NULL) 334 return API_EINVAL; 335 336 /* 3. arg is length of buffer */ 337 len = (int *)va_arg(ap, uintptr_t); 338 if (len == NULL) 339 return API_EINVAL; 340 if (*len <= 0) 341 return API_EINVAL; 342 343 if (di->type & DEV_TYP_STOR) 344 /* 345 * write to storage is currently not supported by U-Boot: 346 * no storage device implements block_write() method 347 */ 348 return API_ENODEV; 349 350 else if (di->type & DEV_TYP_NET) 351 err = dev_write_net(di->cookie, buf, *len); 352 else 353 err = API_ENODEV; 354 355 return err; 356 } 357 358 359 /* 360 * pseudo signature: 361 * 362 * int API_dev_read( 363 * struct device_info *di, 364 * void *buf, 365 * size_t *len, 366 * unsigned long *start 367 * size_t *act_len 368 * ) 369 * 370 * buf: ptr to buffer where to put the read data 371 * 372 * len: ptr to length to be read 373 * - network: len of packet to read (in bytes) 374 * - storage: # of blocks to read (can vary in size depending on define) 375 * 376 * start: ptr to start block (only used for storage devices, ignored for 377 * network) 378 * 379 * act_len: ptr to where to put the len actually read 380 */ 381 static int API_dev_read(va_list ap) 382 { 383 struct device_info *di; 384 void *buf; 385 lbasize_t *len_stor, *act_len_stor; 386 lbastart_t *start; 387 int *len_net, *act_len_net; 388 389 /* 1. arg is ptr to the device_info struct */ 390 di = (struct device_info *)va_arg(ap, uintptr_t); 391 if (di == NULL) 392 return API_EINVAL; 393 394 /* XXX should we check if device is open? i.e. the ->state ? */ 395 396 if (di->cookie == NULL) 397 return API_ENODEV; 398 399 /* 2. arg is ptr to buffer from where to put the read data */ 400 buf = (void *)va_arg(ap, uintptr_t); 401 if (buf == NULL) 402 return API_EINVAL; 403 404 if (di->type & DEV_TYP_STOR) { 405 /* 3. arg - ptr to var with # of blocks to read */ 406 len_stor = (lbasize_t *)va_arg(ap, uintptr_t); 407 if (!len_stor) 408 return API_EINVAL; 409 if (*len_stor <= 0) 410 return API_EINVAL; 411 412 /* 4. arg - ptr to var with start block */ 413 start = (lbastart_t *)va_arg(ap, uintptr_t); 414 415 /* 5. arg - ptr to var where to put the len actually read */ 416 act_len_stor = (lbasize_t *)va_arg(ap, uintptr_t); 417 if (!act_len_stor) 418 return API_EINVAL; 419 420 *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start); 421 422 } else if (di->type & DEV_TYP_NET) { 423 424 /* 3. arg points to the var with length of packet to read */ 425 len_net = (int *)va_arg(ap, uintptr_t); 426 if (!len_net) 427 return API_EINVAL; 428 if (*len_net <= 0) 429 return API_EINVAL; 430 431 /* 4. - ptr to var where to put the len actually read */ 432 act_len_net = (int *)va_arg(ap, uintptr_t); 433 if (!act_len_net) 434 return API_EINVAL; 435 436 *act_len_net = dev_read_net(di->cookie, buf, *len_net); 437 438 } else 439 return API_ENODEV; 440 441 return 0; 442 } 443 444 445 /* 446 * pseudo signature: 447 * 448 * int API_env_get(const char *name, char **value) 449 * 450 * name: ptr to name of env var 451 */ 452 static int API_env_get(va_list ap) 453 { 454 char *name, **value; 455 456 if ((name = (char *)va_arg(ap, uintptr_t)) == NULL) 457 return API_EINVAL; 458 if ((value = (char **)va_arg(ap, uintptr_t)) == NULL) 459 return API_EINVAL; 460 461 *value = getenv(name); 462 463 return 0; 464 } 465 466 /* 467 * pseudo signature: 468 * 469 * int API_env_set(const char *name, const char *value) 470 * 471 * name: ptr to name of env var 472 * 473 * value: ptr to value to be set 474 */ 475 static int API_env_set(va_list ap) 476 { 477 char *name, *value; 478 479 if ((name = (char *)va_arg(ap, uintptr_t)) == NULL) 480 return API_EINVAL; 481 if ((value = (char *)va_arg(ap, uintptr_t)) == NULL) 482 return API_EINVAL; 483 484 setenv(name, value); 485 486 return 0; 487 } 488 489 /* 490 * pseudo signature: 491 * 492 * int API_env_enum(const char *last, char **next) 493 * 494 * last: ptr to name of env var found in last iteration 495 */ 496 static int API_env_enum(va_list ap) 497 { 498 int i, buflen; 499 char *last, **next, *s; 500 ENTRY *match, search; 501 static char *var; 502 503 last = (char *)va_arg(ap, unsigned long); 504 505 if ((next = (char **)va_arg(ap, uintptr_t)) == NULL) 506 return API_EINVAL; 507 508 if (last == NULL) { 509 var = NULL; 510 i = 0; 511 } else { 512 var = strdup(last); 513 s = strchr(var, '='); 514 if (s != NULL) 515 *s = 0; 516 search.key = var; 517 i = hsearch_r(search, FIND, &match, &env_htab, 0); 518 if (i == 0) { 519 i = API_EINVAL; 520 goto done; 521 } 522 } 523 524 /* match the next entry after i */ 525 i = hmatch_r("", i, &match, &env_htab); 526 if (i == 0) 527 goto done; 528 buflen = strlen(match->key) + strlen(match->data) + 2; 529 var = realloc(var, buflen); 530 snprintf(var, buflen, "%s=%s", match->key, match->data); 531 *next = var; 532 return 0; 533 534 done: 535 free(var); 536 var = NULL; 537 *next = NULL; 538 return i; 539 } 540 541 /* 542 * pseudo signature: 543 * 544 * int API_display_get_info(int type, struct display_info *di) 545 */ 546 static int API_display_get_info(va_list ap) 547 { 548 int type; 549 struct display_info *di; 550 551 type = va_arg(ap, int); 552 di = va_arg(ap, struct display_info *); 553 554 return display_get_info(type, di); 555 } 556 557 /* 558 * pseudo signature: 559 * 560 * int API_display_draw_bitmap(ulong bitmap, int x, int y) 561 */ 562 static int API_display_draw_bitmap(va_list ap) 563 { 564 ulong bitmap; 565 int x, y; 566 567 bitmap = va_arg(ap, ulong); 568 x = va_arg(ap, int); 569 y = va_arg(ap, int); 570 571 return display_draw_bitmap(bitmap, x, y); 572 } 573 574 /* 575 * pseudo signature: 576 * 577 * void API_display_clear(void) 578 */ 579 static int API_display_clear(va_list ap) 580 { 581 display_clear(); 582 return 0; 583 } 584 585 static cfp_t calls_table[API_MAXCALL] = { NULL, }; 586 587 /* 588 * The main syscall entry point - this is not reentrant, only one call is 589 * serviced until finished. 590 * 591 * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t); 592 * 593 * call: syscall number 594 * 595 * retval: points to the return value placeholder, this is the place the 596 * syscall puts its return value, if NULL the caller does not 597 * expect a return value 598 * 599 * ... syscall arguments (variable number) 600 * 601 * returns: 0 if the call not found, 1 if serviced 602 */ 603 int syscall(int call, int *retval, ...) 604 { 605 va_list ap; 606 int rv; 607 608 if (call < 0 || call >= calls_no) { 609 debugf("invalid call #%d\n", call); 610 return 0; 611 } 612 613 if (calls_table[call] == NULL) { 614 debugf("syscall #%d does not have a handler\n", call); 615 return 0; 616 } 617 618 va_start(ap, retval); 619 rv = calls_table[call](ap); 620 if (retval != NULL) 621 *retval = rv; 622 623 return 1; 624 } 625 626 void api_init(void) 627 { 628 struct api_signature *sig = NULL; 629 630 /* TODO put this into linker set one day... */ 631 calls_table[API_RSVD] = NULL; 632 calls_table[API_GETC] = &API_getc; 633 calls_table[API_PUTC] = &API_putc; 634 calls_table[API_TSTC] = &API_tstc; 635 calls_table[API_PUTS] = &API_puts; 636 calls_table[API_RESET] = &API_reset; 637 calls_table[API_GET_SYS_INFO] = &API_get_sys_info; 638 calls_table[API_UDELAY] = &API_udelay; 639 calls_table[API_GET_TIMER] = &API_get_timer; 640 calls_table[API_DEV_ENUM] = &API_dev_enum; 641 calls_table[API_DEV_OPEN] = &API_dev_open; 642 calls_table[API_DEV_CLOSE] = &API_dev_close; 643 calls_table[API_DEV_READ] = &API_dev_read; 644 calls_table[API_DEV_WRITE] = &API_dev_write; 645 calls_table[API_ENV_GET] = &API_env_get; 646 calls_table[API_ENV_SET] = &API_env_set; 647 calls_table[API_ENV_ENUM] = &API_env_enum; 648 calls_table[API_DISPLAY_GET_INFO] = &API_display_get_info; 649 calls_table[API_DISPLAY_DRAW_BITMAP] = &API_display_draw_bitmap; 650 calls_table[API_DISPLAY_CLEAR] = &API_display_clear; 651 calls_no = API_MAXCALL; 652 653 debugf("API initialized with %d calls\n", calls_no); 654 655 dev_stor_init(); 656 657 /* 658 * Produce the signature so the API consumers can find it 659 */ 660 sig = malloc(sizeof(struct api_signature)); 661 if (sig == NULL) { 662 printf("API: could not allocate memory for the signature!\n"); 663 return; 664 } 665 666 setenv_hex("api_address", (unsigned long)sig); 667 debugf("API sig @ 0x%lX\n", (unsigned long)sig); 668 memcpy(sig->magic, API_SIG_MAGIC, 8); 669 sig->version = API_SIG_VERSION; 670 sig->syscall = &syscall; 671 sig->checksum = 0; 672 sig->checksum = crc32(0, (unsigned char *)sig, 673 sizeof(struct api_signature)); 674 debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall); 675 } 676 677 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size, 678 int flags) 679 { 680 int i; 681 682 if (!si->mr || !size || (flags == 0)) 683 return; 684 685 /* find free slot */ 686 for (i = 0; i < si->mr_no; i++) 687 if (si->mr[i].flags == 0) { 688 /* insert new mem region */ 689 si->mr[i].start = start; 690 si->mr[i].size = size; 691 si->mr[i].flags = flags; 692 return; 693 } 694 } 695