diff --git a/Makefile b/Makefile index d710df5..59de5cb 100644 --- a/Makefile +++ b/Makefile @@ -68,9 +68,9 @@ USE_GCC= any .if ${PORT_OPTIONS:MX86_TARGETS} .if ${PORT_OPTIONS:MBSD_USER} .if ${ARCH} != "amd64" -CONFIGURE_ARGS+= --enable-nptl --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,sparc-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user +CONFIGURE_ARGS+= --enable-nptl --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,sparc-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user,ppc-bsd-user,ppc64-bsd-user .else -CONFIGURE_ARGS+= --enable-nptl --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,x86_64-bsd-user,sparc-bsd-user,sparc64-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user,mips64-bsd-user +CONFIGURE_ARGS+= --enable-nptl --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,x86_64-bsd-user,sparc-bsd-user,sparc64-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user,mips64-bsd-user,ppc-bsd-user,ppc64-bsd-user .endif .else CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu @@ -81,7 +81,7 @@ CONFIGURE_ARGS+= --disable-bsd-user .else CONFIGURE_ARGS+= --enable-nptl .if ${ARCH} != "amd64" -CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu,alpha-softmmu,arm-softmmu,cris-softmmu,lm32-softmmu,m68k-softmmu,microblaze-softmmu,microblazeel-softmmu,mips-softmmu,mipsel-softmmu,mips64-softmmu,mips64el-softmmu,or32-softmmu,ppc-softmmu,ppcemb-softmmu,ppc64-softmmu,sh4-softmmu,sh4eb-softmmu,sparc-softmmu,sparc64-softmmu,s390x-softmmu,xtensa-softmmu,xtensaeb-softmmu,unicore32-softmmu,i386-bsd-user,sparc-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user +CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu,alpha-softmmu,arm-softmmu,cris-softmmu,lm32-softmmu,m68k-softmmu,microblaze-softmmu,microblazeel-softmmu,mips-softmmu,mipsel-softmmu,mips64-softmmu,mips64el-softmmu,or32-softmmu,ppc-softmmu,ppcemb-softmmu,ppc64-softmmu,sh4-softmmu,sh4eb-softmmu,sparc-softmmu,sparc64-softmmu,s390x-softmmu,xtensa-softmmu,xtensaeb-softmmu,unicore32-softmmu,i386-bsd-user,sparc-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user,ppc-bsd-user,ppc64-bsd-user .endif .endif .endif diff --git a/work/qemu-1.4.0/Makefile.target b/work/qemu-1.4.0/Makefile.target index e256014..4c92f67 100644 --- a/work/qemu-1.4.0/Makefile.target +++ b/work/qemu-1.4.0/Makefile.target @@ -92,7 +92,7 @@ endif #CONFIG_LINUX_USER ifdef CONFIG_BSD_USER -QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) +QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) obj-y += bsd-user/ obj-y += gdbstub.o thunk.o user-exec.o diff --git a/work/qemu-1.4.0/bsd-user/elfload.c b/work/qemu-1.4.0/bsd-user/elfload.c index da9ad73..5d53c2a 100644 --- a/work/qemu-1.4.0/bsd-user/elfload.c +++ b/work/qemu-1.4.0/bsd-user/elfload.c @@ -316,64 +316,40 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif #define ELF_ARCH EM_PPC -/* - * We need to put in some extra aux table entries to tell glibc what - * the cache block size is, so it can use the dcbz instruction safely. - */ -#define AT_DCACHEBSIZE 19 -#define AT_ICACHEBSIZE 20 -#define AT_UCACHEBSIZE 21 -/* A special ignored type value for PPC, for glibc compatibility. */ -#define AT_IGNOREPPC 22 -/* - * The requirements here are: - * - keep the final alignment of sp (sp & 0xf) - * - make sure the 32-bit value at the first 16 byte aligned position of - * AUXV is greater than 16 for glibc compatibility. - * AT_IGNOREPPC is used for that. - * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, - * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. - */ -#define DLINFO_ARCH_ITEMS 5 -#define ARCH_DLINFO \ -do { \ - NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ - NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ - NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ - /* \ - * Now handle glibc compatibility. \ - */ \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - } while (0) - -static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *_regs, + struct image_info *infop) { - abi_ulong pos = infop->start_stack; - abi_ulong tmp; #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) abi_ulong entry, toc; + abi_ulong pos = infop->start_stack; +#else + abi_ulong pos = infop->start_stack; #endif - _regs->gpr[1] = infop->start_stack; + abi_ulong argc; + /* see powerpc/exec_machdep.c exec_setregs */ #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + _regs->gpr[1] = -roundup(-infop->start_stack + 48, 16); entry = ldq_raw(infop->entry) + infop->load_addr; toc = ldq_raw(infop->entry + 8) + infop->load_addr; _regs->gpr[2] = toc; + _regs->gpr[11] = ldq_raw(infop->entry + 16) + infop->load_addr; infop->entry = entry; +#else + _regs->gpr[1] = -roundup(-infop->start_stack + 8, 16); + #endif - _regs->nip = infop->entry; - /* Note that isn't exactly what regular kernel does - * but this is what the ABI wants and is needed to allow - * execution of PPC BSD programs. - */ + _regs->pc = infop->entry; + /* FIXME - what to for failure of get_user()? */ - get_user_ual(_regs->gpr[3], pos); - pos += sizeof(abi_ulong); - _regs->gpr[4] = pos; - for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) - tmp = ldl(pos); - _regs->gpr[5] = pos; + + get_user_ual(argc, pos); + _regs->gpr[3] = argc; /* argc */ + _regs->gpr[4] = pos + sizeof(abi_ulong); /* argv */ + _regs->gpr[5] = pos + (2 + argc) * sizeof(abi_ulong); /* envp */ + _regs->gpr[6] = 0; + _regs->gpr[7] = 0; + _regs->gpr[8] = TARGET_PS_STRINGS; } #define USE_ELF_CORE_DUMP @@ -559,7 +535,11 @@ struct exec #define INTERPRETER_AOUT 1 #define INTERPRETER_ELF 2 +#if defined(__FreeBSD__) && !defined(TARGET_PPC) #define DLINFO_ITEMS 12 +#else +#define DLINFO_ITEMS 8 +#endif static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { @@ -747,7 +727,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, size_t execpath_len; abi_ulong destp, argvp, envp; struct target_ps_strings ps_strs; - char canary[sizeof(abi_long) * 8]; + char canary[8 * 8]; char execpath[PATH_MAX]; stack_hi_addr = p = error + size; @@ -972,11 +952,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); - NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); +#if defined(__FreeBSD__) && !defined(TARGET_PPC) NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); +#endif #ifndef __FreeBSD__ NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); diff --git a/work/qemu-1.4.0/bsd-user/main.c b/work/qemu-1.4.0/bsd-user/main.c index 9b526b3..5bc33f6 100644 --- a/work/qemu-1.4.0/bsd-user/main.c +++ b/work/qemu-1.4.0/bsd-user/main.c @@ -576,6 +576,537 @@ void cpu_loop(CPUX86State *env) } #endif +#ifdef TARGET_PPC +static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env) +{ + /* TO FIX */ + return 0; +} + +uint64_t cpu_ppc_load_tbl(CPUPPCState *env) +{ + return cpu_ppc_get_tb(env); +} + +uint32_t cpu_ppc_load_tbu(CPUPPCState *env) +{ + return cpu_ppc_get_tb(env) >> 32; +} + +uint64_t cpu_ppc_load_atbl(CPUPPCState *env) +{ + return cpu_ppc_get_tb(env); +} + +uint32_t cpu_ppc_load_atbu(CPUPPCState *env) +{ + return cpu_ppc_get_tb(env) >> 32; +} + +uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env) +__attribute__ (( alias ("cpu_ppc_load_tbu") )); + +uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env) +{ + return cpu_ppc_load_tbl(env) & 0x3FFFFF80; +} + +#define EXCP_DUMP(env, fmt, ...) \ +do { \ + fprintf(stderr, fmt , ## __VA_ARGS__); \ + cpu_dump_state(env, stderr, fprintf, 0); \ + qemu_log(fmt, ## __VA_ARGS__); \ + if (qemu_log_enabled()) { \ + log_cpu_state(env, 0); \ + } \ +} while (0) + +/* XXX: to be fixed */ +int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) +{ + return -1; +} + +int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) +{ + return -1; +} + +static int do_store_exclusive(CPUPPCState *env) +{ + target_ulong addr; + target_ulong page_addr; + target_ulong val; + int flags; + int segv = 0; + + addr = env->reserve_ea; + page_addr = addr & TARGET_PAGE_MASK; + start_exclusive(); + mmap_lock(); + flags = page_get_flags(page_addr); + if ((flags & PAGE_READ) == 0) { + segv = 1; + } else { + int reg = env->reserve_info & 0x1f; + int size = (env->reserve_info >> 5) & 0xf; + int stored = 0; + + if (addr == env->reserve_addr) { + switch (size) { + case 1: segv = get_user_u8(val, addr); break; + case 2: segv = get_user_u16(val, addr); break; + case 4: segv = get_user_u32(val, addr); break; +#if defined(TARGET_PPC64) + case 8: segv = get_user_u64(val, addr); break; +#endif + default: + abort(); + } + if (!segv && val == env->reserve_val) { + val = env->gpr[reg]; + switch (size) { + case 1: segv = put_user_u8(val, addr); break; + case 2: segv = put_user_u16(val, addr); break; + case 4: segv = put_user_u32(val, addr); break; +#if defined(TARGET_PPC64) + case 8: segv = put_user_u64(val, addr); break; +#endif + default: + abort(); + } + if (!segv) { + stored = 1; + } + } + } + env->crf[0] = (stored << 1) | xer_so; + env->reserve_addr = (target_ulong)-1; + } + if (!segv) { + env->nip += 4; + } + mmap_unlock(); + end_exclusive(); + return segv; +} + +void cpu_loop(CPUPPCState *env) +{ + target_siginfo_t info; + int trapnr; + target_ulong ret; + + for(;;) { + cpu_exec_start(env); + trapnr = cpu_ppc_exec(env); + cpu_exec_end(env); + switch(trapnr) { + case POWERPC_EXCP_NONE: + /* Just go on */ + break; + case POWERPC_EXCP_CRITICAL: /* Critical input */ + cpu_abort(env, "Critical interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + cpu_abort(env, "Machine check exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n", + env->spr[SPR_DAR]); + /* XXX: check this. Seems bugged */ + switch (env->error_code & 0xFF000000) { + case 0x40000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + case 0x04000000: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + //info.si_code = TARGET_ILL_ILLADR; + break; + case 0x08000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_ACCERR; + break; + default: + /* Let's send a regular segfault... */ + EXCP_DUMP(env, "Invalid segfault errno (%02x)\n", + env->error_code); + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + } + //info._sifields._sigfault._addr = env->nip; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx + "\n", env->spr[SPR_SRR0]); + /* XXX: check this */ + switch (env->error_code & 0xFF000000) { + case 0x40000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + case 0x10000000: + case 0x08000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_ACCERR; + break; + default: + /* Let's send a regular segfault... */ + EXCP_DUMP(env, "Invalid segfault errno (%02x)\n", + env->error_code); + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + } + //info._sifields._sigfault._addr = env->nip - 4; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_EXTERNAL: /* External input */ + cpu_abort(env, "External interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + EXCP_DUMP(env, "Unaligned memory access\n"); + /* XXX: check this */ + info.si_signo = TARGET_SIGBUS; + info.si_errno = 0; + //info.si_code = TARGET_BUS_ADRALN; + //info._sifields._sigfault._addr = env->nip - 4; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_PROGRAM: /* Program exception */ + /* XXX: check this */ + switch (env->error_code & ~0xF) { + case POWERPC_EXCP_FP: + EXCP_DUMP(env, "Floating point program exception\n"); + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + /* switch (env->error_code & 0xF) { + case POWERPC_EXCP_FP_OX: + info.si_code = TARGET_FPE_FLTOVF; + break; + case POWERPC_EXCP_FP_UX: + info.si_code = TARGET_FPE_FLTUND; + break; + case POWERPC_EXCP_FP_ZX: + case POWERPC_EXCP_FP_VXZDZ: + info.si_code = TARGET_FPE_FLTDIV; + break; + case POWERPC_EXCP_FP_XX: + info.si_code = TARGET_FPE_FLTRES; + break; + case POWERPC_EXCP_FP_VXSOFT: + info.si_code = TARGET_FPE_FLTINV; + break; + case POWERPC_EXCP_FP_VXSNAN: + case POWERPC_EXCP_FP_VXISI: + case POWERPC_EXCP_FP_VXIDI: + case POWERPC_EXCP_FP_VXIMZ: + case POWERPC_EXCP_FP_VXVC: + case POWERPC_EXCP_FP_VXSQRT: + case POWERPC_EXCP_FP_VXCVI: + info.si_code = TARGET_FPE_FLTSUB; + break; + default: + EXCP_DUMP(env, "Unknown floating point exception (%02x)\n", + env->error_code); + break; + } */ + break; + case POWERPC_EXCP_INVAL: + EXCP_DUMP(env, "Invalid instruction\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case POWERPC_EXCP_INVAL_INVAL: + //info.si_code = TARGET_ILL_ILLOPC; + break; + case POWERPC_EXCP_INVAL_LSWX: + //info.si_code = TARGET_ILL_ILLOPN; + break; + case POWERPC_EXCP_INVAL_SPR: + //info.si_code = TARGET_ILL_PRVREG; + break; + case POWERPC_EXCP_INVAL_FP: + //info.si_code = TARGET_ILL_COPROC; + break; + default: + EXCP_DUMP(env, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + //info.si_code = TARGET_ILL_ILLADR; + break; + } + break; + case POWERPC_EXCP_PRIV: + EXCP_DUMP(env, "Privilege violation\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case POWERPC_EXCP_PRIV_OPC: + //info.si_code = TARGET_ILL_PRVOPC; + break; + case POWERPC_EXCP_PRIV_REG: + //info.si_code = TARGET_ILL_PRVREG; + break; + default: + EXCP_DUMP(env, "Unknown privilege violation (%02x)\n", + env->error_code & 0xF); + //info.si_code = TARGET_ILL_PRVOPC; + break; + } + break; + case POWERPC_EXCP_TRAP: + cpu_abort(env, "Tried to call a TRAP\n"); + break; + default: + /* Should not happen ! */ + cpu_abort(env, "Unknown program exception (%02x)\n", + env->error_code); + break; + } + //info._sifields._sigfault._addr = env->nip - 4; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ + EXCP_DUMP(env, "No floating point allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + //info.si_code = TARGET_ILL_COPROC; + //info._sifields._sigfault._addr = env->nip - 4; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_SYSCALL: /* System call exception */ + cpu_abort(env, "Syscall exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ + EXCP_DUMP(env, "No APU instruction allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + //info.si_code = TARGET_ILL_COPROC; + //info._sifields._sigfault._addr = env->nip - 4; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_DECR: /* Decrementer exception */ + cpu_abort(env, "Decrementer interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + cpu_abort(env, "Fix interval timer interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + cpu_abort(env, "Watchdog timer interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DTLB: /* Data TLB error */ + cpu_abort(env, "Data TLB exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ITLB: /* Instruction TLB error */ + cpu_abort(env, "Instruction TLB exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */ + EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + //info.si_code = TARGET_ILL_COPROC; + //info._sifields._sigfault._addr = env->nip - 4; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ + cpu_abort(env, "Embedded floating-point data IRQ not handled\n"); + break; + case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */ + cpu_abort(env, "Embedded floating-point round IRQ not handled\n"); + break; + case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */ + cpu_abort(env, "Performance monitor exception not handled\n"); + break; + case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ + cpu_abort(env, "Doorbell interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ + cpu_abort(env, "Doorbell critical interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_RESET: /* System reset exception */ + cpu_abort(env, "Reset interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DSEG: /* Data segment exception */ + cpu_abort(env, "Data segment exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ISEG: /* Instruction segment exception */ + cpu_abort(env, "Instruction segment exception " + "while in user mode. Aborting\n"); + break; + /* PowerPC 64 with hypervisor mode support */ + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ + cpu_abort(env, "Hypervisor decrementer interrupt " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_TRACE: /* Trace exception */ + /* Nothing to do: + * we use this exception to emulate step-by-step execution mode. + */ + break; + /* PowerPC 64 with hypervisor mode support */ + case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ + cpu_abort(env, "Hypervisor data storage exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */ + cpu_abort(env, "Hypervisor instruction storage exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ + cpu_abort(env, "Hypervisor data segment exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */ + cpu_abort(env, "Hypervisor instruction segment exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_VPU: /* Vector unavailable exception */ + EXCP_DUMP(env, "No Altivec instructions allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + //info.si_code = TARGET_ILL_COPROC; + //info._sifields._sigfault._addr = env->nip - 4; + queue_signal(env, info.si_signo, &info); + break; + case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ + cpu_abort(env, "Programmable interval timer interrupt " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_IO: /* IO error exception */ + cpu_abort(env, "IO error exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_RUNM: /* Run mode exception */ + cpu_abort(env, "Run mode exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_EMUL: /* Emulation trap exception */ + cpu_abort(env, "Emulation trap exception not handled\n"); + break; + case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ + cpu_abort(env, "Instruction fetch TLB exception " + "while in user-mode. Aborting"); + break; + case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ + cpu_abort(env, "Data load TLB exception while in user-mode. " + "Aborting"); + break; + case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ + cpu_abort(env, "Data store TLB exception while in user-mode. " + "Aborting"); + break; + case POWERPC_EXCP_FPA: /* Floating-point assist exception */ + cpu_abort(env, "Floating-point assist exception not handled\n"); + break; + case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ + cpu_abort(env, "Instruction address breakpoint exception " + "not handled\n"); + break; + case POWERPC_EXCP_SMI: /* System management interrupt */ + cpu_abort(env, "System management interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_THERM: /* Thermal interrupt */ + cpu_abort(env, "Thermal interrupt interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */ + cpu_abort(env, "Performance monitor exception not handled\n"); + break; + case POWERPC_EXCP_VPUA: /* Vector assist exception */ + cpu_abort(env, "Vector assist exception not handled\n"); + break; + case POWERPC_EXCP_SOFTP: /* Soft patch exception */ + cpu_abort(env, "Soft patch exception not handled\n"); + break; + case POWERPC_EXCP_MAINT: /* Maintenance exception */ + cpu_abort(env, "Maintenance exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_STOP: /* stop translation */ + /* We did invalidate the instruction cache. Go on */ + break; + case POWERPC_EXCP_BRANCH: /* branch instruction: */ + /* We just stopped because of a branch. Go on */ + break; + case POWERPC_EXCP_SYSCALL_USER: + /* system call in user-mode emulation */ + /* WARNING: + * PPC ABI uses overflow flag in cr0 to signal an error + * in syscalls. + */ + env->crf[0] &= ~0x1; + ret = do_freebsd_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], 0, 0); + if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) { + /* Returning from a successful sigreturn syscall. + Avoid corrupting register state. */ + break; + } + if (ret > (target_ulong)(-515)) { + env->crf[0] |= 0x1; + ret = -ret; + } + env->gpr[3] = ret; + break; + case POWERPC_EXCP_STCX: + if (do_store_exclusive(env)) { + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + //info._sifields._sigfault._addr = env->nip; + queue_signal(env, info.si_signo, &info); + } + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, info.si_signo, &info); + } + } + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + default: + cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr); + break; + } + process_pending_signals(env); + } +} +#endif + #ifdef TARGET_ARM // #define DEBUG_ARM @@ -1720,9 +2251,16 @@ int main(int argc, char **argv) #else cpu_model = "Fujitsu MB86904"; #endif +#elif defined(TARGET_PPC) +#ifdef TARGET_PPC64 + cpu_model = "970fx"; +#else + cpu_model = "750"; +#endif #else cpu_model = "any"; #endif + } tcg_exec_init(0); cpu_exec_init_all(); @@ -1973,6 +2511,18 @@ int main(int argc, char **argv) env->hflags |= MIPS_HFLAG_UX | MIPS_HFLAG_64; #endif } +#elif defined(TARGET_PPC) + { + int i; + +#if defined(TARGET_PPC64) + env->msr |= (target_ulong)1 << MSR_SF; +#endif + env->nip = regs->pc; + for(i = 0; i < 32; i++) { + env->gpr[i] = regs->gpr[i]; + } + } #else #error unsupported target CPU #endif diff --git a/work/qemu-1.4.0/bsd-user/ppc/syscall.h b/work/qemu-1.4.0/bsd-user/ppc/syscall.h new file mode 100644 index 0000000..bd551be --- /dev/null +++ b/work/qemu-1.4.0/bsd-user/ppc/syscall.h @@ -0,0 +1,17 @@ +/* This struct defines the way the registers are stored on the + * stack during a system call. + */ +struct target_pt_regs { + abi_ulong gpr[32]; + abi_ulong link; + abi_ulong cr; + abi_ulong xer; + abi_ulong ctr; + abi_ulong pc; /* nip */ +}; + +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) +#define UNAME_MACHINE "powerpc64" +#else +#define UNAME_MACHINE "powerpc" +#endif diff --git a/work/qemu-1.4.0/bsd-user/ppc/target_signal.h b/work/qemu-1.4.0/bsd-user/ppc/target_signal.h new file mode 100644 index 0000000..5a7a2ed --- /dev/null +++ b/work/qemu-1.4.0/bsd-user/ppc/target_signal.h @@ -0,0 +1,215 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +#define TARGET_MC_VERSION 0x1 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +/* see powerpc/include/ucontext.h */ +struct target_mcontext { + int mc_vers; + int mc_flags; +#define TARGET_MC_FP_VALID 0x01 +#define TARGET_MC_AV_VALID 0x02 + int mc_onstack; /* saved onstack flag */ + int mc_len; /* sizeof(__mcontext) */ + uint64_t mc_avec[32*2]; /* vector register file */ + uint32_t mc_av[2]; + register_t mc_frame[42]; + uint64_t mc_fpreg[33]; +} __aligned(16); + +/* GPRs and supervisor-level regs */ +#define mc_gpr mc_frame +#define mc_lr mc_frame[32] +#define mc_cr mc_frame[33] +#define mc_xer mc_frame[34] +#define mc_ctr mc_frame[35] +#define mc_srr0 mc_frame[36] +#define mc_srr1 mc_frame[37] +#define mc_exc mc_frame[38] +#define mc_dar mc_frame[39] +#define mc_dsisr mc_frame[40] + +/* floating-point state */ +#define mc_fpscr mc_fpreg[32] + +/* altivec state */ +#define mc_vscr mc_av[0] +#define mc_vrsave mc_av[1] + +typedef struct target_mcontext target_mcontext_t; + +/* see sys/ucontext.h */ +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +/* see powerpc/include/sigframe.h */ +struct target_sigframe { + target_ucontext_t sf_uc; + target_siginfo_t sf_si; +}; + +/* see powerpc/include/frame.h */ +typedef struct target_trapframe { + abi_ulong fixreg[32]; + abi_ulong lr; + abi_ulong cr; + abi_ulong xer; + abi_ulong ctr; + abi_ulong srr0; + abi_ulong srr1; + abi_ulong exc; + union { + struct { + /* dar & dsisr are only filled on a DSI trap */ + abi_ulong dar; + abi_ulong dsisr; + } aim; + struct { + abi_ulong dear; + abi_ulong esr; + abi_ulong dbcr0; + } booke; + } cpu; +} target_trapframe_t; + +static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state) +{ + return state->gpr[1]; +} + + +static inline int +grab_mcontext(CPUPPCState *regs, target_mcontext_t *mcp, int flags) +{ + /* To be completed. ATO */ + int i; + + memset(mcp, 0, sizeof(target_mcontext_t)); + + mcp->mc_vers = TARGET_MC_VERSION; + mcp->mc_flags = 0; + + for(i = 1; i < 32; i++) + mcp->mc_gpr[i] = tswapal(regs->gpr[i]); + + if (flags & TARGET_MC_GET_CLEAR_RET) { + mcp->mc_gpr[3] = 0; + mcp->mc_gpr[4] = 0; + } + + + /* + * This assumes that floating-point context is *not* lazy, + * so if the thread has used FP there would have been a + * FP-unavailable exception that would have set things up + * correctly. + */ + + /* todo save_fpu(td); */ + + mcp->mc_flags |= TARGET_MC_FP_VALID; + memcpy(&mcp->mc_fpscr, ®s->fpscr, sizeof(double)); + memcpy(mcp->mc_fpreg, regs->fpr, 32*sizeof(double)); + /* Altivec todo */ + + mcp->mc_len = sizeof(*mcp); + + return (0); +} + + +/* compare to powerpc/powerpc/exec_machdep.c get_mcontext() */ +static inline int +get_mcontext(CPUPPCState *regs, target_mcontext_t *mcp, int flags) +{ + /* To be completed. ATO */ + qemu_log("qemu: %s: \n", __func__); + + int error; + + error = grab_mcontext(regs, mcp, flags); + if (error == 0) { + mcp->mc_onstack = tswapal(regs->gpr[1]); + } else { + mcp->mc_onstack = 0; + } + + return (error); + +} + +/* compare to powerpc/powerpc/exec_machdep.c set_mcontext() */ +static inline int +set_mcontext(CPUPPCState *regs, target_mcontext_t *mcp, int flags) +{ + /* To be completed. ATO */ + qemu_log("qemu: %s: \n", __func__); + + int i; + for(i = 1; i < 32; i++) + regs->gpr[i] = tswapal(mcp->mc_gpr[i]); + return (0); +} +/* powerpc/powerpc/machdep.c sys_sigreturn() */ +static inline abi_long +get_ucontext_sigreturn(CPUPPCState *regs, abi_ulong uc_addr, + target_ucontext_t **ucontext, void **locked_addr) +{ + /* To be completed. ATO */ + qemu_log("qemu: %s: \n", __func__); + *locked_addr = *ucontext; + return (0); +} + +/* + * Compare to powerpc/powerpc/exec_machdep.c sendsig() + */ +static inline abi_long +set_sigtramp_args(CPUPPCState *regs, int sig, struct target_sigframe *frame, + abi_ulong frame_addr, struct target_sigaction *ka) +{ + qemu_log("qemu: %s: \n", __func__); + + /* To be completed. ATO */ + + /* + * Set up the registers to return to sigcode. + * + * r1/sp - sigframe ptr + * lr - sig function, dispatched to by blrl in trampoline + * r3 - sig number + * r4 - SIGINFO ? &siginfo : exception code + * r5 - user context + * srr0 - trampoline function addr + */ + + return(0); +} + +/* Compare to powerpc/powerpc/vm_machdep.c cpu_set_upcall_kse() */ +static inline void +thread_set_upcall(CPUPPCState *regs, abi_ulong entry, + abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size) +{ + qemu_log("qemu: %s: \n", __func__); + /* To be completed. ATO */ + + abi_ulong sp; + sp = ((stack_base + stack_size) & ~0x15); + regs->nip = entry; + regs->gpr[3] = arg; + regs->gpr[1] = sp; +} + +#endif /* TARGET_SIGNAL_H */ diff --git a/work/qemu-1.4.0/bsd-user/ppc/target_vmparam.h b/work/qemu-1.4.0/bsd-user/ppc/target_vmparam.h new file mode 100644 index 0000000..a29369d --- /dev/null +++ b/work/qemu-1.4.0/bsd-user/ppc/target_vmparam.h @@ -0,0 +1,44 @@ +#ifndef _TARGET_VMPARAM_H_ +#define _TARGET_VMPARAM_H_ + +#if defined(__FreeBSD__) +#define TARGET_HW_MACHINE "powerpc" + +#define TARGET_MAXTSIZ (64*1024*1024) /* max text size */ +#define TARGET_DFLDSIZ (128*1024*1024) /* default data size */ +#define TARGET_MAXDSIZ (1*1024*1024*1024) /* max data size */ +#define TARGET_DFLSSIZ (8*1024*1024) /* default stack size */ +#define TARGET_MAXSSIZ (64*1024*1024) /* max stack size */ +#define TARGET_SGROWSIZ (128UL*1024) /* amount to grow stack */ + +#if defined(TARGET_PPC64) +#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL) +#define TARGET_VM_MAXUSER_ADDRESS (0x00007fffff000000UL) +#define TARGET_HW_MACHINE_ARCH "powerpc64" +#else +#define TARGET_VM_MINUSER_ADDRESS (0x00000000) +#define TARGET_VM_MAXUSER_ADDRESS (0xfffff000) +#define TARGET_HW_MACHINE_ARCH "powerpc" +#endif + +#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE + +struct target_ps_strings { + abi_ulong ps_argvstr; + uint32_t ps_nargvstr; + abi_ulong ps_envstr; + uint32_t ps_nenvstr; +}; + +#define TARGET_SPACE_USRSPACE 4096 +#define TARGET_ARG_MAX 262144 + +#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) + +#define TARGET_SZSIGCODE 0 +#else /* __FreeBSD__ */ + +#define TARGET_USRSTACK 0 +#endif +#endif /* _TARGET_VMPARAM_H_ */ + diff --git a/work/qemu-1.4.0/bsd-user/signal.c b/work/qemu-1.4.0/bsd-user/signal.c index a26d40a..9daa5f6 100644 --- a/work/qemu-1.4.0/bsd-user/signal.c +++ b/work/qemu-1.4.0/bsd-user/signal.c @@ -619,7 +619,8 @@ do_sigaction(int sig, const struct target_sigaction *act, return (ret); } -#if defined(TARGET_MIPS64) || defined(TARGET_ARM) +/* To be completed for PPC. ATO */ +#if defined(TARGET_MIPS64) || defined(TARGET_ARM) || defined(TARGET_PPC) static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size) diff --git a/work/qemu-1.4.0/bsd-user/syscall.c b/work/qemu-1.4.0/bsd-user/syscall.c index 490227c..e19eeb9 100644 --- a/work/qemu-1.4.0/bsd-user/syscall.c +++ b/work/qemu-1.4.0/bsd-user/syscall.c @@ -403,6 +403,15 @@ static abi_long do_freebsd_sysarch(CPUMIPSState *env, int op, abi_ulong parms) } #endif +#ifdef TARGET_PPC +static abi_long do_freebsd_sysarch(CPUPPCState *env, int op, abi_ulong parms) +{ + qemu_log("qemu: TODO !!! do_freebsd_sysarch: %d\n", op); + + return -TARGET_EINVAL; +} +#endif + #ifdef __FreeBSD__ extern int _getlogin(char *, int); @@ -581,9 +590,30 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol ret = 0; goto out; + case HW_NCPU: + /* For now we have only one cpu. */ + (*(uint32_t *)holdp) = tswap32(1); + holdlen = sizeof(uint32_t); + ret = 0; + goto out; + default: break; } + case CTL_MACHDEP: + switch(snamep[1]) { + /* Fix me ATO + * CPU_CACHELINE frm powerpc/include/cpu.h + * for now I set it to 32. + */ + case 1: + (*(abi_ulong *)holdp) = tswap32(32); + holdlen = sizeof(abi_ulong); + ret = 0; + goto out; + default: + break; + } default: break; @@ -1237,6 +1267,11 @@ regpairs_aligned(void *cpu_env) { #elif defined(TARGET_MIPS) && TARGET_ABI_BITS == 32 static inline int regpairs_aligned(void *cpu_env) { return 1; } +#elif defined(TARGET_PPC) && !defined(TARGET_PPC64) +/* SysV ABI for PPC32 expects 64bit parameters to be passed on odd/even pairs + * of registers which translates to the same as ARM/MIPS, because we start with + * r3 as arg1. */ +static inline int regpairs_aligned(void *cpu_env) { return 1; } #else static inline int regpairs_aligned(void *cpu_env) { return 0; } @@ -2509,6 +2544,8 @@ set_second_rval(CPUArchState *env, abi_ulong retval2) ((CPUX86State*)env)->regs[R_EDX] = retval2; #elif defined(TARGET_SPARC64) || defined(TARGET_SPARC) ((CPUSPARCState*)env)->regwptr[1] = retval2; +#elif defined(TARGET_PPC) + ((CPUPPCState *)env)->gpr[4] = retval2; #else #warning Arch not supported for returning multiple values from syscall. #endif @@ -2713,7 +2750,8 @@ do_thr_new(CPUArchState *env, abi_ulong target_param_addr, int32_t param_size) ts->bprm = parent_ts->bprm; ts->info = parent_ts->info; -#if defined(TARGET_MIPS) || defined(TARGET_ARM) + /* PPC ?? ATO */ +#if defined(TARGET_MIPS) || defined(TARGET_ARM) || defined (TARGET_PPC) cpu_set_tls(env, info.param.tls_base); #endif diff --git a/work/qemu-1.4.0/configure b/work/qemu-1.4.0/configure index 6d17c97..02a95d0 100755 --- a/work/qemu-1.4.0/configure +++ b/work/qemu-1.4.0/configure @@ -1004,6 +1004,8 @@ armeb-bsd-user \ mips-bsd-user \ mipsel-bsd-user \ mips64-bsd-user \ +ppc-bsd-user \ +ppc64-bsd-user \ " fi @@ -3726,7 +3728,7 @@ linux) echo "HOST_USB=linux" >> $config_host_mak ;; bsd) - echo "HOST_USB=bsd" >> $config_host_mak + echo "HOST_USB=stub" >> $config_host_mak ;; *) echo "HOST_USB=stub" >> $config_host_mak diff --git a/work/qemu-1.4.0/default-configs/ppc-bsd-user.mak b/work/qemu-1.4.0/default-configs/ppc-bsd-user.mak new file mode 100644 index 0000000..794b621 --- /dev/null +++ b/work/qemu-1.4.0/default-configs/ppc-bsd-user.mak @@ -0,0 +1,2 @@ +# Default configuration for ppc-bsd-user +CONFIG_GDBSTUB_XML=y diff --git a/work/qemu-1.4.0/default-configs/ppc64-bsd-user.mak b/work/qemu-1.4.0/default-configs/ppc64-bsd-user.mak new file mode 100644 index 0000000..a21c79d --- /dev/null +++ b/work/qemu-1.4.0/default-configs/ppc64-bsd-user.mak @@ -0,0 +1,2 @@ +# Default configuration for ppc64-bsd-user +CONFIG_GDBSTUB_XML=y