api.c 15 KB

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