Move the MIPS CPU timer in a seperate file, by Alec Voropay.
[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(n) tget32(args + (n) * 4)
81 #define SET_ARG(n, val) tput32(args + (n) * 4,val)
82 uint32_t do_arm_semihosting(CPUState *env)
83 {
84     target_ulong args;
85     char * s;
86     int nr;
87     uint32_t ret;
88     TaskState *ts = env->opaque;
89
90     nr = env->regs[0];
91     args = env->regs[1];
92     switch (nr) {
93     case SYS_OPEN:
94         s = (char *)g2h(ARG(0));
95         if (ARG(1) >= 12)
96           return (uint32_t)-1;
97         if (strcmp(s, ":tt") == 0) {
98             if (ARG(1) < 4)
99                 return STDIN_FILENO;
100             else
101                 return STDOUT_FILENO;
102         }
103         return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
104     case SYS_CLOSE:
105         return set_swi_errno(ts, close(ARG(0)));
106     case SYS_WRITEC:
107         {
108           char c = tget8(args);
109           /* Write to debug console.  stderr is near enough.  */
110           return write(STDERR_FILENO, &c, 1);
111         }
112     case SYS_WRITE0:
113         s = lock_user_string(args);
114         ret = write(STDERR_FILENO, s, strlen(s));
115         unlock_user(s, args, 0);
116         return ret;
117     case SYS_WRITE:
118         ret = set_swi_errno(ts, write(ARG(0), g2h(ARG(1)), ARG(2)));
119         if (ret == (uint32_t)-1)
120             return -1;
121         return ARG(2) - ret;
122     case SYS_READ:
123         ret = set_swi_errno(ts, read(ARG(0), g2h(ARG(1)), ARG(2)));
124         if (ret == (uint32_t)-1)
125             return -1;
126         return ARG(2) - ret;
127     case SYS_READC:
128        /* XXX: Read from debug cosole. Not implemented.  */
129         return 0;
130     case SYS_ISTTY:
131         return isatty(ARG(0));
132     case SYS_SEEK:
133         ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
134         if (ret == (uint32_t)-1)
135           return -1;
136         return 0;
137     case SYS_FLEN:
138         {
139             struct stat buf;
140             ret = set_swi_errno(ts, fstat(ARG(0), &buf));
141             if (ret == (uint32_t)-1)
142                 return -1;
143             return buf.st_size;
144         }
145     case SYS_TMPNAM:
146         /* XXX: Not implemented.  */
147         return -1;
148     case SYS_REMOVE:
149         return set_swi_errno(ts, remove((char *)g2h(ARG(0))));
150     case SYS_RENAME:
151         return set_swi_errno(ts, rename((char *)g2h(ARG(0)),
152                              (char *)g2h(ARG(2))));
153     case SYS_CLOCK:
154         return clock() / (CLOCKS_PER_SEC / 100);
155     case SYS_TIME:
156         return set_swi_errno(ts, time(NULL));
157     case SYS_SYSTEM:
158         return set_swi_errno(ts, system((char *)g2h(ARG(0))));
159     case SYS_ERRNO:
160         return ts->swi_errno;
161     case SYS_GET_CMDLINE:
162         /* Build a commandline from the original argv.  */
163         {
164             char **arg = ts->info->host_argv;
165             int len = ARG(1);
166             /* lock the buffer on the ARM side */
167             char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0);
168
169             s = cmdline_buffer;
170             while (*arg && len > 2) {
171                 int n = strlen(*arg);
172
173                 if (s != cmdline_buffer) {
174                     *(s++) = ' ';
175                     len--;
176                 }
177                 if (n >= len)
178                     n = len - 1;
179                 memcpy(s, *arg, n);
180                 s += n;
181                 len -= n;
182                 arg++;
183             }
184             /* Null terminate the string.  */
185             *s = 0;
186             len = s - cmdline_buffer;
187
188             /* Unlock the buffer on the ARM side.  */
189             unlock_user(cmdline_buffer, ARG(0), len);
190
191             /* Adjust the commandline length argument.  */
192             SET_ARG(1, len);
193
194             /* Return success if commandline fit into buffer.  */
195             return *arg ? -1 : 0;
196         }
197     case SYS_HEAPINFO:
198         {
199             uint32_t *ptr;
200             uint32_t limit;
201
202             /* Some C llibraries assume the heap immediately follows .bss, so
203                allocate it using sbrk.  */
204             if (!ts->heap_limit) {
205                 long ret;
206
207                 ts->heap_base = do_brk(0);
208                 limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
209                 /* Try a big heap, and reduce the size if that fails.  */
210                 for (;;) {
211                     ret = do_brk(limit);
212                     if (ret != -1)
213                         break;
214                     limit = (ts->heap_base >> 1) + (limit >> 1);
215                 }
216                 ts->heap_limit = limit;
217             }
218               
219             page_unprotect_range (ARG(0), 32);
220             ptr = (uint32_t *)g2h(ARG(0));
221             ptr[0] = tswap32(ts->heap_base);
222             ptr[1] = tswap32(ts->heap_limit);
223             ptr[2] = tswap32(ts->stack_base);
224             ptr[3] = tswap32(0); /* Stack limit.  */
225             return 0;
226         }
227     case SYS_EXIT:
228         exit(0);
229     default:
230         fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
231         cpu_dump_state(env, stderr, fprintf, 0);
232         abort();
233     }
234 }
235