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, n; 499 char *last, **next; 500 501 last = (char *)va_arg(ap, unsigned long); 502 503 if ((next = (char **)va_arg(ap, uintptr_t)) == NULL) 504 return API_EINVAL; 505 506 if (last == NULL) 507 /* start over */ 508 *next = ((char *)env_get_addr(0)); 509 else { 510 *next = last; 511 512 for (i = 0; env_get_char(i) != '\0'; i = n + 1) { 513 for (n = i; env_get_char(n) != '\0'; ++n) { 514 if (n >= CONFIG_ENV_SIZE) { 515 /* XXX shouldn't we set *next = NULL?? */ 516 return 0; 517 } 518 } 519 520 if (envmatch((uchar *)last, i) < 0) 521 continue; 522 523 /* try to get next name */ 524 i = n + 1; 525 if (env_get_char(i) == '\0') { 526 /* no more left */ 527 *next = NULL; 528 return 0; 529 } 530 531 *next = ((char *)env_get_addr(i)); 532 return 0; 533 } 534 } 535 536 return 0; 537 } 538 539 /* 540 * pseudo signature: 541 * 542 * int API_display_get_info(int type, struct display_info *di) 543 */ 544 static int API_display_get_info(va_list ap) 545 { 546 int type; 547 struct display_info *di; 548 549 type = va_arg(ap, int); 550 di = va_arg(ap, struct display_info *); 551 552 return display_get_info(type, di); 553 } 554 555 /* 556 * pseudo signature: 557 * 558 * int API_display_draw_bitmap(ulong bitmap, int x, int y) 559 */ 560 static int API_display_draw_bitmap(va_list ap) 561 { 562 ulong bitmap; 563 int x, y; 564 565 bitmap = va_arg(ap, ulong); 566 x = va_arg(ap, int); 567 y = va_arg(ap, int); 568 569 return display_draw_bitmap(bitmap, x, y); 570 } 571 572 /* 573 * pseudo signature: 574 * 575 * void API_display_clear(void) 576 */ 577 static int API_display_clear(va_list ap) 578 { 579 display_clear(); 580 return 0; 581 } 582 583 static cfp_t calls_table[API_MAXCALL] = { NULL, }; 584 585 /* 586 * The main syscall entry point - this is not reentrant, only one call is 587 * serviced until finished. 588 * 589 * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t); 590 * 591 * call: syscall number 592 * 593 * retval: points to the return value placeholder, this is the place the 594 * syscall puts its return value, if NULL the caller does not 595 * expect a return value 596 * 597 * ... syscall arguments (variable number) 598 * 599 * returns: 0 if the call not found, 1 if serviced 600 */ 601 int syscall(int call, int *retval, ...) 602 { 603 va_list ap; 604 int rv; 605 606 if (call < 0 || call >= calls_no) { 607 debugf("invalid call #%d\n", call); 608 return 0; 609 } 610 611 if (calls_table[call] == NULL) { 612 debugf("syscall #%d does not have a handler\n", call); 613 return 0; 614 } 615 616 va_start(ap, retval); 617 rv = calls_table[call](ap); 618 if (retval != NULL) 619 *retval = rv; 620 621 return 1; 622 } 623 624 void api_init(void) 625 { 626 struct api_signature *sig = NULL; 627 628 /* TODO put this into linker set one day... */ 629 calls_table[API_RSVD] = NULL; 630 calls_table[API_GETC] = &API_getc; 631 calls_table[API_PUTC] = &API_putc; 632 calls_table[API_TSTC] = &API_tstc; 633 calls_table[API_PUTS] = &API_puts; 634 calls_table[API_RESET] = &API_reset; 635 calls_table[API_GET_SYS_INFO] = &API_get_sys_info; 636 calls_table[API_UDELAY] = &API_udelay; 637 calls_table[API_GET_TIMER] = &API_get_timer; 638 calls_table[API_DEV_ENUM] = &API_dev_enum; 639 calls_table[API_DEV_OPEN] = &API_dev_open; 640 calls_table[API_DEV_CLOSE] = &API_dev_close; 641 calls_table[API_DEV_READ] = &API_dev_read; 642 calls_table[API_DEV_WRITE] = &API_dev_write; 643 calls_table[API_ENV_GET] = &API_env_get; 644 calls_table[API_ENV_SET] = &API_env_set; 645 calls_table[API_ENV_ENUM] = &API_env_enum; 646 calls_table[API_DISPLAY_GET_INFO] = &API_display_get_info; 647 calls_table[API_DISPLAY_DRAW_BITMAP] = &API_display_draw_bitmap; 648 calls_table[API_DISPLAY_CLEAR] = &API_display_clear; 649 calls_no = API_MAXCALL; 650 651 debugf("API initialized with %d calls\n", calls_no); 652 653 dev_stor_init(); 654 655 /* 656 * Produce the signature so the API consumers can find it 657 */ 658 sig = malloc(sizeof(struct api_signature)); 659 if (sig == NULL) { 660 printf("API: could not allocate memory for the signature!\n"); 661 return; 662 } 663 664 setenv_hex("api_address", (unsigned long)sig); 665 debugf("API sig @ 0x%lX\n", (unsigned long)sig); 666 memcpy(sig->magic, API_SIG_MAGIC, 8); 667 sig->version = API_SIG_VERSION; 668 sig->syscall = &syscall; 669 sig->checksum = 0; 670 sig->checksum = crc32(0, (unsigned char *)sig, 671 sizeof(struct api_signature)); 672 debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall); 673 } 674 675 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size, 676 int flags) 677 { 678 int i; 679 680 if (!si->mr || !size || (flags == 0)) 681 return; 682 683 /* find free slot */ 684 for (i = 0; i < si->mr_no; i++) 685 if (si->mr[i].flags == 0) { 686 /* insert new mem region */ 687 si->mr[i].start = start; 688 si->mr[i].size = size; 689 si->mr[i].flags = flags; 690 return; 691 } 692 } 693