qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [patch] Arm semihosting support.
@ 2005-04-17 20:47 Paul Brook
  0 siblings, 0 replies; only message in thread
From: Paul Brook @ 2005-04-17 20:47 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 338 bytes --]

The attached patch adds support for ARM "Angel" semihosting syscalls.
This is a simple syscall layer which provides basic OS services to embedded 
applications. It is implemented by several free and proprietary toolchains/ 
debugging tools, including newlib and the GDB simulator. It's what you get if 
you configure for "arm-elf".

Paul

[-- Attachment #2: patch.qemu_angel --]
[-- Type: text/x-diff, Size: 10228 bytes --]

Index: Makefile.target
===================================================================
RCS file: /cvsroot/qemu/qemu/Makefile.target,v
retrieving revision 1.64
diff -u -p -r1.64 Makefile.target
--- Makefile.target	17 Apr 2005 19:16:13 -0000	1.64
+++ Makefile.target	17 Apr 2005 20:41:12 -0000
@@ -233,7 +233,7 @@ endif
 ifeq ($(TARGET_ARCH), arm)
 OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
 nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
- nwfpe/double_cpdo.o nwfpe/extended_cpdo.o
+ nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o
 endif
 SRCS:= $(OBJS:.o=.c)
 OBJS+= libqemu.a
Index: linux-user/arm-semi.c
===================================================================
RCS file: linux-user/arm-semi.c
diff -N linux-user/arm-semi.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-user/arm-semi.c	17 Apr 2005 20:41:13 -0000
@@ -0,0 +1,194 @@
+/*
+ *  Arm "Angel" semihosting syscalls
+ * 
+ *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "qemu.h"
+
+#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+
+#define SYS_OPEN        0x01
+#define SYS_CLOSE       0x02
+#define SYS_WRITEC      0x03
+#define SYS_WRITE0      0x04
+#define SYS_WRITE       0x05
+#define SYS_READ        0x06
+#define SYS_READC       0x07
+#define SYS_ISTTY       0x09
+#define SYS_SEEK        0x0a
+#define SYS_FLEN        0x0c
+#define SYS_TMPNAM      0x0d
+#define SYS_REMOVE      0x0e
+#define SYS_RENAME      0x0f
+#define SYS_CLOCK       0x10
+#define SYS_TIME        0x11
+#define SYS_SYSTEM      0x12
+#define SYS_ERRNO       0x13
+#define SYS_GET_CMDLINE 0x15
+#define SYS_HEAPINFO    0x16
+#define SYS_EXIT        0x18
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+int open_modeflags[12] = {
+    O_RDONLY,
+    O_RDONLY | O_BINARY,
+    O_RDWR,
+    O_RDWR | O_BINARY,
+    O_WRONLY | O_CREAT | O_TRUNC,
+    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+    O_RDWR | O_CREAT | O_TRUNC,
+    O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+    O_WRONLY | O_CREAT | O_APPEND,
+    O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
+    O_RDWR | O_CREAT | O_APPEND,
+    O_RDWR | O_CREAT | O_APPEND | O_BINARY
+};
+
+static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
+{
+  if (code == (uint32_t)-1)
+      ts->swi_errno = errno;
+  return code;
+}
+
+#define ARG(x) tswap32(args[x])
+uint32_t do_arm_semihosting(CPUState *env)
+{
+    uint32_t *args;
+    char * s;
+    int nr;
+    uint32_t ret;
+    TaskState *ts = env->opaque;
+
+    nr = env->regs[0];
+    args = (uint32_t *)env->regs[1];
+    switch (nr) {
+    case SYS_OPEN:
+        s = (char *)ARG(0);
+        if (ARG(1) >= 12)
+          return (uint32_t)-1;
+        if (strcmp(s, ":tt") == 0) {
+            if (ARG(1) < 4)
+                return STDIN_FILENO;
+            else
+                return STDOUT_FILENO;
+        }
+        return set_swi_errno(ts, open(s, open_modeflags[ARG(1)]));
+    case SYS_CLOSE:
+        return set_swi_errno(ts, close(ARG(0)));
+    case SYS_WRITEC:
+        /* Write to debug console.  stderr is near enough.  */
+        return write(STDERR_FILENO, args, 1);
+    case SYS_WRITE0:
+        s = (char *)args;
+        return write(STDERR_FILENO, s, strlen(s));
+    case SYS_WRITE:
+        ret = set_swi_errno(ts, write(ARG(0), (void *)ARG(1), ARG(2)));
+        if (ret == (uint32_t)-1)
+            return -1;
+        return ARG(2) - ret;
+    case SYS_READ:
+        ret = set_swi_errno(ts, read(ARG(0), (void *)ARG(1), ARG(2)));
+        if (ret == (uint32_t)-1)
+            return -1;
+        return ARG(2) - ret;
+    case SYS_READC:
+       /* XXX: Read from debug cosole. Not implemented.  */
+        return 0;
+    case SYS_ISTTY:
+        return isatty(ARG(0));
+    case SYS_SEEK:
+        return set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
+    case SYS_FLEN:
+        {
+            struct stat buf;
+            ret = set_swi_errno(ts, fstat(ARG(0), &buf));
+            if (ret == (uint32_t)-1)
+                return -1;
+            return buf.st_size;
+        }
+    case SYS_TMPNAM:
+        /* XXX: Not implemented.  */
+        return -1;
+    case SYS_REMOVE:
+        return set_swi_errno(ts, remove((char *)ARG(0)));
+    case SYS_RENAME:
+        return set_swi_errno(ts, rename((char *)ARG(0), (char *)ARG(2)));
+    case SYS_CLOCK:
+        return clock() / (CLOCKS_PER_SEC / 100);
+    case SYS_TIME:
+        return set_swi_errno(ts, time(NULL));
+    case SYS_SYSTEM:
+        return set_swi_errno(ts, system((char *)ARG(0)));
+    case SYS_ERRNO:
+        return ts->swi_errno;
+    case SYS_GET_CMDLINE:
+        /* XXX: Not implemented.  */
+        s = (char *)ARG(0);
+        *s = 0;
+        args[1] = tswap32(0);
+        return -1;
+    case SYS_HEAPINFO:
+        {
+            uint32_t *ptr;
+            uint32_t limit;
+
+            /* Some C llibraries assume the heap immediately follows .bss, so
+               allocate it using sbrk.  */
+            if (!ts->heap_limit) {
+                long ret;
+
+                ts->heap_base = do_brk(NULL);
+                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
+                /* Try a big heap, and reduce the size if that fails.  */
+                for (;;) {
+                    ret = do_brk((char *)limit);
+                    if (ret != -1)
+                        break;
+                    limit = (ts->heap_base >> 1) + (limit >> 1);
+                }
+                ts->heap_limit = limit;
+            }
+              
+            ptr = (uint32_t *)tswap32(ARG(0));
+            ptr[0] = tswap32(ts->heap_base);
+            ptr[1] = tswap32(ts->heap_limit);
+            ptr[2] = tswap32(ts->stack_base);
+            ptr[3] = tswap32(0); /* Stack limit.  */
+            return 0;
+        }
+    case SYS_EXIT:
+        exit(0);
+    default:
+        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
+        cpu_dump_state(env, stderr, fprintf, 0);
+        abort();
+    }
+}
+
Index: linux-user/main.c
===================================================================
RCS file: /cvsroot/qemu/qemu/linux-user/main.c,v
retrieving revision 1.63
diff -u -p -r1.63 main.c
--- linux-user/main.c	17 Apr 2005 19:16:13 -0000	1.63
+++ linux-user/main.c	17 Apr 2005 20:41:13 -0000
@@ -363,6 +363,9 @@ void cpu_loop(CPUARMState *env)
                 n = insn & 0xffffff;
                 if (n == ARM_NR_cacheflush) {
                     arm_cache_flush(env->regs[0], env->regs[1]);
+                } else if (n == ARM_NR_semihosting
+                           || n == ARM_NR_thumb_semihosting) {
+                    env->regs[0] = do_arm_semihosting (env);
                 } else if (n >= ARM_SYSCALL_BASE) {
                     /* linux syscall */
                     n -= ARM_SYSCALL_BASE;
@@ -1207,6 +1210,10 @@ int main(int argc, char **argv)
             env->regs[i] = regs->uregs[i];
         }
         env->cpsr = regs->uregs[16];
+        ts->stack_base = info->start_stack;
+        ts->heap_base = info->brk;
+        /* This will be filled in on the first SYS_HEAPINFO call.  */
+        ts->heap_limit = 0;
     }
 #elif defined(TARGET_SPARC)
     {
Index: linux-user/qemu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/linux-user/qemu.h,v
retrieving revision 1.23
diff -u -p -r1.23 qemu.h
--- linux-user/qemu.h	17 Apr 2005 19:16:13 -0000	1.23
+++ linux-user/qemu.h	17 Apr 2005 20:41:13 -0000
@@ -62,6 +62,11 @@ typedef struct TaskState {
 #ifdef TARGET_ARM
     /* FPA state */
     FPA11 fpa;
+    /* Extra fields for semihosted binaries.  */
+    uint32_t stack_base;
+    uint32_t heap_base;
+    uint32_t heap_limit;
+    int swi_errno;
 #endif
 #ifdef TARGET_I386
     struct target_vm86plus_struct *target_v86;
@@ -80,6 +85,7 @@ int elf_exec(const char * filename, char
              struct target_pt_regs * regs, struct image_info *infop);
 
 void target_set_brk(char *new_brk);
+long do_brk(char *new_brk);
 void syscall_init(void);
 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
                 long arg4, long arg5, long arg6);
Index: linux-user/syscall.c
===================================================================
RCS file: /cvsroot/qemu/qemu/linux-user/syscall.c,v
retrieving revision 1.58
diff -u -p -r1.58 syscall.c
--- linux-user/syscall.c	1 Mar 2005 22:32:06 -0000	1.58
+++ linux-user/syscall.c	17 Apr 2005 20:41:14 -0000
@@ -264,7 +264,7 @@ void target_set_brk(char *new_brk)
     target_original_brk = new_brk;
 }
 
-static long do_brk(char *new_brk)
+long do_brk(char *new_brk)
 {
     char *brk_page;
     long mapped_addr;
Index: linux-user/arm/syscall.h
===================================================================
RCS file: /cvsroot/qemu/qemu/linux-user/arm/syscall.h,v
retrieving revision 1.4
diff -u -p -r1.4 syscall.h
--- linux-user/arm/syscall.h	31 Jan 2005 20:45:13 -0000	1.4
+++ linux-user/arm/syscall.h	17 Apr 2005 20:41:14 -0000
@@ -29,8 +29,13 @@ struct target_pt_regs {
 
 #define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
 
+#define ARM_NR_semihosting	  0x123456
+#define ARM_NR_thumb_semihosting  0xAB
+
 #if defined(TARGET_WORDS_BIGENDIAN)
 #define UNAME_MACHINE "armv5teb"
 #else
 #define UNAME_MACHINE "armv5tel"
 #endif
+
+uint32_t do_arm_semihosting(CPUState *);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-04-17 21:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-17 20:47 [Qemu-devel] [patch] Arm semihosting support Paul Brook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).