api.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /*
  2. * (C) Copyright 2007 Semihalf
  3. *
  4. * Written by: Rafal Jaworowski <raj@semihalf.com>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <config.h>
  9. #include <command.h>
  10. #include <common.h>
  11. #include <malloc.h>
  12. #include <environment.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, u_int32_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, u_int32_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, u_int32_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, u_int32_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, u_int32_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, u_int32_t)) == 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, u_int32_t);
  139. if (cur == NULL)
  140. return API_EINVAL;
  141. base = (unsigned long *)va_arg(ap, u_int32_t);
  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: block_dev_desc_t 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, u_int32_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, u_int32_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, u_int32_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. * Notice: this is for sending network packets only, as U-Boot does not
  240. * support writing to storage at the moment (12.2007)
  241. *
  242. * pseudo signature:
  243. *
  244. * int API_dev_write(
  245. * struct device_info *di,
  246. * void *buf,
  247. * int *len
  248. * )
  249. *
  250. * buf: ptr to buffer from where to get the data to send
  251. *
  252. * len: length of packet to be sent (in bytes)
  253. *
  254. */
  255. static int API_dev_write(va_list ap)
  256. {
  257. struct device_info *di;
  258. void *buf;
  259. int *len;
  260. int err = 0;
  261. /* 1. arg is ptr to the device_info struct */
  262. di = (struct device_info *)va_arg(ap, u_int32_t);
  263. if (di == NULL)
  264. return API_EINVAL;
  265. /* XXX should we check if device is open? i.e. the ->state ? */
  266. if (di->cookie == NULL)
  267. return API_ENODEV;
  268. /* 2. arg is ptr to buffer from where to get data to write */
  269. buf = (void *)va_arg(ap, u_int32_t);
  270. if (buf == NULL)
  271. return API_EINVAL;
  272. /* 3. arg is length of buffer */
  273. len = (int *)va_arg(ap, u_int32_t);
  274. if (len == NULL)
  275. return API_EINVAL;
  276. if (*len <= 0)
  277. return API_EINVAL;
  278. if (di->type & DEV_TYP_STOR)
  279. /*
  280. * write to storage is currently not supported by U-Boot:
  281. * no storage device implements block_write() method
  282. */
  283. return API_ENODEV;
  284. else if (di->type & DEV_TYP_NET)
  285. err = dev_write_net(di->cookie, buf, *len);
  286. else
  287. err = API_ENODEV;
  288. return err;
  289. }
  290. /*
  291. * pseudo signature:
  292. *
  293. * int API_dev_read(
  294. * struct device_info *di,
  295. * void *buf,
  296. * size_t *len,
  297. * unsigned long *start
  298. * size_t *act_len
  299. * )
  300. *
  301. * buf: ptr to buffer where to put the read data
  302. *
  303. * len: ptr to length to be read
  304. * - network: len of packet to read (in bytes)
  305. * - storage: # of blocks to read (can vary in size depending on define)
  306. *
  307. * start: ptr to start block (only used for storage devices, ignored for
  308. * network)
  309. *
  310. * act_len: ptr to where to put the len actually read
  311. */
  312. static int API_dev_read(va_list ap)
  313. {
  314. struct device_info *di;
  315. void *buf;
  316. lbasize_t *len_stor, *act_len_stor;
  317. lbastart_t *start;
  318. int *len_net, *act_len_net;
  319. /* 1. arg is ptr to the device_info struct */
  320. di = (struct device_info *)va_arg(ap, u_int32_t);
  321. if (di == NULL)
  322. return API_EINVAL;
  323. /* XXX should we check if device is open? i.e. the ->state ? */
  324. if (di->cookie == NULL)
  325. return API_ENODEV;
  326. /* 2. arg is ptr to buffer from where to put the read data */
  327. buf = (void *)va_arg(ap, u_int32_t);
  328. if (buf == NULL)
  329. return API_EINVAL;
  330. if (di->type & DEV_TYP_STOR) {
  331. /* 3. arg - ptr to var with # of blocks to read */
  332. len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
  333. if (!len_stor)
  334. return API_EINVAL;
  335. if (*len_stor <= 0)
  336. return API_EINVAL;
  337. /* 4. arg - ptr to var with start block */
  338. start = (lbastart_t *)va_arg(ap, u_int32_t);
  339. /* 5. arg - ptr to var where to put the len actually read */
  340. act_len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
  341. if (!act_len_stor)
  342. return API_EINVAL;
  343. *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
  344. } else if (di->type & DEV_TYP_NET) {
  345. /* 3. arg points to the var with length of packet to read */
  346. len_net = (int *)va_arg(ap, u_int32_t);
  347. if (!len_net)
  348. return API_EINVAL;
  349. if (*len_net <= 0)
  350. return API_EINVAL;
  351. /* 4. - ptr to var where to put the len actually read */
  352. act_len_net = (int *)va_arg(ap, u_int32_t);
  353. if (!act_len_net)
  354. return API_EINVAL;
  355. *act_len_net = dev_read_net(di->cookie, buf, *len_net);
  356. } else
  357. return API_ENODEV;
  358. return 0;
  359. }
  360. /*
  361. * pseudo signature:
  362. *
  363. * int API_env_get(const char *name, char **value)
  364. *
  365. * name: ptr to name of env var
  366. */
  367. static int API_env_get(va_list ap)
  368. {
  369. char *name, **value;
  370. if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
  371. return API_EINVAL;
  372. if ((value = (char **)va_arg(ap, u_int32_t)) == NULL)
  373. return API_EINVAL;
  374. *value = getenv(name);
  375. return 0;
  376. }
  377. /*
  378. * pseudo signature:
  379. *
  380. * int API_env_set(const char *name, const char *value)
  381. *
  382. * name: ptr to name of env var
  383. *
  384. * value: ptr to value to be set
  385. */
  386. static int API_env_set(va_list ap)
  387. {
  388. char *name, *value;
  389. if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
  390. return API_EINVAL;
  391. if ((value = (char *)va_arg(ap, u_int32_t)) == NULL)
  392. return API_EINVAL;
  393. setenv(name, value);
  394. return 0;
  395. }
  396. /*
  397. * pseudo signature:
  398. *
  399. * int API_env_enum(const char *last, char **next)
  400. *
  401. * last: ptr to name of env var found in last iteration
  402. */
  403. static int API_env_enum(va_list ap)
  404. {
  405. int i, n;
  406. char *last, **next;
  407. last = (char *)va_arg(ap, u_int32_t);
  408. if ((next = (char **)va_arg(ap, u_int32_t)) == NULL)
  409. return API_EINVAL;
  410. if (last == NULL)
  411. /* start over */
  412. *next = ((char *)env_get_addr(0));
  413. else {
  414. *next = last;
  415. for (i = 0; env_get_char(i) != '\0'; i = n + 1) {
  416. for (n = i; env_get_char(n) != '\0'; ++n) {
  417. if (n >= CONFIG_ENV_SIZE) {
  418. /* XXX shouldn't we set *next = NULL?? */
  419. return 0;
  420. }
  421. }
  422. if (envmatch((uchar *)last, i) < 0)
  423. continue;
  424. /* try to get next name */
  425. i = n + 1;
  426. if (env_get_char(i) == '\0') {
  427. /* no more left */
  428. *next = NULL;
  429. return 0;
  430. }
  431. *next = ((char *)env_get_addr(i));
  432. return 0;
  433. }
  434. }
  435. return 0;
  436. }
  437. /*
  438. * pseudo signature:
  439. *
  440. * int API_display_get_info(int type, struct display_info *di)
  441. */
  442. static int API_display_get_info(va_list ap)
  443. {
  444. int type;
  445. struct display_info *di;
  446. type = va_arg(ap, int);
  447. di = va_arg(ap, struct display_info *);
  448. return display_get_info(type, di);
  449. }
  450. /*
  451. * pseudo signature:
  452. *
  453. * int API_display_draw_bitmap(ulong bitmap, int x, int y)
  454. */
  455. static int API_display_draw_bitmap(va_list ap)
  456. {
  457. ulong bitmap;
  458. int x, y;
  459. bitmap = va_arg(ap, ulong);
  460. x = va_arg(ap, int);
  461. y = va_arg(ap, int);
  462. return display_draw_bitmap(bitmap, x, y);
  463. }
  464. /*
  465. * pseudo signature:
  466. *
  467. * void API_display_clear(void)
  468. */
  469. static int API_display_clear(va_list ap)
  470. {
  471. display_clear();
  472. return 0;
  473. }
  474. static cfp_t calls_table[API_MAXCALL] = { NULL, };
  475. /*
  476. * The main syscall entry point - this is not reentrant, only one call is
  477. * serviced until finished.
  478. *
  479. * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
  480. *
  481. * call: syscall number
  482. *
  483. * retval: points to the return value placeholder, this is the place the
  484. * syscall puts its return value, if NULL the caller does not
  485. * expect a return value
  486. *
  487. * ... syscall arguments (variable number)
  488. *
  489. * returns: 0 if the call not found, 1 if serviced
  490. */
  491. int syscall(int call, int *retval, ...)
  492. {
  493. va_list ap;
  494. int rv;
  495. if (call < 0 || call >= calls_no) {
  496. debugf("invalid call #%d\n", call);
  497. return 0;
  498. }
  499. if (calls_table[call] == NULL) {
  500. debugf("syscall #%d does not have a handler\n", call);
  501. return 0;
  502. }
  503. va_start(ap, retval);
  504. rv = calls_table[call](ap);
  505. if (retval != NULL)
  506. *retval = rv;
  507. return 1;
  508. }
  509. void api_init(void)
  510. {
  511. struct api_signature *sig = NULL;
  512. /* TODO put this into linker set one day... */
  513. calls_table[API_RSVD] = NULL;
  514. calls_table[API_GETC] = &API_getc;
  515. calls_table[API_PUTC] = &API_putc;
  516. calls_table[API_TSTC] = &API_tstc;
  517. calls_table[API_PUTS] = &API_puts;
  518. calls_table[API_RESET] = &API_reset;
  519. calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
  520. calls_table[API_UDELAY] = &API_udelay;
  521. calls_table[API_GET_TIMER] = &API_get_timer;
  522. calls_table[API_DEV_ENUM] = &API_dev_enum;
  523. calls_table[API_DEV_OPEN] = &API_dev_open;
  524. calls_table[API_DEV_CLOSE] = &API_dev_close;
  525. calls_table[API_DEV_READ] = &API_dev_read;
  526. calls_table[API_DEV_WRITE] = &API_dev_write;
  527. calls_table[API_ENV_GET] = &API_env_get;
  528. calls_table[API_ENV_SET] = &API_env_set;
  529. calls_table[API_ENV_ENUM] = &API_env_enum;
  530. calls_table[API_DISPLAY_GET_INFO] = &API_display_get_info;
  531. calls_table[API_DISPLAY_DRAW_BITMAP] = &API_display_draw_bitmap;
  532. calls_table[API_DISPLAY_CLEAR] = &API_display_clear;
  533. calls_no = API_MAXCALL;
  534. debugf("API initialized with %d calls\n", calls_no);
  535. dev_stor_init();
  536. /*
  537. * Produce the signature so the API consumers can find it
  538. */
  539. sig = malloc(sizeof(struct api_signature));
  540. if (sig == NULL) {
  541. printf("API: could not allocate memory for the signature!\n");
  542. return;
  543. }
  544. debugf("API sig @ 0x%08x\n", sig);
  545. memcpy(sig->magic, API_SIG_MAGIC, 8);
  546. sig->version = API_SIG_VERSION;
  547. sig->syscall = &syscall;
  548. sig->checksum = 0;
  549. sig->checksum = crc32(0, (unsigned char *)sig,
  550. sizeof(struct api_signature));
  551. debugf("syscall entry: 0x%08x\n", sig->syscall);
  552. }
  553. void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
  554. int flags)
  555. {
  556. int i;
  557. if (!si->mr || !size || (flags == 0))
  558. return;
  559. /* find free slot */
  560. for (i = 0; i < si->mr_no; i++)
  561. if (si->mr[i].flags == 0) {
  562. /* insert new mem region */
  563. si->mr[i].start = start;
  564. si->mr[i].size = size;
  565. si->mr[i].flags = flags;
  566. return;
  567. }
  568. }