File:  [Qemu by Fabrice Bellard] / qemu / m68k-semi.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:55:45 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1000, qemu0151, HEAD
qemu 0.15.1

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