xref: /qemu/target/m68k/m68k-semi.c (revision c566080c)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  m68k/ColdFire Semihosting syscall interface
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2005-2007 CodeSourcery.
5fcf5ef2aSThomas Huth  *
6fcf5ef2aSThomas Huth  *  This program is free software; you can redistribute it and/or modify
7fcf5ef2aSThomas Huth  *  it under the terms of the GNU General Public License as published by
8fcf5ef2aSThomas Huth  *  the Free Software Foundation; either version 2 of the License, or
9fcf5ef2aSThomas Huth  *  (at your option) any later version.
10fcf5ef2aSThomas Huth  *
11fcf5ef2aSThomas Huth  *  This program is distributed in the hope that it will be useful,
12fcf5ef2aSThomas Huth  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13fcf5ef2aSThomas Huth  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14fcf5ef2aSThomas Huth  *  GNU General Public License for more details.
15fcf5ef2aSThomas Huth  *
16fcf5ef2aSThomas Huth  *  You should have received a copy of the GNU General Public License
17fcf5ef2aSThomas Huth  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18fcf5ef2aSThomas Huth  */
19fcf5ef2aSThomas Huth 
20fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21fcf5ef2aSThomas Huth 
22fcf5ef2aSThomas Huth #include "cpu.h"
23c566080cSAlex Bennée #include "gdbstub/syscalls.h"
244ea5fe99SAlex Bennée #include "gdbstub/helpers.h"
2595027250SRichard Henderson #include "semihosting/syscalls.h"
26c89a14adSRichard Henderson #include "semihosting/softmmu-uaccess.h"
275601d241SPaolo Bonzini #include "hw/boards.h"
28fcf5ef2aSThomas Huth #include "qemu/log.h"
29fcf5ef2aSThomas Huth 
30fcf5ef2aSThomas Huth #define HOSTED_EXIT  0
31fcf5ef2aSThomas Huth #define HOSTED_INIT_SIM 1
32fcf5ef2aSThomas Huth #define HOSTED_OPEN 2
33fcf5ef2aSThomas Huth #define HOSTED_CLOSE 3
34fcf5ef2aSThomas Huth #define HOSTED_READ 4
35fcf5ef2aSThomas Huth #define HOSTED_WRITE 5
36fcf5ef2aSThomas Huth #define HOSTED_LSEEK 6
37fcf5ef2aSThomas Huth #define HOSTED_RENAME 7
38fcf5ef2aSThomas Huth #define HOSTED_UNLINK 8
39fcf5ef2aSThomas Huth #define HOSTED_STAT 9
40fcf5ef2aSThomas Huth #define HOSTED_FSTAT 10
41fcf5ef2aSThomas Huth #define HOSTED_GETTIMEOFDAY 11
42fcf5ef2aSThomas Huth #define HOSTED_ISATTY 12
43fcf5ef2aSThomas Huth #define HOSTED_SYSTEM 13
44fcf5ef2aSThomas Huth 
457327e602SRichard Henderson static int host_to_gdb_errno(int err)
467327e602SRichard Henderson {
477327e602SRichard Henderson #define E(X)  case E##X: return GDB_E##X
487327e602SRichard Henderson     switch (err) {
497327e602SRichard Henderson     E(PERM);
507327e602SRichard Henderson     E(NOENT);
517327e602SRichard Henderson     E(INTR);
527327e602SRichard Henderson     E(BADF);
537327e602SRichard Henderson     E(ACCES);
547327e602SRichard Henderson     E(FAULT);
557327e602SRichard Henderson     E(BUSY);
567327e602SRichard Henderson     E(EXIST);
577327e602SRichard Henderson     E(NODEV);
587327e602SRichard Henderson     E(NOTDIR);
597327e602SRichard Henderson     E(ISDIR);
607327e602SRichard Henderson     E(INVAL);
617327e602SRichard Henderson     E(NFILE);
627327e602SRichard Henderson     E(MFILE);
637327e602SRichard Henderson     E(FBIG);
647327e602SRichard Henderson     E(NOSPC);
657327e602SRichard Henderson     E(SPIPE);
667327e602SRichard Henderson     E(ROFS);
677327e602SRichard Henderson     E(NAMETOOLONG);
687327e602SRichard Henderson     default:
697327e602SRichard Henderson         return GDB_EUNKNOWN;
707327e602SRichard Henderson     }
717327e602SRichard Henderson #undef E
727327e602SRichard Henderson }
737327e602SRichard Henderson 
74ab294b6cSRichard Henderson static void m68k_semi_u32_cb(CPUState *cs, uint64_t ret, int err)
75fcf5ef2aSThomas Huth {
76ab294b6cSRichard Henderson     M68kCPU *cpu = M68K_CPU(cs);
77ab294b6cSRichard Henderson     CPUM68KState *env = &cpu->env;
78ab294b6cSRichard Henderson 
79fcf5ef2aSThomas Huth     target_ulong args = env->dregs[1];
80fcf5ef2aSThomas Huth     if (put_user_u32(ret, args) ||
817327e602SRichard Henderson         put_user_u32(host_to_gdb_errno(err), args + 4)) {
82808d77bcSLucien Murray-Pitts         /*
83808d77bcSLucien Murray-Pitts          * The m68k semihosting ABI does not provide any way to report this
84fcf5ef2aSThomas Huth          * error to the guest, so the best we can do is log it in qemu.
85fcf5ef2aSThomas Huth          * It is always a guest error not to pass us a valid argument block.
86fcf5ef2aSThomas Huth          */
87fcf5ef2aSThomas Huth         qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value "
88fcf5ef2aSThomas Huth                       "discarded because argument block not writable\n");
89fcf5ef2aSThomas Huth     }
90fcf5ef2aSThomas Huth }
91fcf5ef2aSThomas Huth 
92ab294b6cSRichard Henderson static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
93fcf5ef2aSThomas Huth {
94ab294b6cSRichard Henderson     M68kCPU *cpu = M68K_CPU(cs);
95ab294b6cSRichard Henderson     CPUM68KState *env = &cpu->env;
96ab294b6cSRichard Henderson 
97fcf5ef2aSThomas Huth     target_ulong args = env->dregs[1];
98fcf5ef2aSThomas Huth     if (put_user_u32(ret >> 32, args) ||
99fcf5ef2aSThomas Huth         put_user_u32(ret, args + 4) ||
1007327e602SRichard Henderson         put_user_u32(host_to_gdb_errno(err), args + 8)) {
101fcf5ef2aSThomas Huth         /* No way to report this via m68k semihosting ABI; just log it */
102fcf5ef2aSThomas Huth         qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value "
103fcf5ef2aSThomas Huth                       "discarded because argument block not writable\n");
104fcf5ef2aSThomas Huth     }
105fcf5ef2aSThomas Huth }
106fcf5ef2aSThomas Huth 
107808d77bcSLucien Murray-Pitts /*
108808d77bcSLucien Murray-Pitts  * Read the input value from the argument block; fail the semihosting
109fcf5ef2aSThomas Huth  * call if the memory read fails.
110fcf5ef2aSThomas Huth  */
111fcf5ef2aSThomas Huth #define GET_ARG(n) do {                                 \
112fcf5ef2aSThomas Huth     if (get_user_ual(arg ## n, args + (n) * 4)) {       \
113fcf5ef2aSThomas Huth         goto failed;                                    \
114fcf5ef2aSThomas Huth     }                                                   \
115fcf5ef2aSThomas Huth } while (0)
116fcf5ef2aSThomas Huth 
11795027250SRichard Henderson #define GET_ARG64(n) do {                               \
11895027250SRichard Henderson     if (get_user_ual(arg ## n, args + (n) * 4)) {       \
11995027250SRichard Henderson         goto failed64;                                  \
12095027250SRichard Henderson     }                                                   \
12195027250SRichard Henderson } while (0)
12295027250SRichard Henderson 
12395027250SRichard Henderson 
124fcf5ef2aSThomas Huth void do_m68k_semihosting(CPUM68KState *env, int nr)
125fcf5ef2aSThomas Huth {
126ab294b6cSRichard Henderson     CPUState *cs = env_cpu(env);
127fcf5ef2aSThomas Huth     uint32_t args;
128fcf5ef2aSThomas Huth     target_ulong arg0, arg1, arg2, arg3;
129fcf5ef2aSThomas Huth 
130fcf5ef2aSThomas Huth     args = env->dregs[1];
131fcf5ef2aSThomas Huth     switch (nr) {
132fcf5ef2aSThomas Huth     case HOSTED_EXIT:
133ad9dcb20SAlex Bennée         gdb_exit(env->dregs[0]);
134fcf5ef2aSThomas Huth         exit(env->dregs[0]);
13595027250SRichard Henderson 
136fcf5ef2aSThomas Huth     case HOSTED_OPEN:
137fcf5ef2aSThomas Huth         GET_ARG(0);
138fcf5ef2aSThomas Huth         GET_ARG(1);
139fcf5ef2aSThomas Huth         GET_ARG(2);
140fcf5ef2aSThomas Huth         GET_ARG(3);
14195027250SRichard Henderson         semihost_sys_open(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3);
142fcf5ef2aSThomas Huth         break;
14395027250SRichard Henderson 
144fcf5ef2aSThomas Huth     case HOSTED_CLOSE:
145fcf5ef2aSThomas Huth         GET_ARG(0);
14695027250SRichard Henderson         semihost_sys_close(cs, m68k_semi_u32_cb, arg0);
147fcf5ef2aSThomas Huth         break;
14895027250SRichard Henderson 
149fcf5ef2aSThomas Huth     case HOSTED_READ:
150fcf5ef2aSThomas Huth         GET_ARG(0);
151fcf5ef2aSThomas Huth         GET_ARG(1);
152fcf5ef2aSThomas Huth         GET_ARG(2);
15395027250SRichard Henderson         semihost_sys_read(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
154fcf5ef2aSThomas Huth         break;
15595027250SRichard Henderson 
156fcf5ef2aSThomas Huth     case HOSTED_WRITE:
157fcf5ef2aSThomas Huth         GET_ARG(0);
158fcf5ef2aSThomas Huth         GET_ARG(1);
159fcf5ef2aSThomas Huth         GET_ARG(2);
16095027250SRichard Henderson         semihost_sys_write(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
161fcf5ef2aSThomas Huth         break;
16295027250SRichard Henderson 
163fcf5ef2aSThomas Huth     case HOSTED_LSEEK:
16495027250SRichard Henderson         GET_ARG64(0);
16595027250SRichard Henderson         GET_ARG64(1);
16695027250SRichard Henderson         GET_ARG64(2);
16795027250SRichard Henderson         GET_ARG64(3);
16895027250SRichard Henderson         semihost_sys_lseek(cs, m68k_semi_u64_cb, arg0,
16995027250SRichard Henderson                            deposit64(arg2, arg1, 32, 32), arg3);
17095027250SRichard Henderson         break;
17195027250SRichard Henderson 
172fcf5ef2aSThomas Huth     case HOSTED_RENAME:
173fcf5ef2aSThomas Huth         GET_ARG(0);
174fcf5ef2aSThomas Huth         GET_ARG(1);
175fcf5ef2aSThomas Huth         GET_ARG(2);
176fcf5ef2aSThomas Huth         GET_ARG(3);
17795027250SRichard Henderson         semihost_sys_rename(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3);
178fcf5ef2aSThomas Huth         break;
17995027250SRichard Henderson 
180fcf5ef2aSThomas Huth     case HOSTED_UNLINK:
181fcf5ef2aSThomas Huth         GET_ARG(0);
182fcf5ef2aSThomas Huth         GET_ARG(1);
18395027250SRichard Henderson         semihost_sys_remove(cs, m68k_semi_u32_cb, arg0, arg1);
184fcf5ef2aSThomas Huth         break;
18595027250SRichard Henderson 
186fcf5ef2aSThomas Huth     case HOSTED_STAT:
187fcf5ef2aSThomas Huth         GET_ARG(0);
188fcf5ef2aSThomas Huth         GET_ARG(1);
189fcf5ef2aSThomas Huth         GET_ARG(2);
19095027250SRichard Henderson         semihost_sys_stat(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
191fcf5ef2aSThomas Huth         break;
19295027250SRichard Henderson 
193fcf5ef2aSThomas Huth     case HOSTED_FSTAT:
194fcf5ef2aSThomas Huth         GET_ARG(0);
195fcf5ef2aSThomas Huth         GET_ARG(1);
19695027250SRichard Henderson         semihost_sys_fstat(cs, m68k_semi_u32_cb, arg0, arg1);
197fcf5ef2aSThomas Huth         break;
19895027250SRichard Henderson 
199fcf5ef2aSThomas Huth     case HOSTED_GETTIMEOFDAY:
200fcf5ef2aSThomas Huth         GET_ARG(0);
201fcf5ef2aSThomas Huth         GET_ARG(1);
20295027250SRichard Henderson         semihost_sys_gettimeofday(cs, m68k_semi_u32_cb, arg0, arg1);
203fcf5ef2aSThomas Huth         break;
20495027250SRichard Henderson 
205fcf5ef2aSThomas Huth     case HOSTED_ISATTY:
206fcf5ef2aSThomas Huth         GET_ARG(0);
20795027250SRichard Henderson         semihost_sys_isatty(cs, m68k_semi_u32_cb, arg0);
208fcf5ef2aSThomas Huth         break;
20995027250SRichard Henderson 
210fcf5ef2aSThomas Huth     case HOSTED_SYSTEM:
211fcf5ef2aSThomas Huth         GET_ARG(0);
212fcf5ef2aSThomas Huth         GET_ARG(1);
21395027250SRichard Henderson         semihost_sys_system(cs, m68k_semi_u32_cb, arg0, arg1);
214fcf5ef2aSThomas Huth         break;
21595027250SRichard Henderson 
216fcf5ef2aSThomas Huth     case HOSTED_INIT_SIM:
217808d77bcSLucien Murray-Pitts         /*
218808d77bcSLucien Murray-Pitts          * FIXME: This is wrong for boards where RAM does not start at
219808d77bcSLucien Murray-Pitts          * address zero.
220808d77bcSLucien Murray-Pitts          */
2215601d241SPaolo Bonzini         env->dregs[1] = current_machine->ram_size;
2225601d241SPaolo Bonzini         env->aregs[7] = current_machine->ram_size;
223fcf5ef2aSThomas Huth         return;
22495027250SRichard Henderson 
225fcf5ef2aSThomas Huth     default:
226a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env), "Unsupported semihosting syscall %d\n", nr);
22795027250SRichard Henderson 
228fcf5ef2aSThomas Huth     failed:
22995027250SRichard Henderson         m68k_semi_u32_cb(cs, -1, EFAULT);
23095027250SRichard Henderson         break;
23195027250SRichard Henderson     failed64:
23295027250SRichard Henderson         m68k_semi_u64_cb(cs, -1, EFAULT);
23395027250SRichard Henderson         break;
23495027250SRichard Henderson     }
235fcf5ef2aSThomas Huth }
236