1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include "qemu/osdep.h"
35
36#include "semihosting/semihost.h"
37#include "semihosting/console.h"
38#include "semihosting/common-semi.h"
39#include "qemu/timer.h"
40#ifdef CONFIG_USER_ONLY
41#include "qemu.h"
42
43#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
44#else
45#include "exec/gdbstub.h"
46#include "qemu/cutils.h"
47#ifdef TARGET_ARM
48#include "hw/arm/boot.h"
49#endif
50#include "hw/boards.h"
51#endif
52
53#define TARGET_SYS_OPEN 0x01
54#define TARGET_SYS_CLOSE 0x02
55#define TARGET_SYS_WRITEC 0x03
56#define TARGET_SYS_WRITE0 0x04
57#define TARGET_SYS_WRITE 0x05
58#define TARGET_SYS_READ 0x06
59#define TARGET_SYS_READC 0x07
60#define TARGET_SYS_ISERROR 0x08
61#define TARGET_SYS_ISTTY 0x09
62#define TARGET_SYS_SEEK 0x0a
63#define TARGET_SYS_FLEN 0x0c
64#define TARGET_SYS_TMPNAM 0x0d
65#define TARGET_SYS_REMOVE 0x0e
66#define TARGET_SYS_RENAME 0x0f
67#define TARGET_SYS_CLOCK 0x10
68#define TARGET_SYS_TIME 0x11
69#define TARGET_SYS_SYSTEM 0x12
70#define TARGET_SYS_ERRNO 0x13
71#define TARGET_SYS_GET_CMDLINE 0x15
72#define TARGET_SYS_HEAPINFO 0x16
73#define TARGET_SYS_EXIT 0x18
74#define TARGET_SYS_SYNCCACHE 0x19
75#define TARGET_SYS_EXIT_EXTENDED 0x20
76#define TARGET_SYS_ELAPSED 0x30
77#define TARGET_SYS_TICKFREQ 0x31
78
79
80
81#define ADP_Stopped_ApplicationExit (0x20026)
82
83#ifndef O_BINARY
84#define O_BINARY 0
85#endif
86
87#define GDB_O_RDONLY 0x000
88#define GDB_O_WRONLY 0x001
89#define GDB_O_RDWR 0x002
90#define GDB_O_APPEND 0x008
91#define GDB_O_CREAT 0x200
92#define GDB_O_TRUNC 0x400
93#define GDB_O_BINARY 0
94
95static int gdb_open_modeflags[12] = {
96 GDB_O_RDONLY,
97 GDB_O_RDONLY | GDB_O_BINARY,
98 GDB_O_RDWR,
99 GDB_O_RDWR | GDB_O_BINARY,
100 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
101 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
102 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
103 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
104 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
105 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
106 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
107 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
108};
109
110static int open_modeflags[12] = {
111 O_RDONLY,
112 O_RDONLY | O_BINARY,
113 O_RDWR,
114 O_RDWR | O_BINARY,
115 O_WRONLY | O_CREAT | O_TRUNC,
116 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
117 O_RDWR | O_CREAT | O_TRUNC,
118 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
119 O_WRONLY | O_CREAT | O_APPEND,
120 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
121 O_RDWR | O_CREAT | O_APPEND,
122 O_RDWR | O_CREAT | O_APPEND | O_BINARY
123};
124
125typedef enum GuestFDType {
126 GuestFDUnused = 0,
127 GuestFDHost = 1,
128 GuestFDGDB = 2,
129 GuestFDFeatureFile = 3,
130} GuestFDType;
131
132
133
134
135
136typedef struct GuestFD {
137 GuestFDType type;
138 union {
139 int hostfd;
140 target_ulong featurefile_offset;
141 };
142} GuestFD;
143
144static GArray *guestfd_array;
145
146#ifndef CONFIG_USER_ONLY
147#include "exec/address-spaces.h"
148
149
150
151static inline hwaddr
152common_semi_find_region_base(hwaddr addr)
153{
154 MemoryRegion *subregion;
155
156
157
158
159
160
161 QTAILQ_FOREACH(subregion, &get_system_memory()->subregions,
162 subregions_link) {
163 if (subregion->ram && !subregion->readonly) {
164 Int128 top128 = int128_add(int128_make64(subregion->addr),
165 subregion->size);
166 Int128 addr128 = int128_make64(addr);
167 if (subregion->addr <= addr && int128_lt(addr128, top128)) {
168 return subregion->addr;
169 }
170 }
171 }
172 return 0;
173}
174#endif
175
176#ifdef TARGET_ARM
177static inline target_ulong
178common_semi_arg(CPUState *cs, int argno)
179{
180 ARMCPU *cpu = ARM_CPU(cs);
181 CPUARMState *env = &cpu->env;
182 if (is_a64(env)) {
183 return env->xregs[argno];
184 } else {
185 return env->regs[argno];
186 }
187}
188
189static inline void
190common_semi_set_ret(CPUState *cs, target_ulong ret)
191{
192 ARMCPU *cpu = ARM_CPU(cs);
193 CPUARMState *env = &cpu->env;
194 if (is_a64(env)) {
195 env->xregs[0] = ret;
196 } else {
197 env->regs[0] = ret;
198 }
199}
200
201static inline bool
202common_semi_sys_exit_extended(CPUState *cs, int nr)
203{
204 return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
205}
206
207#ifndef CONFIG_USER_ONLY
208#include "hw/arm/boot.h"
209static inline target_ulong
210common_semi_rambase(CPUState *cs)
211{
212 CPUArchState *env = cs->env_ptr;
213 const struct arm_boot_info *info = env->boot_info;
214 target_ulong sp;
215
216 if (info) {
217 return info->loader_start;
218 }
219
220 if (is_a64(env)) {
221 sp = env->xregs[31];
222 } else {
223 sp = env->regs[13];
224 }
225 return common_semi_find_region_base(sp);
226}
227#endif
228
229#endif
230
231#ifdef TARGET_RISCV
232static inline target_ulong
233common_semi_arg(CPUState *cs, int argno)
234{
235 RISCVCPU *cpu = RISCV_CPU(cs);
236 CPURISCVState *env = &cpu->env;
237 return env->gpr[xA0 + argno];
238}
239
240static inline void
241common_semi_set_ret(CPUState *cs, target_ulong ret)
242{
243 RISCVCPU *cpu = RISCV_CPU(cs);
244 CPURISCVState *env = &cpu->env;
245 env->gpr[xA0] = ret;
246}
247
248static inline bool
249common_semi_sys_exit_extended(CPUState *cs, int nr)
250{
251 return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
252}
253
254#ifndef CONFIG_USER_ONLY
255
256static inline target_ulong
257common_semi_rambase(CPUState *cs)
258{
259 RISCVCPU *cpu = RISCV_CPU(cs);
260 CPURISCVState *env = &cpu->env;
261 return common_semi_find_region_base(env->gpr[xSP]);
262}
263#endif
264
265#endif
266
267
268
269
270
271
272
273
274static int alloc_guestfd(void)
275{
276 guint i;
277
278 if (!guestfd_array) {
279
280 guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
281 }
282
283
284 for (i = 1; i < guestfd_array->len; i++) {
285 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
286
287 if (gf->type == GuestFDUnused) {
288 return i;
289 }
290 }
291
292
293 g_array_set_size(guestfd_array, i + 1);
294 return i;
295}
296
297
298
299
300
301
302static GuestFD *do_get_guestfd(int guestfd)
303{
304 if (!guestfd_array) {
305 return NULL;
306 }
307
308 if (guestfd <= 0 || guestfd >= guestfd_array->len) {
309 return NULL;
310 }
311
312 return &g_array_index(guestfd_array, GuestFD, guestfd);
313}
314
315
316
317
318
319
320static void associate_guestfd(int guestfd, int hostfd)
321{
322 GuestFD *gf = do_get_guestfd(guestfd);
323
324 assert(gf);
325 gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
326 gf->hostfd = hostfd;
327}
328
329
330
331
332
333static void dealloc_guestfd(int guestfd)
334{
335 GuestFD *gf = do_get_guestfd(guestfd);
336
337 assert(gf);
338 gf->type = GuestFDUnused;
339}
340
341
342
343
344
345
346
347
348
349static GuestFD *get_guestfd(int guestfd)
350{
351 GuestFD *gf = do_get_guestfd(guestfd);
352
353 if (!gf || gf->type == GuestFDUnused) {
354 return NULL;
355 }
356 return gf;
357}
358
359
360
361
362
363
364
365
366#ifndef CONFIG_USER_ONLY
367static target_ulong syscall_err;
368
369#include "exec/softmmu-semi.h"
370#endif
371
372static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
373{
374 if (code == (uint32_t)-1) {
375#ifdef CONFIG_USER_ONLY
376 TaskState *ts = cs->opaque;
377
378 ts->swi_errno = errno;
379#else
380 syscall_err = errno;
381#endif
382 }
383 return code;
384}
385
386static inline uint32_t get_swi_errno(CPUState *cs)
387{
388#ifdef CONFIG_USER_ONLY
389 TaskState *ts = cs->opaque;
390
391 return ts->swi_errno;
392#else
393 return syscall_err;
394#endif
395}
396
397static target_ulong common_semi_syscall_len;
398
399static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
400{
401 target_ulong reg0 = common_semi_arg(cs, 0);
402
403 if (ret == (target_ulong)-1) {
404 errno = err;
405 set_swi_errno(cs, -1);
406 reg0 = ret;
407 } else {
408
409 switch (reg0) {
410 case TARGET_SYS_WRITE:
411 case TARGET_SYS_READ:
412 reg0 = common_semi_syscall_len - ret;
413 break;
414 case TARGET_SYS_SEEK:
415 reg0 = 0;
416 break;
417 default:
418 reg0 = ret;
419 break;
420 }
421 }
422 common_semi_set_ret(cs, reg0);
423}
424
425static target_ulong common_semi_flen_buf(CPUState *cs)
426{
427 target_ulong sp;
428#ifdef TARGET_ARM
429
430
431
432
433
434 ARMCPU *cpu = ARM_CPU(cs);
435 CPUARMState *env = &cpu->env;
436
437 if (is_a64(env)) {
438 sp = env->xregs[31];
439 } else {
440 sp = env->regs[13];
441 }
442#endif
443#ifdef TARGET_RISCV
444 RISCVCPU *cpu = RISCV_CPU(cs);
445 CPURISCVState *env = &cpu->env;
446
447 sp = env->gpr[xSP];
448#endif
449
450 return sp - 64;
451}
452
453static void
454common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
455{
456
457
458 uint32_t size;
459 cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32,
460 (uint8_t *)&size, 4, 0);
461 size = be32_to_cpu(size);
462 common_semi_set_ret(cs, size);
463 errno = err;
464 set_swi_errno(cs, -1);
465}
466
467static int common_semi_open_guestfd;
468
469static void
470common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
471{
472 if (ret == (target_ulong)-1) {
473 errno = err;
474 set_swi_errno(cs, -1);
475 dealloc_guestfd(common_semi_open_guestfd);
476 } else {
477 associate_guestfd(common_semi_open_guestfd, ret);
478 ret = common_semi_open_guestfd;
479 }
480 common_semi_set_ret(cs, ret);
481}
482
483static target_ulong
484common_semi_gdb_syscall(CPUState *cs, gdb_syscall_complete_cb cb,
485 const char *fmt, ...)
486{
487 va_list va;
488
489 va_start(va, fmt);
490 gdb_do_syscallv(cb, fmt, va);
491 va_end(va);
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 return common_semi_arg(cs, 0);
511}
512
513
514
515
516
517
518
519typedef uint32_t sys_closefn(CPUState *cs, GuestFD *gf);
520typedef uint32_t sys_writefn(CPUState *cs, GuestFD *gf,
521 target_ulong buf, uint32_t len);
522typedef uint32_t sys_readfn(CPUState *cs, GuestFD *gf,
523 target_ulong buf, uint32_t len);
524typedef uint32_t sys_isattyfn(CPUState *cs, GuestFD *gf);
525typedef uint32_t sys_seekfn(CPUState *cs, GuestFD *gf,
526 target_ulong offset);
527typedef uint32_t sys_flenfn(CPUState *cs, GuestFD *gf);
528
529static uint32_t host_closefn(CPUState *cs, GuestFD *gf)
530{
531
532
533
534
535 if (gf->hostfd == STDIN_FILENO ||
536 gf->hostfd == STDOUT_FILENO ||
537 gf->hostfd == STDERR_FILENO) {
538 return 0;
539 }
540 return set_swi_errno(cs, close(gf->hostfd));
541}
542
543static uint32_t host_writefn(CPUState *cs, GuestFD *gf,
544 target_ulong buf, uint32_t len)
545{
546 CPUArchState *env = cs->env_ptr;
547 uint32_t ret;
548 char *s = lock_user(VERIFY_READ, buf, len, 1);
549 (void) env;
550 if (!s) {
551
552 return len;
553 }
554 ret = set_swi_errno(cs, write(gf->hostfd, s, len));
555 unlock_user(s, buf, 0);
556 if (ret == (uint32_t)-1) {
557 ret = 0;
558 }
559
560 return len - ret;
561}
562
563static uint32_t host_readfn(CPUState *cs, GuestFD *gf,
564 target_ulong buf, uint32_t len)
565{
566 CPUArchState *env = cs->env_ptr;
567 uint32_t ret;
568 char *s = lock_user(VERIFY_WRITE, buf, len, 0);
569 (void) env;
570 if (!s) {
571
572 return len;
573 }
574 do {
575 ret = set_swi_errno(cs, read(gf->hostfd, s, len));
576 } while (ret == -1 && errno == EINTR);
577 unlock_user(s, buf, len);
578 if (ret == (uint32_t)-1) {
579 ret = 0;
580 }
581
582 return len - ret;
583}
584
585static uint32_t host_isattyfn(CPUState *cs, GuestFD *gf)
586{
587 return isatty(gf->hostfd);
588}
589
590static uint32_t host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
591{
592 uint32_t ret = set_swi_errno(cs, lseek(gf->hostfd, offset, SEEK_SET));
593 if (ret == (uint32_t)-1) {
594 return -1;
595 }
596 return 0;
597}
598
599static uint32_t host_flenfn(CPUState *cs, GuestFD *gf)
600{
601 struct stat buf;
602 uint32_t ret = set_swi_errno(cs, fstat(gf->hostfd, &buf));
603 if (ret == (uint32_t)-1) {
604 return -1;
605 }
606 return buf.st_size;
607}
608
609static uint32_t gdb_closefn(CPUState *cs, GuestFD *gf)
610{
611 return common_semi_gdb_syscall(cs, common_semi_cb, "close,%x", gf->hostfd);
612}
613
614static uint32_t gdb_writefn(CPUState *cs, GuestFD *gf,
615 target_ulong buf, uint32_t len)
616{
617 common_semi_syscall_len = len;
618 return common_semi_gdb_syscall(cs, common_semi_cb, "write,%x,%x,%x",
619 gf->hostfd, buf, len);
620}
621
622static uint32_t gdb_readfn(CPUState *cs, GuestFD *gf,
623 target_ulong buf, uint32_t len)
624{
625 common_semi_syscall_len = len;
626 return common_semi_gdb_syscall(cs, common_semi_cb, "read,%x,%x,%x",
627 gf->hostfd, buf, len);
628}
629
630static uint32_t gdb_isattyfn(CPUState *cs, GuestFD *gf)
631{
632 return common_semi_gdb_syscall(cs, common_semi_cb, "isatty,%x", gf->hostfd);
633}
634
635static uint32_t gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
636{
637 return common_semi_gdb_syscall(cs, common_semi_cb, "lseek,%x,%x,0",
638 gf->hostfd, offset);
639}
640
641static uint32_t gdb_flenfn(CPUState *cs, GuestFD *gf)
642{
643 return common_semi_gdb_syscall(cs, common_semi_flen_cb, "fstat,%x,%x",
644 gf->hostfd, common_semi_flen_buf(cs));
645}
646
647#define SHFB_MAGIC_0 0x53
648#define SHFB_MAGIC_1 0x48
649#define SHFB_MAGIC_2 0x46
650#define SHFB_MAGIC_3 0x42
651
652
653#define SH_EXT_EXIT_EXTENDED (1 << 0)
654#define SH_EXT_STDOUT_STDERR (1 << 1)
655
656static const uint8_t featurefile_data[] = {
657 SHFB_MAGIC_0,
658 SHFB_MAGIC_1,
659 SHFB_MAGIC_2,
660 SHFB_MAGIC_3,
661 SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR,
662};
663
664static void init_featurefile_guestfd(int guestfd)
665{
666 GuestFD *gf = do_get_guestfd(guestfd);
667
668 assert(gf);
669 gf->type = GuestFDFeatureFile;
670 gf->featurefile_offset = 0;
671}
672
673static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf)
674{
675
676 return 0;
677}
678
679static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf,
680 target_ulong buf, uint32_t len)
681{
682
683
684 errno = EBADF;
685 return set_swi_errno(cs, -1);
686}
687
688static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
689 target_ulong buf, uint32_t len)
690{
691 CPUArchState *env = cs->env_ptr;
692 uint32_t i;
693 char *s;
694
695 (void) env;
696 s = lock_user(VERIFY_WRITE, buf, len, 0);
697 if (!s) {
698 return len;
699 }
700
701 for (i = 0; i < len; i++) {
702 if (gf->featurefile_offset >= sizeof(featurefile_data)) {
703 break;
704 }
705 s[i] = featurefile_data[gf->featurefile_offset];
706 gf->featurefile_offset++;
707 }
708
709 unlock_user(s, buf, len);
710
711
712 return len - i;
713}
714
715static uint32_t featurefile_isattyfn(CPUState *cs, GuestFD *gf)
716{
717 return 0;
718}
719
720static uint32_t featurefile_seekfn(CPUState *cs, GuestFD *gf,
721 target_ulong offset)
722{
723 gf->featurefile_offset = offset;
724 return 0;
725}
726
727static uint32_t featurefile_flenfn(CPUState *cs, GuestFD *gf)
728{
729 return sizeof(featurefile_data);
730}
731
732typedef struct GuestFDFunctions {
733 sys_closefn *closefn;
734 sys_writefn *writefn;
735 sys_readfn *readfn;
736 sys_isattyfn *isattyfn;
737 sys_seekfn *seekfn;
738 sys_flenfn *flenfn;
739} GuestFDFunctions;
740
741static const GuestFDFunctions guestfd_fns[] = {
742 [GuestFDHost] = {
743 .closefn = host_closefn,
744 .writefn = host_writefn,
745 .readfn = host_readfn,
746 .isattyfn = host_isattyfn,
747 .seekfn = host_seekfn,
748 .flenfn = host_flenfn,
749 },
750 [GuestFDGDB] = {
751 .closefn = gdb_closefn,
752 .writefn = gdb_writefn,
753 .readfn = gdb_readfn,
754 .isattyfn = gdb_isattyfn,
755 .seekfn = gdb_seekfn,
756 .flenfn = gdb_flenfn,
757 },
758 [GuestFDFeatureFile] = {
759 .closefn = featurefile_closefn,
760 .writefn = featurefile_writefn,
761 .readfn = featurefile_readfn,
762 .isattyfn = featurefile_isattyfn,
763 .seekfn = featurefile_seekfn,
764 .flenfn = featurefile_flenfn,
765 },
766};
767
768
769
770
771
772
773static inline bool is_64bit_semihosting(CPUArchState *env)
774{
775#if defined(TARGET_ARM)
776 return is_a64(env);
777#elif defined(TARGET_RISCV)
778 return !riscv_cpu_is_32bit(env);
779#else
780#error un-handled architecture
781#endif
782}
783
784
785#define GET_ARG(n) do { \
786 if (is_64bit_semihosting(env)) { \
787 if (get_user_u64(arg ## n, args + (n) * 8)) { \
788 errno = EFAULT; \
789 return set_swi_errno(cs, -1); \
790 } \
791 } else { \
792 if (get_user_u32(arg ## n, args + (n) * 4)) { \
793 errno = EFAULT; \
794 return set_swi_errno(cs, -1); \
795 } \
796 } \
797} while (0)
798
799#define SET_ARG(n, val) \
800 (is_64bit_semihosting(env) ? \
801 put_user_u64(val, args + (n) * 8) : \
802 put_user_u32(val, args + (n) * 4))
803
804
805
806
807
808
809
810
811
812
813
814target_ulong do_common_semihosting(CPUState *cs)
815{
816 CPUArchState *env = cs->env_ptr;
817 target_ulong args;
818 target_ulong arg0, arg1, arg2, arg3;
819 target_ulong ul_ret;
820 char * s;
821 int nr;
822 uint32_t ret;
823 uint32_t len;
824 GuestFD *gf;
825 int64_t elapsed;
826
827 (void) env;
828 nr = common_semi_arg(cs, 0) & 0xffffffffU;
829 args = common_semi_arg(cs, 1);
830
831 switch (nr) {
832 case TARGET_SYS_OPEN:
833 {
834 int guestfd;
835
836 GET_ARG(0);
837 GET_ARG(1);
838 GET_ARG(2);
839 s = lock_user_string(arg0);
840 if (!s) {
841 errno = EFAULT;
842 return set_swi_errno(cs, -1);
843 }
844 if (arg1 >= 12) {
845 unlock_user(s, arg0, 0);
846 errno = EINVAL;
847 return set_swi_errno(cs, -1);
848 }
849
850 guestfd = alloc_guestfd();
851 if (guestfd < 0) {
852 unlock_user(s, arg0, 0);
853 errno = EMFILE;
854 return set_swi_errno(cs, -1);
855 }
856
857 if (strcmp(s, ":tt") == 0) {
858 int result_fileno;
859
860
861
862
863
864
865
866 if (arg1 < 4) {
867 result_fileno = STDIN_FILENO;
868 } else if (arg1 < 8) {
869 result_fileno = STDOUT_FILENO;
870 } else {
871 result_fileno = STDERR_FILENO;
872 }
873 associate_guestfd(guestfd, result_fileno);
874 unlock_user(s, arg0, 0);
875 return guestfd;
876 }
877 if (strcmp(s, ":semihosting-features") == 0) {
878 unlock_user(s, arg0, 0);
879
880 if (arg1 != 0 && arg1 != 1) {
881 dealloc_guestfd(guestfd);
882 errno = EACCES;
883 return set_swi_errno(cs, -1);
884 }
885 init_featurefile_guestfd(guestfd);
886 return guestfd;
887 }
888
889 if (use_gdb_syscalls()) {
890 common_semi_open_guestfd = guestfd;
891 ret = common_semi_gdb_syscall(cs, common_semi_open_cb,
892 "open,%s,%x,1a4", arg0, (int)arg2 + 1,
893 gdb_open_modeflags[arg1]);
894 } else {
895 ret = set_swi_errno(cs, open(s, open_modeflags[arg1], 0644));
896 if (ret == (uint32_t)-1) {
897 dealloc_guestfd(guestfd);
898 } else {
899 associate_guestfd(guestfd, ret);
900 ret = guestfd;
901 }
902 }
903 unlock_user(s, arg0, 0);
904 return ret;
905 }
906 case TARGET_SYS_CLOSE:
907 GET_ARG(0);
908
909 gf = get_guestfd(arg0);
910 if (!gf) {
911 errno = EBADF;
912 return set_swi_errno(cs, -1);
913 }
914
915 ret = guestfd_fns[gf->type].closefn(cs, gf);
916 dealloc_guestfd(arg0);
917 return ret;
918 case TARGET_SYS_WRITEC:
919 qemu_semihosting_console_outc(cs->env_ptr, args);
920 return 0xdeadbeef;
921 case TARGET_SYS_WRITE0:
922 return qemu_semihosting_console_outs(cs->env_ptr, args);
923 case TARGET_SYS_WRITE:
924 GET_ARG(0);
925 GET_ARG(1);
926 GET_ARG(2);
927 len = arg2;
928
929 gf = get_guestfd(arg0);
930 if (!gf) {
931 errno = EBADF;
932 return set_swi_errno(cs, -1);
933 }
934
935 return guestfd_fns[gf->type].writefn(cs, gf, arg1, len);
936 case TARGET_SYS_READ:
937 GET_ARG(0);
938 GET_ARG(1);
939 GET_ARG(2);
940 len = arg2;
941
942 gf = get_guestfd(arg0);
943 if (!gf) {
944 errno = EBADF;
945 return set_swi_errno(cs, -1);
946 }
947
948 return guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
949 case TARGET_SYS_READC:
950 return qemu_semihosting_console_inc(cs->env_ptr);
951 case TARGET_SYS_ISERROR:
952 GET_ARG(0);
953 return (target_long) arg0 < 0 ? 1 : 0;
954 case TARGET_SYS_ISTTY:
955 GET_ARG(0);
956
957 gf = get_guestfd(arg0);
958 if (!gf) {
959 errno = EBADF;
960 return set_swi_errno(cs, -1);
961 }
962
963 return guestfd_fns[gf->type].isattyfn(cs, gf);
964 case TARGET_SYS_SEEK:
965 GET_ARG(0);
966 GET_ARG(1);
967
968 gf = get_guestfd(arg0);
969 if (!gf) {
970 errno = EBADF;
971 return set_swi_errno(cs, -1);
972 }
973
974 return guestfd_fns[gf->type].seekfn(cs, gf, arg1);
975 case TARGET_SYS_FLEN:
976 GET_ARG(0);
977
978 gf = get_guestfd(arg0);
979 if (!gf) {
980 errno = EBADF;
981 return set_swi_errno(cs, -1);
982 }
983
984 return guestfd_fns[gf->type].flenfn(cs, gf);
985 case TARGET_SYS_TMPNAM:
986 GET_ARG(0);
987 GET_ARG(1);
988 GET_ARG(2);
989 if (asprintf(&s, "/tmp/qemu-%x%02x", getpid(),
990 (int) (arg1 & 0xff)) < 0) {
991 return -1;
992 }
993 ul_ret = (target_ulong) -1;
994
995
996 if (strlen(s) < arg2) {
997 char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0);
998 strcpy(output, s);
999 unlock_user(output, arg0, arg2);
1000 ul_ret = 0;
1001 }
1002 free(s);
1003 return ul_ret;
1004 case TARGET_SYS_REMOVE:
1005 GET_ARG(0);
1006 GET_ARG(1);
1007 if (use_gdb_syscalls()) {
1008 ret = common_semi_gdb_syscall(cs, common_semi_cb, "unlink,%s",
1009 arg0, (int)arg1 + 1);
1010 } else {
1011 s = lock_user_string(arg0);
1012 if (!s) {
1013 errno = EFAULT;
1014 return set_swi_errno(cs, -1);
1015 }
1016 ret = set_swi_errno(cs, remove(s));
1017 unlock_user(s, arg0, 0);
1018 }
1019 return ret;
1020 case TARGET_SYS_RENAME:
1021 GET_ARG(0);
1022 GET_ARG(1);
1023 GET_ARG(2);
1024 GET_ARG(3);
1025 if (use_gdb_syscalls()) {
1026 return common_semi_gdb_syscall(cs, common_semi_cb, "rename,%s,%s",
1027 arg0, (int)arg1 + 1, arg2,
1028 (int)arg3 + 1);
1029 } else {
1030 char *s2;
1031 s = lock_user_string(arg0);
1032 s2 = lock_user_string(arg2);
1033 if (!s || !s2) {
1034 errno = EFAULT;
1035 ret = set_swi_errno(cs, -1);
1036 } else {
1037 ret = set_swi_errno(cs, rename(s, s2));
1038 }
1039 if (s2)
1040 unlock_user(s2, arg2, 0);
1041 if (s)
1042 unlock_user(s, arg0, 0);
1043 return ret;
1044 }
1045 case TARGET_SYS_CLOCK:
1046 return clock() / (CLOCKS_PER_SEC / 100);
1047 case TARGET_SYS_TIME:
1048 return set_swi_errno(cs, time(NULL));
1049 case TARGET_SYS_SYSTEM:
1050 GET_ARG(0);
1051 GET_ARG(1);
1052 if (use_gdb_syscalls()) {
1053 return common_semi_gdb_syscall(cs, common_semi_cb, "system,%s",
1054 arg0, (int)arg1 + 1);
1055 } else {
1056 s = lock_user_string(arg0);
1057 if (!s) {
1058 errno = EFAULT;
1059 return set_swi_errno(cs, -1);
1060 }
1061 ret = set_swi_errno(cs, system(s));
1062 unlock_user(s, arg0, 0);
1063 return ret;
1064 }
1065 case TARGET_SYS_ERRNO:
1066 return get_swi_errno(cs);
1067 case TARGET_SYS_GET_CMDLINE:
1068 {
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083 char *output_buffer;
1084 size_t input_size;
1085 size_t output_size;
1086 int status = 0;
1087#if !defined(CONFIG_USER_ONLY)
1088 const char *cmdline;
1089#else
1090 TaskState *ts = cs->opaque;
1091#endif
1092 GET_ARG(0);
1093 GET_ARG(1);
1094 input_size = arg1;
1095
1096#if !defined(CONFIG_USER_ONLY)
1097 cmdline = semihosting_get_cmdline();
1098 if (cmdline == NULL) {
1099 cmdline = "";
1100 }
1101 output_size = strlen(cmdline) + 1;
1102#else
1103 unsigned int i;
1104
1105 output_size = ts->info->arg_end - ts->info->arg_start;
1106 if (!output_size) {
1107
1108
1109
1110
1111 output_size = 1;
1112 }
1113#endif
1114
1115 if (output_size > input_size) {
1116
1117 errno = E2BIG;
1118 return set_swi_errno(cs, -1);
1119 }
1120
1121
1122 if (SET_ARG(1, output_size - 1)) {
1123
1124 errno = EFAULT;
1125 return set_swi_errno(cs, -1);
1126 }
1127
1128
1129 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
1130 if (!output_buffer) {
1131 errno = EFAULT;
1132 return set_swi_errno(cs, -1);
1133 }
1134
1135
1136#if !defined(CONFIG_USER_ONLY)
1137 pstrcpy(output_buffer, output_size, cmdline);
1138#else
1139 if (output_size == 1) {
1140
1141 output_buffer[0] = '\0';
1142 goto out;
1143 }
1144
1145 if (copy_from_user(output_buffer, ts->info->arg_start,
1146 output_size)) {
1147 errno = EFAULT;
1148 status = set_swi_errno(cs, -1);
1149 goto out;
1150 }
1151
1152
1153 for (i = 0; i < output_size - 1; i++) {
1154 if (output_buffer[i] == 0) {
1155 output_buffer[i] = ' ';
1156 }
1157 }
1158 out:
1159#endif
1160
1161 unlock_user(output_buffer, arg0, output_size);
1162
1163 return status;
1164 }
1165 case TARGET_SYS_HEAPINFO:
1166 {
1167 target_ulong retvals[4];
1168 target_ulong limit;
1169 int i;
1170#ifdef CONFIG_USER_ONLY
1171 TaskState *ts = cs->opaque;
1172#else
1173 target_ulong rambase = common_semi_rambase(cs);
1174#endif
1175
1176 GET_ARG(0);
1177
1178#ifdef CONFIG_USER_ONLY
1179
1180
1181
1182
1183 if (!ts->heap_limit) {
1184 abi_ulong ret;
1185
1186 ts->heap_base = do_brk(0);
1187 limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE;
1188
1189 for (;;) {
1190 ret = do_brk(limit);
1191 if (ret >= limit) {
1192 break;
1193 }
1194 limit = (ts->heap_base >> 1) + (limit >> 1);
1195 }
1196 ts->heap_limit = limit;
1197 }
1198
1199 retvals[0] = ts->heap_base;
1200 retvals[1] = ts->heap_limit;
1201 retvals[2] = ts->stack_base;
1202 retvals[3] = 0;
1203#else
1204 limit = current_machine->ram_size;
1205
1206 retvals[0] = rambase + limit / 2;
1207 retvals[1] = rambase + limit;
1208 retvals[2] = rambase + limit;
1209 retvals[3] = rambase;
1210#endif
1211
1212 for (i = 0; i < ARRAY_SIZE(retvals); i++) {
1213 bool fail;
1214
1215 if (is_64bit_semihosting(env)) {
1216 fail = put_user_u64(retvals[i], arg0 + i * 8);
1217 } else {
1218 fail = put_user_u32(retvals[i], arg0 + i * 4);
1219 }
1220
1221 if (fail) {
1222
1223 errno = EFAULT;
1224 return set_swi_errno(cs, -1);
1225 }
1226 }
1227 return 0;
1228 }
1229 case TARGET_SYS_EXIT:
1230 case TARGET_SYS_EXIT_EXTENDED:
1231 if (common_semi_sys_exit_extended(cs, nr)) {
1232
1233
1234
1235
1236
1237
1238
1239 GET_ARG(0);
1240 GET_ARG(1);
1241
1242 if (arg0 == ADP_Stopped_ApplicationExit) {
1243 ret = arg1;
1244 } else {
1245 ret = 1;
1246 }
1247 } else {
1248
1249
1250
1251
1252
1253
1254 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
1255 }
1256 gdb_exit(ret);
1257 exit(ret);
1258 case TARGET_SYS_ELAPSED:
1259 elapsed = get_clock() - clock_start;
1260 if (sizeof(target_ulong) == 8) {
1261 SET_ARG(0, elapsed);
1262 } else {
1263 SET_ARG(0, (uint32_t) elapsed);
1264 SET_ARG(1, (uint32_t) (elapsed >> 32));
1265 }
1266 return 0;
1267 case TARGET_SYS_TICKFREQ:
1268
1269 return 1000000000;
1270 case TARGET_SYS_SYNCCACHE:
1271
1272
1273
1274
1275
1276#ifdef TARGET_ARM
1277 if (is_a64(cs->env_ptr)) {
1278 return 0;
1279 }
1280#endif
1281#ifdef TARGET_RISCV
1282 return 0;
1283#endif
1284
1285 default:
1286 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
1287 cpu_dump_state(cs, stderr, 0);
1288 abort();
1289 }
1290}
1291