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