1a541f297Sbellard /* 2e9df014cSj_mayer * QEMU generic PowerPC hardware System Emulator 3a541f297Sbellard * 476a66253Sj_mayer * Copyright (c) 2003-2007 Jocelyn Mayer 5a541f297Sbellard * 6a541f297Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7a541f297Sbellard * of this software and associated documentation files (the "Software"), to deal 8a541f297Sbellard * in the Software without restriction, including without limitation the rights 9a541f297Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10a541f297Sbellard * copies of the Software, and to permit persons to whom the Software is 11a541f297Sbellard * furnished to do so, subject to the following conditions: 12a541f297Sbellard * 13a541f297Sbellard * The above copyright notice and this permission notice shall be included in 14a541f297Sbellard * all copies or substantial portions of the Software. 15a541f297Sbellard * 16a541f297Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17a541f297Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18a541f297Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19a541f297Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20a541f297Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21a541f297Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22a541f297Sbellard * THE SOFTWARE. 23a541f297Sbellard */ 2464552b6bSMarkus Armbruster 250d75590dSPeter Maydell #include "qemu/osdep.h" 264771d756SPaolo Bonzini #include "cpu.h" 2764552b6bSMarkus Armbruster #include "hw/irq.h" 280d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 292b927571SAndreas Färber #include "hw/ppc/ppc_e500.h" 301de7afc9SPaolo Bonzini #include "qemu/timer.h" 310ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h" 321de7afc9SPaolo Bonzini #include "qemu/log.h" 33db725815SMarkus Armbruster #include "qemu/main-loop.h" 3498a8b524SAlexey Kardashevskiy #include "qemu/error-report.h" 359c17d615SPaolo Bonzini #include "sysemu/kvm.h" 3654d31236SMarkus Armbruster #include "sysemu/runstate.h" 37fc87e185SAlexander Graf #include "kvm_ppc.h" 38d6454270SMarkus Armbruster #include "migration/vmstate.h" 3998a8b524SAlexey Kardashevskiy #include "trace.h" 40a541f297Sbellard 41e9df014cSj_mayer //#define PPC_DEBUG_IRQ 424b6d0a4cSj_mayer //#define PPC_DEBUG_TB 43e9df014cSj_mayer 44d12d51d5Saliguori #ifdef PPC_DEBUG_IRQ 4593fcfe39Saliguori # define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) 46d12d51d5Saliguori #else 47d12d51d5Saliguori # define LOG_IRQ(...) do { } while (0) 48d12d51d5Saliguori #endif 49d12d51d5Saliguori 50d12d51d5Saliguori 51d12d51d5Saliguori #ifdef PPC_DEBUG_TB 5293fcfe39Saliguori # define LOG_TB(...) qemu_log(__VA_ARGS__) 53d12d51d5Saliguori #else 54d12d51d5Saliguori # define LOG_TB(...) do { } while (0) 55d12d51d5Saliguori #endif 56d12d51d5Saliguori 57e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env); 58e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env); 59dbdd2506Sj_mayer 607058581aSAndreas Färber void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) 6147103572Sj_mayer { 62d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 637058581aSAndreas Färber CPUPPCState *env = &cpu->env; 648d04fb55SJan Kiszka unsigned int old_pending; 658d04fb55SJan Kiszka bool locked = false; 668d04fb55SJan Kiszka 678d04fb55SJan Kiszka /* We may already have the BQL if coming from the reset path */ 688d04fb55SJan Kiszka if (!qemu_mutex_iothread_locked()) { 698d04fb55SJan Kiszka locked = true; 708d04fb55SJan Kiszka qemu_mutex_lock_iothread(); 718d04fb55SJan Kiszka } 728d04fb55SJan Kiszka 738d04fb55SJan Kiszka old_pending = env->pending_interrupts; 74fc87e185SAlexander Graf 7547103572Sj_mayer if (level) { 7647103572Sj_mayer env->pending_interrupts |= 1 << n_IRQ; 77c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 7847103572Sj_mayer } else { 7947103572Sj_mayer env->pending_interrupts &= ~(1 << n_IRQ); 80d8ed887bSAndreas Färber if (env->pending_interrupts == 0) { 81d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 82d8ed887bSAndreas Färber } 8347103572Sj_mayer } 84fc87e185SAlexander Graf 85fc87e185SAlexander Graf if (old_pending != env->pending_interrupts) { 867058581aSAndreas Färber kvmppc_set_interrupt(cpu, n_IRQ, level); 87fc87e185SAlexander Graf } 88fc87e185SAlexander Graf 898d04fb55SJan Kiszka 90d12d51d5Saliguori LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32 91aae9366aSj_mayer "req %08x\n", __func__, env, n_IRQ, level, 92259186a7SAndreas Färber env->pending_interrupts, CPU(cpu)->interrupt_request); 938d04fb55SJan Kiszka 948d04fb55SJan Kiszka if (locked) { 958d04fb55SJan Kiszka qemu_mutex_unlock_iothread(); 968d04fb55SJan Kiszka } 97a496775fSj_mayer } 9847103572Sj_mayer 99e9df014cSj_mayer /* PowerPC 6xx / 7xx internal IRQ controller */ 100e9df014cSj_mayer static void ppc6xx_set_irq(void *opaque, int pin, int level) 101d537cf6cSpbrook { 102a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 103a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 104e9df014cSj_mayer int cur_level; 105d537cf6cSpbrook 106d12d51d5Saliguori LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 107a496775fSj_mayer env, pin, level); 108e9df014cSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 109e9df014cSj_mayer /* Don't generate spurious events */ 11024be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 111259186a7SAndreas Färber CPUState *cs = CPU(cpu); 112259186a7SAndreas Färber 113e9df014cSj_mayer switch (pin) { 114dbdd2506Sj_mayer case PPC6xx_INPUT_TBEN: 115dbdd2506Sj_mayer /* Level sensitive - active high */ 116d12d51d5Saliguori LOG_IRQ("%s: %s the time base\n", 117dbdd2506Sj_mayer __func__, level ? "start" : "stop"); 118dbdd2506Sj_mayer if (level) { 119dbdd2506Sj_mayer cpu_ppc_tb_start(env); 120dbdd2506Sj_mayer } else { 121dbdd2506Sj_mayer cpu_ppc_tb_stop(env); 122dbdd2506Sj_mayer } 12324be5ae3Sj_mayer case PPC6xx_INPUT_INT: 12424be5ae3Sj_mayer /* Level sensitive - active high */ 125d12d51d5Saliguori LOG_IRQ("%s: set the external IRQ state to %d\n", 126a496775fSj_mayer __func__, level); 1277058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 128e9df014cSj_mayer break; 12924be5ae3Sj_mayer case PPC6xx_INPUT_SMI: 130e9df014cSj_mayer /* Level sensitive - active high */ 131d12d51d5Saliguori LOG_IRQ("%s: set the SMI IRQ state to %d\n", 132a496775fSj_mayer __func__, level); 1337058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 134e9df014cSj_mayer break; 13524be5ae3Sj_mayer case PPC6xx_INPUT_MCP: 136e9df014cSj_mayer /* Negative edge sensitive */ 137e9df014cSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 138e9df014cSj_mayer * 603/604/740/750: check HID0[EMCP] 139e9df014cSj_mayer */ 140e9df014cSj_mayer if (cur_level == 1 && level == 0) { 141d12d51d5Saliguori LOG_IRQ("%s: raise machine check state\n", 142a496775fSj_mayer __func__); 1437058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 144d537cf6cSpbrook } 145e9df014cSj_mayer break; 14624be5ae3Sj_mayer case PPC6xx_INPUT_CKSTP_IN: 147e9df014cSj_mayer /* Level sensitive - active low */ 148e9df014cSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 149e63ecc6fSj_mayer /* XXX: Note that the only way to restart the CPU is to reset it */ 150e9df014cSj_mayer if (level) { 151d12d51d5Saliguori LOG_IRQ("%s: stop the CPU\n", __func__); 152259186a7SAndreas Färber cs->halted = 1; 153d537cf6cSpbrook } 15447103572Sj_mayer break; 15524be5ae3Sj_mayer case PPC6xx_INPUT_HRESET: 156e9df014cSj_mayer /* Level sensitive - active low */ 157e9df014cSj_mayer if (level) { 158d12d51d5Saliguori LOG_IRQ("%s: reset the CPU\n", __func__); 159c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 160e9df014cSj_mayer } 16147103572Sj_mayer break; 16224be5ae3Sj_mayer case PPC6xx_INPUT_SRESET: 163d12d51d5Saliguori LOG_IRQ("%s: set the RESET IRQ state to %d\n", 164a496775fSj_mayer __func__, level); 1657058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 16647103572Sj_mayer break; 167e9df014cSj_mayer default: 168e9df014cSj_mayer /* Unknown pin - do nothing */ 169d12d51d5Saliguori LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 17047103572Sj_mayer return; 17147103572Sj_mayer } 172e9df014cSj_mayer if (level) 173e9df014cSj_mayer env->irq_input_state |= 1 << pin; 174e9df014cSj_mayer else 175e9df014cSj_mayer env->irq_input_state &= ~(1 << pin); 176e9df014cSj_mayer } 177e9df014cSj_mayer } 178e9df014cSj_mayer 179aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu) 180e9df014cSj_mayer { 181aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 182a0961245SAndreas Färber 183a0961245SAndreas Färber env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, 1847b62a955Sj_mayer PPC6xx_INPUT_NB); 18547103572Sj_mayer } 18647103572Sj_mayer 18700af685fSj_mayer #if defined(TARGET_PPC64) 188d0dfae6eSj_mayer /* PowerPC 970 internal IRQ controller */ 189d0dfae6eSj_mayer static void ppc970_set_irq(void *opaque, int pin, int level) 190d0dfae6eSj_mayer { 191a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 192a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 193d0dfae6eSj_mayer int cur_level; 194d0dfae6eSj_mayer 195d12d51d5Saliguori LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 196d0dfae6eSj_mayer env, pin, level); 197d0dfae6eSj_mayer cur_level = (env->irq_input_state >> pin) & 1; 198d0dfae6eSj_mayer /* Don't generate spurious events */ 199d0dfae6eSj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 200259186a7SAndreas Färber CPUState *cs = CPU(cpu); 201259186a7SAndreas Färber 202d0dfae6eSj_mayer switch (pin) { 203d0dfae6eSj_mayer case PPC970_INPUT_INT: 204d0dfae6eSj_mayer /* Level sensitive - active high */ 205d12d51d5Saliguori LOG_IRQ("%s: set the external IRQ state to %d\n", 206d0dfae6eSj_mayer __func__, level); 2077058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 208d0dfae6eSj_mayer break; 209d0dfae6eSj_mayer case PPC970_INPUT_THINT: 210d0dfae6eSj_mayer /* Level sensitive - active high */ 211d12d51d5Saliguori LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, 212d0dfae6eSj_mayer level); 2137058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 214d0dfae6eSj_mayer break; 215d0dfae6eSj_mayer case PPC970_INPUT_MCP: 216d0dfae6eSj_mayer /* Negative edge sensitive */ 217d0dfae6eSj_mayer /* XXX: TODO: actual reaction may depends on HID0 status 218d0dfae6eSj_mayer * 603/604/740/750: check HID0[EMCP] 219d0dfae6eSj_mayer */ 220d0dfae6eSj_mayer if (cur_level == 1 && level == 0) { 221d12d51d5Saliguori LOG_IRQ("%s: raise machine check state\n", 222d0dfae6eSj_mayer __func__); 2237058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 224d0dfae6eSj_mayer } 225d0dfae6eSj_mayer break; 226d0dfae6eSj_mayer case PPC970_INPUT_CKSTP: 227d0dfae6eSj_mayer /* Level sensitive - active low */ 228d0dfae6eSj_mayer /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 229d0dfae6eSj_mayer if (level) { 230d12d51d5Saliguori LOG_IRQ("%s: stop the CPU\n", __func__); 231259186a7SAndreas Färber cs->halted = 1; 232d0dfae6eSj_mayer } else { 233d12d51d5Saliguori LOG_IRQ("%s: restart the CPU\n", __func__); 234259186a7SAndreas Färber cs->halted = 0; 235259186a7SAndreas Färber qemu_cpu_kick(cs); 236d0dfae6eSj_mayer } 237d0dfae6eSj_mayer break; 238d0dfae6eSj_mayer case PPC970_INPUT_HRESET: 239d0dfae6eSj_mayer /* Level sensitive - active low */ 240d0dfae6eSj_mayer if (level) { 241c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 242d0dfae6eSj_mayer } 243d0dfae6eSj_mayer break; 244d0dfae6eSj_mayer case PPC970_INPUT_SRESET: 245d12d51d5Saliguori LOG_IRQ("%s: set the RESET IRQ state to %d\n", 246d0dfae6eSj_mayer __func__, level); 2477058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 248d0dfae6eSj_mayer break; 249d0dfae6eSj_mayer case PPC970_INPUT_TBEN: 250d12d51d5Saliguori LOG_IRQ("%s: set the TBEN state to %d\n", __func__, 251d0dfae6eSj_mayer level); 252d0dfae6eSj_mayer /* XXX: TODO */ 253d0dfae6eSj_mayer break; 254d0dfae6eSj_mayer default: 255d0dfae6eSj_mayer /* Unknown pin - do nothing */ 256d12d51d5Saliguori LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 257d0dfae6eSj_mayer return; 258d0dfae6eSj_mayer } 259d0dfae6eSj_mayer if (level) 260d0dfae6eSj_mayer env->irq_input_state |= 1 << pin; 261d0dfae6eSj_mayer else 262d0dfae6eSj_mayer env->irq_input_state &= ~(1 << pin); 263d0dfae6eSj_mayer } 264d0dfae6eSj_mayer } 265d0dfae6eSj_mayer 266aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu) 267d0dfae6eSj_mayer { 268aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 269a0961245SAndreas Färber 270a0961245SAndreas Färber env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, 2717b62a955Sj_mayer PPC970_INPUT_NB); 272d0dfae6eSj_mayer } 2739d52e907SDavid Gibson 2749d52e907SDavid Gibson /* POWER7 internal IRQ controller */ 2759d52e907SDavid Gibson static void power7_set_irq(void *opaque, int pin, int level) 2769d52e907SDavid Gibson { 277a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 2789d52e907SDavid Gibson 2799d52e907SDavid Gibson LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 280c1ad0b89SGreg Kurz &cpu->env, pin, level); 2819d52e907SDavid Gibson 2829d52e907SDavid Gibson switch (pin) { 2839d52e907SDavid Gibson case POWER7_INPUT_INT: 2849d52e907SDavid Gibson /* Level sensitive - active high */ 2859d52e907SDavid Gibson LOG_IRQ("%s: set the external IRQ state to %d\n", 2869d52e907SDavid Gibson __func__, level); 2877058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 2889d52e907SDavid Gibson break; 2899d52e907SDavid Gibson default: 2909d52e907SDavid Gibson /* Unknown pin - do nothing */ 2919d52e907SDavid Gibson LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 2929d52e907SDavid Gibson return; 2939d52e907SDavid Gibson } 2949d52e907SDavid Gibson } 2959d52e907SDavid Gibson 296aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 2979d52e907SDavid Gibson { 298aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 299a0961245SAndreas Färber 300a0961245SAndreas Färber env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, 3019d52e907SDavid Gibson POWER7_INPUT_NB); 3029d52e907SDavid Gibson } 30367afe775SBenjamin Herrenschmidt 30467afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 30567afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 30667afe775SBenjamin Herrenschmidt { 30767afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 30867afe775SBenjamin Herrenschmidt 30967afe775SBenjamin Herrenschmidt LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 310c1ad0b89SGreg Kurz &cpu->env, pin, level); 31167afe775SBenjamin Herrenschmidt 31267afe775SBenjamin Herrenschmidt switch (pin) { 31367afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 31467afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 31567afe775SBenjamin Herrenschmidt LOG_IRQ("%s: set the external IRQ state to %d\n", 31667afe775SBenjamin Herrenschmidt __func__, level); 31767afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 31867afe775SBenjamin Herrenschmidt break; 31967afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 32067afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 32167afe775SBenjamin Herrenschmidt LOG_IRQ("%s: set the external IRQ state to %d\n", 32267afe775SBenjamin Herrenschmidt __func__, level); 32367afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 32467afe775SBenjamin Herrenschmidt break; 32567afe775SBenjamin Herrenschmidt default: 32667afe775SBenjamin Herrenschmidt /* Unknown pin - do nothing */ 32767afe775SBenjamin Herrenschmidt LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 32867afe775SBenjamin Herrenschmidt return; 32967afe775SBenjamin Herrenschmidt } 33067afe775SBenjamin Herrenschmidt } 33167afe775SBenjamin Herrenschmidt 33267afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 33367afe775SBenjamin Herrenschmidt { 33467afe775SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 33567afe775SBenjamin Herrenschmidt 33667afe775SBenjamin Herrenschmidt env->irq_inputs = (void **)qemu_allocate_irqs(&power9_set_irq, cpu, 33767afe775SBenjamin Herrenschmidt POWER9_INPUT_NB); 33867afe775SBenjamin Herrenschmidt } 33900af685fSj_mayer #endif /* defined(TARGET_PPC64) */ 340d0dfae6eSj_mayer 34152144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 34252144b69SThomas Huth { 34352144b69SThomas Huth CPUPPCState *env = &cpu->env; 34452144b69SThomas Huth target_ulong dbsr; 34552144b69SThomas Huth 34652144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 34752144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 34852144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 34952144b69SThomas Huth dbsr &= ~0x00000300; 35052144b69SThomas Huth dbsr |= 0x00000100; 35152144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 35252144b69SThomas Huth } 35352144b69SThomas Huth 35452144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 35552144b69SThomas Huth { 35652144b69SThomas Huth CPUPPCState *env = &cpu->env; 35752144b69SThomas Huth target_ulong dbsr; 35852144b69SThomas Huth 35952144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 36052144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 36152144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 36252144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 36352144b69SThomas Huth dbsr &= ~0x00000300; 36452144b69SThomas Huth dbsr |= 0x00000200; 36552144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 36652144b69SThomas Huth } 36752144b69SThomas Huth 36852144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 36952144b69SThomas Huth { 37052144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 37152144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 37252144b69SThomas Huth } 37352144b69SThomas Huth 37452144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 37552144b69SThomas Huth { 376db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 37752144b69SThomas Huth 37852144b69SThomas Huth switch ((val >> 28) & 0x3) { 37952144b69SThomas Huth case 0x0: 38052144b69SThomas Huth /* No action */ 38152144b69SThomas Huth break; 38252144b69SThomas Huth case 0x1: 38352144b69SThomas Huth /* Core reset */ 38452144b69SThomas Huth ppc40x_core_reset(cpu); 38552144b69SThomas Huth break; 38652144b69SThomas Huth case 0x2: 38752144b69SThomas Huth /* Chip reset */ 38852144b69SThomas Huth ppc40x_chip_reset(cpu); 38952144b69SThomas Huth break; 39052144b69SThomas Huth case 0x3: 39152144b69SThomas Huth /* System reset */ 39252144b69SThomas Huth ppc40x_system_reset(cpu); 39352144b69SThomas Huth break; 39452144b69SThomas Huth } 39552144b69SThomas Huth } 39652144b69SThomas Huth 3974e290a0bSj_mayer /* PowerPC 40x internal IRQ controller */ 3984e290a0bSj_mayer static void ppc40x_set_irq(void *opaque, int pin, int level) 39924be5ae3Sj_mayer { 400a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 401a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 40224be5ae3Sj_mayer int cur_level; 40324be5ae3Sj_mayer 404d12d51d5Saliguori LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 4058ecc7913Sj_mayer env, pin, level); 40624be5ae3Sj_mayer cur_level = (env->irq_input_state >> pin) & 1; 40724be5ae3Sj_mayer /* Don't generate spurious events */ 40824be5ae3Sj_mayer if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 409259186a7SAndreas Färber CPUState *cs = CPU(cpu); 410259186a7SAndreas Färber 41124be5ae3Sj_mayer switch (pin) { 4124e290a0bSj_mayer case PPC40x_INPUT_RESET_SYS: 4138ecc7913Sj_mayer if (level) { 414d12d51d5Saliguori LOG_IRQ("%s: reset the PowerPC system\n", 4158ecc7913Sj_mayer __func__); 416f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 4178ecc7913Sj_mayer } 4188ecc7913Sj_mayer break; 4194e290a0bSj_mayer case PPC40x_INPUT_RESET_CHIP: 4208ecc7913Sj_mayer if (level) { 421d12d51d5Saliguori LOG_IRQ("%s: reset the PowerPC chip\n", __func__); 422f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 4238ecc7913Sj_mayer } 4248ecc7913Sj_mayer break; 4254e290a0bSj_mayer case PPC40x_INPUT_RESET_CORE: 42624be5ae3Sj_mayer /* XXX: TODO: update DBSR[MRR] */ 42724be5ae3Sj_mayer if (level) { 428d12d51d5Saliguori LOG_IRQ("%s: reset the PowerPC core\n", __func__); 429f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 43024be5ae3Sj_mayer } 43124be5ae3Sj_mayer break; 4324e290a0bSj_mayer case PPC40x_INPUT_CINT: 43324be5ae3Sj_mayer /* Level sensitive - active high */ 434d12d51d5Saliguori LOG_IRQ("%s: set the critical IRQ state to %d\n", 4358ecc7913Sj_mayer __func__, level); 4367058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 43724be5ae3Sj_mayer break; 4384e290a0bSj_mayer case PPC40x_INPUT_INT: 43924be5ae3Sj_mayer /* Level sensitive - active high */ 440d12d51d5Saliguori LOG_IRQ("%s: set the external IRQ state to %d\n", 441a496775fSj_mayer __func__, level); 4427058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 44324be5ae3Sj_mayer break; 4444e290a0bSj_mayer case PPC40x_INPUT_HALT: 44524be5ae3Sj_mayer /* Level sensitive - active low */ 44624be5ae3Sj_mayer if (level) { 447d12d51d5Saliguori LOG_IRQ("%s: stop the CPU\n", __func__); 448259186a7SAndreas Färber cs->halted = 1; 44924be5ae3Sj_mayer } else { 450d12d51d5Saliguori LOG_IRQ("%s: restart the CPU\n", __func__); 451259186a7SAndreas Färber cs->halted = 0; 452259186a7SAndreas Färber qemu_cpu_kick(cs); 45324be5ae3Sj_mayer } 45424be5ae3Sj_mayer break; 4554e290a0bSj_mayer case PPC40x_INPUT_DEBUG: 45624be5ae3Sj_mayer /* Level sensitive - active high */ 457d12d51d5Saliguori LOG_IRQ("%s: set the debug pin state to %d\n", 458a496775fSj_mayer __func__, level); 4597058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 46024be5ae3Sj_mayer break; 46124be5ae3Sj_mayer default: 46224be5ae3Sj_mayer /* Unknown pin - do nothing */ 463d12d51d5Saliguori LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 46424be5ae3Sj_mayer return; 46524be5ae3Sj_mayer } 46624be5ae3Sj_mayer if (level) 46724be5ae3Sj_mayer env->irq_input_state |= 1 << pin; 46824be5ae3Sj_mayer else 46924be5ae3Sj_mayer env->irq_input_state &= ~(1 << pin); 47024be5ae3Sj_mayer } 47124be5ae3Sj_mayer } 47224be5ae3Sj_mayer 473aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 47424be5ae3Sj_mayer { 475aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 476a0961245SAndreas Färber 4774e290a0bSj_mayer env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, 478a0961245SAndreas Färber cpu, PPC40x_INPUT_NB); 47924be5ae3Sj_mayer } 48024be5ae3Sj_mayer 4819fdc60bfSaurel32 /* PowerPC E500 internal IRQ controller */ 4829fdc60bfSaurel32 static void ppce500_set_irq(void *opaque, int pin, int level) 4839fdc60bfSaurel32 { 484a0961245SAndreas Färber PowerPCCPU *cpu = opaque; 485a0961245SAndreas Färber CPUPPCState *env = &cpu->env; 4869fdc60bfSaurel32 int cur_level; 4879fdc60bfSaurel32 4889fdc60bfSaurel32 LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 4899fdc60bfSaurel32 env, pin, level); 4909fdc60bfSaurel32 cur_level = (env->irq_input_state >> pin) & 1; 4919fdc60bfSaurel32 /* Don't generate spurious events */ 4929fdc60bfSaurel32 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 4939fdc60bfSaurel32 switch (pin) { 4949fdc60bfSaurel32 case PPCE500_INPUT_MCK: 4959fdc60bfSaurel32 if (level) { 4969fdc60bfSaurel32 LOG_IRQ("%s: reset the PowerPC system\n", 4979fdc60bfSaurel32 __func__); 498cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 4999fdc60bfSaurel32 } 5009fdc60bfSaurel32 break; 5019fdc60bfSaurel32 case PPCE500_INPUT_RESET_CORE: 5029fdc60bfSaurel32 if (level) { 5039fdc60bfSaurel32 LOG_IRQ("%s: reset the PowerPC core\n", __func__); 5047058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 5059fdc60bfSaurel32 } 5069fdc60bfSaurel32 break; 5079fdc60bfSaurel32 case PPCE500_INPUT_CINT: 5089fdc60bfSaurel32 /* Level sensitive - active high */ 5099fdc60bfSaurel32 LOG_IRQ("%s: set the critical IRQ state to %d\n", 5109fdc60bfSaurel32 __func__, level); 5117058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 5129fdc60bfSaurel32 break; 5139fdc60bfSaurel32 case PPCE500_INPUT_INT: 5149fdc60bfSaurel32 /* Level sensitive - active high */ 5159fdc60bfSaurel32 LOG_IRQ("%s: set the core IRQ state to %d\n", 5169fdc60bfSaurel32 __func__, level); 5177058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 5189fdc60bfSaurel32 break; 5199fdc60bfSaurel32 case PPCE500_INPUT_DEBUG: 5209fdc60bfSaurel32 /* Level sensitive - active high */ 5219fdc60bfSaurel32 LOG_IRQ("%s: set the debug pin state to %d\n", 5229fdc60bfSaurel32 __func__, level); 5237058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 5249fdc60bfSaurel32 break; 5259fdc60bfSaurel32 default: 5269fdc60bfSaurel32 /* Unknown pin - do nothing */ 5279fdc60bfSaurel32 LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 5289fdc60bfSaurel32 return; 5299fdc60bfSaurel32 } 5309fdc60bfSaurel32 if (level) 5319fdc60bfSaurel32 env->irq_input_state |= 1 << pin; 5329fdc60bfSaurel32 else 5339fdc60bfSaurel32 env->irq_input_state &= ~(1 << pin); 5349fdc60bfSaurel32 } 5359fdc60bfSaurel32 } 5369fdc60bfSaurel32 537aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 5389fdc60bfSaurel32 { 539aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 540a0961245SAndreas Färber 5419fdc60bfSaurel32 env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, 542a0961245SAndreas Färber cpu, PPCE500_INPUT_NB); 5439fdc60bfSaurel32 } 544e49798b1SAlexander Graf 545e49798b1SAlexander Graf /* Enable or Disable the E500 EPR capability */ 546e49798b1SAlexander Graf void ppce500_set_mpic_proxy(bool enabled) 547e49798b1SAlexander Graf { 548182735efSAndreas Färber CPUState *cs; 549e49798b1SAlexander Graf 550bdc44640SAndreas Färber CPU_FOREACH(cs) { 551182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 5525b95b8b9SAlexander Graf 553182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 5545b95b8b9SAlexander Graf if (kvm_enabled()) { 555182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 5565b95b8b9SAlexander Graf } 557e49798b1SAlexander Graf } 558e49798b1SAlexander Graf } 559e49798b1SAlexander Graf 5609fddaa0cSbellard /*****************************************************************************/ 561e9df014cSj_mayer /* PowerPC time base and decrementer emulation */ 5629fddaa0cSbellard 563ddd1055bSFabien Chouteau uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 5649fddaa0cSbellard { 5659fddaa0cSbellard /* TB time in tb periods */ 56673bcb24dSRutuja Shah return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; 5679fddaa0cSbellard } 5689fddaa0cSbellard 569e2684c0bSAndreas Färber uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 5709fddaa0cSbellard { 571c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 5729fddaa0cSbellard uint64_t tb; 5739fddaa0cSbellard 57490dc8812SScott Wood if (kvm_enabled()) { 57590dc8812SScott Wood return env->spr[SPR_TBL]; 57690dc8812SScott Wood } 57790dc8812SScott Wood 578bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 579d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 5809fddaa0cSbellard 581e3ea6529SAlexander Graf return tb; 5829fddaa0cSbellard } 5839fddaa0cSbellard 584e2684c0bSAndreas Färber static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 5859fddaa0cSbellard { 586c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 5879fddaa0cSbellard uint64_t tb; 5889fddaa0cSbellard 589bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 590d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 59176a66253Sj_mayer 5929fddaa0cSbellard return tb >> 32; 5939fddaa0cSbellard } 5949fddaa0cSbellard 595e2684c0bSAndreas Färber uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 5968a84de23Sj_mayer { 59790dc8812SScott Wood if (kvm_enabled()) { 59890dc8812SScott Wood return env->spr[SPR_TBU]; 59990dc8812SScott Wood } 60090dc8812SScott Wood 6018a84de23Sj_mayer return _cpu_ppc_load_tbu(env); 6028a84de23Sj_mayer } 6038a84de23Sj_mayer 604c227f099SAnthony Liguori static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 605636aa200SBlue Swirl int64_t *tb_offsetp, uint64_t value) 6069fddaa0cSbellard { 60773bcb24dSRutuja Shah *tb_offsetp = value - 60873bcb24dSRutuja Shah muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 60973bcb24dSRutuja Shah 610d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n", 611aae9366aSj_mayer __func__, value, *tb_offsetp); 612a496775fSj_mayer } 6139fddaa0cSbellard 614e2684c0bSAndreas Färber void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 6159fddaa0cSbellard { 616c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 617a062e36cSj_mayer uint64_t tb; 6189fddaa0cSbellard 619bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 620a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 621bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 622dbdd2506Sj_mayer &tb_env->tb_offset, tb | (uint64_t)value); 623a062e36cSj_mayer } 624a062e36cSj_mayer 625e2684c0bSAndreas Färber static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 626a062e36cSj_mayer { 627c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 628a062e36cSj_mayer uint64_t tb; 629a062e36cSj_mayer 630bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 631a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 632bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 633dbdd2506Sj_mayer &tb_env->tb_offset, ((uint64_t)value << 32) | tb); 634a062e36cSj_mayer } 635a062e36cSj_mayer 636e2684c0bSAndreas Färber void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 6378a84de23Sj_mayer { 6388a84de23Sj_mayer _cpu_ppc_store_tbu(env, value); 6398a84de23Sj_mayer } 6408a84de23Sj_mayer 641e2684c0bSAndreas Färber uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 642a062e36cSj_mayer { 643c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 644a062e36cSj_mayer uint64_t tb; 645a062e36cSj_mayer 646bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 647d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 648a062e36cSj_mayer 649b711de95SAurelien Jarno return tb; 650a062e36cSj_mayer } 651a062e36cSj_mayer 652e2684c0bSAndreas Färber uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 653a062e36cSj_mayer { 654c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 655a062e36cSj_mayer uint64_t tb; 656a062e36cSj_mayer 657bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 658d12d51d5Saliguori LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 659a062e36cSj_mayer 660a062e36cSj_mayer return tb >> 32; 661a062e36cSj_mayer } 662a062e36cSj_mayer 663e2684c0bSAndreas Färber void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 664a062e36cSj_mayer { 665c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 666a062e36cSj_mayer uint64_t tb; 667a062e36cSj_mayer 668bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 669a062e36cSj_mayer tb &= 0xFFFFFFFF00000000ULL; 670bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 671dbdd2506Sj_mayer &tb_env->atb_offset, tb | (uint64_t)value); 672a062e36cSj_mayer } 673a062e36cSj_mayer 674e2684c0bSAndreas Färber void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 675a062e36cSj_mayer { 676c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 677a062e36cSj_mayer uint64_t tb; 678a062e36cSj_mayer 679bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 680a062e36cSj_mayer tb &= 0x00000000FFFFFFFFULL; 681bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 682dbdd2506Sj_mayer &tb_env->atb_offset, ((uint64_t)value << 32) | tb); 683dbdd2506Sj_mayer } 684dbdd2506Sj_mayer 6855d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6865d62725bSSuraj Jitindar Singh { 6875d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6885d62725bSSuraj Jitindar Singh 6895d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6905d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6915d62725bSSuraj Jitindar Singh } 6925d62725bSSuraj Jitindar Singh 6935d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6945d62725bSSuraj Jitindar Singh { 6955d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6965d62725bSSuraj Jitindar Singh 6975d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6985d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 6995d62725bSSuraj Jitindar Singh } 7005d62725bSSuraj Jitindar Singh 701e2684c0bSAndreas Färber static void cpu_ppc_tb_stop (CPUPPCState *env) 702dbdd2506Sj_mayer { 703c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 704dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 705dbdd2506Sj_mayer 706dbdd2506Sj_mayer /* If the time base is already frozen, do nothing */ 707dbdd2506Sj_mayer if (tb_env->tb_freq != 0) { 708bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 709dbdd2506Sj_mayer /* Get the time base */ 710dbdd2506Sj_mayer tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 711dbdd2506Sj_mayer /* Get the alternate time base */ 712dbdd2506Sj_mayer atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 713dbdd2506Sj_mayer /* Store the time base value (ie compute the current offset) */ 714dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 715dbdd2506Sj_mayer /* Store the alternate time base value (compute the current offset) */ 716dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 717dbdd2506Sj_mayer /* Set the time base frequency to zero */ 718dbdd2506Sj_mayer tb_env->tb_freq = 0; 719dbdd2506Sj_mayer /* Now, the time bases are frozen to tb_offset / atb_offset value */ 720dbdd2506Sj_mayer } 721dbdd2506Sj_mayer } 722dbdd2506Sj_mayer 723e2684c0bSAndreas Färber static void cpu_ppc_tb_start (CPUPPCState *env) 724dbdd2506Sj_mayer { 725c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 726dbdd2506Sj_mayer uint64_t tb, atb, vmclk; 727dbdd2506Sj_mayer 728dbdd2506Sj_mayer /* If the time base is not frozen, do nothing */ 729dbdd2506Sj_mayer if (tb_env->tb_freq == 0) { 730bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 731dbdd2506Sj_mayer /* Get the time base from tb_offset */ 732dbdd2506Sj_mayer tb = tb_env->tb_offset; 733dbdd2506Sj_mayer /* Get the alternate time base from atb_offset */ 734dbdd2506Sj_mayer atb = tb_env->atb_offset; 735dbdd2506Sj_mayer /* Restore the tb frequency from the decrementer frequency */ 736dbdd2506Sj_mayer tb_env->tb_freq = tb_env->decr_freq; 737dbdd2506Sj_mayer /* Store the time base value */ 738dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 739dbdd2506Sj_mayer /* Store the alternate time base value */ 740dbdd2506Sj_mayer cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 741dbdd2506Sj_mayer } 7429fddaa0cSbellard } 7439fddaa0cSbellard 744e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 745e81a982aSAlexander Graf { 746e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 747e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 748e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 749e81a982aSAlexander Graf } 750e81a982aSAlexander Graf 751a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 7529fddaa0cSbellard { 753c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 754a8dafa52SSuraj Jitindar Singh int64_t decr, diff; 7559fddaa0cSbellard 756bc72ad67SAlex Bligh diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 757ddd1055bSFabien Chouteau if (diff >= 0) { 75873bcb24dSRutuja Shah decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 759ddd1055bSFabien Chouteau } else if (tb_env->flags & PPC_TIMER_BOOKE) { 760ddd1055bSFabien Chouteau decr = 0; 761ddd1055bSFabien Chouteau } else { 76273bcb24dSRutuja Shah decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 763ddd1055bSFabien Chouteau } 764a8dafa52SSuraj Jitindar Singh LOG_TB("%s: %016" PRIx64 "\n", __func__, decr); 76576a66253Sj_mayer 7669fddaa0cSbellard return decr; 7679fddaa0cSbellard } 7689fddaa0cSbellard 769a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env) 77058a7d328Sj_mayer { 771c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 772a8dafa52SSuraj Jitindar Singh uint64_t decr; 77358a7d328Sj_mayer 77490dc8812SScott Wood if (kvm_enabled()) { 77590dc8812SScott Wood return env->spr[SPR_DECR]; 77690dc8812SScott Wood } 77790dc8812SScott Wood 778a8dafa52SSuraj Jitindar Singh decr = _cpu_ppc_load_decr(env, tb_env->decr_next); 779a8dafa52SSuraj Jitindar Singh 780a8dafa52SSuraj Jitindar Singh /* 781a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 782a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 783a8dafa52SSuraj Jitindar Singh */ 784a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 785a8dafa52SSuraj Jitindar Singh return decr; 786a8dafa52SSuraj Jitindar Singh } 787a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 78858a7d328Sj_mayer } 78958a7d328Sj_mayer 790a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 79158a7d328Sj_mayer { 792db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 793a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 794c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 795a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 79658a7d328Sj_mayer 797a8dafa52SSuraj Jitindar Singh hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); 798a8dafa52SSuraj Jitindar Singh 799a8dafa52SSuraj Jitindar Singh /* 800a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 801a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 802a8dafa52SSuraj Jitindar Singh */ 803a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 804a8dafa52SSuraj Jitindar Singh return hdecr; 805a8dafa52SSuraj Jitindar Singh } 806a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 80758a7d328Sj_mayer } 80858a7d328Sj_mayer 809e2684c0bSAndreas Färber uint64_t cpu_ppc_load_purr (CPUPPCState *env) 81058a7d328Sj_mayer { 811c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 81258a7d328Sj_mayer 813*5cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 814*5cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 81558a7d328Sj_mayer } 81658a7d328Sj_mayer 8179fddaa0cSbellard /* When decrementer expires, 8189fddaa0cSbellard * all we need to do is generate or queue a CPU exception 8199fddaa0cSbellard */ 8207e0a9247SAndreas Färber static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 8219fddaa0cSbellard { 8229fddaa0cSbellard /* Raise it */ 823d12d51d5Saliguori LOG_TB("raise decrementer exception\n"); 8247058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 8259fddaa0cSbellard } 8269fddaa0cSbellard 827e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 828e81a982aSAlexander Graf { 829e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 830e81a982aSAlexander Graf } 831e81a982aSAlexander Graf 8327e0a9247SAndreas Färber static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 83358a7d328Sj_mayer { 8344b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 8354b236b62SBenjamin Herrenschmidt 83658a7d328Sj_mayer /* Raise it */ 8374b236b62SBenjamin Herrenschmidt LOG_TB("raise hv decrementer exception\n"); 8384b236b62SBenjamin Herrenschmidt 8394b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 8404b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 8414b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 8424b236b62SBenjamin Herrenschmidt */ 8431e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 8447058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 84558a7d328Sj_mayer } 8464b236b62SBenjamin Herrenschmidt } 84758a7d328Sj_mayer 848e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 849e81a982aSAlexander Graf { 850e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 851e81a982aSAlexander Graf } 852e81a982aSAlexander Graf 8537e0a9247SAndreas Färber static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 8541246b259SStefan Weil QEMUTimer *timer, 855e81a982aSAlexander Graf void (*raise_excp)(void *), 856e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 857a8dafa52SSuraj Jitindar Singh target_ulong decr, target_ulong value, 858a8dafa52SSuraj Jitindar Singh int nr_bits) 8599fddaa0cSbellard { 8607e0a9247SAndreas Färber CPUPPCState *env = &cpu->env; 861c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 8629fddaa0cSbellard uint64_t now, next; 863a8dafa52SSuraj Jitindar Singh bool negative; 8649fddaa0cSbellard 865a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 866a8dafa52SSuraj Jitindar Singh value &= ((1ULL << nr_bits) - 1); 867a8dafa52SSuraj Jitindar Singh negative = !!(value & (1ULL << (nr_bits - 1))); 868a8dafa52SSuraj Jitindar Singh if (negative) { 869a8dafa52SSuraj Jitindar Singh value |= (0xFFFFFFFFULL << nr_bits); 870a8dafa52SSuraj Jitindar Singh } 871a8dafa52SSuraj Jitindar Singh 872a8dafa52SSuraj Jitindar Singh LOG_TB("%s: " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, 873aae9366aSj_mayer decr, value); 87455f7d4b0SDavid Gibson 87555f7d4b0SDavid Gibson if (kvm_enabled()) { 87655f7d4b0SDavid Gibson /* KVM handles decrementer exceptions, we don't need our own timer */ 87755f7d4b0SDavid Gibson return; 87855f7d4b0SDavid Gibson } 87955f7d4b0SDavid Gibson 880e81a982aSAlexander Graf /* 881e81a982aSAlexander Graf * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC 882e81a982aSAlexander Graf * interrupt. 883e81a982aSAlexander Graf * 884e81a982aSAlexander Graf * If we get a really small DEC value, we can assume that by the time we 885e81a982aSAlexander Graf * handled it we should inject an interrupt already. 886e81a982aSAlexander Graf * 887e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 888e81a982aSAlexander Graf * is pending, so raise it on those. 889e81a982aSAlexander Graf * 890e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 891e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 892e81a982aSAlexander Graf */ 893e81a982aSAlexander Graf if ((value < 3) || 894a8dafa52SSuraj Jitindar Singh ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && negative) || 895a8dafa52SSuraj Jitindar Singh ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && negative 896a8dafa52SSuraj Jitindar Singh && !(decr & (1ULL << (nr_bits - 1))))) { 897e81a982aSAlexander Graf (*raise_excp)(cpu); 898e81a982aSAlexander Graf return; 899e81a982aSAlexander Graf } 900e81a982aSAlexander Graf 901e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 902a8dafa52SSuraj Jitindar Singh if (!negative && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) { 903e81a982aSAlexander Graf (*lower_excp)(cpu); 904e81a982aSAlexander Graf } 905e81a982aSAlexander Graf 906e81a982aSAlexander Graf /* Calculate the next timer event */ 907bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 90873bcb24dSRutuja Shah next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 90958a7d328Sj_mayer *nextp = next; 910e81a982aSAlexander Graf 9119fddaa0cSbellard /* Adjust timer */ 912bc72ad67SAlex Bligh timer_mod(timer, next); 913ddd1055bSFabien Chouteau } 91458a7d328Sj_mayer 915a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr, 916a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 91758a7d328Sj_mayer { 9187e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 91958a7d328Sj_mayer 9207e0a9247SAndreas Färber __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, 921e81a982aSAlexander Graf tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr, 922a8dafa52SSuraj Jitindar Singh value, nr_bits); 9239fddaa0cSbellard } 9249fddaa0cSbellard 925a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) 9269fddaa0cSbellard { 927db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 928a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 929a8dafa52SSuraj Jitindar Singh int nr_bits = 32; 9307e0a9247SAndreas Färber 931a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 932a8dafa52SSuraj Jitindar Singh nr_bits = pcc->lrg_decr_bits; 933a8dafa52SSuraj Jitindar Singh } 934a8dafa52SSuraj Jitindar Singh 935a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits); 9369fddaa0cSbellard } 9379fddaa0cSbellard 9389fddaa0cSbellard static void cpu_ppc_decr_cb(void *opaque) 9399fddaa0cSbellard { 94050c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 9417e0a9247SAndreas Färber 942e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 9439fddaa0cSbellard } 9449fddaa0cSbellard 945a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr, 946a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 94758a7d328Sj_mayer { 9487e0a9247SAndreas Färber ppc_tb_t *tb_env = cpu->env.tb_env; 94958a7d328Sj_mayer 950b172c56aSj_mayer if (tb_env->hdecr_timer != NULL) { 9517e0a9247SAndreas Färber __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 952e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 953a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 95458a7d328Sj_mayer } 955b172c56aSj_mayer } 95658a7d328Sj_mayer 957a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 95858a7d328Sj_mayer { 959db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 960a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 9617e0a9247SAndreas Färber 962a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 963a8dafa52SSuraj Jitindar Singh pcc->lrg_decr_bits); 96458a7d328Sj_mayer } 96558a7d328Sj_mayer 96658a7d328Sj_mayer static void cpu_ppc_hdecr_cb(void *opaque) 96758a7d328Sj_mayer { 96850c680f0SAndreas Färber PowerPCCPU *cpu = opaque; 9697e0a9247SAndreas Färber 970e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 97158a7d328Sj_mayer } 97258a7d328Sj_mayer 973*5cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 97458a7d328Sj_mayer { 975*5cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 97658a7d328Sj_mayer 977*5cc7e69fSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 978*5cc7e69fSSuraj Jitindar Singh &tb_env->purr_offset, value); 97958a7d328Sj_mayer } 98058a7d328Sj_mayer 9818ecc7913Sj_mayer static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 9828ecc7913Sj_mayer { 983e2684c0bSAndreas Färber CPUPPCState *env = opaque; 984db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 985c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 9868ecc7913Sj_mayer 9878ecc7913Sj_mayer tb_env->tb_freq = freq; 988dbdd2506Sj_mayer tb_env->decr_freq = freq; 9898ecc7913Sj_mayer /* There is a bug in Linux 2.4 kernels: 9908ecc7913Sj_mayer * if a decrementer exception is pending when it enables msr_ee at startup, 9918ecc7913Sj_mayer * it's not ready to handle it... 9928ecc7913Sj_mayer */ 993a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 994a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 995*5cc7e69fSSuraj Jitindar Singh cpu_ppc_store_purr(env, 0x0000000000000000ULL); 9968ecc7913Sj_mayer } 9978ecc7913Sj_mayer 99842043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 99998a8b524SAlexey Kardashevskiy { 10004a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 100198a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 100298a8b524SAlexey Kardashevskiy 100398a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 100498a8b524SAlexey Kardashevskiy error_report("No timebase object"); 100598a8b524SAlexey Kardashevskiy return; 100698a8b524SAlexey Kardashevskiy } 100798a8b524SAlexey Kardashevskiy 100842043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 100977bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 101098a8b524SAlexey Kardashevskiy /* 101142043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 101298a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 101398a8b524SAlexey Kardashevskiy */ 101498a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 1015d14f3397SMaxiwell S. Garcia 1016d14f3397SMaxiwell S. Garcia tb->runstate_paused = runstate_check(RUN_STATE_PAUSED); 101798a8b524SAlexey Kardashevskiy } 101898a8b524SAlexey Kardashevskiy 101942043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 102098a8b524SAlexey Kardashevskiy { 102198a8b524SAlexey Kardashevskiy CPUState *cpu; 102298a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 102342043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 102498a8b524SAlexey Kardashevskiy unsigned long freq; 102598a8b524SAlexey Kardashevskiy 102698a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 102798a8b524SAlexey Kardashevskiy error_report("No timebase object"); 102842043e4fSLaurent Vivier return; 102998a8b524SAlexey Kardashevskiy } 103098a8b524SAlexey Kardashevskiy 103198a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 103298a8b524SAlexey Kardashevskiy 103342043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 103498a8b524SAlexey Kardashevskiy 103598a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 103698a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 103798a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 103898a8b524SAlexey Kardashevskiy 103998a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 104098a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 104198a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 104298a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 10439723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 104442043e4fSLaurent Vivier } 104598a8b524SAlexey Kardashevskiy } 104698a8b524SAlexey Kardashevskiy 104742043e4fSLaurent Vivier void cpu_ppc_clock_vm_state_change(void *opaque, int running, 104842043e4fSLaurent Vivier RunState state) 104942043e4fSLaurent Vivier { 105042043e4fSLaurent Vivier PPCTimebase *tb = opaque; 105142043e4fSLaurent Vivier 105242043e4fSLaurent Vivier if (running) { 105342043e4fSLaurent Vivier timebase_load(tb); 105442043e4fSLaurent Vivier } else { 105542043e4fSLaurent Vivier timebase_save(tb); 105642043e4fSLaurent Vivier } 105742043e4fSLaurent Vivier } 105842043e4fSLaurent Vivier 105942043e4fSLaurent Vivier /* 1060d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 1061d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 1062d14f3397SMaxiwell S. Garcia * during the events between: 106342043e4fSLaurent Vivier * 106442043e4fSLaurent Vivier * * vm_stop() 106542043e4fSLaurent Vivier * * 106642043e4fSLaurent Vivier * * pre_save() 106742043e4fSLaurent Vivier * 106842043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 106942043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 107042043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 107142043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 107242043e4fSLaurent Vivier */ 107344b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 107442043e4fSLaurent Vivier { 107542043e4fSLaurent Vivier PPCTimebase *tb = opaque; 107642043e4fSLaurent Vivier 1077d14f3397SMaxiwell S. Garcia /* guest_timebase won't be overridden in case of paused guest */ 1078d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 107942043e4fSLaurent Vivier timebase_save(tb); 1080d14f3397SMaxiwell S. Garcia } 108144b1ff31SDr. David Alan Gilbert 108244b1ff31SDr. David Alan Gilbert return 0; 108398a8b524SAlexey Kardashevskiy } 108498a8b524SAlexey Kardashevskiy 108598a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 108698a8b524SAlexey Kardashevskiy .name = "timebase", 108798a8b524SAlexey Kardashevskiy .version_id = 1, 108898a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 108998a8b524SAlexey Kardashevskiy .minimum_version_id_old = 1, 109098a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 109198a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 109298a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 109398a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 109498a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 109598a8b524SAlexey Kardashevskiy }, 109698a8b524SAlexey Kardashevskiy }; 109798a8b524SAlexey Kardashevskiy 10989fddaa0cSbellard /* Set up (once) timebase frequency (in Hz) */ 1099e2684c0bSAndreas Färber clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 11009fddaa0cSbellard { 1101db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 1102c227f099SAnthony Liguori ppc_tb_t *tb_env; 11039fddaa0cSbellard 11047267c094SAnthony Liguori tb_env = g_malloc0(sizeof(ppc_tb_t)); 11059fddaa0cSbellard env->tb_env = tb_env; 1106ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1107d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1108e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1109e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1110e81a982aSAlexander Graf } 11119fddaa0cSbellard /* Create new timer */ 1112bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); 11134b236b62SBenjamin Herrenschmidt if (env->has_hv_mode) { 1114bc72ad67SAlex Bligh tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, 111550c680f0SAndreas Färber cpu); 1116b172c56aSj_mayer } else { 1117b172c56aSj_mayer tb_env->hdecr_timer = NULL; 1118b172c56aSj_mayer } 11198ecc7913Sj_mayer cpu_ppc_set_tb_clk(env, freq); 11209fddaa0cSbellard 11218ecc7913Sj_mayer return &cpu_ppc_set_tb_clk; 11229fddaa0cSbellard } 11239fddaa0cSbellard 112476a66253Sj_mayer /* Specific helpers for POWER & PowerPC 601 RTC */ 1125e2684c0bSAndreas Färber void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value) 11268a84de23Sj_mayer { 11278a84de23Sj_mayer _cpu_ppc_store_tbu(env, value); 11288a84de23Sj_mayer } 112976a66253Sj_mayer 1130e2684c0bSAndreas Färber uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env) 11318a84de23Sj_mayer { 11328a84de23Sj_mayer return _cpu_ppc_load_tbu(env); 11338a84de23Sj_mayer } 113476a66253Sj_mayer 1135e2684c0bSAndreas Färber void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value) 113676a66253Sj_mayer { 113776a66253Sj_mayer cpu_ppc_store_tbl(env, value & 0x3FFFFF80); 113876a66253Sj_mayer } 113976a66253Sj_mayer 1140e2684c0bSAndreas Färber uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env) 114176a66253Sj_mayer { 114276a66253Sj_mayer return cpu_ppc_load_tbl(env) & 0x3FFFFF80; 114376a66253Sj_mayer } 114476a66253Sj_mayer 1145636aaad7Sj_mayer /*****************************************************************************/ 1146ddd1055bSFabien Chouteau /* PowerPC 40x timers */ 1147636aaad7Sj_mayer 1148636aaad7Sj_mayer /* PIT, FIT & WDT */ 1149ddd1055bSFabien Chouteau typedef struct ppc40x_timer_t ppc40x_timer_t; 1150ddd1055bSFabien Chouteau struct ppc40x_timer_t { 1151636aaad7Sj_mayer uint64_t pit_reload; /* PIT auto-reload value */ 1152636aaad7Sj_mayer uint64_t fit_next; /* Tick for next FIT interrupt */ 11531246b259SStefan Weil QEMUTimer *fit_timer; 1154636aaad7Sj_mayer uint64_t wdt_next; /* Tick for next WDT interrupt */ 11551246b259SStefan Weil QEMUTimer *wdt_timer; 1156d63cb48dSEdgar E. Iglesias 1157d63cb48dSEdgar E. Iglesias /* 405 have the PIT, 440 have a DECR. */ 1158d63cb48dSEdgar E. Iglesias unsigned int decr_excp; 1159636aaad7Sj_mayer }; 1160636aaad7Sj_mayer 1161636aaad7Sj_mayer /* Fixed interval timer */ 1162636aaad7Sj_mayer static void cpu_4xx_fit_cb (void *opaque) 116376a66253Sj_mayer { 11647058581aSAndreas Färber PowerPCCPU *cpu; 1165e2684c0bSAndreas Färber CPUPPCState *env; 1166c227f099SAnthony Liguori ppc_tb_t *tb_env; 1167ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1168636aaad7Sj_mayer uint64_t now, next; 1169636aaad7Sj_mayer 1170636aaad7Sj_mayer env = opaque; 1171db70b311SRichard Henderson cpu = env_archcpu(env); 1172636aaad7Sj_mayer tb_env = env->tb_env; 1173ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1174bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1175636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 1176636aaad7Sj_mayer case 0: 1177636aaad7Sj_mayer next = 1 << 9; 1178636aaad7Sj_mayer break; 1179636aaad7Sj_mayer case 1: 1180636aaad7Sj_mayer next = 1 << 13; 1181636aaad7Sj_mayer break; 1182636aaad7Sj_mayer case 2: 1183636aaad7Sj_mayer next = 1 << 17; 1184636aaad7Sj_mayer break; 1185636aaad7Sj_mayer case 3: 1186636aaad7Sj_mayer next = 1 << 21; 1187636aaad7Sj_mayer break; 1188636aaad7Sj_mayer default: 1189636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1190636aaad7Sj_mayer return; 1191636aaad7Sj_mayer } 119273bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); 1193636aaad7Sj_mayer if (next == now) 1194636aaad7Sj_mayer next++; 1195bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 1196636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 26; 11977058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 11987058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 11997058581aSAndreas Färber } 120090e189ecSBlue Swirl LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, 1201e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 1202636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1203636aaad7Sj_mayer } 1204636aaad7Sj_mayer 1205636aaad7Sj_mayer /* Programmable interval timer */ 1206e2684c0bSAndreas Färber static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 1207636aaad7Sj_mayer { 1208ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1209636aaad7Sj_mayer uint64_t now, next; 1210636aaad7Sj_mayer 1211ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1212ddd1055bSFabien Chouteau if (ppc40x_timer->pit_reload <= 1 || 12134b6d0a4cSj_mayer !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 12144b6d0a4cSj_mayer (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 12154b6d0a4cSj_mayer /* Stop PIT */ 1216d12d51d5Saliguori LOG_TB("%s: stop PIT\n", __func__); 1217bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 12184b6d0a4cSj_mayer } else { 1219d12d51d5Saliguori LOG_TB("%s: start PIT %016" PRIx64 "\n", 1220ddd1055bSFabien Chouteau __func__, ppc40x_timer->pit_reload); 1221bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1222ddd1055bSFabien Chouteau next = now + muldiv64(ppc40x_timer->pit_reload, 122373bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, tb_env->decr_freq); 12244b6d0a4cSj_mayer if (is_excp) 12254b6d0a4cSj_mayer next += tb_env->decr_next - now; 1226636aaad7Sj_mayer if (next == now) 1227636aaad7Sj_mayer next++; 1228bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 1229636aaad7Sj_mayer tb_env->decr_next = next; 1230636aaad7Sj_mayer } 12314b6d0a4cSj_mayer } 12324b6d0a4cSj_mayer 12334b6d0a4cSj_mayer static void cpu_4xx_pit_cb (void *opaque) 12344b6d0a4cSj_mayer { 12357058581aSAndreas Färber PowerPCCPU *cpu; 1236e2684c0bSAndreas Färber CPUPPCState *env; 1237c227f099SAnthony Liguori ppc_tb_t *tb_env; 1238ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 12394b6d0a4cSj_mayer 12404b6d0a4cSj_mayer env = opaque; 1241db70b311SRichard Henderson cpu = env_archcpu(env); 12424b6d0a4cSj_mayer tb_env = env->tb_env; 1243ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1244636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 27; 12457058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 12467058581aSAndreas Färber ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 12477058581aSAndreas Färber } 12484b6d0a4cSj_mayer start_stop_pit(env, tb_env, 1); 124990e189ecSBlue Swirl LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " 1250e96efcfcSj_mayer "%016" PRIx64 "\n", __func__, 1251e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 1252e96efcfcSj_mayer (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 1253636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 1254ddd1055bSFabien Chouteau ppc40x_timer->pit_reload); 1255636aaad7Sj_mayer } 1256636aaad7Sj_mayer 1257636aaad7Sj_mayer /* Watchdog timer */ 1258636aaad7Sj_mayer static void cpu_4xx_wdt_cb (void *opaque) 1259636aaad7Sj_mayer { 12607058581aSAndreas Färber PowerPCCPU *cpu; 1261e2684c0bSAndreas Färber CPUPPCState *env; 1262c227f099SAnthony Liguori ppc_tb_t *tb_env; 1263ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1264636aaad7Sj_mayer uint64_t now, next; 1265636aaad7Sj_mayer 1266636aaad7Sj_mayer env = opaque; 1267db70b311SRichard Henderson cpu = env_archcpu(env); 1268636aaad7Sj_mayer tb_env = env->tb_env; 1269ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 1270bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1271636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 1272636aaad7Sj_mayer case 0: 1273636aaad7Sj_mayer next = 1 << 17; 1274636aaad7Sj_mayer break; 1275636aaad7Sj_mayer case 1: 1276636aaad7Sj_mayer next = 1 << 21; 1277636aaad7Sj_mayer break; 1278636aaad7Sj_mayer case 2: 1279636aaad7Sj_mayer next = 1 << 25; 1280636aaad7Sj_mayer break; 1281636aaad7Sj_mayer case 3: 1282636aaad7Sj_mayer next = 1 << 29; 1283636aaad7Sj_mayer break; 1284636aaad7Sj_mayer default: 1285636aaad7Sj_mayer /* Cannot occur, but makes gcc happy */ 1286636aaad7Sj_mayer return; 1287636aaad7Sj_mayer } 128873bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 1289636aaad7Sj_mayer if (next == now) 1290636aaad7Sj_mayer next++; 129190e189ecSBlue Swirl LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, 1292636aaad7Sj_mayer env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 1293636aaad7Sj_mayer switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 1294636aaad7Sj_mayer case 0x0: 1295636aaad7Sj_mayer case 0x1: 1296bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1297ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1298a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 1299636aaad7Sj_mayer break; 1300636aaad7Sj_mayer case 0x2: 1301bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 1302ddd1055bSFabien Chouteau ppc40x_timer->wdt_next = next; 1303636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= 1 << 30; 13047058581aSAndreas Färber if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 13057058581aSAndreas Färber ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 13067058581aSAndreas Färber } 1307636aaad7Sj_mayer break; 1308636aaad7Sj_mayer case 0x3: 1309636aaad7Sj_mayer env->spr[SPR_40x_TSR] &= ~0x30000000; 1310636aaad7Sj_mayer env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 1311636aaad7Sj_mayer switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 1312636aaad7Sj_mayer case 0x0: 1313636aaad7Sj_mayer /* No reset */ 1314636aaad7Sj_mayer break; 1315636aaad7Sj_mayer case 0x1: /* Core reset */ 1316f3273ba6SAndreas Färber ppc40x_core_reset(cpu); 13178ecc7913Sj_mayer break; 1318636aaad7Sj_mayer case 0x2: /* Chip reset */ 1319f3273ba6SAndreas Färber ppc40x_chip_reset(cpu); 13208ecc7913Sj_mayer break; 1321636aaad7Sj_mayer case 0x3: /* System reset */ 1322f3273ba6SAndreas Färber ppc40x_system_reset(cpu); 13238ecc7913Sj_mayer break; 1324636aaad7Sj_mayer } 1325636aaad7Sj_mayer } 132676a66253Sj_mayer } 132776a66253Sj_mayer 1328e2684c0bSAndreas Färber void store_40x_pit (CPUPPCState *env, target_ulong val) 132976a66253Sj_mayer { 1330c227f099SAnthony Liguori ppc_tb_t *tb_env; 1331ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1332636aaad7Sj_mayer 1333636aaad7Sj_mayer tb_env = env->tb_env; 1334ddd1055bSFabien Chouteau ppc40x_timer = tb_env->opaque; 133590e189ecSBlue Swirl LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val); 1336ddd1055bSFabien Chouteau ppc40x_timer->pit_reload = val; 13374b6d0a4cSj_mayer start_stop_pit(env, tb_env, 0); 133876a66253Sj_mayer } 133976a66253Sj_mayer 1340e2684c0bSAndreas Färber target_ulong load_40x_pit (CPUPPCState *env) 134176a66253Sj_mayer { 1342636aaad7Sj_mayer return cpu_ppc_load_decr(env); 134376a66253Sj_mayer } 134476a66253Sj_mayer 1345ddd1055bSFabien Chouteau static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 13464b6d0a4cSj_mayer { 1347e2684c0bSAndreas Färber CPUPPCState *env = opaque; 1348c227f099SAnthony Liguori ppc_tb_t *tb_env = env->tb_env; 13494b6d0a4cSj_mayer 1350d12d51d5Saliguori LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__, 1351aae9366aSj_mayer freq); 13524b6d0a4cSj_mayer tb_env->tb_freq = freq; 1353dbdd2506Sj_mayer tb_env->decr_freq = freq; 13544b6d0a4cSj_mayer /* XXX: we should also update all timers */ 13554b6d0a4cSj_mayer } 13564b6d0a4cSj_mayer 1357e2684c0bSAndreas Färber clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 1358d63cb48dSEdgar E. Iglesias unsigned int decr_excp) 1359636aaad7Sj_mayer { 1360c227f099SAnthony Liguori ppc_tb_t *tb_env; 1361ddd1055bSFabien Chouteau ppc40x_timer_t *ppc40x_timer; 1362636aaad7Sj_mayer 13637267c094SAnthony Liguori tb_env = g_malloc0(sizeof(ppc_tb_t)); 13648ecc7913Sj_mayer env->tb_env = tb_env; 1365ddd1055bSFabien Chouteau tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1366ddd1055bSFabien Chouteau ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t)); 13678ecc7913Sj_mayer tb_env->tb_freq = freq; 1368dbdd2506Sj_mayer tb_env->decr_freq = freq; 1369ddd1055bSFabien Chouteau tb_env->opaque = ppc40x_timer; 1370d12d51d5Saliguori LOG_TB("%s freq %" PRIu32 "\n", __func__, freq); 1371ddd1055bSFabien Chouteau if (ppc40x_timer != NULL) { 1372636aaad7Sj_mayer /* We use decr timer for PIT */ 1373bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env); 1374ddd1055bSFabien Chouteau ppc40x_timer->fit_timer = 1375bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env); 1376ddd1055bSFabien Chouteau ppc40x_timer->wdt_timer = 1377bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env); 1378ddd1055bSFabien Chouteau ppc40x_timer->decr_excp = decr_excp; 1379636aaad7Sj_mayer } 13808ecc7913Sj_mayer 1381ddd1055bSFabien Chouteau return &ppc_40x_set_tb_clk; 138276a66253Sj_mayer } 138376a66253Sj_mayer 13842e719ba3Sj_mayer /*****************************************************************************/ 13852e719ba3Sj_mayer /* Embedded PowerPC Device Control Registers */ 1386c227f099SAnthony Liguori typedef struct ppc_dcrn_t ppc_dcrn_t; 1387c227f099SAnthony Liguori struct ppc_dcrn_t { 13882e719ba3Sj_mayer dcr_read_cb dcr_read; 13892e719ba3Sj_mayer dcr_write_cb dcr_write; 13902e719ba3Sj_mayer void *opaque; 13912e719ba3Sj_mayer }; 13922e719ba3Sj_mayer 1393a750fc0bSj_mayer /* XXX: on 460, DCR addresses are 32 bits wide, 1394a750fc0bSj_mayer * using DCRIPR to get the 22 upper bits of the DCR address 1395a750fc0bSj_mayer */ 13962e719ba3Sj_mayer #define DCRN_NB 1024 1397c227f099SAnthony Liguori struct ppc_dcr_t { 1398c227f099SAnthony Liguori ppc_dcrn_t dcrn[DCRN_NB]; 13992e719ba3Sj_mayer int (*read_error)(int dcrn); 14002e719ba3Sj_mayer int (*write_error)(int dcrn); 14012e719ba3Sj_mayer }; 14022e719ba3Sj_mayer 140373b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 14042e719ba3Sj_mayer { 1405c227f099SAnthony Liguori ppc_dcrn_t *dcr; 14062e719ba3Sj_mayer 14072e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 14082e719ba3Sj_mayer goto error; 14092e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 14102e719ba3Sj_mayer if (dcr->dcr_read == NULL) 14112e719ba3Sj_mayer goto error; 14122e719ba3Sj_mayer *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 14132e719ba3Sj_mayer 14142e719ba3Sj_mayer return 0; 14152e719ba3Sj_mayer 14162e719ba3Sj_mayer error: 14172e719ba3Sj_mayer if (dcr_env->read_error != NULL) 14182e719ba3Sj_mayer return (*dcr_env->read_error)(dcrn); 14192e719ba3Sj_mayer 14202e719ba3Sj_mayer return -1; 14212e719ba3Sj_mayer } 14222e719ba3Sj_mayer 142373b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 14242e719ba3Sj_mayer { 1425c227f099SAnthony Liguori ppc_dcrn_t *dcr; 14262e719ba3Sj_mayer 14272e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 14282e719ba3Sj_mayer goto error; 14292e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 14302e719ba3Sj_mayer if (dcr->dcr_write == NULL) 14312e719ba3Sj_mayer goto error; 14322e719ba3Sj_mayer (*dcr->dcr_write)(dcr->opaque, dcrn, val); 14332e719ba3Sj_mayer 14342e719ba3Sj_mayer return 0; 14352e719ba3Sj_mayer 14362e719ba3Sj_mayer error: 14372e719ba3Sj_mayer if (dcr_env->write_error != NULL) 14382e719ba3Sj_mayer return (*dcr_env->write_error)(dcrn); 14392e719ba3Sj_mayer 14402e719ba3Sj_mayer return -1; 14412e719ba3Sj_mayer } 14422e719ba3Sj_mayer 1443e2684c0bSAndreas Färber int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 14442e719ba3Sj_mayer dcr_read_cb dcr_read, dcr_write_cb dcr_write) 14452e719ba3Sj_mayer { 1446c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 1447c227f099SAnthony Liguori ppc_dcrn_t *dcr; 14482e719ba3Sj_mayer 14492e719ba3Sj_mayer dcr_env = env->dcr_env; 14502e719ba3Sj_mayer if (dcr_env == NULL) 14512e719ba3Sj_mayer return -1; 14522e719ba3Sj_mayer if (dcrn < 0 || dcrn >= DCRN_NB) 14532e719ba3Sj_mayer return -1; 14542e719ba3Sj_mayer dcr = &dcr_env->dcrn[dcrn]; 14552e719ba3Sj_mayer if (dcr->opaque != NULL || 14562e719ba3Sj_mayer dcr->dcr_read != NULL || 14572e719ba3Sj_mayer dcr->dcr_write != NULL) 14582e719ba3Sj_mayer return -1; 14592e719ba3Sj_mayer dcr->opaque = opaque; 14602e719ba3Sj_mayer dcr->dcr_read = dcr_read; 14612e719ba3Sj_mayer dcr->dcr_write = dcr_write; 14622e719ba3Sj_mayer 14632e719ba3Sj_mayer return 0; 14642e719ba3Sj_mayer } 14652e719ba3Sj_mayer 1466e2684c0bSAndreas Färber int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 14672e719ba3Sj_mayer int (*write_error)(int dcrn)) 14682e719ba3Sj_mayer { 1469c227f099SAnthony Liguori ppc_dcr_t *dcr_env; 14702e719ba3Sj_mayer 14717267c094SAnthony Liguori dcr_env = g_malloc0(sizeof(ppc_dcr_t)); 14722e719ba3Sj_mayer dcr_env->read_error = read_error; 14732e719ba3Sj_mayer dcr_env->write_error = write_error; 14742e719ba3Sj_mayer env->dcr_env = dcr_env; 14752e719ba3Sj_mayer 14762e719ba3Sj_mayer return 0; 14772e719ba3Sj_mayer } 14782e719ba3Sj_mayer 147964201201Sbellard /*****************************************************************************/ 148064201201Sbellard /* Debug port */ 1481fd0bbb12Sbellard void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) 148264201201Sbellard { 148364201201Sbellard addr &= 0xF; 148464201201Sbellard switch (addr) { 148564201201Sbellard case 0: 148664201201Sbellard printf("%c", val); 148764201201Sbellard break; 148864201201Sbellard case 1: 148964201201Sbellard printf("\n"); 149064201201Sbellard fflush(stdout); 149164201201Sbellard break; 149264201201Sbellard case 2: 1493aae9366aSj_mayer printf("Set loglevel to %04" PRIx32 "\n", val); 149424537a01SPeter Maydell qemu_set_log(val | 0x100); 149564201201Sbellard break; 149664201201Sbellard } 149764201201Sbellard } 1498051e2973SCédric Le Goater 14994a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 15004a89e204SCédric Le Goater { 15014a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 15024a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 15034a89e204SCédric Le Goater } 15044a89e204SCédric Le Goater 1505051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1506051e2973SCédric Le Goater { 1507051e2973SCédric Le Goater CPUState *cs; 1508051e2973SCédric Le Goater 1509051e2973SCédric Le Goater CPU_FOREACH(cs) { 1510051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1511051e2973SCédric Le Goater 15124a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1513051e2973SCédric Le Goater return cpu; 1514051e2973SCédric Le Goater } 1515051e2973SCédric Le Goater } 1516051e2973SCédric Le Goater 1517051e2973SCédric Le Goater return NULL; 1518051e2973SCédric Le Goater } 151940177438SGreg Kurz 152040177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 152140177438SGreg Kurz { 152240177438SGreg Kurz CPUPPCState *env = &cpu->env; 152340177438SGreg Kurz 152440177438SGreg Kurz env->irq_input_state = 0; 152540177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 152640177438SGreg Kurz } 1527