[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 2/4] bsd-user: move arch/OS dependent code out of ma
From: |
Sean Bruno |
Subject: |
[Qemu-devel] [PATCH 2/4] bsd-user: move arch/OS dependent code out of main.c |
Date: |
Thu, 19 Jun 2014 17:19:46 -0700 |
From: Stacey Son <address@hidden>
This change moves the cpu initialization and main loop code from
main.c to the OS and arch dependent directories. This eliminates
many of the #ifdef's in main.c. The cpu initialization and loop
code is now located in the arch directory along with target arch
support code.
Signed-off-by: Sean Bruno <address@hidden>
---
bsd-user/Makefile.objs | 2 +-
bsd-user/elfload.c | 2 +-
bsd-user/freebsd/host_os.h | 46 ++
bsd-user/freebsd/target_os_vmparam.h | 23 +
bsd-user/i386/target_arch.h | 13 +
bsd-user/i386/target_arch_cpu.c | 79 +++
bsd-user/i386/target_arch_cpu.h | 300 +++++++++++
bsd-user/i386/target_arch_vmparam.h | 28 +
bsd-user/i386/target_signal.h | 6 -
bsd-user/main.c | 927 +++++++--------------------------
bsd-user/mmap.c | 2 +-
bsd-user/netbsd/host_os.h | 31 ++
bsd-user/netbsd/os-strace.h | 2 +-
bsd-user/netbsd/target_os_vmparam.h | 23 +
bsd-user/openbsd/host_os.h | 31 ++
bsd-user/openbsd/os-strace.h | 2 +-
bsd-user/openbsd/target_os_vmparam.h | 23 +
bsd-user/qemu.h | 21 +-
bsd-user/sparc/target_arch.h | 11 +
bsd-user/sparc/target_arch_cpu.c | 113 ++++
bsd-user/sparc/target_arch_cpu.h | 158 ++++++
bsd-user/sparc/target_arch_vmparam.h | 37 ++
bsd-user/sparc/target_signal.h | 5 -
bsd-user/sparc64/target_arch.h | 11 +
bsd-user/sparc64/target_arch_cpu.c | 118 +++++
bsd-user/sparc64/target_arch_cpu.h | 191 +++++++
bsd-user/sparc64/target_arch_vmparam.h | 37 ++
bsd-user/sparc64/target_signal.h | 5 -
bsd-user/x86_64/target_arch.h | 13 +
bsd-user/x86_64/target_arch_cpu.c | 79 +++
bsd-user/x86_64/target_arch_cpu.h | 322 ++++++++++++
bsd-user/x86_64/target_arch_vmparam.h | 28 +
bsd-user/x86_64/target_signal.h | 5 -
33 files changed, 1930 insertions(+), 764 deletions(-)
create mode 100644 bsd-user/freebsd/host_os.h
create mode 100644 bsd-user/freebsd/target_os_vmparam.h
create mode 100644 bsd-user/i386/target_arch.h
create mode 100644 bsd-user/i386/target_arch_cpu.c
create mode 100644 bsd-user/i386/target_arch_cpu.h
create mode 100644 bsd-user/i386/target_arch_vmparam.h
create mode 100644 bsd-user/netbsd/host_os.h
create mode 100644 bsd-user/netbsd/target_os_vmparam.h
create mode 100644 bsd-user/openbsd/host_os.h
create mode 100644 bsd-user/openbsd/target_os_vmparam.h
create mode 100644 bsd-user/sparc/target_arch.h
create mode 100644 bsd-user/sparc/target_arch_cpu.c
create mode 100644 bsd-user/sparc/target_arch_cpu.h
create mode 100644 bsd-user/sparc/target_arch_vmparam.h
create mode 100644 bsd-user/sparc64/target_arch.h
create mode 100644 bsd-user/sparc64/target_arch_cpu.c
create mode 100644 bsd-user/sparc64/target_arch_cpu.h
create mode 100644 bsd-user/sparc64/target_arch_vmparam.h
create mode 100644 bsd-user/x86_64/target_arch.h
create mode 100644 bsd-user/x86_64/target_arch_cpu.c
create mode 100644 bsd-user/x86_64/target_arch_cpu.h
create mode 100644 bsd-user/x86_64/target_arch_vmparam.h
diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index 5e77f57..41e8dce 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,2 +1,2 @@
obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
- uaccess.o
+ uaccess.o $(TARGET_ABI_DIR)/target_arch_cpu.o
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 93fd9e4..ccf72d1 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -674,7 +674,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct
linux_binprm *bprm,
/* Create enough stack to hold everything. If we don't use
* it for args, we'll use it for something else...
*/
- size = x86_stack_size;
+ size = target_dflssiz;
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
error = target_mmap(0,
diff --git a/bsd-user/freebsd/host_os.h b/bsd-user/freebsd/host_os.h
new file mode 100644
index 0000000..efe2351
--- /dev/null
+++ b/bsd-user/freebsd/host_os.h
@@ -0,0 +1,46 @@
+/*
+ * FreeBSD host dependent code and definitions
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include <stdio.h>
+#include <sys/sysctl.h>
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_freebsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+
+ len = PATH_MAX;
+ if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) {
+ perror("sysctl");
+ }
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/freebsd/target_os_vmparam.h
b/bsd-user/freebsd/target_os_vmparam.h
new file mode 100644
index 0000000..80ac6c8
--- /dev/null
+++ b/bsd-user/freebsd/target_os_vmparam.h
@@ -0,0 +1,23 @@
+#ifndef _TARGET_OS_VMPARAM_H_
+#define _TARGET_OS_VMPARAM_H_
+
+#include "target_arch_vmparam.h"
+
+#define TARGET_SPACE_USRSPACE 4096
+#define TARGET_ARG_MAX 262144
+
+/* Compare to sys/exec.h */
+struct target_ps_strings {
+ abi_ulong ps_argvstr;
+ uint32_t ps_nargvstr;
+ abi_ulong ps_envstr;
+ uint32_t ps_nenvstr;
+};
+
+extern abi_ulong target_stkbas;
+extern abi_ulong target_stksiz;
+
+#define TARGET_PS_STRINGS ((target_stkbas + target_stksiz) - \
+ sizeof(struct target_ps_strings))
+
+#endif /* !TARGET_OS_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_arch.h b/bsd-user/i386/target_arch.h
new file mode 100644
index 0000000..4cb398c
--- /dev/null
+++ b/bsd-user/i386/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags);
+void bsd_i386_set_idt(int n, unsigned int dpl);
+void bsd_i386_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c
new file mode 100644
index 0000000..2e0eec0
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ * i386 cpu related code
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+ return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+ return -1;
+}
+
+void bsd_i386_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags)
+{
+ unsigned int e1, e2;
+ uint32_t *p;
+ e1 = (addr << 16) | (limit & 0xffff);
+ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+ e2 |= flags;
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+ uint32_t addr, unsigned int sel)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_i386_set_idt(int n, unsigned int dpl)
+{
+ set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+void bsd_i386_set_idt_base(uint64_t base)
+{
+ idt_table = g2h(base);
+}
+
diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h
new file mode 100644
index 0000000..ab505c4
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.h
@@ -0,0 +1,300 @@
+/*
+ * i386 cpu init and loop
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu32"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+ struct target_pt_regs *regs)
+{
+ uint64_t *gdt_table;
+
+ env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+ env->hflags |= HF_PE_MASK;
+ if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+ env->cr[4] |= CR4_OSFXSR_MASK;
+ env->hflags |= HF_OSFXSR_MASK;
+ }
+
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags |= IF_MASK;
+
+ /* register setup */
+ env->regs[R_EAX] = regs->eax;
+ env->regs[R_EBX] = regs->ebx;
+ env->regs[R_ECX] = regs->ecx;
+ env->regs[R_EDX] = regs->edx;
+ env->regs[R_ESI] = regs->esi;
+ env->regs[R_EDI] = regs->edi;
+ env->regs[R_EBP] = regs->ebp;
+ env->regs[R_ESP] = regs->esp;
+ env->eip = regs->eip;
+
+ /* interrupt setup */
+ env->idt.limit = 255;
+
+ env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+ PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ bsd_i386_set_idt_base(env->idt.base);
+ bsd_i386_set_idt(0, 0);
+ bsd_i386_set_idt(1, 0);
+ bsd_i386_set_idt(2, 0);
+ bsd_i386_set_idt(3, 3);
+ bsd_i386_set_idt(4, 3);
+ bsd_i386_set_idt(5, 0);
+ bsd_i386_set_idt(6, 0);
+ bsd_i386_set_idt(7, 0);
+ bsd_i386_set_idt(8, 0);
+ bsd_i386_set_idt(9, 0);
+ bsd_i386_set_idt(10, 0);
+ bsd_i386_set_idt(11, 0);
+ bsd_i386_set_idt(12, 0);
+ bsd_i386_set_idt(13, 0);
+ bsd_i386_set_idt(14, 0);
+ bsd_i386_set_idt(15, 0);
+ bsd_i386_set_idt(16, 0);
+ bsd_i386_set_idt(17, 0);
+ bsd_i386_set_idt(18, 0);
+ bsd_i386_set_idt(19, 0);
+ bsd_i386_set_idt(0x80, 3);
+
+ /* segment setup */
+ env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+ PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+ gdt_table = g2h(env->gdt.base);
+
+ bsd_i386_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+ bsd_i386_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_FS, __USER_DS);
+ cpu_x86_load_seg(env, R_GS, __USER_DS);
+ /* This hack makes Wine work... */
+ env->segs[R_FS].selector = 0;
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+ int trapnr;
+ abi_ulong pc;
+ /* target_siginfo_t info; */
+
+ for (;;) {
+ trapnr = cpu_x86_exec(env);
+ switch (trapnr) {
+ case 0x80:
+ /* syscall from int $0x80 */
+ if (bsd_type == target_freebsd) {
+ abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+ sizeof(int32_t);
+ int32_t syscall_nr = env->regs[R_EAX];
+ int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+ if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+ get_user_s32(syscall_nr, params);
+ params += sizeof(int32_t);
+ } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+ get_user_s32(syscall_nr, params);
+ params += sizeof(int64_t);
+ }
+ get_user_s32(arg1, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg2, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg3, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg4, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg5, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg6, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg7, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg8, params);
+ env->regs[R_EAX] = do_freebsd_syscall(env,
+ syscall_nr,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ arg7,
+ arg8);
+ } else { /* if (bsd_type == target_openbsd) */
+ env->regs[R_EAX] = do_openbsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EBX],
+ env->regs[R_ECX],
+ env->regs[R_EDX],
+ env->regs[R_ESI],
+ env->regs[R_EDI],
+ env->regs[R_EBP]);
+ }
+ if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+ env->regs[R_EAX] = -env->regs[R_EAX];
+ env->eflags |= CC_C;
+ } else {
+ env->eflags &= ~CC_C;
+ }
+ break;
+
+#if 0
+ case EXCP0B_NOSEG:
+ case EXCP0C_STACK:
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP0D_GPF:
+ /* XXX: potential problem if ABI32 */
+ if (env->eflags & VM_MASK) {
+ handle_vm86_fault(env);
+ } else {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+
+ case EXCP0E_PAGE:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ if (!(env->error_code & 1)) {
+ info.si_code = TARGET_SEGV_MAPERR;
+ } else {
+ info.si_code = TARGET_SEGV_ACCERR;
+ }
+ info._sifields._sigfault._addr = env->cr[2];
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP00_DIVZ:
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else {
+ /* division by zero */
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTDIV;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+
+ case EXCP01_DB:
+ case EXCP03_INT3:
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else {
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ if (trapnr == EXCP01_DB) {
+ info.si_code = TARGET_TRAP_BRKPT;
+ info._sifields._sigfault._addr = env->eip;
+ } else {
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ }
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+
+ case EXCP04_INTO:
+ case EXCP05_BOUND:
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+
+ case EXCP06_ILLOP:
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ break;
+#endif
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+#if 0
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(env, TARGET_SIGTRAP);
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, &info);
+ }
+ }
+ break;
+#endif
+ default:
+ pc = env->segs[R_CS].base + env->eip;
+ fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+ "aborting\n", (long)pc, trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+ if (newsp)
+ env->regs[R_ESP] = newsp;
+ env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+ cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/i386/target_arch_vmparam.h
b/bsd-user/i386/target_arch_vmparam.h
new file mode 100644
index 0000000..f15af91
--- /dev/null
+++ b/bsd-user/i386/target_arch_vmparam.h
@@ -0,0 +1,28 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to i386/include/vmparam.h */
+#define TARGET_MAXTSIZ (128UL*1024*1024) /* max text size */
+#define TARGET_DFLDSIZ (128UL*1024*1024) /* initial data size limit */
+#define TARGET_MAXDSIZ (512UL*1024*1024) /* max data size */
+#define TARGET_DFLSSIZ (8UL*1024*1024) /* initial stack size limit */
+#define TARGET_MAXSSIZ (64UL*1024*1024) /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024) /* amount to grow stack */
+
+#define TARGET_RESERVED_VA 0xf7000000
+
+#define TARGET_USRSTACK (0xbfc00000)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+ return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+ state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h
index 2ef36d1..5491687 100644
--- a/bsd-user/i386/target_signal.h
+++ b/bsd-user/i386/target_signal.h
@@ -11,10 +11,4 @@ typedef struct target_sigaltstack {
abi_ulong ss_size;
} target_stack_t;
-
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
- return state->regs[R_ESP];
-}
-
#endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 0e8c26c..9c5711d 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -1,7 +1,8 @@
/*
- * qemu user main
+ * qemu bsd user main
*
* Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2013 Stacey Son
*
* 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
@@ -23,652 +24,194 @@
#include <errno.h>
#include <unistd.h>
#include <machine/trap.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "qemu.h"
#include "qemu-common.h"
-/* For tb_lock */
#include "cpu.h"
#include "tcg.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
+#include "host_os.h"
+#include "target_arch_cpu.h"
+
int singlestep;
-#if defined(CONFIG_USE_GUEST_BASE)
+static const char *cpu_model;
unsigned long mmap_min_addr;
+#if defined(CONFIG_USE_GUEST_BASE)
unsigned long guest_base;
int have_guest_base;
+#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
+/*
+ * When running 32-on-64 we should make sure we can fit all of the possible
+ * guest address space into a contiguous chunk of virtual host memory.
+ *
+ * This way we will never overlap with our own libraries or binaries or stack
+ * or anything else that QEMU maps.
+ */
+unsigned long reserved_va = TARGET_RESERVED_VA;
+#else
unsigned long reserved_va;
#endif
+#endif /* CONFIG_USE_GUEST_BASE */
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
extern char **environ;
enum BSDType bsd_type;
-/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
- we allocate a bigger stack. Need a better solution, for example
- by remapping the process stack directly at the right place */
-unsigned long x86_stack_size = 512 * 1024;
+unsigned long target_maxtsiz = TARGET_MAXTSIZ; /* max text size */
+unsigned long target_dfldsiz = TARGET_DFLDSIZ; /* initial data size limit */
+unsigned long target_maxdsiz = TARGET_MAXDSIZ; /* max data size */
+unsigned long target_dflssiz = TARGET_DFLSSIZ; /* initial data size limit */
+unsigned long target_maxssiz = TARGET_MAXSSIZ; /* max stack size */
+unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */
-void gemu_log(const char *fmt, ...)
-{
- va_list ap;
+char qemu_proc_pathname[PATH_MAX]; /* full path to exeutable */
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-}
-
-#if defined(TARGET_I386)
-int cpu_get_pic_interrupt(CPUX86State *env)
-{
- return -1;
-}
-#endif
-
-/* These are no-ops because we are not threadsafe. */
-static inline void cpu_exec_start(CPUArchState *env)
-{
-}
-
-static inline void cpu_exec_end(CPUArchState *env)
-{
-}
-
-static inline void start_exclusive(void)
-{
-}
-
-static inline void end_exclusive(void)
-{
-}
+/* Helper routines for implementing atomic operations. */
+/*
+ * To implement exclusive operations we force all cpus to synchronize.
+ * We don't require a full sync, only that no cpus are executing guest code.
+ * The alternative is to map target atomic ops onto host eqivalents,
+ * which requires quite a lot of per host/target work.
+ */
+static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
+static int pending_cpus;
+
+#if defined(CONFIG_USE_NPTL)
+/* Make sure everything is in a consistent state for calling fork(). */
void fork_start(void)
{
+ pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
+ pthread_mutex_lock(&exclusive_lock);
+ mmap_fork_start();
}
void fork_end(int child)
{
+ mmap_fork_end(child);
if (child) {
+ CPUState *cpu, *next_cpu;
+ /*
+ * Child processes created by fork() only have a single thread.
+ * Discard information about the parent threads.
+ */
+ CPU_FOREACH_SAFE(cpu, next_cpu) {
+ if (cpu != thread_cpu) {
+ QTAILQ_REMOVE(&cpus, thread_cpu, node);
+ }
+ }
+ pending_cpus = 0;
+ pthread_mutex_init(&exclusive_lock, NULL);
+ pthread_mutex_init(&cpu_list_mutex, NULL);
+ pthread_cond_init(&exclusive_cond, NULL);
+ pthread_cond_init(&exclusive_resume, NULL);
+ pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL);
gdbserver_fork((CPUArchState *)thread_cpu->env_ptr);
+ } else {
+ pthread_mutex_unlock(&exclusive_lock);
+ pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
}
}
-
-void cpu_list_lock(void)
-{
-}
-
-void cpu_list_unlock(void)
+#else
+void fork_start(void)
{
}
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
-
-void cpu_smm_update(CPUX86State *env)
+void fork_end(int child)
{
-}
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
- return cpu_get_real_ticks();
}
+#endif
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
- int flags)
+/*
+ * Wait for pending exclusive operations to complete. The exclusive lock
+ * must be held.
+ */
+static inline void exclusive_idle(void)
{
- unsigned int e1, e2;
- uint32_t *p;
- e1 = (addr << 16) | (limit & 0xffff);
- e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
- e2 |= flags;
- p = ptr;
- p[0] = tswap32(e1);
- p[1] = tswap32(e2);
+ while (pending_cpus) {
+ pthread_cond_wait(&exclusive_resume, &exclusive_lock);
+ }
}
-static uint64_t *idt_table;
-#ifdef TARGET_X86_64
-static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
- uint64_t addr, unsigned int sel)
-{
- uint32_t *p, e1, e2;
- e1 = (addr & 0xffff) | (sel << 16);
- e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
- p = ptr;
- p[0] = tswap32(e1);
- p[1] = tswap32(e2);
- p[2] = tswap32(addr >> 32);
- p[3] = 0;
-}
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
+/* Start an exclusive operation. Must only be called outside of cpu_exec. */
+void start_exclusive(void)
{
- set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
-}
-#else
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
- uint32_t addr, unsigned int sel)
-{
- uint32_t *p, e1, e2;
- e1 = (addr & 0xffff) | (sel << 16);
- e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
- p = ptr;
- p[0] = tswap32(e1);
- p[1] = tswap32(e2);
-}
+ CPUState *other_cpu;
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
-{
- set_gate(idt_table + n, 0, dpl, 0, 0);
-}
-#endif
+ pthread_mutex_lock(&exclusive_lock);
+ exclusive_idle();
-void cpu_loop(CPUX86State *env)
-{
- int trapnr;
- abi_ulong pc;
- //target_siginfo_t info;
-
- for(;;) {
- trapnr = cpu_x86_exec(env);
- switch(trapnr) {
- case 0x80:
- /* syscall from int $0x80 */
- if (bsd_type == target_freebsd) {
- abi_ulong params = (abi_ulong) env->regs[R_ESP] +
- sizeof(int32_t);
- int32_t syscall_nr = env->regs[R_EAX];
- int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
-
- if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
- get_user_s32(syscall_nr, params);
- params += sizeof(int32_t);
- } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
- get_user_s32(syscall_nr, params);
- params += sizeof(int64_t);
- }
- get_user_s32(arg1, params);
- params += sizeof(int32_t);
- get_user_s32(arg2, params);
- params += sizeof(int32_t);
- get_user_s32(arg3, params);
- params += sizeof(int32_t);
- get_user_s32(arg4, params);
- params += sizeof(int32_t);
- get_user_s32(arg5, params);
- params += sizeof(int32_t);
- get_user_s32(arg6, params);
- params += sizeof(int32_t);
- get_user_s32(arg7, params);
- params += sizeof(int32_t);
- get_user_s32(arg8, params);
- env->regs[R_EAX] = do_freebsd_syscall(env,
- syscall_nr,
- arg1,
- arg2,
- arg3,
- arg4,
- arg5,
- arg6,
- arg7,
- arg8);
- } else { //if (bsd_type == target_openbsd)
- env->regs[R_EAX] = do_openbsd_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EBX],
- env->regs[R_ECX],
- env->regs[R_EDX],
- env->regs[R_ESI],
- env->regs[R_EDI],
- env->regs[R_EBP]);
- }
- if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
- env->regs[R_EAX] = -env->regs[R_EAX];
- env->eflags |= CC_C;
- } else {
- env->eflags &= ~CC_C;
- }
- break;
-#ifndef TARGET_ABI32
- case EXCP_SYSCALL:
- /* syscall from syscall instruction */
- if (bsd_type == target_freebsd)
- env->regs[R_EAX] = do_freebsd_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EDI],
- env->regs[R_ESI],
- env->regs[R_EDX],
- env->regs[R_ECX],
- env->regs[8],
- env->regs[9], 0, 0);
- else { //if (bsd_type == target_openbsd)
- env->regs[R_EAX] = do_openbsd_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EDI],
- env->regs[R_ESI],
- env->regs[R_EDX],
- env->regs[10],
- env->regs[8],
- env->regs[9]);
- }
- env->eip = env->exception_next_eip;
- if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
- env->regs[R_EAX] = -env->regs[R_EAX];
- env->eflags |= CC_C;
- } else {
- env->eflags &= ~CC_C;
- }
- break;
-#endif
-#if 0
- case EXCP0B_NOSEG:
- case EXCP0C_STACK:
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
- break;
- case EXCP0D_GPF:
- /* XXX: potential problem if ABI32 */
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_fault(env);
- } else
-#endif
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
- }
- break;
- case EXCP0E_PAGE:
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- if (!(env->error_code & 1))
- info.si_code = TARGET_SEGV_MAPERR;
- else
- info.si_code = TARGET_SEGV_ACCERR;
- info._sifields._sigfault._addr = env->cr[2];
- queue_signal(env, info.si_signo, &info);
- break;
- case EXCP00_DIVZ:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else
-#endif
- {
- /* division by zero */
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTDIV;
- info._sifields._sigfault._addr = env->eip;
- queue_signal(env, info.si_signo, &info);
- }
- break;
- case EXCP01_DB:
- case EXCP03_INT3:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else
-#endif
- {
- info.si_signo = SIGTRAP;
- info.si_errno = 0;
- if (trapnr == EXCP01_DB) {
- info.si_code = TARGET_TRAP_BRKPT;
- info._sifields._sigfault._addr = env->eip;
- } else {
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- }
- queue_signal(env, info.si_signo, &info);
- }
- break;
- case EXCP04_INTO:
- case EXCP05_BOUND:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else
-#endif
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
- }
- break;
- case EXCP06_ILLOP:
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->eip;
- queue_signal(env, info.si_signo, &info);
- break;
-#endif
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
-#if 0
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
- }
- }
- break;
-#endif
- default:
- pc = env->segs[R_CS].base + env->eip;
- fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x -
aborting\n",
- (long)pc, trapnr);
- abort();
+ pending_cpus = 1;
+ /* Make all other cpus stop executing. */
+ CPU_FOREACH(other_cpu) {
+ if (other_cpu->running) {
+ pending_cpus++;
+ cpu_exit(other_cpu);
}
- process_pending_signals(env);
+ }
+ if (pending_cpus > 1) {
+ pthread_cond_wait(&exclusive_cond, &exclusive_lock);
}
}
-#endif
-
-#ifdef TARGET_SPARC
-#define SPARC64_STACK_BIAS 2047
-//#define DEBUG_WIN
-/* WARNING: dealing with register windows _is_ complicated. More info
- can be found at http://www.sics.se/~psm/sparcstack.html */
-static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
+/* Finish an exclusive operation. */
+void end_exclusive(void)
{
- index = (index + cwp * 16) % (16 * env->nwindows);
- /* wrap handling : if cwp is on the last window, then we use the
- registers 'after' the end */
- if (index < 8 && env->cwp == env->nwindows - 1)
- index += 16 * env->nwindows;
- return index;
+ pending_cpus = 0;
+ pthread_cond_broadcast(&exclusive_resume);
+ pthread_mutex_unlock(&exclusive_lock);
}
-/* save the register window 'cwp1' */
-static inline void save_window_offset(CPUSPARCState *env, int cwp1)
+/* Wait for exclusive ops to finish, and begin cpu execution. */
+void cpu_exec_start(CPUState *cpu)
{
- unsigned int i;
- abi_ulong sp_ptr;
-
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
- if (sp_ptr & 3)
- sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
- printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
- sp_ptr, cwp1);
-#endif
- for(i = 0; i < 16; i++) {
- /* FIXME - what to do if put_user() fails? */
- put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
- sp_ptr += sizeof(abi_ulong);
- }
+ pthread_mutex_lock(&exclusive_lock);
+ exclusive_idle();
+ cpu->running = true;
+ pthread_mutex_unlock(&exclusive_lock);
}
-static void save_window(CPUSPARCState *env)
+/* Mark cpu as not excuting, and release pending exclusive ops. */
+void cpu_exec_end(CPUState *cpu)
{
-#ifndef TARGET_SPARC64
- unsigned int new_wim;
- new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
- ((1LL << env->nwindows) - 1);
- save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
- env->wim = new_wim;
-#else
- save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
- env->cansave++;
- env->canrestore--;
-#endif
+ pthread_mutex_lock(&exclusive_lock);
+ cpu->running = false;
+ if (pending_cpus > 1) {
+ pending_cpus--;
+ if (pending_cpus == 1) {
+ pthread_cond_signal(&exclusive_cond);
+ }
+ }
+ exclusive_idle();
+ pthread_mutex_unlock(&exclusive_lock);
}
-static void restore_window(CPUSPARCState *env)
+void cpu_list_lock(void)
{
-#ifndef TARGET_SPARC64
- unsigned int new_wim;
-#endif
- unsigned int i, cwp1;
- abi_ulong sp_ptr;
-
-#ifndef TARGET_SPARC64
- new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
- ((1LL << env->nwindows) - 1);
-#endif
-
- /* restore the invalid window */
- cwp1 = cpu_cwp_inc(env, env->cwp + 1);
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
- if (sp_ptr & 3)
- sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
- printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
- sp_ptr, cwp1);
-#endif
- for(i = 0; i < 16; i++) {
- /* FIXME - what to do if get_user() fails? */
- get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
- sp_ptr += sizeof(abi_ulong);
- }
-#ifdef TARGET_SPARC64
- env->canrestore++;
- if (env->cleanwin < env->nwindows - 1)
- env->cleanwin++;
- env->cansave--;
-#else
- env->wim = new_wim;
-#endif
+ pthread_mutex_lock(&cpu_list_mutex);
}
-static void flush_windows(CPUSPARCState *env)
+void cpu_list_unlock(void)
{
- int offset, cwp1;
-
- offset = 1;
- for(;;) {
- /* if restore would invoke restore_window(), then we can stop */
- cwp1 = cpu_cwp_inc(env, env->cwp + offset);
-#ifndef TARGET_SPARC64
- if (env->wim & (1 << cwp1))
- break;
-#else
- if (env->canrestore == 0)
- break;
- env->cansave++;
- env->canrestore--;
-#endif
- save_window_offset(env, cwp1);
- offset++;
- }
- cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-#ifndef TARGET_SPARC64
- /* set wim so that restore will reload the registers */
- env->wim = 1 << cwp1;
-#endif
-#if defined(DEBUG_WIN)
- printf("flush_windows: nb=%d\n", offset - 1);
-#endif
+ pthread_mutex_unlock(&cpu_list_mutex);
}
-void cpu_loop(CPUSPARCState *env)
+void cpu_loop(CPUArchState *env)
{
- CPUState *cs = CPU(sparc_env_get_cpu(env));
- int trapnr, ret, syscall_nr;
- //target_siginfo_t info;
-
- while (1) {
- trapnr = cpu_sparc_exec (env);
- switch (trapnr) {
-#ifndef TARGET_SPARC64
- case 0x80:
-#else
- /* FreeBSD uses 0x141 for syscalls too */
- case 0x141:
- if (bsd_type != target_freebsd)
- goto badtrap;
- case 0x100:
-#endif
- syscall_nr = env->gregs[1];
- if (bsd_type == target_freebsd)
- ret = do_freebsd_syscall(env, syscall_nr,
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5], 0,
0);
- else if (bsd_type == target_netbsd)
- ret = do_netbsd_syscall(env, syscall_nr,
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
- else { //if (bsd_type == target_openbsd)
-#if defined(TARGET_SPARC64)
- syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
- TARGET_OPENBSD_SYSCALL_G2RFLAG);
-#endif
- ret = do_openbsd_syscall(env, syscall_nr,
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
- }
- if ((unsigned int)ret >= (unsigned int)(-515)) {
- ret = -ret;
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
- env->xcc |= PSR_CARRY;
-#else
- env->psr |= PSR_CARRY;
-#endif
- } else {
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
- env->xcc &= ~PSR_CARRY;
-#else
- env->psr &= ~PSR_CARRY;
-#endif
- }
- env->regwptr[0] = ret;
- /* next instruction */
-#if defined(TARGET_SPARC64)
- if (bsd_type == target_openbsd &&
- env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
- env->pc = env->gregs[2];
- env->npc = env->pc + 4;
- } else if (bsd_type == target_openbsd &&
- env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
- env->pc = env->gregs[7];
- env->npc = env->pc + 4;
- } else {
- env->pc = env->npc;
- env->npc = env->npc + 4;
- }
-#else
- env->pc = env->npc;
- env->npc = env->npc + 4;
-#endif
- break;
- case 0x83: /* flush windows */
-#ifdef TARGET_ABI32
- case 0x103:
-#endif
- flush_windows(env);
- /* next instruction */
- env->pc = env->npc;
- env->npc = env->npc + 4;
- break;
-#ifndef TARGET_SPARC64
- case TT_WIN_OVF: /* window overflow */
- save_window(env);
- break;
- case TT_WIN_UNF: /* window underflow */
- restore_window(env);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
-#if 0
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->mmuregs[4];
- queue_signal(env, info.si_signo, &info);
- }
-#endif
- break;
-#else
- case TT_SPILL: /* window overflow */
- save_window(env);
- break;
- case TT_FILL: /* window underflow */
- restore_window(env);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
-#if 0
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- if (trapnr == TT_DFAULT)
- info._sifields._sigfault._addr = env->dmmuregs[4];
- else
- info._sifields._sigfault._addr = env->tsptr->tpc;
- //queue_signal(env, info.si_signo, &info);
- }
-#endif
- break;
-#endif
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
-#if 0
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- //queue_signal(env, info.si_signo, &info);
- }
-#endif
- }
- break;
- default:
-#ifdef TARGET_SPARC64
- badtrap:
-#endif
- printf ("Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
- }
- process_pending_signals (env);
- }
+ target_cpu_loop(env);
}
-#endif
-
static void usage(void)
{
printf("qemu-" TARGET_NAME " version " QEMU_VERSION ", Copyright (c)
2003-2008 Fabrice Bellard\n"
@@ -709,12 +252,21 @@ static void usage(void)
,
TARGET_NAME,
interp_prefix,
- x86_stack_size);
+ target_dflssiz);
exit(1);
}
THREAD CPUState *thread_cpu;
+void stop_all_tasks(void)
+{
+ /*
+ * We trust when using NPTL (pthreads) start_exclusive() handles thread
+ * stopping correctly.
+ */
+ start_exclusive();
+}
+
/* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts)
{
@@ -728,14 +280,55 @@ void init_task_state(TaskState *ts)
ts->sigqueue_table[i].next = NULL;
}
+CPUArchState *cpu_copy(CPUArchState *env)
+{
+ CPUArchState *new_env = cpu_init(cpu_model);
+ CPUState *cpu = ENV_GET_CPU(env);
+#if defined(TARGET_HAS_ICE)
+ CPUBreakpoint *bp;
+ CPUWatchpoint *wp;
+#endif
+
+ /* Reset non arch specific state */
+ cpu_reset(ENV_GET_CPU(new_env));
+
+ memcpy(new_env, env, sizeof(CPUArchState));
+
+ /* Clone all break/watchpoints.
+ Note: Once we support ptrace with hw-debug register access, make sure
+ BP_CPU break/watchpoints are handled correctly on clone. */
+ QTAILQ_INIT(&cpu->breakpoints);
+ QTAILQ_INIT(&cpu->watchpoints);
+#if defined(TARGET_HAS_ICE)
+ QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
+ cpu_breakpoint_insert(cpu, bp->pc, bp->flags, NULL);
+ }
+ QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
+ cpu_watchpoint_insert(cpu, wp->vaddr, (~wp->len_mask) + 1,
+ wp->flags, NULL);
+ }
+#endif
+
+ return new_env;
+}
+
+void gemu_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
int main(int argc, char **argv)
{
const char *filename;
- const char *cpu_model;
const char *log_file = NULL;
const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
+ struct linux_binprm bprm;
TaskState ts1, *ts = &ts1;
CPUArchState *env;
CPUState *cpu;
@@ -744,11 +337,13 @@ int main(int argc, char **argv)
int gdbstub_port = 0;
char **target_environ, **wrk;
envlist_t *envlist = NULL;
- bsd_type = target_openbsd;
+ bsd_type = HOST_DEFAULT_BSD_TYPE;
if (argc <= 1)
usage();
+ save_proc_pathname(argv[0]);
+
module_call_init(MODULE_INIT_QOM);
if ((envlist = envlist_create()) == NULL) {
@@ -767,7 +362,7 @@ int main(int argc, char **argv)
#endif
optind = 1;
- for(;;) {
+ for (;;) {
if (optind >= argc)
break;
r = argv[optind];
@@ -803,13 +398,18 @@ int main(int argc, char **argv)
usage();
} else if (!strcmp(r, "s")) {
r = argv[optind++];
- x86_stack_size = strtol(r, (char **)&r, 0);
- if (x86_stack_size <= 0)
+ target_dflssiz = strtol(r, (char **)&r, 0);
+ if (target_dflssiz <= 0) {
+ usage();
+ }
+ if (*r == 'M') {
+ target_dflssiz *= 1024 * 1024;
+ } else if (*r == 'k' || *r == 'K') {
+ target_dflssiz *= 1024;
+ }
+ if (target_dflssiz > target_maxssiz) {
usage();
- if (*r == 'M')
- x86_stack_size *= 1024 * 1024;
- else if (*r == 'k' || *r == 'K')
- x86_stack_size *= 1024;
+ }
} else if (!strcmp(r, "L")) {
interp_prefix = argv[optind++];
} else if (!strcmp(r, "p")) {
@@ -881,6 +481,8 @@ int main(int argc, char **argv)
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
+ memset(&bprm, 0, sizeof(bprm));
+
/* Zero out image_info */
memset(info, 0, sizeof(struct image_info));
@@ -888,21 +490,7 @@ int main(int argc, char **argv)
init_paths(interp_prefix);
if (cpu_model == NULL) {
-#if defined(TARGET_I386)
-#ifdef TARGET_X86_64
- cpu_model = "qemu64";
-#else
- cpu_model = "qemu32";
-#endif
-#elif defined(TARGET_SPARC)
-#ifdef TARGET_SPARC64
- cpu_model = "TI UltraSparc II";
-#else
- cpu_model = "Fujitsu MB86904";
-#endif
-#else
- cpu_model = "any";
-#endif
+ cpu_model = TARGET_DEFAULT_CPU_MODEL;
}
tcg_exec_init(0);
cpu_exec_init_all();
@@ -914,9 +502,7 @@ int main(int argc, char **argv)
exit(1);
}
cpu = ENV_GET_CPU(env);
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
- cpu_reset(cpu);
-#endif
+ TARGET_CPU_RESET(env);
thread_cpu = cpu;
if (getenv("QEMU_STRACE")) {
@@ -955,7 +541,7 @@ int main(int argc, char **argv)
}
#endif /* CONFIG_USE_GUEST_BASE */
- if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+ if (loader_exec(filename, argv+optind, target_environ, regs, info)) {
printf("Error loading %s\n", filename);
_exit(1);
}
@@ -1000,137 +586,10 @@ int main(int argc, char **argv)
memset(ts, 0, sizeof(TaskState));
init_task_state(ts);
ts->info = info;
+ ts->bprm = &bprm;
cpu->opaque = ts;
-#if defined(TARGET_I386)
- env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
- env->hflags |= HF_PE_MASK | HF_CPL_MASK;
- if (env->features[FEAT_1_EDX] & CPUID_SSE) {
- env->cr[4] |= CR4_OSFXSR_MASK;
- env->hflags |= HF_OSFXSR_MASK;
- }
-#ifndef TARGET_ABI32
- /* enable 64 bit mode if possible */
- if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
- fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
- exit(1);
- }
- env->cr[4] |= CR4_PAE_MASK;
- env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
- env->hflags |= HF_LMA_MASK;
-#endif
-
- /* flags setup : we activate the IRQs by default as in user mode */
- env->eflags |= IF_MASK;
-
- /* linux register setup */
-#ifndef TARGET_ABI32
- env->regs[R_EAX] = regs->rax;
- env->regs[R_EBX] = regs->rbx;
- env->regs[R_ECX] = regs->rcx;
- env->regs[R_EDX] = regs->rdx;
- env->regs[R_ESI] = regs->rsi;
- env->regs[R_EDI] = regs->rdi;
- env->regs[R_EBP] = regs->rbp;
- env->regs[R_ESP] = regs->rsp;
- env->eip = regs->rip;
-#else
- env->regs[R_EAX] = regs->eax;
- env->regs[R_EBX] = regs->ebx;
- env->regs[R_ECX] = regs->ecx;
- env->regs[R_EDX] = regs->edx;
- env->regs[R_ESI] = regs->esi;
- env->regs[R_EDI] = regs->edi;
- env->regs[R_EBP] = regs->ebp;
- env->regs[R_ESP] = regs->esp;
- env->eip = regs->eip;
-#endif
-
- /* linux interrupt setup */
-#ifndef TARGET_ABI32
- env->idt.limit = 511;
-#else
- env->idt.limit = 255;
-#endif
- env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
- PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
- idt_table = g2h(env->idt.base);
- set_idt(0, 0);
- set_idt(1, 0);
- set_idt(2, 0);
- set_idt(3, 3);
- set_idt(4, 3);
- set_idt(5, 0);
- set_idt(6, 0);
- set_idt(7, 0);
- set_idt(8, 0);
- set_idt(9, 0);
- set_idt(10, 0);
- set_idt(11, 0);
- set_idt(12, 0);
- set_idt(13, 0);
- set_idt(14, 0);
- set_idt(15, 0);
- set_idt(16, 0);
- set_idt(17, 0);
- set_idt(18, 0);
- set_idt(19, 0);
- set_idt(0x80, 3);
-
- /* linux segment setup */
- {
- uint64_t *gdt_table;
- env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
- PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
- env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
- gdt_table = g2h(env->gdt.base);
-#ifdef TARGET_ABI32
- write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#else
- /* 64 bit code segment */
- write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- DESC_L_MASK |
- (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#endif
- write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
- }
-
- cpu_x86_load_seg(env, R_CS, __USER_CS);
- cpu_x86_load_seg(env, R_SS, __USER_DS);
-#ifdef TARGET_ABI32
- cpu_x86_load_seg(env, R_DS, __USER_DS);
- cpu_x86_load_seg(env, R_ES, __USER_DS);
- cpu_x86_load_seg(env, R_FS, __USER_DS);
- cpu_x86_load_seg(env, R_GS, __USER_DS);
- /* This hack makes Wine work... */
- env->segs[R_FS].selector = 0;
-#else
- cpu_x86_load_seg(env, R_DS, 0);
- cpu_x86_load_seg(env, R_ES, 0);
- cpu_x86_load_seg(env, R_FS, 0);
- cpu_x86_load_seg(env, R_GS, 0);
-#endif
-#elif defined(TARGET_SPARC)
- {
- int i;
- env->pc = regs->pc;
- env->npc = regs->npc;
- env->y = regs->y;
- for(i = 0; i < 8; i++)
- env->gregs[i] = regs->u_regs[i];
- for(i = 0; i < 8; i++)
- env->regwptr[i] = regs->u_regs[i + 8];
- }
-#else
-#error unsupported target CPU
-#endif
+ target_cpu_init(env, regs);
if (gdbstub_port) {
gdbserver_start (gdbstub_port);
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 092bf7f..121443a 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -30,7 +30,7 @@
//#define DEBUG_MMAP
-#if defined(CONFIG_USE_NPTL)
+#ifdef __FreeBSD__
pthread_mutex_t mmap_mutex;
static int __thread mmap_lock_count;
diff --git a/bsd-user/netbsd/host_os.h b/bsd-user/netbsd/host_os.h
new file mode 100644
index 0000000..5c492e3
--- /dev/null
+++ b/bsd-user/netbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ * NetBSD host dependent code and definitions
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_netbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+ /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/netbsd/os-strace.h b/bsd-user/netbsd/os-strace.h
index 20dfd4b..ead15db 100644
--- a/bsd-user/netbsd/os-strace.h
+++ b/bsd-user/netbsd/os-strace.h
@@ -25,7 +25,7 @@ static inline void do_os_print_sysarch(const struct
syscallname *name,
abi_long arg5, abi_long arg6)
{
qemu_log("qemu: Unsupported syscall %s\n", __func__);
- return -TARGET_ENOSYS;
+ return;
}
/* sysarch() is architecture dependent. */
diff --git a/bsd-user/netbsd/target_os_vmparam.h
b/bsd-user/netbsd/target_os_vmparam.h
new file mode 100644
index 0000000..80ac6c8
--- /dev/null
+++ b/bsd-user/netbsd/target_os_vmparam.h
@@ -0,0 +1,23 @@
+#ifndef _TARGET_OS_VMPARAM_H_
+#define _TARGET_OS_VMPARAM_H_
+
+#include "target_arch_vmparam.h"
+
+#define TARGET_SPACE_USRSPACE 4096
+#define TARGET_ARG_MAX 262144
+
+/* Compare to sys/exec.h */
+struct target_ps_strings {
+ abi_ulong ps_argvstr;
+ uint32_t ps_nargvstr;
+ abi_ulong ps_envstr;
+ uint32_t ps_nenvstr;
+};
+
+extern abi_ulong target_stkbas;
+extern abi_ulong target_stksiz;
+
+#define TARGET_PS_STRINGS ((target_stkbas + target_stksiz) - \
+ sizeof(struct target_ps_strings))
+
+#endif /* !TARGET_OS_VMPARAM_H_ */
diff --git a/bsd-user/openbsd/host_os.h b/bsd-user/openbsd/host_os.h
new file mode 100644
index 0000000..162ce58
--- /dev/null
+++ b/bsd-user/openbsd/host_os.h
@@ -0,0 +1,31 @@
+/*
+ * OpenBSD host dependent code and definitions
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST_OS_H_
+#define __HOST_OS_H_
+
+#include "qemu.h"
+
+#define HOST_DEFAULT_BSD_TYPE target_openbsd
+
+static inline void save_proc_pathname(char *argv0)
+{
+ /* XXX */
+}
+
+#endif /*!__HOST_OS_H_ */
diff --git a/bsd-user/openbsd/os-strace.h b/bsd-user/openbsd/os-strace.h
index 277b96c..88907b4 100644
--- a/bsd-user/openbsd/os-strace.h
+++ b/bsd-user/openbsd/os-strace.h
@@ -25,7 +25,7 @@ static inline void do_os_print_sysarch(const struct
syscallname *name,
abi_long arg5, abi_long arg6)
{
qemu_log("qemu: Unsupported syscall %s\n", __func__);
- return -TARGET_ENOSYS;
+ return;
}
/* sysarch() is architecture dependent. */
diff --git a/bsd-user/openbsd/target_os_vmparam.h
b/bsd-user/openbsd/target_os_vmparam.h
new file mode 100644
index 0000000..80ac6c8
--- /dev/null
+++ b/bsd-user/openbsd/target_os_vmparam.h
@@ -0,0 +1,23 @@
+#ifndef _TARGET_OS_VMPARAM_H_
+#define _TARGET_OS_VMPARAM_H_
+
+#include "target_arch_vmparam.h"
+
+#define TARGET_SPACE_USRSPACE 4096
+#define TARGET_ARG_MAX 262144
+
+/* Compare to sys/exec.h */
+struct target_ps_strings {
+ abi_ulong ps_argvstr;
+ uint32_t ps_nargvstr;
+ abi_ulong ps_envstr;
+ uint32_t ps_nenvstr;
+};
+
+extern abi_ulong target_stkbas;
+extern abi_ulong target_stksiz;
+
+#define TARGET_PS_STRINGS ((target_stkbas + target_stksiz) - \
+ sizeof(struct target_ps_strings))
+
+#endif /* !TARGET_OS_VMPARAM_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 658999b..7521ebe 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -39,10 +39,11 @@ extern enum BSDType bsd_type;
#include "syscall_defs.h"
#include "syscall.h"
+#include "target_os_vmparam.h"
#include "target_signal.h"
#include "exec/gdbstub.h"
-#if defined(CONFIG_USE_NPTL)
+#ifdef __FreeBSD__
#define THREAD __thread
#else
#define THREAD
@@ -90,6 +91,7 @@ typedef struct TaskState {
struct TaskState *next;
int used; /* non zero if used */
struct image_info *info;
+ struct linux_binprm *bprm;
struct emulated_sigtable sigtab[TARGET_NSIG];
struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
@@ -100,6 +102,7 @@ typedef struct TaskState {
} __attribute__((aligned(16))) TaskState;
void init_task_state(TaskState *ts);
+void stop_all_tasks(void);
extern const char *qemu_uname_release;
#if defined(CONFIG_USE_GUEST_BASE)
extern unsigned long mmap_min_addr;
@@ -217,13 +220,23 @@ void mmap_lock(void);
void mmap_unlock(void);
void cpu_list_lock(void);
void cpu_list_unlock(void);
-#if defined(CONFIG_USE_NPTL)
+#ifdef __FreeBSD__
void mmap_fork_start(void);
void mmap_fork_end(int child);
#endif
/* main.c */
-extern unsigned long x86_stack_size;
+extern unsigned long target_maxtsiz;
+extern unsigned long target_dfldsiz;
+extern unsigned long target_maxdsiz;
+extern unsigned long target_dflssiz;
+extern unsigned long target_maxssiz;
+extern unsigned long target_sgrowsiz;
+extern char qemu_proc_pathname[];
+void start_exclusive(void);
+void end_exclusive(void);
+void cpu_exec_start(CPUState *cpu);
+void cpu_exec_end(CPUState *cpu);
/* os-strace.h */
abi_long do_bsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
@@ -417,7 +430,7 @@ static inline void *lock_user_string(abi_ulong guest_addr)
#define unlock_user_struct(host_ptr, guest_addr, copy) \
unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
-#if defined(CONFIG_USE_NPTL)
+#ifdef __FreeBSD__
#include <pthread.h>
#endif
diff --git a/bsd-user/sparc/target_arch.h b/bsd-user/sparc/target_arch.h
new file mode 100644
index 0000000..5ee479b
--- /dev/null
+++ b/bsd-user/sparc/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc_save_window(CPUSPARCState *env);
+void bsd_sparc_restore_window(CPUSPARCState *env);
+void bsd_sparc_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc/target_arch_cpu.c b/bsd-user/sparc/target_arch_cpu.c
new file mode 100644
index 0000000..0af5c7e
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.c
@@ -0,0 +1,113 @@
+/*
+ * sparc cpu related code
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+ can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+ index = (index + cwp * 16) % (16 * env->nwindows);
+ /* wrap handling : if cwp is on the last window, then we use the
+ registers 'after' the end */
+ if (index < 8 && env->cwp == env->nwindows - 1) {
+ index += 16 * env->nwindows;
+ }
+ return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+ unsigned int i;
+ abi_ulong sp_ptr;
+
+ sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+ printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+ sp_ptr, cwp1);
+#endif
+ for (i = 0; i < 16; i++) {
+ /* FIXME - what to do if put_user() fails? */
+ put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+ sp_ptr += sizeof(abi_ulong);
+ }
+}
+
+void bsd_sparc_save_window(CPUSPARCState *env)
+{
+ unsigned int new_wim;
+
+ new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
+ ((1LL << env->nwindows) - 1);
+ save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+ env->wim = new_wim;
+}
+
+void bsd_sparc_restore_window(CPUSPARCState *env)
+{
+ unsigned int new_wim;
+ unsigned int i, cwp1;
+ abi_ulong sp_ptr;
+
+ new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
+ ((1LL << env->nwindows) - 1);
+
+ /* restore the invalid window */
+ cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+ sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#if defined(DEBUG_WIN)
+ printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+ sp_ptr, cwp1);
+#endif
+ for (i = 0; i < 16; i++) {
+ /* FIXME - what to do if get_user() fails? */
+ get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+ sp_ptr += sizeof(abi_ulong);
+ }
+ env->wim = new_wim;
+}
+
+void bsd_sparc_flush_windows(CPUSPARCState *env)
+{
+ int offset, cwp1;
+
+ offset = 1;
+ for (;;) {
+ /* if restore would invoke restore_window(), then we can stop */
+ cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+ if (env->wim & (1 << cwp1)) {
+ break;
+ }
+ save_window_offset(env, cwp1);
+ offset++;
+ }
+ cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+ /* set wim so that restore will reload the registers */
+ env->wim = 1 << cwp1;
+#if defined(DEBUG_WIN)
+ printf("bsd_sparc_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc/target_arch_cpu.h b/bsd-user/sparc/target_arch_cpu.h
new file mode 100644
index 0000000..f61884b
--- /dev/null
+++ b/bsd-user/sparc/target_arch_cpu.h
@@ -0,0 +1,158 @@
+/*
+ * sparc cpu init and loop
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "Fujitsu MB86904"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+ struct target_pt_regs *regs)
+{
+ int i;
+
+ env->pc = regs->pc;
+ env->npc = regs->npc;
+ env->y = regs->y;
+ for (i = 0; i < 8; i++) {
+ env->gregs[i] = regs->u_regs[i];
+ }
+ for (i = 0; i < 8; i++) {
+ env->regwptr[i] = regs->u_regs[i + 8];
+ }
+}
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+ CPUState *cs = CPU(sparc_env_get_cpu(env));
+ int trapnr, ret, syscall_nr;
+ /* target_siginfo_t info; */
+
+ while (1) {
+ trapnr = cpu_sparc_exec(env);
+
+ switch (trapnr) {
+ case 0x80:
+ syscall_nr = env->gregs[1];
+ if (bsd_type == target_freebsd) {
+ ret = do_freebsd_syscall(env, syscall_nr,
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
+ env->regwptr[4], env->regwptr[5], 0,
0);
+ } else if (bsd_type == target_netbsd) {
+ ret = do_netbsd_syscall(env, syscall_nr,
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
+ env->regwptr[4], env->regwptr[5]);
+ } else { /* if (bsd_type == target_openbsd) */
+ ret = do_openbsd_syscall(env, syscall_nr,
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
+ env->regwptr[4], env->regwptr[5]);
+ }
+ if ((unsigned int)ret >= (unsigned int)(-515)) {
+ ret = -ret;
+ env->psr |= PSR_CARRY;
+ } else {
+ env->psr &= ~PSR_CARRY;
+ }
+ env->regwptr[0] = ret;
+ /* next instruction */
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ break;
+ case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+ case 0x103:
+#endif
+ bsd_sparc_flush_windows(env);
+ /* next instruction */
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ break;
+
+ case TT_WIN_OVF: /* window overflow */
+ bsd_sparc_save_window(env);
+ break;
+
+ case TT_WIN_UNF: /* window underflow */
+ bsd_sparc_restore_window(env);
+ break;
+
+ case TT_TFAULT:
+ case TT_DFAULT:
+#if 0
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->mmuregs[4];
+ queue_signal(env, info.si_signo, &info);
+ }
+#endif
+ break;
+
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+
+ case EXCP_DEBUG:
+#if 0
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ /* queue_signal(env, info.si_signo, &info); */
+ }
+ }
+#endif
+ break;
+ default:
+ printf("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(1);
+ }
+ process_pending_signals(env);
+ }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong
newsp)
+{
+ if (newsp)
+ env->regwptr[22] = newsp;
+ env->regwptr[0] = 0;
+ /* FIXME: Do we also need to clear CF? */
+ /* XXXXX */
+ printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+ cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc/target_arch_vmparam.h
b/bsd-user/sparc/target_arch_vmparam.h
new file mode 100644
index 0000000..5f28fcf
--- /dev/null
+++ b/bsd-user/sparc/target_arch_vmparam.h
@@ -0,0 +1,37 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+#define TARGET_MAXTSIZ (1*1024*1024*1024) /* max text size */
+#define TARGET_DFLDSIZ (128*1024*1024) /* initial data size limit */
+#define TARGET_MAXDSIZ (1*1024*1024*1024) /* max data size */
+#define TARGET_DFLSSIZ (128*1024*1024) /* initial stack size limit */
+#define TARGET_MAXSSIZ (1*1024*1024*1024) /* max stack size */
+#define TARGET_SGROWSIZ (128*1024) /* amount to grow stack */
+
+#define TARGET_RESERVED_VA 0xf7000000
+
+/* XXX this may not be right */
+#define TARGET_VM_MAXUSER_ADDRESS (0xc0000000 - (512 * 1024 * 1024))
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6 6
+#endif
+#ifndef UREG_FP
+#define UREG_FP UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+ return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+ state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc/target_signal.h
+++ b/bsd-user/sparc/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
#define UREG_FP UREG_I6
#endif
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
- return state->regwptr[UREG_FP];
-}
-
#endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch.h b/bsd-user/sparc64/target_arch.h
new file mode 100644
index 0000000..46bbcf8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+void bsd_sparc64_save_window(CPUSPARCState *env);
+void bsd_sparc64_restore_window(CPUSPARCState *env);
+void bsd_sparc64_flush_windows(CPUSPARCState *env);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* ! _TARGET_ARCH_H_ */
diff --git a/bsd-user/sparc64/target_arch_cpu.c
b/bsd-user/sparc64/target_arch_cpu.c
new file mode 100644
index 0000000..e7bede8
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.c
@@ -0,0 +1,118 @@
+/*
+ * sparc64 cpu related code
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+
+#include "target_arch.h"
+
+#define SPARC64_STACK_BIAS 2047
+
+/* #define DEBUG_WIN */
+/* WARNING: dealing with register windows _is_ complicated. More info
+ can be found at http://www.sics.se/~psm/sparcstack.html */
+static int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+ index = (index + cwp * 16) % (16 * env->nwindows);
+ /* wrap handling : if cwp is on the last window, then we use the
+ registers 'after' the end */
+ if (index < 8 && env->cwp == env->nwindows - 1) {
+ index += 16 * env->nwindows;
+ }
+ return index;
+}
+
+/* save the register window 'cwp1' */
+static void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+ unsigned int i;
+ abi_ulong sp_ptr;
+
+ sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+ if (sp_ptr & 3) {
+ sp_ptr += SPARC64_STACK_BIAS;
+ }
+#if defined(DEBUG_WIN)
+ printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+ sp_ptr, cwp1);
+#endif
+ for (i = 0; i < 16; i++) {
+ /* FIXME - what to do if put_user() fails? */
+ put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+ sp_ptr += sizeof(abi_ulong);
+ }
+}
+
+void bsd_sparc64_save_window(CPUSPARCState *env)
+{
+ save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+ env->cansave++;
+ env->canrestore--;
+}
+
+void bsd_sparc64_restore_window(CPUSPARCState *env)
+{
+ unsigned int i, cwp1;
+ abi_ulong sp_ptr;
+
+ /* restore the invalid window */
+ cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+ sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+ if (sp_ptr & 3) {
+ sp_ptr += SPARC64_STACK_BIAS;
+ }
+#if defined(DEBUG_WIN)
+ printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+ sp_ptr, cwp1);
+#endif
+ for (i = 0; i < 16; i++) {
+ /* FIXME - what to do if get_user() fails? */
+ get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+ sp_ptr += sizeof(abi_ulong);
+ }
+ env->canrestore++;
+ if (env->cleanwin < env->nwindows - 1) {
+ env->cleanwin++;
+ }
+ env->cansave--;
+}
+
+void bsd_sparc64_flush_windows(CPUSPARCState *env)
+{
+ int offset, cwp1;
+
+ offset = 1;
+ for (;;) {
+ /* if restore would invoke restore_window(), then we can stop */
+ cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+ if (env->canrestore == 0) {
+ break;
+ }
+ env->cansave++;
+ env->canrestore--;
+ save_window_offset(env, cwp1);
+ offset++;
+ }
+ cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#if defined(DEBUG_WIN)
+ printf("bsd_sparc64_flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
diff --git a/bsd-user/sparc64/target_arch_cpu.h
b/bsd-user/sparc64/target_arch_cpu.h
new file mode 100644
index 0000000..e497711
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_cpu.h
@@ -0,0 +1,191 @@
+/*
+ * sparc64 cpu init and loop
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "TI UltraSparc II"
+
+#define TARGET_CPU_RESET(env) cpu_reset(ENV_GET_CPU(env))
+
+static inline void target_cpu_init(CPUSPARCState *env,
+ struct target_pt_regs *regs)
+{
+ int i;
+
+ env->pc = regs->pc;
+ env->npc = regs->npc;
+ env->y = regs->y;
+ for (i = 0; i < 8; i++) {
+ env->gregs[i] = regs->u_regs[i];
+ }
+ for (i = 0; i < 8; i++) {
+ env->regwptr[i] = regs->u_regs[i + 8];
+ }
+}
+
+
+static inline void target_cpu_loop(CPUSPARCState *env)
+{
+ CPUState *cs = CPU(sparc_env_get_cpu(env));
+ int trapnr, ret, syscall_nr;
+ /* target_siginfo_t info; */
+
+ while (1) {
+ trapnr = cpu_sparc_exec(env);
+
+ switch (trapnr) {
+ /* FreeBSD uses 0x141 for syscalls too */
+ case 0x141:
+ if (bsd_type != target_freebsd) {
+ goto badtrap;
+ }
+ case 0x100:
+ syscall_nr = env->gregs[1];
+ if (bsd_type == target_freebsd) {
+ ret = do_freebsd_syscall(env, syscall_nr,
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
+ env->regwptr[4], env->regwptr[5], 0,
0);
+ } else if (bsd_type == target_netbsd) {
+ ret = do_netbsd_syscall(env, syscall_nr,
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
+ env->regwptr[4], env->regwptr[5]);
+ } else { /* if (bsd_type == target_openbsd) */
+ syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
+ TARGET_OPENBSD_SYSCALL_G2RFLAG);
+ ret = do_openbsd_syscall(env, syscall_nr,
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
+ env->regwptr[4], env->regwptr[5]);
+ }
+ if ((unsigned int)ret >= (unsigned int)(-515)) {
+ ret = -ret;
+#if !defined(TARGET_ABI32)
+ env->xcc |= PSR_CARRY;
+#else
+ env->psr |= PSR_CARRY;
+#endif
+ } else {
+#if !defined(TARGET_ABI32)
+ env->xcc &= ~PSR_CARRY;
+#else
+ env->psr &= ~PSR_CARRY;
+#endif
+ }
+ env->regwptr[0] = ret;
+ /* next instruction */
+ if (bsd_type == target_openbsd &&
+ env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
+ env->pc = env->gregs[2];
+ env->npc = env->pc + 4;
+ } else if (bsd_type == target_openbsd &&
+ env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
+ env->pc = env->gregs[7];
+ env->npc = env->pc + 4;
+ } else {
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ }
+ break;
+
+ case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+ case 0x103:
+#endif
+ bsd_sparc64_flush_windows(env);
+ /* next instruction */
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ break;
+
+ case TT_SPILL: /* window overflow */
+ bsd_sparc64_save_window(env);
+ break;
+
+ case TT_FILL: /* window underflow */
+ bsd_sparc64_restore_window(env);
+ break;
+
+ case TT_TFAULT:
+ case TT_DFAULT:
+#if 0
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ if (trapnr == TT_DFAULT) {
+ info._sifields._sigfault._addr = env->dmmuregs[4];
+ } else {
+ info._sifields._sigfault._addr = env->tsptr->tpc;
+ /* queue_signal(env, info.si_signo, &info); */
+ }
+ }
+#endif
+ break;
+
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+#if 0
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ /* queue_signal(env, info.si_signo, &info); */
+ }
+#endif
+ }
+ break;
+
+ default:
+badtrap:
+ printf("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(1);
+ }
+ process_pending_signals(env);
+ }
+}
+
+static inline void target_cpu_clone_regs(CPUSPARCState *env, target_ulong
newsp)
+{
+ if (newsp)
+ env->regwptr[22] = newsp;
+ env->regwptr[0] = 0;
+ /* FIXME: Do we also need to clear CF? */
+ /* XXXXX */
+ printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+ cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/sparc64/target_arch_vmparam.h
b/bsd-user/sparc64/target_arch_vmparam.h
new file mode 100644
index 0000000..2c2323b
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_vmparam.h
@@ -0,0 +1,37 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ (1*1024*1024*1024) /* max text size */
+#define TARGET_DFLDSIZ (128*1024*1024) /* initial data size limit */
+#define TARGET_MAXDSIZ (1*1024*1024*1024) /* max data size */
+#define TARGET_DFLSSIZ (128*1024*1024) /* initial stack size limit */
+#define TARGET_MAXSSIZ (1*1024*1024*1024) /* max stack size */
+#define TARGET_SGROWSIZ (128*1024) /* amount to grow stack */
+
+/* XXX */
+#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS (0x000007fe00000000UL)
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+#ifndef UREG_I6
+#define UREG_I6 6
+#endif
+#ifndef UREG_FP
+#define UREG_FP UREG_I6
+#endif
+
+static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+ return state->regwptr[UREG_FP];
+}
+
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+ state->regwptr[1] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
+
diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h
index 5b2abba..181867a 100644
--- a/bsd-user/sparc64/target_signal.h
+++ b/bsd-user/sparc64/target_signal.h
@@ -19,9 +19,4 @@ typedef struct target_sigaltstack {
#define UREG_FP UREG_I6
#endif
-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
-{
- return state->regwptr[UREG_FP];
-}
-
#endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/x86_64/target_arch.h b/bsd-user/x86_64/target_arch.h
new file mode 100644
index 0000000..7fe81dc
--- /dev/null
+++ b/bsd-user/x86_64/target_arch.h
@@ -0,0 +1,13 @@
+
+#ifndef _TARGET_ARCH_H_
+#define _TARGET_ARCH_H_
+
+/* target_arch_cpu.c */
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags);
+void bsd_x86_64_set_idt(int n, unsigned int dpl);
+void bsd_x86_64_set_idt_base(uint64_t base);
+
+#define target_cpu_set_tls(env, newtls)
+
+#endif /* !_TARGET_ARCH_H_ */
diff --git a/bsd-user/x86_64/target_arch_cpu.c
b/bsd-user/x86_64/target_arch_cpu.c
new file mode 100644
index 0000000..5cfdfca
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.c
@@ -0,0 +1,79 @@
+/*
+ * x86_64 cpu related code
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include "cpu.h"
+#include "qemu.h"
+#include "qemu/timer.h"
+
+#include "target_arch.h"
+
+static uint64_t *idt_table;
+
+/* CPUX86 core interface */
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+ return cpu_get_real_ticks();
+}
+
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+ return -1;
+}
+
+void bsd_x86_64_write_dt(void *ptr, unsigned long addr,
+ unsigned long limit, int flags)
+{
+ unsigned int e1, e2;
+ uint32_t *p;
+ e1 = (addr << 16) | (limit & 0xffff);
+ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+ e2 |= flags;
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+ uint64_t addr, unsigned int sel)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+ p[2] = tswap32(addr >> 32);
+ p[3] = 0;
+}
+
+/* only dpl matters as we do only user space emulation */
+void bsd_x86_64_set_idt(int n, unsigned int dpl)
+{
+ set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+
+void bsd_x86_64_set_idt_base(uint64_t base)
+{
+ idt_table = g2h(base);
+}
diff --git a/bsd-user/x86_64/target_arch_cpu.h
b/bsd-user/x86_64/target_arch_cpu.h
new file mode 100644
index 0000000..dd0f128
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.h
@@ -0,0 +1,322 @@
+/*
+ * x86_64 cpu init and loop
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TARGET_ARCH_CPU_H_
+#define _TARGET_ARCH_CPU_H_
+
+#include "target_arch.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "qemu64"
+
+#define TARGET_CPU_RESET(env)
+
+static inline void target_cpu_init(CPUX86State *env,
+ struct target_pt_regs *regs)
+{
+ uint64_t *gdt_table;
+
+ env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+ env->hflags |= HF_PE_MASK;
+ if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+ env->cr[4] |= CR4_OSFXSR_MASK;
+ env->hflags |= HF_OSFXSR_MASK;
+ }
+
+ /* enable 64 bit mode if possible */
+ if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
+ fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+ exit(1);
+ }
+ env->cr[4] |= CR4_PAE_MASK;
+ env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+ env->hflags |= HF_LMA_MASK;
+
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags |= IF_MASK;
+
+ /* register setup */
+ env->regs[R_EAX] = regs->rax;
+ env->regs[R_EBX] = regs->rbx;
+ env->regs[R_ECX] = regs->rcx;
+ env->regs[R_EDX] = regs->rdx;
+ env->regs[R_ESI] = regs->rsi;
+ env->regs[R_EDI] = regs->rdi;
+ env->regs[R_EBP] = regs->rbp;
+ env->regs[R_ESP] = regs->rsp;
+ env->eip = regs->rip;
+
+ /* interrupt setup */
+ env->idt.limit = 511;
+
+ env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+ PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ bsd_x86_64_set_idt_base(env->idt.base);
+ bsd_x86_64_set_idt(0, 0);
+ bsd_x86_64_set_idt(1, 0);
+ bsd_x86_64_set_idt(2, 0);
+ bsd_x86_64_set_idt(3, 3);
+ bsd_x86_64_set_idt(4, 3);
+ bsd_x86_64_set_idt(5, 0);
+ bsd_x86_64_set_idt(6, 0);
+ bsd_x86_64_set_idt(7, 0);
+ bsd_x86_64_set_idt(8, 0);
+ bsd_x86_64_set_idt(9, 0);
+ bsd_x86_64_set_idt(10, 0);
+ bsd_x86_64_set_idt(11, 0);
+ bsd_x86_64_set_idt(12, 0);
+ bsd_x86_64_set_idt(13, 0);
+ bsd_x86_64_set_idt(14, 0);
+ bsd_x86_64_set_idt(15, 0);
+ bsd_x86_64_set_idt(16, 0);
+ bsd_x86_64_set_idt(17, 0);
+ bsd_x86_64_set_idt(18, 0);
+ bsd_x86_64_set_idt(19, 0);
+ bsd_x86_64_set_idt(0x80, 3);
+
+ /* segment setup */
+ env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+ PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+ gdt_table = g2h(env->gdt.base);
+
+ /* 64 bit code segment */
+ bsd_x86_64_write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_L_MASK
+ | (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+
+ bsd_x86_64_write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+ cpu_x86_load_seg(env, R_DS, 0);
+ cpu_x86_load_seg(env, R_ES, 0);
+ cpu_x86_load_seg(env, R_FS, 0);
+ cpu_x86_load_seg(env, R_GS, 0);
+}
+
+static inline void target_cpu_loop(CPUX86State *env)
+{
+ int trapnr;
+ abi_ulong pc;
+ /* target_siginfo_t info; */
+
+ for (;;) {
+ trapnr = cpu_x86_exec(env);
+ switch (trapnr) {
+ case 0x80:
+ /* syscall from int $0x80 */
+ if (bsd_type == target_freebsd) {
+ abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+ sizeof(int32_t);
+ int32_t syscall_nr = env->regs[R_EAX];
+ int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+ if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+ get_user_s32(syscall_nr, params);
+ params += sizeof(int32_t);
+ } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+ get_user_s32(syscall_nr, params);
+ params += sizeof(int64_t);
+ }
+ get_user_s32(arg1, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg2, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg3, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg4, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg5, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg6, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg7, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg8, params);
+ env->regs[R_EAX] = do_freebsd_syscall(env,
+ syscall_nr,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ arg7,
+ arg8);
+ } else { /* if (bsd_type == target_openbsd) */
+ env->regs[R_EAX] = do_openbsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EBX],
+ env->regs[R_ECX],
+ env->regs[R_EDX],
+ env->regs[R_ESI],
+ env->regs[R_EDI],
+ env->regs[R_EBP]);
+ }
+ if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+ env->regs[R_EAX] = -env->regs[R_EAX];
+ env->eflags |= CC_C;
+ } else {
+ env->eflags &= ~CC_C;
+ }
+ break;
+
+ case EXCP_SYSCALL:
+ /* syscall from syscall instruction */
+ if (bsd_type == target_freebsd) {
+ env->regs[R_EAX] = do_freebsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EDI],
+ env->regs[R_ESI],
+ env->regs[R_EDX],
+ env->regs[R_ECX],
+ env->regs[8],
+ env->regs[9], 0, 0);
+ } else { /* if (bsd_type == target_openbsd) */
+ env->regs[R_EAX] = do_openbsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EDI],
+ env->regs[R_ESI],
+ env->regs[R_EDX],
+ env->regs[10],
+ env->regs[8],
+ env->regs[9]);
+ }
+ env->eip = env->exception_next_eip;
+ if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+ env->regs[R_EAX] = -env->regs[R_EAX];
+ env->eflags |= CC_C;
+ } else {
+ env->eflags &= ~CC_C;
+ }
+ break;
+
+#if 0
+ case EXCP0B_NOSEG:
+ case EXCP0C_STACK:
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP0D_GPF:
+ /* XXX: potential problem if ABI32 */
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP0E_PAGE:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ if (!(env->error_code & 1)) {
+ info.si_code = TARGET_SEGV_MAPERR;
+ } else {
+ info.si_code = TARGET_SEGV_ACCERR;
+ }
+ info._sifields._sigfault._addr = env->cr[2];
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP00_DIVZ:
+ /* division by zero */
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTDIV;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP01_DB:
+ case EXCP03_INT3:
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ if (trapnr == EXCP01_DB) {
+ info.si_code = TARGET_TRAP_BRKPT;
+ info._sifields._sigfault._addr = env->eip;
+ } else {
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ }
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP04_INTO:
+ case EXCP05_BOUND:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ break;
+
+ case EXCP06_ILLOP:
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ break;
+#endif
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+#if 0
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(env, TARGET_SIGTRAP);
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, &info);
+ }
+ }
+ break;
+#endif
+ default:
+ pc = env->segs[R_CS].base + env->eip;
+ fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - "
+ "aborting\n", (long)pc, trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+
+static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
+{
+ if (newsp)
+ env->regs[R_ESP] = newsp;
+ env->regs[R_EAX] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *cpu)
+{
+ cpu_reset(ENV_GET_CPU(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/x86_64/target_arch_vmparam.h
b/bsd-user/x86_64/target_arch_vmparam.h
new file mode 100644
index 0000000..ceb8af5
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_vmparam.h
@@ -0,0 +1,28 @@
+#ifndef _TARGET_ARCH_VMPARAM_H_
+#define _TARGET_ARCH_VMPARAM_H_
+
+#include "cpu.h"
+
+/* compare to amd64/include/vmparam.h */
+#define TARGET_MAXTSIZ (128UL*1024*1024) /* max text size */
+#define TARGET_DFLDSIZ (32768UL*1024*1024) /* initial data size limit */
+#define TARGET_MAXDSIZ (32768UL*1024*1024) /* max data size */
+#define TARGET_DFLSSIZ (8UL*1024*1024) /* initial stack size limit */
+#define TARGET_MAXSSIZ (512UL*1024*1024) /* max stack size */
+#define TARGET_SGROWSIZ (128UL*1024) /* amount to grow stack */
+
+#define TARGET_VM_MAXUSER_ADDRESS (0x00007fffff000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+ return state->regs[R_ESP];
+}
+
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+ state->regs[R_EDX] = retval2;
+}
+
+#endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h
index 659cd40..5491687 100644
--- a/bsd-user/x86_64/target_signal.h
+++ b/bsd-user/x86_64/target_signal.h
@@ -11,9 +11,4 @@ typedef struct target_sigaltstack {
abi_ulong ss_size;
} target_stack_t;
-static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
-{
- return state->regs[R_ESP];
-}
-
#endif /* TARGET_SIGNAL_H */
--
2.0.0