Statistics
| Branch: | Revision:

root / target-arm / arm-semi.c @ 06aac7bd

History | View | Annotate | Download (17 kB)

1 a4f81979 bellard
/*
2 a4f81979 bellard
 *  Arm "Angel" semihosting syscalls
3 5fafdf24 ths
 *
4 8e71621f pbrook
 *  Copyright (c) 2005, 2007 CodeSourcery.
5 8e71621f pbrook
 *  Written by Paul Brook.
6 a4f81979 bellard
 *
7 a4f81979 bellard
 *  This program is free software; you can redistribute it and/or modify
8 a4f81979 bellard
 *  it under the terms of the GNU General Public License as published by
9 a4f81979 bellard
 *  the Free Software Foundation; either version 2 of the License, or
10 a4f81979 bellard
 *  (at your option) any later version.
11 a4f81979 bellard
 *
12 a4f81979 bellard
 *  This program is distributed in the hope that it will be useful,
13 a4f81979 bellard
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 a4f81979 bellard
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 a4f81979 bellard
 *  GNU General Public License for more details.
16 a4f81979 bellard
 *
17 a4f81979 bellard
 *  You should have received a copy of the GNU General Public License
18 8167ee88 Blue Swirl
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19 a4f81979 bellard
 */
20 a4f81979 bellard
21 a4f81979 bellard
#include <sys/types.h>
22 a4f81979 bellard
#include <sys/stat.h>
23 a4f81979 bellard
#include <fcntl.h>
24 a4f81979 bellard
#include <unistd.h>
25 a4f81979 bellard
#include <stdlib.h>
26 a4f81979 bellard
#include <stdio.h>
27 a4f81979 bellard
#include <time.h>
28 a4f81979 bellard
29 8e71621f pbrook
#include "cpu.h"
30 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
31 a4f81979 bellard
#include "qemu.h"
32 a4f81979 bellard
33 a4f81979 bellard
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
34 8e71621f pbrook
#else
35 87ecb68b pbrook
#include "qemu-common.h"
36 87ecb68b pbrook
#include "gdbstub.h"
37 1c1b40c1 Cédric VINCENT
#include "hw/arm-misc.h"
38 8e71621f pbrook
#endif
39 a4f81979 bellard
40 3881725c Stefan Weil
#define TARGET_SYS_OPEN        0x01
41 3881725c Stefan Weil
#define TARGET_SYS_CLOSE       0x02
42 3881725c Stefan Weil
#define TARGET_SYS_WRITEC      0x03
43 3881725c Stefan Weil
#define TARGET_SYS_WRITE0      0x04
44 3881725c Stefan Weil
#define TARGET_SYS_WRITE       0x05
45 3881725c Stefan Weil
#define TARGET_SYS_READ        0x06
46 3881725c Stefan Weil
#define TARGET_SYS_READC       0x07
47 3881725c Stefan Weil
#define TARGET_SYS_ISTTY       0x09
48 3881725c Stefan Weil
#define TARGET_SYS_SEEK        0x0a
49 3881725c Stefan Weil
#define TARGET_SYS_FLEN        0x0c
50 3881725c Stefan Weil
#define TARGET_SYS_TMPNAM      0x0d
51 3881725c Stefan Weil
#define TARGET_SYS_REMOVE      0x0e
52 3881725c Stefan Weil
#define TARGET_SYS_RENAME      0x0f
53 3881725c Stefan Weil
#define TARGET_SYS_CLOCK       0x10
54 3881725c Stefan Weil
#define TARGET_SYS_TIME        0x11
55 3881725c Stefan Weil
#define TARGET_SYS_SYSTEM      0x12
56 3881725c Stefan Weil
#define TARGET_SYS_ERRNO       0x13
57 3881725c Stefan Weil
#define TARGET_SYS_GET_CMDLINE 0x15
58 3881725c Stefan Weil
#define TARGET_SYS_HEAPINFO    0x16
59 3881725c Stefan Weil
#define TARGET_SYS_EXIT        0x18
60 a4f81979 bellard
61 a4f81979 bellard
#ifndef O_BINARY
62 a4f81979 bellard
#define O_BINARY 0
63 a4f81979 bellard
#endif
64 a4f81979 bellard
65 a2d1ebaf pbrook
#define GDB_O_RDONLY  0x000
66 a2d1ebaf pbrook
#define GDB_O_WRONLY  0x001
67 a2d1ebaf pbrook
#define GDB_O_RDWR    0x002
68 a2d1ebaf pbrook
#define GDB_O_APPEND  0x008
69 a2d1ebaf pbrook
#define GDB_O_CREAT   0x200
70 a2d1ebaf pbrook
#define GDB_O_TRUNC   0x400
71 a2d1ebaf pbrook
#define GDB_O_BINARY  0
72 a2d1ebaf pbrook
73 a2d1ebaf pbrook
static int gdb_open_modeflags[12] = {
74 a2d1ebaf pbrook
    GDB_O_RDONLY,
75 a2d1ebaf pbrook
    GDB_O_RDONLY | GDB_O_BINARY,
76 a2d1ebaf pbrook
    GDB_O_RDWR,
77 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_BINARY,
78 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
79 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
80 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
81 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
82 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
83 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
84 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
85 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
86 a2d1ebaf pbrook
};
87 a2d1ebaf pbrook
88 a2d1ebaf pbrook
static int open_modeflags[12] = {
89 a4f81979 bellard
    O_RDONLY,
90 a4f81979 bellard
    O_RDONLY | O_BINARY,
91 a4f81979 bellard
    O_RDWR,
92 a4f81979 bellard
    O_RDWR | O_BINARY,
93 a4f81979 bellard
    O_WRONLY | O_CREAT | O_TRUNC,
94 a4f81979 bellard
    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
95 a4f81979 bellard
    O_RDWR | O_CREAT | O_TRUNC,
96 a4f81979 bellard
    O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
97 a4f81979 bellard
    O_WRONLY | O_CREAT | O_APPEND,
98 a4f81979 bellard
    O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
99 a4f81979 bellard
    O_RDWR | O_CREAT | O_APPEND,
100 a4f81979 bellard
    O_RDWR | O_CREAT | O_APPEND | O_BINARY
101 a4f81979 bellard
};
102 a4f81979 bellard
103 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
104 a4f81979 bellard
static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
105 a4f81979 bellard
{
106 8e71621f pbrook
    if (code == (uint32_t)-1)
107 8e71621f pbrook
        ts->swi_errno = errno;
108 8e71621f pbrook
    return code;
109 8e71621f pbrook
}
110 8e71621f pbrook
#else
111 81926f47 Andreas Färber
static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
112 8e71621f pbrook
{
113 8e71621f pbrook
    return code;
114 8e71621f pbrook
}
115 8e71621f pbrook
116 a87295e8 pbrook
#include "softmmu-semi.h"
117 8e71621f pbrook
#endif
118 a4f81979 bellard
119 a2d1ebaf pbrook
static target_ulong arm_semi_syscall_len;
120 a2d1ebaf pbrook
121 33d9cc8a pbrook
#if !defined(CONFIG_USER_ONLY)
122 33d9cc8a pbrook
static target_ulong syscall_err;
123 33d9cc8a pbrook
#endif
124 33d9cc8a pbrook
125 81926f47 Andreas Färber
static void arm_semi_cb(CPUARMState *env, target_ulong ret, target_ulong err)
126 a2d1ebaf pbrook
{
127 a2d1ebaf pbrook
#ifdef CONFIG_USER_ONLY
128 a2d1ebaf pbrook
    TaskState *ts = env->opaque;
129 a2d1ebaf pbrook
#endif
130 33d9cc8a pbrook
131 a2d1ebaf pbrook
    if (ret == (target_ulong)-1) {
132 a2d1ebaf pbrook
#ifdef CONFIG_USER_ONLY
133 a2d1ebaf pbrook
        ts->swi_errno = err;
134 33d9cc8a pbrook
#else
135 33d9cc8a pbrook
        syscall_err = err;
136 a2d1ebaf pbrook
#endif
137 a2d1ebaf pbrook
        env->regs[0] = ret;
138 a2d1ebaf pbrook
    } else {
139 a2d1ebaf pbrook
        /* Fixup syscalls that use nonstardard return conventions.  */
140 a2d1ebaf pbrook
        switch (env->regs[0]) {
141 3881725c Stefan Weil
        case TARGET_SYS_WRITE:
142 3881725c Stefan Weil
        case TARGET_SYS_READ:
143 a2d1ebaf pbrook
            env->regs[0] = arm_semi_syscall_len - ret;
144 a2d1ebaf pbrook
            break;
145 3881725c Stefan Weil
        case TARGET_SYS_SEEK:
146 a2d1ebaf pbrook
            env->regs[0] = 0;
147 a2d1ebaf pbrook
            break;
148 a2d1ebaf pbrook
        default:
149 a2d1ebaf pbrook
            env->regs[0] = ret;
150 a2d1ebaf pbrook
            break;
151 a2d1ebaf pbrook
        }
152 a2d1ebaf pbrook
    }
153 a2d1ebaf pbrook
}
154 a2d1ebaf pbrook
155 81926f47 Andreas Färber
static void arm_semi_flen_cb(CPUARMState *env, target_ulong ret, target_ulong err)
156 33d9cc8a pbrook
{
157 33d9cc8a pbrook
    /* The size is always stored in big-endian order, extract
158 33d9cc8a pbrook
       the value. We assume the size always fit in 32 bits.  */
159 33d9cc8a pbrook
    uint32_t size;
160 33d9cc8a pbrook
    cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
161 33d9cc8a pbrook
    env->regs[0] = be32_to_cpu(size);
162 33d9cc8a pbrook
#ifdef CONFIG_USER_ONLY
163 33d9cc8a pbrook
    ((TaskState *)env->opaque)->swi_errno = err;
164 33d9cc8a pbrook
#else
165 33d9cc8a pbrook
    syscall_err = err;
166 33d9cc8a pbrook
#endif
167 33d9cc8a pbrook
}
168 33d9cc8a pbrook
169 f296c0d1 Peter Maydell
/* Read the input value from the argument block; fail the semihosting
170 f296c0d1 Peter Maydell
 * call if the memory read fails.
171 f296c0d1 Peter Maydell
 */
172 f296c0d1 Peter Maydell
#define GET_ARG(n) do {                                 \
173 f296c0d1 Peter Maydell
    if (get_user_ual(arg ## n, args + (n) * 4)) {       \
174 f296c0d1 Peter Maydell
        return (uint32_t)-1;                            \
175 f296c0d1 Peter Maydell
    }                                                   \
176 f296c0d1 Peter Maydell
} while (0)
177 f296c0d1 Peter Maydell
178 2f619698 bellard
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
179 81926f47 Andreas Färber
uint32_t do_arm_semihosting(CPUARMState *env)
180 a4f81979 bellard
{
181 53a5960a pbrook
    target_ulong args;
182 f296c0d1 Peter Maydell
    target_ulong arg0, arg1, arg2, arg3;
183 a4f81979 bellard
    char * s;
184 a4f81979 bellard
    int nr;
185 a4f81979 bellard
    uint32_t ret;
186 8e71621f pbrook
    uint32_t len;
187 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
188 a4f81979 bellard
    TaskState *ts = env->opaque;
189 8e71621f pbrook
#else
190 81926f47 Andreas Färber
    CPUARMState *ts = env;
191 8e71621f pbrook
#endif
192 a4f81979 bellard
193 a4f81979 bellard
    nr = env->regs[0];
194 53a5960a pbrook
    args = env->regs[1];
195 a4f81979 bellard
    switch (nr) {
196 3881725c Stefan Weil
    case TARGET_SYS_OPEN:
197 f296c0d1 Peter Maydell
        GET_ARG(0);
198 f296c0d1 Peter Maydell
        GET_ARG(1);
199 f296c0d1 Peter Maydell
        GET_ARG(2);
200 f296c0d1 Peter Maydell
        s = lock_user_string(arg0);
201 f296c0d1 Peter Maydell
        if (!s) {
202 579a97f7 bellard
            /* FIXME - should this error code be -TARGET_EFAULT ? */
203 579a97f7 bellard
            return (uint32_t)-1;
204 f296c0d1 Peter Maydell
        }
205 f296c0d1 Peter Maydell
        if (arg1 >= 12) {
206 f296c0d1 Peter Maydell
            unlock_user(s, arg0, 0);
207 579a97f7 bellard
            return (uint32_t)-1;
208 396bef4b Jim Meyering
        }
209 a4f81979 bellard
        if (strcmp(s, ":tt") == 0) {
210 f296c0d1 Peter Maydell
            int result_fileno = arg1 < 4 ? STDIN_FILENO : STDOUT_FILENO;
211 f296c0d1 Peter Maydell
            unlock_user(s, arg0, 0);
212 396bef4b Jim Meyering
            return result_fileno;
213 a4f81979 bellard
        }
214 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
215 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", arg0,
216 f296c0d1 Peter Maydell
                           (int)arg2+1, gdb_open_modeflags[arg1]);
217 396bef4b Jim Meyering
            ret = env->regs[0];
218 a2d1ebaf pbrook
        } else {
219 f296c0d1 Peter Maydell
            ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644));
220 a2d1ebaf pbrook
        }
221 f296c0d1 Peter Maydell
        unlock_user(s, arg0, 0);
222 8e71621f pbrook
        return ret;
223 3881725c Stefan Weil
    case TARGET_SYS_CLOSE:
224 f296c0d1 Peter Maydell
        GET_ARG(0);
225 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
226 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "close,%x", arg0);
227 a2d1ebaf pbrook
            return env->regs[0];
228 a2d1ebaf pbrook
        } else {
229 f296c0d1 Peter Maydell
            return set_swi_errno(ts, close(arg0));
230 a2d1ebaf pbrook
        }
231 3881725c Stefan Weil
    case TARGET_SYS_WRITEC:
232 53a5960a pbrook
        {
233 2f619698 bellard
          char c;
234 2f619698 bellard
235 2f619698 bellard
          if (get_user_u8(c, args))
236 2f619698 bellard
              /* FIXME - should this error code be -TARGET_EFAULT ? */
237 2f619698 bellard
              return (uint32_t)-1;
238 53a5960a pbrook
          /* Write to debug console.  stderr is near enough.  */
239 a2d1ebaf pbrook
          if (use_gdb_syscalls()) {
240 a2d1ebaf pbrook
                gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
241 a2d1ebaf pbrook
                return env->regs[0];
242 a2d1ebaf pbrook
          } else {
243 a2d1ebaf pbrook
                return write(STDERR_FILENO, &c, 1);
244 a2d1ebaf pbrook
          }
245 53a5960a pbrook
        }
246 3881725c Stefan Weil
    case TARGET_SYS_WRITE0:
247 579a97f7 bellard
        if (!(s = lock_user_string(args)))
248 579a97f7 bellard
            /* FIXME - should this error code be -TARGET_EFAULT ? */
249 579a97f7 bellard
            return (uint32_t)-1;
250 a2d1ebaf pbrook
        len = strlen(s);
251 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
252 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
253 a2d1ebaf pbrook
            ret = env->regs[0];
254 a2d1ebaf pbrook
        } else {
255 a2d1ebaf pbrook
            ret = write(STDERR_FILENO, s, len);
256 a2d1ebaf pbrook
        }
257 53a5960a pbrook
        unlock_user(s, args, 0);
258 53a5960a pbrook
        return ret;
259 3881725c Stefan Weil
    case TARGET_SYS_WRITE:
260 f296c0d1 Peter Maydell
        GET_ARG(0);
261 f296c0d1 Peter Maydell
        GET_ARG(1);
262 f296c0d1 Peter Maydell
        GET_ARG(2);
263 f296c0d1 Peter Maydell
        len = arg2;
264 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
265 a2d1ebaf pbrook
            arm_semi_syscall_len = len;
266 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", arg0, arg1, len);
267 a2d1ebaf pbrook
            return env->regs[0];
268 a2d1ebaf pbrook
        } else {
269 f296c0d1 Peter Maydell
            s = lock_user(VERIFY_READ, arg1, len, 1);
270 f296c0d1 Peter Maydell
            if (!s) {
271 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
272 579a97f7 bellard
                return (uint32_t)-1;
273 f296c0d1 Peter Maydell
            }
274 f296c0d1 Peter Maydell
            ret = set_swi_errno(ts, write(arg0, s, len));
275 f296c0d1 Peter Maydell
            unlock_user(s, arg1, 0);
276 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
277 a2d1ebaf pbrook
                return -1;
278 a2d1ebaf pbrook
            return len - ret;
279 a2d1ebaf pbrook
        }
280 3881725c Stefan Weil
    case TARGET_SYS_READ:
281 f296c0d1 Peter Maydell
        GET_ARG(0);
282 f296c0d1 Peter Maydell
        GET_ARG(1);
283 f296c0d1 Peter Maydell
        GET_ARG(2);
284 f296c0d1 Peter Maydell
        len = arg2;
285 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
286 a2d1ebaf pbrook
            arm_semi_syscall_len = len;
287 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", arg0, arg1, len);
288 a2d1ebaf pbrook
            return env->regs[0];
289 a2d1ebaf pbrook
        } else {
290 f296c0d1 Peter Maydell
            s = lock_user(VERIFY_WRITE, arg1, len, 0);
291 f296c0d1 Peter Maydell
            if (!s) {
292 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
293 579a97f7 bellard
                return (uint32_t)-1;
294 f296c0d1 Peter Maydell
            }
295 f296c0d1 Peter Maydell
            do {
296 f296c0d1 Peter Maydell
                ret = set_swi_errno(ts, read(arg0, s, len));
297 f296c0d1 Peter Maydell
            } while (ret == -1 && errno == EINTR);
298 f296c0d1 Peter Maydell
            unlock_user(s, arg1, len);
299 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
300 a2d1ebaf pbrook
                return -1;
301 a2d1ebaf pbrook
            return len - ret;
302 a2d1ebaf pbrook
        }
303 3881725c Stefan Weil
    case TARGET_SYS_READC:
304 b90372ad Peter Maydell
       /* XXX: Read from debug console. Not implemented.  */
305 a4f81979 bellard
        return 0;
306 3881725c Stefan Weil
    case TARGET_SYS_ISTTY:
307 f296c0d1 Peter Maydell
        GET_ARG(0);
308 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
309 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "isatty,%x", arg0);
310 a2d1ebaf pbrook
            return env->regs[0];
311 a2d1ebaf pbrook
        } else {
312 f296c0d1 Peter Maydell
            return isatty(arg0);
313 a2d1ebaf pbrook
        }
314 3881725c Stefan Weil
    case TARGET_SYS_SEEK:
315 f296c0d1 Peter Maydell
        GET_ARG(0);
316 f296c0d1 Peter Maydell
        GET_ARG(1);
317 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
318 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", arg0, arg1);
319 a2d1ebaf pbrook
            return env->regs[0];
320 a2d1ebaf pbrook
        } else {
321 f296c0d1 Peter Maydell
            ret = set_swi_errno(ts, lseek(arg0, arg1, SEEK_SET));
322 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
323 a2d1ebaf pbrook
              return -1;
324 a2d1ebaf pbrook
            return 0;
325 a2d1ebaf pbrook
        }
326 3881725c Stefan Weil
    case TARGET_SYS_FLEN:
327 f296c0d1 Peter Maydell
        GET_ARG(0);
328 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
329 5fafdf24 ths
            gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
330 f296c0d1 Peter Maydell
                           arg0, env->regs[13]-64);
331 33d9cc8a pbrook
            return env->regs[0];
332 a2d1ebaf pbrook
        } else {
333 a4f81979 bellard
            struct stat buf;
334 f296c0d1 Peter Maydell
            ret = set_swi_errno(ts, fstat(arg0, &buf));
335 a4f81979 bellard
            if (ret == (uint32_t)-1)
336 a4f81979 bellard
                return -1;
337 a4f81979 bellard
            return buf.st_size;
338 a4f81979 bellard
        }
339 3881725c Stefan Weil
    case TARGET_SYS_TMPNAM:
340 a4f81979 bellard
        /* XXX: Not implemented.  */
341 a4f81979 bellard
        return -1;
342 3881725c Stefan Weil
    case TARGET_SYS_REMOVE:
343 f296c0d1 Peter Maydell
        GET_ARG(0);
344 f296c0d1 Peter Maydell
        GET_ARG(1);
345 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
346 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "unlink,%s", arg0, (int)arg1+1);
347 a2d1ebaf pbrook
            ret = env->regs[0];
348 a2d1ebaf pbrook
        } else {
349 f296c0d1 Peter Maydell
            s = lock_user_string(arg0);
350 f296c0d1 Peter Maydell
            if (!s) {
351 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
352 579a97f7 bellard
                return (uint32_t)-1;
353 f296c0d1 Peter Maydell
            }
354 a2d1ebaf pbrook
            ret =  set_swi_errno(ts, remove(s));
355 f296c0d1 Peter Maydell
            unlock_user(s, arg0, 0);
356 a2d1ebaf pbrook
        }
357 8e71621f pbrook
        return ret;
358 3881725c Stefan Weil
    case TARGET_SYS_RENAME:
359 f296c0d1 Peter Maydell
        GET_ARG(0);
360 f296c0d1 Peter Maydell
        GET_ARG(1);
361 f296c0d1 Peter Maydell
        GET_ARG(2);
362 f296c0d1 Peter Maydell
        GET_ARG(3);
363 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
364 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
365 f296c0d1 Peter Maydell
                           arg0, (int)arg1+1, arg2, (int)arg3+1);
366 a2d1ebaf pbrook
            return env->regs[0];
367 a2d1ebaf pbrook
        } else {
368 8e71621f pbrook
            char *s2;
369 f296c0d1 Peter Maydell
            s = lock_user_string(arg0);
370 f296c0d1 Peter Maydell
            s2 = lock_user_string(arg2);
371 579a97f7 bellard
            if (!s || !s2)
372 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
373 579a97f7 bellard
                ret = (uint32_t)-1;
374 579a97f7 bellard
            else
375 579a97f7 bellard
                ret = set_swi_errno(ts, rename(s, s2));
376 579a97f7 bellard
            if (s2)
377 f296c0d1 Peter Maydell
                unlock_user(s2, arg2, 0);
378 579a97f7 bellard
            if (s)
379 f296c0d1 Peter Maydell
                unlock_user(s, arg0, 0);
380 8e71621f pbrook
            return ret;
381 8e71621f pbrook
        }
382 3881725c Stefan Weil
    case TARGET_SYS_CLOCK:
383 a4f81979 bellard
        return clock() / (CLOCKS_PER_SEC / 100);
384 3881725c Stefan Weil
    case TARGET_SYS_TIME:
385 a4f81979 bellard
        return set_swi_errno(ts, time(NULL));
386 3881725c Stefan Weil
    case TARGET_SYS_SYSTEM:
387 f296c0d1 Peter Maydell
        GET_ARG(0);
388 f296c0d1 Peter Maydell
        GET_ARG(1);
389 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
390 f296c0d1 Peter Maydell
            gdb_do_syscall(arm_semi_cb, "system,%s", arg0, (int)arg1+1);
391 a2d1ebaf pbrook
            return env->regs[0];
392 a2d1ebaf pbrook
        } else {
393 f296c0d1 Peter Maydell
            s = lock_user_string(arg0);
394 f296c0d1 Peter Maydell
            if (!s) {
395 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
396 579a97f7 bellard
                return (uint32_t)-1;
397 f296c0d1 Peter Maydell
            }
398 a2d1ebaf pbrook
            ret = set_swi_errno(ts, system(s));
399 f296c0d1 Peter Maydell
            unlock_user(s, arg0, 0);
400 a982b531 ths
            return ret;
401 a2d1ebaf pbrook
        }
402 3881725c Stefan Weil
    case TARGET_SYS_ERRNO:
403 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
404 a4f81979 bellard
        return ts->swi_errno;
405 8e71621f pbrook
#else
406 33d9cc8a pbrook
        return syscall_err;
407 8e71621f pbrook
#endif
408 3881725c Stefan Weil
    case TARGET_SYS_GET_CMDLINE:
409 38d0662a pbrook
        {
410 1c1b40c1 Cédric VINCENT
            /* Build a command-line from the original argv.
411 1c1b40c1 Cédric VINCENT
             *
412 1c1b40c1 Cédric VINCENT
             * The inputs are:
413 f296c0d1 Peter Maydell
             *     * arg0, pointer to a buffer of at least the size
414 f296c0d1 Peter Maydell
             *               specified in arg1.
415 f296c0d1 Peter Maydell
             *     * arg1, size of the buffer pointed to by arg0 in
416 1c1b40c1 Cédric VINCENT
             *               bytes.
417 1c1b40c1 Cédric VINCENT
             *
418 1c1b40c1 Cédric VINCENT
             * The outputs are:
419 f296c0d1 Peter Maydell
             *     * arg0, pointer to null-terminated string of the
420 1c1b40c1 Cédric VINCENT
             *               command line.
421 f296c0d1 Peter Maydell
             *     * arg1, length of the string pointed to by arg0.
422 1c1b40c1 Cédric VINCENT
             */
423 579a97f7 bellard
424 1c1b40c1 Cédric VINCENT
            char *output_buffer;
425 f296c0d1 Peter Maydell
            size_t input_size;
426 1c1b40c1 Cédric VINCENT
            size_t output_size;
427 1c1b40c1 Cédric VINCENT
            int status = 0;
428 f296c0d1 Peter Maydell
            GET_ARG(0);
429 f296c0d1 Peter Maydell
            GET_ARG(1);
430 f296c0d1 Peter Maydell
            input_size = arg1;
431 1c1b40c1 Cédric VINCENT
            /* Compute the size of the output string.  */
432 1c1b40c1 Cédric VINCENT
#if !defined(CONFIG_USER_ONLY)
433 1c1b40c1 Cédric VINCENT
            output_size = strlen(ts->boot_info->kernel_filename)
434 1c1b40c1 Cédric VINCENT
                        + 1  /* Separating space.  */
435 1c1b40c1 Cédric VINCENT
                        + strlen(ts->boot_info->kernel_cmdline)
436 1c1b40c1 Cédric VINCENT
                        + 1; /* Terminating null byte.  */
437 1c1b40c1 Cédric VINCENT
#else
438 1c1b40c1 Cédric VINCENT
            unsigned int i;
439 38d0662a pbrook
440 1c1b40c1 Cédric VINCENT
            output_size = ts->info->arg_end - ts->info->arg_start;
441 1c1b40c1 Cédric VINCENT
            if (!output_size) {
442 2e8785ac Wolfgang Schildbach
                /* We special-case the "empty command line" case (argc==0).
443 2e8785ac Wolfgang Schildbach
                   Just provide the terminating 0. */
444 1c1b40c1 Cédric VINCENT
                output_size = 1;
445 1c1b40c1 Cédric VINCENT
            }
446 1c1b40c1 Cédric VINCENT
#endif
447 38d0662a pbrook
448 1c1b40c1 Cédric VINCENT
            if (output_size > input_size) {
449 1c1b40c1 Cédric VINCENT
                 /* Not enough space to store command-line arguments.  */
450 1c1b40c1 Cédric VINCENT
                return -1;
451 38d0662a pbrook
            }
452 38d0662a pbrook
453 1c1b40c1 Cédric VINCENT
            /* Adjust the command-line length.  */
454 f296c0d1 Peter Maydell
            if (SET_ARG(1, output_size - 1)) {
455 f296c0d1 Peter Maydell
                /* Couldn't write back to argument block */
456 f296c0d1 Peter Maydell
                return -1;
457 f296c0d1 Peter Maydell
            }
458 38d0662a pbrook
459 1c1b40c1 Cédric VINCENT
            /* Lock the buffer on the ARM side.  */
460 f296c0d1 Peter Maydell
            output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
461 1c1b40c1 Cédric VINCENT
            if (!output_buffer) {
462 1c1b40c1 Cédric VINCENT
                return -1;
463 1c1b40c1 Cédric VINCENT
            }
464 38d0662a pbrook
465 1c1b40c1 Cédric VINCENT
            /* Copy the command-line arguments.  */
466 1c1b40c1 Cédric VINCENT
#if !defined(CONFIG_USER_ONLY)
467 1c1b40c1 Cédric VINCENT
            pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
468 1c1b40c1 Cédric VINCENT
            pstrcat(output_buffer, output_size, " ");
469 1c1b40c1 Cédric VINCENT
            pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
470 1c1b40c1 Cédric VINCENT
#else
471 1c1b40c1 Cédric VINCENT
            if (output_size == 1) {
472 1c1b40c1 Cédric VINCENT
                /* Empty command-line.  */
473 1c1b40c1 Cédric VINCENT
                output_buffer[0] = '\0';
474 1c1b40c1 Cédric VINCENT
                goto out;
475 1c1b40c1 Cédric VINCENT
            }
476 2e8785ac Wolfgang Schildbach
477 1c1b40c1 Cédric VINCENT
            if (copy_from_user(output_buffer, ts->info->arg_start,
478 1c1b40c1 Cédric VINCENT
                               output_size)) {
479 1c1b40c1 Cédric VINCENT
                status = -1;
480 1c1b40c1 Cédric VINCENT
                goto out;
481 2e8785ac Wolfgang Schildbach
            }
482 2e8785ac Wolfgang Schildbach
483 1c1b40c1 Cédric VINCENT
            /* Separate arguments by white spaces.  */
484 1c1b40c1 Cédric VINCENT
            for (i = 0; i < output_size - 1; i++) {
485 1c1b40c1 Cédric VINCENT
                if (output_buffer[i] == 0) {
486 1c1b40c1 Cédric VINCENT
                    output_buffer[i] = ' ';
487 1c1b40c1 Cédric VINCENT
                }
488 1c1b40c1 Cédric VINCENT
            }
489 1c1b40c1 Cédric VINCENT
        out:
490 1c1b40c1 Cédric VINCENT
#endif
491 1c1b40c1 Cédric VINCENT
            /* Unlock the buffer on the ARM side.  */
492 f296c0d1 Peter Maydell
            unlock_user(output_buffer, arg0, output_size);
493 2e8785ac Wolfgang Schildbach
494 1c1b40c1 Cédric VINCENT
            return status;
495 38d0662a pbrook
        }
496 3881725c Stefan Weil
    case TARGET_SYS_HEAPINFO:
497 a4f81979 bellard
        {
498 a4f81979 bellard
            uint32_t *ptr;
499 a4f81979 bellard
            uint32_t limit;
500 f296c0d1 Peter Maydell
            GET_ARG(0);
501 a4f81979 bellard
502 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
503 8e71621f pbrook
            /* Some C libraries assume the heap immediately follows .bss, so
504 a4f81979 bellard
               allocate it using sbrk.  */
505 a4f81979 bellard
            if (!ts->heap_limit) {
506 206ae74a Peter Maydell
                abi_ulong ret;
507 a4f81979 bellard
508 53a5960a pbrook
                ts->heap_base = do_brk(0);
509 a4f81979 bellard
                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
510 a4f81979 bellard
                /* Try a big heap, and reduce the size if that fails.  */
511 a4f81979 bellard
                for (;;) {
512 53a5960a pbrook
                    ret = do_brk(limit);
513 206ae74a Peter Maydell
                    if (ret >= limit) {
514 a4f81979 bellard
                        break;
515 206ae74a Peter Maydell
                    }
516 a4f81979 bellard
                    limit = (ts->heap_base >> 1) + (limit >> 1);
517 a4f81979 bellard
                }
518 a4f81979 bellard
                ts->heap_limit = limit;
519 a4f81979 bellard
            }
520 3b46e624 ths
521 f296c0d1 Peter Maydell
            ptr = lock_user(VERIFY_WRITE, arg0, 16, 0);
522 f296c0d1 Peter Maydell
            if (!ptr) {
523 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
524 579a97f7 bellard
                return (uint32_t)-1;
525 f296c0d1 Peter Maydell
            }
526 a4f81979 bellard
            ptr[0] = tswap32(ts->heap_base);
527 a4f81979 bellard
            ptr[1] = tswap32(ts->heap_limit);
528 a4f81979 bellard
            ptr[2] = tswap32(ts->stack_base);
529 a4f81979 bellard
            ptr[3] = tswap32(0); /* Stack limit.  */
530 f296c0d1 Peter Maydell
            unlock_user(ptr, arg0, 16);
531 8e71621f pbrook
#else
532 8e71621f pbrook
            limit = ram_size;
533 f296c0d1 Peter Maydell
            ptr = lock_user(VERIFY_WRITE, arg0, 16, 0);
534 f296c0d1 Peter Maydell
            if (!ptr) {
535 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
536 579a97f7 bellard
                return (uint32_t)-1;
537 f296c0d1 Peter Maydell
            }
538 8e71621f pbrook
            /* TODO: Make this use the limit of the loaded application.  */
539 8e71621f pbrook
            ptr[0] = tswap32(limit / 2);
540 8e71621f pbrook
            ptr[1] = tswap32(limit);
541 8e71621f pbrook
            ptr[2] = tswap32(limit); /* Stack base */
542 8e71621f pbrook
            ptr[3] = tswap32(0); /* Stack limit.  */
543 f296c0d1 Peter Maydell
            unlock_user(ptr, arg0, 16);
544 8e71621f pbrook
#endif
545 a4f81979 bellard
            return 0;
546 a4f81979 bellard
        }
547 3881725c Stefan Weil
    case TARGET_SYS_EXIT:
548 0e1c9c54 Paul Brook
        gdb_exit(env, 0);
549 a4f81979 bellard
        exit(0);
550 a4f81979 bellard
    default:
551 a4f81979 bellard
        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
552 a4f81979 bellard
        cpu_dump_state(env, stderr, fprintf, 0);
553 a4f81979 bellard
        abort();
554 a4f81979 bellard
    }
555 a4f81979 bellard
}