]>
Commit | Line | Data |
---|---|---|
a87295e8 PB |
1 | /* |
2 | * m68k/ColdFire Semihosting syscall interface | |
5fafdf24 | 3 | * |
a87295e8 PB |
4 | * Copyright (c) 2005-2007 CodeSourcery. |
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 | |
8167ee88 | 17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
a87295e8 PB |
18 | */ |
19 | ||
d8416665 | 20 | #include "qemu/osdep.h" |
a87295e8 PB |
21 | |
22 | #include "cpu.h" | |
c566080c | 23 | #include "gdbstub/syscalls.h" |
4ea5fe99 | 24 | #include "gdbstub/helpers.h" |
95027250 | 25 | #include "semihosting/syscalls.h" |
c89a14ad | 26 | #include "semihosting/softmmu-uaccess.h" |
5601d241 | 27 | #include "hw/boards.h" |
63c91552 | 28 | #include "qemu/log.h" |
a87295e8 PB |
29 | |
30 | #define HOSTED_EXIT 0 | |
31 | #define HOSTED_INIT_SIM 1 | |
32 | #define HOSTED_OPEN 2 | |
33 | #define HOSTED_CLOSE 3 | |
34 | #define HOSTED_READ 4 | |
35 | #define HOSTED_WRITE 5 | |
36 | #define HOSTED_LSEEK 6 | |
37 | #define HOSTED_RENAME 7 | |
38 | #define HOSTED_UNLINK 8 | |
39 | #define HOSTED_STAT 9 | |
40 | #define HOSTED_FSTAT 10 | |
41 | #define HOSTED_GETTIMEOFDAY 11 | |
42 | #define HOSTED_ISATTY 12 | |
43 | #define HOSTED_SYSTEM 13 | |
44 | ||
7327e602 RH |
45 | static int host_to_gdb_errno(int err) |
46 | { | |
47 | #define E(X) case E##X: return GDB_E##X | |
48 | switch (err) { | |
49 | E(PERM); | |
50 | E(NOENT); | |
51 | E(INTR); | |
52 | E(BADF); | |
53 | E(ACCES); | |
54 | E(FAULT); | |
55 | E(BUSY); | |
56 | E(EXIST); | |
57 | E(NODEV); | |
58 | E(NOTDIR); | |
59 | E(ISDIR); | |
60 | E(INVAL); | |
61 | E(NFILE); | |
62 | E(MFILE); | |
63 | E(FBIG); | |
64 | E(NOSPC); | |
65 | E(SPIPE); | |
66 | E(ROFS); | |
67 | E(NAMETOOLONG); | |
68 | default: | |
69 | return GDB_EUNKNOWN; | |
70 | } | |
71 | #undef E | |
72 | } | |
73 | ||
ab294b6c | 74 | static void m68k_semi_u32_cb(CPUState *cs, uint64_t ret, int err) |
1073bfd8 | 75 | { |
ab294b6c RH |
76 | M68kCPU *cpu = M68K_CPU(cs); |
77 | CPUM68KState *env = &cpu->env; | |
78 | ||
1073bfd8 PM |
79 | target_ulong args = env->dregs[1]; |
80 | if (put_user_u32(ret, args) || | |
7327e602 | 81 | put_user_u32(host_to_gdb_errno(err), args + 4)) { |
808d77bc LMP |
82 | /* |
83 | * The m68k semihosting ABI does not provide any way to report this | |
1073bfd8 PM |
84 | * error to the guest, so the best we can do is log it in qemu. |
85 | * It is always a guest error not to pass us a valid argument block. | |
86 | */ | |
87 | qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value " | |
88 | "discarded because argument block not writable\n"); | |
89 | } | |
90 | } | |
91 | ||
ab294b6c | 92 | static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err) |
1073bfd8 | 93 | { |
ab294b6c RH |
94 | M68kCPU *cpu = M68K_CPU(cs); |
95 | CPUM68KState *env = &cpu->env; | |
96 | ||
1073bfd8 PM |
97 | target_ulong args = env->dregs[1]; |
98 | if (put_user_u32(ret >> 32, args) || | |
99 | put_user_u32(ret, args + 4) || | |
7327e602 | 100 | put_user_u32(host_to_gdb_errno(err), args + 8)) { |
1073bfd8 PM |
101 | /* No way to report this via m68k semihosting ABI; just log it */ |
102 | qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value " | |
103 | "discarded because argument block not writable\n"); | |
104 | } | |
105 | } | |
106 | ||
808d77bc LMP |
107 | /* |
108 | * Read the input value from the argument block; fail the semihosting | |
7ba6c104 PM |
109 | * call if the memory read fails. |
110 | */ | |
111 | #define GET_ARG(n) do { \ | |
112 | if (get_user_ual(arg ## n, args + (n) * 4)) { \ | |
7ba6c104 PM |
113 | goto failed; \ |
114 | } \ | |
115 | } while (0) | |
116 | ||
95027250 RH |
117 | #define GET_ARG64(n) do { \ |
118 | if (get_user_ual(arg ## n, args + (n) * 4)) { \ | |
119 | goto failed64; \ | |
120 | } \ | |
121 | } while (0) | |
122 | ||
123 | ||
a87295e8 PB |
124 | void do_m68k_semihosting(CPUM68KState *env, int nr) |
125 | { | |
ab294b6c | 126 | CPUState *cs = env_cpu(env); |
a87295e8 | 127 | uint32_t args; |
7ba6c104 | 128 | target_ulong arg0, arg1, arg2, arg3; |
a87295e8 PB |
129 | |
130 | args = env->dregs[1]; | |
131 | switch (nr) { | |
132 | case HOSTED_EXIT: | |
ad9dcb20 | 133 | gdb_exit(env->dregs[0]); |
a87295e8 | 134 | exit(env->dregs[0]); |
95027250 | 135 | |
a87295e8 | 136 | case HOSTED_OPEN: |
7ba6c104 PM |
137 | GET_ARG(0); |
138 | GET_ARG(1); | |
139 | GET_ARG(2); | |
140 | GET_ARG(3); | |
95027250 | 141 | semihost_sys_open(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3); |
a87295e8 | 142 | break; |
95027250 | 143 | |
a87295e8 | 144 | case HOSTED_CLOSE: |
95027250 RH |
145 | GET_ARG(0); |
146 | semihost_sys_close(cs, m68k_semi_u32_cb, arg0); | |
147 | break; | |
148 | ||
a87295e8 | 149 | case HOSTED_READ: |
7ba6c104 PM |
150 | GET_ARG(0); |
151 | GET_ARG(1); | |
152 | GET_ARG(2); | |
95027250 | 153 | semihost_sys_read(cs, m68k_semi_u32_cb, arg0, arg1, arg2); |
a87295e8 | 154 | break; |
95027250 | 155 | |
a87295e8 | 156 | case HOSTED_WRITE: |
7ba6c104 PM |
157 | GET_ARG(0); |
158 | GET_ARG(1); | |
159 | GET_ARG(2); | |
95027250 | 160 | semihost_sys_write(cs, m68k_semi_u32_cb, arg0, arg1, arg2); |
a87295e8 | 161 | break; |
95027250 | 162 | |
a87295e8 | 163 | case HOSTED_LSEEK: |
95027250 RH |
164 | GET_ARG64(0); |
165 | GET_ARG64(1); | |
166 | GET_ARG64(2); | |
167 | GET_ARG64(3); | |
168 | semihost_sys_lseek(cs, m68k_semi_u64_cb, arg0, | |
169 | deposit64(arg2, arg1, 32, 32), arg3); | |
170 | break; | |
171 | ||
a87295e8 | 172 | case HOSTED_RENAME: |
7ba6c104 PM |
173 | GET_ARG(0); |
174 | GET_ARG(1); | |
175 | GET_ARG(2); | |
176 | GET_ARG(3); | |
95027250 | 177 | semihost_sys_rename(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3); |
a87295e8 | 178 | break; |
95027250 | 179 | |
a87295e8 | 180 | case HOSTED_UNLINK: |
7ba6c104 PM |
181 | GET_ARG(0); |
182 | GET_ARG(1); | |
95027250 | 183 | semihost_sys_remove(cs, m68k_semi_u32_cb, arg0, arg1); |
a87295e8 | 184 | break; |
95027250 | 185 | |
a87295e8 | 186 | case HOSTED_STAT: |
7ba6c104 PM |
187 | GET_ARG(0); |
188 | GET_ARG(1); | |
189 | GET_ARG(2); | |
95027250 | 190 | semihost_sys_stat(cs, m68k_semi_u32_cb, arg0, arg1, arg2); |
a87295e8 | 191 | break; |
95027250 | 192 | |
a87295e8 | 193 | case HOSTED_FSTAT: |
7ba6c104 PM |
194 | GET_ARG(0); |
195 | GET_ARG(1); | |
95027250 | 196 | semihost_sys_fstat(cs, m68k_semi_u32_cb, arg0, arg1); |
a87295e8 | 197 | break; |
95027250 | 198 | |
a87295e8 | 199 | case HOSTED_GETTIMEOFDAY: |
7ba6c104 PM |
200 | GET_ARG(0); |
201 | GET_ARG(1); | |
95027250 | 202 | semihost_sys_gettimeofday(cs, m68k_semi_u32_cb, arg0, arg1); |
a87295e8 | 203 | break; |
95027250 | 204 | |
a87295e8 | 205 | case HOSTED_ISATTY: |
7ba6c104 | 206 | GET_ARG(0); |
95027250 | 207 | semihost_sys_isatty(cs, m68k_semi_u32_cb, arg0); |
a87295e8 | 208 | break; |
95027250 | 209 | |
a87295e8 | 210 | case HOSTED_SYSTEM: |
7ba6c104 PM |
211 | GET_ARG(0); |
212 | GET_ARG(1); | |
95027250 | 213 | semihost_sys_system(cs, m68k_semi_u32_cb, arg0, arg1); |
a87295e8 | 214 | break; |
95027250 | 215 | |
a87295e8 | 216 | case HOSTED_INIT_SIM: |
808d77bc LMP |
217 | /* |
218 | * FIXME: This is wrong for boards where RAM does not start at | |
219 | * address zero. | |
220 | */ | |
5601d241 PB |
221 | env->dregs[1] = current_machine->ram_size; |
222 | env->aregs[7] = current_machine->ram_size; | |
a87295e8 | 223 | return; |
95027250 | 224 | |
a87295e8 | 225 | default: |
a8d92fd8 | 226 | cpu_abort(env_cpu(env), "Unsupported semihosting syscall %d\n", nr); |
95027250 RH |
227 | |
228 | failed: | |
229 | m68k_semi_u32_cb(cs, -1, EFAULT); | |
230 | break; | |
231 | failed64: | |
232 | m68k_semi_u64_cb(cs, -1, EFAULT); | |
233 | break; | |
a87295e8 | 234 | } |
a87295e8 | 235 | } |