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