qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

m68k-semi.c (6256B)


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