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