xref: /qemu/target/m68k/m68k-semi.c (revision 8caaae7319a5f7ca449900c0e6bfcaed78fa3ae2)
1a87295e8Spbrook /*
2a87295e8Spbrook  *  m68k/ColdFire Semihosting syscall interface
3a87295e8Spbrook  *
4a87295e8Spbrook  *  Copyright (c) 2005-2007 CodeSourcery.
5a87295e8Spbrook  *
6a87295e8Spbrook  *  This program is free software; you can redistribute it and/or modify
7a87295e8Spbrook  *  it under the terms of the GNU General Public License as published by
8a87295e8Spbrook  *  the Free Software Foundation; either version 2 of the License, or
9a87295e8Spbrook  *  (at your option) any later version.
10a87295e8Spbrook  *
11a87295e8Spbrook  *  This program is distributed in the hope that it will be useful,
12a87295e8Spbrook  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13a87295e8Spbrook  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14a87295e8Spbrook  *  GNU General Public License for more details.
15a87295e8Spbrook  *
16a87295e8Spbrook  *  You should have received a copy of the GNU General Public License
178167ee88SBlue Swirl  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18a87295e8Spbrook  */
19a87295e8Spbrook 
20d8416665SPeter Maydell #include "qemu/osdep.h"
21a87295e8Spbrook 
22a87295e8Spbrook #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"
2863c91552SPaolo Bonzini #include "qemu/log.h"
29a87295e8Spbrook 
30a87295e8Spbrook #define HOSTED_EXIT  0
31a87295e8Spbrook #define HOSTED_INIT_SIM 1
32a87295e8Spbrook #define HOSTED_OPEN 2
33a87295e8Spbrook #define HOSTED_CLOSE 3
34a87295e8Spbrook #define HOSTED_READ 4
35a87295e8Spbrook #define HOSTED_WRITE 5
36a87295e8Spbrook #define HOSTED_LSEEK 6
37a87295e8Spbrook #define HOSTED_RENAME 7
38a87295e8Spbrook #define HOSTED_UNLINK 8
39a87295e8Spbrook #define HOSTED_STAT 9
40a87295e8Spbrook #define HOSTED_FSTAT 10
41a87295e8Spbrook #define HOSTED_GETTIMEOFDAY 11
42a87295e8Spbrook #define HOSTED_ISATTY 12
43a87295e8Spbrook #define HOSTED_SYSTEM 13
44a87295e8Spbrook 
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)
751073bfd8SPeter Maydell {
76ab294b6cSRichard Henderson     M68kCPU *cpu = M68K_CPU(cs);
77ab294b6cSRichard Henderson     CPUM68KState *env = &cpu->env;
78ab294b6cSRichard Henderson 
791073bfd8SPeter Maydell     target_ulong args = env->dregs[1];
801073bfd8SPeter Maydell     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
841073bfd8SPeter Maydell          * error to the guest, so the best we can do is log it in qemu.
851073bfd8SPeter Maydell          * It is always a guest error not to pass us a valid argument block.
861073bfd8SPeter Maydell          */
871073bfd8SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value "
881073bfd8SPeter Maydell                       "discarded because argument block not writable\n");
891073bfd8SPeter Maydell     }
901073bfd8SPeter Maydell }
911073bfd8SPeter Maydell 
92ab294b6cSRichard Henderson static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
931073bfd8SPeter Maydell {
94ab294b6cSRichard Henderson     M68kCPU *cpu = M68K_CPU(cs);
95ab294b6cSRichard Henderson     CPUM68KState *env = &cpu->env;
96ab294b6cSRichard Henderson 
971073bfd8SPeter Maydell     target_ulong args = env->dregs[1];
981073bfd8SPeter Maydell     if (put_user_u32(ret >> 32, args) ||
991073bfd8SPeter Maydell         put_user_u32(ret, args + 4) ||
1007327e602SRichard Henderson         put_user_u32(host_to_gdb_errno(err), args + 8)) {
1011073bfd8SPeter Maydell         /* No way to report this via m68k semihosting ABI; just log it */
1021073bfd8SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value "
1031073bfd8SPeter Maydell                       "discarded because argument block not writable\n");
1041073bfd8SPeter Maydell     }
1051073bfd8SPeter Maydell }
1061073bfd8SPeter Maydell 
107808d77bcSLucien Murray-Pitts /*
108808d77bcSLucien Murray-Pitts  * Read the input value from the argument block; fail the semihosting
1097ba6c104SPeter Maydell  * call if the memory read fails.
1107ba6c104SPeter Maydell  */
1117ba6c104SPeter Maydell #define GET_ARG(n) do {                                 \
1127ba6c104SPeter Maydell     if (get_user_ual(arg ## n, args + (n) * 4)) {       \
1137ba6c104SPeter Maydell         goto failed;                                    \
1147ba6c104SPeter Maydell     }                                                   \
1157ba6c104SPeter Maydell } while (0)
1167ba6c104SPeter Maydell 
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 
124a87295e8Spbrook void do_m68k_semihosting(CPUM68KState *env, int nr)
125a87295e8Spbrook {
126ab294b6cSRichard Henderson     CPUState *cs = env_cpu(env);
127a87295e8Spbrook     uint32_t args;
1287ba6c104SPeter Maydell     target_ulong arg0, arg1, arg2, arg3;
129a87295e8Spbrook 
130a87295e8Spbrook     args = env->dregs[1];
131a87295e8Spbrook     switch (nr) {
132a87295e8Spbrook     case HOSTED_EXIT:
133ad9dcb20SAlex Bennée         gdb_exit(env->dregs[0]);
134a87295e8Spbrook         exit(env->dregs[0]);
13595027250SRichard Henderson 
136a87295e8Spbrook     case HOSTED_OPEN:
1377ba6c104SPeter Maydell         GET_ARG(0);
1387ba6c104SPeter Maydell         GET_ARG(1);
1397ba6c104SPeter Maydell         GET_ARG(2);
1407ba6c104SPeter Maydell         GET_ARG(3);
14195027250SRichard Henderson         semihost_sys_open(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3);
142a87295e8Spbrook         break;
14395027250SRichard Henderson 
144a87295e8Spbrook     case HOSTED_CLOSE:
1457ba6c104SPeter Maydell         GET_ARG(0);
14695027250SRichard Henderson         semihost_sys_close(cs, m68k_semi_u32_cb, arg0);
147a87295e8Spbrook         break;
14895027250SRichard Henderson 
149a87295e8Spbrook     case HOSTED_READ:
1507ba6c104SPeter Maydell         GET_ARG(0);
1517ba6c104SPeter Maydell         GET_ARG(1);
1527ba6c104SPeter Maydell         GET_ARG(2);
15395027250SRichard Henderson         semihost_sys_read(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
154a87295e8Spbrook         break;
15595027250SRichard Henderson 
156a87295e8Spbrook     case HOSTED_WRITE:
1577ba6c104SPeter Maydell         GET_ARG(0);
1587ba6c104SPeter Maydell         GET_ARG(1);
1597ba6c104SPeter Maydell         GET_ARG(2);
16095027250SRichard Henderson         semihost_sys_write(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
161a87295e8Spbrook         break;
16295027250SRichard Henderson 
163a87295e8Spbrook     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,
169*8caaae73SPeter Maydell                            deposit64(arg2, 32, 32, arg1), arg3);
17095027250SRichard Henderson         break;
17195027250SRichard Henderson 
172a87295e8Spbrook     case HOSTED_RENAME:
1737ba6c104SPeter Maydell         GET_ARG(0);
1747ba6c104SPeter Maydell         GET_ARG(1);
1757ba6c104SPeter Maydell         GET_ARG(2);
1767ba6c104SPeter Maydell         GET_ARG(3);
17795027250SRichard Henderson         semihost_sys_rename(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3);
178a87295e8Spbrook         break;
17995027250SRichard Henderson 
180a87295e8Spbrook     case HOSTED_UNLINK:
1817ba6c104SPeter Maydell         GET_ARG(0);
1827ba6c104SPeter Maydell         GET_ARG(1);
18395027250SRichard Henderson         semihost_sys_remove(cs, m68k_semi_u32_cb, arg0, arg1);
184a87295e8Spbrook         break;
18595027250SRichard Henderson 
186a87295e8Spbrook     case HOSTED_STAT:
1877ba6c104SPeter Maydell         GET_ARG(0);
1887ba6c104SPeter Maydell         GET_ARG(1);
1897ba6c104SPeter Maydell         GET_ARG(2);
19095027250SRichard Henderson         semihost_sys_stat(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
191a87295e8Spbrook         break;
19295027250SRichard Henderson 
193a87295e8Spbrook     case HOSTED_FSTAT:
1947ba6c104SPeter Maydell         GET_ARG(0);
1957ba6c104SPeter Maydell         GET_ARG(1);
19695027250SRichard Henderson         semihost_sys_fstat(cs, m68k_semi_u32_cb, arg0, arg1);
197a87295e8Spbrook         break;
19895027250SRichard Henderson 
199a87295e8Spbrook     case HOSTED_GETTIMEOFDAY:
2007ba6c104SPeter Maydell         GET_ARG(0);
2017ba6c104SPeter Maydell         GET_ARG(1);
20295027250SRichard Henderson         semihost_sys_gettimeofday(cs, m68k_semi_u32_cb, arg0, arg1);
203a87295e8Spbrook         break;
20495027250SRichard Henderson 
205a87295e8Spbrook     case HOSTED_ISATTY:
2067ba6c104SPeter Maydell         GET_ARG(0);
20795027250SRichard Henderson         semihost_sys_isatty(cs, m68k_semi_u32_cb, arg0);
208a87295e8Spbrook         break;
20995027250SRichard Henderson 
210a87295e8Spbrook     case HOSTED_SYSTEM:
2117ba6c104SPeter Maydell         GET_ARG(0);
2127ba6c104SPeter Maydell         GET_ARG(1);
21395027250SRichard Henderson         semihost_sys_system(cs, m68k_semi_u32_cb, arg0, arg1);
214a87295e8Spbrook         break;
21595027250SRichard Henderson 
216a87295e8Spbrook     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;
223a87295e8Spbrook         return;
22495027250SRichard Henderson 
225a87295e8Spbrook     default:
226a8d92fd8SRichard Henderson         cpu_abort(env_cpu(env), "Unsupported semihosting syscall %d\n", nr);
22795027250SRichard Henderson 
2287ba6c104SPeter Maydell     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     }
235a87295e8Spbrook }
236