diff --git a/linux-user/e2k/cpu_loop.c b/linux-user/e2k/cpu_loop.c index fd720f62eb..cfe5952226 100644 --- a/linux-user/e2k/cpu_loop.c +++ b/linux-user/e2k/cpu_loop.c @@ -25,6 +25,8 @@ #include "user-mmap.h" #include "cpu_loop-common.h" +void helper_return(CPUE2KState *env); + void cpu_loop(CPUE2KState *env) { CPUState *cs = env_cpu(env); @@ -39,34 +41,32 @@ void cpu_loop(CPUE2KState *env) switch (trapnr) { case E2K_EXCP_SYSCALL: { - int offset = E2K_NR_COUNT + env->wd.base + env->syscall_wbs * 2; - uint64_t *regs = env->regs; - abi_ulong ret = do_syscall(env, - regs[(0 + offset) % E2K_NR_COUNT], - regs[(1 + offset) % E2K_NR_COUNT], - regs[(2 + offset) % E2K_NR_COUNT], - regs[(3 + offset) % E2K_NR_COUNT], - regs[(4 + offset) % E2K_NR_COUNT], - regs[(5 + offset) % E2K_NR_COUNT], - regs[(6 + offset) % E2K_NR_COUNT], - regs[(7 + offset) % E2K_NR_COUNT], - regs[(8 + offset) % E2K_NR_COUNT] - ); + abi_long args[10] = { 0 }; + int psize = env->wd.psize <= 10 ? env->wd.psize : 10; + int i; + + for (i = 0; i < psize; i++) { + args[i] = env->regs[e2k_wrap_reg_index(env->wd.base + i)]; + } + + abi_ulong ret = do_syscall(env, args[0], args[1], args[2], args[3], + args[4], args[5], args[6], args[7], args[8]); + if (ret == -TARGET_ERESTARTSYS) { /* TODO: restart syscall */ abort(); - } else if (ret != -TARGET_QEMU_ESIGRETURN) { - unsigned int i; + } else if (env->wd.psize > 0 && ret != -TARGET_QEMU_ESIGRETURN) { + env->regs[env->wd.base] = ret; + env->tags[env->wd.base] = 0; - env->regs[offset % E2K_NR_COUNT] = ret; - env->tags[offset % E2K_NR_COUNT] = 0; - - for (i = 1; i < 8; i++) { - int idx = (offset + i) % E2K_NR_COUNT; - env->regs[idx] = 0; - env->tags[idx] = E2K_TAG_NON_NUMBER64; + for (i = 1; i < env->wd.psize; i++) { + int index = e2k_wrap_reg_index(env->wd.base + i); + env->regs[index] = 0; + env->tags[index] = E2K_TAG_NON_NUMBER64; } } + // FIXME: Can call helpers from here? + helper_return(env); break; } case E2K_EXCP_ILLOPC: @@ -129,4 +129,7 @@ void target_cpu_copy_regs(CPUE2KState *env, struct target_pt_regs *regs) env->sbr = regs->sbr; e2k_break_save_state(env); + + env->pcs_base = env->pcsp.base; + env->ps_base = env->psp.base; } diff --git a/linux-user/e2k/target_structs.h b/linux-user/e2k/target_structs.h index 888c836b47..1b9b7baf6d 100644 --- a/linux-user/e2k/target_structs.h +++ b/linux-user/e2k/target_structs.h @@ -25,4 +25,17 @@ struct target_shmid_ds { void *shm_unused3; }; +struct target_jmp_info { + abi_ullong sigmask; + abi_ullong cr0hi; + abi_ullong cr1lo; + abi_ullong pcsplo; + abi_ullong pcsphi; + abi_uint pcshtp; + abi_uint br; + abi_ullong usdlo; + abi_ullong wd; + abi_ullong reserv1; +}; + #endif diff --git a/linux-user/e2k/target_syscall.h b/linux-user/e2k/target_syscall.h index 213f16c2de..1f46f6da82 100644 --- a/linux-user/e2k/target_syscall.h +++ b/linux-user/e2k/target_syscall.h @@ -62,5 +62,12 @@ struct target_pt_regs { uint16_t gext[32]; }; +// FIXME: Is it right place for these constants? +#if TARGET_LONG_BITS == 64 +#define TARGET_PAGE_OFFSET 0x0000d00000000000UL +#define TARGET_TASK_SIZE TARGET_PAGE_OFFSET +#else +#define TARGET_TASK_SIZE 0xf0000000UL +#endif #endif /* E2K_TARGET_SYSCALL_H */ diff --git a/linux-user/strace.c b/linux-user/strace.c index 7d882526da..450b7908eb 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -3761,6 +3761,19 @@ print_ioctl(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_e2k_longjmp2 +static void +print_e2k_jmp_info(void *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_pointer(arg0, 0); + print_raw_param("%d", arg1, 1); + print_syscall_epilogue(name); +} +#endif + /* * An array of all of the syscalls we know about */ diff --git a/linux-user/strace.list b/linux-user/strace.list index 72e17b1acf..1f3cfb4ae9 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -126,6 +126,10 @@ #ifdef TARGET_NR_dup3 { TARGET_NR_dup3, "dup3" , "%s(%d,%d,%d)", NULL, NULL }, #endif +#ifdef TARGET_NR_e2k_longjmp2 +{ TARGET_NR_e2k_longjmp2, "e2k_longjmp2", "%s(%p, %d)", + print_e2k_jmp_info, NULL }, +#endif #ifdef TARGET_NR_epoll_create { TARGET_NR_epoll_create, "epoll_create", "%s(%d)", NULL, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f55cdebee5..3c316d669a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6987,6 +6987,86 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr, return 0; } +#ifdef TARGET_E2K +static inline abi_long copy_from_user_jmp_info(struct target_jmp_info *ji, + abi_ulong target_jmp_info_addr) +{ + struct target_jmp_info *target_ji; + + if (!lock_user_struct(VERIFY_READ, target_ji, target_jmp_info_addr, 1)) { + return -TARGET_EFAULT; + } + __get_user(ji->sigmask, &target_ji->sigmask); + __get_user(ji->cr0hi, &target_ji->cr0hi); + __get_user(ji->cr1lo, &target_ji->cr1lo); + __get_user(ji->pcsplo, &target_ji->pcsplo); + __get_user(ji->pcsphi, &target_ji->pcsphi); + __get_user(ji->pcshtp, &target_ji->pcshtp); + __get_user(ji->br, &target_ji->br); + __get_user(ji->usdlo, &target_ji->usdlo); + __get_user(ji->wd, &target_ji->wd); + __get_user(ji->reserv1, &target_ji->reserv1); + unlock_user_struct(target_ji, target_jmp_info_addr, 0); + if (ji->cr0hi > TARGET_TASK_SIZE) { + return -TARGET_EFAULT; + } + return 0; +} + +static inline abi_long copy_from_user_crs(E2KCrs *crs, + abi_ulong target_crs_addr) +{ + E2KCrs *target_crs; + + if (!lock_user_struct(VERIFY_READ, target_crs, target_crs_addr, 1)) { + return -TARGET_EFAULT; + } + __get_user(crs->cr0_lo, &target_crs->cr0_lo); + __get_user(crs->cr0_hi, &target_crs->cr0_hi); + __get_user(crs->cr1.lo, &target_crs->cr1.lo); + __get_user(crs->cr1.hi, &target_crs->cr1.hi); + unlock_user_struct(target_crs, target_crs_addr, 0); + return 0; +} + +static abi_long do_e2k_longjmp2(CPUE2KState *env, struct target_jmp_info *jmp_info) +{ + E2KPcsState jmp_pcsp; + E2KCrs crs = env->crs; + int level; /* how many CRs need to restore */ + int pcs_index = env->pcsp.index; + int ps_index = env->psp.index; + int psize = env->wd.psize; + int ret, i; + + jmp_pcsp.lo = jmp_info->pcsplo; + jmp_pcsp.hi = jmp_info->pcsphi; + + level = (env->pcsp.index - jmp_pcsp.index) / CRS_SIZE; + for (i = 0; i < level; i++) { + // FIXME: nfx + psize = crs.cr1.wpsz * 2; + ps_index -= crs.cr1.wbs * E2K_REG_LEN * 4; + pcs_index -= CRS_SIZE; + ret = copy_from_user_crs(&crs, env->pcsp.base + pcs_index); + if (ret) { + return ret; + } + } + + env->crs.cr0_hi = jmp_info->cr0hi; + env->crs.cr1.lo = jmp_info->cr1lo; + env->crs.cr1.br = jmp_info->br; + env->crs.cr1.ussz = (env->sbr - extract64(jmp_info->usdlo, 0, 48)) >> 4; + env->pcsp.index = pcs_index; + env->psp.index = ps_index; + env->wd.base = 0; + env->wd.psize = psize; + + return 0; +} +#endif /* end of TARGET_E2K */ + static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) { struct flock64 fl64; @@ -11885,6 +11965,19 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #endif return ret; #endif +#ifdef TARGET_NR_e2k_longjmp2 + case TARGET_NR_e2k_longjmp2: { + E2KCPU *e2k_cpu = E2K_CPU(cpu); + CPUE2KState *env = &e2k_cpu->env; + struct target_jmp_info ji; + ret = copy_from_user_jmp_info(&ji, arg1); + if (ret) { + break; + } + do_e2k_longjmp2(env, &ji); + return arg2; + } +#endif #ifdef CONFIG_ATTR #ifdef TARGET_NR_setxattr case TARGET_NR_listxattr: diff --git a/target/e2k/cpu.c b/target/e2k/cpu.c index e5e0c49bf3..e069b3da56 100644 --- a/target/e2k/cpu.c +++ b/target/e2k/cpu.c @@ -44,8 +44,8 @@ static void e2k_cpu_reset(DeviceState *dev) memset(env, 0, offsetof(CPUE2KState, end_reset_fields)); - env->cr1.wpsz = 4; - env->cr1.wbs = 4; + env->crs.cr1.wpsz = 4; + env->crs.cr1.wbs = 4; env->wd.base = 0; env->wd.size = 16; env->wd.psize = 8; @@ -61,7 +61,7 @@ static void e2k_cpu_reset(DeviceState *dev) e2k_update_fp_status(env); // FIXME: testing - env->idr = 0x3a207; // mimic 8c + env->idr = 0x3a207; /* mimic 8c */ } #ifdef CONFIG_SOFTMMU @@ -157,10 +157,10 @@ void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, " ip = 0x%016lx\n", env->ip); qemu_fprintf(f, " pregs = 0x%016lx\n", env->pregs); - qemu_fprintf(f, " cr0_lo = 0x%016lx\n", env->cr0_lo); - qemu_fprintf(f, " cr0_hi = 0x%016lx\n", env->cr0_hi); - qemu_fprintf(f, " cr1_lo = 0x%016lx\n", env->cr1.lo); - qemu_fprintf(f, " cr1_hi = 0x%016lx\n", env->cr1.hi); + qemu_fprintf(f, " cr0_lo = 0x%016lx\n", env->crs.cr0_lo); + qemu_fprintf(f, " cr0_hi = 0x%016lx\n", env->crs.cr0_hi); + qemu_fprintf(f, " cr1_lo = 0x%016lx\n", env->crs.cr1.lo); + qemu_fprintf(f, " cr1_hi = 0x%016lx\n", env->crs.cr1.hi); qemu_fprintf(f, " pcsp_lo = 0x%016lx\n", e2k_state_pcsp_lo(env)); qemu_fprintf(f, " pcsp_hi = 0x%016lx\n", e2k_state_pcsp_hi(env)); qemu_fprintf(f, " psp_lo = 0x%016lx\n", e2k_state_psp_lo(env)); diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index 93f6a0e405..dd57e98823 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -41,6 +41,8 @@ typedef enum { E2K_TAG_NON_NUMBER64 = 5, } E2kRegisterTag; +#define CRS_SIZE (sizeof(E2KCrs)) + #define CTPR_BASE_OFF 0 #define CTPR_BASE_END 47 #define CTPR_BASE_LEN (CTPR_BASE_END - CTPR_BASE_OFF + 1) @@ -313,15 +315,36 @@ typedef struct { }; uint64_t hi; }; -} E2KCr1State; +} E2KCr1; typedef struct { - target_ulong base; + uint64_t cr0_lo; + uint64_t cr0_hi; + E2KCr1 cr1; +} E2KCrs; + +typedef struct { + union { + struct { + uint64_t base: 48; /* 47:0 */ + uint64_t unused1: 7; /* 55:48 */ + uint64_t stub3: 1; /* 56 */ + uint64_t stub2: 1; /* 57 */ + uint64_t stub1: 1; /* 58 */ + uint64_t is_readable: 1; /* 59 */ + uint64_t is_writable: 1; /* 60 */ + uint64_t itag: 3; /* 63:61 */ + }; + uint64_t lo; + }; + union { + struct { + uint64_t index: 32; /* 31:0 */ + uint64_t size: 32; /* 63:32 */ + }; + uint64_t hi; + }; target_ulong base_tag; - uint32_t index; - uint32_t size; - bool is_readable; - bool is_writable; } E2KStackState, E2KPsState, E2KPcsState; typedef struct { @@ -594,9 +617,7 @@ typedef struct CPUArchState { E2KDamEntry dam[32]; /* procedure chain info */ - uint64_t cr0_lo; - uint64_t cr0_hi; - E2KCr1State cr1; + E2KCrs crs; /* Procedure chain info = cr0_lo, cr0_hi, cr1_lo, cr1_hi */ E2KPcsState pcsp; @@ -640,6 +661,9 @@ typedef struct CPUArchState { /* zeroing upper register half for 32-bit instructions */ uint32_t wdbl; + target_ulong pcs_base; + target_ulong ps_base; + /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; @@ -749,6 +773,14 @@ static inline uint64_t e2k_state_wd(CPUE2KState *env) return ret; } +static inline void e2k_state_wd_set(CPUE2KState *env, uint64_t raw) +{ + env->wd.base = extract64(raw, WD_BASE_OFF, WD_BASE_LEN) / 8; + env->wd.size = extract64(raw, WD_SIZE_OFF, WD_SIZE_LEN) / 8; + env->wd.psize = extract64(raw, WD_PSIZE_OFF, WD_PSIZE_LEN) / 8; + env->wd.fx = extract64(raw, WD_FX_OFF, 1); +} + static inline uint32_t e2k_state_br(CPUE2KState *env) { E2KBnState *bn = &env->bn; diff --git a/target/e2k/gdbstub.c b/target/e2k/gdbstub.c index b78c214510..1147d555ad 100644 --- a/target/e2k/gdbstub.c +++ b/target/e2k/gdbstub.c @@ -62,8 +62,8 @@ int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) case 51: return gdb_get_reg64(mem_buf, e2k_state_pshtp(env)); // pshtp case 52: return gdb_get_reg64(mem_buf, env->pregs); // pregs case 53: return gdb_get_reg64(mem_buf, env->ip); // ip - case 54: return gdb_get_reg64(mem_buf, env->cr1.lo); // cr1_lo - case 55: return gdb_get_reg64(mem_buf, env->cr1.hi); // cr1_hi + case 54: return gdb_get_reg64(mem_buf, env->crs.cr1.lo); // cr1_lo + case 55: return gdb_get_reg64(mem_buf, env->crs.cr1.hi); // cr1_hi case 56: return gdb_get_reg64(mem_buf, 0); // cwd case 57: return gdb_get_reg64(mem_buf, e2k_state_pcsp_lo(env)); // pcsp_lo case 58: return gdb_get_reg64(mem_buf, e2k_state_pcsp_hi(env)); // pcsp_hi diff --git a/target/e2k/helper.c b/target/e2k/helper.c index a9b54852ba..40bd095228 100644 --- a/target/e2k/helper.c +++ b/target/e2k/helper.c @@ -59,21 +59,21 @@ static inline uint64_t ps_pop(CPUE2KState *env, uint8_t *ret_tag) static void proc_chain_save(CPUE2KState *env, int wbs) { - pcs_push(env, env->cr0_lo); - pcs_push(env, env->cr0_hi); - pcs_push(env, env->cr1.lo); - pcs_push(env, env->cr1.hi); + pcs_push(env, env->crs.cr0_lo); + pcs_push(env, env->crs.cr0_hi); + pcs_push(env, env->crs.cr1.lo); + pcs_push(env, env->crs.cr1.hi); env->pshtp.index += wbs * 2; - env->cr0_lo = env->pregs; - env->cr0_hi = env->ip; - env->cr1.wbs = wbs; - env->cr1.wpsz = env->wd.psize / 2; - env->cr1.wfx = env->wd.fx; - env->cr1.wdbl = env->wdbl; - env->cr1.br = e2k_state_br(env); - env->cr1.ussz = env->usd.size >> 4; + env->crs.cr0_lo = env->pregs; + env->crs.cr0_hi = env->ip; + env->crs.cr1.wbs = wbs; + env->crs.cr1.wpsz = env->wd.psize / 2; + env->crs.cr1.wfx = env->wd.fx; + env->crs.cr1.wdbl = env->wdbl; + env->crs.cr1.br = e2k_state_br(env); + env->crs.cr1.ussz = env->usd.size >> 4; env->wd.fx = true; env->wd.base = e2k_wrap_reg_index(env->wd.base + wbs * 2); @@ -85,47 +85,64 @@ static inline void proc_chain_restore(CPUE2KState *env) { int wbs; - env->pregs = env->cr0_lo; - env->ip = env->cr0_hi; - wbs = env->cr1.wbs; - e2k_state_br_set(env, env->cr1.br); + env->pregs = env->crs.cr0_lo; + env->ip = env->crs.cr0_hi; + wbs = env->crs.cr1.wbs; + e2k_state_br_set(env, env->crs.cr1.br); env->wd.size = env->wd.psize + wbs * 2; - env->wd.psize = env->cr1.wpsz * 2; + env->wd.psize = env->crs.cr1.wpsz * 2; env->wd.base = e2k_wrap_reg_index(env->wd.base - wbs * 2); - env->wd.fx = env->cr1.wfx; - env->wdbl = env->cr1.wdbl; - env->usd.size = env->cr1.ussz << 4; + env->wd.fx = env->crs.cr1.wfx; + env->wdbl = env->crs.cr1.wdbl; + env->usd.size = env->crs.cr1.ussz << 4; env->usd.base = env->sbr - env->usd.size; env->pshtp.index -= wbs * 2; - env->cr1.hi = pcs_pop(env); - env->cr1.lo = pcs_pop(env); - env->cr0_hi = pcs_pop(env); - env->cr0_lo = pcs_pop(env); + env->crs.cr1.hi = pcs_pop(env); + env->crs.cr1.lo = pcs_pop(env); + env->crs.cr0_hi = pcs_pop(env); + env->crs.cr0_lo = pcs_pop(env); } -static inline void ps_spill(CPUE2KState *env, bool force, bool force_fx) +static inline void ps_spill_round(CPUE2KState *env, bool force_fx) { - while (E2K_NR_COUNT < env->pshtp.index + env->wd.size || - (force && env->wd.size + env->pshtp.index)) - { - int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index); - ps_push(env, env->regs[i], env->tags[i]); - ps_push(env, env->regs[i + 1], env->tags[i + 1]); + int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index); + ps_push(env, env->regs[i], env->tags[i]); + ps_push(env, env->regs[i + 1], env->tags[i + 1]); - // TODO: push fx - if (force_fx) { - ps_push(env, env->xregs[i], 0); - ps_push(env, env->xregs[i + 1], 0); - } + // TODO: push fx + if (force_fx) { + ps_push(env, env->xregs[i], 0); + ps_push(env, env->xregs[i + 1], 0); + } - env->regs[i] = 0; - env->tags[i] = E2K_TAG_NON_NUMBER64; - env->regs[i + 1] = 0; - env->tags[i + 1] = E2K_TAG_NON_NUMBER64; + env->regs[i] = 0; + env->tags[i] = E2K_TAG_NON_NUMBER64; + env->regs[i + 1] = 0; + env->tags[i + 1] = E2K_TAG_NON_NUMBER64; - env->pshtp.index -= 2; + env->pshtp.index -= 2; +} + +static inline void ps_spill_all(CPUE2KState *env, bool force_fx) +{ + while (env->pshtp.index > 0) { + ps_spill_round(env, force_fx); + } +} + +static inline void ps_spill_debug(CPUE2KState *env, bool force_fx) +{ + while (env->wd.size + env->pshtp.index) { + ps_spill_round(env, force_fx); + } +} + +static inline void ps_spill(CPUE2KState *env, bool force_fx) +{ + while (E2K_NR_COUNT < env->pshtp.index + env->wd.size) { + ps_spill_round(env, force_fx); } } @@ -167,7 +184,7 @@ void helper_setwd(CPUE2KState *env, uint32_t lts) env->wdbl = dbl; } - ps_spill(env, false, PS_FORCE_FX); + ps_spill(env, PS_FORCE_FX); if (old_size < size) { unsigned int i, offset = env->wd.base + old_size; @@ -189,7 +206,7 @@ uint64_t helper_prep_return(CPUE2KState *env, int ipd) return 0; } - ret.base = env->cr0_hi; + ret.base = env->crs.cr0_hi; ret.tag = CTPR_TAG_RETURN; ret.ipd = ipd; @@ -207,11 +224,10 @@ static inline void do_syscall(CPUE2KState *env, int call_wbs, target_ulong pc_next) { CPUState *cs = env_cpu(env); - env->ip = pc_next; - env->syscall_wbs = call_wbs; + proc_chain_save(env, call_wbs); + ps_spill_all(env, PS_FORCE_FX); reset_ctprs(env); - cs->exception_index = E2K_EXCP_SYSCALL; cpu_loop_exit(cs); } @@ -241,7 +257,7 @@ void helper_raise_exception(CPUE2KState *env, int tt) cs->exception_index = tt; proc_chain_save(env, env->wd.size / 2); - ps_spill(env, true, true); + ps_spill_debug(env, PS_FORCE_FX); cpu_loop_exit(cs); } @@ -257,7 +273,7 @@ void e2k_break_save_state(CPUE2KState *env) { env->is_bp = true; proc_chain_save(env, env->wd.size / 2); - ps_spill(env, true, true); + ps_spill(env, PS_FORCE_FX); } void helper_break_restore_state(CPUE2KState *env) @@ -274,7 +290,7 @@ bool e2k_cpu_tlb_fill(CPUState *cs, vaddr address, int size, CPUE2KState *env = &cpu->env; proc_chain_save(env, env->wd.size / 2); - ps_spill(env, true, true); + ps_spill(env, PS_FORCE_FX); cs->exception_index = E2K_EXCP_MAPERR; cpu_loop_exit_restore(cs, retaddr); diff --git a/target/e2k/helper_int.c b/target/e2k/helper_int.c index 08f3d8bde7..e47bf6b88f 100644 --- a/target/e2k/helper_int.c +++ b/target/e2k/helper_int.c @@ -48,10 +48,10 @@ uint64_t helper_state_reg_read_i64(CPUE2KState *env, int idx) case 0x13: return env->pcshtp; /* %pcshtp */ case 0x2c: return env->usd.hi; /* %usd.hi */ case 0x2d: return env->usd.lo; /* %usd.lo */ - case 0x51: return env->cr0_hi; /* %cr0.hi */ - case 0x53: return env->cr0_lo; /* %cr0.lo */ - case 0x55: return env->cr1.hi; /* %cr1.hi */ - case 0x57: return env->cr1.lo; /* %cr1.lo */ + case 0x51: return env->crs.cr0_hi; /* %cr0.hi */ + case 0x53: return env->crs.cr0_lo; /* %cr0.lo */ + case 0x55: return env->crs.cr1.hi; /* %cr1.hi */ + case 0x57: return env->crs.cr1.lo; /* %cr1.lo */ case 0x81: return env->ip; /* %ip */ case 0x85: return env->fpcr.raw; /* %fpcr */ case 0x86: return env->fpsr.raw; /* %fpsr */