diff --git a/include/unicorn/ppc.h b/include/unicorn/ppc.h index 14a20498..5705ffff 100644 --- a/include/unicorn/ppc.h +++ b/include/unicorn/ppc.h @@ -370,6 +370,54 @@ typedef enum uc_ppc_reg { UC_PPC_REG_29, UC_PPC_REG_30, UC_PPC_REG_31, + + UC_PPC_REG_CR0, + UC_PPC_REG_CR1, + UC_PPC_REG_CR2, + UC_PPC_REG_CR3, + UC_PPC_REG_CR4, + UC_PPC_REG_CR5, + UC_PPC_REG_CR6, + UC_PPC_REG_CR7, + + UC_PPC_REG_FPR0, + UC_PPC_REG_FPR1, + UC_PPC_REG_FPR2, + UC_PPC_REG_FPR3, + UC_PPC_REG_FPR4, + UC_PPC_REG_FPR5, + UC_PPC_REG_FPR6, + UC_PPC_REG_FPR7, + UC_PPC_REG_FPR8, + UC_PPC_REG_FPR9, + UC_PPC_REG_FPR10, + UC_PPC_REG_FPR11, + UC_PPC_REG_FPR12, + UC_PPC_REG_FPR13, + UC_PPC_REG_FPR14, + UC_PPC_REG_FPR15, + UC_PPC_REG_FPR16, + UC_PPC_REG_FPR17, + UC_PPC_REG_FPR18, + UC_PPC_REG_FPR19, + UC_PPC_REG_FPR20, + UC_PPC_REG_FPR21, + UC_PPC_REG_FPR22, + UC_PPC_REG_FPR23, + UC_PPC_REG_FPR24, + UC_PPC_REG_FPR25, + UC_PPC_REG_FPR26, + UC_PPC_REG_FPR27, + UC_PPC_REG_FPR28, + UC_PPC_REG_FPR29, + UC_PPC_REG_FPR30, + UC_PPC_REG_FPR31, + + UC_PPC_REG_LR, + UC_PPC_REG_XER, + UC_PPC_REG_CTR, + UC_PPC_REG_MSR, + UC_PPC_REG_FPSCR } uc_ppc_reg; #ifdef __cplusplus diff --git a/qemu/target/ppc/translate_init.inc.c b/qemu/target/ppc/translate_init.inc.c index 65956ad1..920ea602 100644 --- a/qemu/target/ppc/translate_init.inc.c +++ b/qemu/target/ppc/translate_init.inc.c @@ -11196,5 +11196,7 @@ PowerPCCPU *cpu_ppc_init(struct uc_struct *uc) qemu_init_vcpu(cs); + ppc_cpu_reset((CPUState *)cpu); + return cpu; } diff --git a/qemu/target/ppc/unicorn.c b/qemu/target/ppc/unicorn.c index d8d50d57..52737f76 100644 --- a/qemu/target/ppc/unicorn.c +++ b/qemu/target/ppc/unicorn.c @@ -9,6 +9,8 @@ #include "unicorn_common.h" #include "uc_priv.h" #include "unicorn.h" +#include "helper_regs.h" +#include "cpu.h" #ifdef TARGET_PPC64 typedef uint64_t ppcreg_t; @@ -16,6 +18,65 @@ typedef uint64_t ppcreg_t; typedef uint32_t ppcreg_t; #endif +// Unicorn version to ensure writing MSR without exception +static inline int uc_ppc_store_msr(CPUPPCState *env, target_ulong value, + int alter_hv) +{ + // int excp; + // CPUState *cs = env_cpu(env); + + // excp = 0; + value &= env->msr_mask; + + /* Neither mtmsr nor guest state can alter HV */ + if (!alter_hv || !(env->msr & MSR_HVB)) { + value &= ~MSR_HVB; + value |= env->msr & MSR_HVB; + } + if (((value >> MSR_IR) & 1) != msr_ir || + ((value >> MSR_DR) & 1) != msr_dr) { + // cpu_interrupt_exittb(cs); + } + if ((env->mmu_model & POWERPC_MMU_BOOKE) && + ((value >> MSR_GS) & 1) != msr_gs) { + // cpu_interrupt_exittb(cs); + } + if (unlikely((env->flags & POWERPC_FLAG_TGPR) && + ((value ^ env->msr) & (1 << MSR_TGPR)))) { + /* Swap temporary saved registers with GPRs */ + hreg_swap_gpr_tgpr(env); + } + if (unlikely((value >> MSR_EP) & 1) != msr_ep) { + /* Change the exception prefix on PowerPC 601 */ + env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + } + /* + * If PR=1 then EE, IR and DR must be 1 + * + * Note: We only enforce this on 64-bit server processors. + * It appears that: + * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS + * exploits it. + * - 64-bit embedded implementations do not need any operation to be + * performed when PR is set. + */ + if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { + value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); + } + + env->msr = value; + hreg_compute_hflags(env); + + // if (unlikely(msr_pow == 1)) { + // if (!env->pending_interrupts && (*env->check_pow)(env)) { + // cs->halted = 1; + // excp = EXCP_HALTED; + // } + // } + + return 0; +} + static uint64_t ppc_mem_redirect(uint64_t address) { /* // kseg0 range masks off high address bit @@ -79,6 +140,7 @@ void ppc_reg_reset(struct uc_struct *uc) env->nip = 0; } +// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Motorola_PowerPC/PowerPc/GenInfo/pemch2.pdf static void reg_read(CPUPPCState *env, unsigned int regid, void *value) { if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31) @@ -90,12 +152,65 @@ static void reg_read(CPUPPCState *env, unsigned int regid, void *value) case UC_PPC_REG_PC: *(ppcreg_t *)value = env->nip; break; - /* case UC_PPC_REG_CP0_CONFIG3: - *(mipsreg_t *)value = env->CP0_Config3; - break; - case UC_MIPS_REG_CP0_USERLOCAL: - *(mipsreg_t *)value = env->active_tc.CP0_UserLocal; - break; */ + case UC_PPC_REG_FPR0: + case UC_PPC_REG_FPR1: + case UC_PPC_REG_FPR2: + case UC_PPC_REG_FPR3: + case UC_PPC_REG_FPR4: + case UC_PPC_REG_FPR5: + case UC_PPC_REG_FPR6: + case UC_PPC_REG_FPR7: + case UC_PPC_REG_FPR8: + case UC_PPC_REG_FPR9: + case UC_PPC_REG_FPR10: + case UC_PPC_REG_FPR11: + case UC_PPC_REG_FPR12: + case UC_PPC_REG_FPR13: + case UC_PPC_REG_FPR14: + case UC_PPC_REG_FPR15: + case UC_PPC_REG_FPR16: + case UC_PPC_REG_FPR17: + case UC_PPC_REG_FPR18: + case UC_PPC_REG_FPR19: + case UC_PPC_REG_FPR20: + case UC_PPC_REG_FPR21: + case UC_PPC_REG_FPR22: + case UC_PPC_REG_FPR23: + case UC_PPC_REG_FPR24: + case UC_PPC_REG_FPR25: + case UC_PPC_REG_FPR26: + case UC_PPC_REG_FPR27: + case UC_PPC_REG_FPR28: + case UC_PPC_REG_FPR29: + case UC_PPC_REG_FPR30: + case UC_PPC_REG_FPR31: + *(uint64_t *)value = env->vsr[regid - UC_PPC_REG_FPR0].VsrD(0); + break; + case UC_PPC_REG_CR0: + case UC_PPC_REG_CR1: + case UC_PPC_REG_CR2: + case UC_PPC_REG_CR3: + case UC_PPC_REG_CR4: + case UC_PPC_REG_CR5: + case UC_PPC_REG_CR6: + case UC_PPC_REG_CR7: + *(uint32_t *)value = env->crf[regid - UC_PPC_REG_CR0]; + break; + case UC_PPC_REG_LR: + *(ppcreg_t *)value = env->lr; + break; + case UC_PPC_REG_CTR: + *(ppcreg_t *)value = env->ctr; + break; + case UC_PPC_REG_MSR: + *(ppcreg_t *)value = env->msr; + break; + case UC_PPC_REG_XER: + *(uint32_t *)value = env->xer; + break; + case UC_PPC_REG_FPSCR: + *(uint32_t *)value = env->fpscr; + break; } } @@ -113,12 +228,65 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value) case UC_PPC_REG_PC: env->nip = *(ppcreg_t *)value; break; - /* case UC_MIPS_REG_CP0_CONFIG3: - env->CP0_Config3 = *(mipsreg_t *)value; - break; - case UC_MIPS_REG_CP0_USERLOCAL: - env->active_tc.CP0_UserLocal = *(mipsreg_t *)value; - break; */ + case UC_PPC_REG_FPR0: + case UC_PPC_REG_FPR1: + case UC_PPC_REG_FPR2: + case UC_PPC_REG_FPR3: + case UC_PPC_REG_FPR4: + case UC_PPC_REG_FPR5: + case UC_PPC_REG_FPR6: + case UC_PPC_REG_FPR7: + case UC_PPC_REG_FPR8: + case UC_PPC_REG_FPR9: + case UC_PPC_REG_FPR10: + case UC_PPC_REG_FPR11: + case UC_PPC_REG_FPR12: + case UC_PPC_REG_FPR13: + case UC_PPC_REG_FPR14: + case UC_PPC_REG_FPR15: + case UC_PPC_REG_FPR16: + case UC_PPC_REG_FPR17: + case UC_PPC_REG_FPR18: + case UC_PPC_REG_FPR19: + case UC_PPC_REG_FPR20: + case UC_PPC_REG_FPR21: + case UC_PPC_REG_FPR22: + case UC_PPC_REG_FPR23: + case UC_PPC_REG_FPR24: + case UC_PPC_REG_FPR25: + case UC_PPC_REG_FPR26: + case UC_PPC_REG_FPR27: + case UC_PPC_REG_FPR28: + case UC_PPC_REG_FPR29: + case UC_PPC_REG_FPR30: + case UC_PPC_REG_FPR31: + env->vsr[regid - UC_PPC_REG_FPR0].VsrD(0) = *(uint64_t *)value; + break; + case UC_PPC_REG_CR0: + case UC_PPC_REG_CR1: + case UC_PPC_REG_CR2: + case UC_PPC_REG_CR3: + case UC_PPC_REG_CR4: + case UC_PPC_REG_CR5: + case UC_PPC_REG_CR6: + case UC_PPC_REG_CR7: + env->crf[regid - UC_PPC_REG_CR0] = *(uint32_t *)value; + break; + case UC_PPC_REG_LR: + env->lr = *(ppcreg_t *)value; + break; + case UC_PPC_REG_CTR: + env->ctr = *(ppcreg_t *)value; + break; + case UC_PPC_REG_MSR: + uc_ppc_store_msr(env, *(ppcreg_t *)value, 0); + break; + case UC_PPC_REG_XER: + env->xer = *(uint32_t *)value; + break; + case UC_PPC_REG_FPSCR: + store_fpscr(env, *(uint32_t *)value, 0xffffffff); + break; } } diff --git a/tests/unit/test_ppc.c b/tests/unit/test_ppc.c index 41fed7c4..21ba64fa 100644 --- a/tests/unit/test_ppc.c +++ b/tests/unit/test_ppc.c @@ -34,4 +34,35 @@ static void test_ppc32_add() OK(uc_close(uc)); } -TEST_LIST = {{"test_ppc32_add", test_ppc32_add}, {NULL, NULL}}; \ No newline at end of file +// https://www.ibm.com/docs/en/aix/7.2?topic=set-fadd-fa-floating-add-instruction +static void test_ppc32_fadd() +{ + uc_engine *uc; + char code[] = "\xfc\xc4\x28\x2a"; // fadd 6, 4, 5 + uint32_t r_msr; + uint64_t r_fpr4, r_fpr5, r_fpr6; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_32 | UC_MODE_BIG_ENDIAN, code, + sizeof(code) - 1); + + OK(uc_reg_read(uc, UC_PPC_REG_MSR, &r_msr)); + r_msr |= (1 << 13); // Big endian + OK(uc_reg_write(uc, UC_PPC_REG_MSR, &r_msr)); // enable FP + + r_fpr4 = 0xC053400000000000ul; + r_fpr5 = 0x400C000000000000ul; + OK(uc_reg_write(uc, UC_PPC_REG_FPR4, &r_fpr4)); + OK(uc_reg_write(uc, UC_PPC_REG_FPR5, &r_fpr5)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_PPC_REG_FPR6, &r_fpr6)); + + TEST_CHECK(r_fpr6 == 0xC052600000000000ul); + + OK(uc_close(uc)); +} + +TEST_LIST = {{"test_ppc32_add", test_ppc32_add}, + {"test_ppc32_fadd", test_ppc32_fadd}, + {NULL, NULL}}; \ No newline at end of file