File:  [Qemu by Fabrice Bellard] / qemu / arm-semi.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:50:52 2018 UTC (19 months, 2 weeks ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

    1: /*
    2:  *  Arm "Angel" semihosting syscalls
    3:  *
    4:  *  Copyright (c) 2005, 2007 CodeSourcery.
    5:  *  Written by Paul Brook.
    6:  *
    7:  *  This program is free software; you can redistribute it and/or modify
    8:  *  it under the terms of the GNU General Public License as published by
    9:  *  the Free Software Foundation; either version 2 of the License, or
   10:  *  (at your option) any later version.
   11:  *
   12:  *  This program is distributed in the hope that it will be useful,
   13:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:  *  GNU General Public License for more details.
   16:  *
   17:  *  You should have received a copy of the GNU General Public License
   18:  *  along with this program; if not, write to the Free Software
   19:  *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   20:  *  MA 02110-1301, USA.
   21:  */
   22: 
   23: #include <sys/types.h>
   24: #include <sys/stat.h>
   25: #include <fcntl.h>
   26: #include <unistd.h>
   27: #include <stdlib.h>
   28: #include <stdio.h>
   29: #include <time.h>
   30: 
   31: #include "cpu.h"
   32: #ifdef CONFIG_USER_ONLY
   33: #include "qemu.h"
   34: 
   35: #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
   36: #else
   37: #include "qemu-common.h"
   38: #include "sysemu.h"
   39: #include "gdbstub.h"
   40: #endif
   41: 
   42: #define SYS_OPEN        0x01
   43: #define SYS_CLOSE       0x02
   44: #define SYS_WRITEC      0x03
   45: #define SYS_WRITE0      0x04
   46: #define SYS_WRITE       0x05
   47: #define SYS_READ        0x06
   48: #define SYS_READC       0x07
   49: #define SYS_ISTTY       0x09
   50: #define SYS_SEEK        0x0a
   51: #define SYS_FLEN        0x0c
   52: #define SYS_TMPNAM      0x0d
   53: #define SYS_REMOVE      0x0e
   54: #define SYS_RENAME      0x0f
   55: #define SYS_CLOCK       0x10
   56: #define SYS_TIME        0x11
   57: #define SYS_SYSTEM      0x12
   58: #define SYS_ERRNO       0x13
   59: #define SYS_GET_CMDLINE 0x15
   60: #define SYS_HEAPINFO    0x16
   61: #define SYS_EXIT        0x18
   62: 
   63: #ifndef O_BINARY
   64: #define O_BINARY 0
   65: #endif
   66: 
   67: #define GDB_O_RDONLY  0x000
   68: #define GDB_O_WRONLY  0x001
   69: #define GDB_O_RDWR    0x002
   70: #define GDB_O_APPEND  0x008
   71: #define GDB_O_CREAT   0x200
   72: #define GDB_O_TRUNC   0x400
   73: #define GDB_O_BINARY  0
   74: 
   75: static int gdb_open_modeflags[12] = {
   76:     GDB_O_RDONLY,
   77:     GDB_O_RDONLY | GDB_O_BINARY,
   78:     GDB_O_RDWR,
   79:     GDB_O_RDWR | GDB_O_BINARY,
   80:     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
   81:     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
   82:     GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
   83:     GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
   84:     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
   85:     GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
   86:     GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
   87:     GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
   88: };
   89: 
   90: static int open_modeflags[12] = {
   91:     O_RDONLY,
   92:     O_RDONLY | O_BINARY,
   93:     O_RDWR,
   94:     O_RDWR | O_BINARY,
   95:     O_WRONLY | O_CREAT | O_TRUNC,
   96:     O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   97:     O_RDWR | O_CREAT | O_TRUNC,
   98:     O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
   99:     O_WRONLY | O_CREAT | O_APPEND,
  100:     O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
  101:     O_RDWR | O_CREAT | O_APPEND,
  102:     O_RDWR | O_CREAT | O_APPEND | O_BINARY
  103: };
  104: 
  105: #ifdef CONFIG_USER_ONLY
  106: static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
  107: {
  108:     if (code == (uint32_t)-1)
  109:         ts->swi_errno = errno;
  110:     return code;
  111: }
  112: #else
  113: static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
  114: {
  115:     return code;
  116: }
  117: 
  118: #include "softmmu-semi.h"
  119: #endif
  120: 
  121: static target_ulong arm_semi_syscall_len;
  122: 
  123: #if !defined(CONFIG_USER_ONLY)
  124: static target_ulong syscall_err;
  125: #endif
  126: 
  127: static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
  128: {
  129: #ifdef CONFIG_USER_ONLY
  130:     TaskState *ts = env->opaque;
  131: #endif
  132: 
  133:     if (ret == (target_ulong)-1) {
  134: #ifdef CONFIG_USER_ONLY
  135:         ts->swi_errno = err;
  136: #else
  137: 	syscall_err = err;
  138: #endif
  139:         env->regs[0] = ret;
  140:     } else {
  141:         /* Fixup syscalls that use nonstardard return conventions.  */
  142:         switch (env->regs[0]) {
  143:         case SYS_WRITE:
  144:         case SYS_READ:
  145:             env->regs[0] = arm_semi_syscall_len - ret;
  146:             break;
  147:         case SYS_SEEK:
  148:             env->regs[0] = 0;
  149:             break;
  150:         default:
  151:             env->regs[0] = ret;
  152:             break;
  153:         }
  154:     }
  155: }
  156: 
  157: static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err)
  158: {
  159:     /* The size is always stored in big-endian order, extract
  160:        the value. We assume the size always fit in 32 bits.  */
  161:     uint32_t size;
  162:     cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
  163:     env->regs[0] = be32_to_cpu(size);
  164: #ifdef CONFIG_USER_ONLY
  165:     ((TaskState *)env->opaque)->swi_errno = err;
  166: #else
  167:     syscall_err = err;
  168: #endif
  169: }
  170: 
  171: #define ARG(n)					\
  172: ({						\
  173:     target_ulong __arg;				\
  174:     /* FIXME - handle get_user() failure */	\
  175:     get_user_ual(__arg, args + (n) * 4);	\
  176:     __arg;					\
  177: })
  178: #define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
  179: uint32_t do_arm_semihosting(CPUState *env)
  180: {
  181:     target_ulong args;
  182:     char * s;
  183:     int nr;
  184:     uint32_t ret;
  185:     uint32_t len;
  186: #ifdef CONFIG_USER_ONLY
  187:     TaskState *ts = env->opaque;
  188: #else
  189:     CPUState *ts = env;
  190: #endif
  191: 
  192:     nr = env->regs[0];
  193:     args = env->regs[1];
  194:     switch (nr) {
  195:     case SYS_OPEN:
  196:         if (!(s = lock_user_string(ARG(0))))
  197:             /* FIXME - should this error code be -TARGET_EFAULT ? */
  198:             return (uint32_t)-1;
  199:         if (ARG(1) >= 12)
  200:             return (uint32_t)-1;
  201:         if (strcmp(s, ":tt") == 0) {
  202:             if (ARG(1) < 4)
  203:                 return STDIN_FILENO;
  204:             else
  205:                 return STDOUT_FILENO;
  206:         }
  207:         if (use_gdb_syscalls()) {
  208:             gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
  209: 			   (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
  210:             return env->regs[0];
  211:         } else {
  212:             ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
  213:         }
  214:         unlock_user(s, ARG(0), 0);
  215:         return ret;
  216:     case SYS_CLOSE:
  217:         if (use_gdb_syscalls()) {
  218:             gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
  219:             return env->regs[0];
  220:         } else {
  221:             return set_swi_errno(ts, close(ARG(0)));
  222:         }
  223:     case SYS_WRITEC:
  224:         {
  225:           char c;
  226: 
  227:           if (get_user_u8(c, args))
  228:               /* FIXME - should this error code be -TARGET_EFAULT ? */
  229:               return (uint32_t)-1;
  230:           /* Write to debug console.  stderr is near enough.  */
  231:           if (use_gdb_syscalls()) {
  232:                 gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
  233:                 return env->regs[0];
  234:           } else {
  235:                 return write(STDERR_FILENO, &c, 1);
  236:           }
  237:         }
  238:     case SYS_WRITE0:
  239:         if (!(s = lock_user_string(args)))
  240:             /* FIXME - should this error code be -TARGET_EFAULT ? */
  241:             return (uint32_t)-1;
  242:         len = strlen(s);
  243:         if (use_gdb_syscalls()) {
  244:             gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
  245:             ret = env->regs[0];
  246:         } else {
  247:             ret = write(STDERR_FILENO, s, len);
  248:         }
  249:         unlock_user(s, args, 0);
  250:         return ret;
  251:     case SYS_WRITE:
  252:         len = ARG(2);
  253:         if (use_gdb_syscalls()) {
  254:             arm_semi_syscall_len = len;
  255:             gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
  256:             return env->regs[0];
  257:         } else {
  258:             if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1)))
  259:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  260:                 return (uint32_t)-1;
  261:             ret = set_swi_errno(ts, write(ARG(0), s, len));
  262:             unlock_user(s, ARG(1), 0);
  263:             if (ret == (uint32_t)-1)
  264:                 return -1;
  265:             return len - ret;
  266:         }
  267:     case SYS_READ:
  268:         len = ARG(2);
  269:         if (use_gdb_syscalls()) {
  270:             arm_semi_syscall_len = len;
  271:             gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
  272:             return env->regs[0];
  273:         } else {
  274:             if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0)))
  275:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  276:                 return (uint32_t)-1;
  277:             do
  278:               ret = set_swi_errno(ts, read(ARG(0), s, len));
  279:             while (ret == -1 && errno == EINTR);
  280:             unlock_user(s, ARG(1), len);
  281:             if (ret == (uint32_t)-1)
  282:                 return -1;
  283:             return len - ret;
  284:         }
  285:     case SYS_READC:
  286:        /* XXX: Read from debug cosole. Not implemented.  */
  287:         return 0;
  288:     case SYS_ISTTY:
  289:         if (use_gdb_syscalls()) {
  290:             gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
  291:             return env->regs[0];
  292:         } else {
  293:             return isatty(ARG(0));
  294:         }
  295:     case SYS_SEEK:
  296:         if (use_gdb_syscalls()) {
  297:             gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
  298:             return env->regs[0];
  299:         } else {
  300:             ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
  301:             if (ret == (uint32_t)-1)
  302:               return -1;
  303:             return 0;
  304:         }
  305:     case SYS_FLEN:
  306:         if (use_gdb_syscalls()) {
  307:             gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
  308: 			   ARG(0), env->regs[13]-64);
  309:             return env->regs[0];
  310:         } else {
  311:             struct stat buf;
  312:             ret = set_swi_errno(ts, fstat(ARG(0), &buf));
  313:             if (ret == (uint32_t)-1)
  314:                 return -1;
  315:             return buf.st_size;
  316:         }
  317:     case SYS_TMPNAM:
  318:         /* XXX: Not implemented.  */
  319:         return -1;
  320:     case SYS_REMOVE:
  321:         if (use_gdb_syscalls()) {
  322:             gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
  323:             ret = env->regs[0];
  324:         } else {
  325:             if (!(s = lock_user_string(ARG(0))))
  326:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  327:                 return (uint32_t)-1;
  328:             ret =  set_swi_errno(ts, remove(s));
  329:             unlock_user(s, ARG(0), 0);
  330:         }
  331:         return ret;
  332:     case SYS_RENAME:
  333:         if (use_gdb_syscalls()) {
  334:             gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
  335:                            ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
  336:             return env->regs[0];
  337:         } else {
  338:             char *s2;
  339:             s = lock_user_string(ARG(0));
  340:             s2 = lock_user_string(ARG(2));
  341:             if (!s || !s2)
  342:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  343:                 ret = (uint32_t)-1;
  344:             else
  345:                 ret = set_swi_errno(ts, rename(s, s2));
  346:             if (s2)
  347:                 unlock_user(s2, ARG(2), 0);
  348:             if (s)
  349:                 unlock_user(s, ARG(0), 0);
  350:             return ret;
  351:         }
  352:     case SYS_CLOCK:
  353:         return clock() / (CLOCKS_PER_SEC / 100);
  354:     case SYS_TIME:
  355:         return set_swi_errno(ts, time(NULL));
  356:     case SYS_SYSTEM:
  357:         if (use_gdb_syscalls()) {
  358:             gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
  359:             return env->regs[0];
  360:         } else {
  361:             if (!(s = lock_user_string(ARG(0))))
  362:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  363:                 return (uint32_t)-1;
  364:             ret = set_swi_errno(ts, system(s));
  365:             unlock_user(s, ARG(0), 0);
  366:             return ret;
  367:         }
  368:     case SYS_ERRNO:
  369: #ifdef CONFIG_USER_ONLY
  370:         return ts->swi_errno;
  371: #else
  372:         return syscall_err;
  373: #endif
  374:     case SYS_GET_CMDLINE:
  375: #ifdef CONFIG_USER_ONLY
  376:         /* Build a commandline from the original argv.  */
  377:         {
  378:             char **arg = ts->info->host_argv;
  379:             int len = ARG(1);
  380:             /* lock the buffer on the ARM side */
  381:             char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
  382: 
  383:             if (!cmdline_buffer)
  384:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  385:                 return (uint32_t)-1;
  386: 
  387:             s = cmdline_buffer;
  388:             while (*arg && len > 2) {
  389:                 int n = strlen(*arg);
  390: 
  391:                 if (s != cmdline_buffer) {
  392:                     *(s++) = ' ';
  393:                     len--;
  394:                 }
  395:                 if (n >= len)
  396:                     n = len - 1;
  397:                 memcpy(s, *arg, n);
  398:                 s += n;
  399:                 len -= n;
  400:                 arg++;
  401:             }
  402:             /* Null terminate the string.  */
  403:             *s = 0;
  404:             len = s - cmdline_buffer;
  405: 
  406:             /* Unlock the buffer on the ARM side.  */
  407:             unlock_user(cmdline_buffer, ARG(0), len);
  408: 
  409:             /* Adjust the commandline length argument.  */
  410:             SET_ARG(1, len);
  411: 
  412:             /* Return success if commandline fit into buffer.  */
  413:             return *arg ? -1 : 0;
  414:         }
  415: #else
  416:       return -1;
  417: #endif
  418:     case SYS_HEAPINFO:
  419:         {
  420:             uint32_t *ptr;
  421:             uint32_t limit;
  422: 
  423: #ifdef CONFIG_USER_ONLY
  424:             /* Some C libraries assume the heap immediately follows .bss, so
  425:                allocate it using sbrk.  */
  426:             if (!ts->heap_limit) {
  427:                 long ret;
  428: 
  429:                 ts->heap_base = do_brk(0);
  430:                 limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
  431:                 /* Try a big heap, and reduce the size if that fails.  */
  432:                 for (;;) {
  433:                     ret = do_brk(limit);
  434:                     if (ret != -1)
  435:                         break;
  436:                     limit = (ts->heap_base >> 1) + (limit >> 1);
  437:                 }
  438:                 ts->heap_limit = limit;
  439:             }
  440: 
  441:             if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
  442:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  443:                 return (uint32_t)-1;
  444:             ptr[0] = tswap32(ts->heap_base);
  445:             ptr[1] = tswap32(ts->heap_limit);
  446:             ptr[2] = tswap32(ts->stack_base);
  447:             ptr[3] = tswap32(0); /* Stack limit.  */
  448:             unlock_user(ptr, ARG(0), 16);
  449: #else
  450:             limit = ram_size;
  451:             if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
  452:                 /* FIXME - should this error code be -TARGET_EFAULT ? */
  453:                 return (uint32_t)-1;
  454:             /* TODO: Make this use the limit of the loaded application.  */
  455:             ptr[0] = tswap32(limit / 2);
  456:             ptr[1] = tswap32(limit);
  457:             ptr[2] = tswap32(limit); /* Stack base */
  458:             ptr[3] = tswap32(0); /* Stack limit.  */
  459:             unlock_user(ptr, ARG(0), 16);
  460: #endif
  461:             return 0;
  462:         }
  463:     case SYS_EXIT:
  464:         exit(0);
  465:     default:
  466:         fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
  467:         cpu_dump_state(env, stderr, fprintf, 0);
  468:         abort();
  469:     }
  470: }

unix.superglobalmegacorp.com