blob: ee469c49c5f0b0eb39655e7c6e5f7c5622a04940 [file] [log] [blame]
bellarda4f81972005-04-23 18:25:41 +00001/*
2 * Arm "Angel" semihosting syscalls
ths5fafdf22007-09-16 21:08:06 +00003 *
pbrook8e716212007-01-20 17:12:09 +00004 * Copyright (c) 2005, 2007 CodeSourcery.
5 * Written by Paul Brook.
bellarda4f81972005-04-23 18:25:41 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000018 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellarda4f81972005-04-23 18:25:41 +000019 */
20
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <time.h>
28
pbrook8e716212007-01-20 17:12:09 +000029#include "cpu.h"
30#ifdef CONFIG_USER_ONLY
bellarda4f81972005-04-23 18:25:41 +000031#include "qemu.h"
32
33#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
pbrook8e716212007-01-20 17:12:09 +000034#else
pbrook87ecb682007-11-17 17:14:51 +000035#include "qemu-common.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010036#include "exec/gdbstub.h"
Peter Maydellbd2be152013-04-09 15:26:55 +010037#include "hw/arm/arm.h"
pbrook8e716212007-01-20 17:12:09 +000038#endif
bellarda4f81972005-04-23 18:25:41 +000039
Stefan Weil38817252012-04-28 05:07:47 +000040#define TARGET_SYS_OPEN 0x01
41#define TARGET_SYS_CLOSE 0x02
42#define TARGET_SYS_WRITEC 0x03
43#define TARGET_SYS_WRITE0 0x04
44#define TARGET_SYS_WRITE 0x05
45#define TARGET_SYS_READ 0x06
46#define TARGET_SYS_READC 0x07
47#define TARGET_SYS_ISTTY 0x09
48#define TARGET_SYS_SEEK 0x0a
49#define TARGET_SYS_FLEN 0x0c
50#define TARGET_SYS_TMPNAM 0x0d
51#define TARGET_SYS_REMOVE 0x0e
52#define TARGET_SYS_RENAME 0x0f
53#define TARGET_SYS_CLOCK 0x10
54#define TARGET_SYS_TIME 0x11
55#define TARGET_SYS_SYSTEM 0x12
56#define TARGET_SYS_ERRNO 0x13
57#define TARGET_SYS_GET_CMDLINE 0x15
58#define TARGET_SYS_HEAPINFO 0x16
59#define TARGET_SYS_EXIT 0x18
bellarda4f81972005-04-23 18:25:41 +000060
61#ifndef O_BINARY
62#define O_BINARY 0
63#endif
64
pbrooka2d1eba2007-01-28 03:10:55 +000065#define GDB_O_RDONLY 0x000
66#define GDB_O_WRONLY 0x001
67#define GDB_O_RDWR 0x002
68#define GDB_O_APPEND 0x008
69#define GDB_O_CREAT 0x200
70#define GDB_O_TRUNC 0x400
71#define GDB_O_BINARY 0
72
73static int gdb_open_modeflags[12] = {
74 GDB_O_RDONLY,
75 GDB_O_RDONLY | GDB_O_BINARY,
76 GDB_O_RDWR,
77 GDB_O_RDWR | GDB_O_BINARY,
78 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
79 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
80 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
81 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
82 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
83 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
84 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
85 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
86};
87
88static int open_modeflags[12] = {
bellarda4f81972005-04-23 18:25:41 +000089 O_RDONLY,
90 O_RDONLY | O_BINARY,
91 O_RDWR,
92 O_RDWR | O_BINARY,
93 O_WRONLY | O_CREAT | O_TRUNC,
94 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
95 O_RDWR | O_CREAT | O_TRUNC,
96 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
97 O_WRONLY | O_CREAT | O_APPEND,
98 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
99 O_RDWR | O_CREAT | O_APPEND,
100 O_RDWR | O_CREAT | O_APPEND | O_BINARY
101};
102
pbrook8e716212007-01-20 17:12:09 +0000103#ifdef CONFIG_USER_ONLY
bellarda4f81972005-04-23 18:25:41 +0000104static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
105{
pbrook8e716212007-01-20 17:12:09 +0000106 if (code == (uint32_t)-1)
107 ts->swi_errno = errno;
108 return code;
bellarda4f81972005-04-23 18:25:41 +0000109}
pbrook8e716212007-01-20 17:12:09 +0000110#else
Andreas Färber81926f42012-03-14 01:38:23 +0100111static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
pbrook8e716212007-01-20 17:12:09 +0000112{
113 return code;
114}
115
Paolo Bonzini022c62c2012-12-17 18:19:49 +0100116#include "exec/softmmu-semi.h"
pbrook8e716212007-01-20 17:12:09 +0000117#endif
bellarda4f81972005-04-23 18:25:41 +0000118
pbrooka2d1eba2007-01-28 03:10:55 +0000119static target_ulong arm_semi_syscall_len;
120
pbrook33d9cc82007-06-09 14:44:00 +0000121#if !defined(CONFIG_USER_ONLY)
122static target_ulong syscall_err;
123#endif
124
Andreas Färber9e0c5422013-06-27 17:45:01 +0200125static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
pbrooka2d1eba2007-01-28 03:10:55 +0000126{
Andreas Färber9e0c5422013-06-27 17:45:01 +0200127 ARMCPU *cpu = ARM_CPU(cs);
128 CPUARMState *env = &cpu->env;
pbrooka2d1eba2007-01-28 03:10:55 +0000129#ifdef CONFIG_USER_ONLY
130 TaskState *ts = env->opaque;
131#endif
pbrook33d9cc82007-06-09 14:44:00 +0000132
pbrooka2d1eba2007-01-28 03:10:55 +0000133 if (ret == (target_ulong)-1) {
134#ifdef CONFIG_USER_ONLY
135 ts->swi_errno = err;
pbrook33d9cc82007-06-09 14:44:00 +0000136#else
137 syscall_err = err;
pbrooka2d1eba2007-01-28 03:10:55 +0000138#endif
139 env->regs[0] = ret;
140 } else {
141 /* Fixup syscalls that use nonstardard return conventions. */
142 switch (env->regs[0]) {
Stefan Weil38817252012-04-28 05:07:47 +0000143 case TARGET_SYS_WRITE:
144 case TARGET_SYS_READ:
pbrooka2d1eba2007-01-28 03:10:55 +0000145 env->regs[0] = arm_semi_syscall_len - ret;
146 break;
Stefan Weil38817252012-04-28 05:07:47 +0000147 case TARGET_SYS_SEEK:
pbrooka2d1eba2007-01-28 03:10:55 +0000148 env->regs[0] = 0;
149 break;
150 default:
151 env->regs[0] = ret;
152 break;
153 }
154 }
155}
156
Andreas Färber9e0c5422013-06-27 17:45:01 +0200157static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
pbrook33d9cc82007-06-09 14:44:00 +0000158{
Andreas Färber9e0c5422013-06-27 17:45:01 +0200159 ARMCPU *cpu = ARM_CPU(cs);
160 CPUARMState *env = &cpu->env;
pbrook33d9cc82007-06-09 14:44:00 +0000161 /* The size is always stored in big-endian order, extract
162 the value. We assume the size always fit in 32 bits. */
163 uint32_t size;
Andreas Färberf17ec442013-06-29 19:40:58 +0200164 cpu_memory_rw_debug(cs, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
pbrook33d9cc82007-06-09 14:44:00 +0000165 env->regs[0] = be32_to_cpu(size);
166#ifdef CONFIG_USER_ONLY
167 ((TaskState *)env->opaque)->swi_errno = err;
168#else
169 syscall_err = err;
170#endif
171}
172
Peter Maydellf296c0d2012-10-14 09:52:27 +0000173/* Read the input value from the argument block; fail the semihosting
174 * call if the memory read fails.
175 */
176#define GET_ARG(n) do { \
177 if (get_user_ual(arg ## n, args + (n) * 4)) { \
178 return (uint32_t)-1; \
179 } \
180} while (0)
181
bellard2f619692007-11-16 10:46:05 +0000182#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
Andreas Färber81926f42012-03-14 01:38:23 +0100183uint32_t do_arm_semihosting(CPUARMState *env)
bellarda4f81972005-04-23 18:25:41 +0000184{
Andreas Färber878096e2013-05-27 01:33:50 +0200185 ARMCPU *cpu = arm_env_get_cpu(env);
pbrook53a59602006-03-25 19:31:22 +0000186 target_ulong args;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000187 target_ulong arg0, arg1, arg2, arg3;
bellarda4f81972005-04-23 18:25:41 +0000188 char * s;
189 int nr;
190 uint32_t ret;
pbrook8e716212007-01-20 17:12:09 +0000191 uint32_t len;
192#ifdef CONFIG_USER_ONLY
bellarda4f81972005-04-23 18:25:41 +0000193 TaskState *ts = env->opaque;
pbrook8e716212007-01-20 17:12:09 +0000194#else
Andreas Färber81926f42012-03-14 01:38:23 +0100195 CPUARMState *ts = env;
pbrook8e716212007-01-20 17:12:09 +0000196#endif
bellarda4f81972005-04-23 18:25:41 +0000197
198 nr = env->regs[0];
pbrook53a59602006-03-25 19:31:22 +0000199 args = env->regs[1];
bellarda4f81972005-04-23 18:25:41 +0000200 switch (nr) {
Stefan Weil38817252012-04-28 05:07:47 +0000201 case TARGET_SYS_OPEN:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000202 GET_ARG(0);
203 GET_ARG(1);
204 GET_ARG(2);
205 s = lock_user_string(arg0);
206 if (!s) {
bellard579a97f2007-11-11 14:26:47 +0000207 /* FIXME - should this error code be -TARGET_EFAULT ? */
208 return (uint32_t)-1;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000209 }
210 if (arg1 >= 12) {
211 unlock_user(s, arg0, 0);
bellard579a97f2007-11-11 14:26:47 +0000212 return (uint32_t)-1;
Jim Meyering396bef42012-08-22 13:55:55 +0200213 }
bellarda4f81972005-04-23 18:25:41 +0000214 if (strcmp(s, ":tt") == 0) {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000215 int result_fileno = arg1 < 4 ? STDIN_FILENO : STDOUT_FILENO;
216 unlock_user(s, arg0, 0);
Jim Meyering396bef42012-08-22 13:55:55 +0200217 return result_fileno;
bellarda4f81972005-04-23 18:25:41 +0000218 }
pbrooka2d1eba2007-01-28 03:10:55 +0000219 if (use_gdb_syscalls()) {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000220 gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", arg0,
221 (int)arg2+1, gdb_open_modeflags[arg1]);
Jim Meyering396bef42012-08-22 13:55:55 +0200222 ret = env->regs[0];
pbrooka2d1eba2007-01-28 03:10:55 +0000223 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000224 ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644));
pbrooka2d1eba2007-01-28 03:10:55 +0000225 }
Peter Maydellf296c0d2012-10-14 09:52:27 +0000226 unlock_user(s, arg0, 0);
pbrook8e716212007-01-20 17:12:09 +0000227 return ret;
Stefan Weil38817252012-04-28 05:07:47 +0000228 case TARGET_SYS_CLOSE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000229 GET_ARG(0);
pbrooka2d1eba2007-01-28 03:10:55 +0000230 if (use_gdb_syscalls()) {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000231 gdb_do_syscall(arm_semi_cb, "close,%x", arg0);
pbrooka2d1eba2007-01-28 03:10:55 +0000232 return env->regs[0];
233 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000234 return set_swi_errno(ts, close(arg0));
pbrooka2d1eba2007-01-28 03:10:55 +0000235 }
Stefan Weil38817252012-04-28 05:07:47 +0000236 case TARGET_SYS_WRITEC:
pbrook53a59602006-03-25 19:31:22 +0000237 {
bellard2f619692007-11-16 10:46:05 +0000238 char c;
239
240 if (get_user_u8(c, args))
241 /* FIXME - should this error code be -TARGET_EFAULT ? */
242 return (uint32_t)-1;
pbrook53a59602006-03-25 19:31:22 +0000243 /* Write to debug console. stderr is near enough. */
pbrooka2d1eba2007-01-28 03:10:55 +0000244 if (use_gdb_syscalls()) {
245 gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
246 return env->regs[0];
247 } else {
248 return write(STDERR_FILENO, &c, 1);
249 }
pbrook53a59602006-03-25 19:31:22 +0000250 }
Stefan Weil38817252012-04-28 05:07:47 +0000251 case TARGET_SYS_WRITE0:
bellard579a97f2007-11-11 14:26:47 +0000252 if (!(s = lock_user_string(args)))
253 /* FIXME - should this error code be -TARGET_EFAULT ? */
254 return (uint32_t)-1;
pbrooka2d1eba2007-01-28 03:10:55 +0000255 len = strlen(s);
256 if (use_gdb_syscalls()) {
257 gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
258 ret = env->regs[0];
259 } else {
260 ret = write(STDERR_FILENO, s, len);
261 }
pbrook53a59602006-03-25 19:31:22 +0000262 unlock_user(s, args, 0);
263 return ret;
Stefan Weil38817252012-04-28 05:07:47 +0000264 case TARGET_SYS_WRITE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000265 GET_ARG(0);
266 GET_ARG(1);
267 GET_ARG(2);
268 len = arg2;
pbrooka2d1eba2007-01-28 03:10:55 +0000269 if (use_gdb_syscalls()) {
270 arm_semi_syscall_len = len;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000271 gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", arg0, arg1, len);
pbrooka2d1eba2007-01-28 03:10:55 +0000272 return env->regs[0];
273 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000274 s = lock_user(VERIFY_READ, arg1, len, 1);
275 if (!s) {
bellard579a97f2007-11-11 14:26:47 +0000276 /* FIXME - should this error code be -TARGET_EFAULT ? */
277 return (uint32_t)-1;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000278 }
279 ret = set_swi_errno(ts, write(arg0, s, len));
280 unlock_user(s, arg1, 0);
pbrooka2d1eba2007-01-28 03:10:55 +0000281 if (ret == (uint32_t)-1)
282 return -1;
283 return len - ret;
284 }
Stefan Weil38817252012-04-28 05:07:47 +0000285 case TARGET_SYS_READ:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000286 GET_ARG(0);
287 GET_ARG(1);
288 GET_ARG(2);
289 len = arg2;
pbrooka2d1eba2007-01-28 03:10:55 +0000290 if (use_gdb_syscalls()) {
291 arm_semi_syscall_len = len;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000292 gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", arg0, arg1, len);
pbrooka2d1eba2007-01-28 03:10:55 +0000293 return env->regs[0];
294 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000295 s = lock_user(VERIFY_WRITE, arg1, len, 0);
296 if (!s) {
bellard579a97f2007-11-11 14:26:47 +0000297 /* FIXME - should this error code be -TARGET_EFAULT ? */
298 return (uint32_t)-1;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000299 }
300 do {
301 ret = set_swi_errno(ts, read(arg0, s, len));
302 } while (ret == -1 && errno == EINTR);
303 unlock_user(s, arg1, len);
pbrooka2d1eba2007-01-28 03:10:55 +0000304 if (ret == (uint32_t)-1)
305 return -1;
306 return len - ret;
307 }
Stefan Weil38817252012-04-28 05:07:47 +0000308 case TARGET_SYS_READC:
Peter Maydellb90372a2012-08-06 17:42:18 +0100309 /* XXX: Read from debug console. Not implemented. */
bellarda4f81972005-04-23 18:25:41 +0000310 return 0;
Stefan Weil38817252012-04-28 05:07:47 +0000311 case TARGET_SYS_ISTTY:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000312 GET_ARG(0);
pbrooka2d1eba2007-01-28 03:10:55 +0000313 if (use_gdb_syscalls()) {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000314 gdb_do_syscall(arm_semi_cb, "isatty,%x", arg0);
pbrooka2d1eba2007-01-28 03:10:55 +0000315 return env->regs[0];
316 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000317 return isatty(arg0);
pbrooka2d1eba2007-01-28 03:10:55 +0000318 }
Stefan Weil38817252012-04-28 05:07:47 +0000319 case TARGET_SYS_SEEK:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000320 GET_ARG(0);
321 GET_ARG(1);
pbrooka2d1eba2007-01-28 03:10:55 +0000322 if (use_gdb_syscalls()) {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000323 gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", arg0, arg1);
pbrooka2d1eba2007-01-28 03:10:55 +0000324 return env->regs[0];
325 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000326 ret = set_swi_errno(ts, lseek(arg0, arg1, SEEK_SET));
pbrooka2d1eba2007-01-28 03:10:55 +0000327 if (ret == (uint32_t)-1)
328 return -1;
329 return 0;
330 }
Stefan Weil38817252012-04-28 05:07:47 +0000331 case TARGET_SYS_FLEN:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000332 GET_ARG(0);
pbrooka2d1eba2007-01-28 03:10:55 +0000333 if (use_gdb_syscalls()) {
ths5fafdf22007-09-16 21:08:06 +0000334 gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
Peter Maydellf296c0d2012-10-14 09:52:27 +0000335 arg0, env->regs[13]-64);
pbrook33d9cc82007-06-09 14:44:00 +0000336 return env->regs[0];
pbrooka2d1eba2007-01-28 03:10:55 +0000337 } else {
bellarda4f81972005-04-23 18:25:41 +0000338 struct stat buf;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000339 ret = set_swi_errno(ts, fstat(arg0, &buf));
bellarda4f81972005-04-23 18:25:41 +0000340 if (ret == (uint32_t)-1)
341 return -1;
342 return buf.st_size;
343 }
Stefan Weil38817252012-04-28 05:07:47 +0000344 case TARGET_SYS_TMPNAM:
bellarda4f81972005-04-23 18:25:41 +0000345 /* XXX: Not implemented. */
346 return -1;
Stefan Weil38817252012-04-28 05:07:47 +0000347 case TARGET_SYS_REMOVE:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000348 GET_ARG(0);
349 GET_ARG(1);
pbrooka2d1eba2007-01-28 03:10:55 +0000350 if (use_gdb_syscalls()) {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000351 gdb_do_syscall(arm_semi_cb, "unlink,%s", arg0, (int)arg1+1);
pbrooka2d1eba2007-01-28 03:10:55 +0000352 ret = env->regs[0];
353 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000354 s = lock_user_string(arg0);
355 if (!s) {
bellard579a97f2007-11-11 14:26:47 +0000356 /* FIXME - should this error code be -TARGET_EFAULT ? */
357 return (uint32_t)-1;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000358 }
pbrooka2d1eba2007-01-28 03:10:55 +0000359 ret = set_swi_errno(ts, remove(s));
Peter Maydellf296c0d2012-10-14 09:52:27 +0000360 unlock_user(s, arg0, 0);
pbrooka2d1eba2007-01-28 03:10:55 +0000361 }
pbrook8e716212007-01-20 17:12:09 +0000362 return ret;
Stefan Weil38817252012-04-28 05:07:47 +0000363 case TARGET_SYS_RENAME:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000364 GET_ARG(0);
365 GET_ARG(1);
366 GET_ARG(2);
367 GET_ARG(3);
pbrooka2d1eba2007-01-28 03:10:55 +0000368 if (use_gdb_syscalls()) {
369 gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
Peter Maydellf296c0d2012-10-14 09:52:27 +0000370 arg0, (int)arg1+1, arg2, (int)arg3+1);
pbrooka2d1eba2007-01-28 03:10:55 +0000371 return env->regs[0];
372 } else {
pbrook8e716212007-01-20 17:12:09 +0000373 char *s2;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000374 s = lock_user_string(arg0);
375 s2 = lock_user_string(arg2);
bellard579a97f2007-11-11 14:26:47 +0000376 if (!s || !s2)
377 /* FIXME - should this error code be -TARGET_EFAULT ? */
378 ret = (uint32_t)-1;
379 else
380 ret = set_swi_errno(ts, rename(s, s2));
381 if (s2)
Peter Maydellf296c0d2012-10-14 09:52:27 +0000382 unlock_user(s2, arg2, 0);
bellard579a97f2007-11-11 14:26:47 +0000383 if (s)
Peter Maydellf296c0d2012-10-14 09:52:27 +0000384 unlock_user(s, arg0, 0);
pbrook8e716212007-01-20 17:12:09 +0000385 return ret;
386 }
Stefan Weil38817252012-04-28 05:07:47 +0000387 case TARGET_SYS_CLOCK:
bellarda4f81972005-04-23 18:25:41 +0000388 return clock() / (CLOCKS_PER_SEC / 100);
Stefan Weil38817252012-04-28 05:07:47 +0000389 case TARGET_SYS_TIME:
bellarda4f81972005-04-23 18:25:41 +0000390 return set_swi_errno(ts, time(NULL));
Stefan Weil38817252012-04-28 05:07:47 +0000391 case TARGET_SYS_SYSTEM:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000392 GET_ARG(0);
393 GET_ARG(1);
pbrooka2d1eba2007-01-28 03:10:55 +0000394 if (use_gdb_syscalls()) {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000395 gdb_do_syscall(arm_semi_cb, "system,%s", arg0, (int)arg1+1);
pbrooka2d1eba2007-01-28 03:10:55 +0000396 return env->regs[0];
397 } else {
Peter Maydellf296c0d2012-10-14 09:52:27 +0000398 s = lock_user_string(arg0);
399 if (!s) {
bellard579a97f2007-11-11 14:26:47 +0000400 /* FIXME - should this error code be -TARGET_EFAULT ? */
401 return (uint32_t)-1;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000402 }
pbrooka2d1eba2007-01-28 03:10:55 +0000403 ret = set_swi_errno(ts, system(s));
Peter Maydellf296c0d2012-10-14 09:52:27 +0000404 unlock_user(s, arg0, 0);
thsa982b532008-07-01 16:40:04 +0000405 return ret;
pbrooka2d1eba2007-01-28 03:10:55 +0000406 }
Stefan Weil38817252012-04-28 05:07:47 +0000407 case TARGET_SYS_ERRNO:
pbrook8e716212007-01-20 17:12:09 +0000408#ifdef CONFIG_USER_ONLY
bellarda4f81972005-04-23 18:25:41 +0000409 return ts->swi_errno;
pbrook8e716212007-01-20 17:12:09 +0000410#else
pbrook33d9cc82007-06-09 14:44:00 +0000411 return syscall_err;
pbrook8e716212007-01-20 17:12:09 +0000412#endif
Stefan Weil38817252012-04-28 05:07:47 +0000413 case TARGET_SYS_GET_CMDLINE:
pbrook38d06622006-11-19 20:29:35 +0000414 {
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200415 /* Build a command-line from the original argv.
416 *
417 * The inputs are:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000418 * * arg0, pointer to a buffer of at least the size
419 * specified in arg1.
420 * * arg1, size of the buffer pointed to by arg0 in
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200421 * bytes.
422 *
423 * The outputs are:
Peter Maydellf296c0d2012-10-14 09:52:27 +0000424 * * arg0, pointer to null-terminated string of the
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200425 * command line.
Peter Maydellf296c0d2012-10-14 09:52:27 +0000426 * * arg1, length of the string pointed to by arg0.
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200427 */
bellard579a97f2007-11-11 14:26:47 +0000428
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200429 char *output_buffer;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000430 size_t input_size;
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200431 size_t output_size;
432 int status = 0;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000433 GET_ARG(0);
434 GET_ARG(1);
435 input_size = arg1;
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200436 /* Compute the size of the output string. */
437#if !defined(CONFIG_USER_ONLY)
438 output_size = strlen(ts->boot_info->kernel_filename)
439 + 1 /* Separating space. */
440 + strlen(ts->boot_info->kernel_cmdline)
441 + 1; /* Terminating null byte. */
442#else
Wolfgang Schildbach2e8785a2010-12-06 15:06:05 +0000443 unsigned int i;
pbrook38d06622006-11-19 20:29:35 +0000444
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200445 output_size = ts->info->arg_end - ts->info->arg_start;
446 if (!output_size) {
Wolfgang Schildbach2e8785a2010-12-06 15:06:05 +0000447 /* We special-case the "empty command line" case (argc==0).
448 Just provide the terminating 0. */
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200449 output_size = 1;
Wolfgang Schildbach2e8785a2010-12-06 15:06:05 +0000450 }
pbrook8e716212007-01-20 17:12:09 +0000451#endif
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200452
453 if (output_size > input_size) {
454 /* Not enough space to store command-line arguments. */
455 return -1;
456 }
457
458 /* Adjust the command-line length. */
Peter Maydellf296c0d2012-10-14 09:52:27 +0000459 if (SET_ARG(1, output_size - 1)) {
460 /* Couldn't write back to argument block */
461 return -1;
462 }
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200463
464 /* Lock the buffer on the ARM side. */
Peter Maydellf296c0d2012-10-14 09:52:27 +0000465 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200466 if (!output_buffer) {
467 return -1;
468 }
469
470 /* Copy the command-line arguments. */
471#if !defined(CONFIG_USER_ONLY)
472 pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
473 pstrcat(output_buffer, output_size, " ");
474 pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
475#else
476 if (output_size == 1) {
477 /* Empty command-line. */
478 output_buffer[0] = '\0';
479 goto out;
480 }
481
482 if (copy_from_user(output_buffer, ts->info->arg_start,
483 output_size)) {
484 status = -1;
485 goto out;
486 }
487
488 /* Separate arguments by white spaces. */
489 for (i = 0; i < output_size - 1; i++) {
490 if (output_buffer[i] == 0) {
491 output_buffer[i] = ' ';
492 }
493 }
494 out:
495#endif
496 /* Unlock the buffer on the ARM side. */
Peter Maydellf296c0d2012-10-14 09:52:27 +0000497 unlock_user(output_buffer, arg0, output_size);
Cédric VINCENT1c1b40c2011-06-29 12:49:41 +0200498
499 return status;
500 }
Stefan Weil38817252012-04-28 05:07:47 +0000501 case TARGET_SYS_HEAPINFO:
bellarda4f81972005-04-23 18:25:41 +0000502 {
503 uint32_t *ptr;
504 uint32_t limit;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000505 GET_ARG(0);
bellarda4f81972005-04-23 18:25:41 +0000506
pbrook8e716212007-01-20 17:12:09 +0000507#ifdef CONFIG_USER_ONLY
508 /* Some C libraries assume the heap immediately follows .bss, so
bellarda4f81972005-04-23 18:25:41 +0000509 allocate it using sbrk. */
510 if (!ts->heap_limit) {
Peter Maydell206ae742011-04-18 16:34:25 +0100511 abi_ulong ret;
bellarda4f81972005-04-23 18:25:41 +0000512
pbrook53a59602006-03-25 19:31:22 +0000513 ts->heap_base = do_brk(0);
bellarda4f81972005-04-23 18:25:41 +0000514 limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
515 /* Try a big heap, and reduce the size if that fails. */
516 for (;;) {
pbrook53a59602006-03-25 19:31:22 +0000517 ret = do_brk(limit);
Peter Maydell206ae742011-04-18 16:34:25 +0100518 if (ret >= limit) {
bellarda4f81972005-04-23 18:25:41 +0000519 break;
Peter Maydell206ae742011-04-18 16:34:25 +0100520 }
bellarda4f81972005-04-23 18:25:41 +0000521 limit = (ts->heap_base >> 1) + (limit >> 1);
522 }
523 ts->heap_limit = limit;
524 }
ths3b46e622007-09-17 08:09:54 +0000525
Peter Maydellf296c0d2012-10-14 09:52:27 +0000526 ptr = lock_user(VERIFY_WRITE, arg0, 16, 0);
527 if (!ptr) {
bellard579a97f2007-11-11 14:26:47 +0000528 /* FIXME - should this error code be -TARGET_EFAULT ? */
529 return (uint32_t)-1;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000530 }
bellarda4f81972005-04-23 18:25:41 +0000531 ptr[0] = tswap32(ts->heap_base);
532 ptr[1] = tswap32(ts->heap_limit);
533 ptr[2] = tswap32(ts->stack_base);
534 ptr[3] = tswap32(0); /* Stack limit. */
Peter Maydellf296c0d2012-10-14 09:52:27 +0000535 unlock_user(ptr, arg0, 16);
pbrook8e716212007-01-20 17:12:09 +0000536#else
537 limit = ram_size;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000538 ptr = lock_user(VERIFY_WRITE, arg0, 16, 0);
539 if (!ptr) {
bellard579a97f2007-11-11 14:26:47 +0000540 /* FIXME - should this error code be -TARGET_EFAULT ? */
541 return (uint32_t)-1;
Peter Maydellf296c0d2012-10-14 09:52:27 +0000542 }
pbrook8e716212007-01-20 17:12:09 +0000543 /* TODO: Make this use the limit of the loaded application. */
544 ptr[0] = tswap32(limit / 2);
545 ptr[1] = tswap32(limit);
546 ptr[2] = tswap32(limit); /* Stack base */
547 ptr[3] = tswap32(0); /* Stack limit. */
Peter Maydellf296c0d2012-10-14 09:52:27 +0000548 unlock_user(ptr, arg0, 16);
pbrook8e716212007-01-20 17:12:09 +0000549#endif
bellarda4f81972005-04-23 18:25:41 +0000550 return 0;
551 }
Stefan Weil38817252012-04-28 05:07:47 +0000552 case TARGET_SYS_EXIT:
Paul Brook0e1c9c52010-06-16 13:03:51 +0100553 gdb_exit(env, 0);
bellarda4f81972005-04-23 18:25:41 +0000554 exit(0);
555 default:
556 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
Andreas Färber878096e2013-05-27 01:33:50 +0200557 cpu_dump_state(CPU(cpu), stderr, fprintf, 0);
bellarda4f81972005-04-23 18:25:41 +0000558 abort();
559 }
560}