api.c 15 KB

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