From owner-freebsd-emulation@FreeBSD.ORG Wed Oct 7 22:11:08 2009 Return-Path: Delivered-To: freebsd-emulation@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B33041065672 for ; Wed, 7 Oct 2009 22:11:08 +0000 (UTC) (envelope-from nox@jelal.kn-bremen.de) Received: from smtp.kn-bremen.de (gelbbaer.kn-bremen.de [78.46.108.116]) by mx1.freebsd.org (Postfix) with ESMTP id 2FC218FC1D for ; Wed, 7 Oct 2009 22:11:07 +0000 (UTC) Received: by smtp.kn-bremen.de (Postfix, from userid 10) id 82CFE1E006E0; Thu, 8 Oct 2009 00:11:06 +0200 (CEST) Received: from triton8.kn-bremen.de (noident@localhost [127.0.0.1]) by triton8.kn-bremen.de (8.14.3/8.14.3) with ESMTP id n97M5s9P067950; Thu, 8 Oct 2009 00:05:54 +0200 (CEST) (envelope-from nox@triton8.kn-bremen.de) Received: (from nox@localhost) by triton8.kn-bremen.de (8.14.3/8.14.3/Submit) id n97M5n0J067949; Thu, 8 Oct 2009 00:05:49 +0200 (CEST) (envelope-from nox) From: Juergen Lock Date: Thu, 8 Oct 2009 00:05:49 +0200 To: freebsd-emulation@FreeBSD.org Message-ID: <20091007220549.GA65997@triton8.kn-bremen.de> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) Cc: qemu-devel@nongnu.org, Toni Subject: playing with qemu usermode emulation on FreeBSD... X-BeenThere: freebsd-emulation@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Development of Emulators of other operating systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 07 Oct 2009 22:11:08 -0000 I recently noticed there are x86 bsd-user targets now (yeah I totally missed those commits...) and now got it working a tiny little bit: I can run qemu-x86_64 -bsd freebsd /rescue/echo foo bar here on FreeBSD 8/amd64 and it echoes foo bar as expected, but segfaults afterwards. :) (in pthread_setcancelstate() invoked from a guest write() syscall, in case anyone is wondering.) Other things I tried either exit with errors or segfault as well, and i386 hosts probably still don't work at all yet. (qemu-i386 here on amd64 does at least something, but probably needs lock_user() treatment for all kinds of syscalls, I only tried adding that for sysctl so far.) Anyway, here is an emulators/qemu-devel git head snapshot port update with my current patches (files/patch-bsd-user), feel free to test/debug/improve: http://people.freebsd.org/~nox/qemu/qemu-devel-20091007.patch (For the folks reading this on the qemu list: I shall start doing `proper' patch submissions later, this is more for the FreeBSD folks and because I was asked to send what I have...) Enjoy, Juergen PS: well I guess I could inline the patch here too so the curious don't have to extract it out of the update: Index: qemu/bsd-user/freebsd/strace.list @@ -39,6 +39,7 @@ { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL }, +{ TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL }, { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL }, { TARGET_FREEBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL }, { TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL }, Index: qemu/bsd-user/elfload.c @@ -126,6 +126,8 @@ regs->rax = 0; regs->rsp = infop->start_stack; regs->rip = infop->entry; + if (1 /* bsd_type == target_freebsd */) + regs->rdi = infop->start_stack; } #else Index: qemu/bsd-user/main.c @@ -171,26 +171,63 @@ switch(trapnr) { case 0x80: /* syscall from int $0x80 */ - 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 (bsd_type == target_freebsd) { + abi_ulong params = (abi_ulong) env->regs[R_ESP] + + sizeof(int32_t); + abi_ulong arg1, arg2, arg3, arg4, arg5, arg6; + + 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); + env->regs[R_EAX] = do_freebsd_syscall(env, + env->regs[R_EAX], + arg1, + arg2, + arg3, + arg4, + arg5, + arg6); + } 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]); + } break; #ifndef TARGET_ABI32 case EXCP_SYSCALL: /* linux syscall from syscall intruction */ - 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]); + 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[10], + env->regs[8], + env->regs[9]); + 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; break; #endif Index: qemu/bsd-user/syscall.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -40,14 +41,88 @@ static abi_ulong target_brk; static abi_ulong target_original_brk; -#define get_errno(x) (x) +static inline abi_long get_errno(abi_long ret) +{ + if (ret == -1) + /* XXX need to translate host -> target errnos here */ + return -(errno); + else + return ret; +} + #define target_to_host_bitmask(x, tbl) (x) +static inline int is_error(abi_long ret) +{ + return (abi_ulong)ret >= (abi_ulong)(-4096); +} + void target_set_brk(abi_ulong new_brk) { target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); } +/* do_obreak() must return target errnos. */ +static abi_long do_obreak(abi_ulong new_brk) +{ + abi_ulong brk_page; + abi_long mapped_addr; + int new_alloc_size; + + if (!new_brk) + return 0; + if (new_brk < target_original_brk) + return -TARGET_EINVAL; + + brk_page = HOST_PAGE_ALIGN(target_brk); + + /* If the new brk is less than this, set it and we're done... */ + if (new_brk < brk_page) { + target_brk = new_brk; + return 0; + } + + /* We need to allocate more memory after the brk... */ + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); + mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)); + + if (!is_error(mapped_addr)) + target_brk = new_brk; + else + return mapped_addr; + + return 0; +} + +/* XXX this needs to be emulated on non-FreeBSD hosts... */ +static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp, + abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) +{ + abi_long ret; + void *hnamep, *holdp, *hnewp = NULL; + size_t holdlen; + abi_ulong oldlen = 0; + + if (oldlenp) + get_user_ual(oldlen, oldlenp); + if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1))) + return -TARGET_EFAULT; + if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1))) + return -TARGET_EFAULT; + if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) + return -TARGET_EFAULT; + holdlen = oldlen; + ret = get_errno(sysctl(hnamep, namelen, holdp, &holdlen, hnewp, newlen)); + put_user_ual(holdlen, oldlenp); + unlock_user(hnamep, namep, 0); + unlock_user(holdp, oldp, holdlen); + if (hnewp) + unlock_user(hnewp, newp, 0); + return ret; +} + /* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. All errnos that do_syscall() returns must be -TARGET_. */ @@ -103,12 +178,18 @@ case TARGET_FREEBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; + case TARGET_FREEBSD_NR_break: + ret = do_obreak(arg1); + break; + case TARGET_FREEBSD_NR___sysctl: + ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); + break; case TARGET_FREEBSD_NR_syscall: case TARGET_FREEBSD_NR___syscall: ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); break; default: - ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6)); break; } fail: Index: qemu/cpu-exec.c @@ -1252,6 +1252,12 @@ # define TRAP_sig(context) ((context)->sc_trapno) # define ERROR_sig(context) ((context)->sc_err) # define MASK_sig(context) ((context)->sc_mask) +#elif defined(__FreeBSD__) +#include +#define EIP_sig(context) ((context)->uc_mcontext.mc_eip) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define MASK_sig(context) ((context)->uc_sigmask) #else # define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) # define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) @@ -1265,6 +1271,8 @@ siginfo_t *info = pinfo; #if defined(__OpenBSD__) struct sigcontext *uc = puc; +#elif defined(__FreeBSD__) + ucontext_t *uc = puc; #else struct ucontext *uc = puc; #endif @@ -1297,6 +1305,12 @@ #define TRAP_sig(context) ((context)->sc_trapno) #define ERROR_sig(context) ((context)->sc_err) #define MASK_sig(context) ((context)->sc_mask) +#elif defined(__FreeBSD__) +#include +#define PC_sig(context) ((context)->uc_mcontext.mc_rip) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define MASK_sig(context) ((context)->uc_sigmask) #else #define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP]) #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) @@ -1313,6 +1327,8 @@ ucontext_t *uc = puc; #elif defined(__OpenBSD__) struct sigcontext *uc = puc; +#elif defined(__FreeBSD__) + ucontext_t *uc = puc; #else struct ucontext *uc = puc; #endif