All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.