blob: 5ce565d5ec0a658bd10861a6a74520f847e28ae4 [file] [log] [blame]
bellarda541f292004-04-12 20:39:29 +00001/*
j_mayere9df0142007-04-09 22:45:36 +00002 * QEMU generic PowerPC hardware System Emulator
ths5fafdf22007-09-16 21:08:06 +00003 *
j_mayer76a66252007-03-07 08:32:30 +00004 * Copyright (c) 2003-2007 Jocelyn Mayer
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarda541f292004-04-12 20:39:29 +00006 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010024#include "hw/hw.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010025#include "hw/ppc/ppc.h"
Andreas Färber2b927572013-06-16 17:04:21 +020026#include "hw/ppc/ppc_e500.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010027#include "qemu/timer.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010028#include "sysemu/sysemu.h"
Alexey Kardashevskiy0ce470c2014-02-02 01:45:51 +110029#include "sysemu/cpus.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010030#include "hw/timer/m48t59.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010031#include "qemu/log.h"
Alexey Kardashevskiy98a8b522014-05-01 20:37:09 +100032#include "qemu/error-report.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010033#include "hw/loader.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010034#include "sysemu/kvm.h"
Alexander Graffc87e182010-08-30 13:49:15 +020035#include "kvm_ppc.h"
Alexey Kardashevskiy98a8b522014-05-01 20:37:09 +100036#include "trace.h"
bellarda541f292004-04-12 20:39:29 +000037
j_mayere9df0142007-04-09 22:45:36 +000038//#define PPC_DEBUG_IRQ
j_mayer4b6d0a42007-04-24 06:32:00 +000039//#define PPC_DEBUG_TB
j_mayere9df0142007-04-09 22:45:36 +000040
aliguorid12d51d2009-01-15 21:48:06 +000041#ifdef PPC_DEBUG_IRQ
aliguori93fcfe32009-01-15 22:34:14 +000042# define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000043#else
44# define LOG_IRQ(...) do { } while (0)
45#endif
46
47
48#ifdef PPC_DEBUG_TB
aliguori93fcfe32009-01-15 22:34:14 +000049# define LOG_TB(...) qemu_log(__VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000050#else
51# define LOG_TB(...) do { } while (0)
52#endif
53
Alexey Kardashevskiy98a8b522014-05-01 20:37:09 +100054#define NSEC_PER_SEC 1000000000LL
55
Andreas Färbere2684c02012-03-14 01:38:23 +010056static void cpu_ppc_tb_stop (CPUPPCState *env);
57static void cpu_ppc_tb_start (CPUPPCState *env);
j_mayerdbdd2502007-10-14 09:35:30 +000058
Andreas Färber70585812012-12-01 03:55:58 +010059void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
j_mayer47103572007-03-30 09:38:04 +000060{
Andreas Färberd8ed8872013-01-17 22:30:20 +010061 CPUState *cs = CPU(cpu);
Andreas Färber70585812012-12-01 03:55:58 +010062 CPUPPCState *env = &cpu->env;
Alexander Graffc87e182010-08-30 13:49:15 +020063 unsigned int old_pending = env->pending_interrupts;
64
j_mayer47103572007-03-30 09:38:04 +000065 if (level) {
66 env->pending_interrupts |= 1 << n_IRQ;
Andreas Färberc3affe52013-01-18 15:03:43 +010067 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
j_mayer47103572007-03-30 09:38:04 +000068 } else {
69 env->pending_interrupts &= ~(1 << n_IRQ);
Andreas Färberd8ed8872013-01-17 22:30:20 +010070 if (env->pending_interrupts == 0) {
71 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
72 }
j_mayer47103572007-03-30 09:38:04 +000073 }
Alexander Graffc87e182010-08-30 13:49:15 +020074
75 if (old_pending != env->pending_interrupts) {
76#ifdef CONFIG_KVM
Andreas Färber70585812012-12-01 03:55:58 +010077 kvmppc_set_interrupt(cpu, n_IRQ, level);
Alexander Graffc87e182010-08-30 13:49:15 +020078#endif
79 }
80
aliguorid12d51d2009-01-15 21:48:06 +000081 LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
j_mayeraae93662007-11-24 02:56:36 +000082 "req %08x\n", __func__, env, n_IRQ, level,
Andreas Färber259186a2013-01-17 18:51:17 +010083 env->pending_interrupts, CPU(cpu)->interrupt_request);
j_mayer47103572007-03-30 09:38:04 +000084}
85
j_mayere9df0142007-04-09 22:45:36 +000086/* PowerPC 6xx / 7xx internal IRQ controller */
Andreas Färbera0961242012-05-03 02:48:44 +020087static void ppc6xx_set_irq(void *opaque, int pin, int level)
pbrookd537cf62007-04-07 18:14:41 +000088{
Andreas Färbera0961242012-05-03 02:48:44 +020089 PowerPCCPU *cpu = opaque;
90 CPUPPCState *env = &cpu->env;
j_mayere9df0142007-04-09 22:45:36 +000091 int cur_level;
pbrookd537cf62007-04-07 18:14:41 +000092
aliguorid12d51d2009-01-15 21:48:06 +000093 LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
j_mayera4967752007-04-16 07:10:48 +000094 env, pin, level);
j_mayere9df0142007-04-09 22:45:36 +000095 cur_level = (env->irq_input_state >> pin) & 1;
96 /* Don't generate spurious events */
j_mayer24be5ae2007-04-12 21:24:29 +000097 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
Andreas Färber259186a2013-01-17 18:51:17 +010098 CPUState *cs = CPU(cpu);
99
j_mayere9df0142007-04-09 22:45:36 +0000100 switch (pin) {
j_mayerdbdd2502007-10-14 09:35:30 +0000101 case PPC6xx_INPUT_TBEN:
102 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000103 LOG_IRQ("%s: %s the time base\n",
j_mayerdbdd2502007-10-14 09:35:30 +0000104 __func__, level ? "start" : "stop");
j_mayerdbdd2502007-10-14 09:35:30 +0000105 if (level) {
106 cpu_ppc_tb_start(env);
107 } else {
108 cpu_ppc_tb_stop(env);
109 }
j_mayer24be5ae2007-04-12 21:24:29 +0000110 case PPC6xx_INPUT_INT:
111 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000112 LOG_IRQ("%s: set the external IRQ state to %d\n",
j_mayera4967752007-04-16 07:10:48 +0000113 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100114 ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
j_mayere9df0142007-04-09 22:45:36 +0000115 break;
j_mayer24be5ae2007-04-12 21:24:29 +0000116 case PPC6xx_INPUT_SMI:
j_mayere9df0142007-04-09 22:45:36 +0000117 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000118 LOG_IRQ("%s: set the SMI IRQ state to %d\n",
j_mayera4967752007-04-16 07:10:48 +0000119 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100120 ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level);
j_mayere9df0142007-04-09 22:45:36 +0000121 break;
j_mayer24be5ae2007-04-12 21:24:29 +0000122 case PPC6xx_INPUT_MCP:
j_mayere9df0142007-04-09 22:45:36 +0000123 /* Negative edge sensitive */
124 /* XXX: TODO: actual reaction may depends on HID0 status
125 * 603/604/740/750: check HID0[EMCP]
126 */
127 if (cur_level == 1 && level == 0) {
aliguorid12d51d2009-01-15 21:48:06 +0000128 LOG_IRQ("%s: raise machine check state\n",
j_mayera4967752007-04-16 07:10:48 +0000129 __func__);
Andreas Färber70585812012-12-01 03:55:58 +0100130 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
j_mayere9df0142007-04-09 22:45:36 +0000131 }
132 break;
j_mayer24be5ae2007-04-12 21:24:29 +0000133 case PPC6xx_INPUT_CKSTP_IN:
j_mayere9df0142007-04-09 22:45:36 +0000134 /* Level sensitive - active low */
135 /* XXX: TODO: relay the signal to CKSTP_OUT pin */
j_mayere63ecc62007-10-14 08:48:23 +0000136 /* XXX: Note that the only way to restart the CPU is to reset it */
j_mayere9df0142007-04-09 22:45:36 +0000137 if (level) {
aliguorid12d51d2009-01-15 21:48:06 +0000138 LOG_IRQ("%s: stop the CPU\n", __func__);
Andreas Färber259186a2013-01-17 18:51:17 +0100139 cs->halted = 1;
j_mayere9df0142007-04-09 22:45:36 +0000140 }
141 break;
j_mayer24be5ae2007-04-12 21:24:29 +0000142 case PPC6xx_INPUT_HRESET:
j_mayere9df0142007-04-09 22:45:36 +0000143 /* Level sensitive - active low */
144 if (level) {
aliguorid12d51d2009-01-15 21:48:06 +0000145 LOG_IRQ("%s: reset the CPU\n", __func__);
Andreas Färberc3affe52013-01-18 15:03:43 +0100146 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
j_mayere9df0142007-04-09 22:45:36 +0000147 }
148 break;
j_mayer24be5ae2007-04-12 21:24:29 +0000149 case PPC6xx_INPUT_SRESET:
aliguorid12d51d2009-01-15 21:48:06 +0000150 LOG_IRQ("%s: set the RESET IRQ state to %d\n",
j_mayera4967752007-04-16 07:10:48 +0000151 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100152 ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
j_mayere9df0142007-04-09 22:45:36 +0000153 break;
154 default:
155 /* Unknown pin - do nothing */
aliguorid12d51d2009-01-15 21:48:06 +0000156 LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
j_mayere9df0142007-04-09 22:45:36 +0000157 return;
158 }
159 if (level)
160 env->irq_input_state |= 1 << pin;
161 else
162 env->irq_input_state &= ~(1 << pin);
pbrookd537cf62007-04-07 18:14:41 +0000163 }
164}
165
Andreas Färbera0961242012-05-03 02:48:44 +0200166void ppc6xx_irq_init(CPUPPCState *env)
j_mayer47103572007-03-30 09:38:04 +0000167{
Andreas Färbera0961242012-05-03 02:48:44 +0200168 PowerPCCPU *cpu = ppc_env_get_cpu(env);
169
170 env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu,
j_mayer7b62a952007-11-17 02:04:00 +0000171 PPC6xx_INPUT_NB);
j_mayer47103572007-03-30 09:38:04 +0000172}
173
j_mayer00af6852007-10-03 01:05:39 +0000174#if defined(TARGET_PPC64)
j_mayerd0dfae62007-04-16 07:34:39 +0000175/* PowerPC 970 internal IRQ controller */
Andreas Färbera0961242012-05-03 02:48:44 +0200176static void ppc970_set_irq(void *opaque, int pin, int level)
j_mayerd0dfae62007-04-16 07:34:39 +0000177{
Andreas Färbera0961242012-05-03 02:48:44 +0200178 PowerPCCPU *cpu = opaque;
179 CPUPPCState *env = &cpu->env;
j_mayerd0dfae62007-04-16 07:34:39 +0000180 int cur_level;
181
aliguorid12d51d2009-01-15 21:48:06 +0000182 LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
j_mayerd0dfae62007-04-16 07:34:39 +0000183 env, pin, level);
j_mayerd0dfae62007-04-16 07:34:39 +0000184 cur_level = (env->irq_input_state >> pin) & 1;
185 /* Don't generate spurious events */
186 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
Andreas Färber259186a2013-01-17 18:51:17 +0100187 CPUState *cs = CPU(cpu);
188
j_mayerd0dfae62007-04-16 07:34:39 +0000189 switch (pin) {
190 case PPC970_INPUT_INT:
191 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000192 LOG_IRQ("%s: set the external IRQ state to %d\n",
j_mayerd0dfae62007-04-16 07:34:39 +0000193 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100194 ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
j_mayerd0dfae62007-04-16 07:34:39 +0000195 break;
196 case PPC970_INPUT_THINT:
197 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000198 LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
j_mayerd0dfae62007-04-16 07:34:39 +0000199 level);
Andreas Färber70585812012-12-01 03:55:58 +0100200 ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level);
j_mayerd0dfae62007-04-16 07:34:39 +0000201 break;
202 case PPC970_INPUT_MCP:
203 /* Negative edge sensitive */
204 /* XXX: TODO: actual reaction may depends on HID0 status
205 * 603/604/740/750: check HID0[EMCP]
206 */
207 if (cur_level == 1 && level == 0) {
aliguorid12d51d2009-01-15 21:48:06 +0000208 LOG_IRQ("%s: raise machine check state\n",
j_mayerd0dfae62007-04-16 07:34:39 +0000209 __func__);
Andreas Färber70585812012-12-01 03:55:58 +0100210 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1);
j_mayerd0dfae62007-04-16 07:34:39 +0000211 }
212 break;
213 case PPC970_INPUT_CKSTP:
214 /* Level sensitive - active low */
215 /* XXX: TODO: relay the signal to CKSTP_OUT pin */
216 if (level) {
aliguorid12d51d2009-01-15 21:48:06 +0000217 LOG_IRQ("%s: stop the CPU\n", __func__);
Andreas Färber259186a2013-01-17 18:51:17 +0100218 cs->halted = 1;
j_mayerd0dfae62007-04-16 07:34:39 +0000219 } else {
aliguorid12d51d2009-01-15 21:48:06 +0000220 LOG_IRQ("%s: restart the CPU\n", __func__);
Andreas Färber259186a2013-01-17 18:51:17 +0100221 cs->halted = 0;
222 qemu_cpu_kick(cs);
j_mayerd0dfae62007-04-16 07:34:39 +0000223 }
224 break;
225 case PPC970_INPUT_HRESET:
226 /* Level sensitive - active low */
227 if (level) {
Andreas Färberc3affe52013-01-18 15:03:43 +0100228 cpu_interrupt(cs, CPU_INTERRUPT_RESET);
j_mayerd0dfae62007-04-16 07:34:39 +0000229 }
230 break;
231 case PPC970_INPUT_SRESET:
aliguorid12d51d2009-01-15 21:48:06 +0000232 LOG_IRQ("%s: set the RESET IRQ state to %d\n",
j_mayerd0dfae62007-04-16 07:34:39 +0000233 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100234 ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level);
j_mayerd0dfae62007-04-16 07:34:39 +0000235 break;
236 case PPC970_INPUT_TBEN:
aliguorid12d51d2009-01-15 21:48:06 +0000237 LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
j_mayerd0dfae62007-04-16 07:34:39 +0000238 level);
j_mayerd0dfae62007-04-16 07:34:39 +0000239 /* XXX: TODO */
240 break;
241 default:
242 /* Unknown pin - do nothing */
aliguorid12d51d2009-01-15 21:48:06 +0000243 LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
j_mayerd0dfae62007-04-16 07:34:39 +0000244 return;
245 }
246 if (level)
247 env->irq_input_state |= 1 << pin;
248 else
249 env->irq_input_state &= ~(1 << pin);
250 }
251}
252
Andreas Färbera0961242012-05-03 02:48:44 +0200253void ppc970_irq_init(CPUPPCState *env)
j_mayerd0dfae62007-04-16 07:34:39 +0000254{
Andreas Färbera0961242012-05-03 02:48:44 +0200255 PowerPCCPU *cpu = ppc_env_get_cpu(env);
256
257 env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu,
j_mayer7b62a952007-11-17 02:04:00 +0000258 PPC970_INPUT_NB);
j_mayerd0dfae62007-04-16 07:34:39 +0000259}
David Gibson9d52e902011-04-01 15:15:19 +1100260
261/* POWER7 internal IRQ controller */
Andreas Färbera0961242012-05-03 02:48:44 +0200262static void power7_set_irq(void *opaque, int pin, int level)
David Gibson9d52e902011-04-01 15:15:19 +1100263{
Andreas Färbera0961242012-05-03 02:48:44 +0200264 PowerPCCPU *cpu = opaque;
265 CPUPPCState *env = &cpu->env;
David Gibson9d52e902011-04-01 15:15:19 +1100266
267 LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
268 env, pin, level);
David Gibson9d52e902011-04-01 15:15:19 +1100269
270 switch (pin) {
271 case POWER7_INPUT_INT:
272 /* Level sensitive - active high */
273 LOG_IRQ("%s: set the external IRQ state to %d\n",
274 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100275 ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
David Gibson9d52e902011-04-01 15:15:19 +1100276 break;
277 default:
278 /* Unknown pin - do nothing */
279 LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
280 return;
281 }
282 if (level) {
283 env->irq_input_state |= 1 << pin;
284 } else {
285 env->irq_input_state &= ~(1 << pin);
286 }
287}
288
Andreas Färbera0961242012-05-03 02:48:44 +0200289void ppcPOWER7_irq_init(CPUPPCState *env)
David Gibson9d52e902011-04-01 15:15:19 +1100290{
Andreas Färbera0961242012-05-03 02:48:44 +0200291 PowerPCCPU *cpu = ppc_env_get_cpu(env);
292
293 env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu,
David Gibson9d52e902011-04-01 15:15:19 +1100294 POWER7_INPUT_NB);
295}
j_mayer00af6852007-10-03 01:05:39 +0000296#endif /* defined(TARGET_PPC64) */
j_mayerd0dfae62007-04-16 07:34:39 +0000297
j_mayer4e290a02007-10-01 01:27:10 +0000298/* PowerPC 40x internal IRQ controller */
Andreas Färbera0961242012-05-03 02:48:44 +0200299static void ppc40x_set_irq(void *opaque, int pin, int level)
j_mayer24be5ae2007-04-12 21:24:29 +0000300{
Andreas Färbera0961242012-05-03 02:48:44 +0200301 PowerPCCPU *cpu = opaque;
302 CPUPPCState *env = &cpu->env;
j_mayer24be5ae2007-04-12 21:24:29 +0000303 int cur_level;
304
aliguorid12d51d2009-01-15 21:48:06 +0000305 LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
j_mayer8ecc7912007-04-16 20:09:45 +0000306 env, pin, level);
j_mayer24be5ae2007-04-12 21:24:29 +0000307 cur_level = (env->irq_input_state >> pin) & 1;
308 /* Don't generate spurious events */
309 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
Andreas Färber259186a2013-01-17 18:51:17 +0100310 CPUState *cs = CPU(cpu);
311
j_mayer24be5ae2007-04-12 21:24:29 +0000312 switch (pin) {
j_mayer4e290a02007-10-01 01:27:10 +0000313 case PPC40x_INPUT_RESET_SYS:
j_mayer8ecc7912007-04-16 20:09:45 +0000314 if (level) {
aliguorid12d51d2009-01-15 21:48:06 +0000315 LOG_IRQ("%s: reset the PowerPC system\n",
j_mayer8ecc7912007-04-16 20:09:45 +0000316 __func__);
Andreas Färberf3273ba2013-01-18 15:57:51 +0100317 ppc40x_system_reset(cpu);
j_mayer8ecc7912007-04-16 20:09:45 +0000318 }
319 break;
j_mayer4e290a02007-10-01 01:27:10 +0000320 case PPC40x_INPUT_RESET_CHIP:
j_mayer8ecc7912007-04-16 20:09:45 +0000321 if (level) {
aliguorid12d51d2009-01-15 21:48:06 +0000322 LOG_IRQ("%s: reset the PowerPC chip\n", __func__);
Andreas Färberf3273ba2013-01-18 15:57:51 +0100323 ppc40x_chip_reset(cpu);
j_mayer8ecc7912007-04-16 20:09:45 +0000324 }
325 break;
j_mayer4e290a02007-10-01 01:27:10 +0000326 case PPC40x_INPUT_RESET_CORE:
j_mayer24be5ae2007-04-12 21:24:29 +0000327 /* XXX: TODO: update DBSR[MRR] */
328 if (level) {
aliguorid12d51d2009-01-15 21:48:06 +0000329 LOG_IRQ("%s: reset the PowerPC core\n", __func__);
Andreas Färberf3273ba2013-01-18 15:57:51 +0100330 ppc40x_core_reset(cpu);
j_mayer24be5ae2007-04-12 21:24:29 +0000331 }
332 break;
j_mayer4e290a02007-10-01 01:27:10 +0000333 case PPC40x_INPUT_CINT:
j_mayer24be5ae2007-04-12 21:24:29 +0000334 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000335 LOG_IRQ("%s: set the critical IRQ state to %d\n",
j_mayer8ecc7912007-04-16 20:09:45 +0000336 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100337 ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
j_mayer24be5ae2007-04-12 21:24:29 +0000338 break;
j_mayer4e290a02007-10-01 01:27:10 +0000339 case PPC40x_INPUT_INT:
j_mayer24be5ae2007-04-12 21:24:29 +0000340 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000341 LOG_IRQ("%s: set the external IRQ state to %d\n",
j_mayera4967752007-04-16 07:10:48 +0000342 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100343 ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
j_mayer24be5ae2007-04-12 21:24:29 +0000344 break;
j_mayer4e290a02007-10-01 01:27:10 +0000345 case PPC40x_INPUT_HALT:
j_mayer24be5ae2007-04-12 21:24:29 +0000346 /* Level sensitive - active low */
347 if (level) {
aliguorid12d51d2009-01-15 21:48:06 +0000348 LOG_IRQ("%s: stop the CPU\n", __func__);
Andreas Färber259186a2013-01-17 18:51:17 +0100349 cs->halted = 1;
j_mayer24be5ae2007-04-12 21:24:29 +0000350 } else {
aliguorid12d51d2009-01-15 21:48:06 +0000351 LOG_IRQ("%s: restart the CPU\n", __func__);
Andreas Färber259186a2013-01-17 18:51:17 +0100352 cs->halted = 0;
353 qemu_cpu_kick(cs);
j_mayer24be5ae2007-04-12 21:24:29 +0000354 }
355 break;
j_mayer4e290a02007-10-01 01:27:10 +0000356 case PPC40x_INPUT_DEBUG:
j_mayer24be5ae2007-04-12 21:24:29 +0000357 /* Level sensitive - active high */
aliguorid12d51d2009-01-15 21:48:06 +0000358 LOG_IRQ("%s: set the debug pin state to %d\n",
j_mayera4967752007-04-16 07:10:48 +0000359 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100360 ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
j_mayer24be5ae2007-04-12 21:24:29 +0000361 break;
362 default:
363 /* Unknown pin - do nothing */
aliguorid12d51d2009-01-15 21:48:06 +0000364 LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
j_mayer24be5ae2007-04-12 21:24:29 +0000365 return;
366 }
367 if (level)
368 env->irq_input_state |= 1 << pin;
369 else
370 env->irq_input_state &= ~(1 << pin);
371 }
372}
373
Andreas Färbera0961242012-05-03 02:48:44 +0200374void ppc40x_irq_init(CPUPPCState *env)
j_mayer24be5ae2007-04-12 21:24:29 +0000375{
Andreas Färbera0961242012-05-03 02:48:44 +0200376 PowerPCCPU *cpu = ppc_env_get_cpu(env);
377
j_mayer4e290a02007-10-01 01:27:10 +0000378 env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
Andreas Färbera0961242012-05-03 02:48:44 +0200379 cpu, PPC40x_INPUT_NB);
j_mayer24be5ae2007-04-12 21:24:29 +0000380}
381
aurel329fdc60b2009-03-02 16:42:32 +0000382/* PowerPC E500 internal IRQ controller */
Andreas Färbera0961242012-05-03 02:48:44 +0200383static void ppce500_set_irq(void *opaque, int pin, int level)
aurel329fdc60b2009-03-02 16:42:32 +0000384{
Andreas Färbera0961242012-05-03 02:48:44 +0200385 PowerPCCPU *cpu = opaque;
386 CPUPPCState *env = &cpu->env;
aurel329fdc60b2009-03-02 16:42:32 +0000387 int cur_level;
388
389 LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
390 env, pin, level);
391 cur_level = (env->irq_input_state >> pin) & 1;
392 /* Don't generate spurious events */
393 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
394 switch (pin) {
395 case PPCE500_INPUT_MCK:
396 if (level) {
397 LOG_IRQ("%s: reset the PowerPC system\n",
398 __func__);
399 qemu_system_reset_request();
400 }
401 break;
402 case PPCE500_INPUT_RESET_CORE:
403 if (level) {
404 LOG_IRQ("%s: reset the PowerPC core\n", __func__);
Andreas Färber70585812012-12-01 03:55:58 +0100405 ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level);
aurel329fdc60b2009-03-02 16:42:32 +0000406 }
407 break;
408 case PPCE500_INPUT_CINT:
409 /* Level sensitive - active high */
410 LOG_IRQ("%s: set the critical IRQ state to %d\n",
411 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100412 ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level);
aurel329fdc60b2009-03-02 16:42:32 +0000413 break;
414 case PPCE500_INPUT_INT:
415 /* Level sensitive - active high */
416 LOG_IRQ("%s: set the core IRQ state to %d\n",
417 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100418 ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level);
aurel329fdc60b2009-03-02 16:42:32 +0000419 break;
420 case PPCE500_INPUT_DEBUG:
421 /* Level sensitive - active high */
422 LOG_IRQ("%s: set the debug pin state to %d\n",
423 __func__, level);
Andreas Färber70585812012-12-01 03:55:58 +0100424 ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level);
aurel329fdc60b2009-03-02 16:42:32 +0000425 break;
426 default:
427 /* Unknown pin - do nothing */
428 LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
429 return;
430 }
431 if (level)
432 env->irq_input_state |= 1 << pin;
433 else
434 env->irq_input_state &= ~(1 << pin);
435 }
436}
437
Andreas Färbera0961242012-05-03 02:48:44 +0200438void ppce500_irq_init(CPUPPCState *env)
aurel329fdc60b2009-03-02 16:42:32 +0000439{
Andreas Färbera0961242012-05-03 02:48:44 +0200440 PowerPCCPU *cpu = ppc_env_get_cpu(env);
441
aurel329fdc60b2009-03-02 16:42:32 +0000442 env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
Andreas Färbera0961242012-05-03 02:48:44 +0200443 cpu, PPCE500_INPUT_NB);
aurel329fdc60b2009-03-02 16:42:32 +0000444}
Alexander Grafe49798b2013-01-17 11:32:21 +0100445
446/* Enable or Disable the E500 EPR capability */
447void ppce500_set_mpic_proxy(bool enabled)
448{
Andreas Färber182735e2013-05-29 22:29:20 +0200449 CPUState *cs;
Alexander Grafe49798b2013-01-17 11:32:21 +0100450
Andreas Färberbdc44642013-06-24 23:50:24 +0200451 CPU_FOREACH(cs) {
Andreas Färber182735e2013-05-29 22:29:20 +0200452 PowerPCCPU *cpu = POWERPC_CPU(cs);
Alexander Graf5b95b8b2013-01-17 11:54:38 +0100453
Andreas Färber182735e2013-05-29 22:29:20 +0200454 cpu->env.mpic_proxy = enabled;
Alexander Graf5b95b8b2013-01-17 11:54:38 +0100455 if (kvm_enabled()) {
Andreas Färber182735e2013-05-29 22:29:20 +0200456 kvmppc_set_mpic_proxy(cpu, enabled);
Alexander Graf5b95b8b2013-01-17 11:54:38 +0100457 }
Alexander Grafe49798b2013-01-17 11:32:21 +0100458 }
459}
460
bellard9fddaa02004-05-21 12:59:32 +0000461/*****************************************************************************/
j_mayere9df0142007-04-09 22:45:36 +0000462/* PowerPC time base and decrementer emulation */
bellard9fddaa02004-05-21 12:59:32 +0000463
Fabien Chouteauddd10552011-09-13 04:00:32 +0000464uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
bellard9fddaa02004-05-21 12:59:32 +0000465{
466 /* TB time in tb periods */
Juan Quintela6ee093c2009-09-10 03:04:26 +0200467 return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
bellard9fddaa02004-05-21 12:59:32 +0000468}
469
Andreas Färbere2684c02012-03-14 01:38:23 +0100470uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
bellard9fddaa02004-05-21 12:59:32 +0000471{
Anthony Liguoric227f092009-10-01 16:12:16 -0500472 ppc_tb_t *tb_env = env->tb_env;
bellard9fddaa02004-05-21 12:59:32 +0000473 uint64_t tb;
474
Scott Wood90dc8812011-04-29 17:10:23 -0500475 if (kvm_enabled()) {
476 return env->spr[SPR_TBL];
477 }
478
Alex Blighbc72ad62013-08-21 16:03:08 +0100479 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
aliguorid12d51d2009-01-15 21:48:06 +0000480 LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
bellard9fddaa02004-05-21 12:59:32 +0000481
Alexander Grafe3ea6522009-12-21 12:24:17 +0100482 return tb;
bellard9fddaa02004-05-21 12:59:32 +0000483}
484
Andreas Färbere2684c02012-03-14 01:38:23 +0100485static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
bellard9fddaa02004-05-21 12:59:32 +0000486{
Anthony Liguoric227f092009-10-01 16:12:16 -0500487 ppc_tb_t *tb_env = env->tb_env;
bellard9fddaa02004-05-21 12:59:32 +0000488 uint64_t tb;
489
Alex Blighbc72ad62013-08-21 16:03:08 +0100490 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
aliguorid12d51d2009-01-15 21:48:06 +0000491 LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
j_mayer76a66252007-03-07 08:32:30 +0000492
bellard9fddaa02004-05-21 12:59:32 +0000493 return tb >> 32;
494}
495
Andreas Färbere2684c02012-03-14 01:38:23 +0100496uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
j_mayer8a84de22007-09-30 14:44:52 +0000497{
Scott Wood90dc8812011-04-29 17:10:23 -0500498 if (kvm_enabled()) {
499 return env->spr[SPR_TBU];
500 }
501
j_mayer8a84de22007-09-30 14:44:52 +0000502 return _cpu_ppc_load_tbu(env);
503}
504
Anthony Liguoric227f092009-10-01 16:12:16 -0500505static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
Blue Swirl636aa202009-08-16 09:06:54 +0000506 int64_t *tb_offsetp, uint64_t value)
bellard9fddaa02004-05-21 12:59:32 +0000507{
Juan Quintela6ee093c2009-09-10 03:04:26 +0200508 *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec());
aliguorid12d51d2009-01-15 21:48:06 +0000509 LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
j_mayeraae93662007-11-24 02:56:36 +0000510 __func__, value, *tb_offsetp);
bellard9fddaa02004-05-21 12:59:32 +0000511}
512
Andreas Färbere2684c02012-03-14 01:38:23 +0100513void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
bellard9fddaa02004-05-21 12:59:32 +0000514{
Anthony Liguoric227f092009-10-01 16:12:16 -0500515 ppc_tb_t *tb_env = env->tb_env;
j_mayera062e362007-09-30 00:38:38 +0000516 uint64_t tb;
bellard9fddaa02004-05-21 12:59:32 +0000517
Alex Blighbc72ad62013-08-21 16:03:08 +0100518 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
j_mayera062e362007-09-30 00:38:38 +0000519 tb &= 0xFFFFFFFF00000000ULL;
Alex Blighbc72ad62013-08-21 16:03:08 +0100520 cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
j_mayerdbdd2502007-10-14 09:35:30 +0000521 &tb_env->tb_offset, tb | (uint64_t)value);
j_mayera062e362007-09-30 00:38:38 +0000522}
523
Andreas Färbere2684c02012-03-14 01:38:23 +0100524static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
j_mayera062e362007-09-30 00:38:38 +0000525{
Anthony Liguoric227f092009-10-01 16:12:16 -0500526 ppc_tb_t *tb_env = env->tb_env;
j_mayera062e362007-09-30 00:38:38 +0000527 uint64_t tb;
528
Alex Blighbc72ad62013-08-21 16:03:08 +0100529 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
j_mayera062e362007-09-30 00:38:38 +0000530 tb &= 0x00000000FFFFFFFFULL;
Alex Blighbc72ad62013-08-21 16:03:08 +0100531 cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
j_mayerdbdd2502007-10-14 09:35:30 +0000532 &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
j_mayera062e362007-09-30 00:38:38 +0000533}
534
Andreas Färbere2684c02012-03-14 01:38:23 +0100535void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
j_mayer8a84de22007-09-30 14:44:52 +0000536{
537 _cpu_ppc_store_tbu(env, value);
538}
539
Andreas Färbere2684c02012-03-14 01:38:23 +0100540uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
j_mayera062e362007-09-30 00:38:38 +0000541{
Anthony Liguoric227f092009-10-01 16:12:16 -0500542 ppc_tb_t *tb_env = env->tb_env;
j_mayera062e362007-09-30 00:38:38 +0000543 uint64_t tb;
544
Alex Blighbc72ad62013-08-21 16:03:08 +0100545 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
aliguorid12d51d2009-01-15 21:48:06 +0000546 LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
j_mayera062e362007-09-30 00:38:38 +0000547
Aurelien Jarnob711de92009-12-21 13:52:08 +0100548 return tb;
j_mayera062e362007-09-30 00:38:38 +0000549}
550
Andreas Färbere2684c02012-03-14 01:38:23 +0100551uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
j_mayera062e362007-09-30 00:38:38 +0000552{
Anthony Liguoric227f092009-10-01 16:12:16 -0500553 ppc_tb_t *tb_env = env->tb_env;
j_mayera062e362007-09-30 00:38:38 +0000554 uint64_t tb;
555
Alex Blighbc72ad62013-08-21 16:03:08 +0100556 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
aliguorid12d51d2009-01-15 21:48:06 +0000557 LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
j_mayera062e362007-09-30 00:38:38 +0000558
559 return tb >> 32;
560}
561
Andreas Färbere2684c02012-03-14 01:38:23 +0100562void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
j_mayera062e362007-09-30 00:38:38 +0000563{
Anthony Liguoric227f092009-10-01 16:12:16 -0500564 ppc_tb_t *tb_env = env->tb_env;
j_mayera062e362007-09-30 00:38:38 +0000565 uint64_t tb;
566
Alex Blighbc72ad62013-08-21 16:03:08 +0100567 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
j_mayera062e362007-09-30 00:38:38 +0000568 tb &= 0xFFFFFFFF00000000ULL;
Alex Blighbc72ad62013-08-21 16:03:08 +0100569 cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
j_mayerdbdd2502007-10-14 09:35:30 +0000570 &tb_env->atb_offset, tb | (uint64_t)value);
j_mayera062e362007-09-30 00:38:38 +0000571}
572
Andreas Färbere2684c02012-03-14 01:38:23 +0100573void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
j_mayera062e362007-09-30 00:38:38 +0000574{
Anthony Liguoric227f092009-10-01 16:12:16 -0500575 ppc_tb_t *tb_env = env->tb_env;
j_mayera062e362007-09-30 00:38:38 +0000576 uint64_t tb;
577
Alex Blighbc72ad62013-08-21 16:03:08 +0100578 tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
j_mayera062e362007-09-30 00:38:38 +0000579 tb &= 0x00000000FFFFFFFFULL;
Alex Blighbc72ad62013-08-21 16:03:08 +0100580 cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
j_mayerdbdd2502007-10-14 09:35:30 +0000581 &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
582}
583
Andreas Färbere2684c02012-03-14 01:38:23 +0100584static void cpu_ppc_tb_stop (CPUPPCState *env)
j_mayerdbdd2502007-10-14 09:35:30 +0000585{
Anthony Liguoric227f092009-10-01 16:12:16 -0500586 ppc_tb_t *tb_env = env->tb_env;
j_mayerdbdd2502007-10-14 09:35:30 +0000587 uint64_t tb, atb, vmclk;
588
589 /* If the time base is already frozen, do nothing */
590 if (tb_env->tb_freq != 0) {
Alex Blighbc72ad62013-08-21 16:03:08 +0100591 vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
j_mayerdbdd2502007-10-14 09:35:30 +0000592 /* Get the time base */
593 tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
594 /* Get the alternate time base */
595 atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
596 /* Store the time base value (ie compute the current offset) */
597 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
598 /* Store the alternate time base value (compute the current offset) */
599 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
600 /* Set the time base frequency to zero */
601 tb_env->tb_freq = 0;
602 /* Now, the time bases are frozen to tb_offset / atb_offset value */
603 }
604}
605
Andreas Färbere2684c02012-03-14 01:38:23 +0100606static void cpu_ppc_tb_start (CPUPPCState *env)
j_mayerdbdd2502007-10-14 09:35:30 +0000607{
Anthony Liguoric227f092009-10-01 16:12:16 -0500608 ppc_tb_t *tb_env = env->tb_env;
j_mayerdbdd2502007-10-14 09:35:30 +0000609 uint64_t tb, atb, vmclk;
j_mayeraae93662007-11-24 02:56:36 +0000610
j_mayerdbdd2502007-10-14 09:35:30 +0000611 /* If the time base is not frozen, do nothing */
612 if (tb_env->tb_freq == 0) {
Alex Blighbc72ad62013-08-21 16:03:08 +0100613 vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
j_mayerdbdd2502007-10-14 09:35:30 +0000614 /* Get the time base from tb_offset */
615 tb = tb_env->tb_offset;
616 /* Get the alternate time base from atb_offset */
617 atb = tb_env->atb_offset;
618 /* Restore the tb frequency from the decrementer frequency */
619 tb_env->tb_freq = tb_env->decr_freq;
620 /* Store the time base value */
621 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
622 /* Store the alternate time base value */
623 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
624 }
bellard9fddaa02004-05-21 12:59:32 +0000625}
626
Alexander Grafe81a9822014-04-06 01:32:06 +0200627bool ppc_decr_clear_on_delivery(CPUPPCState *env)
628{
629 ppc_tb_t *tb_env = env->tb_env;
630 int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
631 return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
632}
633
Andreas Färbere2684c02012-03-14 01:38:23 +0100634static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
bellard9fddaa02004-05-21 12:59:32 +0000635{
Anthony Liguoric227f092009-10-01 16:12:16 -0500636 ppc_tb_t *tb_env = env->tb_env;
bellard9fddaa02004-05-21 12:59:32 +0000637 uint32_t decr;
bellard4e588a42005-07-07 21:46:29 +0000638 int64_t diff;
bellard9fddaa02004-05-21 12:59:32 +0000639
Alex Blighbc72ad62013-08-21 16:03:08 +0100640 diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
Fabien Chouteauddd10552011-09-13 04:00:32 +0000641 if (diff >= 0) {
Juan Quintela6ee093c2009-09-10 03:04:26 +0200642 decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
Fabien Chouteauddd10552011-09-13 04:00:32 +0000643 } else if (tb_env->flags & PPC_TIMER_BOOKE) {
644 decr = 0;
645 } else {
Juan Quintela6ee093c2009-09-10 03:04:26 +0200646 decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
Fabien Chouteauddd10552011-09-13 04:00:32 +0000647 }
aliguorid12d51d2009-01-15 21:48:06 +0000648 LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
j_mayer76a66252007-03-07 08:32:30 +0000649
bellard9fddaa02004-05-21 12:59:32 +0000650 return decr;
651}
652
Andreas Färbere2684c02012-03-14 01:38:23 +0100653uint32_t cpu_ppc_load_decr (CPUPPCState *env)
j_mayer58a7d322007-09-29 13:21:37 +0000654{
Anthony Liguoric227f092009-10-01 16:12:16 -0500655 ppc_tb_t *tb_env = env->tb_env;
j_mayer58a7d322007-09-29 13:21:37 +0000656
Scott Wood90dc8812011-04-29 17:10:23 -0500657 if (kvm_enabled()) {
658 return env->spr[SPR_DECR];
659 }
660
Tristan Gingoldf55e9d92009-04-27 10:55:47 +0200661 return _cpu_ppc_load_decr(env, tb_env->decr_next);
j_mayer58a7d322007-09-29 13:21:37 +0000662}
663
Andreas Färbere2684c02012-03-14 01:38:23 +0100664uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
j_mayer58a7d322007-09-29 13:21:37 +0000665{
Anthony Liguoric227f092009-10-01 16:12:16 -0500666 ppc_tb_t *tb_env = env->tb_env;
j_mayer58a7d322007-09-29 13:21:37 +0000667
Tristan Gingoldf55e9d92009-04-27 10:55:47 +0200668 return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
j_mayer58a7d322007-09-29 13:21:37 +0000669}
670
Andreas Färbere2684c02012-03-14 01:38:23 +0100671uint64_t cpu_ppc_load_purr (CPUPPCState *env)
j_mayer58a7d322007-09-29 13:21:37 +0000672{
Anthony Liguoric227f092009-10-01 16:12:16 -0500673 ppc_tb_t *tb_env = env->tb_env;
j_mayer58a7d322007-09-29 13:21:37 +0000674 uint64_t diff;
675
Alex Blighbc72ad62013-08-21 16:03:08 +0100676 diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start;
j_mayerb33c17e2007-10-07 17:30:34 +0000677
Juan Quintela6ee093c2009-09-10 03:04:26 +0200678 return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec());
j_mayer58a7d322007-09-29 13:21:37 +0000679}
j_mayer58a7d322007-09-29 13:21:37 +0000680
bellard9fddaa02004-05-21 12:59:32 +0000681/* When decrementer expires,
682 * all we need to do is generate or queue a CPU exception
683 */
Andreas Färber7e0a9242012-12-01 04:18:02 +0100684static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
bellard9fddaa02004-05-21 12:59:32 +0000685{
686 /* Raise it */
aliguorid12d51d2009-01-15 21:48:06 +0000687 LOG_TB("raise decrementer exception\n");
Andreas Färber70585812012-12-01 03:55:58 +0100688 ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
bellard9fddaa02004-05-21 12:59:32 +0000689}
690
Alexander Grafe81a9822014-04-06 01:32:06 +0200691static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
692{
693 ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
694}
695
Andreas Färber7e0a9242012-12-01 04:18:02 +0100696static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
j_mayer58a7d322007-09-29 13:21:37 +0000697{
698 /* Raise it */
aliguorid12d51d2009-01-15 21:48:06 +0000699 LOG_TB("raise decrementer exception\n");
Andreas Färber70585812012-12-01 03:55:58 +0100700 ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
j_mayer58a7d322007-09-29 13:21:37 +0000701}
702
Alexander Grafe81a9822014-04-06 01:32:06 +0200703static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
704{
705 ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
706}
707
Andreas Färber7e0a9242012-12-01 04:18:02 +0100708static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
Stefan Weil1246b252013-12-01 08:49:47 +0100709 QEMUTimer *timer,
Alexander Grafe81a9822014-04-06 01:32:06 +0200710 void (*raise_excp)(void *),
711 void (*lower_excp)(PowerPCCPU *),
712 uint32_t decr, uint32_t value)
bellard9fddaa02004-05-21 12:59:32 +0000713{
Andreas Färber7e0a9242012-12-01 04:18:02 +0100714 CPUPPCState *env = &cpu->env;
Anthony Liguoric227f092009-10-01 16:12:16 -0500715 ppc_tb_t *tb_env = env->tb_env;
bellard9fddaa02004-05-21 12:59:32 +0000716 uint64_t now, next;
717
aliguorid12d51d2009-01-15 21:48:06 +0000718 LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
j_mayeraae93662007-11-24 02:56:36 +0000719 decr, value);
David Gibson55f7d4b2011-10-16 19:26:17 +0000720
721 if (kvm_enabled()) {
722 /* KVM handles decrementer exceptions, we don't need our own timer */
723 return;
724 }
725
Alexander Grafe81a9822014-04-06 01:32:06 +0200726 /*
727 * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC
728 * interrupt.
729 *
730 * If we get a really small DEC value, we can assume that by the time we
731 * handled it we should inject an interrupt already.
732 *
733 * On MSB level based DEC implementations the MSB always means the interrupt
734 * is pending, so raise it on those.
735 *
736 * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
737 * an edge interrupt, so raise it here too.
738 */
739 if ((value < 3) ||
740 ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
741 ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
742 && !(decr & 0x80000000))) {
743 (*raise_excp)(cpu);
744 return;
745 }
746
747 /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
748 if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
749 (*lower_excp)(cpu);
750 }
751
752 /* Calculate the next timer event */
Alex Blighbc72ad62013-08-21 16:03:08 +0100753 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
Juan Quintela6ee093c2009-09-10 03:04:26 +0200754 next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
j_mayer58a7d322007-09-29 13:21:37 +0000755 *nextp = next;
Alexander Grafe81a9822014-04-06 01:32:06 +0200756
bellard9fddaa02004-05-21 12:59:32 +0000757 /* Adjust timer */
Alex Blighbc72ad62013-08-21 16:03:08 +0100758 timer_mod(timer, next);
j_mayer58a7d322007-09-29 13:21:37 +0000759}
760
Andreas Färber7e0a9242012-12-01 04:18:02 +0100761static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
Alexander Grafe81a9822014-04-06 01:32:06 +0200762 uint32_t value)
j_mayer58a7d322007-09-29 13:21:37 +0000763{
Andreas Färber7e0a9242012-12-01 04:18:02 +0100764 ppc_tb_t *tb_env = cpu->env.tb_env;
j_mayer58a7d322007-09-29 13:21:37 +0000765
Andreas Färber7e0a9242012-12-01 04:18:02 +0100766 __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
Alexander Grafe81a9822014-04-06 01:32:06 +0200767 tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
768 value);
bellard9fddaa02004-05-21 12:59:32 +0000769}
770
Andreas Färbere2684c02012-03-14 01:38:23 +0100771void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
bellard9fddaa02004-05-21 12:59:32 +0000772{
Andreas Färber7e0a9242012-12-01 04:18:02 +0100773 PowerPCCPU *cpu = ppc_env_get_cpu(env);
774
Alexander Grafe81a9822014-04-06 01:32:06 +0200775 _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
bellard9fddaa02004-05-21 12:59:32 +0000776}
777
Andreas Färber50c680f2012-12-01 04:26:55 +0100778static void cpu_ppc_decr_cb(void *opaque)
bellard9fddaa02004-05-21 12:59:32 +0000779{
Andreas Färber50c680f2012-12-01 04:26:55 +0100780 PowerPCCPU *cpu = opaque;
Andreas Färber7e0a9242012-12-01 04:18:02 +0100781
Alexander Grafe81a9822014-04-06 01:32:06 +0200782 cpu_ppc_decr_excp(cpu);
bellard9fddaa02004-05-21 12:59:32 +0000783}
784
Andreas Färber7e0a9242012-12-01 04:18:02 +0100785static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
Alexander Grafe81a9822014-04-06 01:32:06 +0200786 uint32_t value)
j_mayer58a7d322007-09-29 13:21:37 +0000787{
Andreas Färber7e0a9242012-12-01 04:18:02 +0100788 ppc_tb_t *tb_env = cpu->env.tb_env;
j_mayer58a7d322007-09-29 13:21:37 +0000789
j_mayerb172c562007-11-17 01:37:44 +0000790 if (tb_env->hdecr_timer != NULL) {
Andreas Färber7e0a9242012-12-01 04:18:02 +0100791 __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
Alexander Grafe81a9822014-04-06 01:32:06 +0200792 tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
793 hdecr, value);
j_mayerb172c562007-11-17 01:37:44 +0000794 }
j_mayer58a7d322007-09-29 13:21:37 +0000795}
796
Andreas Färbere2684c02012-03-14 01:38:23 +0100797void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
j_mayer58a7d322007-09-29 13:21:37 +0000798{
Andreas Färber7e0a9242012-12-01 04:18:02 +0100799 PowerPCCPU *cpu = ppc_env_get_cpu(env);
800
Alexander Grafe81a9822014-04-06 01:32:06 +0200801 _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
j_mayer58a7d322007-09-29 13:21:37 +0000802}
803
Andreas Färber50c680f2012-12-01 04:26:55 +0100804static void cpu_ppc_hdecr_cb(void *opaque)
j_mayer58a7d322007-09-29 13:21:37 +0000805{
Andreas Färber50c680f2012-12-01 04:26:55 +0100806 PowerPCCPU *cpu = opaque;
Andreas Färber7e0a9242012-12-01 04:18:02 +0100807
Alexander Grafe81a9822014-04-06 01:32:06 +0200808 cpu_ppc_hdecr_excp(cpu);
j_mayer58a7d322007-09-29 13:21:37 +0000809}
810
Andreas Färber7e0a9242012-12-01 04:18:02 +0100811static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
j_mayer58a7d322007-09-29 13:21:37 +0000812{
Andreas Färber7e0a9242012-12-01 04:18:02 +0100813 ppc_tb_t *tb_env = cpu->env.tb_env;
j_mayer58a7d322007-09-29 13:21:37 +0000814
815 tb_env->purr_load = value;
Alex Blighbc72ad62013-08-21 16:03:08 +0100816 tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
j_mayer58a7d322007-09-29 13:21:37 +0000817}
j_mayer58a7d322007-09-29 13:21:37 +0000818
j_mayer8ecc7912007-04-16 20:09:45 +0000819static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
820{
Andreas Färbere2684c02012-03-14 01:38:23 +0100821 CPUPPCState *env = opaque;
Andreas Färber7e0a9242012-12-01 04:18:02 +0100822 PowerPCCPU *cpu = ppc_env_get_cpu(env);
Anthony Liguoric227f092009-10-01 16:12:16 -0500823 ppc_tb_t *tb_env = env->tb_env;
j_mayer8ecc7912007-04-16 20:09:45 +0000824
825 tb_env->tb_freq = freq;
j_mayerdbdd2502007-10-14 09:35:30 +0000826 tb_env->decr_freq = freq;
j_mayer8ecc7912007-04-16 20:09:45 +0000827 /* There is a bug in Linux 2.4 kernels:
828 * if a decrementer exception is pending when it enables msr_ee at startup,
829 * it's not ready to handle it...
830 */
Alexander Grafe81a9822014-04-06 01:32:06 +0200831 _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
832 _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
Andreas Färber7e0a9242012-12-01 04:18:02 +0100833 cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
j_mayer8ecc7912007-04-16 20:09:45 +0000834}
835
Alexey Kardashevskiy98a8b522014-05-01 20:37:09 +1000836static void timebase_pre_save(void *opaque)
837{
838 PPCTimebase *tb = opaque;
839 uint64_t ticks = cpu_get_real_ticks();
840 PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
841
842 if (!first_ppc_cpu->env.tb_env) {
843 error_report("No timebase object");
844 return;
845 }
846
Paolo Bonzini77bad152014-11-26 15:01:01 +0100847 tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
Alexey Kardashevskiy98a8b522014-05-01 20:37:09 +1000848 /*
849 * tb_offset is only expected to be changed by migration so
850 * there is no need to update it from KVM here
851 */
852 tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
853}
854
855static int timebase_post_load(void *opaque, int version_id)
856{
857 PPCTimebase *tb_remote = opaque;
858 CPUState *cpu;
859 PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
860 int64_t tb_off_adj, tb_off, ns_diff;
861 int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns;
862 unsigned long freq;
863
864 if (!first_ppc_cpu->env.tb_env) {
865 error_report("No timebase object");
866 return -1;
867 }
868
869 freq = first_ppc_cpu->env.tb_env->tb_freq;
870 /*
871 * Calculate timebase on the destination side of migration.
872 * The destination timebase must be not less than the source timebase.
873 * We try to adjust timebase by downtime if host clocks are not
874 * too much out of sync (1 second for now).
875 */
Paolo Bonzini77bad152014-11-26 15:01:01 +0100876 host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
Alexey Kardashevskiy98a8b522014-05-01 20:37:09 +1000877 ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns);
878 migration_duration_ns = MIN(NSEC_PER_SEC, ns_diff);
879 migration_duration_tb = muldiv64(migration_duration_ns, freq, NSEC_PER_SEC);
880 guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb);
881
882 tb_off_adj = guest_tb - cpu_get_real_ticks();
883
884 tb_off = first_ppc_cpu->env.tb_env->tb_offset;
885 trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
886 (tb_off_adj - tb_off) / freq);
887
888 /* Set new offset to all CPUs */
889 CPU_FOREACH(cpu) {
890 PowerPCCPU *pcpu = POWERPC_CPU(cpu);
891 pcpu->env.tb_env->tb_offset = tb_off_adj;
892 }
893
894 return 0;
895}
896
897const VMStateDescription vmstate_ppc_timebase = {
898 .name = "timebase",
899 .version_id = 1,
900 .minimum_version_id = 1,
901 .minimum_version_id_old = 1,
902 .pre_save = timebase_pre_save,
903 .post_load = timebase_post_load,
904 .fields = (VMStateField []) {
905 VMSTATE_UINT64(guest_timebase, PPCTimebase),
906 VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
907 VMSTATE_END_OF_LIST()
908 },
909};
910
bellard9fddaa02004-05-21 12:59:32 +0000911/* Set up (once) timebase frequency (in Hz) */
Andreas Färbere2684c02012-03-14 01:38:23 +0100912clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
bellard9fddaa02004-05-21 12:59:32 +0000913{
Andreas Färber50c680f2012-12-01 04:26:55 +0100914 PowerPCCPU *cpu = ppc_env_get_cpu(env);
Anthony Liguoric227f092009-10-01 16:12:16 -0500915 ppc_tb_t *tb_env;
bellard9fddaa02004-05-21 12:59:32 +0000916
Anthony Liguori7267c092011-08-20 22:09:37 -0500917 tb_env = g_malloc0(sizeof(ppc_tb_t));
bellard9fddaa02004-05-21 12:59:32 +0000918 env->tb_env = tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +0000919 tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
Alexander Grafe81a9822014-04-06 01:32:06 +0200920 if (env->insns_flags & PPC_SEGMENT_64B) {
921 /* All Book3S 64bit CPUs implement level based DEC logic */
922 tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
923 }
j_mayer8ecc7912007-04-16 20:09:45 +0000924 /* Create new timer */
Alex Blighbc72ad62013-08-21 16:03:08 +0100925 tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
j_mayerb172c562007-11-17 01:37:44 +0000926 if (0) {
927 /* XXX: find a suitable condition to enable the hypervisor decrementer
928 */
Alex Blighbc72ad62013-08-21 16:03:08 +0100929 tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb,
Andreas Färber50c680f2012-12-01 04:26:55 +0100930 cpu);
j_mayerb172c562007-11-17 01:37:44 +0000931 } else {
932 tb_env->hdecr_timer = NULL;
933 }
j_mayer8ecc7912007-04-16 20:09:45 +0000934 cpu_ppc_set_tb_clk(env, freq);
bellard9fddaa02004-05-21 12:59:32 +0000935
j_mayer8ecc7912007-04-16 20:09:45 +0000936 return &cpu_ppc_set_tb_clk;
bellard9fddaa02004-05-21 12:59:32 +0000937}
938
j_mayer76a66252007-03-07 08:32:30 +0000939/* Specific helpers for POWER & PowerPC 601 RTC */
blueswir1b1d8e522008-10-26 13:43:07 +0000940#if 0
Andreas Färbere2684c02012-03-14 01:38:23 +0100941static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
j_mayer76a66252007-03-07 08:32:30 +0000942{
943 return cpu_ppc_tb_init(env, 7812500);
944}
blueswir1b1d8e522008-10-26 13:43:07 +0000945#endif
j_mayer76a66252007-03-07 08:32:30 +0000946
Andreas Färbere2684c02012-03-14 01:38:23 +0100947void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
j_mayer8a84de22007-09-30 14:44:52 +0000948{
949 _cpu_ppc_store_tbu(env, value);
950}
j_mayer76a66252007-03-07 08:32:30 +0000951
Andreas Färbere2684c02012-03-14 01:38:23 +0100952uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
j_mayer8a84de22007-09-30 14:44:52 +0000953{
954 return _cpu_ppc_load_tbu(env);
955}
j_mayer76a66252007-03-07 08:32:30 +0000956
Andreas Färbere2684c02012-03-14 01:38:23 +0100957void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
j_mayer76a66252007-03-07 08:32:30 +0000958{
959 cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
960}
961
Andreas Färbere2684c02012-03-14 01:38:23 +0100962uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
j_mayer76a66252007-03-07 08:32:30 +0000963{
964 return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
965}
966
j_mayer636aaad2007-03-31 11:38:38 +0000967/*****************************************************************************/
Fabien Chouteauddd10552011-09-13 04:00:32 +0000968/* PowerPC 40x timers */
j_mayer636aaad2007-03-31 11:38:38 +0000969
970/* PIT, FIT & WDT */
Fabien Chouteauddd10552011-09-13 04:00:32 +0000971typedef struct ppc40x_timer_t ppc40x_timer_t;
972struct ppc40x_timer_t {
j_mayer636aaad2007-03-31 11:38:38 +0000973 uint64_t pit_reload; /* PIT auto-reload value */
974 uint64_t fit_next; /* Tick for next FIT interrupt */
Stefan Weil1246b252013-12-01 08:49:47 +0100975 QEMUTimer *fit_timer;
j_mayer636aaad2007-03-31 11:38:38 +0000976 uint64_t wdt_next; /* Tick for next WDT interrupt */
Stefan Weil1246b252013-12-01 08:49:47 +0100977 QEMUTimer *wdt_timer;
Edgar E. Iglesiasd63cb482010-09-20 19:08:42 +0200978
979 /* 405 have the PIT, 440 have a DECR. */
980 unsigned int decr_excp;
j_mayer636aaad2007-03-31 11:38:38 +0000981};
ths3b46e622007-09-17 08:09:54 +0000982
j_mayer636aaad2007-03-31 11:38:38 +0000983/* Fixed interval timer */
984static void cpu_4xx_fit_cb (void *opaque)
j_mayer76a66252007-03-07 08:32:30 +0000985{
Andreas Färber70585812012-12-01 03:55:58 +0100986 PowerPCCPU *cpu;
Andreas Färbere2684c02012-03-14 01:38:23 +0100987 CPUPPCState *env;
Anthony Liguoric227f092009-10-01 16:12:16 -0500988 ppc_tb_t *tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +0000989 ppc40x_timer_t *ppc40x_timer;
j_mayer636aaad2007-03-31 11:38:38 +0000990 uint64_t now, next;
991
992 env = opaque;
Andreas Färber70585812012-12-01 03:55:58 +0100993 cpu = ppc_env_get_cpu(env);
j_mayer636aaad2007-03-31 11:38:38 +0000994 tb_env = env->tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +0000995 ppc40x_timer = tb_env->opaque;
Alex Blighbc72ad62013-08-21 16:03:08 +0100996 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
j_mayer636aaad2007-03-31 11:38:38 +0000997 switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
998 case 0:
999 next = 1 << 9;
1000 break;
1001 case 1:
1002 next = 1 << 13;
1003 break;
1004 case 2:
1005 next = 1 << 17;
1006 break;
1007 case 3:
1008 next = 1 << 21;
1009 break;
1010 default:
1011 /* Cannot occur, but makes gcc happy */
1012 return;
1013 }
Juan Quintela6ee093c2009-09-10 03:04:26 +02001014 next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
j_mayer636aaad2007-03-31 11:38:38 +00001015 if (next == now)
1016 next++;
Alex Blighbc72ad62013-08-21 16:03:08 +01001017 timer_mod(ppc40x_timer->fit_timer, next);
j_mayer636aaad2007-03-31 11:38:38 +00001018 env->spr[SPR_40x_TSR] |= 1 << 26;
Andreas Färber70585812012-12-01 03:55:58 +01001019 if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
1020 ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
1021 }
Blue Swirl90e189e2009-08-16 11:13:18 +00001022 LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
1023 (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
1024 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
j_mayer636aaad2007-03-31 11:38:38 +00001025}
1026
1027/* Programmable interval timer */
Andreas Färbere2684c02012-03-14 01:38:23 +01001028static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
j_mayer636aaad2007-03-31 11:38:38 +00001029{
Fabien Chouteauddd10552011-09-13 04:00:32 +00001030 ppc40x_timer_t *ppc40x_timer;
j_mayer636aaad2007-03-31 11:38:38 +00001031 uint64_t now, next;
1032
Fabien Chouteauddd10552011-09-13 04:00:32 +00001033 ppc40x_timer = tb_env->opaque;
1034 if (ppc40x_timer->pit_reload <= 1 ||
j_mayer4b6d0a42007-04-24 06:32:00 +00001035 !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
1036 (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
1037 /* Stop PIT */
aliguorid12d51d2009-01-15 21:48:06 +00001038 LOG_TB("%s: stop PIT\n", __func__);
Alex Blighbc72ad62013-08-21 16:03:08 +01001039 timer_del(tb_env->decr_timer);
j_mayer4b6d0a42007-04-24 06:32:00 +00001040 } else {
aliguorid12d51d2009-01-15 21:48:06 +00001041 LOG_TB("%s: start PIT %016" PRIx64 "\n",
Fabien Chouteauddd10552011-09-13 04:00:32 +00001042 __func__, ppc40x_timer->pit_reload);
Alex Blighbc72ad62013-08-21 16:03:08 +01001043 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001044 next = now + muldiv64(ppc40x_timer->pit_reload,
Juan Quintela6ee093c2009-09-10 03:04:26 +02001045 get_ticks_per_sec(), tb_env->decr_freq);
j_mayer4b6d0a42007-04-24 06:32:00 +00001046 if (is_excp)
1047 next += tb_env->decr_next - now;
j_mayer636aaad2007-03-31 11:38:38 +00001048 if (next == now)
1049 next++;
Alex Blighbc72ad62013-08-21 16:03:08 +01001050 timer_mod(tb_env->decr_timer, next);
j_mayer636aaad2007-03-31 11:38:38 +00001051 tb_env->decr_next = next;
1052 }
j_mayer4b6d0a42007-04-24 06:32:00 +00001053}
1054
1055static void cpu_4xx_pit_cb (void *opaque)
1056{
Andreas Färber70585812012-12-01 03:55:58 +01001057 PowerPCCPU *cpu;
Andreas Färbere2684c02012-03-14 01:38:23 +01001058 CPUPPCState *env;
Anthony Liguoric227f092009-10-01 16:12:16 -05001059 ppc_tb_t *tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001060 ppc40x_timer_t *ppc40x_timer;
j_mayer4b6d0a42007-04-24 06:32:00 +00001061
1062 env = opaque;
Andreas Färber70585812012-12-01 03:55:58 +01001063 cpu = ppc_env_get_cpu(env);
j_mayer4b6d0a42007-04-24 06:32:00 +00001064 tb_env = env->tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001065 ppc40x_timer = tb_env->opaque;
j_mayer636aaad2007-03-31 11:38:38 +00001066 env->spr[SPR_40x_TSR] |= 1 << 27;
Andreas Färber70585812012-12-01 03:55:58 +01001067 if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) {
1068 ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1);
1069 }
j_mayer4b6d0a42007-04-24 06:32:00 +00001070 start_stop_pit(env, tb_env, 1);
Blue Swirl90e189e2009-08-16 11:13:18 +00001071 LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
1072 "%016" PRIx64 "\n", __func__,
1073 (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
1074 (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
1075 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
Fabien Chouteauddd10552011-09-13 04:00:32 +00001076 ppc40x_timer->pit_reload);
j_mayer636aaad2007-03-31 11:38:38 +00001077}
1078
1079/* Watchdog timer */
1080static void cpu_4xx_wdt_cb (void *opaque)
1081{
Andreas Färber70585812012-12-01 03:55:58 +01001082 PowerPCCPU *cpu;
Andreas Färbere2684c02012-03-14 01:38:23 +01001083 CPUPPCState *env;
Anthony Liguoric227f092009-10-01 16:12:16 -05001084 ppc_tb_t *tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001085 ppc40x_timer_t *ppc40x_timer;
j_mayer636aaad2007-03-31 11:38:38 +00001086 uint64_t now, next;
1087
1088 env = opaque;
Andreas Färber70585812012-12-01 03:55:58 +01001089 cpu = ppc_env_get_cpu(env);
j_mayer636aaad2007-03-31 11:38:38 +00001090 tb_env = env->tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001091 ppc40x_timer = tb_env->opaque;
Alex Blighbc72ad62013-08-21 16:03:08 +01001092 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
j_mayer636aaad2007-03-31 11:38:38 +00001093 switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
1094 case 0:
1095 next = 1 << 17;
1096 break;
1097 case 1:
1098 next = 1 << 21;
1099 break;
1100 case 2:
1101 next = 1 << 25;
1102 break;
1103 case 3:
1104 next = 1 << 29;
1105 break;
1106 default:
1107 /* Cannot occur, but makes gcc happy */
1108 return;
1109 }
Juan Quintela6ee093c2009-09-10 03:04:26 +02001110 next = now + muldiv64(next, get_ticks_per_sec(), tb_env->decr_freq);
j_mayer636aaad2007-03-31 11:38:38 +00001111 if (next == now)
1112 next++;
Blue Swirl90e189e2009-08-16 11:13:18 +00001113 LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
1114 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
j_mayer636aaad2007-03-31 11:38:38 +00001115 switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
1116 case 0x0:
1117 case 0x1:
Alex Blighbc72ad62013-08-21 16:03:08 +01001118 timer_mod(ppc40x_timer->wdt_timer, next);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001119 ppc40x_timer->wdt_next = next;
Peter Maydella1f7f972014-03-17 16:00:37 +00001120 env->spr[SPR_40x_TSR] |= 1U << 31;
j_mayer636aaad2007-03-31 11:38:38 +00001121 break;
1122 case 0x2:
Alex Blighbc72ad62013-08-21 16:03:08 +01001123 timer_mod(ppc40x_timer->wdt_timer, next);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001124 ppc40x_timer->wdt_next = next;
j_mayer636aaad2007-03-31 11:38:38 +00001125 env->spr[SPR_40x_TSR] |= 1 << 30;
Andreas Färber70585812012-12-01 03:55:58 +01001126 if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
1127 ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1);
1128 }
j_mayer636aaad2007-03-31 11:38:38 +00001129 break;
1130 case 0x3:
1131 env->spr[SPR_40x_TSR] &= ~0x30000000;
1132 env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
1133 switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
1134 case 0x0:
1135 /* No reset */
1136 break;
1137 case 0x1: /* Core reset */
Andreas Färberf3273ba2013-01-18 15:57:51 +01001138 ppc40x_core_reset(cpu);
j_mayer8ecc7912007-04-16 20:09:45 +00001139 break;
j_mayer636aaad2007-03-31 11:38:38 +00001140 case 0x2: /* Chip reset */
Andreas Färberf3273ba2013-01-18 15:57:51 +01001141 ppc40x_chip_reset(cpu);
j_mayer8ecc7912007-04-16 20:09:45 +00001142 break;
j_mayer636aaad2007-03-31 11:38:38 +00001143 case 0x3: /* System reset */
Andreas Färberf3273ba2013-01-18 15:57:51 +01001144 ppc40x_system_reset(cpu);
j_mayer8ecc7912007-04-16 20:09:45 +00001145 break;
j_mayer636aaad2007-03-31 11:38:38 +00001146 }
1147 }
j_mayer76a66252007-03-07 08:32:30 +00001148}
1149
Andreas Färbere2684c02012-03-14 01:38:23 +01001150void store_40x_pit (CPUPPCState *env, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00001151{
Anthony Liguoric227f092009-10-01 16:12:16 -05001152 ppc_tb_t *tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001153 ppc40x_timer_t *ppc40x_timer;
j_mayer636aaad2007-03-31 11:38:38 +00001154
1155 tb_env = env->tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001156 ppc40x_timer = tb_env->opaque;
Blue Swirl90e189e2009-08-16 11:13:18 +00001157 LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001158 ppc40x_timer->pit_reload = val;
j_mayer4b6d0a42007-04-24 06:32:00 +00001159 start_stop_pit(env, tb_env, 0);
j_mayer76a66252007-03-07 08:32:30 +00001160}
1161
Andreas Färbere2684c02012-03-14 01:38:23 +01001162target_ulong load_40x_pit (CPUPPCState *env)
j_mayer76a66252007-03-07 08:32:30 +00001163{
j_mayer636aaad2007-03-31 11:38:38 +00001164 return cpu_ppc_load_decr(env);
j_mayer76a66252007-03-07 08:32:30 +00001165}
1166
Fabien Chouteauddd10552011-09-13 04:00:32 +00001167static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
j_mayer4b6d0a42007-04-24 06:32:00 +00001168{
Andreas Färbere2684c02012-03-14 01:38:23 +01001169 CPUPPCState *env = opaque;
Anthony Liguoric227f092009-10-01 16:12:16 -05001170 ppc_tb_t *tb_env = env->tb_env;
j_mayer4b6d0a42007-04-24 06:32:00 +00001171
aliguorid12d51d2009-01-15 21:48:06 +00001172 LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__,
j_mayeraae93662007-11-24 02:56:36 +00001173 freq);
j_mayer4b6d0a42007-04-24 06:32:00 +00001174 tb_env->tb_freq = freq;
j_mayerdbdd2502007-10-14 09:35:30 +00001175 tb_env->decr_freq = freq;
j_mayer4b6d0a42007-04-24 06:32:00 +00001176 /* XXX: we should also update all timers */
1177}
1178
Andreas Färbere2684c02012-03-14 01:38:23 +01001179clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
Edgar E. Iglesiasd63cb482010-09-20 19:08:42 +02001180 unsigned int decr_excp)
j_mayer636aaad2007-03-31 11:38:38 +00001181{
Anthony Liguoric227f092009-10-01 16:12:16 -05001182 ppc_tb_t *tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001183 ppc40x_timer_t *ppc40x_timer;
j_mayer636aaad2007-03-31 11:38:38 +00001184
Anthony Liguori7267c092011-08-20 22:09:37 -05001185 tb_env = g_malloc0(sizeof(ppc_tb_t));
j_mayer8ecc7912007-04-16 20:09:45 +00001186 env->tb_env = tb_env;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001187 tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
1188 ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
j_mayer8ecc7912007-04-16 20:09:45 +00001189 tb_env->tb_freq = freq;
j_mayerdbdd2502007-10-14 09:35:30 +00001190 tb_env->decr_freq = freq;
Fabien Chouteauddd10552011-09-13 04:00:32 +00001191 tb_env->opaque = ppc40x_timer;
aliguorid12d51d2009-01-15 21:48:06 +00001192 LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001193 if (ppc40x_timer != NULL) {
j_mayer636aaad2007-03-31 11:38:38 +00001194 /* We use decr timer for PIT */
Alex Blighbc72ad62013-08-21 16:03:08 +01001195 tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001196 ppc40x_timer->fit_timer =
Alex Blighbc72ad62013-08-21 16:03:08 +01001197 timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001198 ppc40x_timer->wdt_timer =
Alex Blighbc72ad62013-08-21 16:03:08 +01001199 timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env);
Fabien Chouteauddd10552011-09-13 04:00:32 +00001200 ppc40x_timer->decr_excp = decr_excp;
j_mayer636aaad2007-03-31 11:38:38 +00001201 }
j_mayer8ecc7912007-04-16 20:09:45 +00001202
Fabien Chouteauddd10552011-09-13 04:00:32 +00001203 return &ppc_40x_set_tb_clk;
j_mayer76a66252007-03-07 08:32:30 +00001204}
1205
j_mayer2e719ba2007-04-12 21:11:03 +00001206/*****************************************************************************/
1207/* Embedded PowerPC Device Control Registers */
Anthony Liguoric227f092009-10-01 16:12:16 -05001208typedef struct ppc_dcrn_t ppc_dcrn_t;
1209struct ppc_dcrn_t {
j_mayer2e719ba2007-04-12 21:11:03 +00001210 dcr_read_cb dcr_read;
1211 dcr_write_cb dcr_write;
1212 void *opaque;
1213};
1214
j_mayera750fc02007-09-26 23:54:22 +00001215/* XXX: on 460, DCR addresses are 32 bits wide,
1216 * using DCRIPR to get the 22 upper bits of the DCR address
1217 */
j_mayer2e719ba2007-04-12 21:11:03 +00001218#define DCRN_NB 1024
Anthony Liguoric227f092009-10-01 16:12:16 -05001219struct ppc_dcr_t {
1220 ppc_dcrn_t dcrn[DCRN_NB];
j_mayer2e719ba2007-04-12 21:11:03 +00001221 int (*read_error)(int dcrn);
1222 int (*write_error)(int dcrn);
1223};
1224
Alexander Graf73b01962009-12-21 14:02:39 +01001225int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
j_mayer2e719ba2007-04-12 21:11:03 +00001226{
Anthony Liguoric227f092009-10-01 16:12:16 -05001227 ppc_dcrn_t *dcr;
j_mayer2e719ba2007-04-12 21:11:03 +00001228
1229 if (dcrn < 0 || dcrn >= DCRN_NB)
1230 goto error;
1231 dcr = &dcr_env->dcrn[dcrn];
1232 if (dcr->dcr_read == NULL)
1233 goto error;
1234 *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1235
1236 return 0;
1237
1238 error:
1239 if (dcr_env->read_error != NULL)
1240 return (*dcr_env->read_error)(dcrn);
1241
1242 return -1;
1243}
1244
Alexander Graf73b01962009-12-21 14:02:39 +01001245int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
j_mayer2e719ba2007-04-12 21:11:03 +00001246{
Anthony Liguoric227f092009-10-01 16:12:16 -05001247 ppc_dcrn_t *dcr;
j_mayer2e719ba2007-04-12 21:11:03 +00001248
1249 if (dcrn < 0 || dcrn >= DCRN_NB)
1250 goto error;
1251 dcr = &dcr_env->dcrn[dcrn];
1252 if (dcr->dcr_write == NULL)
1253 goto error;
1254 (*dcr->dcr_write)(dcr->opaque, dcrn, val);
1255
1256 return 0;
1257
1258 error:
1259 if (dcr_env->write_error != NULL)
1260 return (*dcr_env->write_error)(dcrn);
1261
1262 return -1;
1263}
1264
Andreas Färbere2684c02012-03-14 01:38:23 +01001265int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
j_mayer2e719ba2007-04-12 21:11:03 +00001266 dcr_read_cb dcr_read, dcr_write_cb dcr_write)
1267{
Anthony Liguoric227f092009-10-01 16:12:16 -05001268 ppc_dcr_t *dcr_env;
1269 ppc_dcrn_t *dcr;
j_mayer2e719ba2007-04-12 21:11:03 +00001270
1271 dcr_env = env->dcr_env;
1272 if (dcr_env == NULL)
1273 return -1;
1274 if (dcrn < 0 || dcrn >= DCRN_NB)
1275 return -1;
1276 dcr = &dcr_env->dcrn[dcrn];
1277 if (dcr->opaque != NULL ||
1278 dcr->dcr_read != NULL ||
1279 dcr->dcr_write != NULL)
1280 return -1;
1281 dcr->opaque = opaque;
1282 dcr->dcr_read = dcr_read;
1283 dcr->dcr_write = dcr_write;
1284
1285 return 0;
1286}
1287
Andreas Färbere2684c02012-03-14 01:38:23 +01001288int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
j_mayer2e719ba2007-04-12 21:11:03 +00001289 int (*write_error)(int dcrn))
1290{
Anthony Liguoric227f092009-10-01 16:12:16 -05001291 ppc_dcr_t *dcr_env;
j_mayer2e719ba2007-04-12 21:11:03 +00001292
Anthony Liguori7267c092011-08-20 22:09:37 -05001293 dcr_env = g_malloc0(sizeof(ppc_dcr_t));
j_mayer2e719ba2007-04-12 21:11:03 +00001294 dcr_env->read_error = read_error;
1295 dcr_env->write_error = write_error;
1296 env->dcr_env = dcr_env;
1297
1298 return 0;
1299}
1300
bellard64201202004-05-26 22:55:16 +00001301/*****************************************************************************/
1302/* Debug port */
bellardfd0bbb12004-06-21 16:53:42 +00001303void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
bellard64201202004-05-26 22:55:16 +00001304{
1305 addr &= 0xF;
1306 switch (addr) {
1307 case 0:
1308 printf("%c", val);
1309 break;
1310 case 1:
1311 printf("\n");
1312 fflush(stdout);
1313 break;
1314 case 2:
j_mayeraae93662007-11-24 02:56:36 +00001315 printf("Set loglevel to %04" PRIx32 "\n", val);
Peter Maydell24537a02013-02-11 16:41:23 +00001316 qemu_set_log(val | 0x100);
bellard64201202004-05-26 22:55:16 +00001317 break;
1318 }
1319}
1320
1321/*****************************************************************************/
1322/* NVRAM helpers */
Anthony Liguoric227f092009-10-01 16:12:16 -05001323static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
bellard64201202004-05-26 22:55:16 +00001324{
Dong Xu Wang3a931132011-11-29 16:52:38 +08001325 return (*nvram->read_fn)(nvram->opaque, addr);
bellard64201202004-05-26 22:55:16 +00001326}
1327
Anthony Liguoric227f092009-10-01 16:12:16 -05001328static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
bellard64201202004-05-26 22:55:16 +00001329{
j_mayer3cbee152007-10-28 23:42:18 +00001330 (*nvram->write_fn)(nvram->opaque, addr, val);
bellard64201202004-05-26 22:55:16 +00001331}
1332
Blue Swirl43448292012-10-28 11:04:49 +00001333static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value)
bellard64201202004-05-26 22:55:16 +00001334{
j_mayer3cbee152007-10-28 23:42:18 +00001335 nvram_write(nvram, addr, value);
bellard64201202004-05-26 22:55:16 +00001336}
1337
Blue Swirl43448292012-10-28 11:04:49 +00001338static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr)
j_mayer3cbee152007-10-28 23:42:18 +00001339{
1340 return nvram_read(nvram, addr);
1341}
1342
Blue Swirl43448292012-10-28 11:04:49 +00001343static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value)
j_mayer3cbee152007-10-28 23:42:18 +00001344{
1345 nvram_write(nvram, addr, value >> 8);
1346 nvram_write(nvram, addr + 1, value & 0xFF);
1347}
1348
Blue Swirl43448292012-10-28 11:04:49 +00001349static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr)
bellard64201202004-05-26 22:55:16 +00001350{
1351 uint16_t tmp;
1352
j_mayer3cbee152007-10-28 23:42:18 +00001353 tmp = nvram_read(nvram, addr) << 8;
1354 tmp |= nvram_read(nvram, addr + 1);
1355
bellard64201202004-05-26 22:55:16 +00001356 return tmp;
1357}
1358
Blue Swirl43448292012-10-28 11:04:49 +00001359static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value)
bellard64201202004-05-26 22:55:16 +00001360{
j_mayer3cbee152007-10-28 23:42:18 +00001361 nvram_write(nvram, addr, value >> 24);
1362 nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
1363 nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
1364 nvram_write(nvram, addr + 3, value & 0xFF);
bellard64201202004-05-26 22:55:16 +00001365}
1366
Anthony Liguoric227f092009-10-01 16:12:16 -05001367uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
bellard64201202004-05-26 22:55:16 +00001368{
1369 uint32_t tmp;
1370
j_mayer3cbee152007-10-28 23:42:18 +00001371 tmp = nvram_read(nvram, addr) << 24;
1372 tmp |= nvram_read(nvram, addr + 1) << 16;
1373 tmp |= nvram_read(nvram, addr + 2) << 8;
1374 tmp |= nvram_read(nvram, addr + 3);
j_mayer76a66252007-03-07 08:32:30 +00001375
bellard64201202004-05-26 22:55:16 +00001376 return tmp;
1377}
1378
Blue Swirl43448292012-10-28 11:04:49 +00001379static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str,
1380 uint32_t max)
bellard64201202004-05-26 22:55:16 +00001381{
1382 int i;
1383
1384 for (i = 0; i < max && str[i] != '\0'; i++) {
j_mayer3cbee152007-10-28 23:42:18 +00001385 nvram_write(nvram, addr + i, str[i]);
bellard64201202004-05-26 22:55:16 +00001386 }
j_mayer3cbee152007-10-28 23:42:18 +00001387 nvram_write(nvram, addr + i, str[i]);
1388 nvram_write(nvram, addr + max - 1, '\0');
bellard64201202004-05-26 22:55:16 +00001389}
1390
Anthony Liguoric227f092009-10-01 16:12:16 -05001391int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
bellard64201202004-05-26 22:55:16 +00001392{
1393 int i;
1394
1395 memset(dst, 0, max);
1396 for (i = 0; i < max; i++) {
1397 dst[i] = NVRAM_get_byte(nvram, addr + i);
1398 if (dst[i] == '\0')
1399 break;
1400 }
1401
1402 return i;
1403}
1404
1405static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1406{
1407 uint16_t tmp;
1408 uint16_t pd, pd1, pd2;
1409
1410 tmp = prev >> 8;
1411 pd = prev ^ value;
1412 pd1 = pd & 0x000F;
1413 pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1414 tmp ^= (pd1 << 3) | (pd1 << 8);
1415 tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1416
1417 return tmp;
1418}
1419
Anthony Liguoric227f092009-10-01 16:12:16 -05001420static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
bellard64201202004-05-26 22:55:16 +00001421{
1422 uint32_t i;
1423 uint16_t crc = 0xFFFF;
1424 int odd;
1425
1426 odd = count & 1;
1427 count &= ~1;
1428 for (i = 0; i != count; i++) {
j_mayer76a66252007-03-07 08:32:30 +00001429 crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
bellard64201202004-05-26 22:55:16 +00001430 }
1431 if (odd) {
j_mayer76a66252007-03-07 08:32:30 +00001432 crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
bellard64201202004-05-26 22:55:16 +00001433 }
1434
1435 return crc;
1436}
1437
bellardfd0bbb12004-06-21 16:53:42 +00001438#define CMDLINE_ADDR 0x017ff000
1439
Anthony Liguoric227f092009-10-01 16:12:16 -05001440int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
blueswir1b55266b2008-09-20 08:07:15 +00001441 const char *arch,
bellard64201202004-05-26 22:55:16 +00001442 uint32_t RAM_size, int boot_device,
1443 uint32_t kernel_image, uint32_t kernel_size,
bellardfd0bbb12004-06-21 16:53:42 +00001444 const char *cmdline,
bellard64201202004-05-26 22:55:16 +00001445 uint32_t initrd_image, uint32_t initrd_size,
bellardfd0bbb12004-06-21 16:53:42 +00001446 uint32_t NVRAM_image,
1447 int width, int height, int depth)
bellard64201202004-05-26 22:55:16 +00001448{
1449 uint16_t crc;
1450
1451 /* Set parameters for Open Hack'Ware BIOS */
1452 NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1453 NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
1454 NVRAM_set_word(nvram, 0x14, NVRAM_size);
1455 NVRAM_set_string(nvram, 0x20, arch, 16);
1456 NVRAM_set_lword(nvram, 0x30, RAM_size);
1457 NVRAM_set_byte(nvram, 0x34, boot_device);
1458 NVRAM_set_lword(nvram, 0x38, kernel_image);
1459 NVRAM_set_lword(nvram, 0x3C, kernel_size);
bellardfd0bbb12004-06-21 16:53:42 +00001460 if (cmdline) {
1461 /* XXX: put the cmdline in NVRAM too ? */
Gerd Hoffmann3c178e72009-10-07 13:37:06 +02001462 pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
bellardfd0bbb12004-06-21 16:53:42 +00001463 NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
1464 NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
1465 } else {
1466 NVRAM_set_lword(nvram, 0x40, 0);
1467 NVRAM_set_lword(nvram, 0x44, 0);
1468 }
bellard64201202004-05-26 22:55:16 +00001469 NVRAM_set_lword(nvram, 0x48, initrd_image);
1470 NVRAM_set_lword(nvram, 0x4C, initrd_size);
1471 NVRAM_set_lword(nvram, 0x50, NVRAM_image);
bellardfd0bbb12004-06-21 16:53:42 +00001472
1473 NVRAM_set_word(nvram, 0x54, width);
1474 NVRAM_set_word(nvram, 0x56, height);
1475 NVRAM_set_word(nvram, 0x58, depth);
1476 crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
j_mayer3cbee152007-10-28 23:42:18 +00001477 NVRAM_set_word(nvram, 0xFC, crc);
bellard64201202004-05-26 22:55:16 +00001478
1479 return 0;
bellarda541f292004-04-12 20:39:29 +00001480}
Alexey Kardashevskiy0ce470c2014-02-02 01:45:51 +11001481
1482/* CPU device-tree ID helpers */
1483int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
1484{
1485 return cpu->cpu_dt_id;
1486}
1487
1488PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
1489{
1490 CPUState *cs;
1491
1492 CPU_FOREACH(cs) {
1493 PowerPCCPU *cpu = POWERPC_CPU(cs);
1494
1495 if (cpu->cpu_dt_id == cpu_dt_id) {
1496 return cpu;
1497 }
1498 }
1499
1500 return NULL;
1501}