uint64_t helper_stq_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v) { CPUState *cs = CPU(alpha_env_get_cpu(env)); uint64_t ret = 0; if (p == env->lock_addr) { uint64_t old = ldq_phys(cs->as, p); if (old == env->lock_value) { stq_phys(cs->as, p, v); ret = 1; } } env->lock_addr = -1; return ret; }
static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) { CPUAlphaState *env = cpu_single_env; TyphoonState *s = opaque; CPUState *cpu; uint64_t ret = 0; if (addr & 4) { return s->latch_tmp; } switch (addr) { case 0x0000: /* CSC: Cchip System Configuration Register. */ /* All sorts of data here; probably the only thing relevant is PIP<14> Pchip 1 Present = 0. */ break; case 0x0040: /* MTR: Memory Timing Register. */ /* All sorts of stuff related to real DRAM. */ break; case 0x0080: /* MISC: Miscellaneous Register. */ cpu = ENV_GET_CPU(env); ret = s->cchip.misc | (cpu->cpu_index & 3); break; case 0x00c0: /* MPD: Memory Presence Detect Register. */ break; case 0x0100: /* AAR0 */ case 0x0140: /* AAR1 */ case 0x0180: /* AAR2 */ case 0x01c0: /* AAR3 */ /* AAR: Array Address Register. */ /* All sorts of information about DRAM. */ break; case 0x0200: /* DIM0: Device Interrupt Mask Register, CPU0. */ ret = s->cchip.dim[0]; break; case 0x0240: /* DIM1: Device Interrupt Mask Register, CPU1. */ ret = s->cchip.dim[1]; break; case 0x0280: /* DIR0: Device Interrupt Request Register, CPU0. */ ret = s->cchip.dim[0] & s->cchip.drir; break; case 0x02c0: /* DIR1: Device Interrupt Request Register, CPU1. */ ret = s->cchip.dim[1] & s->cchip.drir; break; case 0x0300: /* DRIR: Device Raw Interrupt Request Register. */ ret = s->cchip.drir; break; case 0x0340: /* PRBEN: Probe Enable Register. */ break; case 0x0380: /* IIC0: Interval Ignore Count Register, CPU0. */ ret = s->cchip.iic[0]; break; case 0x03c0: /* IIC1: Interval Ignore Count Register, CPU1. */ ret = s->cchip.iic[1]; break; case 0x0400: /* MPR0 */ case 0x0440: /* MPR1 */ case 0x0480: /* MPR2 */ case 0x04c0: /* MPR3 */ /* MPR: Memory Programming Register. */ break; case 0x0580: /* TTR: TIGbus Timing Register. */ /* All sorts of stuff related to interrupt delivery timings. */ break; case 0x05c0: /* TDR: TIGbug Device Timing Register. */ break; case 0x0600: /* DIM2: Device Interrupt Mask Register, CPU2. */ ret = s->cchip.dim[2]; break; case 0x0640: /* DIM3: Device Interrupt Mask Register, CPU3. */ ret = s->cchip.dim[3]; break; case 0x0680: /* DIR2: Device Interrupt Request Register, CPU2. */ ret = s->cchip.dim[2] & s->cchip.drir; break; case 0x06c0: /* DIR3: Device Interrupt Request Register, CPU3. */ ret = s->cchip.dim[3] & s->cchip.drir; break; case 0x0700: /* IIC2: Interval Ignore Count Register, CPU2. */ ret = s->cchip.iic[2]; break; case 0x0740: /* IIC3: Interval Ignore Count Register, CPU3. */ ret = s->cchip.iic[3]; break; case 0x0780: /* PWR: Power Management Control. */ break; case 0x0c00: /* CMONCTLA */ case 0x0c40: /* CMONCTLB */ case 0x0c80: /* CMONCNT01 */ case 0x0cc0: /* CMONCNT23 */ break; default: cpu = CPU(alpha_env_get_cpu(cpu_single_env)); cpu_unassigned_access(cpu, addr, false, false, 0, size); return -1; } s->latch_tmp = ret >> 32; return ret; }
static void pchip_write(void *opaque, hwaddr addr, uint64_t v32, unsigned size) { TyphoonState *s = opaque; CPUState *cs; uint64_t val, oldval; if (addr & 4) { val = v32 << 32 | s->latch_tmp; addr ^= 4; } else { s->latch_tmp = v32; return; } switch (addr) { case 0x0000: /* WSBA0: Window Space Base Address Register. */ s->pchip.win[0].base_addr = val; break; case 0x0040: /* WSBA1 */ s->pchip.win[1].base_addr = val; break; case 0x0080: /* WSBA2 */ s->pchip.win[2].base_addr = val; break; case 0x00c0: /* WSBA3 */ s->pchip.win[3].base_addr = val; break; case 0x0100: /* WSM0: Window Space Mask Register. */ s->pchip.win[0].mask = val; break; case 0x0140: /* WSM1 */ s->pchip.win[1].mask = val; break; case 0x0180: /* WSM2 */ s->pchip.win[2].mask = val; break; case 0x01c0: /* WSM3 */ s->pchip.win[3].mask = val; break; case 0x0200: /* TBA0: Translated Base Address Register. */ s->pchip.win[0].translated_base_pfn = val >> 10; break; case 0x0240: /* TBA1 */ s->pchip.win[1].translated_base_pfn = val >> 10; break; case 0x0280: /* TBA2 */ s->pchip.win[2].translated_base_pfn = val >> 10; break; case 0x02c0: /* TBA3 */ s->pchip.win[3].translated_base_pfn = val >> 10; break; case 0x0300: /* PCTL: Pchip Control Register. */ oldval = s->pchip.ctl; oldval &= ~0x00001cff0fc7ffull; /* RW fields */ oldval |= val & 0x00001cff0fc7ffull; s->pchip.ctl = oldval; break; case 0x0340: /* PLAT: Pchip Master Latency Register. */ break; case 0x03c0: /* PERROR: Pchip Error Register. */ break; case 0x0400: /* PERRMASK: Pchip Error Mask Register. */ break; case 0x0440: /* PERRSET: Pchip Error Set Register. */ break; case 0x0480: /* TLBIV: Translation Buffer Invalidate Virtual Register. */ break; case 0x04c0: /* TLBIA: Translation Buffer Invalidate All Register (WO). */ break; case 0x0500: /* PMONCTL */ case 0x0540: /* PMONCNT */ case 0x0800: /* SPRST */ break; default: cs = CPU(alpha_env_get_cpu(cpu_single_env)); cpu_unassigned_access(cs, addr, true, false, 0, size); return; } }
static void cchip_write(void *opaque, hwaddr addr, uint64_t v32, unsigned size) { TyphoonState *s = opaque; CPUState *cpu_single_cpu = CPU(alpha_env_get_cpu(cpu_single_env)); uint64_t val, oldval, newval; if (addr & 4) { val = v32 << 32 | s->latch_tmp; addr ^= 4; } else { s->latch_tmp = v32; return; } switch (addr) { case 0x0000: /* CSC: Cchip System Configuration Register. */ /* All sorts of data here; nothing relevant RW. */ break; case 0x0040: /* MTR: Memory Timing Register. */ /* All sorts of stuff related to real DRAM. */ break; case 0x0080: /* MISC: Miscellaneous Register. */ newval = oldval = s->cchip.misc; newval &= ~(val & 0x10000ff0); /* W1C fields */ if (val & 0x100000) { newval &= ~0xff0000ull; /* ACL clears ABT and ABW */ } else { newval |= val & 0x00f00000; /* ABT field is W1S */ if ((newval & 0xf0000) == 0) { newval |= val & 0xf0000; /* ABW field is W1S iff zero */ } } newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */ newval &= ~0xf0000000000ull; /* WO and RW fields */ newval |= val & 0xf0000000000ull; s->cchip.misc = newval; /* Pass on changes to IPI and ITI state. */ if ((newval ^ oldval) & 0xff0) { int i; for (i = 0; i < 4; ++i) { AlphaCPU *cpu = s->cchip.cpu[i]; if (cpu != NULL) { CPUState *cs = CPU(cpu); /* IPI can be either cleared or set by the write. */ if (newval & (1 << (i + 8))) { cpu_interrupt(cs, CPU_INTERRUPT_SMP); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP); } /* ITI can only be cleared by the write. */ if ((newval & (1 << (i + 4))) == 0) { cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER); } } } } break; case 0x00c0: /* MPD: Memory Presence Detect Register. */ break; case 0x0100: /* AAR0 */ case 0x0140: /* AAR1 */ case 0x0180: /* AAR2 */ case 0x01c0: /* AAR3 */ /* AAR: Array Address Register. */ /* All sorts of information about DRAM. */ break; case 0x0200: /* DIM0 */ /* DIM: Device Interrupt Mask Register, CPU0. */ s->cchip.dim[0] = val; cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir); break; case 0x0240: /* DIM1 */ /* DIM: Device Interrupt Mask Register, CPU1. */ s->cchip.dim[0] = val; cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir); break; case 0x0280: /* DIR0 (RO) */ case 0x02c0: /* DIR1 (RO) */ case 0x0300: /* DRIR (RO) */ break; case 0x0340: /* PRBEN: Probe Enable Register. */ break; case 0x0380: /* IIC0 */ s->cchip.iic[0] = val & 0xffffff; break; case 0x03c0: /* IIC1 */ s->cchip.iic[1] = val & 0xffffff; break; case 0x0400: /* MPR0 */ case 0x0440: /* MPR1 */ case 0x0480: /* MPR2 */ case 0x04c0: /* MPR3 */ /* MPR: Memory Programming Register. */ break; case 0x0580: /* TTR: TIGbus Timing Register. */ /* All sorts of stuff related to interrupt delivery timings. */ break; case 0x05c0: /* TDR: TIGbug Device Timing Register. */ break; case 0x0600: /* DIM2: Device Interrupt Mask Register, CPU2. */ s->cchip.dim[2] = val; cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir); break; case 0x0640: /* DIM3: Device Interrupt Mask Register, CPU3. */ s->cchip.dim[3] = val; cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir); break; case 0x0680: /* DIR2 (RO) */ case 0x06c0: /* DIR3 (RO) */ break; case 0x0700: /* IIC2 */ s->cchip.iic[2] = val & 0xffffff; break; case 0x0740: /* IIC3 */ s->cchip.iic[3] = val & 0xffffff; break; case 0x0780: /* PWR: Power Management Control. */ break; case 0x0c00: /* CMONCTLA */ case 0x0c40: /* CMONCTLB */ case 0x0c80: /* CMONCNT01 */ case 0x0cc0: /* CMONCNT23 */ break; default: cpu_unassigned_access(cpu_single_cpu, addr, true, false, 0, size); return; } }
static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) { TyphoonState *s = opaque; CPUState *cs; uint64_t ret = 0; if (addr & 4) { return s->latch_tmp; } switch (addr) { case 0x0000: /* WSBA0: Window Space Base Address Register. */ ret = s->pchip.win[0].base_addr; break; case 0x0040: /* WSBA1 */ ret = s->pchip.win[1].base_addr; break; case 0x0080: /* WSBA2 */ ret = s->pchip.win[2].base_addr; break; case 0x00c0: /* WSBA3 */ ret = s->pchip.win[3].base_addr; break; case 0x0100: /* WSM0: Window Space Mask Register. */ ret = s->pchip.win[0].mask; break; case 0x0140: /* WSM1 */ ret = s->pchip.win[1].mask; break; case 0x0180: /* WSM2 */ ret = s->pchip.win[2].mask; break; case 0x01c0: /* WSM3 */ ret = s->pchip.win[3].mask; break; case 0x0200: /* TBA0: Translated Base Address Register. */ ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10; break; case 0x0240: /* TBA1 */ ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10; break; case 0x0280: /* TBA2 */ ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10; break; case 0x02c0: /* TBA3 */ ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10; break; case 0x0300: /* PCTL: Pchip Control Register. */ ret = s->pchip.ctl; break; case 0x0340: /* PLAT: Pchip Master Latency Register. */ break; case 0x03c0: /* PERROR: Pchip Error Register. */ break; case 0x0400: /* PERRMASK: Pchip Error Mask Register. */ break; case 0x0440: /* PERRSET: Pchip Error Set Register. */ break; case 0x0480: /* TLBIV: Translation Buffer Invalidate Virtual Register (WO). */ break; case 0x04c0: /* TLBIA: Translation Buffer Invalidate All Register (WO). */ break; case 0x0500: /* PMONCTL */ case 0x0540: /* PMONCNT */ case 0x0800: /* SPRST */ break; default: cs = CPU(alpha_env_get_cpu(cpu_single_env)); cpu_unassigned_access(cs, addr, false, false, 0, size); return -1; } s->latch_tmp = ret >> 32; return ret; }
void cpu_loop(CPUAlphaState *env) { CPUState *cs = CPU(alpha_env_get_cpu(env)); int trapnr; target_siginfo_t info; abi_long sysret; while (1) { bool arch_interrupt = true; cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); process_queued_cpu_work(cs); switch (trapnr) { case EXCP_RESET: fprintf(stderr, "Reset requested. Exit\n"); exit(EXIT_FAILURE); break; case EXCP_MCHK: fprintf(stderr, "Machine check exception. Exit\n"); exit(EXIT_FAILURE); break; case EXCP_SMP_INTERRUPT: case EXCP_CLK_INTERRUPT: case EXCP_DEV_INTERRUPT: fprintf(stderr, "External interrupt. Exit\n"); exit(EXIT_FAILURE); break; case EXCP_MMFAULT: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); info._sifields._sigfault._addr = env->trap_arg0; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_UNALIGN: info.si_signo = TARGET_SIGBUS; info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; info._sifields._sigfault._addr = env->trap_arg0; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_OPCDEC: do_sigill: info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPC; info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_ARITH: info.si_signo = TARGET_SIGFPE; info.si_errno = 0; info.si_code = TARGET_FPE_FLTINV; info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_FEN: /* No-op. Linux simply re-enables the FPU. */ break; case EXCP_CALL_PAL: switch (env->error_code) { case 0x80: /* BPT */ info.si_signo = TARGET_SIGTRAP; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case 0x81: /* BUGCHK */ info.si_signo = TARGET_SIGTRAP; info.si_errno = 0; info.si_code = 0; info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case 0x83: /* CALLSYS */ trapnr = env->ir[IR_V0]; sysret = do_syscall(env, trapnr, env->ir[IR_A0], env->ir[IR_A1], env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], env->ir[IR_A5], 0, 0); if (sysret == -TARGET_ERESTARTSYS) { env->pc -= 4; break; } if (sysret == -TARGET_QEMU_ESIGRETURN) { break; } /* Syscall writes 0 to V0 to bypass error check, similar to how this is handled internal to Linux kernel. (Ab)use trapnr temporarily as boolean indicating error. */ trapnr = (env->ir[IR_V0] != 0 && sysret < 0); env->ir[IR_V0] = (trapnr ? -sysret : sysret); env->ir[IR_A3] = trapnr; break; case 0x86: /* IMB */ /* ??? We can probably elide the code using page_unprotect that is checking for self-modifying code. Instead we could simply call tb_flush here. Until we work out the changes required to turn off the extra write protection, this can be a no-op. */ break; case 0x9E: /* RDUNIQUE */ /* Handled in the translator for usermode. */ abort(); case 0x9F: /* WRUNIQUE */ /* Handled in the translator for usermode. */ abort(); case 0xAA: /* GENTRAP */ info.si_signo = TARGET_SIGFPE; switch (env->ir[IR_A0]) { case TARGET_GEN_INTOVF: info.si_code = TARGET_FPE_INTOVF; break; case TARGET_GEN_INTDIV: info.si_code = TARGET_FPE_INTDIV; break; case TARGET_GEN_FLTOVF: info.si_code = TARGET_FPE_FLTOVF; break; case TARGET_GEN_FLTUND: info.si_code = TARGET_FPE_FLTUND; break; case TARGET_GEN_FLTINV: info.si_code = TARGET_FPE_FLTINV; break; case TARGET_GEN_FLTINE: info.si_code = TARGET_FPE_FLTRES; break; case TARGET_GEN_ROPRAND: info.si_code = 0; break; default: info.si_signo = TARGET_SIGTRAP; info.si_code = 0; break; } info.si_errno = 0; info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: goto do_sigill; } break; case EXCP_DEBUG: info.si_signo = gdb_handlesig(cs, TARGET_SIGTRAP); if (info.si_signo) { info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } else { arch_interrupt = false; } break; case EXCP_INTERRUPT: /* Just indicate that signals should be handled asap. */ break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); arch_interrupt = false; break; default: fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, fprintf, 0); exit(EXIT_FAILURE); } process_pending_signals (env); /* Most of the traps imply a transition through PALcode, which implies an REI instruction has been executed. Which means that RX and LOCK_ADDR should be cleared. But there are a few exceptions for traps internal to QEMU. */ if (arch_interrupt) { env->flags &= ~ENV_FLAG_RX_FLAG; env->lock_addr = -1; } } }
void helper_stq_phys(CPUAlphaState *env, uint64_t p, uint64_t v) { CPUState *cs = CPU(alpha_env_get_cpu(env)); stq_phys(cs->as, p, v); }
uint64_t helper_ldq_l_phys(CPUAlphaState *env, uint64_t p) { CPUState *cs = CPU(alpha_env_get_cpu(env)); env->lock_addr = p; return env->lock_value = ldq_phys(cs->as, p); }
uint64_t helper_ldq_phys(CPUAlphaState *env, uint64_t p) { CPUState *cs = CPU(alpha_env_get_cpu(env)); return ldq_phys(cs->as, p); }