0.7.0-alt1
[qemu] / qemu / linux-user / arm-semi.c
1 /*
2  *  Arm "Angel" semihosting syscalls
3  * 
4  *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <time.h>
28
29 #include "qemu.h"
30
31 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
32
33 #define SYS_OPEN        0x01
34 #define SYS_CLOSE       0x02
35 #define SYS_WRITEC      0x03
36 #define SYS_WRITE0      0x04
37 #define SYS_WRITE       0x05
38 #define SYS_READ        0x06
39 #define SYS_READC       0x07
40 #define SYS_ISTTY       0x09
41 #define SYS_SEEK        0x0a
42 #define SYS_FLEN        0x0c
43 #define SYS_TMPNAM      0x0d
44 #define SYS_REMOVE      0x0e
45 #define SYS_RENAME      0x0f
46 #define SYS_CLOCK       0x10
47 #define SYS_TIME        0x11
48 #define SYS_SYSTEM      0x12
49 #define SYS_ERRNO       0x13
50 #define SYS_GET_CMDLINE 0x15
51 #define SYS_HEAPINFO    0x16
52 #define SYS_EXIT        0x18
53
54 #ifndef O_BINARY
55 #define O_BINARY 0
56 #endif
57
58 int open_modeflags[12] = {
59     O_RDONLY,
60     O_RDONLY | O_BINARY,
61     O_RDWR,
62     O_RDWR | O_BINARY,
63     O_WRONLY | O_CREAT | O_TRUNC,
64     O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
65     O_RDWR | O_CREAT | O_TRUNC,
66     O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
67     O_WRONLY | O_CREAT | O_APPEND,
68     O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
69     O_RDWR | O_CREAT | O_APPEND,
70     O_RDWR | O_CREAT | O_APPEND | O_BINARY
71 };
72
73 static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
74 {
75   if (code == (uint32_t)-1)
76       ts->swi_errno = errno;
77   return code;
78 }
79
80 #define ARG(x) tswap32(args[x])
81 uint32_t do_arm_semihosting(CPUState *env)
82 {
83     uint32_t *args;
84     char * s;
85     int nr;
86     uint32_t ret;
87     TaskState *ts = env->opaque;
88
89     nr = env->regs[0];
90     args = (uint32_t *)env->regs[1];
91     switch (nr) {
92     case SYS_OPEN:
93         s = (char *)ARG(0);
94         if (ARG(1) >= 12)
95           return (uint32_t)-1;
96         if (strcmp(s, ":tt") == 0) {
97             if (ARG(1) < 4)
98                 return STDIN_FILENO;
99             else
100                 return STDOUT_FILENO;
101         }
102         return set_swi_errno(ts, open(s, open_modeflags[ARG(1)]));
103     case SYS_CLOSE:
104         return set_swi_errno(ts, close(ARG(0)));
105     case SYS_WRITEC:
106         /* Write to debug console.  stderr is near enough.  */
107         return write(STDERR_FILENO, args, 1);
108     case SYS_WRITE0:
109         s = (char *)args;
110         return write(STDERR_FILENO, s, strlen(s));
111     case SYS_WRITE:
112         ret = set_swi_errno(ts, write(ARG(0), (void *)ARG(1), ARG(2)));
113         if (ret == (uint32_t)-1)
114             return -1;
115         return ARG(2) - ret;
116     case SYS_READ:
117         ret = set_swi_errno(ts, read(ARG(0), (void *)ARG(1), ARG(2)));
118         if (ret == (uint32_t)-1)
119             return -1;
120         return ARG(2) - ret;
121     case SYS_READC:
122        /* XXX: Read from debug cosole. Not implemented.  */
123         return 0;
124     case SYS_ISTTY:
125         return isatty(ARG(0));
126     case SYS_SEEK:
127         ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
128         if (ret == (uint32_t)-1)
129           return -1;
130         return 0;
131     case SYS_FLEN:
132         {
133             struct stat buf;
134             ret = set_swi_errno(ts, fstat(ARG(0), &buf));
135             if (ret == (uint32_t)-1)
136                 return -1;
137             return buf.st_size;
138         }
139     case SYS_TMPNAM:
140         /* XXX: Not implemented.  */
141         return -1;
142     case SYS_REMOVE:
143         return set_swi_errno(ts, remove((char *)ARG(0)));
144     case SYS_RENAME:
145         return set_swi_errno(ts, rename((char *)ARG(0), (char *)ARG(2)));
146     case SYS_CLOCK:
147         return clock() / (CLOCKS_PER_SEC / 100);
148     case SYS_TIME:
149         return set_swi_errno(ts, time(NULL));
150     case SYS_SYSTEM:
151         return set_swi_errno(ts, system((char *)ARG(0)));
152     case SYS_ERRNO:
153         return ts->swi_errno;
154     case SYS_GET_CMDLINE:
155         /* XXX: Not implemented.  */
156         s = (char *)ARG(0);
157         *s = 0;
158         return -1;
159     case SYS_HEAPINFO:
160         {
161             uint32_t *ptr;
162             uint32_t limit;
163
164             /* Some C llibraries assume the heap immediately follows .bss, so
165                allocate it using sbrk.  */
166             if (!ts->heap_limit) {
167                 long ret;
168
169                 ts->heap_base = do_brk(NULL);
170                 limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
171                 /* Try a big heap, and reduce the size if that fails.  */
172                 for (;;) {
173                     ret = do_brk((char *)limit);
174                     if (ret != -1)
175                         break;
176                     limit = (ts->heap_base >> 1) + (limit >> 1);
177                 }
178                 ts->heap_limit = limit;
179             }
180               
181             ptr = (uint32_t *)tswap32(ARG(0));
182             ptr[0] = tswap32(ts->heap_base);
183             ptr[1] = tswap32(ts->heap_limit);
184             ptr[2] = tswap32(ts->stack_base);
185             ptr[3] = tswap32(0); /* Stack limit.  */
186             return 0;
187         }
188     case SYS_EXIT:
189         exit(0);
190     default:
191         fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
192         cpu_dump_state(env, stderr, fprintf, 0);
193         abort();
194     }
195 }
196