Statistics
| Branch: | Revision:

root / arm-semi.c @ 153859be

History | View | Annotate | Download (14.2 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 a4f81979 bellard
 *  along with this program; if not, write to the Free Software
19 530e7615 blueswir1
 *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 530e7615 blueswir1
 *  MA 02110-1301, USA.
21 a4f81979 bellard
 */
22 a4f81979 bellard
23 a4f81979 bellard
#include <sys/types.h>
24 a4f81979 bellard
#include <sys/stat.h>
25 a4f81979 bellard
#include <fcntl.h>
26 a4f81979 bellard
#include <unistd.h>
27 a4f81979 bellard
#include <stdlib.h>
28 a4f81979 bellard
#include <stdio.h>
29 a4f81979 bellard
#include <time.h>
30 a4f81979 bellard
31 8e71621f pbrook
#include "cpu.h"
32 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
33 a4f81979 bellard
#include "qemu.h"
34 a4f81979 bellard
35 a4f81979 bellard
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
36 8e71621f pbrook
#else
37 87ecb68b pbrook
#include "qemu-common.h"
38 87ecb68b pbrook
#include "sysemu.h"
39 87ecb68b pbrook
#include "gdbstub.h"
40 8e71621f pbrook
#endif
41 a4f81979 bellard
42 a4f81979 bellard
#define SYS_OPEN        0x01
43 a4f81979 bellard
#define SYS_CLOSE       0x02
44 a4f81979 bellard
#define SYS_WRITEC      0x03
45 a4f81979 bellard
#define SYS_WRITE0      0x04
46 a4f81979 bellard
#define SYS_WRITE       0x05
47 a4f81979 bellard
#define SYS_READ        0x06
48 a4f81979 bellard
#define SYS_READC       0x07
49 a4f81979 bellard
#define SYS_ISTTY       0x09
50 a4f81979 bellard
#define SYS_SEEK        0x0a
51 a4f81979 bellard
#define SYS_FLEN        0x0c
52 a4f81979 bellard
#define SYS_TMPNAM      0x0d
53 a4f81979 bellard
#define SYS_REMOVE      0x0e
54 a4f81979 bellard
#define SYS_RENAME      0x0f
55 a4f81979 bellard
#define SYS_CLOCK       0x10
56 a4f81979 bellard
#define SYS_TIME        0x11
57 a4f81979 bellard
#define SYS_SYSTEM      0x12
58 a4f81979 bellard
#define SYS_ERRNO       0x13
59 a4f81979 bellard
#define SYS_GET_CMDLINE 0x15
60 a4f81979 bellard
#define SYS_HEAPINFO    0x16
61 a4f81979 bellard
#define SYS_EXIT        0x18
62 a4f81979 bellard
63 a4f81979 bellard
#ifndef O_BINARY
64 a4f81979 bellard
#define O_BINARY 0
65 a4f81979 bellard
#endif
66 a4f81979 bellard
67 a2d1ebaf pbrook
#define GDB_O_RDONLY  0x000
68 a2d1ebaf pbrook
#define GDB_O_WRONLY  0x001
69 a2d1ebaf pbrook
#define GDB_O_RDWR    0x002
70 a2d1ebaf pbrook
#define GDB_O_APPEND  0x008
71 a2d1ebaf pbrook
#define GDB_O_CREAT   0x200
72 a2d1ebaf pbrook
#define GDB_O_TRUNC   0x400
73 a2d1ebaf pbrook
#define GDB_O_BINARY  0
74 a2d1ebaf pbrook
75 a2d1ebaf pbrook
static int gdb_open_modeflags[12] = {
76 a2d1ebaf pbrook
    GDB_O_RDONLY,
77 a2d1ebaf pbrook
    GDB_O_RDONLY | GDB_O_BINARY,
78 a2d1ebaf pbrook
    GDB_O_RDWR,
79 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_BINARY,
80 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
81 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
82 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
83 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
84 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
85 a2d1ebaf pbrook
    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
86 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
87 a2d1ebaf pbrook
    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
88 a2d1ebaf pbrook
};
89 a2d1ebaf pbrook
90 a2d1ebaf pbrook
static int open_modeflags[12] = {
91 a4f81979 bellard
    O_RDONLY,
92 a4f81979 bellard
    O_RDONLY | O_BINARY,
93 a4f81979 bellard
    O_RDWR,
94 a4f81979 bellard
    O_RDWR | O_BINARY,
95 a4f81979 bellard
    O_WRONLY | O_CREAT | O_TRUNC,
96 a4f81979 bellard
    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
97 a4f81979 bellard
    O_RDWR | O_CREAT | O_TRUNC,
98 a4f81979 bellard
    O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
99 a4f81979 bellard
    O_WRONLY | O_CREAT | O_APPEND,
100 a4f81979 bellard
    O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
101 a4f81979 bellard
    O_RDWR | O_CREAT | O_APPEND,
102 a4f81979 bellard
    O_RDWR | O_CREAT | O_APPEND | O_BINARY
103 a4f81979 bellard
};
104 a4f81979 bellard
105 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
106 a4f81979 bellard
static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
107 a4f81979 bellard
{
108 8e71621f pbrook
    if (code == (uint32_t)-1)
109 8e71621f pbrook
        ts->swi_errno = errno;
110 8e71621f pbrook
    return code;
111 8e71621f pbrook
}
112 8e71621f pbrook
#else
113 8e71621f pbrook
static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
114 8e71621f pbrook
{
115 8e71621f pbrook
    return code;
116 8e71621f pbrook
}
117 8e71621f pbrook
118 a87295e8 pbrook
#include "softmmu-semi.h"
119 8e71621f pbrook
#endif
120 a4f81979 bellard
121 a2d1ebaf pbrook
static target_ulong arm_semi_syscall_len;
122 a2d1ebaf pbrook
123 33d9cc8a pbrook
#if !defined(CONFIG_USER_ONLY)
124 33d9cc8a pbrook
static target_ulong syscall_err;
125 33d9cc8a pbrook
#endif
126 33d9cc8a pbrook
127 a2d1ebaf pbrook
static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
128 a2d1ebaf pbrook
{
129 a2d1ebaf pbrook
#ifdef CONFIG_USER_ONLY
130 a2d1ebaf pbrook
    TaskState *ts = env->opaque;
131 a2d1ebaf pbrook
#endif
132 33d9cc8a pbrook
133 a2d1ebaf pbrook
    if (ret == (target_ulong)-1) {
134 a2d1ebaf pbrook
#ifdef CONFIG_USER_ONLY
135 a2d1ebaf pbrook
        ts->swi_errno = err;
136 33d9cc8a pbrook
#else
137 33d9cc8a pbrook
        syscall_err = err;
138 a2d1ebaf pbrook
#endif
139 a2d1ebaf pbrook
        env->regs[0] = ret;
140 a2d1ebaf pbrook
    } else {
141 a2d1ebaf pbrook
        /* Fixup syscalls that use nonstardard return conventions.  */
142 a2d1ebaf pbrook
        switch (env->regs[0]) {
143 a2d1ebaf pbrook
        case SYS_WRITE:
144 a2d1ebaf pbrook
        case SYS_READ:
145 a2d1ebaf pbrook
            env->regs[0] = arm_semi_syscall_len - ret;
146 a2d1ebaf pbrook
            break;
147 a2d1ebaf pbrook
        case SYS_SEEK:
148 a2d1ebaf pbrook
            env->regs[0] = 0;
149 a2d1ebaf pbrook
            break;
150 a2d1ebaf pbrook
        default:
151 a2d1ebaf pbrook
            env->regs[0] = ret;
152 a2d1ebaf pbrook
            break;
153 a2d1ebaf pbrook
        }
154 a2d1ebaf pbrook
    }
155 a2d1ebaf pbrook
}
156 a2d1ebaf pbrook
157 33d9cc8a pbrook
static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err)
158 33d9cc8a pbrook
{
159 33d9cc8a pbrook
    /* The size is always stored in big-endian order, extract
160 33d9cc8a pbrook
       the value. We assume the size always fit in 32 bits.  */
161 33d9cc8a pbrook
    uint32_t size;
162 33d9cc8a pbrook
    cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
163 33d9cc8a pbrook
    env->regs[0] = be32_to_cpu(size);
164 33d9cc8a pbrook
#ifdef CONFIG_USER_ONLY
165 33d9cc8a pbrook
    ((TaskState *)env->opaque)->swi_errno = err;
166 33d9cc8a pbrook
#else
167 33d9cc8a pbrook
    syscall_err = err;
168 33d9cc8a pbrook
#endif
169 33d9cc8a pbrook
}
170 33d9cc8a pbrook
171 2f619698 bellard
#define ARG(n)                                        \
172 2f619698 bellard
({                                                \
173 2f619698 bellard
    target_ulong __arg;                                \
174 2f619698 bellard
    /* FIXME - handle get_user() failure */        \
175 2f619698 bellard
    get_user_ual(__arg, args + (n) * 4);        \
176 2f619698 bellard
    __arg;                                        \
177 2f619698 bellard
})
178 2f619698 bellard
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
179 a4f81979 bellard
uint32_t do_arm_semihosting(CPUState *env)
180 a4f81979 bellard
{
181 53a5960a pbrook
    target_ulong args;
182 a4f81979 bellard
    char * s;
183 a4f81979 bellard
    int nr;
184 a4f81979 bellard
    uint32_t ret;
185 8e71621f pbrook
    uint32_t len;
186 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
187 a4f81979 bellard
    TaskState *ts = env->opaque;
188 8e71621f pbrook
#else
189 8e71621f pbrook
    CPUState *ts = env;
190 8e71621f pbrook
#endif
191 a4f81979 bellard
192 a4f81979 bellard
    nr = env->regs[0];
193 53a5960a pbrook
    args = env->regs[1];
194 a4f81979 bellard
    switch (nr) {
195 a4f81979 bellard
    case SYS_OPEN:
196 579a97f7 bellard
        if (!(s = lock_user_string(ARG(0))))
197 579a97f7 bellard
            /* FIXME - should this error code be -TARGET_EFAULT ? */
198 579a97f7 bellard
            return (uint32_t)-1;
199 a4f81979 bellard
        if (ARG(1) >= 12)
200 579a97f7 bellard
            return (uint32_t)-1;
201 a4f81979 bellard
        if (strcmp(s, ":tt") == 0) {
202 a4f81979 bellard
            if (ARG(1) < 4)
203 a4f81979 bellard
                return STDIN_FILENO;
204 a4f81979 bellard
            else
205 a4f81979 bellard
                return STDOUT_FILENO;
206 a4f81979 bellard
        }
207 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
208 5fafdf24 ths
            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
209 33d9cc8a pbrook
                           (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
210 a2d1ebaf pbrook
            return env->regs[0];
211 a2d1ebaf pbrook
        } else {
212 a2d1ebaf pbrook
            ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
213 a2d1ebaf pbrook
        }
214 8e71621f pbrook
        unlock_user(s, ARG(0), 0);
215 8e71621f pbrook
        return ret;
216 a4f81979 bellard
    case SYS_CLOSE:
217 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
218 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
219 a2d1ebaf pbrook
            return env->regs[0];
220 a2d1ebaf pbrook
        } else {
221 a2d1ebaf pbrook
            return set_swi_errno(ts, close(ARG(0)));
222 a2d1ebaf pbrook
        }
223 a4f81979 bellard
    case SYS_WRITEC:
224 53a5960a pbrook
        {
225 2f619698 bellard
          char c;
226 2f619698 bellard
227 2f619698 bellard
          if (get_user_u8(c, args))
228 2f619698 bellard
              /* FIXME - should this error code be -TARGET_EFAULT ? */
229 2f619698 bellard
              return (uint32_t)-1;
230 53a5960a pbrook
          /* Write to debug console.  stderr is near enough.  */
231 a2d1ebaf pbrook
          if (use_gdb_syscalls()) {
232 a2d1ebaf pbrook
                gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
233 a2d1ebaf pbrook
                return env->regs[0];
234 a2d1ebaf pbrook
          } else {
235 a2d1ebaf pbrook
                return write(STDERR_FILENO, &c, 1);
236 a2d1ebaf pbrook
          }
237 53a5960a pbrook
        }
238 a4f81979 bellard
    case SYS_WRITE0:
239 579a97f7 bellard
        if (!(s = lock_user_string(args)))
240 579a97f7 bellard
            /* FIXME - should this error code be -TARGET_EFAULT ? */
241 579a97f7 bellard
            return (uint32_t)-1;
242 a2d1ebaf pbrook
        len = strlen(s);
243 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
244 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
245 a2d1ebaf pbrook
            ret = env->regs[0];
246 a2d1ebaf pbrook
        } else {
247 a2d1ebaf pbrook
            ret = write(STDERR_FILENO, s, len);
248 a2d1ebaf pbrook
        }
249 53a5960a pbrook
        unlock_user(s, args, 0);
250 53a5960a pbrook
        return ret;
251 a4f81979 bellard
    case SYS_WRITE:
252 8e71621f pbrook
        len = ARG(2);
253 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
254 a2d1ebaf pbrook
            arm_semi_syscall_len = len;
255 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
256 a2d1ebaf pbrook
            return env->regs[0];
257 a2d1ebaf pbrook
        } else {
258 579a97f7 bellard
            if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1)))
259 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
260 579a97f7 bellard
                return (uint32_t)-1;
261 a2d1ebaf pbrook
            ret = set_swi_errno(ts, write(ARG(0), s, len));
262 a2d1ebaf pbrook
            unlock_user(s, ARG(1), 0);
263 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
264 a2d1ebaf pbrook
                return -1;
265 a2d1ebaf pbrook
            return len - ret;
266 a2d1ebaf pbrook
        }
267 a4f81979 bellard
    case SYS_READ:
268 8e71621f pbrook
        len = ARG(2);
269 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
270 a2d1ebaf pbrook
            arm_semi_syscall_len = len;
271 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
272 a2d1ebaf pbrook
            return env->regs[0];
273 a2d1ebaf pbrook
        } else {
274 579a97f7 bellard
            if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0)))
275 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
276 579a97f7 bellard
                return (uint32_t)-1;
277 a2d1ebaf pbrook
            do
278 a2d1ebaf pbrook
              ret = set_swi_errno(ts, read(ARG(0), s, len));
279 a2d1ebaf pbrook
            while (ret == -1 && errno == EINTR);
280 a2d1ebaf pbrook
            unlock_user(s, ARG(1), len);
281 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
282 a2d1ebaf pbrook
                return -1;
283 a2d1ebaf pbrook
            return len - ret;
284 a2d1ebaf pbrook
        }
285 a4f81979 bellard
    case SYS_READC:
286 a4f81979 bellard
       /* XXX: Read from debug cosole. Not implemented.  */
287 a4f81979 bellard
        return 0;
288 a4f81979 bellard
    case SYS_ISTTY:
289 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
290 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
291 a2d1ebaf pbrook
            return env->regs[0];
292 a2d1ebaf pbrook
        } else {
293 a2d1ebaf pbrook
            return isatty(ARG(0));
294 a2d1ebaf pbrook
        }
295 a4f81979 bellard
    case SYS_SEEK:
296 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
297 33d9cc8a pbrook
            gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
298 a2d1ebaf pbrook
            return env->regs[0];
299 a2d1ebaf pbrook
        } else {
300 a2d1ebaf pbrook
            ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
301 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
302 a2d1ebaf pbrook
              return -1;
303 a2d1ebaf pbrook
            return 0;
304 a2d1ebaf pbrook
        }
305 a4f81979 bellard
    case SYS_FLEN:
306 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
307 5fafdf24 ths
            gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
308 33d9cc8a pbrook
                           ARG(0), env->regs[13]-64);
309 33d9cc8a pbrook
            return env->regs[0];
310 a2d1ebaf pbrook
        } else {
311 a4f81979 bellard
            struct stat buf;
312 a4f81979 bellard
            ret = set_swi_errno(ts, fstat(ARG(0), &buf));
313 a4f81979 bellard
            if (ret == (uint32_t)-1)
314 a4f81979 bellard
                return -1;
315 a4f81979 bellard
            return buf.st_size;
316 a4f81979 bellard
        }
317 a4f81979 bellard
    case SYS_TMPNAM:
318 a4f81979 bellard
        /* XXX: Not implemented.  */
319 a4f81979 bellard
        return -1;
320 a4f81979 bellard
    case SYS_REMOVE:
321 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
322 33d9cc8a pbrook
            gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
323 a2d1ebaf pbrook
            ret = env->regs[0];
324 a2d1ebaf pbrook
        } else {
325 579a97f7 bellard
            if (!(s = lock_user_string(ARG(0))))
326 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
327 579a97f7 bellard
                return (uint32_t)-1;
328 a2d1ebaf pbrook
            ret =  set_swi_errno(ts, remove(s));
329 a2d1ebaf pbrook
            unlock_user(s, ARG(0), 0);
330 a2d1ebaf pbrook
        }
331 8e71621f pbrook
        return ret;
332 a4f81979 bellard
    case SYS_RENAME:
333 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
334 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
335 33d9cc8a pbrook
                           ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
336 a2d1ebaf pbrook
            return env->regs[0];
337 a2d1ebaf pbrook
        } else {
338 8e71621f pbrook
            char *s2;
339 8e71621f pbrook
            s = lock_user_string(ARG(0));
340 8e71621f pbrook
            s2 = lock_user_string(ARG(2));
341 579a97f7 bellard
            if (!s || !s2)
342 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
343 579a97f7 bellard
                ret = (uint32_t)-1;
344 579a97f7 bellard
            else
345 579a97f7 bellard
                ret = set_swi_errno(ts, rename(s, s2));
346 579a97f7 bellard
            if (s2)
347 579a97f7 bellard
                unlock_user(s2, ARG(2), 0);
348 579a97f7 bellard
            if (s)
349 579a97f7 bellard
                unlock_user(s, ARG(0), 0);
350 8e71621f pbrook
            return ret;
351 8e71621f pbrook
        }
352 a4f81979 bellard
    case SYS_CLOCK:
353 a4f81979 bellard
        return clock() / (CLOCKS_PER_SEC / 100);
354 a4f81979 bellard
    case SYS_TIME:
355 a4f81979 bellard
        return set_swi_errno(ts, time(NULL));
356 a4f81979 bellard
    case SYS_SYSTEM:
357 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
358 33d9cc8a pbrook
            gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
359 a2d1ebaf pbrook
            return env->regs[0];
360 a2d1ebaf pbrook
        } else {
361 579a97f7 bellard
            if (!(s = lock_user_string(ARG(0))))
362 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
363 579a97f7 bellard
                return (uint32_t)-1;
364 a2d1ebaf pbrook
            ret = set_swi_errno(ts, system(s));
365 a2d1ebaf pbrook
            unlock_user(s, ARG(0), 0);
366 a982b531 ths
            return ret;
367 a2d1ebaf pbrook
        }
368 a4f81979 bellard
    case SYS_ERRNO:
369 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
370 a4f81979 bellard
        return ts->swi_errno;
371 8e71621f pbrook
#else
372 33d9cc8a pbrook
        return syscall_err;
373 8e71621f pbrook
#endif
374 a4f81979 bellard
    case SYS_GET_CMDLINE:
375 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
376 38d0662a pbrook
        /* Build a commandline from the original argv.  */
377 38d0662a pbrook
        {
378 38d0662a pbrook
            char **arg = ts->info->host_argv;
379 38d0662a pbrook
            int len = ARG(1);
380 38d0662a pbrook
            /* lock the buffer on the ARM side */
381 579a97f7 bellard
            char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
382 579a97f7 bellard
383 579a97f7 bellard
            if (!cmdline_buffer)
384 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
385 579a97f7 bellard
                return (uint32_t)-1;
386 38d0662a pbrook
387 38d0662a pbrook
            s = cmdline_buffer;
388 38d0662a pbrook
            while (*arg && len > 2) {
389 38d0662a pbrook
                int n = strlen(*arg);
390 38d0662a pbrook
391 38d0662a pbrook
                if (s != cmdline_buffer) {
392 38d0662a pbrook
                    *(s++) = ' ';
393 38d0662a pbrook
                    len--;
394 38d0662a pbrook
                }
395 38d0662a pbrook
                if (n >= len)
396 38d0662a pbrook
                    n = len - 1;
397 38d0662a pbrook
                memcpy(s, *arg, n);
398 38d0662a pbrook
                s += n;
399 38d0662a pbrook
                len -= n;
400 38d0662a pbrook
                arg++;
401 38d0662a pbrook
            }
402 38d0662a pbrook
            /* Null terminate the string.  */
403 38d0662a pbrook
            *s = 0;
404 38d0662a pbrook
            len = s - cmdline_buffer;
405 38d0662a pbrook
406 38d0662a pbrook
            /* Unlock the buffer on the ARM side.  */
407 38d0662a pbrook
            unlock_user(cmdline_buffer, ARG(0), len);
408 38d0662a pbrook
409 38d0662a pbrook
            /* Adjust the commandline length argument.  */
410 38d0662a pbrook
            SET_ARG(1, len);
411 38d0662a pbrook
412 38d0662a pbrook
            /* Return success if commandline fit into buffer.  */
413 38d0662a pbrook
            return *arg ? -1 : 0;
414 38d0662a pbrook
        }
415 8e71621f pbrook
#else
416 8e71621f pbrook
      return -1;
417 8e71621f pbrook
#endif
418 a4f81979 bellard
    case SYS_HEAPINFO:
419 a4f81979 bellard
        {
420 a4f81979 bellard
            uint32_t *ptr;
421 a4f81979 bellard
            uint32_t limit;
422 a4f81979 bellard
423 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
424 8e71621f pbrook
            /* Some C libraries assume the heap immediately follows .bss, so
425 a4f81979 bellard
               allocate it using sbrk.  */
426 a4f81979 bellard
            if (!ts->heap_limit) {
427 a4f81979 bellard
                long ret;
428 a4f81979 bellard
429 53a5960a pbrook
                ts->heap_base = do_brk(0);
430 a4f81979 bellard
                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
431 a4f81979 bellard
                /* Try a big heap, and reduce the size if that fails.  */
432 a4f81979 bellard
                for (;;) {
433 53a5960a pbrook
                    ret = do_brk(limit);
434 a4f81979 bellard
                    if (ret != -1)
435 a4f81979 bellard
                        break;
436 a4f81979 bellard
                    limit = (ts->heap_base >> 1) + (limit >> 1);
437 a4f81979 bellard
                }
438 a4f81979 bellard
                ts->heap_limit = limit;
439 a4f81979 bellard
            }
440 3b46e624 ths
441 579a97f7 bellard
            if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
442 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
443 579a97f7 bellard
                return (uint32_t)-1;
444 a4f81979 bellard
            ptr[0] = tswap32(ts->heap_base);
445 a4f81979 bellard
            ptr[1] = tswap32(ts->heap_limit);
446 a4f81979 bellard
            ptr[2] = tswap32(ts->stack_base);
447 a4f81979 bellard
            ptr[3] = tswap32(0); /* Stack limit.  */
448 8e71621f pbrook
            unlock_user(ptr, ARG(0), 16);
449 8e71621f pbrook
#else
450 8e71621f pbrook
            limit = ram_size;
451 579a97f7 bellard
            if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
452 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
453 579a97f7 bellard
                return (uint32_t)-1;
454 8e71621f pbrook
            /* TODO: Make this use the limit of the loaded application.  */
455 8e71621f pbrook
            ptr[0] = tswap32(limit / 2);
456 8e71621f pbrook
            ptr[1] = tswap32(limit);
457 8e71621f pbrook
            ptr[2] = tswap32(limit); /* Stack base */
458 8e71621f pbrook
            ptr[3] = tswap32(0); /* Stack limit.  */
459 8e71621f pbrook
            unlock_user(ptr, ARG(0), 16);
460 8e71621f pbrook
#endif
461 a4f81979 bellard
            return 0;
462 a4f81979 bellard
        }
463 a4f81979 bellard
    case SYS_EXIT:
464 a4f81979 bellard
        exit(0);
465 a4f81979 bellard
    default:
466 a4f81979 bellard
        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
467 a4f81979 bellard
        cpu_dump_state(env, stderr, fprintf, 0);
468 a4f81979 bellard
        abort();
469 a4f81979 bellard
    }
470 a4f81979 bellard
}