File:  [Qemu by Fabrice Bellard] / qemu / m68k-semi.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:50:21 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

    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, write to the Free Software
   18:  *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   19:  *  MA 02110-1301, USA.
   20:  */
   21: 
   22: #include <sys/types.h>
   23: #include <sys/stat.h>
   24: #include <errno.h>
   25: #include <fcntl.h>
   26: #include <unistd.h>
   27: #include <stdlib.h>
   28: #include <stdio.h>
   29: #include <sys/time.h>
   30: #include <time.h>
   31: 
   32: #include "cpu.h"
   33: #if defined(CONFIG_USER_ONLY)
   34: #include "qemu.h"
   35: #define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
   36: #else
   37: #include "qemu-common.h"
   38: #include "sysemu.h"
   39: #include "gdbstub.h"
   40: #include "softmmu-semi.h"
   41: #endif
   42: 
   43: #define HOSTED_EXIT  0
   44: #define HOSTED_INIT_SIM 1
   45: #define HOSTED_OPEN 2
   46: #define HOSTED_CLOSE 3
   47: #define HOSTED_READ 4
   48: #define HOSTED_WRITE 5
   49: #define HOSTED_LSEEK 6
   50: #define HOSTED_RENAME 7
   51: #define HOSTED_UNLINK 8
   52: #define HOSTED_STAT 9
   53: #define HOSTED_FSTAT 10
   54: #define HOSTED_GETTIMEOFDAY 11
   55: #define HOSTED_ISATTY 12
   56: #define HOSTED_SYSTEM 13
   57: 
   58: typedef uint32_t gdb_mode_t;
   59: typedef uint32_t gdb_time_t;
   60: 
   61: struct m68k_gdb_stat {
   62:   uint32_t    gdb_st_dev;     /* device */
   63:   uint32_t    gdb_st_ino;     /* inode */
   64:   gdb_mode_t  gdb_st_mode;    /* protection */
   65:   uint32_t    gdb_st_nlink;   /* number of hard links */
   66:   uint32_t    gdb_st_uid;     /* user ID of owner */
   67:   uint32_t    gdb_st_gid;     /* group ID of owner */
   68:   uint32_t    gdb_st_rdev;    /* device type (if inode device) */
   69:   uint64_t    gdb_st_size;    /* total size, in bytes */
   70:   uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
   71:   uint64_t    gdb_st_blocks;  /* number of blocks allocated */
   72:   gdb_time_t  gdb_st_atime;   /* time of last access */
   73:   gdb_time_t  gdb_st_mtime;   /* time of last modification */
   74:   gdb_time_t  gdb_st_ctime;   /* time of last change */
   75: } __attribute__((packed));
   76: 
   77: struct gdb_timeval {
   78:   gdb_time_t tv_sec;  /* second */
   79:   uint64_t tv_usec;   /* microsecond */
   80: } __attribute__((packed));
   81: 
   82: #define GDB_O_RDONLY   0x0
   83: #define GDB_O_WRONLY   0x1
   84: #define GDB_O_RDWR     0x2
   85: #define GDB_O_APPEND   0x8
   86: #define GDB_O_CREAT  0x200
   87: #define GDB_O_TRUNC  0x400
   88: #define GDB_O_EXCL   0x800
   89: 
   90: static int translate_openflags(int flags)
   91: {
   92:     int hf;
   93: 
   94:     if (flags & GDB_O_WRONLY)
   95:         hf = O_WRONLY;
   96:     else if (flags & GDB_O_RDWR)
   97:         hf = O_RDWR;
   98:     else
   99:         hf = O_RDONLY;
  100: 
  101:     if (flags & GDB_O_APPEND) hf |= O_APPEND;
  102:     if (flags & GDB_O_CREAT) hf |= O_CREAT;
  103:     if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
  104:     if (flags & GDB_O_EXCL) hf |= O_EXCL;
  105: 
  106:     return hf;
  107: }
  108: 
  109: static void translate_stat(CPUState *env, target_ulong addr, struct stat *s)
  110: {
  111:     struct m68k_gdb_stat *p;
  112: 
  113:     if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0)))
  114:         /* FIXME - should this return an error code? */
  115:         return;
  116:     p->gdb_st_dev = cpu_to_be32(s->st_dev);
  117:     p->gdb_st_ino = cpu_to_be32(s->st_ino);
  118:     p->gdb_st_mode = cpu_to_be32(s->st_mode);
  119:     p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
  120:     p->gdb_st_uid = cpu_to_be32(s->st_uid);
  121:     p->gdb_st_gid = cpu_to_be32(s->st_gid);
  122:     p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
  123:     p->gdb_st_size = cpu_to_be64(s->st_size);
  124: #ifdef _WIN32
  125:     /* Windows stat is missing some fields.  */
  126:     p->gdb_st_blksize = 0;
  127:     p->gdb_st_blocks = 0;
  128: #else
  129:     p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
  130:     p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
  131: #endif
  132:     p->gdb_st_atime = cpu_to_be32(s->st_atime);
  133:     p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
  134:     p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
  135:     unlock_user(p, addr, sizeof(struct m68k_gdb_stat));
  136: }
  137: 
  138: static int m68k_semi_is_fseek;
  139: 
  140: static void m68k_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
  141: {
  142:     target_ulong args;
  143: 
  144:     args = env->dregs[1];
  145:     if (m68k_semi_is_fseek) {
  146:         /* FIXME: We've already lost the high bits of the fseek
  147:            return value.  */
  148:         /* FIXME - handle put_user() failure */
  149:         put_user_u32(0, args);
  150:         args += 4;
  151:         m68k_semi_is_fseek = 0;
  152:     }
  153:     /* FIXME - handle put_user() failure */
  154:     put_user_u32(ret, args);
  155:     put_user_u32(errno, args + 4);
  156: }
  157: 
  158: #define ARG(n)					\
  159: ({						\
  160:     target_ulong __arg;				\
  161:     /* FIXME - handle get_user() failure */	\
  162:     get_user_ual(__arg, args + (n) * 4);	\
  163:     __arg;					\
  164: })
  165: #define PARG(x) ((unsigned long)ARG(x))
  166: void do_m68k_semihosting(CPUM68KState *env, int nr)
  167: {
  168:     uint32_t args;
  169:     void *p;
  170:     void *q;
  171:     uint32_t len;
  172:     uint32_t result;
  173: 
  174:     args = env->dregs[1];
  175:     switch (nr) {
  176:     case HOSTED_EXIT:
  177:         exit(env->dregs[0]);
  178:     case HOSTED_OPEN:
  179:         if (use_gdb_syscalls()) {
  180:             gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", ARG(0), (int)ARG(1),
  181:                            ARG(2), ARG(3));
  182:             return;
  183:         } else {
  184:             if (!(p = lock_user_string(ARG(0)))) {
  185:                 /* FIXME - check error code? */
  186:                 result = -1;
  187:             } else {
  188:                 result = open(p, translate_openflags(ARG(2)), ARG(3));
  189:                 unlock_user(p, ARG(0), 0);
  190:             }
  191:         }
  192:         break;
  193:     case HOSTED_CLOSE:
  194:         {
  195:             /* Ignore attempts to close stdin/out/err.  */
  196:             int fd = ARG(0);
  197:             if (fd > 2) {
  198:                 if (use_gdb_syscalls()) {
  199:                     gdb_do_syscall(m68k_semi_cb, "close,%x", ARG(0));
  200:                     return;
  201:                 } else {
  202:                     result = close(fd);
  203:                 }
  204:             } else {
  205:                 result = 0;
  206:             }
  207:             break;
  208:         }
  209:     case HOSTED_READ:
  210:         len = ARG(2);
  211:         if (use_gdb_syscalls()) {
  212:             gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x",
  213:                            ARG(0), ARG(1), len);
  214:             return;
  215:         } else {
  216:             if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) {
  217:                 /* FIXME - check error code? */
  218:                 result = -1;
  219:             } else {
  220:                 result = read(ARG(0), p, len);
  221:                 unlock_user(p, ARG(1), len);
  222:             }
  223:         }
  224:         break;
  225:     case HOSTED_WRITE:
  226:         len = ARG(2);
  227:         if (use_gdb_syscalls()) {
  228:             gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x",
  229:                            ARG(0), ARG(1), len);
  230:             return;
  231:         } else {
  232:             if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) {
  233:                 /* FIXME - check error code? */
  234:                 result = -1;
  235:             } else {
  236:                 result = write(ARG(0), p, len);
  237:                 unlock_user(p, ARG(0), 0);
  238:             }
  239:         }
  240:         break;
  241:     case HOSTED_LSEEK:
  242:         {
  243:             uint64_t off;
  244:             off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32);
  245:             if (use_gdb_syscalls()) {
  246:                 m68k_semi_is_fseek = 1;
  247:                 gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x",
  248:                                ARG(0), off, ARG(3));
  249:             } else {
  250:                 off = lseek(ARG(0), off, ARG(3));
  251:                 /* FIXME - handle put_user() failure */
  252:                 put_user_u32(off >> 32, args);
  253:                 put_user_u32(off, args + 4);
  254:                 put_user_u32(errno, args + 8);
  255:             }
  256:             return;
  257:         }
  258:     case HOSTED_RENAME:
  259:         if (use_gdb_syscalls()) {
  260:             gdb_do_syscall(m68k_semi_cb, "rename,%s,%s",
  261:                            ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
  262:             return;
  263:         } else {
  264:             p = lock_user_string(ARG(0));
  265:             q = lock_user_string(ARG(2));
  266:             if (!p || !q) {
  267:                 /* FIXME - check error code? */
  268:                 result = -1;
  269:             } else {
  270:                 result = rename(p, q);
  271:             }
  272:             unlock_user(p, ARG(0), 0);
  273:             unlock_user(q, ARG(2), 0);
  274:         }
  275:         break;
  276:     case HOSTED_UNLINK:
  277:         if (use_gdb_syscalls()) {
  278:             gdb_do_syscall(m68k_semi_cb, "unlink,%s",
  279:                            ARG(0), (int)ARG(1));
  280:             return;
  281:         } else {
  282:             if (!(p = lock_user_string(ARG(0)))) {
  283:                 /* FIXME - check error code? */
  284:                 result = -1;
  285:             } else {
  286:                 result = unlink(p);
  287:                 unlock_user(p, ARG(0), 0);
  288:             }
  289:         }
  290:         break;
  291:     case HOSTED_STAT:
  292:         if (use_gdb_syscalls()) {
  293:             gdb_do_syscall(m68k_semi_cb, "stat,%s,%x",
  294:                            ARG(0), (int)ARG(1), ARG(2));
  295:             return;
  296:         } else {
  297:             struct stat s;
  298:             if (!(p = lock_user_string(ARG(0)))) {
  299:                 /* FIXME - check error code? */
  300:                 result = -1;
  301:             } else {
  302:                 result = stat(p, &s);
  303:                 unlock_user(p, ARG(0), 0);
  304:             }
  305:             if (result == 0) {
  306:                 translate_stat(env, ARG(2), &s);
  307:             }
  308:         }
  309:         break;
  310:     case HOSTED_FSTAT:
  311:         if (use_gdb_syscalls()) {
  312:             gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x",
  313:                            ARG(0), ARG(1));
  314:             return;
  315:         } else {
  316:             struct stat s;
  317:             result = fstat(ARG(0), &s);
  318:             if (result == 0) {
  319:                 translate_stat(env, ARG(1), &s);
  320:             }
  321:         }
  322:         break;
  323:     case HOSTED_GETTIMEOFDAY:
  324:         if (use_gdb_syscalls()) {
  325:             gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x",
  326:                            ARG(0), ARG(1));
  327:             return;
  328:         } else {
  329:             qemu_timeval tv;
  330:             struct gdb_timeval *p;
  331:             result = qemu_gettimeofday(&tv);
  332:             if (result != 0) {
  333:                 if (!(p = lock_user(VERIFY_WRITE,
  334:                                     ARG(0), sizeof(struct gdb_timeval), 0))) {
  335:                     /* FIXME - check error code? */
  336:                     result = -1;
  337:                 } else {
  338:                     p->tv_sec = cpu_to_be32(tv.tv_sec);
  339:                     p->tv_usec = cpu_to_be64(tv.tv_usec);
  340:                     unlock_user(p, ARG(0), sizeof(struct gdb_timeval));
  341:                 }
  342:             }
  343:         }
  344:         break;
  345:     case HOSTED_ISATTY:
  346:         if (use_gdb_syscalls()) {
  347:             gdb_do_syscall(m68k_semi_cb, "isatty,%x", ARG(0));
  348:             return;
  349:         } else {
  350:             result = isatty(ARG(0));
  351:         }
  352:         break;
  353:     case HOSTED_SYSTEM:
  354:         if (use_gdb_syscalls()) {
  355:             gdb_do_syscall(m68k_semi_cb, "system,%s",
  356:                            ARG(0), (int)ARG(1));
  357:             return;
  358:         } else {
  359:             if (!(p = lock_user_string(ARG(0)))) {
  360:                 /* FIXME - check error code? */
  361:                 result = -1;
  362:             } else {
  363:                 result = system(p);
  364:                 unlock_user(p, ARG(0), 0);
  365:             }
  366:         }
  367:         break;
  368:     case HOSTED_INIT_SIM:
  369: #if defined(CONFIG_USER_ONLY)
  370:         {
  371:         TaskState *ts = env->opaque;
  372:         /* Allocate the heap using sbrk.  */
  373:         if (!ts->heap_limit) {
  374:             long ret;
  375:             uint32_t size;
  376:             uint32_t base;
  377: 
  378:             base = do_brk(0);
  379:             size = SEMIHOSTING_HEAP_SIZE;
  380:             /* Try a big heap, and reduce the size if that fails.  */
  381:             for (;;) {
  382:                 ret = do_brk(base + size);
  383:                 if (ret != -1)
  384:                     break;
  385:                 size >>= 1;
  386:             }
  387:             ts->heap_limit = base + size;
  388:         }
  389:         /* This call may happen before we have writable memory, so return
  390:            values directly in registers.  */
  391:         env->dregs[1] = ts->heap_limit;
  392:         env->aregs[7] = ts->stack_base;
  393:         }
  394: #else
  395:         /* FIXME: This is wrong for boards where RAM does not start at
  396:            address zero.  */
  397:         env->dregs[1] = ram_size;
  398:         env->aregs[7] = ram_size;
  399: #endif
  400:         return;
  401:     default:
  402:         cpu_abort(env, "Unsupported semihosting syscall %d\n", nr);
  403:         result = 0;
  404:     }
  405:     /* FIXME - handle put_user() failure */
  406:     put_user_u32(result, args);
  407:     put_user_u32(errno, args + 4);
  408: }

unix.superglobalmegacorp.com