Statistics
| Branch: | Revision:

root / arm-semi.c @ e7c5e893

History | View | Annotate | Download (15.7 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 a4f81979 bellard
#define SYS_OPEN        0x01
41 a4f81979 bellard
#define SYS_CLOSE       0x02
42 a4f81979 bellard
#define SYS_WRITEC      0x03
43 a4f81979 bellard
#define SYS_WRITE0      0x04
44 a4f81979 bellard
#define SYS_WRITE       0x05
45 a4f81979 bellard
#define SYS_READ        0x06
46 a4f81979 bellard
#define SYS_READC       0x07
47 a4f81979 bellard
#define SYS_ISTTY       0x09
48 a4f81979 bellard
#define SYS_SEEK        0x0a
49 a4f81979 bellard
#define SYS_FLEN        0x0c
50 a4f81979 bellard
#define SYS_TMPNAM      0x0d
51 a4f81979 bellard
#define SYS_REMOVE      0x0e
52 a4f81979 bellard
#define SYS_RENAME      0x0f
53 a4f81979 bellard
#define SYS_CLOCK       0x10
54 a4f81979 bellard
#define SYS_TIME        0x11
55 a4f81979 bellard
#define SYS_SYSTEM      0x12
56 a4f81979 bellard
#define SYS_ERRNO       0x13
57 a4f81979 bellard
#define SYS_GET_CMDLINE 0x15
58 a4f81979 bellard
#define SYS_HEAPINFO    0x16
59 a4f81979 bellard
#define 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 8e71621f pbrook
static inline uint32_t set_swi_errno(CPUState *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 a2d1ebaf pbrook
static void arm_semi_cb(CPUState *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 a2d1ebaf pbrook
        case SYS_WRITE:
142 a2d1ebaf pbrook
        case SYS_READ:
143 a2d1ebaf pbrook
            env->regs[0] = arm_semi_syscall_len - ret;
144 a2d1ebaf pbrook
            break;
145 a2d1ebaf pbrook
        case 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 33d9cc8a pbrook
static void arm_semi_flen_cb(CPUState *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 2f619698 bellard
#define ARG(n)                                        \
170 2f619698 bellard
({                                                \
171 2f619698 bellard
    target_ulong __arg;                                \
172 2f619698 bellard
    /* FIXME - handle get_user() failure */        \
173 2f619698 bellard
    get_user_ual(__arg, args + (n) * 4);        \
174 2f619698 bellard
    __arg;                                        \
175 2f619698 bellard
})
176 2f619698 bellard
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
177 a4f81979 bellard
uint32_t do_arm_semihosting(CPUState *env)
178 a4f81979 bellard
{
179 53a5960a pbrook
    target_ulong args;
180 a4f81979 bellard
    char * s;
181 a4f81979 bellard
    int nr;
182 a4f81979 bellard
    uint32_t ret;
183 8e71621f pbrook
    uint32_t len;
184 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
185 a4f81979 bellard
    TaskState *ts = env->opaque;
186 8e71621f pbrook
#else
187 8e71621f pbrook
    CPUState *ts = env;
188 8e71621f pbrook
#endif
189 a4f81979 bellard
190 a4f81979 bellard
    nr = env->regs[0];
191 53a5960a pbrook
    args = env->regs[1];
192 a4f81979 bellard
    switch (nr) {
193 a4f81979 bellard
    case SYS_OPEN:
194 579a97f7 bellard
        if (!(s = lock_user_string(ARG(0))))
195 579a97f7 bellard
            /* FIXME - should this error code be -TARGET_EFAULT ? */
196 579a97f7 bellard
            return (uint32_t)-1;
197 a4f81979 bellard
        if (ARG(1) >= 12)
198 579a97f7 bellard
            return (uint32_t)-1;
199 a4f81979 bellard
        if (strcmp(s, ":tt") == 0) {
200 a4f81979 bellard
            if (ARG(1) < 4)
201 a4f81979 bellard
                return STDIN_FILENO;
202 a4f81979 bellard
            else
203 a4f81979 bellard
                return STDOUT_FILENO;
204 a4f81979 bellard
        }
205 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
206 5fafdf24 ths
            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
207 33d9cc8a pbrook
                           (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
208 a2d1ebaf pbrook
            return env->regs[0];
209 a2d1ebaf pbrook
        } else {
210 a2d1ebaf pbrook
            ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
211 a2d1ebaf pbrook
        }
212 8e71621f pbrook
        unlock_user(s, ARG(0), 0);
213 8e71621f pbrook
        return ret;
214 a4f81979 bellard
    case SYS_CLOSE:
215 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
216 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
217 a2d1ebaf pbrook
            return env->regs[0];
218 a2d1ebaf pbrook
        } else {
219 a2d1ebaf pbrook
            return set_swi_errno(ts, close(ARG(0)));
220 a2d1ebaf pbrook
        }
221 a4f81979 bellard
    case SYS_WRITEC:
222 53a5960a pbrook
        {
223 2f619698 bellard
          char c;
224 2f619698 bellard
225 2f619698 bellard
          if (get_user_u8(c, args))
226 2f619698 bellard
              /* FIXME - should this error code be -TARGET_EFAULT ? */
227 2f619698 bellard
              return (uint32_t)-1;
228 53a5960a pbrook
          /* Write to debug console.  stderr is near enough.  */
229 a2d1ebaf pbrook
          if (use_gdb_syscalls()) {
230 a2d1ebaf pbrook
                gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
231 a2d1ebaf pbrook
                return env->regs[0];
232 a2d1ebaf pbrook
          } else {
233 a2d1ebaf pbrook
                return write(STDERR_FILENO, &c, 1);
234 a2d1ebaf pbrook
          }
235 53a5960a pbrook
        }
236 a4f81979 bellard
    case SYS_WRITE0:
237 579a97f7 bellard
        if (!(s = lock_user_string(args)))
238 579a97f7 bellard
            /* FIXME - should this error code be -TARGET_EFAULT ? */
239 579a97f7 bellard
            return (uint32_t)-1;
240 a2d1ebaf pbrook
        len = strlen(s);
241 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
242 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
243 a2d1ebaf pbrook
            ret = env->regs[0];
244 a2d1ebaf pbrook
        } else {
245 a2d1ebaf pbrook
            ret = write(STDERR_FILENO, s, len);
246 a2d1ebaf pbrook
        }
247 53a5960a pbrook
        unlock_user(s, args, 0);
248 53a5960a pbrook
        return ret;
249 a4f81979 bellard
    case SYS_WRITE:
250 8e71621f pbrook
        len = ARG(2);
251 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
252 a2d1ebaf pbrook
            arm_semi_syscall_len = len;
253 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
254 a2d1ebaf pbrook
            return env->regs[0];
255 a2d1ebaf pbrook
        } else {
256 579a97f7 bellard
            if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1)))
257 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
258 579a97f7 bellard
                return (uint32_t)-1;
259 a2d1ebaf pbrook
            ret = set_swi_errno(ts, write(ARG(0), s, len));
260 a2d1ebaf pbrook
            unlock_user(s, ARG(1), 0);
261 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
262 a2d1ebaf pbrook
                return -1;
263 a2d1ebaf pbrook
            return len - ret;
264 a2d1ebaf pbrook
        }
265 a4f81979 bellard
    case SYS_READ:
266 8e71621f pbrook
        len = ARG(2);
267 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
268 a2d1ebaf pbrook
            arm_semi_syscall_len = len;
269 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
270 a2d1ebaf pbrook
            return env->regs[0];
271 a2d1ebaf pbrook
        } else {
272 579a97f7 bellard
            if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0)))
273 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
274 579a97f7 bellard
                return (uint32_t)-1;
275 a2d1ebaf pbrook
            do
276 a2d1ebaf pbrook
              ret = set_swi_errno(ts, read(ARG(0), s, len));
277 a2d1ebaf pbrook
            while (ret == -1 && errno == EINTR);
278 a2d1ebaf pbrook
            unlock_user(s, ARG(1), len);
279 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
280 a2d1ebaf pbrook
                return -1;
281 a2d1ebaf pbrook
            return len - ret;
282 a2d1ebaf pbrook
        }
283 a4f81979 bellard
    case SYS_READC:
284 a4f81979 bellard
       /* XXX: Read from debug cosole. Not implemented.  */
285 a4f81979 bellard
        return 0;
286 a4f81979 bellard
    case SYS_ISTTY:
287 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
288 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
289 a2d1ebaf pbrook
            return env->regs[0];
290 a2d1ebaf pbrook
        } else {
291 a2d1ebaf pbrook
            return isatty(ARG(0));
292 a2d1ebaf pbrook
        }
293 a4f81979 bellard
    case SYS_SEEK:
294 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
295 33d9cc8a pbrook
            gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
296 a2d1ebaf pbrook
            return env->regs[0];
297 a2d1ebaf pbrook
        } else {
298 a2d1ebaf pbrook
            ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
299 a2d1ebaf pbrook
            if (ret == (uint32_t)-1)
300 a2d1ebaf pbrook
              return -1;
301 a2d1ebaf pbrook
            return 0;
302 a2d1ebaf pbrook
        }
303 a4f81979 bellard
    case SYS_FLEN:
304 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
305 5fafdf24 ths
            gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
306 33d9cc8a pbrook
                           ARG(0), env->regs[13]-64);
307 33d9cc8a pbrook
            return env->regs[0];
308 a2d1ebaf pbrook
        } else {
309 a4f81979 bellard
            struct stat buf;
310 a4f81979 bellard
            ret = set_swi_errno(ts, fstat(ARG(0), &buf));
311 a4f81979 bellard
            if (ret == (uint32_t)-1)
312 a4f81979 bellard
                return -1;
313 a4f81979 bellard
            return buf.st_size;
314 a4f81979 bellard
        }
315 a4f81979 bellard
    case SYS_TMPNAM:
316 a4f81979 bellard
        /* XXX: Not implemented.  */
317 a4f81979 bellard
        return -1;
318 a4f81979 bellard
    case SYS_REMOVE:
319 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
320 33d9cc8a pbrook
            gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
321 a2d1ebaf pbrook
            ret = env->regs[0];
322 a2d1ebaf pbrook
        } else {
323 579a97f7 bellard
            if (!(s = lock_user_string(ARG(0))))
324 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
325 579a97f7 bellard
                return (uint32_t)-1;
326 a2d1ebaf pbrook
            ret =  set_swi_errno(ts, remove(s));
327 a2d1ebaf pbrook
            unlock_user(s, ARG(0), 0);
328 a2d1ebaf pbrook
        }
329 8e71621f pbrook
        return ret;
330 a4f81979 bellard
    case SYS_RENAME:
331 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
332 a2d1ebaf pbrook
            gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
333 33d9cc8a pbrook
                           ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
334 a2d1ebaf pbrook
            return env->regs[0];
335 a2d1ebaf pbrook
        } else {
336 8e71621f pbrook
            char *s2;
337 8e71621f pbrook
            s = lock_user_string(ARG(0));
338 8e71621f pbrook
            s2 = lock_user_string(ARG(2));
339 579a97f7 bellard
            if (!s || !s2)
340 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
341 579a97f7 bellard
                ret = (uint32_t)-1;
342 579a97f7 bellard
            else
343 579a97f7 bellard
                ret = set_swi_errno(ts, rename(s, s2));
344 579a97f7 bellard
            if (s2)
345 579a97f7 bellard
                unlock_user(s2, ARG(2), 0);
346 579a97f7 bellard
            if (s)
347 579a97f7 bellard
                unlock_user(s, ARG(0), 0);
348 8e71621f pbrook
            return ret;
349 8e71621f pbrook
        }
350 a4f81979 bellard
    case SYS_CLOCK:
351 a4f81979 bellard
        return clock() / (CLOCKS_PER_SEC / 100);
352 a4f81979 bellard
    case SYS_TIME:
353 a4f81979 bellard
        return set_swi_errno(ts, time(NULL));
354 a4f81979 bellard
    case SYS_SYSTEM:
355 a2d1ebaf pbrook
        if (use_gdb_syscalls()) {
356 33d9cc8a pbrook
            gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
357 a2d1ebaf pbrook
            return env->regs[0];
358 a2d1ebaf pbrook
        } else {
359 579a97f7 bellard
            if (!(s = lock_user_string(ARG(0))))
360 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
361 579a97f7 bellard
                return (uint32_t)-1;
362 a2d1ebaf pbrook
            ret = set_swi_errno(ts, system(s));
363 a2d1ebaf pbrook
            unlock_user(s, ARG(0), 0);
364 a982b531 ths
            return ret;
365 a2d1ebaf pbrook
        }
366 a4f81979 bellard
    case SYS_ERRNO:
367 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
368 a4f81979 bellard
        return ts->swi_errno;
369 8e71621f pbrook
#else
370 33d9cc8a pbrook
        return syscall_err;
371 8e71621f pbrook
#endif
372 a4f81979 bellard
    case SYS_GET_CMDLINE:
373 38d0662a pbrook
        {
374 1c1b40c1 Cédric VINCENT
            /* Build a command-line from the original argv.
375 1c1b40c1 Cédric VINCENT
             *
376 1c1b40c1 Cédric VINCENT
             * The inputs are:
377 1c1b40c1 Cédric VINCENT
             *     * ARG(0), pointer to a buffer of at least the size
378 1c1b40c1 Cédric VINCENT
             *               specified in ARG(1).
379 1c1b40c1 Cédric VINCENT
             *     * ARG(1), size of the buffer pointed to by ARG(0) in
380 1c1b40c1 Cédric VINCENT
             *               bytes.
381 1c1b40c1 Cédric VINCENT
             *
382 1c1b40c1 Cédric VINCENT
             * The outputs are:
383 1c1b40c1 Cédric VINCENT
             *     * ARG(0), pointer to null-terminated string of the
384 1c1b40c1 Cédric VINCENT
             *               command line.
385 1c1b40c1 Cédric VINCENT
             *     * ARG(1), length of the string pointed to by ARG(0).
386 1c1b40c1 Cédric VINCENT
             */
387 579a97f7 bellard
388 1c1b40c1 Cédric VINCENT
            char *output_buffer;
389 1c1b40c1 Cédric VINCENT
            size_t input_size = ARG(1);
390 1c1b40c1 Cédric VINCENT
            size_t output_size;
391 1c1b40c1 Cédric VINCENT
            int status = 0;
392 2e8785ac Wolfgang Schildbach
393 1c1b40c1 Cédric VINCENT
            /* Compute the size of the output string.  */
394 1c1b40c1 Cédric VINCENT
#if !defined(CONFIG_USER_ONLY)
395 1c1b40c1 Cédric VINCENT
            output_size = strlen(ts->boot_info->kernel_filename)
396 1c1b40c1 Cédric VINCENT
                        + 1  /* Separating space.  */
397 1c1b40c1 Cédric VINCENT
                        + strlen(ts->boot_info->kernel_cmdline)
398 1c1b40c1 Cédric VINCENT
                        + 1; /* Terminating null byte.  */
399 1c1b40c1 Cédric VINCENT
#else
400 1c1b40c1 Cédric VINCENT
            unsigned int i;
401 38d0662a pbrook
402 1c1b40c1 Cédric VINCENT
            output_size = ts->info->arg_end - ts->info->arg_start;
403 1c1b40c1 Cédric VINCENT
            if (!output_size) {
404 2e8785ac Wolfgang Schildbach
                /* We special-case the "empty command line" case (argc==0).
405 2e8785ac Wolfgang Schildbach
                   Just provide the terminating 0. */
406 1c1b40c1 Cédric VINCENT
                output_size = 1;
407 1c1b40c1 Cédric VINCENT
            }
408 1c1b40c1 Cédric VINCENT
#endif
409 38d0662a pbrook
410 1c1b40c1 Cédric VINCENT
            if (output_size > input_size) {
411 1c1b40c1 Cédric VINCENT
                 /* Not enough space to store command-line arguments.  */
412 1c1b40c1 Cédric VINCENT
                return -1;
413 38d0662a pbrook
            }
414 38d0662a pbrook
415 1c1b40c1 Cédric VINCENT
            /* Adjust the command-line length.  */
416 1c1b40c1 Cédric VINCENT
            SET_ARG(1, output_size - 1);
417 38d0662a pbrook
418 1c1b40c1 Cédric VINCENT
            /* Lock the buffer on the ARM side.  */
419 1c1b40c1 Cédric VINCENT
            output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0);
420 1c1b40c1 Cédric VINCENT
            if (!output_buffer) {
421 1c1b40c1 Cédric VINCENT
                return -1;
422 1c1b40c1 Cédric VINCENT
            }
423 38d0662a pbrook
424 1c1b40c1 Cédric VINCENT
            /* Copy the command-line arguments.  */
425 1c1b40c1 Cédric VINCENT
#if !defined(CONFIG_USER_ONLY)
426 1c1b40c1 Cédric VINCENT
            pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
427 1c1b40c1 Cédric VINCENT
            pstrcat(output_buffer, output_size, " ");
428 1c1b40c1 Cédric VINCENT
            pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
429 1c1b40c1 Cédric VINCENT
#else
430 1c1b40c1 Cédric VINCENT
            if (output_size == 1) {
431 1c1b40c1 Cédric VINCENT
                /* Empty command-line.  */
432 1c1b40c1 Cédric VINCENT
                output_buffer[0] = '\0';
433 1c1b40c1 Cédric VINCENT
                goto out;
434 1c1b40c1 Cédric VINCENT
            }
435 2e8785ac Wolfgang Schildbach
436 1c1b40c1 Cédric VINCENT
            if (copy_from_user(output_buffer, ts->info->arg_start,
437 1c1b40c1 Cédric VINCENT
                               output_size)) {
438 1c1b40c1 Cédric VINCENT
                status = -1;
439 1c1b40c1 Cédric VINCENT
                goto out;
440 2e8785ac Wolfgang Schildbach
            }
441 2e8785ac Wolfgang Schildbach
442 1c1b40c1 Cédric VINCENT
            /* Separate arguments by white spaces.  */
443 1c1b40c1 Cédric VINCENT
            for (i = 0; i < output_size - 1; i++) {
444 1c1b40c1 Cédric VINCENT
                if (output_buffer[i] == 0) {
445 1c1b40c1 Cédric VINCENT
                    output_buffer[i] = ' ';
446 1c1b40c1 Cédric VINCENT
                }
447 1c1b40c1 Cédric VINCENT
            }
448 1c1b40c1 Cédric VINCENT
        out:
449 1c1b40c1 Cédric VINCENT
#endif
450 1c1b40c1 Cédric VINCENT
            /* Unlock the buffer on the ARM side.  */
451 1c1b40c1 Cédric VINCENT
            unlock_user(output_buffer, ARG(0), output_size);
452 2e8785ac Wolfgang Schildbach
453 1c1b40c1 Cédric VINCENT
            return status;
454 38d0662a pbrook
        }
455 a4f81979 bellard
    case SYS_HEAPINFO:
456 a4f81979 bellard
        {
457 a4f81979 bellard
            uint32_t *ptr;
458 a4f81979 bellard
            uint32_t limit;
459 a4f81979 bellard
460 8e71621f pbrook
#ifdef CONFIG_USER_ONLY
461 8e71621f pbrook
            /* Some C libraries assume the heap immediately follows .bss, so
462 a4f81979 bellard
               allocate it using sbrk.  */
463 a4f81979 bellard
            if (!ts->heap_limit) {
464 206ae74a Peter Maydell
                abi_ulong ret;
465 a4f81979 bellard
466 53a5960a pbrook
                ts->heap_base = do_brk(0);
467 a4f81979 bellard
                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
468 a4f81979 bellard
                /* Try a big heap, and reduce the size if that fails.  */
469 a4f81979 bellard
                for (;;) {
470 53a5960a pbrook
                    ret = do_brk(limit);
471 206ae74a Peter Maydell
                    if (ret >= limit) {
472 a4f81979 bellard
                        break;
473 206ae74a Peter Maydell
                    }
474 a4f81979 bellard
                    limit = (ts->heap_base >> 1) + (limit >> 1);
475 a4f81979 bellard
                }
476 a4f81979 bellard
                ts->heap_limit = limit;
477 a4f81979 bellard
            }
478 3b46e624 ths
479 579a97f7 bellard
            if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
480 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
481 579a97f7 bellard
                return (uint32_t)-1;
482 a4f81979 bellard
            ptr[0] = tswap32(ts->heap_base);
483 a4f81979 bellard
            ptr[1] = tswap32(ts->heap_limit);
484 a4f81979 bellard
            ptr[2] = tswap32(ts->stack_base);
485 a4f81979 bellard
            ptr[3] = tswap32(0); /* Stack limit.  */
486 8e71621f pbrook
            unlock_user(ptr, ARG(0), 16);
487 8e71621f pbrook
#else
488 8e71621f pbrook
            limit = ram_size;
489 579a97f7 bellard
            if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
490 579a97f7 bellard
                /* FIXME - should this error code be -TARGET_EFAULT ? */
491 579a97f7 bellard
                return (uint32_t)-1;
492 8e71621f pbrook
            /* TODO: Make this use the limit of the loaded application.  */
493 8e71621f pbrook
            ptr[0] = tswap32(limit / 2);
494 8e71621f pbrook
            ptr[1] = tswap32(limit);
495 8e71621f pbrook
            ptr[2] = tswap32(limit); /* Stack base */
496 8e71621f pbrook
            ptr[3] = tswap32(0); /* Stack limit.  */
497 8e71621f pbrook
            unlock_user(ptr, ARG(0), 16);
498 8e71621f pbrook
#endif
499 a4f81979 bellard
            return 0;
500 a4f81979 bellard
        }
501 a4f81979 bellard
    case SYS_EXIT:
502 0e1c9c54 Paul Brook
        gdb_exit(env, 0);
503 a4f81979 bellard
        exit(0);
504 a4f81979 bellard
    default:
505 a4f81979 bellard
        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
506 a4f81979 bellard
        cpu_dump_state(env, stderr, fprintf, 0);
507 a4f81979 bellard
        abort();
508 a4f81979 bellard
    }
509 a4f81979 bellard
}