Statistics
| Branch: | Revision:

root / hw / ppc.c @ 9bfa659e

History | View | Annotate | Download (38.3 kB)

1 a541f297 bellard
/*
2 e9df014c j_mayer
 * QEMU generic PowerPC hardware System Emulator
3 5fafdf24 ths
 *
4 76a66253 j_mayer
 * Copyright (c) 2003-2007 Jocelyn Mayer
5 5fafdf24 ths
 *
6 a541f297 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 a541f297 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 a541f297 bellard
 * in the Software without restriction, including without limitation the rights
9 a541f297 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 a541f297 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 a541f297 bellard
 * furnished to do so, subject to the following conditions:
12 a541f297 bellard
 *
13 a541f297 bellard
 * The above copyright notice and this permission notice shall be included in
14 a541f297 bellard
 * all copies or substantial portions of the Software.
15 a541f297 bellard
 *
16 a541f297 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 a541f297 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 a541f297 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 a541f297 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 a541f297 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 a541f297 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 a541f297 bellard
 * THE SOFTWARE.
23 a541f297 bellard
 */
24 87ecb68b pbrook
#include "hw.h"
25 87ecb68b pbrook
#include "ppc.h"
26 87ecb68b pbrook
#include "qemu-timer.h"
27 87ecb68b pbrook
#include "sysemu.h"
28 87ecb68b pbrook
#include "nvram.h"
29 3b3fb322 blueswir1
#include "qemu-log.h"
30 ca20cf32 Blue Swirl
#include "loader.h"
31 fc87e185 Alexander Graf
#include "kvm.h"
32 fc87e185 Alexander Graf
#include "kvm_ppc.h"
33 a541f297 bellard
34 e9df014c j_mayer
//#define PPC_DEBUG_IRQ
35 4b6d0a4c j_mayer
//#define PPC_DEBUG_TB
36 e9df014c j_mayer
37 d12d51d5 aliguori
#ifdef PPC_DEBUG_IRQ
38 93fcfe39 aliguori
#  define LOG_IRQ(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
39 d12d51d5 aliguori
#else
40 d12d51d5 aliguori
#  define LOG_IRQ(...) do { } while (0)
41 d12d51d5 aliguori
#endif
42 d12d51d5 aliguori
43 d12d51d5 aliguori
44 d12d51d5 aliguori
#ifdef PPC_DEBUG_TB
45 93fcfe39 aliguori
#  define LOG_TB(...) qemu_log(__VA_ARGS__)
46 d12d51d5 aliguori
#else
47 d12d51d5 aliguori
#  define LOG_TB(...) do { } while (0)
48 d12d51d5 aliguori
#endif
49 d12d51d5 aliguori
50 e2684c0b Andreas Färber
static void cpu_ppc_tb_stop (CPUPPCState *env);
51 e2684c0b Andreas Färber
static void cpu_ppc_tb_start (CPUPPCState *env);
52 dbdd2506 j_mayer
53 e2684c0b Andreas Färber
void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level)
54 47103572 j_mayer
{
55 fc87e185 Alexander Graf
    unsigned int old_pending = env->pending_interrupts;
56 fc87e185 Alexander Graf
57 47103572 j_mayer
    if (level) {
58 47103572 j_mayer
        env->pending_interrupts |= 1 << n_IRQ;
59 47103572 j_mayer
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
60 47103572 j_mayer
    } else {
61 47103572 j_mayer
        env->pending_interrupts &= ~(1 << n_IRQ);
62 47103572 j_mayer
        if (env->pending_interrupts == 0)
63 47103572 j_mayer
            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
64 47103572 j_mayer
    }
65 fc87e185 Alexander Graf
66 fc87e185 Alexander Graf
    if (old_pending != env->pending_interrupts) {
67 fc87e185 Alexander Graf
#ifdef CONFIG_KVM
68 fc87e185 Alexander Graf
        kvmppc_set_interrupt(env, n_IRQ, level);
69 fc87e185 Alexander Graf
#endif
70 fc87e185 Alexander Graf
    }
71 fc87e185 Alexander Graf
72 d12d51d5 aliguori
    LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
73 aae9366a j_mayer
                "req %08x\n", __func__, env, n_IRQ, level,
74 a496775f j_mayer
                env->pending_interrupts, env->interrupt_request);
75 47103572 j_mayer
}
76 47103572 j_mayer
77 e9df014c j_mayer
/* PowerPC 6xx / 7xx internal IRQ controller */
78 e9df014c j_mayer
static void ppc6xx_set_irq (void *opaque, int pin, int level)
79 d537cf6c pbrook
{
80 e2684c0b Andreas Färber
    CPUPPCState *env = opaque;
81 e9df014c j_mayer
    int cur_level;
82 d537cf6c pbrook
83 d12d51d5 aliguori
    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
84 a496775f j_mayer
                env, pin, level);
85 e9df014c j_mayer
    cur_level = (env->irq_input_state >> pin) & 1;
86 e9df014c j_mayer
    /* Don't generate spurious events */
87 24be5ae3 j_mayer
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
88 e9df014c j_mayer
        switch (pin) {
89 dbdd2506 j_mayer
        case PPC6xx_INPUT_TBEN:
90 dbdd2506 j_mayer
            /* Level sensitive - active high */
91 d12d51d5 aliguori
            LOG_IRQ("%s: %s the time base\n",
92 dbdd2506 j_mayer
                        __func__, level ? "start" : "stop");
93 dbdd2506 j_mayer
            if (level) {
94 dbdd2506 j_mayer
                cpu_ppc_tb_start(env);
95 dbdd2506 j_mayer
            } else {
96 dbdd2506 j_mayer
                cpu_ppc_tb_stop(env);
97 dbdd2506 j_mayer
            }
98 24be5ae3 j_mayer
        case PPC6xx_INPUT_INT:
99 24be5ae3 j_mayer
            /* Level sensitive - active high */
100 d12d51d5 aliguori
            LOG_IRQ("%s: set the external IRQ state to %d\n",
101 a496775f j_mayer
                        __func__, level);
102 e9df014c j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
103 e9df014c j_mayer
            break;
104 24be5ae3 j_mayer
        case PPC6xx_INPUT_SMI:
105 e9df014c j_mayer
            /* Level sensitive - active high */
106 d12d51d5 aliguori
            LOG_IRQ("%s: set the SMI IRQ state to %d\n",
107 a496775f j_mayer
                        __func__, level);
108 e9df014c j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
109 e9df014c j_mayer
            break;
110 24be5ae3 j_mayer
        case PPC6xx_INPUT_MCP:
111 e9df014c j_mayer
            /* Negative edge sensitive */
112 e9df014c j_mayer
            /* XXX: TODO: actual reaction may depends on HID0 status
113 e9df014c j_mayer
             *            603/604/740/750: check HID0[EMCP]
114 e9df014c j_mayer
             */
115 e9df014c j_mayer
            if (cur_level == 1 && level == 0) {
116 d12d51d5 aliguori
                LOG_IRQ("%s: raise machine check state\n",
117 a496775f j_mayer
                            __func__);
118 e9df014c j_mayer
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
119 e9df014c j_mayer
            }
120 e9df014c j_mayer
            break;
121 24be5ae3 j_mayer
        case PPC6xx_INPUT_CKSTP_IN:
122 e9df014c j_mayer
            /* Level sensitive - active low */
123 e9df014c j_mayer
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
124 e63ecc6f j_mayer
            /* XXX: Note that the only way to restart the CPU is to reset it */
125 e9df014c j_mayer
            if (level) {
126 d12d51d5 aliguori
                LOG_IRQ("%s: stop the CPU\n", __func__);
127 e9df014c j_mayer
                env->halted = 1;
128 e9df014c j_mayer
            }
129 e9df014c j_mayer
            break;
130 24be5ae3 j_mayer
        case PPC6xx_INPUT_HRESET:
131 e9df014c j_mayer
            /* Level sensitive - active low */
132 e9df014c j_mayer
            if (level) {
133 d12d51d5 aliguori
                LOG_IRQ("%s: reset the CPU\n", __func__);
134 fc0b2c0f Alexander Graf
                cpu_interrupt(env, CPU_INTERRUPT_RESET);
135 e9df014c j_mayer
            }
136 e9df014c j_mayer
            break;
137 24be5ae3 j_mayer
        case PPC6xx_INPUT_SRESET:
138 d12d51d5 aliguori
            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
139 a496775f j_mayer
                        __func__, level);
140 e9df014c j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
141 e9df014c j_mayer
            break;
142 e9df014c j_mayer
        default:
143 e9df014c j_mayer
            /* Unknown pin - do nothing */
144 d12d51d5 aliguori
            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
145 e9df014c j_mayer
            return;
146 e9df014c j_mayer
        }
147 e9df014c j_mayer
        if (level)
148 e9df014c j_mayer
            env->irq_input_state |= 1 << pin;
149 e9df014c j_mayer
        else
150 e9df014c j_mayer
            env->irq_input_state &= ~(1 << pin);
151 d537cf6c pbrook
    }
152 d537cf6c pbrook
}
153 d537cf6c pbrook
154 e2684c0b Andreas Färber
void ppc6xx_irq_init (CPUPPCState *env)
155 47103572 j_mayer
{
156 7b62a955 j_mayer
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env,
157 7b62a955 j_mayer
                                                  PPC6xx_INPUT_NB);
158 47103572 j_mayer
}
159 47103572 j_mayer
160 00af685f j_mayer
#if defined(TARGET_PPC64)
161 d0dfae6e j_mayer
/* PowerPC 970 internal IRQ controller */
162 d0dfae6e j_mayer
static void ppc970_set_irq (void *opaque, int pin, int level)
163 d0dfae6e j_mayer
{
164 e2684c0b Andreas Färber
    CPUPPCState *env = opaque;
165 d0dfae6e j_mayer
    int cur_level;
166 d0dfae6e j_mayer
167 d12d51d5 aliguori
    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
168 d0dfae6e j_mayer
                env, pin, level);
169 d0dfae6e j_mayer
    cur_level = (env->irq_input_state >> pin) & 1;
170 d0dfae6e j_mayer
    /* Don't generate spurious events */
171 d0dfae6e j_mayer
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
172 d0dfae6e j_mayer
        switch (pin) {
173 d0dfae6e j_mayer
        case PPC970_INPUT_INT:
174 d0dfae6e j_mayer
            /* Level sensitive - active high */
175 d12d51d5 aliguori
            LOG_IRQ("%s: set the external IRQ state to %d\n",
176 d0dfae6e j_mayer
                        __func__, level);
177 d0dfae6e j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
178 d0dfae6e j_mayer
            break;
179 d0dfae6e j_mayer
        case PPC970_INPUT_THINT:
180 d0dfae6e j_mayer
            /* Level sensitive - active high */
181 d12d51d5 aliguori
            LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__,
182 d0dfae6e j_mayer
                        level);
183 d0dfae6e j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
184 d0dfae6e j_mayer
            break;
185 d0dfae6e j_mayer
        case PPC970_INPUT_MCP:
186 d0dfae6e j_mayer
            /* Negative edge sensitive */
187 d0dfae6e j_mayer
            /* XXX: TODO: actual reaction may depends on HID0 status
188 d0dfae6e j_mayer
             *            603/604/740/750: check HID0[EMCP]
189 d0dfae6e j_mayer
             */
190 d0dfae6e j_mayer
            if (cur_level == 1 && level == 0) {
191 d12d51d5 aliguori
                LOG_IRQ("%s: raise machine check state\n",
192 d0dfae6e j_mayer
                            __func__);
193 d0dfae6e j_mayer
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
194 d0dfae6e j_mayer
            }
195 d0dfae6e j_mayer
            break;
196 d0dfae6e j_mayer
        case PPC970_INPUT_CKSTP:
197 d0dfae6e j_mayer
            /* Level sensitive - active low */
198 d0dfae6e j_mayer
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
199 d0dfae6e j_mayer
            if (level) {
200 d12d51d5 aliguori
                LOG_IRQ("%s: stop the CPU\n", __func__);
201 d0dfae6e j_mayer
                env->halted = 1;
202 d0dfae6e j_mayer
            } else {
203 d12d51d5 aliguori
                LOG_IRQ("%s: restart the CPU\n", __func__);
204 d0dfae6e j_mayer
                env->halted = 0;
205 94ad5b00 Paolo Bonzini
                qemu_cpu_kick(env);
206 d0dfae6e j_mayer
            }
207 d0dfae6e j_mayer
            break;
208 d0dfae6e j_mayer
        case PPC970_INPUT_HRESET:
209 d0dfae6e j_mayer
            /* Level sensitive - active low */
210 d0dfae6e j_mayer
            if (level) {
211 fc0b2c0f Alexander Graf
                cpu_interrupt(env, CPU_INTERRUPT_RESET);
212 d0dfae6e j_mayer
            }
213 d0dfae6e j_mayer
            break;
214 d0dfae6e j_mayer
        case PPC970_INPUT_SRESET:
215 d12d51d5 aliguori
            LOG_IRQ("%s: set the RESET IRQ state to %d\n",
216 d0dfae6e j_mayer
                        __func__, level);
217 d0dfae6e j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
218 d0dfae6e j_mayer
            break;
219 d0dfae6e j_mayer
        case PPC970_INPUT_TBEN:
220 d12d51d5 aliguori
            LOG_IRQ("%s: set the TBEN state to %d\n", __func__,
221 d0dfae6e j_mayer
                        level);
222 d0dfae6e j_mayer
            /* XXX: TODO */
223 d0dfae6e j_mayer
            break;
224 d0dfae6e j_mayer
        default:
225 d0dfae6e j_mayer
            /* Unknown pin - do nothing */
226 d12d51d5 aliguori
            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
227 d0dfae6e j_mayer
            return;
228 d0dfae6e j_mayer
        }
229 d0dfae6e j_mayer
        if (level)
230 d0dfae6e j_mayer
            env->irq_input_state |= 1 << pin;
231 d0dfae6e j_mayer
        else
232 d0dfae6e j_mayer
            env->irq_input_state &= ~(1 << pin);
233 d0dfae6e j_mayer
    }
234 d0dfae6e j_mayer
}
235 d0dfae6e j_mayer
236 e2684c0b Andreas Färber
void ppc970_irq_init (CPUPPCState *env)
237 d0dfae6e j_mayer
{
238 7b62a955 j_mayer
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
239 7b62a955 j_mayer
                                                  PPC970_INPUT_NB);
240 d0dfae6e j_mayer
}
241 9d52e907 David Gibson
242 9d52e907 David Gibson
/* POWER7 internal IRQ controller */
243 9d52e907 David Gibson
static void power7_set_irq (void *opaque, int pin, int level)
244 9d52e907 David Gibson
{
245 e2684c0b Andreas Färber
    CPUPPCState *env = opaque;
246 9d52e907 David Gibson
247 9d52e907 David Gibson
    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
248 9d52e907 David Gibson
                env, pin, level);
249 9d52e907 David Gibson
250 9d52e907 David Gibson
    switch (pin) {
251 9d52e907 David Gibson
    case POWER7_INPUT_INT:
252 9d52e907 David Gibson
        /* Level sensitive - active high */
253 9d52e907 David Gibson
        LOG_IRQ("%s: set the external IRQ state to %d\n",
254 9d52e907 David Gibson
                __func__, level);
255 9d52e907 David Gibson
        ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
256 9d52e907 David Gibson
        break;
257 9d52e907 David Gibson
    default:
258 9d52e907 David Gibson
        /* Unknown pin - do nothing */
259 9d52e907 David Gibson
        LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
260 9d52e907 David Gibson
        return;
261 9d52e907 David Gibson
    }
262 9d52e907 David Gibson
    if (level) {
263 9d52e907 David Gibson
        env->irq_input_state |= 1 << pin;
264 9d52e907 David Gibson
    } else {
265 9d52e907 David Gibson
        env->irq_input_state &= ~(1 << pin);
266 9d52e907 David Gibson
    }
267 9d52e907 David Gibson
}
268 9d52e907 David Gibson
269 e2684c0b Andreas Färber
void ppcPOWER7_irq_init (CPUPPCState *env)
270 9d52e907 David Gibson
{
271 9d52e907 David Gibson
    env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env,
272 9d52e907 David Gibson
                                                  POWER7_INPUT_NB);
273 9d52e907 David Gibson
}
274 00af685f j_mayer
#endif /* defined(TARGET_PPC64) */
275 d0dfae6e j_mayer
276 4e290a0b j_mayer
/* PowerPC 40x internal IRQ controller */
277 4e290a0b j_mayer
static void ppc40x_set_irq (void *opaque, int pin, int level)
278 24be5ae3 j_mayer
{
279 e2684c0b Andreas Färber
    CPUPPCState *env = opaque;
280 24be5ae3 j_mayer
    int cur_level;
281 24be5ae3 j_mayer
282 d12d51d5 aliguori
    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
283 8ecc7913 j_mayer
                env, pin, level);
284 24be5ae3 j_mayer
    cur_level = (env->irq_input_state >> pin) & 1;
285 24be5ae3 j_mayer
    /* Don't generate spurious events */
286 24be5ae3 j_mayer
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
287 24be5ae3 j_mayer
        switch (pin) {
288 4e290a0b j_mayer
        case PPC40x_INPUT_RESET_SYS:
289 8ecc7913 j_mayer
            if (level) {
290 d12d51d5 aliguori
                LOG_IRQ("%s: reset the PowerPC system\n",
291 8ecc7913 j_mayer
                            __func__);
292 8ecc7913 j_mayer
                ppc40x_system_reset(env);
293 8ecc7913 j_mayer
            }
294 8ecc7913 j_mayer
            break;
295 4e290a0b j_mayer
        case PPC40x_INPUT_RESET_CHIP:
296 8ecc7913 j_mayer
            if (level) {
297 d12d51d5 aliguori
                LOG_IRQ("%s: reset the PowerPC chip\n", __func__);
298 8ecc7913 j_mayer
                ppc40x_chip_reset(env);
299 8ecc7913 j_mayer
            }
300 8ecc7913 j_mayer
            break;
301 4e290a0b j_mayer
        case PPC40x_INPUT_RESET_CORE:
302 24be5ae3 j_mayer
            /* XXX: TODO: update DBSR[MRR] */
303 24be5ae3 j_mayer
            if (level) {
304 d12d51d5 aliguori
                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
305 8ecc7913 j_mayer
                ppc40x_core_reset(env);
306 24be5ae3 j_mayer
            }
307 24be5ae3 j_mayer
            break;
308 4e290a0b j_mayer
        case PPC40x_INPUT_CINT:
309 24be5ae3 j_mayer
            /* Level sensitive - active high */
310 d12d51d5 aliguori
            LOG_IRQ("%s: set the critical IRQ state to %d\n",
311 8ecc7913 j_mayer
                        __func__, level);
312 4e290a0b j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
313 24be5ae3 j_mayer
            break;
314 4e290a0b j_mayer
        case PPC40x_INPUT_INT:
315 24be5ae3 j_mayer
            /* Level sensitive - active high */
316 d12d51d5 aliguori
            LOG_IRQ("%s: set the external IRQ state to %d\n",
317 a496775f j_mayer
                        __func__, level);
318 24be5ae3 j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
319 24be5ae3 j_mayer
            break;
320 4e290a0b j_mayer
        case PPC40x_INPUT_HALT:
321 24be5ae3 j_mayer
            /* Level sensitive - active low */
322 24be5ae3 j_mayer
            if (level) {
323 d12d51d5 aliguori
                LOG_IRQ("%s: stop the CPU\n", __func__);
324 24be5ae3 j_mayer
                env->halted = 1;
325 24be5ae3 j_mayer
            } else {
326 d12d51d5 aliguori
                LOG_IRQ("%s: restart the CPU\n", __func__);
327 24be5ae3 j_mayer
                env->halted = 0;
328 94ad5b00 Paolo Bonzini
                qemu_cpu_kick(env);
329 24be5ae3 j_mayer
            }
330 24be5ae3 j_mayer
            break;
331 4e290a0b j_mayer
        case PPC40x_INPUT_DEBUG:
332 24be5ae3 j_mayer
            /* Level sensitive - active high */
333 d12d51d5 aliguori
            LOG_IRQ("%s: set the debug pin state to %d\n",
334 a496775f j_mayer
                        __func__, level);
335 a750fc0b j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
336 24be5ae3 j_mayer
            break;
337 24be5ae3 j_mayer
        default:
338 24be5ae3 j_mayer
            /* Unknown pin - do nothing */
339 d12d51d5 aliguori
            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
340 24be5ae3 j_mayer
            return;
341 24be5ae3 j_mayer
        }
342 24be5ae3 j_mayer
        if (level)
343 24be5ae3 j_mayer
            env->irq_input_state |= 1 << pin;
344 24be5ae3 j_mayer
        else
345 24be5ae3 j_mayer
            env->irq_input_state &= ~(1 << pin);
346 24be5ae3 j_mayer
    }
347 24be5ae3 j_mayer
}
348 24be5ae3 j_mayer
349 e2684c0b Andreas Färber
void ppc40x_irq_init (CPUPPCState *env)
350 24be5ae3 j_mayer
{
351 4e290a0b j_mayer
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
352 4e290a0b j_mayer
                                                  env, PPC40x_INPUT_NB);
353 24be5ae3 j_mayer
}
354 24be5ae3 j_mayer
355 9fdc60bf aurel32
/* PowerPC E500 internal IRQ controller */
356 9fdc60bf aurel32
static void ppce500_set_irq (void *opaque, int pin, int level)
357 9fdc60bf aurel32
{
358 e2684c0b Andreas Färber
    CPUPPCState *env = opaque;
359 9fdc60bf aurel32
    int cur_level;
360 9fdc60bf aurel32
361 9fdc60bf aurel32
    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
362 9fdc60bf aurel32
                env, pin, level);
363 9fdc60bf aurel32
    cur_level = (env->irq_input_state >> pin) & 1;
364 9fdc60bf aurel32
    /* Don't generate spurious events */
365 9fdc60bf aurel32
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
366 9fdc60bf aurel32
        switch (pin) {
367 9fdc60bf aurel32
        case PPCE500_INPUT_MCK:
368 9fdc60bf aurel32
            if (level) {
369 9fdc60bf aurel32
                LOG_IRQ("%s: reset the PowerPC system\n",
370 9fdc60bf aurel32
                            __func__);
371 9fdc60bf aurel32
                qemu_system_reset_request();
372 9fdc60bf aurel32
            }
373 9fdc60bf aurel32
            break;
374 9fdc60bf aurel32
        case PPCE500_INPUT_RESET_CORE:
375 9fdc60bf aurel32
            if (level) {
376 9fdc60bf aurel32
                LOG_IRQ("%s: reset the PowerPC core\n", __func__);
377 9fdc60bf aurel32
                ppc_set_irq(env, PPC_INTERRUPT_MCK, level);
378 9fdc60bf aurel32
            }
379 9fdc60bf aurel32
            break;
380 9fdc60bf aurel32
        case PPCE500_INPUT_CINT:
381 9fdc60bf aurel32
            /* Level sensitive - active high */
382 9fdc60bf aurel32
            LOG_IRQ("%s: set the critical IRQ state to %d\n",
383 9fdc60bf aurel32
                        __func__, level);
384 9fdc60bf aurel32
            ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
385 9fdc60bf aurel32
            break;
386 9fdc60bf aurel32
        case PPCE500_INPUT_INT:
387 9fdc60bf aurel32
            /* Level sensitive - active high */
388 9fdc60bf aurel32
            LOG_IRQ("%s: set the core IRQ state to %d\n",
389 9fdc60bf aurel32
                        __func__, level);
390 9fdc60bf aurel32
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
391 9fdc60bf aurel32
            break;
392 9fdc60bf aurel32
        case PPCE500_INPUT_DEBUG:
393 9fdc60bf aurel32
            /* Level sensitive - active high */
394 9fdc60bf aurel32
            LOG_IRQ("%s: set the debug pin state to %d\n",
395 9fdc60bf aurel32
                        __func__, level);
396 9fdc60bf aurel32
            ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
397 9fdc60bf aurel32
            break;
398 9fdc60bf aurel32
        default:
399 9fdc60bf aurel32
            /* Unknown pin - do nothing */
400 9fdc60bf aurel32
            LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
401 9fdc60bf aurel32
            return;
402 9fdc60bf aurel32
        }
403 9fdc60bf aurel32
        if (level)
404 9fdc60bf aurel32
            env->irq_input_state |= 1 << pin;
405 9fdc60bf aurel32
        else
406 9fdc60bf aurel32
            env->irq_input_state &= ~(1 << pin);
407 9fdc60bf aurel32
    }
408 9fdc60bf aurel32
}
409 9fdc60bf aurel32
410 e2684c0b Andreas Färber
void ppce500_irq_init (CPUPPCState *env)
411 9fdc60bf aurel32
{
412 9fdc60bf aurel32
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
413 9fdc60bf aurel32
                                        env, PPCE500_INPUT_NB);
414 9fdc60bf aurel32
}
415 9fddaa0c bellard
/*****************************************************************************/
416 e9df014c j_mayer
/* PowerPC time base and decrementer emulation */
417 9fddaa0c bellard
418 ddd1055b Fabien Chouteau
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
419 9fddaa0c bellard
{
420 9fddaa0c bellard
    /* TB time in tb periods */
421 6ee093c9 Juan Quintela
    return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
422 9fddaa0c bellard
}
423 9fddaa0c bellard
424 e2684c0b Andreas Färber
uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
425 9fddaa0c bellard
{
426 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
427 9fddaa0c bellard
    uint64_t tb;
428 9fddaa0c bellard
429 90dc8812 Scott Wood
    if (kvm_enabled()) {
430 90dc8812 Scott Wood
        return env->spr[SPR_TBL];
431 90dc8812 Scott Wood
    }
432 90dc8812 Scott Wood
433 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
434 d12d51d5 aliguori
    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
435 9fddaa0c bellard
436 e3ea6529 Alexander Graf
    return tb;
437 9fddaa0c bellard
}
438 9fddaa0c bellard
439 e2684c0b Andreas Färber
static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
440 9fddaa0c bellard
{
441 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
442 9fddaa0c bellard
    uint64_t tb;
443 9fddaa0c bellard
444 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
445 d12d51d5 aliguori
    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
446 76a66253 j_mayer
447 9fddaa0c bellard
    return tb >> 32;
448 9fddaa0c bellard
}
449 9fddaa0c bellard
450 e2684c0b Andreas Färber
uint32_t cpu_ppc_load_tbu (CPUPPCState *env)
451 8a84de23 j_mayer
{
452 90dc8812 Scott Wood
    if (kvm_enabled()) {
453 90dc8812 Scott Wood
        return env->spr[SPR_TBU];
454 90dc8812 Scott Wood
    }
455 90dc8812 Scott Wood
456 8a84de23 j_mayer
    return _cpu_ppc_load_tbu(env);
457 8a84de23 j_mayer
}
458 8a84de23 j_mayer
459 c227f099 Anthony Liguori
static inline void cpu_ppc_store_tb(ppc_tb_t *tb_env, uint64_t vmclk,
460 636aa200 Blue Swirl
                                    int64_t *tb_offsetp, uint64_t value)
461 9fddaa0c bellard
{
462 6ee093c9 Juan Quintela
    *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec());
463 d12d51d5 aliguori
    LOG_TB("%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
464 aae9366a j_mayer
                __func__, value, *tb_offsetp);
465 9fddaa0c bellard
}
466 9fddaa0c bellard
467 e2684c0b Andreas Färber
void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
468 a062e36c j_mayer
{
469 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
470 a062e36c j_mayer
    uint64_t tb;
471 a062e36c j_mayer
472 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
473 a062e36c j_mayer
    tb &= 0xFFFFFFFF00000000ULL;
474 74475455 Paolo Bonzini
    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
475 dbdd2506 j_mayer
                     &tb_env->tb_offset, tb | (uint64_t)value);
476 a062e36c j_mayer
}
477 a062e36c j_mayer
478 e2684c0b Andreas Färber
static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
479 9fddaa0c bellard
{
480 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
481 a062e36c j_mayer
    uint64_t tb;
482 9fddaa0c bellard
483 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
484 a062e36c j_mayer
    tb &= 0x00000000FFFFFFFFULL;
485 74475455 Paolo Bonzini
    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
486 dbdd2506 j_mayer
                     &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
487 9fddaa0c bellard
}
488 9fddaa0c bellard
489 e2684c0b Andreas Färber
void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value)
490 8a84de23 j_mayer
{
491 8a84de23 j_mayer
    _cpu_ppc_store_tbu(env, value);
492 8a84de23 j_mayer
}
493 8a84de23 j_mayer
494 e2684c0b Andreas Färber
uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
495 a062e36c j_mayer
{
496 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
497 a062e36c j_mayer
    uint64_t tb;
498 a062e36c j_mayer
499 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
500 d12d51d5 aliguori
    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
501 a062e36c j_mayer
502 b711de95 Aurelien Jarno
    return tb;
503 a062e36c j_mayer
}
504 a062e36c j_mayer
505 e2684c0b Andreas Färber
uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
506 a062e36c j_mayer
{
507 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
508 a062e36c j_mayer
    uint64_t tb;
509 a062e36c j_mayer
510 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
511 d12d51d5 aliguori
    LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
512 a062e36c j_mayer
513 a062e36c j_mayer
    return tb >> 32;
514 a062e36c j_mayer
}
515 a062e36c j_mayer
516 e2684c0b Andreas Färber
void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
517 a062e36c j_mayer
{
518 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
519 a062e36c j_mayer
    uint64_t tb;
520 a062e36c j_mayer
521 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
522 a062e36c j_mayer
    tb &= 0xFFFFFFFF00000000ULL;
523 74475455 Paolo Bonzini
    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
524 dbdd2506 j_mayer
                     &tb_env->atb_offset, tb | (uint64_t)value);
525 a062e36c j_mayer
}
526 a062e36c j_mayer
527 e2684c0b Andreas Färber
void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
528 9fddaa0c bellard
{
529 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
530 a062e36c j_mayer
    uint64_t tb;
531 9fddaa0c bellard
532 74475455 Paolo Bonzini
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
533 a062e36c j_mayer
    tb &= 0x00000000FFFFFFFFULL;
534 74475455 Paolo Bonzini
    cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
535 dbdd2506 j_mayer
                     &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
536 dbdd2506 j_mayer
}
537 dbdd2506 j_mayer
538 e2684c0b Andreas Färber
static void cpu_ppc_tb_stop (CPUPPCState *env)
539 dbdd2506 j_mayer
{
540 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
541 dbdd2506 j_mayer
    uint64_t tb, atb, vmclk;
542 dbdd2506 j_mayer
543 dbdd2506 j_mayer
    /* If the time base is already frozen, do nothing */
544 dbdd2506 j_mayer
    if (tb_env->tb_freq != 0) {
545 74475455 Paolo Bonzini
        vmclk = qemu_get_clock_ns(vm_clock);
546 dbdd2506 j_mayer
        /* Get the time base */
547 dbdd2506 j_mayer
        tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
548 dbdd2506 j_mayer
        /* Get the alternate time base */
549 dbdd2506 j_mayer
        atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
550 dbdd2506 j_mayer
        /* Store the time base value (ie compute the current offset) */
551 dbdd2506 j_mayer
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
552 dbdd2506 j_mayer
        /* Store the alternate time base value (compute the current offset) */
553 dbdd2506 j_mayer
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
554 dbdd2506 j_mayer
        /* Set the time base frequency to zero */
555 dbdd2506 j_mayer
        tb_env->tb_freq = 0;
556 dbdd2506 j_mayer
        /* Now, the time bases are frozen to tb_offset / atb_offset value */
557 dbdd2506 j_mayer
    }
558 dbdd2506 j_mayer
}
559 dbdd2506 j_mayer
560 e2684c0b Andreas Färber
static void cpu_ppc_tb_start (CPUPPCState *env)
561 dbdd2506 j_mayer
{
562 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
563 dbdd2506 j_mayer
    uint64_t tb, atb, vmclk;
564 aae9366a j_mayer
565 dbdd2506 j_mayer
    /* If the time base is not frozen, do nothing */
566 dbdd2506 j_mayer
    if (tb_env->tb_freq == 0) {
567 74475455 Paolo Bonzini
        vmclk = qemu_get_clock_ns(vm_clock);
568 dbdd2506 j_mayer
        /* Get the time base from tb_offset */
569 dbdd2506 j_mayer
        tb = tb_env->tb_offset;
570 dbdd2506 j_mayer
        /* Get the alternate time base from atb_offset */
571 dbdd2506 j_mayer
        atb = tb_env->atb_offset;
572 dbdd2506 j_mayer
        /* Restore the tb frequency from the decrementer frequency */
573 dbdd2506 j_mayer
        tb_env->tb_freq = tb_env->decr_freq;
574 dbdd2506 j_mayer
        /* Store the time base value */
575 dbdd2506 j_mayer
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
576 dbdd2506 j_mayer
        /* Store the alternate time base value */
577 dbdd2506 j_mayer
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
578 dbdd2506 j_mayer
    }
579 9fddaa0c bellard
}
580 9fddaa0c bellard
581 e2684c0b Andreas Färber
static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
582 9fddaa0c bellard
{
583 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
584 9fddaa0c bellard
    uint32_t decr;
585 4e588a4d bellard
    int64_t diff;
586 9fddaa0c bellard
587 74475455 Paolo Bonzini
    diff = next - qemu_get_clock_ns(vm_clock);
588 ddd1055b Fabien Chouteau
    if (diff >= 0) {
589 6ee093c9 Juan Quintela
        decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
590 ddd1055b Fabien Chouteau
    } else if (tb_env->flags & PPC_TIMER_BOOKE) {
591 ddd1055b Fabien Chouteau
        decr = 0;
592 ddd1055b Fabien Chouteau
    }  else {
593 6ee093c9 Juan Quintela
        decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
594 ddd1055b Fabien Chouteau
    }
595 d12d51d5 aliguori
    LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
596 76a66253 j_mayer
597 9fddaa0c bellard
    return decr;
598 9fddaa0c bellard
}
599 9fddaa0c bellard
600 e2684c0b Andreas Färber
uint32_t cpu_ppc_load_decr (CPUPPCState *env)
601 58a7d328 j_mayer
{
602 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
603 58a7d328 j_mayer
604 90dc8812 Scott Wood
    if (kvm_enabled()) {
605 90dc8812 Scott Wood
        return env->spr[SPR_DECR];
606 90dc8812 Scott Wood
    }
607 90dc8812 Scott Wood
608 f55e9d9a Tristan Gingold
    return _cpu_ppc_load_decr(env, tb_env->decr_next);
609 58a7d328 j_mayer
}
610 58a7d328 j_mayer
611 e2684c0b Andreas Färber
uint32_t cpu_ppc_load_hdecr (CPUPPCState *env)
612 58a7d328 j_mayer
{
613 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
614 58a7d328 j_mayer
615 f55e9d9a Tristan Gingold
    return _cpu_ppc_load_decr(env, tb_env->hdecr_next);
616 58a7d328 j_mayer
}
617 58a7d328 j_mayer
618 e2684c0b Andreas Färber
uint64_t cpu_ppc_load_purr (CPUPPCState *env)
619 58a7d328 j_mayer
{
620 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
621 58a7d328 j_mayer
    uint64_t diff;
622 58a7d328 j_mayer
623 74475455 Paolo Bonzini
    diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start;
624 b33c17e1 j_mayer
625 6ee093c9 Juan Quintela
    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec());
626 58a7d328 j_mayer
}
627 58a7d328 j_mayer
628 9fddaa0c bellard
/* When decrementer expires,
629 9fddaa0c bellard
 * all we need to do is generate or queue a CPU exception
630 9fddaa0c bellard
 */
631 e2684c0b Andreas Färber
static inline void cpu_ppc_decr_excp(CPUPPCState *env)
632 9fddaa0c bellard
{
633 9fddaa0c bellard
    /* Raise it */
634 d12d51d5 aliguori
    LOG_TB("raise decrementer exception\n");
635 47103572 j_mayer
    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
636 9fddaa0c bellard
}
637 9fddaa0c bellard
638 e2684c0b Andreas Färber
static inline void cpu_ppc_hdecr_excp(CPUPPCState *env)
639 58a7d328 j_mayer
{
640 58a7d328 j_mayer
    /* Raise it */
641 d12d51d5 aliguori
    LOG_TB("raise decrementer exception\n");
642 58a7d328 j_mayer
    ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
643 58a7d328 j_mayer
}
644 58a7d328 j_mayer
645 e2684c0b Andreas Färber
static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp,
646 b33c17e1 j_mayer
                                  struct QEMUTimer *timer,
647 e2684c0b Andreas Färber
                                  void (*raise_excp)(CPUPPCState *),
648 b33c17e1 j_mayer
                                  uint32_t decr, uint32_t value,
649 b33c17e1 j_mayer
                                  int is_excp)
650 9fddaa0c bellard
{
651 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
652 9fddaa0c bellard
    uint64_t now, next;
653 9fddaa0c bellard
654 d12d51d5 aliguori
    LOG_TB("%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
655 aae9366a j_mayer
                decr, value);
656 55f7d4b0 David Gibson
657 55f7d4b0 David Gibson
    if (kvm_enabled()) {
658 55f7d4b0 David Gibson
        /* KVM handles decrementer exceptions, we don't need our own timer */
659 55f7d4b0 David Gibson
        return;
660 55f7d4b0 David Gibson
    }
661 55f7d4b0 David Gibson
662 74475455 Paolo Bonzini
    now = qemu_get_clock_ns(vm_clock);
663 6ee093c9 Juan Quintela
    next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
664 ddd1055b Fabien Chouteau
    if (is_excp) {
665 58a7d328 j_mayer
        next += *nextp - now;
666 ddd1055b Fabien Chouteau
    }
667 ddd1055b Fabien Chouteau
    if (next == now) {
668 76a66253 j_mayer
        next++;
669 ddd1055b Fabien Chouteau
    }
670 58a7d328 j_mayer
    *nextp = next;
671 9fddaa0c bellard
    /* Adjust timer */
672 58a7d328 j_mayer
    qemu_mod_timer(timer, next);
673 ddd1055b Fabien Chouteau
674 ddd1055b Fabien Chouteau
    /* If we set a negative value and the decrementer was positive, raise an
675 ddd1055b Fabien Chouteau
     * exception.
676 9fddaa0c bellard
     */
677 ddd1055b Fabien Chouteau
    if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
678 ddd1055b Fabien Chouteau
        && (value & 0x80000000)
679 ddd1055b Fabien Chouteau
        && !(decr & 0x80000000)) {
680 58a7d328 j_mayer
        (*raise_excp)(env);
681 ddd1055b Fabien Chouteau
    }
682 58a7d328 j_mayer
}
683 58a7d328 j_mayer
684 e2684c0b Andreas Färber
static inline void _cpu_ppc_store_decr(CPUPPCState *env, uint32_t decr,
685 636aa200 Blue Swirl
                                       uint32_t value, int is_excp)
686 58a7d328 j_mayer
{
687 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
688 58a7d328 j_mayer
689 58a7d328 j_mayer
    __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
690 58a7d328 j_mayer
                         &cpu_ppc_decr_excp, decr, value, is_excp);
691 9fddaa0c bellard
}
692 9fddaa0c bellard
693 e2684c0b Andreas Färber
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
694 9fddaa0c bellard
{
695 9fddaa0c bellard
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
696 9fddaa0c bellard
}
697 9fddaa0c bellard
698 9fddaa0c bellard
static void cpu_ppc_decr_cb (void *opaque)
699 9fddaa0c bellard
{
700 9fddaa0c bellard
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
701 9fddaa0c bellard
}
702 9fddaa0c bellard
703 e2684c0b Andreas Färber
static inline void _cpu_ppc_store_hdecr(CPUPPCState *env, uint32_t hdecr,
704 636aa200 Blue Swirl
                                        uint32_t value, int is_excp)
705 58a7d328 j_mayer
{
706 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
707 58a7d328 j_mayer
708 b172c56a j_mayer
    if (tb_env->hdecr_timer != NULL) {
709 b172c56a j_mayer
        __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
710 b172c56a j_mayer
                             &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
711 b172c56a j_mayer
    }
712 58a7d328 j_mayer
}
713 58a7d328 j_mayer
714 e2684c0b Andreas Färber
void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
715 58a7d328 j_mayer
{
716 58a7d328 j_mayer
    _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
717 58a7d328 j_mayer
}
718 58a7d328 j_mayer
719 58a7d328 j_mayer
static void cpu_ppc_hdecr_cb (void *opaque)
720 58a7d328 j_mayer
{
721 58a7d328 j_mayer
    _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
722 58a7d328 j_mayer
}
723 58a7d328 j_mayer
724 e2684c0b Andreas Färber
void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value)
725 58a7d328 j_mayer
{
726 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
727 58a7d328 j_mayer
728 58a7d328 j_mayer
    tb_env->purr_load = value;
729 74475455 Paolo Bonzini
    tb_env->purr_start = qemu_get_clock_ns(vm_clock);
730 58a7d328 j_mayer
}
731 58a7d328 j_mayer
732 8ecc7913 j_mayer
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
733 8ecc7913 j_mayer
{
734 e2684c0b Andreas Färber
    CPUPPCState *env = opaque;
735 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
736 8ecc7913 j_mayer
737 8ecc7913 j_mayer
    tb_env->tb_freq = freq;
738 dbdd2506 j_mayer
    tb_env->decr_freq = freq;
739 8ecc7913 j_mayer
    /* There is a bug in Linux 2.4 kernels:
740 8ecc7913 j_mayer
     * if a decrementer exception is pending when it enables msr_ee at startup,
741 8ecc7913 j_mayer
     * it's not ready to handle it...
742 8ecc7913 j_mayer
     */
743 8ecc7913 j_mayer
    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
744 58a7d328 j_mayer
    _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
745 58a7d328 j_mayer
    cpu_ppc_store_purr(env, 0x0000000000000000ULL);
746 8ecc7913 j_mayer
}
747 8ecc7913 j_mayer
748 9fddaa0c bellard
/* Set up (once) timebase frequency (in Hz) */
749 e2684c0b Andreas Färber
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
750 9fddaa0c bellard
{
751 c227f099 Anthony Liguori
    ppc_tb_t *tb_env;
752 9fddaa0c bellard
753 7267c094 Anthony Liguori
    tb_env = g_malloc0(sizeof(ppc_tb_t));
754 9fddaa0c bellard
    env->tb_env = tb_env;
755 ddd1055b Fabien Chouteau
    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
756 8ecc7913 j_mayer
    /* Create new timer */
757 74475455 Paolo Bonzini
    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, env);
758 b172c56a j_mayer
    if (0) {
759 b172c56a j_mayer
        /* XXX: find a suitable condition to enable the hypervisor decrementer
760 b172c56a j_mayer
         */
761 74475455 Paolo Bonzini
        tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, env);
762 b172c56a j_mayer
    } else {
763 b172c56a j_mayer
        tb_env->hdecr_timer = NULL;
764 b172c56a j_mayer
    }
765 8ecc7913 j_mayer
    cpu_ppc_set_tb_clk(env, freq);
766 9fddaa0c bellard
767 8ecc7913 j_mayer
    return &cpu_ppc_set_tb_clk;
768 9fddaa0c bellard
}
769 9fddaa0c bellard
770 76a66253 j_mayer
/* Specific helpers for POWER & PowerPC 601 RTC */
771 b1d8e52e blueswir1
#if 0
772 e2684c0b Andreas Färber
static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
773 76a66253 j_mayer
{
774 76a66253 j_mayer
    return cpu_ppc_tb_init(env, 7812500);
775 76a66253 j_mayer
}
776 b1d8e52e blueswir1
#endif
777 76a66253 j_mayer
778 e2684c0b Andreas Färber
void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
779 8a84de23 j_mayer
{
780 8a84de23 j_mayer
    _cpu_ppc_store_tbu(env, value);
781 8a84de23 j_mayer
}
782 76a66253 j_mayer
783 e2684c0b Andreas Färber
uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
784 8a84de23 j_mayer
{
785 8a84de23 j_mayer
    return _cpu_ppc_load_tbu(env);
786 8a84de23 j_mayer
}
787 76a66253 j_mayer
788 e2684c0b Andreas Färber
void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
789 76a66253 j_mayer
{
790 76a66253 j_mayer
    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
791 76a66253 j_mayer
}
792 76a66253 j_mayer
793 e2684c0b Andreas Färber
uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
794 76a66253 j_mayer
{
795 76a66253 j_mayer
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
796 76a66253 j_mayer
}
797 76a66253 j_mayer
798 636aaad7 j_mayer
/*****************************************************************************/
799 ddd1055b Fabien Chouteau
/* PowerPC 40x timers */
800 636aaad7 j_mayer
801 636aaad7 j_mayer
/* PIT, FIT & WDT */
802 ddd1055b Fabien Chouteau
typedef struct ppc40x_timer_t ppc40x_timer_t;
803 ddd1055b Fabien Chouteau
struct ppc40x_timer_t {
804 636aaad7 j_mayer
    uint64_t pit_reload;  /* PIT auto-reload value        */
805 636aaad7 j_mayer
    uint64_t fit_next;    /* Tick for next FIT interrupt  */
806 636aaad7 j_mayer
    struct QEMUTimer *fit_timer;
807 636aaad7 j_mayer
    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
808 636aaad7 j_mayer
    struct QEMUTimer *wdt_timer;
809 d63cb48d Edgar E. Iglesias
810 d63cb48d Edgar E. Iglesias
    /* 405 have the PIT, 440 have a DECR.  */
811 d63cb48d Edgar E. Iglesias
    unsigned int decr_excp;
812 636aaad7 j_mayer
};
813 3b46e624 ths
814 636aaad7 j_mayer
/* Fixed interval timer */
815 636aaad7 j_mayer
static void cpu_4xx_fit_cb (void *opaque)
816 636aaad7 j_mayer
{
817 e2684c0b Andreas Färber
    CPUPPCState *env;
818 c227f099 Anthony Liguori
    ppc_tb_t *tb_env;
819 ddd1055b Fabien Chouteau
    ppc40x_timer_t *ppc40x_timer;
820 636aaad7 j_mayer
    uint64_t now, next;
821 636aaad7 j_mayer
822 636aaad7 j_mayer
    env = opaque;
823 636aaad7 j_mayer
    tb_env = env->tb_env;
824 ddd1055b Fabien Chouteau
    ppc40x_timer = tb_env->opaque;
825 74475455 Paolo Bonzini
    now = qemu_get_clock_ns(vm_clock);
826 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
827 636aaad7 j_mayer
    case 0:
828 636aaad7 j_mayer
        next = 1 << 9;
829 636aaad7 j_mayer
        break;
830 636aaad7 j_mayer
    case 1:
831 636aaad7 j_mayer
        next = 1 << 13;
832 636aaad7 j_mayer
        break;
833 636aaad7 j_mayer
    case 2:
834 636aaad7 j_mayer
        next = 1 << 17;
835 636aaad7 j_mayer
        break;
836 636aaad7 j_mayer
    case 3:
837 636aaad7 j_mayer
        next = 1 << 21;
838 636aaad7 j_mayer
        break;
839 636aaad7 j_mayer
    default:
840 636aaad7 j_mayer
        /* Cannot occur, but makes gcc happy */
841 636aaad7 j_mayer
        return;
842 636aaad7 j_mayer
    }
843 6ee093c9 Juan Quintela
    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
844 636aaad7 j_mayer
    if (next == now)
845 636aaad7 j_mayer
        next++;
846 ddd1055b Fabien Chouteau
    qemu_mod_timer(ppc40x_timer->fit_timer, next);
847 636aaad7 j_mayer
    env->spr[SPR_40x_TSR] |= 1 << 26;
848 636aaad7 j_mayer
    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
849 636aaad7 j_mayer
        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
850 90e189ec Blue Swirl
    LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
851 90e189ec Blue Swirl
           (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
852 90e189ec Blue Swirl
           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
853 636aaad7 j_mayer
}
854 636aaad7 j_mayer
855 636aaad7 j_mayer
/* Programmable interval timer */
856 e2684c0b Andreas Färber
static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
857 76a66253 j_mayer
{
858 ddd1055b Fabien Chouteau
    ppc40x_timer_t *ppc40x_timer;
859 636aaad7 j_mayer
    uint64_t now, next;
860 636aaad7 j_mayer
861 ddd1055b Fabien Chouteau
    ppc40x_timer = tb_env->opaque;
862 ddd1055b Fabien Chouteau
    if (ppc40x_timer->pit_reload <= 1 ||
863 4b6d0a4c j_mayer
        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
864 4b6d0a4c j_mayer
        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
865 4b6d0a4c j_mayer
        /* Stop PIT */
866 d12d51d5 aliguori
        LOG_TB("%s: stop PIT\n", __func__);
867 4b6d0a4c j_mayer
        qemu_del_timer(tb_env->decr_timer);
868 4b6d0a4c j_mayer
    } else {
869 d12d51d5 aliguori
        LOG_TB("%s: start PIT %016" PRIx64 "\n",
870 ddd1055b Fabien Chouteau
                    __func__, ppc40x_timer->pit_reload);
871 74475455 Paolo Bonzini
        now = qemu_get_clock_ns(vm_clock);
872 ddd1055b Fabien Chouteau
        next = now + muldiv64(ppc40x_timer->pit_reload,
873 6ee093c9 Juan Quintela
                              get_ticks_per_sec(), tb_env->decr_freq);
874 4b6d0a4c j_mayer
        if (is_excp)
875 4b6d0a4c j_mayer
            next += tb_env->decr_next - now;
876 636aaad7 j_mayer
        if (next == now)
877 636aaad7 j_mayer
            next++;
878 636aaad7 j_mayer
        qemu_mod_timer(tb_env->decr_timer, next);
879 636aaad7 j_mayer
        tb_env->decr_next = next;
880 636aaad7 j_mayer
    }
881 4b6d0a4c j_mayer
}
882 4b6d0a4c j_mayer
883 4b6d0a4c j_mayer
static void cpu_4xx_pit_cb (void *opaque)
884 4b6d0a4c j_mayer
{
885 e2684c0b Andreas Färber
    CPUPPCState *env;
886 c227f099 Anthony Liguori
    ppc_tb_t *tb_env;
887 ddd1055b Fabien Chouteau
    ppc40x_timer_t *ppc40x_timer;
888 4b6d0a4c j_mayer
889 4b6d0a4c j_mayer
    env = opaque;
890 4b6d0a4c j_mayer
    tb_env = env->tb_env;
891 ddd1055b Fabien Chouteau
    ppc40x_timer = tb_env->opaque;
892 636aaad7 j_mayer
    env->spr[SPR_40x_TSR] |= 1 << 27;
893 636aaad7 j_mayer
    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
894 ddd1055b Fabien Chouteau
        ppc_set_irq(env, ppc40x_timer->decr_excp, 1);
895 4b6d0a4c j_mayer
    start_stop_pit(env, tb_env, 1);
896 90e189ec Blue Swirl
    LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
897 90e189ec Blue Swirl
           "%016" PRIx64 "\n", __func__,
898 90e189ec Blue Swirl
           (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
899 90e189ec Blue Swirl
           (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
900 90e189ec Blue Swirl
           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
901 ddd1055b Fabien Chouteau
           ppc40x_timer->pit_reload);
902 636aaad7 j_mayer
}
903 636aaad7 j_mayer
904 636aaad7 j_mayer
/* Watchdog timer */
905 636aaad7 j_mayer
static void cpu_4xx_wdt_cb (void *opaque)
906 636aaad7 j_mayer
{
907 e2684c0b Andreas Färber
    CPUPPCState *env;
908 c227f099 Anthony Liguori
    ppc_tb_t *tb_env;
909 ddd1055b Fabien Chouteau
    ppc40x_timer_t *ppc40x_timer;
910 636aaad7 j_mayer
    uint64_t now, next;
911 636aaad7 j_mayer
912 636aaad7 j_mayer
    env = opaque;
913 636aaad7 j_mayer
    tb_env = env->tb_env;
914 ddd1055b Fabien Chouteau
    ppc40x_timer = tb_env->opaque;
915 74475455 Paolo Bonzini
    now = qemu_get_clock_ns(vm_clock);
916 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
917 636aaad7 j_mayer
    case 0:
918 636aaad7 j_mayer
        next = 1 << 17;
919 636aaad7 j_mayer
        break;
920 636aaad7 j_mayer
    case 1:
921 636aaad7 j_mayer
        next = 1 << 21;
922 636aaad7 j_mayer
        break;
923 636aaad7 j_mayer
    case 2:
924 636aaad7 j_mayer
        next = 1 << 25;
925 636aaad7 j_mayer
        break;
926 636aaad7 j_mayer
    case 3:
927 636aaad7 j_mayer
        next = 1 << 29;
928 636aaad7 j_mayer
        break;
929 636aaad7 j_mayer
    default:
930 636aaad7 j_mayer
        /* Cannot occur, but makes gcc happy */
931 636aaad7 j_mayer
        return;
932 636aaad7 j_mayer
    }
933 6ee093c9 Juan Quintela
    next = now + muldiv64(next, get_ticks_per_sec(), tb_env->decr_freq);
934 636aaad7 j_mayer
    if (next == now)
935 636aaad7 j_mayer
        next++;
936 90e189ec Blue Swirl
    LOG_TB("%s: TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__,
937 90e189ec Blue Swirl
           env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
938 636aaad7 j_mayer
    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
939 636aaad7 j_mayer
    case 0x0:
940 636aaad7 j_mayer
    case 0x1:
941 ddd1055b Fabien Chouteau
        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
942 ddd1055b Fabien Chouteau
        ppc40x_timer->wdt_next = next;
943 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= 1 << 31;
944 636aaad7 j_mayer
        break;
945 636aaad7 j_mayer
    case 0x2:
946 ddd1055b Fabien Chouteau
        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
947 ddd1055b Fabien Chouteau
        ppc40x_timer->wdt_next = next;
948 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= 1 << 30;
949 636aaad7 j_mayer
        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
950 636aaad7 j_mayer
            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
951 636aaad7 j_mayer
        break;
952 636aaad7 j_mayer
    case 0x3:
953 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] &= ~0x30000000;
954 636aaad7 j_mayer
        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
955 636aaad7 j_mayer
        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
956 636aaad7 j_mayer
        case 0x0:
957 636aaad7 j_mayer
            /* No reset */
958 636aaad7 j_mayer
            break;
959 636aaad7 j_mayer
        case 0x1: /* Core reset */
960 8ecc7913 j_mayer
            ppc40x_core_reset(env);
961 8ecc7913 j_mayer
            break;
962 636aaad7 j_mayer
        case 0x2: /* Chip reset */
963 8ecc7913 j_mayer
            ppc40x_chip_reset(env);
964 8ecc7913 j_mayer
            break;
965 636aaad7 j_mayer
        case 0x3: /* System reset */
966 8ecc7913 j_mayer
            ppc40x_system_reset(env);
967 8ecc7913 j_mayer
            break;
968 636aaad7 j_mayer
        }
969 636aaad7 j_mayer
    }
970 76a66253 j_mayer
}
971 76a66253 j_mayer
972 e2684c0b Andreas Färber
void store_40x_pit (CPUPPCState *env, target_ulong val)
973 76a66253 j_mayer
{
974 c227f099 Anthony Liguori
    ppc_tb_t *tb_env;
975 ddd1055b Fabien Chouteau
    ppc40x_timer_t *ppc40x_timer;
976 636aaad7 j_mayer
977 636aaad7 j_mayer
    tb_env = env->tb_env;
978 ddd1055b Fabien Chouteau
    ppc40x_timer = tb_env->opaque;
979 90e189ec Blue Swirl
    LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
980 ddd1055b Fabien Chouteau
    ppc40x_timer->pit_reload = val;
981 4b6d0a4c j_mayer
    start_stop_pit(env, tb_env, 0);
982 76a66253 j_mayer
}
983 76a66253 j_mayer
984 e2684c0b Andreas Färber
target_ulong load_40x_pit (CPUPPCState *env)
985 76a66253 j_mayer
{
986 636aaad7 j_mayer
    return cpu_ppc_load_decr(env);
987 76a66253 j_mayer
}
988 76a66253 j_mayer
989 ddd1055b Fabien Chouteau
static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
990 4b6d0a4c j_mayer
{
991 e2684c0b Andreas Färber
    CPUPPCState *env = opaque;
992 c227f099 Anthony Liguori
    ppc_tb_t *tb_env = env->tb_env;
993 4b6d0a4c j_mayer
994 d12d51d5 aliguori
    LOG_TB("%s set new frequency to %" PRIu32 "\n", __func__,
995 aae9366a j_mayer
                freq);
996 4b6d0a4c j_mayer
    tb_env->tb_freq = freq;
997 dbdd2506 j_mayer
    tb_env->decr_freq = freq;
998 4b6d0a4c j_mayer
    /* XXX: we should also update all timers */
999 4b6d0a4c j_mayer
}
1000 4b6d0a4c j_mayer
1001 e2684c0b Andreas Färber
clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
1002 d63cb48d Edgar E. Iglesias
                                  unsigned int decr_excp)
1003 636aaad7 j_mayer
{
1004 c227f099 Anthony Liguori
    ppc_tb_t *tb_env;
1005 ddd1055b Fabien Chouteau
    ppc40x_timer_t *ppc40x_timer;
1006 636aaad7 j_mayer
1007 7267c094 Anthony Liguori
    tb_env = g_malloc0(sizeof(ppc_tb_t));
1008 8ecc7913 j_mayer
    env->tb_env = tb_env;
1009 ddd1055b Fabien Chouteau
    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
1010 ddd1055b Fabien Chouteau
    ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
1011 8ecc7913 j_mayer
    tb_env->tb_freq = freq;
1012 dbdd2506 j_mayer
    tb_env->decr_freq = freq;
1013 ddd1055b Fabien Chouteau
    tb_env->opaque = ppc40x_timer;
1014 d12d51d5 aliguori
    LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
1015 ddd1055b Fabien Chouteau
    if (ppc40x_timer != NULL) {
1016 636aaad7 j_mayer
        /* We use decr timer for PIT */
1017 74475455 Paolo Bonzini
        tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
1018 ddd1055b Fabien Chouteau
        ppc40x_timer->fit_timer =
1019 74475455 Paolo Bonzini
            qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
1020 ddd1055b Fabien Chouteau
        ppc40x_timer->wdt_timer =
1021 74475455 Paolo Bonzini
            qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
1022 ddd1055b Fabien Chouteau
        ppc40x_timer->decr_excp = decr_excp;
1023 636aaad7 j_mayer
    }
1024 8ecc7913 j_mayer
1025 ddd1055b Fabien Chouteau
    return &ppc_40x_set_tb_clk;
1026 76a66253 j_mayer
}
1027 76a66253 j_mayer
1028 2e719ba3 j_mayer
/*****************************************************************************/
1029 2e719ba3 j_mayer
/* Embedded PowerPC Device Control Registers */
1030 c227f099 Anthony Liguori
typedef struct ppc_dcrn_t ppc_dcrn_t;
1031 c227f099 Anthony Liguori
struct ppc_dcrn_t {
1032 2e719ba3 j_mayer
    dcr_read_cb dcr_read;
1033 2e719ba3 j_mayer
    dcr_write_cb dcr_write;
1034 2e719ba3 j_mayer
    void *opaque;
1035 2e719ba3 j_mayer
};
1036 2e719ba3 j_mayer
1037 a750fc0b j_mayer
/* XXX: on 460, DCR addresses are 32 bits wide,
1038 a750fc0b j_mayer
 *      using DCRIPR to get the 22 upper bits of the DCR address
1039 a750fc0b j_mayer
 */
1040 2e719ba3 j_mayer
#define DCRN_NB 1024
1041 c227f099 Anthony Liguori
struct ppc_dcr_t {
1042 c227f099 Anthony Liguori
    ppc_dcrn_t dcrn[DCRN_NB];
1043 2e719ba3 j_mayer
    int (*read_error)(int dcrn);
1044 2e719ba3 j_mayer
    int (*write_error)(int dcrn);
1045 2e719ba3 j_mayer
};
1046 2e719ba3 j_mayer
1047 73b01960 Alexander Graf
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
1048 2e719ba3 j_mayer
{
1049 c227f099 Anthony Liguori
    ppc_dcrn_t *dcr;
1050 2e719ba3 j_mayer
1051 2e719ba3 j_mayer
    if (dcrn < 0 || dcrn >= DCRN_NB)
1052 2e719ba3 j_mayer
        goto error;
1053 2e719ba3 j_mayer
    dcr = &dcr_env->dcrn[dcrn];
1054 2e719ba3 j_mayer
    if (dcr->dcr_read == NULL)
1055 2e719ba3 j_mayer
        goto error;
1056 2e719ba3 j_mayer
    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1057 2e719ba3 j_mayer
1058 2e719ba3 j_mayer
    return 0;
1059 2e719ba3 j_mayer
1060 2e719ba3 j_mayer
 error:
1061 2e719ba3 j_mayer
    if (dcr_env->read_error != NULL)
1062 2e719ba3 j_mayer
        return (*dcr_env->read_error)(dcrn);
1063 2e719ba3 j_mayer
1064 2e719ba3 j_mayer
    return -1;
1065 2e719ba3 j_mayer
}
1066 2e719ba3 j_mayer
1067 73b01960 Alexander Graf
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
1068 2e719ba3 j_mayer
{
1069 c227f099 Anthony Liguori
    ppc_dcrn_t *dcr;
1070 2e719ba3 j_mayer
1071 2e719ba3 j_mayer
    if (dcrn < 0 || dcrn >= DCRN_NB)
1072 2e719ba3 j_mayer
        goto error;
1073 2e719ba3 j_mayer
    dcr = &dcr_env->dcrn[dcrn];
1074 2e719ba3 j_mayer
    if (dcr->dcr_write == NULL)
1075 2e719ba3 j_mayer
        goto error;
1076 2e719ba3 j_mayer
    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
1077 2e719ba3 j_mayer
1078 2e719ba3 j_mayer
    return 0;
1079 2e719ba3 j_mayer
1080 2e719ba3 j_mayer
 error:
1081 2e719ba3 j_mayer
    if (dcr_env->write_error != NULL)
1082 2e719ba3 j_mayer
        return (*dcr_env->write_error)(dcrn);
1083 2e719ba3 j_mayer
1084 2e719ba3 j_mayer
    return -1;
1085 2e719ba3 j_mayer
}
1086 2e719ba3 j_mayer
1087 e2684c0b Andreas Färber
int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
1088 2e719ba3 j_mayer
                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
1089 2e719ba3 j_mayer
{
1090 c227f099 Anthony Liguori
    ppc_dcr_t *dcr_env;
1091 c227f099 Anthony Liguori
    ppc_dcrn_t *dcr;
1092 2e719ba3 j_mayer
1093 2e719ba3 j_mayer
    dcr_env = env->dcr_env;
1094 2e719ba3 j_mayer
    if (dcr_env == NULL)
1095 2e719ba3 j_mayer
        return -1;
1096 2e719ba3 j_mayer
    if (dcrn < 0 || dcrn >= DCRN_NB)
1097 2e719ba3 j_mayer
        return -1;
1098 2e719ba3 j_mayer
    dcr = &dcr_env->dcrn[dcrn];
1099 2e719ba3 j_mayer
    if (dcr->opaque != NULL ||
1100 2e719ba3 j_mayer
        dcr->dcr_read != NULL ||
1101 2e719ba3 j_mayer
        dcr->dcr_write != NULL)
1102 2e719ba3 j_mayer
        return -1;
1103 2e719ba3 j_mayer
    dcr->opaque = opaque;
1104 2e719ba3 j_mayer
    dcr->dcr_read = dcr_read;
1105 2e719ba3 j_mayer
    dcr->dcr_write = dcr_write;
1106 2e719ba3 j_mayer
1107 2e719ba3 j_mayer
    return 0;
1108 2e719ba3 j_mayer
}
1109 2e719ba3 j_mayer
1110 e2684c0b Andreas Färber
int ppc_dcr_init (CPUPPCState *env, int (*read_error)(int dcrn),
1111 2e719ba3 j_mayer
                  int (*write_error)(int dcrn))
1112 2e719ba3 j_mayer
{
1113 c227f099 Anthony Liguori
    ppc_dcr_t *dcr_env;
1114 2e719ba3 j_mayer
1115 7267c094 Anthony Liguori
    dcr_env = g_malloc0(sizeof(ppc_dcr_t));
1116 2e719ba3 j_mayer
    dcr_env->read_error = read_error;
1117 2e719ba3 j_mayer
    dcr_env->write_error = write_error;
1118 2e719ba3 j_mayer
    env->dcr_env = dcr_env;
1119 2e719ba3 j_mayer
1120 2e719ba3 j_mayer
    return 0;
1121 2e719ba3 j_mayer
}
1122 2e719ba3 j_mayer
1123 64201201 bellard
/*****************************************************************************/
1124 64201201 bellard
/* Debug port */
1125 fd0bbb12 bellard
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
1126 64201201 bellard
{
1127 64201201 bellard
    addr &= 0xF;
1128 64201201 bellard
    switch (addr) {
1129 64201201 bellard
    case 0:
1130 64201201 bellard
        printf("%c", val);
1131 64201201 bellard
        break;
1132 64201201 bellard
    case 1:
1133 64201201 bellard
        printf("\n");
1134 64201201 bellard
        fflush(stdout);
1135 64201201 bellard
        break;
1136 64201201 bellard
    case 2:
1137 aae9366a j_mayer
        printf("Set loglevel to %04" PRIx32 "\n", val);
1138 fd0bbb12 bellard
        cpu_set_log(val | 0x100);
1139 64201201 bellard
        break;
1140 64201201 bellard
    }
1141 64201201 bellard
}
1142 64201201 bellard
1143 64201201 bellard
/*****************************************************************************/
1144 64201201 bellard
/* NVRAM helpers */
1145 c227f099 Anthony Liguori
static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
1146 64201201 bellard
{
1147 3a93113a Dong Xu Wang
    return (*nvram->read_fn)(nvram->opaque, addr);
1148 64201201 bellard
}
1149 64201201 bellard
1150 c227f099 Anthony Liguori
static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
1151 64201201 bellard
{
1152 3cbee15b j_mayer
    (*nvram->write_fn)(nvram->opaque, addr, val);
1153 64201201 bellard
}
1154 64201201 bellard
1155 c227f099 Anthony Liguori
void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
1156 64201201 bellard
{
1157 3cbee15b j_mayer
    nvram_write(nvram, addr, value);
1158 64201201 bellard
}
1159 64201201 bellard
1160 c227f099 Anthony Liguori
uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr)
1161 3cbee15b j_mayer
{
1162 3cbee15b j_mayer
    return nvram_read(nvram, addr);
1163 3cbee15b j_mayer
}
1164 3cbee15b j_mayer
1165 c227f099 Anthony Liguori
void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value)
1166 3cbee15b j_mayer
{
1167 3cbee15b j_mayer
    nvram_write(nvram, addr, value >> 8);
1168 3cbee15b j_mayer
    nvram_write(nvram, addr + 1, value & 0xFF);
1169 3cbee15b j_mayer
}
1170 3cbee15b j_mayer
1171 c227f099 Anthony Liguori
uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr)
1172 64201201 bellard
{
1173 64201201 bellard
    uint16_t tmp;
1174 64201201 bellard
1175 3cbee15b j_mayer
    tmp = nvram_read(nvram, addr) << 8;
1176 3cbee15b j_mayer
    tmp |= nvram_read(nvram, addr + 1);
1177 3cbee15b j_mayer
1178 64201201 bellard
    return tmp;
1179 64201201 bellard
}
1180 64201201 bellard
1181 c227f099 Anthony Liguori
void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value)
1182 64201201 bellard
{
1183 3cbee15b j_mayer
    nvram_write(nvram, addr, value >> 24);
1184 3cbee15b j_mayer
    nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
1185 3cbee15b j_mayer
    nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
1186 3cbee15b j_mayer
    nvram_write(nvram, addr + 3, value & 0xFF);
1187 64201201 bellard
}
1188 64201201 bellard
1189 c227f099 Anthony Liguori
uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
1190 64201201 bellard
{
1191 64201201 bellard
    uint32_t tmp;
1192 64201201 bellard
1193 3cbee15b j_mayer
    tmp = nvram_read(nvram, addr) << 24;
1194 3cbee15b j_mayer
    tmp |= nvram_read(nvram, addr + 1) << 16;
1195 3cbee15b j_mayer
    tmp |= nvram_read(nvram, addr + 2) << 8;
1196 3cbee15b j_mayer
    tmp |= nvram_read(nvram, addr + 3);
1197 76a66253 j_mayer
1198 64201201 bellard
    return tmp;
1199 64201201 bellard
}
1200 64201201 bellard
1201 c227f099 Anthony Liguori
void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
1202 b55266b5 blueswir1
                       const char *str, uint32_t max)
1203 64201201 bellard
{
1204 64201201 bellard
    int i;
1205 64201201 bellard
1206 64201201 bellard
    for (i = 0; i < max && str[i] != '\0'; i++) {
1207 3cbee15b j_mayer
        nvram_write(nvram, addr + i, str[i]);
1208 64201201 bellard
    }
1209 3cbee15b j_mayer
    nvram_write(nvram, addr + i, str[i]);
1210 3cbee15b j_mayer
    nvram_write(nvram, addr + max - 1, '\0');
1211 64201201 bellard
}
1212 64201201 bellard
1213 c227f099 Anthony Liguori
int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
1214 64201201 bellard
{
1215 64201201 bellard
    int i;
1216 64201201 bellard
1217 64201201 bellard
    memset(dst, 0, max);
1218 64201201 bellard
    for (i = 0; i < max; i++) {
1219 64201201 bellard
        dst[i] = NVRAM_get_byte(nvram, addr + i);
1220 64201201 bellard
        if (dst[i] == '\0')
1221 64201201 bellard
            break;
1222 64201201 bellard
    }
1223 64201201 bellard
1224 64201201 bellard
    return i;
1225 64201201 bellard
}
1226 64201201 bellard
1227 64201201 bellard
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1228 64201201 bellard
{
1229 64201201 bellard
    uint16_t tmp;
1230 64201201 bellard
    uint16_t pd, pd1, pd2;
1231 64201201 bellard
1232 64201201 bellard
    tmp = prev >> 8;
1233 64201201 bellard
    pd = prev ^ value;
1234 64201201 bellard
    pd1 = pd & 0x000F;
1235 64201201 bellard
    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1236 64201201 bellard
    tmp ^= (pd1 << 3) | (pd1 << 8);
1237 64201201 bellard
    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1238 64201201 bellard
1239 64201201 bellard
    return tmp;
1240 64201201 bellard
}
1241 64201201 bellard
1242 c227f099 Anthony Liguori
static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
1243 64201201 bellard
{
1244 64201201 bellard
    uint32_t i;
1245 64201201 bellard
    uint16_t crc = 0xFFFF;
1246 64201201 bellard
    int odd;
1247 64201201 bellard
1248 64201201 bellard
    odd = count & 1;
1249 64201201 bellard
    count &= ~1;
1250 64201201 bellard
    for (i = 0; i != count; i++) {
1251 76a66253 j_mayer
        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1252 64201201 bellard
    }
1253 64201201 bellard
    if (odd) {
1254 76a66253 j_mayer
        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1255 64201201 bellard
    }
1256 64201201 bellard
1257 64201201 bellard
    return crc;
1258 64201201 bellard
}
1259 64201201 bellard
1260 fd0bbb12 bellard
#define CMDLINE_ADDR 0x017ff000
1261 fd0bbb12 bellard
1262 c227f099 Anthony Liguori
int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
1263 b55266b5 blueswir1
                          const char *arch,
1264 64201201 bellard
                          uint32_t RAM_size, int boot_device,
1265 64201201 bellard
                          uint32_t kernel_image, uint32_t kernel_size,
1266 fd0bbb12 bellard
                          const char *cmdline,
1267 64201201 bellard
                          uint32_t initrd_image, uint32_t initrd_size,
1268 fd0bbb12 bellard
                          uint32_t NVRAM_image,
1269 fd0bbb12 bellard
                          int width, int height, int depth)
1270 64201201 bellard
{
1271 64201201 bellard
    uint16_t crc;
1272 64201201 bellard
1273 64201201 bellard
    /* Set parameters for Open Hack'Ware BIOS */
1274 64201201 bellard
    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1275 64201201 bellard
    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
1276 64201201 bellard
    NVRAM_set_word(nvram,   0x14, NVRAM_size);
1277 64201201 bellard
    NVRAM_set_string(nvram, 0x20, arch, 16);
1278 64201201 bellard
    NVRAM_set_lword(nvram,  0x30, RAM_size);
1279 64201201 bellard
    NVRAM_set_byte(nvram,   0x34, boot_device);
1280 64201201 bellard
    NVRAM_set_lword(nvram,  0x38, kernel_image);
1281 64201201 bellard
    NVRAM_set_lword(nvram,  0x3C, kernel_size);
1282 fd0bbb12 bellard
    if (cmdline) {
1283 fd0bbb12 bellard
        /* XXX: put the cmdline in NVRAM too ? */
1284 3c178e72 Gerd Hoffmann
        pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
1285 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
1286 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
1287 fd0bbb12 bellard
    } else {
1288 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x40, 0);
1289 fd0bbb12 bellard
        NVRAM_set_lword(nvram,  0x44, 0);
1290 fd0bbb12 bellard
    }
1291 64201201 bellard
    NVRAM_set_lword(nvram,  0x48, initrd_image);
1292 64201201 bellard
    NVRAM_set_lword(nvram,  0x4C, initrd_size);
1293 64201201 bellard
    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
1294 fd0bbb12 bellard
1295 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x54, width);
1296 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x56, height);
1297 fd0bbb12 bellard
    NVRAM_set_word(nvram,   0x58, depth);
1298 fd0bbb12 bellard
    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1299 3cbee15b j_mayer
    NVRAM_set_word(nvram,   0xFC, crc);
1300 64201201 bellard
1301 64201201 bellard
    return 0;
1302 a541f297 bellard
}