Fork of the vendor (Boundary Devices) u-boot for Reform 2, with minor tweaks. The goal is to migrate to mainstream u-boot or barebox ASAP. The main impediment so far is the 4GB RAM config.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

694 lines
14KB

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