api.c 15 KB

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