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