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