arm-compat-semi.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. /*
  2. * Semihosting support for systems modeled on the Arm "Angel"
  3. * semihosting syscalls design. This includes Arm and RISC-V processors
  4. *
  5. * Copyright (c) 2005, 2007 CodeSourcery.
  6. * Copyright (c) 2019 Linaro
  7. * Written by Paul Brook.
  8. *
  9. * Copyright © 2020 by Keith Packard <keithp@keithp.com>
  10. * Adapted for systems other than ARM, including RISC-V, by Keith Packard
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  24. *
  25. * ARM Semihosting is documented in:
  26. * Semihosting for AArch32 and AArch64 Release 2.0
  27. * https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst
  28. *
  29. * RISC-V Semihosting is documented in:
  30. * RISC-V Semihosting
  31. * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
  32. */
  33. #include "qemu/osdep.h"
  34. #include "qemu/timer.h"
  35. #include "exec/gdbstub.h"
  36. #include "gdbstub/syscalls.h"
  37. #include "semihosting/semihost.h"
  38. #include "semihosting/console.h"
  39. #include "semihosting/common-semi.h"
  40. #include "semihosting/guestfd.h"
  41. #include "semihosting/syscalls.h"
  42. #ifdef CONFIG_USER_ONLY
  43. #include "qemu.h"
  44. #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
  45. #else
  46. #include "qemu/cutils.h"
  47. #include "hw/loader.h"
  48. #include "hw/boards.h"
  49. #endif
  50. #define TARGET_SYS_OPEN 0x01
  51. #define TARGET_SYS_CLOSE 0x02
  52. #define TARGET_SYS_WRITEC 0x03
  53. #define TARGET_SYS_WRITE0 0x04
  54. #define TARGET_SYS_WRITE 0x05
  55. #define TARGET_SYS_READ 0x06
  56. #define TARGET_SYS_READC 0x07
  57. #define TARGET_SYS_ISERROR 0x08
  58. #define TARGET_SYS_ISTTY 0x09
  59. #define TARGET_SYS_SEEK 0x0a
  60. #define TARGET_SYS_FLEN 0x0c
  61. #define TARGET_SYS_TMPNAM 0x0d
  62. #define TARGET_SYS_REMOVE 0x0e
  63. #define TARGET_SYS_RENAME 0x0f
  64. #define TARGET_SYS_CLOCK 0x10
  65. #define TARGET_SYS_TIME 0x11
  66. #define TARGET_SYS_SYSTEM 0x12
  67. #define TARGET_SYS_ERRNO 0x13
  68. #define TARGET_SYS_GET_CMDLINE 0x15
  69. #define TARGET_SYS_HEAPINFO 0x16
  70. #define TARGET_SYS_EXIT 0x18
  71. #define TARGET_SYS_SYNCCACHE 0x19
  72. #define TARGET_SYS_EXIT_EXTENDED 0x20
  73. #define TARGET_SYS_ELAPSED 0x30
  74. #define TARGET_SYS_TICKFREQ 0x31
  75. /* ADP_Stopped_ApplicationExit is used for exit(0),
  76. * anything else is implemented as exit(1) */
  77. #define ADP_Stopped_ApplicationExit (0x20026)
  78. #ifndef O_BINARY
  79. #define O_BINARY 0
  80. #endif
  81. static int gdb_open_modeflags[12] = {
  82. GDB_O_RDONLY,
  83. GDB_O_RDONLY,
  84. GDB_O_RDWR,
  85. GDB_O_RDWR,
  86. GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
  87. GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
  88. GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
  89. GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
  90. GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
  91. GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
  92. GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
  93. GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
  94. };
  95. #ifndef CONFIG_USER_ONLY
  96. /**
  97. * common_semi_find_bases: find information about ram and heap base
  98. *
  99. * This function attempts to provide meaningful numbers for RAM and
  100. * HEAP base addresses. The rambase is simply the lowest addressable
  101. * RAM position. For the heapbase we ask the loader to scan the
  102. * address space and the largest available gap by querying the "ROM"
  103. * regions.
  104. *
  105. * Returns: a structure with the numbers we need.
  106. */
  107. typedef struct LayoutInfo {
  108. target_ulong rambase;
  109. size_t ramsize;
  110. hwaddr heapbase;
  111. hwaddr heaplimit;
  112. } LayoutInfo;
  113. static bool find_ram_cb(Int128 start, Int128 len, const MemoryRegion *mr,
  114. hwaddr offset_in_region, void *opaque)
  115. {
  116. LayoutInfo *info = (LayoutInfo *) opaque;
  117. uint64_t size = int128_get64(len);
  118. if (!mr->ram || mr->readonly) {
  119. return false;
  120. }
  121. if (size > info->ramsize) {
  122. info->rambase = int128_get64(start);
  123. info->ramsize = size;
  124. }
  125. /* search exhaustively for largest RAM */
  126. return false;
  127. }
  128. static LayoutInfo common_semi_find_bases(CPUState *cs)
  129. {
  130. FlatView *fv;
  131. LayoutInfo info = { 0, 0, 0, 0 };
  132. RCU_READ_LOCK_GUARD();
  133. fv = address_space_to_flatview(cs->as);
  134. flatview_for_each_range(fv, find_ram_cb, &info);
  135. /*
  136. * If we have found the RAM lets iterate through the ROM blobs to
  137. * work out the best place for the remainder of RAM and split it
  138. * equally between stack and heap.
  139. */
  140. if (info.rambase || info.ramsize > 0) {
  141. RomGap gap = rom_find_largest_gap_between(info.rambase, info.ramsize);
  142. info.heapbase = gap.base;
  143. info.heaplimit = gap.base + gap.size;
  144. }
  145. return info;
  146. }
  147. #endif
  148. #include "cpu.h"
  149. #include "common-semi-target.h"
  150. /*
  151. * Read the input value from the argument block; fail the semihosting
  152. * call if the memory read fails. Eventually we could use a generic
  153. * CPUState helper function here.
  154. * Note that GET_ARG() handles memory access errors by jumping to
  155. * do_fault, so must be used as the first thing done in handling a
  156. * semihosting call, to avoid accidentally leaking allocated resources.
  157. * SET_ARG(), since it unavoidably happens late, instead returns an
  158. * error indication (0 on success, non-0 for error) which the caller
  159. * should check.
  160. */
  161. #define GET_ARG(n) do { \
  162. if (is_64bit_semihosting(env)) { \
  163. if (get_user_u64(arg ## n, args + (n) * 8)) { \
  164. goto do_fault; \
  165. } \
  166. } else { \
  167. if (get_user_u32(arg ## n, args + (n) * 4)) { \
  168. goto do_fault; \
  169. } \
  170. } \
  171. } while (0)
  172. #define SET_ARG(n, val) \
  173. (is_64bit_semihosting(env) ? \
  174. put_user_u64(val, args + (n) * 8) : \
  175. put_user_u32(val, args + (n) * 4))
  176. /*
  177. * The semihosting API has no concept of its errno being thread-safe,
  178. * as the API design predates SMP CPUs and was intended as a simple
  179. * real-hardware set of debug functionality. For QEMU, we make the
  180. * errno be per-thread in linux-user mode; in system-mode it is a simple
  181. * global, and we assume that the guest takes care of avoiding any races.
  182. */
  183. #ifndef CONFIG_USER_ONLY
  184. static target_ulong syscall_err;
  185. #include "semihosting/uaccess.h"
  186. #endif
  187. static inline uint32_t get_swi_errno(CPUState *cs)
  188. {
  189. #ifdef CONFIG_USER_ONLY
  190. TaskState *ts = get_task_state(cs);
  191. return ts->swi_errno;
  192. #else
  193. return syscall_err;
  194. #endif
  195. }
  196. static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
  197. {
  198. if (err) {
  199. #ifdef CONFIG_USER_ONLY
  200. TaskState *ts = get_task_state(cs);
  201. ts->swi_errno = err;
  202. #else
  203. syscall_err = err;
  204. #endif
  205. }
  206. common_semi_set_ret(cs, ret);
  207. }
  208. /*
  209. * Use 0xdeadbeef as the return value when there isn't a defined
  210. * return value for the call.
  211. */
  212. static void common_semi_dead_cb(CPUState *cs, uint64_t ret, int err)
  213. {
  214. common_semi_set_ret(cs, 0xdeadbeef);
  215. }
  216. /*
  217. * SYS_READ and SYS_WRITE always return the number of bytes not read/written.
  218. * There is no error condition, other than returning the original length.
  219. */
  220. static void common_semi_rw_cb(CPUState *cs, uint64_t ret, int err)
  221. {
  222. /* Recover the original length from the third argument. */
  223. CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
  224. target_ulong args = common_semi_arg(cs, 1);
  225. target_ulong arg2;
  226. GET_ARG(2);
  227. if (err) {
  228. do_fault:
  229. ret = 0; /* error: no bytes transmitted */
  230. }
  231. common_semi_set_ret(cs, arg2 - ret);
  232. }
  233. /*
  234. * Convert from Posix ret+errno to Arm SYS_ISTTY return values.
  235. * With gdbstub, err is only ever set for protocol errors to EIO.
  236. */
  237. static void common_semi_istty_cb(CPUState *cs, uint64_t ret, int err)
  238. {
  239. if (err) {
  240. ret = (err == ENOTTY ? 0 : -1);
  241. }
  242. common_semi_cb(cs, ret, err);
  243. }
  244. /*
  245. * SYS_SEEK returns 0 on success, not the resulting offset.
  246. */
  247. static void common_semi_seek_cb(CPUState *cs, uint64_t ret, int err)
  248. {
  249. if (!err) {
  250. ret = 0;
  251. }
  252. common_semi_cb(cs, ret, err);
  253. }
  254. /*
  255. * Return an address in target memory of 64 bytes where the remote
  256. * gdb should write its stat struct. (The format of this structure
  257. * is defined by GDB's remote protocol and is not target-specific.)
  258. * We put this on the guest's stack just below SP.
  259. */
  260. static target_ulong common_semi_flen_buf(CPUState *cs)
  261. {
  262. target_ulong sp = common_semi_stack_bottom(cs);
  263. return sp - 64;
  264. }
  265. static void
  266. common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, int err)
  267. {
  268. if (!err) {
  269. /* The size is always stored in big-endian order, extract the value. */
  270. uint64_t size;
  271. if (cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) +
  272. offsetof(struct gdb_stat, gdb_st_size),
  273. &size, 8, 0)) {
  274. ret = -1, err = EFAULT;
  275. } else {
  276. size = be64_to_cpu(size);
  277. if (ret != size) {
  278. ret = -1, err = EOVERFLOW;
  279. }
  280. }
  281. }
  282. common_semi_cb(cs, ret, err);
  283. }
  284. static void
  285. common_semi_readc_cb(CPUState *cs, uint64_t ret, int err)
  286. {
  287. if (!err) {
  288. CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
  289. uint8_t ch;
  290. if (get_user_u8(ch, common_semi_stack_bottom(cs) - 1)) {
  291. ret = -1, err = EFAULT;
  292. } else {
  293. ret = ch;
  294. }
  295. }
  296. common_semi_cb(cs, ret, err);
  297. }
  298. #define SHFB_MAGIC_0 0x53
  299. #define SHFB_MAGIC_1 0x48
  300. #define SHFB_MAGIC_2 0x46
  301. #define SHFB_MAGIC_3 0x42
  302. /* Feature bits reportable in feature byte 0 */
  303. #define SH_EXT_EXIT_EXTENDED (1 << 0)
  304. #define SH_EXT_STDOUT_STDERR (1 << 1)
  305. static const uint8_t featurefile_data[] = {
  306. SHFB_MAGIC_0,
  307. SHFB_MAGIC_1,
  308. SHFB_MAGIC_2,
  309. SHFB_MAGIC_3,
  310. SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
  311. };
  312. /*
  313. * Do a semihosting call.
  314. *
  315. * The specification always says that the "return register" either
  316. * returns a specific value or is corrupted, so we don't need to
  317. * report to our caller whether we are returning a value or trying to
  318. * leave the register unchanged.
  319. */
  320. void do_common_semihosting(CPUState *cs)
  321. {
  322. CPUArchState *env = cpu_env(cs);
  323. target_ulong args;
  324. target_ulong arg0, arg1, arg2, arg3;
  325. target_ulong ul_ret;
  326. char * s;
  327. int nr;
  328. int64_t elapsed;
  329. nr = common_semi_arg(cs, 0) & 0xffffffffU;
  330. args = common_semi_arg(cs, 1);
  331. switch (nr) {
  332. case TARGET_SYS_OPEN:
  333. {
  334. int ret, err = 0;
  335. int hostfd;
  336. GET_ARG(0);
  337. GET_ARG(1);
  338. GET_ARG(2);
  339. s = lock_user_string(arg0);
  340. if (!s) {
  341. goto do_fault;
  342. }
  343. if (arg1 >= 12) {
  344. unlock_user(s, arg0, 0);
  345. common_semi_cb(cs, -1, EINVAL);
  346. break;
  347. }
  348. if (strcmp(s, ":tt") == 0) {
  349. /*
  350. * We implement SH_EXT_STDOUT_STDERR, so:
  351. * open for read == stdin
  352. * open for write == stdout
  353. * open for append == stderr
  354. */
  355. if (arg1 < 4) {
  356. hostfd = STDIN_FILENO;
  357. } else if (arg1 < 8) {
  358. hostfd = STDOUT_FILENO;
  359. } else {
  360. hostfd = STDERR_FILENO;
  361. }
  362. ret = alloc_guestfd();
  363. associate_guestfd(ret, hostfd);
  364. } else if (strcmp(s, ":semihosting-features") == 0) {
  365. /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
  366. if (arg1 != 0 && arg1 != 1) {
  367. ret = -1;
  368. err = EACCES;
  369. } else {
  370. ret = alloc_guestfd();
  371. staticfile_guestfd(ret, featurefile_data,
  372. sizeof(featurefile_data));
  373. }
  374. } else {
  375. unlock_user(s, arg0, 0);
  376. semihost_sys_open(cs, common_semi_cb, arg0, arg2 + 1,
  377. gdb_open_modeflags[arg1], 0644);
  378. break;
  379. }
  380. unlock_user(s, arg0, 0);
  381. common_semi_cb(cs, ret, err);
  382. break;
  383. }
  384. case TARGET_SYS_CLOSE:
  385. GET_ARG(0);
  386. semihost_sys_close(cs, common_semi_cb, arg0);
  387. break;
  388. case TARGET_SYS_WRITEC:
  389. /*
  390. * FIXME: the byte to be written is in a target_ulong slot,
  391. * which means this is wrong for a big-endian guest.
  392. */
  393. semihost_sys_write_gf(cs, common_semi_dead_cb,
  394. &console_out_gf, args, 1);
  395. break;
  396. case TARGET_SYS_WRITE0:
  397. {
  398. ssize_t len = target_strlen(args);
  399. if (len < 0) {
  400. common_semi_dead_cb(cs, -1, EFAULT);
  401. } else {
  402. semihost_sys_write_gf(cs, common_semi_dead_cb,
  403. &console_out_gf, args, len);
  404. }
  405. }
  406. break;
  407. case TARGET_SYS_WRITE:
  408. GET_ARG(0);
  409. GET_ARG(1);
  410. GET_ARG(2);
  411. semihost_sys_write(cs, common_semi_rw_cb, arg0, arg1, arg2);
  412. break;
  413. case TARGET_SYS_READ:
  414. GET_ARG(0);
  415. GET_ARG(1);
  416. GET_ARG(2);
  417. semihost_sys_read(cs, common_semi_rw_cb, arg0, arg1, arg2);
  418. break;
  419. case TARGET_SYS_READC:
  420. semihost_sys_read_gf(cs, common_semi_readc_cb, &console_in_gf,
  421. common_semi_stack_bottom(cs) - 1, 1);
  422. break;
  423. case TARGET_SYS_ISERROR:
  424. GET_ARG(0);
  425. common_semi_set_ret(cs, (target_long)arg0 < 0);
  426. break;
  427. case TARGET_SYS_ISTTY:
  428. GET_ARG(0);
  429. semihost_sys_isatty(cs, common_semi_istty_cb, arg0);
  430. break;
  431. case TARGET_SYS_SEEK:
  432. GET_ARG(0);
  433. GET_ARG(1);
  434. semihost_sys_lseek(cs, common_semi_seek_cb, arg0, arg1, GDB_SEEK_SET);
  435. break;
  436. case TARGET_SYS_FLEN:
  437. GET_ARG(0);
  438. semihost_sys_flen(cs, common_semi_flen_fstat_cb, common_semi_cb,
  439. arg0, common_semi_flen_buf(cs));
  440. break;
  441. case TARGET_SYS_TMPNAM:
  442. {
  443. int len;
  444. char *p;
  445. GET_ARG(0);
  446. GET_ARG(1);
  447. GET_ARG(2);
  448. len = asprintf(&s, "%s/qemu-%x%02x", g_get_tmp_dir(),
  449. getpid(), (int)arg1 & 0xff);
  450. if (len < 0) {
  451. common_semi_set_ret(cs, -1);
  452. break;
  453. }
  454. /* Allow for trailing NUL */
  455. len++;
  456. /* Make sure there's enough space in the buffer */
  457. if (len > arg2) {
  458. free(s);
  459. common_semi_set_ret(cs, -1);
  460. break;
  461. }
  462. p = lock_user(VERIFY_WRITE, arg0, len, 0);
  463. if (!p) {
  464. free(s);
  465. goto do_fault;
  466. }
  467. memcpy(p, s, len);
  468. unlock_user(p, arg0, len);
  469. free(s);
  470. common_semi_set_ret(cs, 0);
  471. break;
  472. }
  473. case TARGET_SYS_REMOVE:
  474. GET_ARG(0);
  475. GET_ARG(1);
  476. semihost_sys_remove(cs, common_semi_cb, arg0, arg1 + 1);
  477. break;
  478. case TARGET_SYS_RENAME:
  479. GET_ARG(0);
  480. GET_ARG(1);
  481. GET_ARG(2);
  482. GET_ARG(3);
  483. semihost_sys_rename(cs, common_semi_cb, arg0, arg1 + 1, arg2, arg3 + 1);
  484. break;
  485. case TARGET_SYS_CLOCK:
  486. common_semi_set_ret(cs, clock() / (CLOCKS_PER_SEC / 100));
  487. break;
  488. case TARGET_SYS_TIME:
  489. ul_ret = time(NULL);
  490. common_semi_cb(cs, ul_ret, ul_ret == -1 ? errno : 0);
  491. break;
  492. case TARGET_SYS_SYSTEM:
  493. GET_ARG(0);
  494. GET_ARG(1);
  495. semihost_sys_system(cs, common_semi_cb, arg0, arg1 + 1);
  496. break;
  497. case TARGET_SYS_ERRNO:
  498. common_semi_set_ret(cs, get_swi_errno(cs));
  499. break;
  500. case TARGET_SYS_GET_CMDLINE:
  501. {
  502. /* Build a command-line from the original argv.
  503. *
  504. * The inputs are:
  505. * * arg0, pointer to a buffer of at least the size
  506. * specified in arg1.
  507. * * arg1, size of the buffer pointed to by arg0 in
  508. * bytes.
  509. *
  510. * The outputs are:
  511. * * arg0, pointer to null-terminated string of the
  512. * command line.
  513. * * arg1, length of the string pointed to by arg0.
  514. */
  515. char *output_buffer;
  516. size_t input_size;
  517. size_t output_size;
  518. int status = 0;
  519. #if !defined(CONFIG_USER_ONLY)
  520. const char *cmdline;
  521. #else
  522. TaskState *ts = get_task_state(cs);
  523. #endif
  524. GET_ARG(0);
  525. GET_ARG(1);
  526. input_size = arg1;
  527. /* Compute the size of the output string. */
  528. #if !defined(CONFIG_USER_ONLY)
  529. cmdline = semihosting_get_cmdline();
  530. if (cmdline == NULL) {
  531. cmdline = ""; /* Default to an empty line. */
  532. }
  533. output_size = strlen(cmdline) + 1; /* Count terminating 0. */
  534. #else
  535. unsigned int i;
  536. output_size = ts->info->env_strings - ts->info->arg_strings;
  537. if (!output_size) {
  538. /*
  539. * We special-case the "empty command line" case (argc==0).
  540. * Just provide the terminating 0.
  541. */
  542. output_size = 1;
  543. }
  544. #endif
  545. if (output_size > input_size) {
  546. /* Not enough space to store command-line arguments. */
  547. common_semi_cb(cs, -1, E2BIG);
  548. break;
  549. }
  550. /* Adjust the command-line length. */
  551. if (SET_ARG(1, output_size - 1)) {
  552. /* Couldn't write back to argument block */
  553. goto do_fault;
  554. }
  555. /* Lock the buffer on the ARM side. */
  556. output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
  557. if (!output_buffer) {
  558. goto do_fault;
  559. }
  560. /* Copy the command-line arguments. */
  561. #if !defined(CONFIG_USER_ONLY)
  562. pstrcpy(output_buffer, output_size, cmdline);
  563. #else
  564. if (output_size == 1) {
  565. /* Empty command-line. */
  566. output_buffer[0] = '\0';
  567. goto out;
  568. }
  569. if (copy_from_user(output_buffer, ts->info->arg_strings,
  570. output_size)) {
  571. unlock_user(output_buffer, arg0, 0);
  572. goto do_fault;
  573. }
  574. /* Separate arguments by white spaces. */
  575. for (i = 0; i < output_size - 1; i++) {
  576. if (output_buffer[i] == 0) {
  577. output_buffer[i] = ' ';
  578. }
  579. }
  580. out:
  581. #endif
  582. /* Unlock the buffer on the ARM side. */
  583. unlock_user(output_buffer, arg0, output_size);
  584. common_semi_cb(cs, status, 0);
  585. }
  586. break;
  587. case TARGET_SYS_HEAPINFO:
  588. {
  589. target_ulong retvals[4];
  590. int i;
  591. #ifdef CONFIG_USER_ONLY
  592. TaskState *ts = get_task_state(cs);
  593. target_ulong limit;
  594. #else
  595. LayoutInfo info = common_semi_find_bases(cs);
  596. #endif
  597. GET_ARG(0);
  598. #ifdef CONFIG_USER_ONLY
  599. /*
  600. * Some C libraries assume the heap immediately follows .bss, so
  601. * allocate it using sbrk.
  602. */
  603. if (!ts->heap_limit) {
  604. abi_ulong ret;
  605. ts->heap_base = do_brk(0);
  606. limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE;
  607. /* Try a big heap, and reduce the size if that fails. */
  608. for (;;) {
  609. ret = do_brk(limit);
  610. if (ret >= limit) {
  611. break;
  612. }
  613. limit = (ts->heap_base >> 1) + (limit >> 1);
  614. }
  615. ts->heap_limit = limit;
  616. }
  617. retvals[0] = ts->heap_base;
  618. retvals[1] = ts->heap_limit;
  619. retvals[2] = ts->stack_base;
  620. retvals[3] = 0; /* Stack limit. */
  621. #else
  622. retvals[0] = info.heapbase; /* Heap Base */
  623. retvals[1] = info.heaplimit; /* Heap Limit */
  624. retvals[2] = info.heaplimit; /* Stack base */
  625. retvals[3] = info.heapbase; /* Stack limit. */
  626. #endif
  627. for (i = 0; i < ARRAY_SIZE(retvals); i++) {
  628. bool fail;
  629. if (is_64bit_semihosting(env)) {
  630. fail = put_user_u64(retvals[i], arg0 + i * 8);
  631. } else {
  632. fail = put_user_u32(retvals[i], arg0 + i * 4);
  633. }
  634. if (fail) {
  635. /* Couldn't write back to argument block */
  636. goto do_fault;
  637. }
  638. }
  639. common_semi_set_ret(cs, 0);
  640. }
  641. break;
  642. case TARGET_SYS_EXIT:
  643. case TARGET_SYS_EXIT_EXTENDED:
  644. {
  645. uint32_t ret;
  646. if (common_semi_sys_exit_extended(cs, nr)) {
  647. /*
  648. * The A64 version of SYS_EXIT takes a parameter block,
  649. * so the application-exit type can return a subcode which
  650. * is the exit status code from the application.
  651. * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
  652. * which allows A32/T32 guests to also provide a status code.
  653. */
  654. GET_ARG(0);
  655. GET_ARG(1);
  656. if (arg0 == ADP_Stopped_ApplicationExit) {
  657. ret = arg1;
  658. } else {
  659. ret = 1;
  660. }
  661. } else {
  662. /*
  663. * The A32/T32 version of SYS_EXIT specifies only
  664. * Stopped_ApplicationExit as normal exit, but does not
  665. * allow the guest to specify the exit status code.
  666. * Everything else is considered an error.
  667. */
  668. ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
  669. }
  670. gdb_exit(ret);
  671. exit(ret);
  672. }
  673. case TARGET_SYS_ELAPSED:
  674. elapsed = get_clock() - clock_start;
  675. if (sizeof(target_ulong) == 8) {
  676. if (SET_ARG(0, elapsed)) {
  677. goto do_fault;
  678. }
  679. } else {
  680. if (SET_ARG(0, (uint32_t) elapsed) ||
  681. SET_ARG(1, (uint32_t) (elapsed >> 32))) {
  682. goto do_fault;
  683. }
  684. }
  685. common_semi_set_ret(cs, 0);
  686. break;
  687. case TARGET_SYS_TICKFREQ:
  688. /* qemu always uses nsec */
  689. common_semi_set_ret(cs, 1000000000);
  690. break;
  691. case TARGET_SYS_SYNCCACHE:
  692. /*
  693. * Clean the D-cache and invalidate the I-cache for the specified
  694. * virtual address range. This is a nop for us since we don't
  695. * implement caches. This is only present on A64.
  696. */
  697. if (common_semi_has_synccache(env)) {
  698. common_semi_set_ret(cs, 0);
  699. break;
  700. }
  701. /* fall through */
  702. default:
  703. fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
  704. cpu_dump_state(cs, stderr, 0);
  705. abort();
  706. do_fault:
  707. common_semi_cb(cs, -1, EFAULT);
  708. break;
  709. }
  710. }