* [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.