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