diff mbox series

[for,6.2,22/49] bsd-user: Move per-cpu code into target_arch_cpu.h

Message ID 20210807214242.82385-23-imp@bsdimp.com (mailing list archive)
State New, archived
Headers show
Series bsd-user updates to run hello world | expand

Commit Message

Warner Losh Aug. 7, 2021, 9:42 p.m. UTC
From: Warner Losh <imp@FreeBSD.org>

Move cpu_loop() into target_cpu_loop(), and put that in
target_arch_cpu.h for each architecture.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/i386/target_arch_cpu.c   |   1 +
 bsd-user/i386/target_arch_cpu.h   | 306 ++++++++++++++++++++++++++++
 bsd-user/main.c                   | 309 ++--------------------------
 bsd-user/x86_64/target_arch_cpu.c |   1 +
 bsd-user/x86_64/target_arch_cpu.h | 328 ++++++++++++++++++++++++++++++
 5 files changed, 651 insertions(+), 294 deletions(-)
 create mode 100644 bsd-user/i386/target_arch_cpu.h
 create mode 100644 bsd-user/x86_64/target_arch_cpu.h

Comments

Richard Henderson Aug. 8, 2021, 5:35 a.m. UTC | #1
On 8/7/21 11:42 AM, Warner Losh wrote:
> diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c
> index 7f2f755a11..71998e5ba5 100644
> --- a/bsd-user/i386/target_arch_cpu.c
> +++ b/bsd-user/i386/target_arch_cpu.c
> @@ -1,6 +1,7 @@
>   /*
>    *  i386 cpu related code
>    *
> + * Copyright (c) 2013 Stacey Son <sson@FreeBSD.org>
>    *
>    *  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

Should be in previous.

> +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 | HF_CPL_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_untagged(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)
> +{
> +    CPUState *cs = env_cpu(env);
> +    int trapnr;
> +    abi_ulong pc;
> +    /* target_siginfo_t info; */
> +
> +    for (;;) {
> +	cpu_exec_start(cs);
> +        trapnr = cpu_exec(cs);
> +	cpu_exec_end(cs);
> +	process_queued_cpu_work(cs);
> +
> +        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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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:
> +            {
> +
> +                info.si_signo = TARGET_SIGTRAP;
> +                info.si_errno = 0;
> +                info.si_code = TARGET_TRAP_BRKPT;
> +                queue_signal(env, info.si_signo, &info);
> +            }
> +            break;
> +#endif
> +
> +        case EXCP_ATOMIC:
> +            cpu_exec_step_atomic(cs);
> +            break;
> +
> +        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);
> +    }
> +}

Those are some really big functions to want to inline.  Any reason for that?  At first 
glance they could live just fine in target_arch_cpu.c.

r~
Warner Losh Aug. 8, 2021, 6:03 a.m. UTC | #2
On Sat, Aug 7, 2021 at 11:35 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> On 8/7/21 11:42 AM, Warner Losh wrote:
> > diff --git a/bsd-user/i386/target_arch_cpu.c
> b/bsd-user/i386/target_arch_cpu.c
> > index 7f2f755a11..71998e5ba5 100644
> > --- a/bsd-user/i386/target_arch_cpu.c
> > +++ b/bsd-user/i386/target_arch_cpu.c
> > @@ -1,6 +1,7 @@
> >   /*
> >    *  i386 cpu related code
> >    *
> > + * Copyright (c) 2013 Stacey Son <sson@FreeBSD.org>
> >    *
> >    *  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
>
> Should be in previous.
>

Gotcha.


> > +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 | HF_CPL_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_untagged(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)
> > +{
> > +    CPUState *cs = env_cpu(env);
> > +    int trapnr;
> > +    abi_ulong pc;
> > +    /* target_siginfo_t info; */
> > +
> > +    for (;;) {
> > +     cpu_exec_start(cs);
> > +        trapnr = cpu_exec(cs);
> > +     cpu_exec_end(cs);
> > +     process_queued_cpu_work(cs);
> > +
> > +        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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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:
> > +            {
> > +
> > +                info.si_signo = TARGET_SIGTRAP;
> > +                info.si_errno = 0;
> > +                info.si_code = TARGET_TRAP_BRKPT;
> > +                queue_signal(env, info.si_signo, &info);
> > +            }
> > +            break;
> > +#endif
> > +
> > +        case EXCP_ATOMIC:
> > +            cpu_exec_step_atomic(cs);
> > +            break;
> > +
> > +        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);
> > +    }
> > +}
>
> Those are some really big functions to want to inline.  Any reason for
> that?  At first
> glance they could live just fine in target_arch_cpu.c.
>

Mostly because that's how Stacey wrote it and we have half a dozen
implementations
already.  I'll see how hard it would be to transition to this structure. I
worried about
this being so different than linux-user, but at the same time I worried
about regressions
that may be introduced in the effort since our testing story isn't what I'd
like. I'm also
a bit worried because we have two branches: the tip that we're trying to
release from
and this effort which needs any changes also merged to that tip branch.

Having said that, I'll see what I can do.

Warner
Richard Henderson Aug. 8, 2021, 6:16 a.m. UTC | #3
On 8/7/21 8:03 PM, Warner Losh wrote:
> 
> 
> On Sat, Aug 7, 2021 at 11:35 PM Richard Henderson <richard.henderson@linaro.org 
> <mailto:richard.henderson@linaro.org>> wrote:
> 
>     On 8/7/21 11:42 AM, Warner Losh wrote:
>      > diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c
>      > index 7f2f755a11..71998e5ba5 100644
>      > --- a/bsd-user/i386/target_arch_cpu.c
>      > +++ b/bsd-user/i386/target_arch_cpu.c
>      > @@ -1,6 +1,7 @@
>      >   /*
>      >    *  i386 cpu related code
>      >    *
>      > + * Copyright (c) 2013 Stacey Son <sson@FreeBSD.org>
>      >    *
>      >    *  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
> 
>     Should be in previous.
> 
> 
> Gotcha.
> 
>      > +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 | HF_CPL_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_untagged(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)
>      > +{
>      > +    CPUState *cs = env_cpu(env);
>      > +    int trapnr;
>      > +    abi_ulong pc;
>      > +    /* target_siginfo_t info; */
>      > +
>      > +    for (;;) {
>      > +     cpu_exec_start(cs);
>      > +        trapnr = cpu_exec(cs);
>      > +     cpu_exec_end(cs);
>      > +     process_queued_cpu_work(cs);
>      > +
>      > +        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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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:
>      > +            {
>      > +
>      > +                info.si_signo = TARGET_SIGTRAP;
>      > +                info.si_errno = 0;
>      > +                info.si_code = TARGET_TRAP_BRKPT;
>      > +                queue_signal(env, info.si_signo, &info);
>      > +            }
>      > +            break;
>      > +#endif
>      > +
>      > +        case EXCP_ATOMIC:
>      > +            cpu_exec_step_atomic(cs);
>      > +            break;
>      > +
>      > +        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);
>      > +    }
>      > +}
> 
>     Those are some really big functions to want to inline.  Any reason for that?  At first
>     glance they could live just fine in target_arch_cpu.c.
> 
> 
> Mostly because that's how Stacey wrote it and we have half a dozen implementations
> already.  I'll see how hard it would be to transition to this structure. I worried about
> this being so different than linux-user, but at the same time I worried about regressions
> that may be introduced in the effort since our testing story isn't what I'd like. I'm also
> a bit worried because we have two branches: the tip that we're trying to release from
> and this effort which needs any changes also merged to that tip branch.
> 
> Having said that, I'll see what I can do.

I guess I'm happy to have them in the header for now, but just add something to the to-do 
list once you're not juggling multiple branches.

I'll not say that linux-user is ideal either, btw.  Just stuff you see doing new patch review.


r~
Warner Losh Aug. 8, 2021, 5:38 p.m. UTC | #4
On Sun, Aug 8, 2021 at 12:16 AM Richard Henderson <
richard.henderson@linaro.org> wrote:

> On 8/7/21 8:03 PM, Warner Losh wrote:
> >
> >
> > On Sat, Aug 7, 2021 at 11:35 PM Richard Henderson <
> richard.henderson@linaro.org
> > <mailto:richard.henderson@linaro.org>> wrote:
> >
> >     On 8/7/21 11:42 AM, Warner Losh wrote:
> >      > diff --git a/bsd-user/i386/target_arch_cpu.c
> b/bsd-user/i386/target_arch_cpu.c
> >      > index 7f2f755a11..71998e5ba5 100644
> >      > --- a/bsd-user/i386/target_arch_cpu.c
> >      > +++ b/bsd-user/i386/target_arch_cpu.c
> >      > @@ -1,6 +1,7 @@
> >      >   /*
> >      >    *  i386 cpu related code
> >      >    *
> >      > + * Copyright (c) 2013 Stacey Son <sson@FreeBSD.org>
> >      >    *
> >      >    *  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
> >
> >     Should be in previous.
> >
> >
> > Gotcha.
> >
> >      > +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 | HF_CPL_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_untagged(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)
> >      > +{
> >      > +    CPUState *cs = env_cpu(env);
> >      > +    int trapnr;
> >      > +    abi_ulong pc;
> >      > +    /* target_siginfo_t info; */
> >      > +
> >      > +    for (;;) {
> >      > +     cpu_exec_start(cs);
> >      > +        trapnr = cpu_exec(cs);
> >      > +     cpu_exec_end(cs);
> >      > +     process_queued_cpu_work(cs);
> >      > +
> >      > +        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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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:
> >      > +            {
> >      > +
> >      > +                info.si_signo = TARGET_SIGTRAP;
> >      > +                info.si_errno = 0;
> >      > +                info.si_code = TARGET_TRAP_BRKPT;
> >      > +                queue_signal(env, info.si_signo, &info);
> >      > +            }
> >      > +            break;
> >      > +#endif
> >      > +
> >      > +        case EXCP_ATOMIC:
> >      > +            cpu_exec_step_atomic(cs);
> >      > +            break;
> >      > +
> >      > +        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);
> >      > +    }
> >      > +}
> >
> >     Those are some really big functions to want to inline.  Any reason
> for that?  At first
> >     glance they could live just fine in target_arch_cpu.c.
> >
> >
> > Mostly because that's how Stacey wrote it and we have half a dozen
> implementations
> > already.  I'll see how hard it would be to transition to this structure.
> I worried about
> > this being so different than linux-user, but at the same time I worried
> about regressions
> > that may be introduced in the effort since our testing story isn't what
> I'd like. I'm also
> > a bit worried because we have two branches: the tip that we're trying to
> release from
> > and this effort which needs any changes also merged to that tip branch.
> >
> > Having said that, I'll see what I can do.
>
> I guess I'm happy to have them in the header for now, but just add
> something to the to-do
> list once you're not juggling multiple branches.
>
> I'll not say that linux-user is ideal either, btw.  Just stuff you see
> doing new patch review.
>

I think I'll take you up on that offer. It's a pattern that Stacey Son
used  a lot when writing
this code, and I'd need to do it to many different files. If it were just
this one, I'd definitely
do that in a heart-beat. But since there's a lot, I think I'd get bogged
down with so
many changes. There's a number of things you see when upstreaming the code
too
that suggest themselves as cleanup, and so far I've just been keeping a
list for later
on the larger of those items (eg command line parsing). In general, there
was a preference
for having lots of inline functions, some quite long, so that they could be
swapped out
more easily by including an alternative header (per arch, per bsd flavor,
etc). With LTO
here or on the horizon, I'm thinking having the interface in the .h file
and the code in a .c file
and having LTO eliminate the extra calls that would create may be
acceptable. But
I think the optimal solution needs some time for thought and study as well.

Warner
diff mbox series

Patch

diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c
index 7f2f755a11..71998e5ba5 100644
--- a/bsd-user/i386/target_arch_cpu.c
+++ b/bsd-user/i386/target_arch_cpu.c
@@ -1,6 +1,7 @@ 
 /*
  *  i386 cpu related code
  *
+ * Copyright (c) 2013 Stacey Son <sson@FreeBSD.org>
  *
  *  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
diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h
new file mode 100644
index 0000000000..c7603d4ec6
--- /dev/null
+++ b/bsd-user/i386/target_arch_cpu.h
@@ -0,0 +1,306 @@ 
+/*
+ *  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(cpu)
+
+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 | HF_CPL_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_untagged(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)
+{
+    CPUState *cs = env_cpu(env);
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+	cpu_exec_start(cs);
+        trapnr = cpu_exec(cs);
+	cpu_exec_end(cs);
+	process_queued_cpu_work(cs);
+
+        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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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:
+            {
+
+                info.si_signo = TARGET_SIGTRAP;
+                info.si_errno = 0;
+                info.si_code = TARGET_TRAP_BRKPT;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+#endif
+
+        case EXCP_ATOMIC:
+            cpu_exec_step_atomic(cs);
+            break;
+
+        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_cpu(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index ac435b216a..91e6abb6e4 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -42,6 +42,7 @@ 
 #include "trace/control.h"
 
 #include "host-os.h"
+#include "target_arch_cpu.h"
 
 #include <sys/sysctl.h>
 
@@ -83,177 +84,10 @@  void fork_end(int child)
     }
 }
 
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
-
-static void 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 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)
-{
-    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);
-}
-
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
+void cpu_loop(CPUArchState *env)
 {
-    set_gate(idt_table + n, 0, dpl, 0, 0);
-}
-#endif
-
-void cpu_loop(CPUX86State *env)
-{
-    CPUState *cs = env_cpu(env);
-    int trapnr;
-    abi_ulong pc;
-    /* target_siginfo_t info; */
-
-    for (;;) {
-        cpu_exec_start(cs);
-        trapnr = cpu_exec(cs);
-        cpu_exec_end(cs);
-        process_queued_cpu_work(cs);
-
-        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
-        case EXCP_INTERRUPT:
-            /* just indicate that signals should be handled asap */
-            break;
-        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);
-    }
+    target_cpu_loop(env);
 }
-#endif
 
 static void usage(void)
 {
@@ -521,18 +355,11 @@  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
-#else
-        cpu_model = "any";
-#endif
+        cpu_model = TARGET_DEFAULT_CPU_MODEL;
     }
 
     cpu_type = parse_cpu_option(cpu_model);
+
     /* init tcg before creating CPUs and to get qemu_host_page_size */
     {
         AccelClass *ac = ACCEL_GET_CLASS(current_accel());
@@ -626,124 +453,18 @@  int main(int argc, char **argv)
     ts->info = info;
     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
+    target_set_brk(info->brk);
+    syscall_init();
+    signal_init();
 
-    /* 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_untagged(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_untagged(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));
-    }
+    /*
+     * Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
+     * generating the prologue until now so that the prologue can take
+     * the real value of GUEST_BASE into account.
+     */
+    tcg_prologue_init(tcg_ctx);
 
-    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
-#else
-#error unsupported target CPU
-#endif
+    target_cpu_init(env, regs);
 
     if (gdbstub) {
         gdbserver_start(gdbstub);
diff --git a/bsd-user/x86_64/target_arch_cpu.c b/bsd-user/x86_64/target_arch_cpu.c
index a2c5b176a4..db822e54c6 100644
--- a/bsd-user/x86_64/target_arch_cpu.c
+++ b/bsd-user/x86_64/target_arch_cpu.c
@@ -1,6 +1,7 @@ 
 /*
  *  x86_64 cpu related code
  *
+ * Copyright (c) 2013 Stacey Son <sson@FreeBSD.org>
  *
  *  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
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 0000000000..ba0533ea0c
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_cpu.h
@@ -0,0 +1,328 @@ 
+/*
+ *  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(cpu)
+
+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 | HF_CPL_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_untagged(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)
+{
+    CPUState *cs = env_cpu(env);
+    int trapnr;
+    abi_ulong pc;
+    /* target_siginfo_t info; */
+
+    for (;;) {
+	cpu_exec_start(cs);
+        trapnr = cpu_exec(cs);
+	cpu_exec_end(cs);
+	process_queued_cpu_work(cs);
+
+        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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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 = TARGET_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:
+            {
+
+                info.si_signo = TARGET_SIGTRAP;
+                info.si_errno = 0;
+                info.si_code = TARGET_TRAP_BRKPT;
+                queue_signal(env, info.si_signo, &info);
+            }
+            break;
+#endif
+
+        case EXCP_ATOMIC:
+            cpu_exec_step_atomic(cs);
+            break;
+
+        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_cpu(cpu));
+}
+
+#endif /* ! _TARGET_ARCH_CPU_H_ */