153018216SPaolo Bonzini /* 253018216SPaolo Bonzini * QEMU generic PowerPC hardware System Emulator 353018216SPaolo Bonzini * 453018216SPaolo Bonzini * Copyright (c) 2003-2007 Jocelyn Mayer 553018216SPaolo Bonzini * 653018216SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 753018216SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 853018216SPaolo Bonzini * in the Software without restriction, including without limitation the rights 953018216SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1053018216SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1153018216SPaolo Bonzini * furnished to do so, subject to the following conditions: 1253018216SPaolo Bonzini * 1353018216SPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1453018216SPaolo Bonzini * all copies or substantial portions of the Software. 1553018216SPaolo Bonzini * 1653018216SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1753018216SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1853018216SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1953018216SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2053018216SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2153018216SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2253018216SPaolo Bonzini * THE SOFTWARE. 2353018216SPaolo Bonzini */ 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" 3053018216SPaolo Bonzini #include "qemu/timer.h" 310ce470cdSAlexey Kardashevskiy #include "sysemu/cpus.h" 3253018216SPaolo Bonzini #include "qemu/log.h" 33db725815SMarkus Armbruster #include "qemu/main-loop.h" 3498a8b524SAlexey Kardashevskiy #include "qemu/error-report.h" 3553018216SPaolo Bonzini #include "sysemu/kvm.h" 3654d31236SMarkus Armbruster #include "sysemu/runstate.h" 3753018216SPaolo Bonzini #include "kvm_ppc.h" 38d6454270SMarkus Armbruster #include "migration/vmstate.h" 3998a8b524SAlexey Kardashevskiy #include "trace.h" 4053018216SPaolo Bonzini 4153018216SPaolo Bonzini //#define PPC_DEBUG_IRQ 4253018216SPaolo Bonzini //#define PPC_DEBUG_TB 4353018216SPaolo Bonzini 4453018216SPaolo Bonzini #ifdef PPC_DEBUG_IRQ 4553018216SPaolo Bonzini # define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) 4653018216SPaolo Bonzini #else 4753018216SPaolo Bonzini # define LOG_IRQ(...) do { } while (0) 4853018216SPaolo Bonzini #endif 4953018216SPaolo Bonzini 5053018216SPaolo Bonzini 5153018216SPaolo Bonzini #ifdef PPC_DEBUG_TB 5253018216SPaolo Bonzini # define LOG_TB(...) qemu_log(__VA_ARGS__) 5353018216SPaolo Bonzini #else 5453018216SPaolo Bonzini # define LOG_TB(...) do { } while (0) 5553018216SPaolo Bonzini #endif 5653018216SPaolo Bonzini 5753018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env); 5853018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env); 5953018216SPaolo Bonzini 6053018216SPaolo Bonzini void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) 6153018216SPaolo Bonzini { 62d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 6353018216SPaolo Bonzini 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; 7453018216SPaolo Bonzini 7553018216SPaolo Bonzini if (level) { 7653018216SPaolo Bonzini env->pending_interrupts |= 1 << n_IRQ; 77c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 7853018216SPaolo Bonzini } else { 7953018216SPaolo Bonzini 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 } 8353018216SPaolo Bonzini } 8453018216SPaolo Bonzini 8553018216SPaolo Bonzini if (old_pending != env->pending_interrupts) { 8653018216SPaolo Bonzini kvmppc_set_interrupt(cpu, n_IRQ, level); 8753018216SPaolo Bonzini } 8853018216SPaolo Bonzini 898d04fb55SJan Kiszka 9053018216SPaolo Bonzini LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32 9153018216SPaolo Bonzini "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 } 9753018216SPaolo Bonzini } 9853018216SPaolo Bonzini 9953018216SPaolo Bonzini /* PowerPC 6xx / 7xx internal IRQ controller */ 10053018216SPaolo Bonzini static void ppc6xx_set_irq(void *opaque, int pin, int level) 10153018216SPaolo Bonzini { 10253018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 10353018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 10453018216SPaolo Bonzini int cur_level; 10553018216SPaolo Bonzini 10653018216SPaolo Bonzini LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 10753018216SPaolo Bonzini env, pin, level); 10853018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 10953018216SPaolo Bonzini /* Don't generate spurious events */ 11053018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 111259186a7SAndreas Färber CPUState *cs = CPU(cpu); 112259186a7SAndreas Färber 11353018216SPaolo Bonzini switch (pin) { 11453018216SPaolo Bonzini case PPC6xx_INPUT_TBEN: 11553018216SPaolo Bonzini /* Level sensitive - active high */ 11653018216SPaolo Bonzini LOG_IRQ("%s: %s the time base\n", 11753018216SPaolo Bonzini __func__, level ? "start" : "stop"); 11853018216SPaolo Bonzini if (level) { 11953018216SPaolo Bonzini cpu_ppc_tb_start(env); 12053018216SPaolo Bonzini } else { 12153018216SPaolo Bonzini cpu_ppc_tb_stop(env); 12253018216SPaolo Bonzini } 123b2bd5b20SChen Qun break; 12453018216SPaolo Bonzini case PPC6xx_INPUT_INT: 12553018216SPaolo Bonzini /* Level sensitive - active high */ 12653018216SPaolo Bonzini LOG_IRQ("%s: set the external IRQ state to %d\n", 12753018216SPaolo Bonzini __func__, level); 12853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 12953018216SPaolo Bonzini break; 13053018216SPaolo Bonzini case PPC6xx_INPUT_SMI: 13153018216SPaolo Bonzini /* Level sensitive - active high */ 13253018216SPaolo Bonzini LOG_IRQ("%s: set the SMI IRQ state to %d\n", 13353018216SPaolo Bonzini __func__, level); 13453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); 13553018216SPaolo Bonzini break; 13653018216SPaolo Bonzini case PPC6xx_INPUT_MCP: 13753018216SPaolo Bonzini /* Negative edge sensitive */ 13853018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 13953018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 14053018216SPaolo Bonzini */ 14153018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 14253018216SPaolo Bonzini LOG_IRQ("%s: raise machine check state\n", 14353018216SPaolo Bonzini __func__); 14453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 14553018216SPaolo Bonzini } 14653018216SPaolo Bonzini break; 14753018216SPaolo Bonzini case PPC6xx_INPUT_CKSTP_IN: 14853018216SPaolo Bonzini /* Level sensitive - active low */ 14953018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 15053018216SPaolo Bonzini /* XXX: Note that the only way to restart the CPU is to reset it */ 15153018216SPaolo Bonzini if (level) { 15253018216SPaolo Bonzini LOG_IRQ("%s: stop the CPU\n", __func__); 153259186a7SAndreas Färber cs->halted = 1; 15453018216SPaolo Bonzini } 15553018216SPaolo Bonzini break; 15653018216SPaolo Bonzini case PPC6xx_INPUT_HRESET: 15753018216SPaolo Bonzini /* Level sensitive - active low */ 15853018216SPaolo Bonzini if (level) { 15953018216SPaolo Bonzini LOG_IRQ("%s: reset the CPU\n", __func__); 160c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 16153018216SPaolo Bonzini } 16253018216SPaolo Bonzini break; 16353018216SPaolo Bonzini case PPC6xx_INPUT_SRESET: 16453018216SPaolo Bonzini LOG_IRQ("%s: set the RESET IRQ state to %d\n", 16553018216SPaolo Bonzini __func__, level); 16653018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 16753018216SPaolo Bonzini break; 16853018216SPaolo Bonzini default: 16953018216SPaolo Bonzini /* Unknown pin - do nothing */ 17053018216SPaolo Bonzini LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 17153018216SPaolo Bonzini return; 17253018216SPaolo Bonzini } 17353018216SPaolo Bonzini if (level) 17453018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 17553018216SPaolo Bonzini else 17653018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 17753018216SPaolo Bonzini } 17853018216SPaolo Bonzini } 17953018216SPaolo Bonzini 180aa5a9e24SPaolo Bonzini void ppc6xx_irq_init(PowerPCCPU *cpu) 18153018216SPaolo Bonzini { 182aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 18353018216SPaolo Bonzini 18453018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, 18553018216SPaolo Bonzini PPC6xx_INPUT_NB); 18653018216SPaolo Bonzini } 18753018216SPaolo Bonzini 18853018216SPaolo Bonzini #if defined(TARGET_PPC64) 18953018216SPaolo Bonzini /* PowerPC 970 internal IRQ controller */ 19053018216SPaolo Bonzini static void ppc970_set_irq(void *opaque, int pin, int level) 19153018216SPaolo Bonzini { 19253018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 19353018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 19453018216SPaolo Bonzini int cur_level; 19553018216SPaolo Bonzini 19653018216SPaolo Bonzini LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 19753018216SPaolo Bonzini env, pin, level); 19853018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 19953018216SPaolo Bonzini /* Don't generate spurious events */ 20053018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 201259186a7SAndreas Färber CPUState *cs = CPU(cpu); 202259186a7SAndreas Färber 20353018216SPaolo Bonzini switch (pin) { 20453018216SPaolo Bonzini case PPC970_INPUT_INT: 20553018216SPaolo Bonzini /* Level sensitive - active high */ 20653018216SPaolo Bonzini LOG_IRQ("%s: set the external IRQ state to %d\n", 20753018216SPaolo Bonzini __func__, level); 20853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 20953018216SPaolo Bonzini break; 21053018216SPaolo Bonzini case PPC970_INPUT_THINT: 21153018216SPaolo Bonzini /* Level sensitive - active high */ 21253018216SPaolo Bonzini LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, 21353018216SPaolo Bonzini level); 21453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); 21553018216SPaolo Bonzini break; 21653018216SPaolo Bonzini case PPC970_INPUT_MCP: 21753018216SPaolo Bonzini /* Negative edge sensitive */ 21853018216SPaolo Bonzini /* XXX: TODO: actual reaction may depends on HID0 status 21953018216SPaolo Bonzini * 603/604/740/750: check HID0[EMCP] 22053018216SPaolo Bonzini */ 22153018216SPaolo Bonzini if (cur_level == 1 && level == 0) { 22253018216SPaolo Bonzini LOG_IRQ("%s: raise machine check state\n", 22353018216SPaolo Bonzini __func__); 22453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); 22553018216SPaolo Bonzini } 22653018216SPaolo Bonzini break; 22753018216SPaolo Bonzini case PPC970_INPUT_CKSTP: 22853018216SPaolo Bonzini /* Level sensitive - active low */ 22953018216SPaolo Bonzini /* XXX: TODO: relay the signal to CKSTP_OUT pin */ 23053018216SPaolo Bonzini if (level) { 23153018216SPaolo Bonzini LOG_IRQ("%s: stop the CPU\n", __func__); 232259186a7SAndreas Färber cs->halted = 1; 23353018216SPaolo Bonzini } else { 23453018216SPaolo Bonzini LOG_IRQ("%s: restart the CPU\n", __func__); 235259186a7SAndreas Färber cs->halted = 0; 236259186a7SAndreas Färber qemu_cpu_kick(cs); 23753018216SPaolo Bonzini } 23853018216SPaolo Bonzini break; 23953018216SPaolo Bonzini case PPC970_INPUT_HRESET: 24053018216SPaolo Bonzini /* Level sensitive - active low */ 24153018216SPaolo Bonzini if (level) { 242c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_RESET); 24353018216SPaolo Bonzini } 24453018216SPaolo Bonzini break; 24553018216SPaolo Bonzini case PPC970_INPUT_SRESET: 24653018216SPaolo Bonzini LOG_IRQ("%s: set the RESET IRQ state to %d\n", 24753018216SPaolo Bonzini __func__, level); 24853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); 24953018216SPaolo Bonzini break; 25053018216SPaolo Bonzini case PPC970_INPUT_TBEN: 25153018216SPaolo Bonzini LOG_IRQ("%s: set the TBEN state to %d\n", __func__, 25253018216SPaolo Bonzini level); 25353018216SPaolo Bonzini /* XXX: TODO */ 25453018216SPaolo Bonzini break; 25553018216SPaolo Bonzini default: 25653018216SPaolo Bonzini /* Unknown pin - do nothing */ 25753018216SPaolo Bonzini LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 25853018216SPaolo Bonzini return; 25953018216SPaolo Bonzini } 26053018216SPaolo Bonzini if (level) 26153018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 26253018216SPaolo Bonzini else 26353018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 26453018216SPaolo Bonzini } 26553018216SPaolo Bonzini } 26653018216SPaolo Bonzini 267aa5a9e24SPaolo Bonzini void ppc970_irq_init(PowerPCCPU *cpu) 26853018216SPaolo Bonzini { 269aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 27053018216SPaolo Bonzini 27153018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, 27253018216SPaolo Bonzini PPC970_INPUT_NB); 27353018216SPaolo Bonzini } 27453018216SPaolo Bonzini 27553018216SPaolo Bonzini /* POWER7 internal IRQ controller */ 27653018216SPaolo Bonzini static void power7_set_irq(void *opaque, int pin, int level) 27753018216SPaolo Bonzini { 27853018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 27953018216SPaolo Bonzini 28053018216SPaolo Bonzini LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 281c1ad0b89SGreg Kurz &cpu->env, pin, level); 28253018216SPaolo Bonzini 28353018216SPaolo Bonzini switch (pin) { 28453018216SPaolo Bonzini case POWER7_INPUT_INT: 28553018216SPaolo Bonzini /* Level sensitive - active high */ 28653018216SPaolo Bonzini LOG_IRQ("%s: set the external IRQ state to %d\n", 28753018216SPaolo Bonzini __func__, level); 28853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 28953018216SPaolo Bonzini break; 29053018216SPaolo Bonzini default: 29153018216SPaolo Bonzini /* Unknown pin - do nothing */ 29253018216SPaolo Bonzini LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 29353018216SPaolo Bonzini return; 29453018216SPaolo Bonzini } 29553018216SPaolo Bonzini } 29653018216SPaolo Bonzini 297aa5a9e24SPaolo Bonzini void ppcPOWER7_irq_init(PowerPCCPU *cpu) 29853018216SPaolo Bonzini { 299aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 30053018216SPaolo Bonzini 30153018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, 30253018216SPaolo Bonzini POWER7_INPUT_NB); 30353018216SPaolo Bonzini } 30467afe775SBenjamin Herrenschmidt 30567afe775SBenjamin Herrenschmidt /* POWER9 internal IRQ controller */ 30667afe775SBenjamin Herrenschmidt static void power9_set_irq(void *opaque, int pin, int level) 30767afe775SBenjamin Herrenschmidt { 30867afe775SBenjamin Herrenschmidt PowerPCCPU *cpu = opaque; 30967afe775SBenjamin Herrenschmidt 31067afe775SBenjamin Herrenschmidt LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 311c1ad0b89SGreg Kurz &cpu->env, pin, level); 31267afe775SBenjamin Herrenschmidt 31367afe775SBenjamin Herrenschmidt switch (pin) { 31467afe775SBenjamin Herrenschmidt case POWER9_INPUT_INT: 31567afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 31667afe775SBenjamin Herrenschmidt LOG_IRQ("%s: set the external IRQ state to %d\n", 31767afe775SBenjamin Herrenschmidt __func__, level); 31867afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 31967afe775SBenjamin Herrenschmidt break; 32067afe775SBenjamin Herrenschmidt case POWER9_INPUT_HINT: 32167afe775SBenjamin Herrenschmidt /* Level sensitive - active high */ 32267afe775SBenjamin Herrenschmidt LOG_IRQ("%s: set the external IRQ state to %d\n", 32367afe775SBenjamin Herrenschmidt __func__, level); 32467afe775SBenjamin Herrenschmidt ppc_set_irq(cpu, PPC_INTERRUPT_HVIRT, level); 32567afe775SBenjamin Herrenschmidt break; 32667afe775SBenjamin Herrenschmidt default: 32767afe775SBenjamin Herrenschmidt /* Unknown pin - do nothing */ 32867afe775SBenjamin Herrenschmidt LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 32967afe775SBenjamin Herrenschmidt return; 33067afe775SBenjamin Herrenschmidt } 33167afe775SBenjamin Herrenschmidt } 33267afe775SBenjamin Herrenschmidt 33367afe775SBenjamin Herrenschmidt void ppcPOWER9_irq_init(PowerPCCPU *cpu) 33467afe775SBenjamin Herrenschmidt { 33567afe775SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 33667afe775SBenjamin Herrenschmidt 33767afe775SBenjamin Herrenschmidt env->irq_inputs = (void **)qemu_allocate_irqs(&power9_set_irq, cpu, 33867afe775SBenjamin Herrenschmidt POWER9_INPUT_NB); 33967afe775SBenjamin Herrenschmidt } 34053018216SPaolo Bonzini #endif /* defined(TARGET_PPC64) */ 34153018216SPaolo Bonzini 34252144b69SThomas Huth void ppc40x_core_reset(PowerPCCPU *cpu) 34352144b69SThomas Huth { 34452144b69SThomas Huth CPUPPCState *env = &cpu->env; 34552144b69SThomas Huth target_ulong dbsr; 34652144b69SThomas Huth 34752144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC core\n"); 34852144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 34952144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 35052144b69SThomas Huth dbsr &= ~0x00000300; 35152144b69SThomas Huth dbsr |= 0x00000100; 35252144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 35352144b69SThomas Huth } 35452144b69SThomas Huth 35552144b69SThomas Huth void ppc40x_chip_reset(PowerPCCPU *cpu) 35652144b69SThomas Huth { 35752144b69SThomas Huth CPUPPCState *env = &cpu->env; 35852144b69SThomas Huth target_ulong dbsr; 35952144b69SThomas Huth 36052144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC chip\n"); 36152144b69SThomas Huth cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); 36252144b69SThomas Huth /* XXX: TODO reset all internal peripherals */ 36352144b69SThomas Huth dbsr = env->spr[SPR_40x_DBSR]; 36452144b69SThomas Huth dbsr &= ~0x00000300; 36552144b69SThomas Huth dbsr |= 0x00000200; 36652144b69SThomas Huth env->spr[SPR_40x_DBSR] = dbsr; 36752144b69SThomas Huth } 36852144b69SThomas Huth 36952144b69SThomas Huth void ppc40x_system_reset(PowerPCCPU *cpu) 37052144b69SThomas Huth { 37152144b69SThomas Huth qemu_log_mask(CPU_LOG_RESET, "Reset PowerPC system\n"); 37252144b69SThomas Huth qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 37352144b69SThomas Huth } 37452144b69SThomas Huth 37552144b69SThomas Huth void store_40x_dbcr0(CPUPPCState *env, uint32_t val) 37652144b69SThomas Huth { 377db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 37852144b69SThomas Huth 37952144b69SThomas Huth switch ((val >> 28) & 0x3) { 38052144b69SThomas Huth case 0x0: 38152144b69SThomas Huth /* No action */ 38252144b69SThomas Huth break; 38352144b69SThomas Huth case 0x1: 38452144b69SThomas Huth /* Core reset */ 38552144b69SThomas Huth ppc40x_core_reset(cpu); 38652144b69SThomas Huth break; 38752144b69SThomas Huth case 0x2: 38852144b69SThomas Huth /* Chip reset */ 38952144b69SThomas Huth ppc40x_chip_reset(cpu); 39052144b69SThomas Huth break; 39152144b69SThomas Huth case 0x3: 39252144b69SThomas Huth /* System reset */ 39352144b69SThomas Huth ppc40x_system_reset(cpu); 39452144b69SThomas Huth break; 39552144b69SThomas Huth } 39652144b69SThomas Huth } 39752144b69SThomas Huth 39853018216SPaolo Bonzini /* PowerPC 40x internal IRQ controller */ 39953018216SPaolo Bonzini static void ppc40x_set_irq(void *opaque, int pin, int level) 40053018216SPaolo Bonzini { 40153018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 40253018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 40353018216SPaolo Bonzini int cur_level; 40453018216SPaolo Bonzini 40553018216SPaolo Bonzini LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 40653018216SPaolo Bonzini env, pin, level); 40753018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 40853018216SPaolo Bonzini /* Don't generate spurious events */ 40953018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 410259186a7SAndreas Färber CPUState *cs = CPU(cpu); 411259186a7SAndreas Färber 41253018216SPaolo Bonzini switch (pin) { 41353018216SPaolo Bonzini case PPC40x_INPUT_RESET_SYS: 41453018216SPaolo Bonzini if (level) { 41553018216SPaolo Bonzini LOG_IRQ("%s: reset the PowerPC system\n", 41653018216SPaolo Bonzini __func__); 41753018216SPaolo Bonzini ppc40x_system_reset(cpu); 41853018216SPaolo Bonzini } 41953018216SPaolo Bonzini break; 42053018216SPaolo Bonzini case PPC40x_INPUT_RESET_CHIP: 42153018216SPaolo Bonzini if (level) { 42253018216SPaolo Bonzini LOG_IRQ("%s: reset the PowerPC chip\n", __func__); 42353018216SPaolo Bonzini ppc40x_chip_reset(cpu); 42453018216SPaolo Bonzini } 42553018216SPaolo Bonzini break; 42653018216SPaolo Bonzini case PPC40x_INPUT_RESET_CORE: 42753018216SPaolo Bonzini /* XXX: TODO: update DBSR[MRR] */ 42853018216SPaolo Bonzini if (level) { 42953018216SPaolo Bonzini LOG_IRQ("%s: reset the PowerPC core\n", __func__); 43053018216SPaolo Bonzini ppc40x_core_reset(cpu); 43153018216SPaolo Bonzini } 43253018216SPaolo Bonzini break; 43353018216SPaolo Bonzini case PPC40x_INPUT_CINT: 43453018216SPaolo Bonzini /* Level sensitive - active high */ 43553018216SPaolo Bonzini LOG_IRQ("%s: set the critical IRQ state to %d\n", 43653018216SPaolo Bonzini __func__, level); 43753018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 43853018216SPaolo Bonzini break; 43953018216SPaolo Bonzini case PPC40x_INPUT_INT: 44053018216SPaolo Bonzini /* Level sensitive - active high */ 44153018216SPaolo Bonzini LOG_IRQ("%s: set the external IRQ state to %d\n", 44253018216SPaolo Bonzini __func__, level); 44353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 44453018216SPaolo Bonzini break; 44553018216SPaolo Bonzini case PPC40x_INPUT_HALT: 44653018216SPaolo Bonzini /* Level sensitive - active low */ 44753018216SPaolo Bonzini if (level) { 44853018216SPaolo Bonzini LOG_IRQ("%s: stop the CPU\n", __func__); 449259186a7SAndreas Färber cs->halted = 1; 45053018216SPaolo Bonzini } else { 45153018216SPaolo Bonzini LOG_IRQ("%s: restart the CPU\n", __func__); 452259186a7SAndreas Färber cs->halted = 0; 453259186a7SAndreas Färber qemu_cpu_kick(cs); 45453018216SPaolo Bonzini } 45553018216SPaolo Bonzini break; 45653018216SPaolo Bonzini case PPC40x_INPUT_DEBUG: 45753018216SPaolo Bonzini /* Level sensitive - active high */ 45853018216SPaolo Bonzini LOG_IRQ("%s: set the debug pin state to %d\n", 45953018216SPaolo Bonzini __func__, level); 46053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 46153018216SPaolo Bonzini break; 46253018216SPaolo Bonzini default: 46353018216SPaolo Bonzini /* Unknown pin - do nothing */ 46453018216SPaolo Bonzini LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 46553018216SPaolo Bonzini return; 46653018216SPaolo Bonzini } 46753018216SPaolo Bonzini if (level) 46853018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 46953018216SPaolo Bonzini else 47053018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 47153018216SPaolo Bonzini } 47253018216SPaolo Bonzini } 47353018216SPaolo Bonzini 474aa5a9e24SPaolo Bonzini void ppc40x_irq_init(PowerPCCPU *cpu) 47553018216SPaolo Bonzini { 476aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 47753018216SPaolo Bonzini 47853018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, 47953018216SPaolo Bonzini cpu, PPC40x_INPUT_NB); 48053018216SPaolo Bonzini } 48153018216SPaolo Bonzini 48253018216SPaolo Bonzini /* PowerPC E500 internal IRQ controller */ 48353018216SPaolo Bonzini static void ppce500_set_irq(void *opaque, int pin, int level) 48453018216SPaolo Bonzini { 48553018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 48653018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 48753018216SPaolo Bonzini int cur_level; 48853018216SPaolo Bonzini 48953018216SPaolo Bonzini LOG_IRQ("%s: env %p pin %d level %d\n", __func__, 49053018216SPaolo Bonzini env, pin, level); 49153018216SPaolo Bonzini cur_level = (env->irq_input_state >> pin) & 1; 49253018216SPaolo Bonzini /* Don't generate spurious events */ 49353018216SPaolo Bonzini if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { 49453018216SPaolo Bonzini switch (pin) { 49553018216SPaolo Bonzini case PPCE500_INPUT_MCK: 49653018216SPaolo Bonzini if (level) { 49753018216SPaolo Bonzini LOG_IRQ("%s: reset the PowerPC system\n", 49853018216SPaolo Bonzini __func__); 499cf83f140SEric Blake qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 50053018216SPaolo Bonzini } 50153018216SPaolo Bonzini break; 50253018216SPaolo Bonzini case PPCE500_INPUT_RESET_CORE: 50353018216SPaolo Bonzini if (level) { 50453018216SPaolo Bonzini LOG_IRQ("%s: reset the PowerPC core\n", __func__); 50553018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); 50653018216SPaolo Bonzini } 50753018216SPaolo Bonzini break; 50853018216SPaolo Bonzini case PPCE500_INPUT_CINT: 50953018216SPaolo Bonzini /* Level sensitive - active high */ 51053018216SPaolo Bonzini LOG_IRQ("%s: set the critical IRQ state to %d\n", 51153018216SPaolo Bonzini __func__, level); 51253018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); 51353018216SPaolo Bonzini break; 51453018216SPaolo Bonzini case PPCE500_INPUT_INT: 51553018216SPaolo Bonzini /* Level sensitive - active high */ 51653018216SPaolo Bonzini LOG_IRQ("%s: set the core IRQ state to %d\n", 51753018216SPaolo Bonzini __func__, level); 51853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); 51953018216SPaolo Bonzini break; 52053018216SPaolo Bonzini case PPCE500_INPUT_DEBUG: 52153018216SPaolo Bonzini /* Level sensitive - active high */ 52253018216SPaolo Bonzini LOG_IRQ("%s: set the debug pin state to %d\n", 52353018216SPaolo Bonzini __func__, level); 52453018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); 52553018216SPaolo Bonzini break; 52653018216SPaolo Bonzini default: 52753018216SPaolo Bonzini /* Unknown pin - do nothing */ 52853018216SPaolo Bonzini LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); 52953018216SPaolo Bonzini return; 53053018216SPaolo Bonzini } 53153018216SPaolo Bonzini if (level) 53253018216SPaolo Bonzini env->irq_input_state |= 1 << pin; 53353018216SPaolo Bonzini else 53453018216SPaolo Bonzini env->irq_input_state &= ~(1 << pin); 53553018216SPaolo Bonzini } 53653018216SPaolo Bonzini } 53753018216SPaolo Bonzini 538aa5a9e24SPaolo Bonzini void ppce500_irq_init(PowerPCCPU *cpu) 53953018216SPaolo Bonzini { 540aa5a9e24SPaolo Bonzini CPUPPCState *env = &cpu->env; 54153018216SPaolo Bonzini 54253018216SPaolo Bonzini env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, 54353018216SPaolo Bonzini cpu, PPCE500_INPUT_NB); 54453018216SPaolo Bonzini } 54553018216SPaolo Bonzini 54653018216SPaolo Bonzini /* Enable or Disable the E500 EPR capability */ 54753018216SPaolo Bonzini void ppce500_set_mpic_proxy(bool enabled) 54853018216SPaolo Bonzini { 549182735efSAndreas Färber CPUState *cs; 55053018216SPaolo Bonzini 551bdc44640SAndreas Färber CPU_FOREACH(cs) { 552182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 55353018216SPaolo Bonzini 554182735efSAndreas Färber cpu->env.mpic_proxy = enabled; 55553018216SPaolo Bonzini if (kvm_enabled()) { 556182735efSAndreas Färber kvmppc_set_mpic_proxy(cpu, enabled); 55753018216SPaolo Bonzini } 55853018216SPaolo Bonzini } 55953018216SPaolo Bonzini } 56053018216SPaolo Bonzini 56153018216SPaolo Bonzini /*****************************************************************************/ 56253018216SPaolo Bonzini /* PowerPC time base and decrementer emulation */ 56353018216SPaolo Bonzini 56453018216SPaolo Bonzini uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) 56553018216SPaolo Bonzini { 56653018216SPaolo Bonzini /* TB time in tb periods */ 56773bcb24dSRutuja Shah return muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND) + tb_offset; 56853018216SPaolo Bonzini } 56953018216SPaolo Bonzini 57053018216SPaolo Bonzini uint64_t cpu_ppc_load_tbl (CPUPPCState *env) 57153018216SPaolo Bonzini { 57253018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 57353018216SPaolo Bonzini uint64_t tb; 57453018216SPaolo Bonzini 57553018216SPaolo Bonzini if (kvm_enabled()) { 57653018216SPaolo Bonzini return env->spr[SPR_TBL]; 57753018216SPaolo Bonzini } 57853018216SPaolo Bonzini 579bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 58053018216SPaolo Bonzini LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 58153018216SPaolo Bonzini 58253018216SPaolo Bonzini return tb; 58353018216SPaolo Bonzini } 58453018216SPaolo Bonzini 58553018216SPaolo Bonzini static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env) 58653018216SPaolo Bonzini { 58753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 58853018216SPaolo Bonzini uint64_t tb; 58953018216SPaolo Bonzini 590bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 59153018216SPaolo Bonzini LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 59253018216SPaolo Bonzini 59353018216SPaolo Bonzini return tb >> 32; 59453018216SPaolo Bonzini } 59553018216SPaolo Bonzini 59653018216SPaolo Bonzini uint32_t cpu_ppc_load_tbu (CPUPPCState *env) 59753018216SPaolo Bonzini { 59853018216SPaolo Bonzini if (kvm_enabled()) { 59953018216SPaolo Bonzini return env->spr[SPR_TBU]; 60053018216SPaolo Bonzini } 60153018216SPaolo Bonzini 60253018216SPaolo Bonzini return _cpu_ppc_load_tbu(env); 60353018216SPaolo Bonzini } 60453018216SPaolo Bonzini 60553018216SPaolo Bonzini static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk, 60653018216SPaolo Bonzini int64_t *tb_offsetp, uint64_t value) 60753018216SPaolo Bonzini { 60873bcb24dSRutuja Shah *tb_offsetp = value - 60973bcb24dSRutuja Shah muldiv64(vmclk, tb_env->tb_freq, NANOSECONDS_PER_SECOND); 61073bcb24dSRutuja Shah 61153018216SPaolo Bonzini LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n", 61253018216SPaolo Bonzini __func__, value, *tb_offsetp); 61353018216SPaolo Bonzini } 61453018216SPaolo Bonzini 61553018216SPaolo Bonzini void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value) 61653018216SPaolo Bonzini { 61753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 61853018216SPaolo Bonzini uint64_t tb; 61953018216SPaolo Bonzini 620bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 62153018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 622bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 62353018216SPaolo Bonzini &tb_env->tb_offset, tb | (uint64_t)value); 62453018216SPaolo Bonzini } 62553018216SPaolo Bonzini 62653018216SPaolo Bonzini static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value) 62753018216SPaolo Bonzini { 62853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 62953018216SPaolo Bonzini uint64_t tb; 63053018216SPaolo Bonzini 631bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset); 63253018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 633bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 63453018216SPaolo Bonzini &tb_env->tb_offset, ((uint64_t)value << 32) | tb); 63553018216SPaolo Bonzini } 63653018216SPaolo Bonzini 63753018216SPaolo Bonzini void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value) 63853018216SPaolo Bonzini { 63953018216SPaolo Bonzini _cpu_ppc_store_tbu(env, value); 64053018216SPaolo Bonzini } 64153018216SPaolo Bonzini 64253018216SPaolo Bonzini uint64_t cpu_ppc_load_atbl (CPUPPCState *env) 64353018216SPaolo Bonzini { 64453018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 64553018216SPaolo Bonzini uint64_t tb; 64653018216SPaolo Bonzini 647bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 64853018216SPaolo Bonzini LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 64953018216SPaolo Bonzini 65053018216SPaolo Bonzini return tb; 65153018216SPaolo Bonzini } 65253018216SPaolo Bonzini 65353018216SPaolo Bonzini uint32_t cpu_ppc_load_atbu (CPUPPCState *env) 65453018216SPaolo Bonzini { 65553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 65653018216SPaolo Bonzini uint64_t tb; 65753018216SPaolo Bonzini 658bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 65953018216SPaolo Bonzini LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); 66053018216SPaolo Bonzini 66153018216SPaolo Bonzini return tb >> 32; 66253018216SPaolo Bonzini } 66353018216SPaolo Bonzini 66453018216SPaolo Bonzini void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value) 66553018216SPaolo Bonzini { 66653018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 66753018216SPaolo Bonzini uint64_t tb; 66853018216SPaolo Bonzini 669bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 67053018216SPaolo Bonzini tb &= 0xFFFFFFFF00000000ULL; 671bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 67253018216SPaolo Bonzini &tb_env->atb_offset, tb | (uint64_t)value); 67353018216SPaolo Bonzini } 67453018216SPaolo Bonzini 67553018216SPaolo Bonzini void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value) 67653018216SPaolo Bonzini { 67753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 67853018216SPaolo Bonzini uint64_t tb; 67953018216SPaolo Bonzini 680bc72ad67SAlex Bligh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset); 68153018216SPaolo Bonzini tb &= 0x00000000FFFFFFFFULL; 682bc72ad67SAlex Bligh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 68353018216SPaolo Bonzini &tb_env->atb_offset, ((uint64_t)value << 32) | tb); 68453018216SPaolo Bonzini } 68553018216SPaolo Bonzini 6865d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env) 6875d62725bSSuraj Jitindar Singh { 6885d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6895d62725bSSuraj Jitindar Singh 6905d62725bSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6915d62725bSSuraj Jitindar Singh tb_env->vtb_offset); 6925d62725bSSuraj Jitindar Singh } 6935d62725bSSuraj Jitindar Singh 6945d62725bSSuraj Jitindar Singh void cpu_ppc_store_vtb(CPUPPCState *env, uint64_t value) 6955d62725bSSuraj Jitindar Singh { 6965d62725bSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 6975d62725bSSuraj Jitindar Singh 6985d62725bSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 6995d62725bSSuraj Jitindar Singh &tb_env->vtb_offset, value); 7005d62725bSSuraj Jitindar Singh } 7015d62725bSSuraj Jitindar Singh 702f0ec31b1SSuraj Jitindar Singh void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value) 703f0ec31b1SSuraj Jitindar Singh { 704f0ec31b1SSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 705f0ec31b1SSuraj Jitindar Singh uint64_t tb; 706f0ec31b1SSuraj Jitindar Singh 707f0ec31b1SSuraj Jitindar Singh tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 708f0ec31b1SSuraj Jitindar Singh tb_env->tb_offset); 709f0ec31b1SSuraj Jitindar Singh tb &= 0xFFFFFFUL; 710f0ec31b1SSuraj Jitindar Singh tb |= (value & ~0xFFFFFFUL); 711f0ec31b1SSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 712f0ec31b1SSuraj Jitindar Singh &tb_env->tb_offset, tb); 713f0ec31b1SSuraj Jitindar Singh } 714f0ec31b1SSuraj Jitindar Singh 71553018216SPaolo Bonzini static void cpu_ppc_tb_stop (CPUPPCState *env) 71653018216SPaolo Bonzini { 71753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 71853018216SPaolo Bonzini uint64_t tb, atb, vmclk; 71953018216SPaolo Bonzini 72053018216SPaolo Bonzini /* If the time base is already frozen, do nothing */ 72153018216SPaolo Bonzini if (tb_env->tb_freq != 0) { 722bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 72353018216SPaolo Bonzini /* Get the time base */ 72453018216SPaolo Bonzini tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); 72553018216SPaolo Bonzini /* Get the alternate time base */ 72653018216SPaolo Bonzini atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); 72753018216SPaolo Bonzini /* Store the time base value (ie compute the current offset) */ 72853018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 72953018216SPaolo Bonzini /* Store the alternate time base value (compute the current offset) */ 73053018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 73153018216SPaolo Bonzini /* Set the time base frequency to zero */ 73253018216SPaolo Bonzini tb_env->tb_freq = 0; 73353018216SPaolo Bonzini /* Now, the time bases are frozen to tb_offset / atb_offset value */ 73453018216SPaolo Bonzini } 73553018216SPaolo Bonzini } 73653018216SPaolo Bonzini 73753018216SPaolo Bonzini static void cpu_ppc_tb_start (CPUPPCState *env) 73853018216SPaolo Bonzini { 73953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 74053018216SPaolo Bonzini uint64_t tb, atb, vmclk; 74153018216SPaolo Bonzini 74253018216SPaolo Bonzini /* If the time base is not frozen, do nothing */ 74353018216SPaolo Bonzini if (tb_env->tb_freq == 0) { 744bc72ad67SAlex Bligh vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 74553018216SPaolo Bonzini /* Get the time base from tb_offset */ 74653018216SPaolo Bonzini tb = tb_env->tb_offset; 74753018216SPaolo Bonzini /* Get the alternate time base from atb_offset */ 74853018216SPaolo Bonzini atb = tb_env->atb_offset; 74953018216SPaolo Bonzini /* Restore the tb frequency from the decrementer frequency */ 75053018216SPaolo Bonzini tb_env->tb_freq = tb_env->decr_freq; 75153018216SPaolo Bonzini /* Store the time base value */ 75253018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); 75353018216SPaolo Bonzini /* Store the alternate time base value */ 75453018216SPaolo Bonzini cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); 75553018216SPaolo Bonzini } 75653018216SPaolo Bonzini } 75753018216SPaolo Bonzini 758e81a982aSAlexander Graf bool ppc_decr_clear_on_delivery(CPUPPCState *env) 759e81a982aSAlexander Graf { 760e81a982aSAlexander Graf ppc_tb_t *tb_env = env->tb_env; 761e81a982aSAlexander Graf int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL; 762e81a982aSAlexander Graf return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED); 763e81a982aSAlexander Graf } 764e81a982aSAlexander Graf 765a8dafa52SSuraj Jitindar Singh static inline int64_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next) 76653018216SPaolo Bonzini { 76753018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 768a8dafa52SSuraj Jitindar Singh int64_t decr, diff; 76953018216SPaolo Bonzini 770bc72ad67SAlex Bligh diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 77153018216SPaolo Bonzini if (diff >= 0) { 77273bcb24dSRutuja Shah decr = muldiv64(diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 77353018216SPaolo Bonzini } else if (tb_env->flags & PPC_TIMER_BOOKE) { 77453018216SPaolo Bonzini decr = 0; 77553018216SPaolo Bonzini } else { 77673bcb24dSRutuja Shah decr = -muldiv64(-diff, tb_env->decr_freq, NANOSECONDS_PER_SECOND); 77753018216SPaolo Bonzini } 778a8dafa52SSuraj Jitindar Singh LOG_TB("%s: %016" PRIx64 "\n", __func__, decr); 77953018216SPaolo Bonzini 78053018216SPaolo Bonzini return decr; 78153018216SPaolo Bonzini } 78253018216SPaolo Bonzini 783a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_decr(CPUPPCState *env) 78453018216SPaolo Bonzini { 78553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 786a8dafa52SSuraj Jitindar Singh uint64_t decr; 78753018216SPaolo Bonzini 78853018216SPaolo Bonzini if (kvm_enabled()) { 78953018216SPaolo Bonzini return env->spr[SPR_DECR]; 79053018216SPaolo Bonzini } 79153018216SPaolo Bonzini 792a8dafa52SSuraj Jitindar Singh decr = _cpu_ppc_load_decr(env, tb_env->decr_next); 793a8dafa52SSuraj Jitindar Singh 794a8dafa52SSuraj Jitindar Singh /* 795a8dafa52SSuraj Jitindar Singh * If large decrementer is enabled then the decrementer is signed extened 796a8dafa52SSuraj Jitindar Singh * to 64 bits, otherwise it is a 32 bit value. 797a8dafa52SSuraj Jitindar Singh */ 798a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 799a8dafa52SSuraj Jitindar Singh return decr; 800a8dafa52SSuraj Jitindar Singh } 801a8dafa52SSuraj Jitindar Singh return (uint32_t) decr; 80253018216SPaolo Bonzini } 80353018216SPaolo Bonzini 804a8dafa52SSuraj Jitindar Singh target_ulong cpu_ppc_load_hdecr(CPUPPCState *env) 80553018216SPaolo Bonzini { 806db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 807a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 80853018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 809a8dafa52SSuraj Jitindar Singh uint64_t hdecr; 81053018216SPaolo Bonzini 811a8dafa52SSuraj Jitindar Singh hdecr = _cpu_ppc_load_decr(env, tb_env->hdecr_next); 812a8dafa52SSuraj Jitindar Singh 813a8dafa52SSuraj Jitindar Singh /* 814a8dafa52SSuraj Jitindar Singh * If we have a large decrementer (POWER9 or later) then hdecr is sign 815a8dafa52SSuraj Jitindar Singh * extended to 64 bits, otherwise it is 32 bits. 816a8dafa52SSuraj Jitindar Singh */ 817a8dafa52SSuraj Jitindar Singh if (pcc->lrg_decr_bits > 32) { 818a8dafa52SSuraj Jitindar Singh return hdecr; 819a8dafa52SSuraj Jitindar Singh } 820a8dafa52SSuraj Jitindar Singh return (uint32_t) hdecr; 82153018216SPaolo Bonzini } 82253018216SPaolo Bonzini 82353018216SPaolo Bonzini uint64_t cpu_ppc_load_purr (CPUPPCState *env) 82453018216SPaolo Bonzini { 82553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 82653018216SPaolo Bonzini 8275cc7e69fSSuraj Jitindar Singh return cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 8285cc7e69fSSuraj Jitindar Singh tb_env->purr_offset); 82953018216SPaolo Bonzini } 83053018216SPaolo Bonzini 83153018216SPaolo Bonzini /* When decrementer expires, 83253018216SPaolo Bonzini * all we need to do is generate or queue a CPU exception 83353018216SPaolo Bonzini */ 83453018216SPaolo Bonzini static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) 83553018216SPaolo Bonzini { 83653018216SPaolo Bonzini /* Raise it */ 83753018216SPaolo Bonzini LOG_TB("raise decrementer exception\n"); 83853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); 83953018216SPaolo Bonzini } 84053018216SPaolo Bonzini 841e81a982aSAlexander Graf static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) 842e81a982aSAlexander Graf { 843e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0); 844e81a982aSAlexander Graf } 845e81a982aSAlexander Graf 84653018216SPaolo Bonzini static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) 84753018216SPaolo Bonzini { 8484b236b62SBenjamin Herrenschmidt CPUPPCState *env = &cpu->env; 8494b236b62SBenjamin Herrenschmidt 85053018216SPaolo Bonzini /* Raise it */ 8514b236b62SBenjamin Herrenschmidt LOG_TB("raise hv decrementer exception\n"); 8524b236b62SBenjamin Herrenschmidt 8534b236b62SBenjamin Herrenschmidt /* The architecture specifies that we don't deliver HDEC 8544b236b62SBenjamin Herrenschmidt * interrupts in a PM state. Not only they don't cause a 8554b236b62SBenjamin Herrenschmidt * wakeup but they also get effectively discarded. 8564b236b62SBenjamin Herrenschmidt */ 8571e7fd61dSBenjamin Herrenschmidt if (!env->resume_as_sreset) { 85853018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); 85953018216SPaolo Bonzini } 8604b236b62SBenjamin Herrenschmidt } 86153018216SPaolo Bonzini 862e81a982aSAlexander Graf static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) 863e81a982aSAlexander Graf { 864e81a982aSAlexander Graf ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0); 865e81a982aSAlexander Graf } 866e81a982aSAlexander Graf 86753018216SPaolo Bonzini static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, 8681246b259SStefan Weil QEMUTimer *timer, 869e81a982aSAlexander Graf void (*raise_excp)(void *), 870e81a982aSAlexander Graf void (*lower_excp)(PowerPCCPU *), 871a8dafa52SSuraj Jitindar Singh target_ulong decr, target_ulong value, 872a8dafa52SSuraj Jitindar Singh int nr_bits) 87353018216SPaolo Bonzini { 87453018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 87553018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 87653018216SPaolo Bonzini uint64_t now, next; 877a8dafa52SSuraj Jitindar Singh bool negative; 87853018216SPaolo Bonzini 879a8dafa52SSuraj Jitindar Singh /* Truncate value to decr_width and sign extend for simplicity */ 880a8dafa52SSuraj Jitindar Singh value &= ((1ULL << nr_bits) - 1); 881a8dafa52SSuraj Jitindar Singh negative = !!(value & (1ULL << (nr_bits - 1))); 882a8dafa52SSuraj Jitindar Singh if (negative) { 883a8dafa52SSuraj Jitindar Singh value |= (0xFFFFFFFFULL << nr_bits); 884a8dafa52SSuraj Jitindar Singh } 885a8dafa52SSuraj Jitindar Singh 886a8dafa52SSuraj Jitindar Singh LOG_TB("%s: " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, 88753018216SPaolo Bonzini decr, value); 88853018216SPaolo Bonzini 88953018216SPaolo Bonzini if (kvm_enabled()) { 89053018216SPaolo Bonzini /* KVM handles decrementer exceptions, we don't need our own timer */ 89153018216SPaolo Bonzini return; 89253018216SPaolo Bonzini } 89353018216SPaolo Bonzini 894e81a982aSAlexander Graf /* 895e81a982aSAlexander Graf * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC 896e81a982aSAlexander Graf * interrupt. 897e81a982aSAlexander Graf * 898e81a982aSAlexander Graf * If we get a really small DEC value, we can assume that by the time we 899e81a982aSAlexander Graf * handled it we should inject an interrupt already. 900e81a982aSAlexander Graf * 901e81a982aSAlexander Graf * On MSB level based DEC implementations the MSB always means the interrupt 902e81a982aSAlexander Graf * is pending, so raise it on those. 903e81a982aSAlexander Graf * 904e81a982aSAlexander Graf * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers 905e81a982aSAlexander Graf * an edge interrupt, so raise it here too. 906e81a982aSAlexander Graf */ 907e81a982aSAlexander Graf if ((value < 3) || 908a8dafa52SSuraj Jitindar Singh ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && negative) || 909a8dafa52SSuraj Jitindar Singh ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && negative 910a8dafa52SSuraj Jitindar Singh && !(decr & (1ULL << (nr_bits - 1))))) { 911e81a982aSAlexander Graf (*raise_excp)(cpu); 912e81a982aSAlexander Graf return; 913e81a982aSAlexander Graf } 914e81a982aSAlexander Graf 915e81a982aSAlexander Graf /* On MSB level based systems a 0 for the MSB stops interrupt delivery */ 916a8dafa52SSuraj Jitindar Singh if (!negative && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) { 917e81a982aSAlexander Graf (*lower_excp)(cpu); 918e81a982aSAlexander Graf } 919e81a982aSAlexander Graf 920e81a982aSAlexander Graf /* Calculate the next timer event */ 921bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 92273bcb24dSRutuja Shah next = now + muldiv64(value, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 92353018216SPaolo Bonzini *nextp = next; 924e81a982aSAlexander Graf 92553018216SPaolo Bonzini /* Adjust timer */ 926bc72ad67SAlex Bligh timer_mod(timer, next); 92753018216SPaolo Bonzini } 92853018216SPaolo Bonzini 929a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, target_ulong decr, 930a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 93153018216SPaolo Bonzini { 93253018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 93353018216SPaolo Bonzini 93453018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, 935e81a982aSAlexander Graf tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr, 936a8dafa52SSuraj Jitindar Singh value, nr_bits); 93753018216SPaolo Bonzini } 93853018216SPaolo Bonzini 939a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_decr(CPUPPCState *env, target_ulong value) 94053018216SPaolo Bonzini { 941db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 942a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 943a8dafa52SSuraj Jitindar Singh int nr_bits = 32; 94453018216SPaolo Bonzini 945a8dafa52SSuraj Jitindar Singh if (env->spr[SPR_LPCR] & LPCR_LD) { 946a8dafa52SSuraj Jitindar Singh nr_bits = pcc->lrg_decr_bits; 947a8dafa52SSuraj Jitindar Singh } 948a8dafa52SSuraj Jitindar Singh 949a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, nr_bits); 95053018216SPaolo Bonzini } 95153018216SPaolo Bonzini 95253018216SPaolo Bonzini static void cpu_ppc_decr_cb(void *opaque) 95353018216SPaolo Bonzini { 95453018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 95553018216SPaolo Bonzini 956e81a982aSAlexander Graf cpu_ppc_decr_excp(cpu); 95753018216SPaolo Bonzini } 95853018216SPaolo Bonzini 959a8dafa52SSuraj Jitindar Singh static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, target_ulong hdecr, 960a8dafa52SSuraj Jitindar Singh target_ulong value, int nr_bits) 96153018216SPaolo Bonzini { 96253018216SPaolo Bonzini ppc_tb_t *tb_env = cpu->env.tb_env; 96353018216SPaolo Bonzini 96453018216SPaolo Bonzini if (tb_env->hdecr_timer != NULL) { 96553018216SPaolo Bonzini __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, 966e81a982aSAlexander Graf tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower, 967a8dafa52SSuraj Jitindar Singh hdecr, value, nr_bits); 96853018216SPaolo Bonzini } 96953018216SPaolo Bonzini } 97053018216SPaolo Bonzini 971a8dafa52SSuraj Jitindar Singh void cpu_ppc_store_hdecr(CPUPPCState *env, target_ulong value) 97253018216SPaolo Bonzini { 973db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 974a8dafa52SSuraj Jitindar Singh PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 97553018216SPaolo Bonzini 976a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 977a8dafa52SSuraj Jitindar Singh pcc->lrg_decr_bits); 97853018216SPaolo Bonzini } 97953018216SPaolo Bonzini 98053018216SPaolo Bonzini static void cpu_ppc_hdecr_cb(void *opaque) 98153018216SPaolo Bonzini { 98253018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 98353018216SPaolo Bonzini 984e81a982aSAlexander Graf cpu_ppc_hdecr_excp(cpu); 98553018216SPaolo Bonzini } 98653018216SPaolo Bonzini 9875cc7e69fSSuraj Jitindar Singh void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) 98853018216SPaolo Bonzini { 9895cc7e69fSSuraj Jitindar Singh ppc_tb_t *tb_env = env->tb_env; 99053018216SPaolo Bonzini 9915cc7e69fSSuraj Jitindar Singh cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 9925cc7e69fSSuraj Jitindar Singh &tb_env->purr_offset, value); 99353018216SPaolo Bonzini } 99453018216SPaolo Bonzini 99553018216SPaolo Bonzini static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) 99653018216SPaolo Bonzini { 99753018216SPaolo Bonzini CPUPPCState *env = opaque; 998db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 99953018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 100053018216SPaolo Bonzini 100153018216SPaolo Bonzini tb_env->tb_freq = freq; 100253018216SPaolo Bonzini tb_env->decr_freq = freq; 100353018216SPaolo Bonzini /* There is a bug in Linux 2.4 kernels: 100453018216SPaolo Bonzini * if a decrementer exception is pending when it enables msr_ee at startup, 100553018216SPaolo Bonzini * it's not ready to handle it... 100653018216SPaolo Bonzini */ 1007a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 1008a8dafa52SSuraj Jitindar Singh _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 32); 10095cc7e69fSSuraj Jitindar Singh cpu_ppc_store_purr(env, 0x0000000000000000ULL); 101053018216SPaolo Bonzini } 101153018216SPaolo Bonzini 101242043e4fSLaurent Vivier static void timebase_save(PPCTimebase *tb) 101398a8b524SAlexey Kardashevskiy { 10144a7428c5SChristopher Covington uint64_t ticks = cpu_get_host_ticks(); 101598a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 101698a8b524SAlexey Kardashevskiy 101798a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 101898a8b524SAlexey Kardashevskiy error_report("No timebase object"); 101998a8b524SAlexey Kardashevskiy return; 102098a8b524SAlexey Kardashevskiy } 102198a8b524SAlexey Kardashevskiy 102242043e4fSLaurent Vivier /* not used anymore, we keep it for compatibility */ 102377bad151SPaolo Bonzini tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); 102498a8b524SAlexey Kardashevskiy /* 102542043e4fSLaurent Vivier * tb_offset is only expected to be changed by QEMU so 102698a8b524SAlexey Kardashevskiy * there is no need to update it from KVM here 102798a8b524SAlexey Kardashevskiy */ 102898a8b524SAlexey Kardashevskiy tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; 1029d14f3397SMaxiwell S. Garcia 1030711dfb24SGreg Kurz tb->runstate_paused = 1031711dfb24SGreg Kurz runstate_check(RUN_STATE_PAUSED) || runstate_check(RUN_STATE_SAVE_VM); 103298a8b524SAlexey Kardashevskiy } 103398a8b524SAlexey Kardashevskiy 103442043e4fSLaurent Vivier static void timebase_load(PPCTimebase *tb) 103598a8b524SAlexey Kardashevskiy { 103698a8b524SAlexey Kardashevskiy CPUState *cpu; 103798a8b524SAlexey Kardashevskiy PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); 103842043e4fSLaurent Vivier int64_t tb_off_adj, tb_off; 103998a8b524SAlexey Kardashevskiy unsigned long freq; 104098a8b524SAlexey Kardashevskiy 104198a8b524SAlexey Kardashevskiy if (!first_ppc_cpu->env.tb_env) { 104298a8b524SAlexey Kardashevskiy error_report("No timebase object"); 104342043e4fSLaurent Vivier return; 104498a8b524SAlexey Kardashevskiy } 104598a8b524SAlexey Kardashevskiy 104698a8b524SAlexey Kardashevskiy freq = first_ppc_cpu->env.tb_env->tb_freq; 104798a8b524SAlexey Kardashevskiy 104842043e4fSLaurent Vivier tb_off_adj = tb->guest_timebase - cpu_get_host_ticks(); 104998a8b524SAlexey Kardashevskiy 105098a8b524SAlexey Kardashevskiy tb_off = first_ppc_cpu->env.tb_env->tb_offset; 105198a8b524SAlexey Kardashevskiy trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, 105298a8b524SAlexey Kardashevskiy (tb_off_adj - tb_off) / freq); 105398a8b524SAlexey Kardashevskiy 105498a8b524SAlexey Kardashevskiy /* Set new offset to all CPUs */ 105598a8b524SAlexey Kardashevskiy CPU_FOREACH(cpu) { 105698a8b524SAlexey Kardashevskiy PowerPCCPU *pcpu = POWERPC_CPU(cpu); 105798a8b524SAlexey Kardashevskiy pcpu->env.tb_env->tb_offset = tb_off_adj; 10589723295aSGreg Kurz kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset); 105942043e4fSLaurent Vivier } 106098a8b524SAlexey Kardashevskiy } 106198a8b524SAlexey Kardashevskiy 1062*538f0497SPhilippe Mathieu-Daudé void cpu_ppc_clock_vm_state_change(void *opaque, bool running, 106342043e4fSLaurent Vivier RunState state) 106442043e4fSLaurent Vivier { 106542043e4fSLaurent Vivier PPCTimebase *tb = opaque; 106642043e4fSLaurent Vivier 106742043e4fSLaurent Vivier if (running) { 106842043e4fSLaurent Vivier timebase_load(tb); 106942043e4fSLaurent Vivier } else { 107042043e4fSLaurent Vivier timebase_save(tb); 107142043e4fSLaurent Vivier } 107242043e4fSLaurent Vivier } 107342043e4fSLaurent Vivier 107442043e4fSLaurent Vivier /* 1075d14f3397SMaxiwell S. Garcia * When migrating a running guest, read the clock just 1076d14f3397SMaxiwell S. Garcia * before migration, so that the guest clock counts 1077d14f3397SMaxiwell S. Garcia * during the events between: 107842043e4fSLaurent Vivier * 107942043e4fSLaurent Vivier * * vm_stop() 108042043e4fSLaurent Vivier * * 108142043e4fSLaurent Vivier * * pre_save() 108242043e4fSLaurent Vivier * 108342043e4fSLaurent Vivier * This reduces clock difference on migration from 5s 108442043e4fSLaurent Vivier * to 0.1s (when max_downtime == 5s), because sending the 108542043e4fSLaurent Vivier * final pages of memory (which happens between vm_stop() 108642043e4fSLaurent Vivier * and pre_save()) takes max_downtime. 108742043e4fSLaurent Vivier */ 108844b1ff31SDr. David Alan Gilbert static int timebase_pre_save(void *opaque) 108942043e4fSLaurent Vivier { 109042043e4fSLaurent Vivier PPCTimebase *tb = opaque; 109142043e4fSLaurent Vivier 1092711dfb24SGreg Kurz /* guest_timebase won't be overridden in case of paused guest or savevm */ 1093d14f3397SMaxiwell S. Garcia if (!tb->runstate_paused) { 109442043e4fSLaurent Vivier timebase_save(tb); 1095d14f3397SMaxiwell S. Garcia } 109644b1ff31SDr. David Alan Gilbert 109744b1ff31SDr. David Alan Gilbert return 0; 109898a8b524SAlexey Kardashevskiy } 109998a8b524SAlexey Kardashevskiy 110098a8b524SAlexey Kardashevskiy const VMStateDescription vmstate_ppc_timebase = { 110198a8b524SAlexey Kardashevskiy .name = "timebase", 110298a8b524SAlexey Kardashevskiy .version_id = 1, 110398a8b524SAlexey Kardashevskiy .minimum_version_id = 1, 110498a8b524SAlexey Kardashevskiy .minimum_version_id_old = 1, 110598a8b524SAlexey Kardashevskiy .pre_save = timebase_pre_save, 110698a8b524SAlexey Kardashevskiy .fields = (VMStateField []) { 110798a8b524SAlexey Kardashevskiy VMSTATE_UINT64(guest_timebase, PPCTimebase), 110898a8b524SAlexey Kardashevskiy VMSTATE_INT64(time_of_the_day_ns, PPCTimebase), 110998a8b524SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 111098a8b524SAlexey Kardashevskiy }, 111198a8b524SAlexey Kardashevskiy }; 111298a8b524SAlexey Kardashevskiy 111353018216SPaolo Bonzini /* Set up (once) timebase frequency (in Hz) */ 111453018216SPaolo Bonzini clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) 111553018216SPaolo Bonzini { 1116db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 111753018216SPaolo Bonzini ppc_tb_t *tb_env; 111853018216SPaolo Bonzini 111953018216SPaolo Bonzini tb_env = g_malloc0(sizeof(ppc_tb_t)); 112053018216SPaolo Bonzini env->tb_env = tb_env; 112153018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 1122d0db7cadSGreg Kurz if (is_book3s_arch2x(env)) { 1123e81a982aSAlexander Graf /* All Book3S 64bit CPUs implement level based DEC logic */ 1124e81a982aSAlexander Graf tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL; 1125e81a982aSAlexander Graf } 112653018216SPaolo Bonzini /* Create new timer */ 1127bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); 11284b236b62SBenjamin Herrenschmidt if (env->has_hv_mode) { 1129bc72ad67SAlex Bligh tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, 113053018216SPaolo Bonzini cpu); 113153018216SPaolo Bonzini } else { 113253018216SPaolo Bonzini tb_env->hdecr_timer = NULL; 113353018216SPaolo Bonzini } 113453018216SPaolo Bonzini cpu_ppc_set_tb_clk(env, freq); 113553018216SPaolo Bonzini 113653018216SPaolo Bonzini return &cpu_ppc_set_tb_clk; 113753018216SPaolo Bonzini } 113853018216SPaolo Bonzini 113953018216SPaolo Bonzini /* Specific helpers for POWER & PowerPC 601 RTC */ 114053018216SPaolo Bonzini void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value) 114153018216SPaolo Bonzini { 114253018216SPaolo Bonzini _cpu_ppc_store_tbu(env, value); 114353018216SPaolo Bonzini } 114453018216SPaolo Bonzini 114553018216SPaolo Bonzini uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env) 114653018216SPaolo Bonzini { 114753018216SPaolo Bonzini return _cpu_ppc_load_tbu(env); 114853018216SPaolo Bonzini } 114953018216SPaolo Bonzini 115053018216SPaolo Bonzini void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value) 115153018216SPaolo Bonzini { 115253018216SPaolo Bonzini cpu_ppc_store_tbl(env, value & 0x3FFFFF80); 115353018216SPaolo Bonzini } 115453018216SPaolo Bonzini 115553018216SPaolo Bonzini uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env) 115653018216SPaolo Bonzini { 115753018216SPaolo Bonzini return cpu_ppc_load_tbl(env) & 0x3FFFFF80; 115853018216SPaolo Bonzini } 115953018216SPaolo Bonzini 116053018216SPaolo Bonzini /*****************************************************************************/ 116153018216SPaolo Bonzini /* PowerPC 40x timers */ 116253018216SPaolo Bonzini 116353018216SPaolo Bonzini /* PIT, FIT & WDT */ 116453018216SPaolo Bonzini typedef struct ppc40x_timer_t ppc40x_timer_t; 116553018216SPaolo Bonzini struct ppc40x_timer_t { 116653018216SPaolo Bonzini uint64_t pit_reload; /* PIT auto-reload value */ 116753018216SPaolo Bonzini uint64_t fit_next; /* Tick for next FIT interrupt */ 11681246b259SStefan Weil QEMUTimer *fit_timer; 116953018216SPaolo Bonzini uint64_t wdt_next; /* Tick for next WDT interrupt */ 11701246b259SStefan Weil QEMUTimer *wdt_timer; 117153018216SPaolo Bonzini 117253018216SPaolo Bonzini /* 405 have the PIT, 440 have a DECR. */ 117353018216SPaolo Bonzini unsigned int decr_excp; 117453018216SPaolo Bonzini }; 117553018216SPaolo Bonzini 117653018216SPaolo Bonzini /* Fixed interval timer */ 117753018216SPaolo Bonzini static void cpu_4xx_fit_cb (void *opaque) 117853018216SPaolo Bonzini { 117953018216SPaolo Bonzini PowerPCCPU *cpu; 118053018216SPaolo Bonzini CPUPPCState *env; 118153018216SPaolo Bonzini ppc_tb_t *tb_env; 118253018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 118353018216SPaolo Bonzini uint64_t now, next; 118453018216SPaolo Bonzini 118553018216SPaolo Bonzini env = opaque; 1186db70b311SRichard Henderson cpu = env_archcpu(env); 118753018216SPaolo Bonzini tb_env = env->tb_env; 118853018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1189bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 119053018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { 119153018216SPaolo Bonzini case 0: 119253018216SPaolo Bonzini next = 1 << 9; 119353018216SPaolo Bonzini break; 119453018216SPaolo Bonzini case 1: 119553018216SPaolo Bonzini next = 1 << 13; 119653018216SPaolo Bonzini break; 119753018216SPaolo Bonzini case 2: 119853018216SPaolo Bonzini next = 1 << 17; 119953018216SPaolo Bonzini break; 120053018216SPaolo Bonzini case 3: 120153018216SPaolo Bonzini next = 1 << 21; 120253018216SPaolo Bonzini break; 120353018216SPaolo Bonzini default: 120453018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 120553018216SPaolo Bonzini return; 120653018216SPaolo Bonzini } 120773bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->tb_freq); 120853018216SPaolo Bonzini if (next == now) 120953018216SPaolo Bonzini next++; 1210bc72ad67SAlex Bligh timer_mod(ppc40x_timer->fit_timer, next); 121153018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 26; 121253018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { 121353018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); 121453018216SPaolo Bonzini } 121553018216SPaolo Bonzini LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, 121653018216SPaolo Bonzini (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), 121753018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 121853018216SPaolo Bonzini } 121953018216SPaolo Bonzini 122053018216SPaolo Bonzini /* Programmable interval timer */ 122153018216SPaolo Bonzini static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) 122253018216SPaolo Bonzini { 122353018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 122453018216SPaolo Bonzini uint64_t now, next; 122553018216SPaolo Bonzini 122653018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 122753018216SPaolo Bonzini if (ppc40x_timer->pit_reload <= 1 || 122853018216SPaolo Bonzini !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || 122953018216SPaolo Bonzini (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { 123053018216SPaolo Bonzini /* Stop PIT */ 123153018216SPaolo Bonzini LOG_TB("%s: stop PIT\n", __func__); 1232bc72ad67SAlex Bligh timer_del(tb_env->decr_timer); 123353018216SPaolo Bonzini } else { 123453018216SPaolo Bonzini LOG_TB("%s: start PIT %016" PRIx64 "\n", 123553018216SPaolo Bonzini __func__, ppc40x_timer->pit_reload); 1236bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 123753018216SPaolo Bonzini next = now + muldiv64(ppc40x_timer->pit_reload, 123873bcb24dSRutuja Shah NANOSECONDS_PER_SECOND, tb_env->decr_freq); 123953018216SPaolo Bonzini if (is_excp) 124053018216SPaolo Bonzini next += tb_env->decr_next - now; 124153018216SPaolo Bonzini if (next == now) 124253018216SPaolo Bonzini next++; 1243bc72ad67SAlex Bligh timer_mod(tb_env->decr_timer, next); 124453018216SPaolo Bonzini tb_env->decr_next = next; 124553018216SPaolo Bonzini } 124653018216SPaolo Bonzini } 124753018216SPaolo Bonzini 124853018216SPaolo Bonzini static void cpu_4xx_pit_cb (void *opaque) 124953018216SPaolo Bonzini { 125053018216SPaolo Bonzini PowerPCCPU *cpu; 125153018216SPaolo Bonzini CPUPPCState *env; 125253018216SPaolo Bonzini ppc_tb_t *tb_env; 125353018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 125453018216SPaolo Bonzini 125553018216SPaolo Bonzini env = opaque; 1256db70b311SRichard Henderson cpu = env_archcpu(env); 125753018216SPaolo Bonzini tb_env = env->tb_env; 125853018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 125953018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 27; 126053018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { 126153018216SPaolo Bonzini ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); 126253018216SPaolo Bonzini } 126353018216SPaolo Bonzini start_stop_pit(env, tb_env, 1); 126453018216SPaolo Bonzini LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " 126553018216SPaolo Bonzini "%016" PRIx64 "\n", __func__, 126653018216SPaolo Bonzini (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), 126753018216SPaolo Bonzini (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), 126853018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], 126953018216SPaolo Bonzini ppc40x_timer->pit_reload); 127053018216SPaolo Bonzini } 127153018216SPaolo Bonzini 127253018216SPaolo Bonzini /* Watchdog timer */ 127353018216SPaolo Bonzini static void cpu_4xx_wdt_cb (void *opaque) 127453018216SPaolo Bonzini { 127553018216SPaolo Bonzini PowerPCCPU *cpu; 127653018216SPaolo Bonzini CPUPPCState *env; 127753018216SPaolo Bonzini ppc_tb_t *tb_env; 127853018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 127953018216SPaolo Bonzini uint64_t now, next; 128053018216SPaolo Bonzini 128153018216SPaolo Bonzini env = opaque; 1282db70b311SRichard Henderson cpu = env_archcpu(env); 128353018216SPaolo Bonzini tb_env = env->tb_env; 128453018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 1285bc72ad67SAlex Bligh now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 128653018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { 128753018216SPaolo Bonzini case 0: 128853018216SPaolo Bonzini next = 1 << 17; 128953018216SPaolo Bonzini break; 129053018216SPaolo Bonzini case 1: 129153018216SPaolo Bonzini next = 1 << 21; 129253018216SPaolo Bonzini break; 129353018216SPaolo Bonzini case 2: 129453018216SPaolo Bonzini next = 1 << 25; 129553018216SPaolo Bonzini break; 129653018216SPaolo Bonzini case 3: 129753018216SPaolo Bonzini next = 1 << 29; 129853018216SPaolo Bonzini break; 129953018216SPaolo Bonzini default: 130053018216SPaolo Bonzini /* Cannot occur, but makes gcc happy */ 130153018216SPaolo Bonzini return; 130253018216SPaolo Bonzini } 130373bcb24dSRutuja Shah next = now + muldiv64(next, NANOSECONDS_PER_SECOND, tb_env->decr_freq); 130453018216SPaolo Bonzini if (next == now) 130553018216SPaolo Bonzini next++; 130653018216SPaolo Bonzini LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, 130753018216SPaolo Bonzini env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); 130853018216SPaolo Bonzini switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { 130953018216SPaolo Bonzini case 0x0: 131053018216SPaolo Bonzini case 0x1: 1311bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 131253018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 1313a1f7f97bSPeter Maydell env->spr[SPR_40x_TSR] |= 1U << 31; 131453018216SPaolo Bonzini break; 131553018216SPaolo Bonzini case 0x2: 1316bc72ad67SAlex Bligh timer_mod(ppc40x_timer->wdt_timer, next); 131753018216SPaolo Bonzini ppc40x_timer->wdt_next = next; 131853018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= 1 << 30; 131953018216SPaolo Bonzini if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { 132053018216SPaolo Bonzini ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); 132153018216SPaolo Bonzini } 132253018216SPaolo Bonzini break; 132353018216SPaolo Bonzini case 0x3: 132453018216SPaolo Bonzini env->spr[SPR_40x_TSR] &= ~0x30000000; 132553018216SPaolo Bonzini env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; 132653018216SPaolo Bonzini switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { 132753018216SPaolo Bonzini case 0x0: 132853018216SPaolo Bonzini /* No reset */ 132953018216SPaolo Bonzini break; 133053018216SPaolo Bonzini case 0x1: /* Core reset */ 133153018216SPaolo Bonzini ppc40x_core_reset(cpu); 133253018216SPaolo Bonzini break; 133353018216SPaolo Bonzini case 0x2: /* Chip reset */ 133453018216SPaolo Bonzini ppc40x_chip_reset(cpu); 133553018216SPaolo Bonzini break; 133653018216SPaolo Bonzini case 0x3: /* System reset */ 133753018216SPaolo Bonzini ppc40x_system_reset(cpu); 133853018216SPaolo Bonzini break; 133953018216SPaolo Bonzini } 134053018216SPaolo Bonzini } 134153018216SPaolo Bonzini } 134253018216SPaolo Bonzini 134353018216SPaolo Bonzini void store_40x_pit (CPUPPCState *env, target_ulong val) 134453018216SPaolo Bonzini { 134553018216SPaolo Bonzini ppc_tb_t *tb_env; 134653018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 134753018216SPaolo Bonzini 134853018216SPaolo Bonzini tb_env = env->tb_env; 134953018216SPaolo Bonzini ppc40x_timer = tb_env->opaque; 135053018216SPaolo Bonzini LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val); 135153018216SPaolo Bonzini ppc40x_timer->pit_reload = val; 135253018216SPaolo Bonzini start_stop_pit(env, tb_env, 0); 135353018216SPaolo Bonzini } 135453018216SPaolo Bonzini 135553018216SPaolo Bonzini target_ulong load_40x_pit (CPUPPCState *env) 135653018216SPaolo Bonzini { 135753018216SPaolo Bonzini return cpu_ppc_load_decr(env); 135853018216SPaolo Bonzini } 135953018216SPaolo Bonzini 136053018216SPaolo Bonzini static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq) 136153018216SPaolo Bonzini { 136253018216SPaolo Bonzini CPUPPCState *env = opaque; 136353018216SPaolo Bonzini ppc_tb_t *tb_env = env->tb_env; 136453018216SPaolo Bonzini 136553018216SPaolo Bonzini LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__, 136653018216SPaolo Bonzini freq); 136753018216SPaolo Bonzini tb_env->tb_freq = freq; 136853018216SPaolo Bonzini tb_env->decr_freq = freq; 136953018216SPaolo Bonzini /* XXX: we should also update all timers */ 137053018216SPaolo Bonzini } 137153018216SPaolo Bonzini 137253018216SPaolo Bonzini clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, 137353018216SPaolo Bonzini unsigned int decr_excp) 137453018216SPaolo Bonzini { 137553018216SPaolo Bonzini ppc_tb_t *tb_env; 137653018216SPaolo Bonzini ppc40x_timer_t *ppc40x_timer; 137753018216SPaolo Bonzini 137853018216SPaolo Bonzini tb_env = g_malloc0(sizeof(ppc_tb_t)); 137953018216SPaolo Bonzini env->tb_env = tb_env; 138053018216SPaolo Bonzini tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; 138153018216SPaolo Bonzini ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t)); 138253018216SPaolo Bonzini tb_env->tb_freq = freq; 138353018216SPaolo Bonzini tb_env->decr_freq = freq; 138453018216SPaolo Bonzini tb_env->opaque = ppc40x_timer; 138553018216SPaolo Bonzini LOG_TB("%s freq %" PRIu32 "\n", __func__, freq); 138653018216SPaolo Bonzini if (ppc40x_timer != NULL) { 138753018216SPaolo Bonzini /* We use decr timer for PIT */ 1388bc72ad67SAlex Bligh tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env); 138953018216SPaolo Bonzini ppc40x_timer->fit_timer = 1390bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env); 139153018216SPaolo Bonzini ppc40x_timer->wdt_timer = 1392bc72ad67SAlex Bligh timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env); 139353018216SPaolo Bonzini ppc40x_timer->decr_excp = decr_excp; 139453018216SPaolo Bonzini } 139553018216SPaolo Bonzini 139653018216SPaolo Bonzini return &ppc_40x_set_tb_clk; 139753018216SPaolo Bonzini } 139853018216SPaolo Bonzini 139953018216SPaolo Bonzini /*****************************************************************************/ 140053018216SPaolo Bonzini /* Embedded PowerPC Device Control Registers */ 140153018216SPaolo Bonzini typedef struct ppc_dcrn_t ppc_dcrn_t; 140253018216SPaolo Bonzini struct ppc_dcrn_t { 140353018216SPaolo Bonzini dcr_read_cb dcr_read; 140453018216SPaolo Bonzini dcr_write_cb dcr_write; 140553018216SPaolo Bonzini void *opaque; 140653018216SPaolo Bonzini }; 140753018216SPaolo Bonzini 140853018216SPaolo Bonzini /* XXX: on 460, DCR addresses are 32 bits wide, 140953018216SPaolo Bonzini * using DCRIPR to get the 22 upper bits of the DCR address 141053018216SPaolo Bonzini */ 141153018216SPaolo Bonzini #define DCRN_NB 1024 141253018216SPaolo Bonzini struct ppc_dcr_t { 141353018216SPaolo Bonzini ppc_dcrn_t dcrn[DCRN_NB]; 141453018216SPaolo Bonzini int (*read_error)(int dcrn); 141553018216SPaolo Bonzini int (*write_error)(int dcrn); 141653018216SPaolo Bonzini }; 141753018216SPaolo Bonzini 141853018216SPaolo Bonzini int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 141953018216SPaolo Bonzini { 142053018216SPaolo Bonzini ppc_dcrn_t *dcr; 142153018216SPaolo Bonzini 142253018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 142353018216SPaolo Bonzini goto error; 142453018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 142553018216SPaolo Bonzini if (dcr->dcr_read == NULL) 142653018216SPaolo Bonzini goto error; 142753018216SPaolo Bonzini *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); 142853018216SPaolo Bonzini 142953018216SPaolo Bonzini return 0; 143053018216SPaolo Bonzini 143153018216SPaolo Bonzini error: 143253018216SPaolo Bonzini if (dcr_env->read_error != NULL) 143353018216SPaolo Bonzini return (*dcr_env->read_error)(dcrn); 143453018216SPaolo Bonzini 143553018216SPaolo Bonzini return -1; 143653018216SPaolo Bonzini } 143753018216SPaolo Bonzini 143853018216SPaolo Bonzini int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 143953018216SPaolo Bonzini { 144053018216SPaolo Bonzini ppc_dcrn_t *dcr; 144153018216SPaolo Bonzini 144253018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 144353018216SPaolo Bonzini goto error; 144453018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 144553018216SPaolo Bonzini if (dcr->dcr_write == NULL) 144653018216SPaolo Bonzini goto error; 144753018216SPaolo Bonzini (*dcr->dcr_write)(dcr->opaque, dcrn, val); 144853018216SPaolo Bonzini 144953018216SPaolo Bonzini return 0; 145053018216SPaolo Bonzini 145153018216SPaolo Bonzini error: 145253018216SPaolo Bonzini if (dcr_env->write_error != NULL) 145353018216SPaolo Bonzini return (*dcr_env->write_error)(dcrn); 145453018216SPaolo Bonzini 145553018216SPaolo Bonzini return -1; 145653018216SPaolo Bonzini } 145753018216SPaolo Bonzini 145853018216SPaolo Bonzini int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque, 145953018216SPaolo Bonzini dcr_read_cb dcr_read, dcr_write_cb dcr_write) 146053018216SPaolo Bonzini { 146153018216SPaolo Bonzini ppc_dcr_t *dcr_env; 146253018216SPaolo Bonzini ppc_dcrn_t *dcr; 146353018216SPaolo Bonzini 146453018216SPaolo Bonzini dcr_env = env->dcr_env; 146553018216SPaolo Bonzini if (dcr_env == NULL) 146653018216SPaolo Bonzini return -1; 146753018216SPaolo Bonzini if (dcrn < 0 || dcrn >= DCRN_NB) 146853018216SPaolo Bonzini return -1; 146953018216SPaolo Bonzini dcr = &dcr_env->dcrn[dcrn]; 147053018216SPaolo Bonzini if (dcr->opaque != NULL || 147153018216SPaolo Bonzini dcr->dcr_read != NULL || 147253018216SPaolo Bonzini dcr->dcr_write != NULL) 147353018216SPaolo Bonzini return -1; 147453018216SPaolo Bonzini dcr->opaque = opaque; 147553018216SPaolo Bonzini dcr->dcr_read = dcr_read; 147653018216SPaolo Bonzini dcr->dcr_write = dcr_write; 147753018216SPaolo Bonzini 147853018216SPaolo Bonzini return 0; 147953018216SPaolo Bonzini } 148053018216SPaolo Bonzini 148153018216SPaolo Bonzini int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn), 148253018216SPaolo Bonzini int (*write_error)(int dcrn)) 148353018216SPaolo Bonzini { 148453018216SPaolo Bonzini ppc_dcr_t *dcr_env; 148553018216SPaolo Bonzini 148653018216SPaolo Bonzini dcr_env = g_malloc0(sizeof(ppc_dcr_t)); 148753018216SPaolo Bonzini dcr_env->read_error = read_error; 148853018216SPaolo Bonzini dcr_env->write_error = write_error; 148953018216SPaolo Bonzini env->dcr_env = dcr_env; 149053018216SPaolo Bonzini 149153018216SPaolo Bonzini return 0; 149253018216SPaolo Bonzini } 149353018216SPaolo Bonzini 149453018216SPaolo Bonzini /*****************************************************************************/ 1495051e2973SCédric Le Goater 14964a89e204SCédric Le Goater int ppc_cpu_pir(PowerPCCPU *cpu) 14974a89e204SCédric Le Goater { 14984a89e204SCédric Le Goater CPUPPCState *env = &cpu->env; 14994a89e204SCédric Le Goater return env->spr_cb[SPR_PIR].default_value; 15004a89e204SCédric Le Goater } 15014a89e204SCédric Le Goater 1502051e2973SCédric Le Goater PowerPCCPU *ppc_get_vcpu_by_pir(int pir) 1503051e2973SCédric Le Goater { 1504051e2973SCédric Le Goater CPUState *cs; 1505051e2973SCédric Le Goater 1506051e2973SCédric Le Goater CPU_FOREACH(cs) { 1507051e2973SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 1508051e2973SCédric Le Goater 15094a89e204SCédric Le Goater if (ppc_cpu_pir(cpu) == pir) { 1510051e2973SCédric Le Goater return cpu; 1511051e2973SCédric Le Goater } 1512051e2973SCédric Le Goater } 1513051e2973SCédric Le Goater 1514051e2973SCédric Le Goater return NULL; 1515051e2973SCédric Le Goater } 151640177438SGreg Kurz 151740177438SGreg Kurz void ppc_irq_reset(PowerPCCPU *cpu) 151840177438SGreg Kurz { 151940177438SGreg Kurz CPUPPCState *env = &cpu->env; 152040177438SGreg Kurz 152140177438SGreg Kurz env->irq_input_state = 0; 152240177438SGreg Kurz kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); 152340177438SGreg Kurz } 1524