Statistics
| Branch: | Revision:

root / hw / ppc.c @ 1a14026e

History | View | Annotate | Download (40.1 kB)

1
/*
2
 * QEMU generic PowerPC hardware System Emulator
3
 *
4
 * Copyright (c) 2003-2007 Jocelyn Mayer
5
 *
6
 * 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
 */
24
#include "hw.h"
25
#include "ppc.h"
26
#include "qemu-timer.h"
27
#include "sysemu.h"
28
#include "nvram.h"
29

    
30
//#define PPC_DEBUG_IRQ
31
//#define PPC_DEBUG_TB
32

    
33
extern FILE *logfile;
34
extern int loglevel;
35

    
36
static void cpu_ppc_tb_stop (CPUState *env);
37
static void cpu_ppc_tb_start (CPUState *env);
38

    
39
static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
40
{
41
    if (level) {
42
        env->pending_interrupts |= 1 << n_IRQ;
43
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
44
    } else {
45
        env->pending_interrupts &= ~(1 << n_IRQ);
46
        if (env->pending_interrupts == 0)
47
            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
48
    }
49
#if defined(PPC_DEBUG_IRQ)
50
    if (loglevel & CPU_LOG_INT) {
51
        fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08" PRIx32
52
                "req %08x\n", __func__, env, n_IRQ, level,
53
                env->pending_interrupts, env->interrupt_request);
54
    }
55
#endif
56
}
57

    
58
/* PowerPC 6xx / 7xx internal IRQ controller */
59
static void ppc6xx_set_irq (void *opaque, int pin, int level)
60
{
61
    CPUState *env = opaque;
62
    int cur_level;
63

    
64
#if defined(PPC_DEBUG_IRQ)
65
    if (loglevel & CPU_LOG_INT) {
66
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
67
                env, pin, level);
68
    }
69
#endif
70
    cur_level = (env->irq_input_state >> pin) & 1;
71
    /* Don't generate spurious events */
72
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
73
        switch (pin) {
74
        case PPC6xx_INPUT_TBEN:
75
            /* Level sensitive - active high */
76
#if defined(PPC_DEBUG_IRQ)
77
            if (loglevel & CPU_LOG_INT) {
78
                fprintf(logfile, "%s: %s the time base\n",
79
                        __func__, level ? "start" : "stop");
80
            }
81
#endif
82
            if (level) {
83
                cpu_ppc_tb_start(env);
84
            } else {
85
                cpu_ppc_tb_stop(env);
86
            }
87
        case PPC6xx_INPUT_INT:
88
            /* Level sensitive - active high */
89
#if defined(PPC_DEBUG_IRQ)
90
            if (loglevel & CPU_LOG_INT) {
91
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
92
                        __func__, level);
93
            }
94
#endif
95
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
96
            break;
97
        case PPC6xx_INPUT_SMI:
98
            /* Level sensitive - active high */
99
#if defined(PPC_DEBUG_IRQ)
100
            if (loglevel & CPU_LOG_INT) {
101
                fprintf(logfile, "%s: set the SMI IRQ state to %d\n",
102
                        __func__, level);
103
            }
104
#endif
105
            ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
106
            break;
107
        case PPC6xx_INPUT_MCP:
108
            /* Negative edge sensitive */
109
            /* XXX: TODO: actual reaction may depends on HID0 status
110
             *            603/604/740/750: check HID0[EMCP]
111
             */
112
            if (cur_level == 1 && level == 0) {
113
#if defined(PPC_DEBUG_IRQ)
114
                if (loglevel & CPU_LOG_INT) {
115
                    fprintf(logfile, "%s: raise machine check state\n",
116
                            __func__);
117
                }
118
#endif
119
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
120
            }
121
            break;
122
        case PPC6xx_INPUT_CKSTP_IN:
123
            /* Level sensitive - active low */
124
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
125
            /* XXX: Note that the only way to restart the CPU is to reset it */
126
            if (level) {
127
#if defined(PPC_DEBUG_IRQ)
128
                if (loglevel & CPU_LOG_INT) {
129
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
130
                }
131
#endif
132
                env->halted = 1;
133
            }
134
            break;
135
        case PPC6xx_INPUT_HRESET:
136
            /* Level sensitive - active low */
137
            if (level) {
138
#if defined(PPC_DEBUG_IRQ)
139
                if (loglevel & CPU_LOG_INT) {
140
                    fprintf(logfile, "%s: reset the CPU\n", __func__);
141
                }
142
#endif
143
                env->interrupt_request |= CPU_INTERRUPT_EXITTB;
144
                /* XXX: TOFIX */
145
#if 0
146
                cpu_ppc_reset(env);
147
#else
148
                qemu_system_reset_request();
149
#endif
150
            }
151
            break;
152
        case PPC6xx_INPUT_SRESET:
153
#if defined(PPC_DEBUG_IRQ)
154
            if (loglevel & CPU_LOG_INT) {
155
                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
156
                        __func__, level);
157
            }
158
#endif
159
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
160
            break;
161
        default:
162
            /* Unknown pin - do nothing */
163
#if defined(PPC_DEBUG_IRQ)
164
            if (loglevel & CPU_LOG_INT) {
165
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
166
            }
167
#endif
168
            return;
169
        }
170
        if (level)
171
            env->irq_input_state |= 1 << pin;
172
        else
173
            env->irq_input_state &= ~(1 << pin);
174
    }
175
}
176

    
177
void ppc6xx_irq_init (CPUState *env)
178
{
179
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env,
180
                                                  PPC6xx_INPUT_NB);
181
}
182

    
183
#if defined(TARGET_PPC64)
184
/* PowerPC 970 internal IRQ controller */
185
static void ppc970_set_irq (void *opaque, int pin, int level)
186
{
187
    CPUState *env = opaque;
188
    int cur_level;
189

    
190
#if defined(PPC_DEBUG_IRQ)
191
    if (loglevel & CPU_LOG_INT) {
192
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
193
                env, pin, level);
194
    }
195
#endif
196
    cur_level = (env->irq_input_state >> pin) & 1;
197
    /* Don't generate spurious events */
198
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
199
        switch (pin) {
200
        case PPC970_INPUT_INT:
201
            /* Level sensitive - active high */
202
#if defined(PPC_DEBUG_IRQ)
203
            if (loglevel & CPU_LOG_INT) {
204
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
205
                        __func__, level);
206
            }
207
#endif
208
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
209
            break;
210
        case PPC970_INPUT_THINT:
211
            /* Level sensitive - active high */
212
#if defined(PPC_DEBUG_IRQ)
213
            if (loglevel & CPU_LOG_INT) {
214
                fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__,
215
                        level);
216
            }
217
#endif
218
            ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
219
            break;
220
        case PPC970_INPUT_MCP:
221
            /* Negative edge sensitive */
222
            /* XXX: TODO: actual reaction may depends on HID0 status
223
             *            603/604/740/750: check HID0[EMCP]
224
             */
225
            if (cur_level == 1 && level == 0) {
226
#if defined(PPC_DEBUG_IRQ)
227
                if (loglevel & CPU_LOG_INT) {
228
                    fprintf(logfile, "%s: raise machine check state\n",
229
                            __func__);
230
                }
231
#endif
232
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
233
            }
234
            break;
235
        case PPC970_INPUT_CKSTP:
236
            /* Level sensitive - active low */
237
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
238
            if (level) {
239
#if defined(PPC_DEBUG_IRQ)
240
                if (loglevel & CPU_LOG_INT) {
241
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
242
                }
243
#endif
244
                env->halted = 1;
245
            } else {
246
#if defined(PPC_DEBUG_IRQ)
247
                if (loglevel & CPU_LOG_INT) {
248
                    fprintf(logfile, "%s: restart the CPU\n", __func__);
249
                }
250
#endif
251
                env->halted = 0;
252
            }
253
            break;
254
        case PPC970_INPUT_HRESET:
255
            /* Level sensitive - active low */
256
            if (level) {
257
#if 0 // XXX: TOFIX
258
#if defined(PPC_DEBUG_IRQ)
259
                if (loglevel & CPU_LOG_INT) {
260
                    fprintf(logfile, "%s: reset the CPU\n", __func__);
261
                }
262
#endif
263
                cpu_reset(env);
264
#endif
265
            }
266
            break;
267
        case PPC970_INPUT_SRESET:
268
#if defined(PPC_DEBUG_IRQ)
269
            if (loglevel & CPU_LOG_INT) {
270
                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
271
                        __func__, level);
272
            }
273
#endif
274
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
275
            break;
276
        case PPC970_INPUT_TBEN:
277
#if defined(PPC_DEBUG_IRQ)
278
            if (loglevel & CPU_LOG_INT) {
279
                fprintf(logfile, "%s: set the TBEN state to %d\n", __func__,
280
                        level);
281
            }
282
#endif
283
            /* XXX: TODO */
284
            break;
285
        default:
286
            /* Unknown pin - do nothing */
287
#if defined(PPC_DEBUG_IRQ)
288
            if (loglevel & CPU_LOG_INT) {
289
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
290
            }
291
#endif
292
            return;
293
        }
294
        if (level)
295
            env->irq_input_state |= 1 << pin;
296
        else
297
            env->irq_input_state &= ~(1 << pin);
298
    }
299
}
300

    
301
void ppc970_irq_init (CPUState *env)
302
{
303
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
304
                                                  PPC970_INPUT_NB);
305
}
306
#endif /* defined(TARGET_PPC64) */
307

    
308
/* PowerPC 40x internal IRQ controller */
309
static void ppc40x_set_irq (void *opaque, int pin, int level)
310
{
311
    CPUState *env = opaque;
312
    int cur_level;
313

    
314
#if defined(PPC_DEBUG_IRQ)
315
    if (loglevel & CPU_LOG_INT) {
316
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
317
                env, pin, level);
318
    }
319
#endif
320
    cur_level = (env->irq_input_state >> pin) & 1;
321
    /* Don't generate spurious events */
322
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
323
        switch (pin) {
324
        case PPC40x_INPUT_RESET_SYS:
325
            if (level) {
326
#if defined(PPC_DEBUG_IRQ)
327
                if (loglevel & CPU_LOG_INT) {
328
                    fprintf(logfile, "%s: reset the PowerPC system\n",
329
                            __func__);
330
                }
331
#endif
332
                ppc40x_system_reset(env);
333
            }
334
            break;
335
        case PPC40x_INPUT_RESET_CHIP:
336
            if (level) {
337
#if defined(PPC_DEBUG_IRQ)
338
                if (loglevel & CPU_LOG_INT) {
339
                    fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
340
                }
341
#endif
342
                ppc40x_chip_reset(env);
343
            }
344
            break;
345
        case PPC40x_INPUT_RESET_CORE:
346
            /* XXX: TODO: update DBSR[MRR] */
347
            if (level) {
348
#if defined(PPC_DEBUG_IRQ)
349
                if (loglevel & CPU_LOG_INT) {
350
                    fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
351
                }
352
#endif
353
                ppc40x_core_reset(env);
354
            }
355
            break;
356
        case PPC40x_INPUT_CINT:
357
            /* Level sensitive - active high */
358
#if defined(PPC_DEBUG_IRQ)
359
            if (loglevel & CPU_LOG_INT) {
360
                fprintf(logfile, "%s: set the critical IRQ state to %d\n",
361
                        __func__, level);
362
            }
363
#endif
364
            ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
365
            break;
366
        case PPC40x_INPUT_INT:
367
            /* Level sensitive - active high */
368
#if defined(PPC_DEBUG_IRQ)
369
            if (loglevel & CPU_LOG_INT) {
370
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
371
                        __func__, level);
372
            }
373
#endif
374
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
375
            break;
376
        case PPC40x_INPUT_HALT:
377
            /* Level sensitive - active low */
378
            if (level) {
379
#if defined(PPC_DEBUG_IRQ)
380
                if (loglevel & CPU_LOG_INT) {
381
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
382
                }
383
#endif
384
                env->halted = 1;
385
            } else {
386
#if defined(PPC_DEBUG_IRQ)
387
                if (loglevel & CPU_LOG_INT) {
388
                    fprintf(logfile, "%s: restart the CPU\n", __func__);
389
                }
390
#endif
391
                env->halted = 0;
392
            }
393
            break;
394
        case PPC40x_INPUT_DEBUG:
395
            /* Level sensitive - active high */
396
#if defined(PPC_DEBUG_IRQ)
397
            if (loglevel & CPU_LOG_INT) {
398
                fprintf(logfile, "%s: set the debug pin state to %d\n",
399
                        __func__, level);
400
            }
401
#endif
402
            ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
403
            break;
404
        default:
405
            /* Unknown pin - do nothing */
406
#if defined(PPC_DEBUG_IRQ)
407
            if (loglevel & CPU_LOG_INT) {
408
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
409
            }
410
#endif
411
            return;
412
        }
413
        if (level)
414
            env->irq_input_state |= 1 << pin;
415
        else
416
            env->irq_input_state &= ~(1 << pin);
417
    }
418
}
419

    
420
void ppc40x_irq_init (CPUState *env)
421
{
422
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
423
                                                  env, PPC40x_INPUT_NB);
424
}
425

    
426
/*****************************************************************************/
427
/* PowerPC time base and decrementer emulation */
428
struct ppc_tb_t {
429
    /* Time base management */
430
    int64_t  tb_offset;    /* Compensation                    */
431
    int64_t  atb_offset;   /* Compensation                    */
432
    uint32_t tb_freq;      /* TB frequency                    */
433
    /* Decrementer management */
434
    uint64_t decr_next;    /* Tick for next decr interrupt    */
435
    uint32_t decr_freq;    /* decrementer frequency           */
436
    struct QEMUTimer *decr_timer;
437
    /* Hypervisor decrementer management */
438
    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
439
    struct QEMUTimer *hdecr_timer;
440
    uint64_t purr_load;
441
    uint64_t purr_start;
442
    void *opaque;
443
};
444

    
445
static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, uint64_t vmclk,
446
                                              int64_t tb_offset)
447
{
448
    /* TB time in tb periods */
449
    return muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec) + tb_offset;
450
}
451

    
452
uint32_t cpu_ppc_load_tbl (CPUState *env)
453
{
454
    ppc_tb_t *tb_env = env->tb_env;
455
    uint64_t tb;
456

    
457
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
458
#if defined(PPC_DEBUG_TB)
459
    if (loglevel != 0) {
460
        fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
461
    }
462
#endif
463

    
464
    return tb & 0xFFFFFFFF;
465
}
466

    
467
static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env)
468
{
469
    ppc_tb_t *tb_env = env->tb_env;
470
    uint64_t tb;
471

    
472
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
473
#if defined(PPC_DEBUG_TB)
474
    if (loglevel != 0) {
475
        fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
476
    }
477
#endif
478

    
479
    return tb >> 32;
480
}
481

    
482
uint32_t cpu_ppc_load_tbu (CPUState *env)
483
{
484
    return _cpu_ppc_load_tbu(env);
485
}
486

    
487
static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t vmclk,
488
                                            int64_t *tb_offsetp,
489
                                            uint64_t value)
490
{
491
    *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec);
492
#ifdef PPC_DEBUG_TB
493
    if (loglevel != 0) {
494
        fprintf(logfile, "%s: tb %016" PRIx64 " offset %08" PRIx64 "\n",
495
                __func__, value, *tb_offsetp);
496
    }
497
#endif
498
}
499

    
500
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
501
{
502
    ppc_tb_t *tb_env = env->tb_env;
503
    uint64_t tb;
504

    
505
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
506
    tb &= 0xFFFFFFFF00000000ULL;
507
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
508
                     &tb_env->tb_offset, tb | (uint64_t)value);
509
}
510

    
511
static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
512
{
513
    ppc_tb_t *tb_env = env->tb_env;
514
    uint64_t tb;
515

    
516
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
517
    tb &= 0x00000000FFFFFFFFULL;
518
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
519
                     &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
520
}
521

    
522
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
523
{
524
    _cpu_ppc_store_tbu(env, value);
525
}
526

    
527
uint32_t cpu_ppc_load_atbl (CPUState *env)
528
{
529
    ppc_tb_t *tb_env = env->tb_env;
530
    uint64_t tb;
531

    
532
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
533
#if defined(PPC_DEBUG_TB)
534
    if (loglevel != 0) {
535
        fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
536
    }
537
#endif
538

    
539
    return tb & 0xFFFFFFFF;
540
}
541

    
542
uint32_t cpu_ppc_load_atbu (CPUState *env)
543
{
544
    ppc_tb_t *tb_env = env->tb_env;
545
    uint64_t tb;
546

    
547
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
548
#if defined(PPC_DEBUG_TB)
549
    if (loglevel != 0) {
550
        fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb);
551
    }
552
#endif
553

    
554
    return tb >> 32;
555
}
556

    
557
void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
558
{
559
    ppc_tb_t *tb_env = env->tb_env;
560
    uint64_t tb;
561

    
562
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
563
    tb &= 0xFFFFFFFF00000000ULL;
564
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
565
                     &tb_env->atb_offset, tb | (uint64_t)value);
566
}
567

    
568
void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
569
{
570
    ppc_tb_t *tb_env = env->tb_env;
571
    uint64_t tb;
572

    
573
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
574
    tb &= 0x00000000FFFFFFFFULL;
575
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
576
                     &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
577
}
578

    
579
static void cpu_ppc_tb_stop (CPUState *env)
580
{
581
    ppc_tb_t *tb_env = env->tb_env;
582
    uint64_t tb, atb, vmclk;
583

    
584
    /* If the time base is already frozen, do nothing */
585
    if (tb_env->tb_freq != 0) {
586
        vmclk = qemu_get_clock(vm_clock);
587
        /* Get the time base */
588
        tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
589
        /* Get the alternate time base */
590
        atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
591
        /* Store the time base value (ie compute the current offset) */
592
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
593
        /* Store the alternate time base value (compute the current offset) */
594
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
595
        /* Set the time base frequency to zero */
596
        tb_env->tb_freq = 0;
597
        /* Now, the time bases are frozen to tb_offset / atb_offset value */
598
    }
599
}
600

    
601
static void cpu_ppc_tb_start (CPUState *env)
602
{
603
    ppc_tb_t *tb_env = env->tb_env;
604
    uint64_t tb, atb, vmclk;
605

    
606
    /* If the time base is not frozen, do nothing */
607
    if (tb_env->tb_freq == 0) {
608
        vmclk = qemu_get_clock(vm_clock);
609
        /* Get the time base from tb_offset */
610
        tb = tb_env->tb_offset;
611
        /* Get the alternate time base from atb_offset */
612
        atb = tb_env->atb_offset;
613
        /* Restore the tb frequency from the decrementer frequency */
614
        tb_env->tb_freq = tb_env->decr_freq;
615
        /* Store the time base value */
616
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
617
        /* Store the alternate time base value */
618
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
619
    }
620
}
621

    
622
static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env,
623
                                                  uint64_t *next)
624
{
625
    ppc_tb_t *tb_env = env->tb_env;
626
    uint32_t decr;
627
    int64_t diff;
628

    
629
    diff = tb_env->decr_next - qemu_get_clock(vm_clock);
630
    if (diff >= 0)
631
        decr = muldiv64(diff, tb_env->decr_freq, ticks_per_sec);
632
    else
633
        decr = -muldiv64(-diff, tb_env->decr_freq, ticks_per_sec);
634
#if defined(PPC_DEBUG_TB)
635
    if (loglevel != 0) {
636
        fprintf(logfile, "%s: %08" PRIx32 "\n", __func__, decr);
637
    }
638
#endif
639

    
640
    return decr;
641
}
642

    
643
uint32_t cpu_ppc_load_decr (CPUState *env)
644
{
645
    ppc_tb_t *tb_env = env->tb_env;
646

    
647
    return _cpu_ppc_load_decr(env, &tb_env->decr_next);
648
}
649

    
650
uint32_t cpu_ppc_load_hdecr (CPUState *env)
651
{
652
    ppc_tb_t *tb_env = env->tb_env;
653

    
654
    return _cpu_ppc_load_decr(env, &tb_env->hdecr_next);
655
}
656

    
657
uint64_t cpu_ppc_load_purr (CPUState *env)
658
{
659
    ppc_tb_t *tb_env = env->tb_env;
660
    uint64_t diff;
661

    
662
    diff = qemu_get_clock(vm_clock) - tb_env->purr_start;
663

    
664
    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
665
}
666

    
667
/* When decrementer expires,
668
 * all we need to do is generate or queue a CPU exception
669
 */
670
static always_inline void cpu_ppc_decr_excp (CPUState *env)
671
{
672
    /* Raise it */
673
#ifdef PPC_DEBUG_TB
674
    if (loglevel != 0) {
675
        fprintf(logfile, "raise decrementer exception\n");
676
    }
677
#endif
678
    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
679
}
680

    
681
static always_inline void cpu_ppc_hdecr_excp (CPUState *env)
682
{
683
    /* Raise it */
684
#ifdef PPC_DEBUG_TB
685
    if (loglevel != 0) {
686
        fprintf(logfile, "raise decrementer exception\n");
687
    }
688
#endif
689
    ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
690
}
691

    
692
static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
693
                                  struct QEMUTimer *timer,
694
                                  void (*raise_excp)(CPUState *),
695
                                  uint32_t decr, uint32_t value,
696
                                  int is_excp)
697
{
698
    ppc_tb_t *tb_env = env->tb_env;
699
    uint64_t now, next;
700

    
701
#ifdef PPC_DEBUG_TB
702
    if (loglevel != 0) {
703
        fprintf(logfile, "%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__,
704
                decr, value);
705
    }
706
#endif
707
    now = qemu_get_clock(vm_clock);
708
    next = now + muldiv64(value, ticks_per_sec, tb_env->decr_freq);
709
    if (is_excp)
710
        next += *nextp - now;
711
    if (next == now)
712
        next++;
713
    *nextp = next;
714
    /* Adjust timer */
715
    qemu_mod_timer(timer, next);
716
    /* If we set a negative value and the decrementer was positive,
717
     * raise an exception.
718
     */
719
    if ((value & 0x80000000) && !(decr & 0x80000000))
720
        (*raise_excp)(env);
721
}
722

    
723
static always_inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
724
                                               uint32_t value, int is_excp)
725
{
726
    ppc_tb_t *tb_env = env->tb_env;
727

    
728
    __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
729
                         &cpu_ppc_decr_excp, decr, value, is_excp);
730
}
731

    
732
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
733
{
734
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
735
}
736

    
737
static void cpu_ppc_decr_cb (void *opaque)
738
{
739
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
740
}
741

    
742
static always_inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr,
743
                                                uint32_t value, int is_excp)
744
{
745
    ppc_tb_t *tb_env = env->tb_env;
746

    
747
    if (tb_env->hdecr_timer != NULL) {
748
        __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
749
                             &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
750
    }
751
}
752

    
753
void cpu_ppc_store_hdecr (CPUState *env, uint32_t value)
754
{
755
    _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
756
}
757

    
758
static void cpu_ppc_hdecr_cb (void *opaque)
759
{
760
    _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
761
}
762

    
763
void cpu_ppc_store_purr (CPUState *env, uint64_t value)
764
{
765
    ppc_tb_t *tb_env = env->tb_env;
766

    
767
    tb_env->purr_load = value;
768
    tb_env->purr_start = qemu_get_clock(vm_clock);
769
}
770

    
771
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
772
{
773
    CPUState *env = opaque;
774
    ppc_tb_t *tb_env = env->tb_env;
775

    
776
    tb_env->tb_freq = freq;
777
    tb_env->decr_freq = freq;
778
    /* There is a bug in Linux 2.4 kernels:
779
     * if a decrementer exception is pending when it enables msr_ee at startup,
780
     * it's not ready to handle it...
781
     */
782
    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
783
    _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
784
    cpu_ppc_store_purr(env, 0x0000000000000000ULL);
785
}
786

    
787
/* Set up (once) timebase frequency (in Hz) */
788
clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
789
{
790
    ppc_tb_t *tb_env;
791

    
792
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
793
    if (tb_env == NULL)
794
        return NULL;
795
    env->tb_env = tb_env;
796
    /* Create new timer */
797
    tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
798
    if (0) {
799
        /* XXX: find a suitable condition to enable the hypervisor decrementer
800
         */
801
        tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env);
802
    } else {
803
        tb_env->hdecr_timer = NULL;
804
    }
805
    cpu_ppc_set_tb_clk(env, freq);
806

    
807
    return &cpu_ppc_set_tb_clk;
808
}
809

    
810
/* Specific helpers for POWER & PowerPC 601 RTC */
811
clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
812
{
813
    return cpu_ppc_tb_init(env, 7812500);
814
}
815

    
816
void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
817
{
818
    _cpu_ppc_store_tbu(env, value);
819
}
820

    
821
uint32_t cpu_ppc601_load_rtcu (CPUState *env)
822
{
823
    return _cpu_ppc_load_tbu(env);
824
}
825

    
826
void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
827
{
828
    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
829
}
830

    
831
uint32_t cpu_ppc601_load_rtcl (CPUState *env)
832
{
833
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
834
}
835

    
836
/*****************************************************************************/
837
/* Embedded PowerPC timers */
838

    
839
/* PIT, FIT & WDT */
840
typedef struct ppcemb_timer_t ppcemb_timer_t;
841
struct ppcemb_timer_t {
842
    uint64_t pit_reload;  /* PIT auto-reload value        */
843
    uint64_t fit_next;    /* Tick for next FIT interrupt  */
844
    struct QEMUTimer *fit_timer;
845
    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
846
    struct QEMUTimer *wdt_timer;
847
};
848

    
849
/* Fixed interval timer */
850
static void cpu_4xx_fit_cb (void *opaque)
851
{
852
    CPUState *env;
853
    ppc_tb_t *tb_env;
854
    ppcemb_timer_t *ppcemb_timer;
855
    uint64_t now, next;
856

    
857
    env = opaque;
858
    tb_env = env->tb_env;
859
    ppcemb_timer = tb_env->opaque;
860
    now = qemu_get_clock(vm_clock);
861
    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
862
    case 0:
863
        next = 1 << 9;
864
        break;
865
    case 1:
866
        next = 1 << 13;
867
        break;
868
    case 2:
869
        next = 1 << 17;
870
        break;
871
    case 3:
872
        next = 1 << 21;
873
        break;
874
    default:
875
        /* Cannot occur, but makes gcc happy */
876
        return;
877
    }
878
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
879
    if (next == now)
880
        next++;
881
    qemu_mod_timer(ppcemb_timer->fit_timer, next);
882
    env->spr[SPR_40x_TSR] |= 1 << 26;
883
    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
884
        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
885
#ifdef PPC_DEBUG_TB
886
    if (loglevel != 0) {
887
        fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
888
                (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
889
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
890
    }
891
#endif
892
}
893

    
894
/* Programmable interval timer */
895
static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
896
{
897
    ppcemb_timer_t *ppcemb_timer;
898
    uint64_t now, next;
899

    
900
    ppcemb_timer = tb_env->opaque;
901
    if (ppcemb_timer->pit_reload <= 1 ||
902
        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
903
        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
904
        /* Stop PIT */
905
#ifdef PPC_DEBUG_TB
906
        if (loglevel != 0) {
907
            fprintf(logfile, "%s: stop PIT\n", __func__);
908
        }
909
#endif
910
        qemu_del_timer(tb_env->decr_timer);
911
    } else {
912
#ifdef PPC_DEBUG_TB
913
        if (loglevel != 0) {
914
            fprintf(logfile, "%s: start PIT %016" PRIx64 "\n",
915
                    __func__, ppcemb_timer->pit_reload);
916
        }
917
#endif
918
        now = qemu_get_clock(vm_clock);
919
        next = now + muldiv64(ppcemb_timer->pit_reload,
920
                              ticks_per_sec, tb_env->decr_freq);
921
        if (is_excp)
922
            next += tb_env->decr_next - now;
923
        if (next == now)
924
            next++;
925
        qemu_mod_timer(tb_env->decr_timer, next);
926
        tb_env->decr_next = next;
927
    }
928
}
929

    
930
static void cpu_4xx_pit_cb (void *opaque)
931
{
932
    CPUState *env;
933
    ppc_tb_t *tb_env;
934
    ppcemb_timer_t *ppcemb_timer;
935

    
936
    env = opaque;
937
    tb_env = env->tb_env;
938
    ppcemb_timer = tb_env->opaque;
939
    env->spr[SPR_40x_TSR] |= 1 << 27;
940
    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
941
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
942
    start_stop_pit(env, tb_env, 1);
943
#ifdef PPC_DEBUG_TB
944
    if (loglevel != 0) {
945
        fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
946
                "%016" PRIx64 "\n", __func__,
947
                (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
948
                (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
949
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
950
                ppcemb_timer->pit_reload);
951
    }
952
#endif
953
}
954

    
955
/* Watchdog timer */
956
static void cpu_4xx_wdt_cb (void *opaque)
957
{
958
    CPUState *env;
959
    ppc_tb_t *tb_env;
960
    ppcemb_timer_t *ppcemb_timer;
961
    uint64_t now, next;
962

    
963
    env = opaque;
964
    tb_env = env->tb_env;
965
    ppcemb_timer = tb_env->opaque;
966
    now = qemu_get_clock(vm_clock);
967
    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
968
    case 0:
969
        next = 1 << 17;
970
        break;
971
    case 1:
972
        next = 1 << 21;
973
        break;
974
    case 2:
975
        next = 1 << 25;
976
        break;
977
    case 3:
978
        next = 1 << 29;
979
        break;
980
    default:
981
        /* Cannot occur, but makes gcc happy */
982
        return;
983
    }
984
    next = now + muldiv64(next, ticks_per_sec, tb_env->decr_freq);
985
    if (next == now)
986
        next++;
987
#ifdef PPC_DEBUG_TB
988
    if (loglevel != 0) {
989
        fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
990
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
991
    }
992
#endif
993
    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
994
    case 0x0:
995
    case 0x1:
996
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
997
        ppcemb_timer->wdt_next = next;
998
        env->spr[SPR_40x_TSR] |= 1 << 31;
999
        break;
1000
    case 0x2:
1001
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
1002
        ppcemb_timer->wdt_next = next;
1003
        env->spr[SPR_40x_TSR] |= 1 << 30;
1004
        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
1005
            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
1006
        break;
1007
    case 0x3:
1008
        env->spr[SPR_40x_TSR] &= ~0x30000000;
1009
        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
1010
        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
1011
        case 0x0:
1012
            /* No reset */
1013
            break;
1014
        case 0x1: /* Core reset */
1015
            ppc40x_core_reset(env);
1016
            break;
1017
        case 0x2: /* Chip reset */
1018
            ppc40x_chip_reset(env);
1019
            break;
1020
        case 0x3: /* System reset */
1021
            ppc40x_system_reset(env);
1022
            break;
1023
        }
1024
    }
1025
}
1026

    
1027
void store_40x_pit (CPUState *env, target_ulong val)
1028
{
1029
    ppc_tb_t *tb_env;
1030
    ppcemb_timer_t *ppcemb_timer;
1031

    
1032
    tb_env = env->tb_env;
1033
    ppcemb_timer = tb_env->opaque;
1034
#ifdef PPC_DEBUG_TB
1035
    if (loglevel != 0) {
1036
        fprintf(logfile, "%s val" ADDRX "\n", __func__, val);
1037
    }
1038
#endif
1039
    ppcemb_timer->pit_reload = val;
1040
    start_stop_pit(env, tb_env, 0);
1041
}
1042

    
1043
target_ulong load_40x_pit (CPUState *env)
1044
{
1045
    return cpu_ppc_load_decr(env);
1046
}
1047

    
1048
void store_booke_tsr (CPUState *env, target_ulong val)
1049
{
1050
#ifdef PPC_DEBUG_TB
1051
    if (loglevel != 0) {
1052
        fprintf(logfile, "%s: val " ADDRX "\n", __func__, val);
1053
    }
1054
#endif
1055
    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
1056
    if (val & 0x80000000)
1057
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
1058
}
1059

    
1060
void store_booke_tcr (CPUState *env, target_ulong val)
1061
{
1062
    ppc_tb_t *tb_env;
1063

    
1064
    tb_env = env->tb_env;
1065
#ifdef PPC_DEBUG_TB
1066
    if (loglevel != 0) {
1067
        fprintf(logfile, "%s: val " ADDRX "\n", __func__, val);
1068
    }
1069
#endif
1070
    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1071
    start_stop_pit(env, tb_env, 1);
1072
    cpu_4xx_wdt_cb(env);
1073
}
1074

    
1075
static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
1076
{
1077
    CPUState *env = opaque;
1078
    ppc_tb_t *tb_env = env->tb_env;
1079

    
1080
#ifdef PPC_DEBUG_TB
1081
    if (loglevel != 0) {
1082
        fprintf(logfile, "%s set new frequency to %" PRIu32 "\n", __func__,
1083
                freq);
1084
    }
1085
#endif
1086
    tb_env->tb_freq = freq;
1087
    tb_env->decr_freq = freq;
1088
    /* XXX: we should also update all timers */
1089
}
1090

    
1091
clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
1092
{
1093
    ppc_tb_t *tb_env;
1094
    ppcemb_timer_t *ppcemb_timer;
1095

    
1096
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
1097
    if (tb_env == NULL) {
1098
        return NULL;
1099
    }
1100
    env->tb_env = tb_env;
1101
    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
1102
    tb_env->tb_freq = freq;
1103
    tb_env->decr_freq = freq;
1104
    tb_env->opaque = ppcemb_timer;
1105
#ifdef PPC_DEBUG_TB
1106
    if (loglevel != 0) {
1107
        fprintf(logfile, "%s freq %" PRIu32 "\n", __func__, freq);
1108
    }
1109
#endif
1110
    if (ppcemb_timer != NULL) {
1111
        /* We use decr timer for PIT */
1112
        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
1113
        ppcemb_timer->fit_timer =
1114
            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
1115
        ppcemb_timer->wdt_timer =
1116
            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
1117
    }
1118

    
1119
    return &ppc_emb_set_tb_clk;
1120
}
1121

    
1122
/*****************************************************************************/
1123
/* Embedded PowerPC Device Control Registers */
1124
typedef struct ppc_dcrn_t ppc_dcrn_t;
1125
struct ppc_dcrn_t {
1126
    dcr_read_cb dcr_read;
1127
    dcr_write_cb dcr_write;
1128
    void *opaque;
1129
};
1130

    
1131
/* XXX: on 460, DCR addresses are 32 bits wide,
1132
 *      using DCRIPR to get the 22 upper bits of the DCR address
1133
 */
1134
#define DCRN_NB 1024
1135
struct ppc_dcr_t {
1136
    ppc_dcrn_t dcrn[DCRN_NB];
1137
    int (*read_error)(int dcrn);
1138
    int (*write_error)(int dcrn);
1139
};
1140

    
1141
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
1142
{
1143
    ppc_dcrn_t *dcr;
1144

    
1145
    if (dcrn < 0 || dcrn >= DCRN_NB)
1146
        goto error;
1147
    dcr = &dcr_env->dcrn[dcrn];
1148
    if (dcr->dcr_read == NULL)
1149
        goto error;
1150
    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1151

    
1152
    return 0;
1153

    
1154
 error:
1155
    if (dcr_env->read_error != NULL)
1156
        return (*dcr_env->read_error)(dcrn);
1157

    
1158
    return -1;
1159
}
1160

    
1161
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
1162
{
1163
    ppc_dcrn_t *dcr;
1164

    
1165
    if (dcrn < 0 || dcrn >= DCRN_NB)
1166
        goto error;
1167
    dcr = &dcr_env->dcrn[dcrn];
1168
    if (dcr->dcr_write == NULL)
1169
        goto error;
1170
    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
1171

    
1172
    return 0;
1173

    
1174
 error:
1175
    if (dcr_env->write_error != NULL)
1176
        return (*dcr_env->write_error)(dcrn);
1177

    
1178
    return -1;
1179
}
1180

    
1181
int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
1182
                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
1183
{
1184
    ppc_dcr_t *dcr_env;
1185
    ppc_dcrn_t *dcr;
1186

    
1187
    dcr_env = env->dcr_env;
1188
    if (dcr_env == NULL)
1189
        return -1;
1190
    if (dcrn < 0 || dcrn >= DCRN_NB)
1191
        return -1;
1192
    dcr = &dcr_env->dcrn[dcrn];
1193
    if (dcr->opaque != NULL ||
1194
        dcr->dcr_read != NULL ||
1195
        dcr->dcr_write != NULL)
1196
        return -1;
1197
    dcr->opaque = opaque;
1198
    dcr->dcr_read = dcr_read;
1199
    dcr->dcr_write = dcr_write;
1200

    
1201
    return 0;
1202
}
1203

    
1204
int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
1205
                  int (*write_error)(int dcrn))
1206
{
1207
    ppc_dcr_t *dcr_env;
1208

    
1209
    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
1210
    if (dcr_env == NULL)
1211
        return -1;
1212
    dcr_env->read_error = read_error;
1213
    dcr_env->write_error = write_error;
1214
    env->dcr_env = dcr_env;
1215

    
1216
    return 0;
1217
}
1218

    
1219
#if 0
1220
/*****************************************************************************/
1221
/* Handle system reset (for now, just stop emulation) */
1222
void cpu_ppc_reset (CPUState *env)
1223
{
1224
    printf("Reset asked... Stop emulation\n");
1225
    abort();
1226
}
1227
#endif
1228

    
1229
/*****************************************************************************/
1230
/* Debug port */
1231
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
1232
{
1233
    addr &= 0xF;
1234
    switch (addr) {
1235
    case 0:
1236
        printf("%c", val);
1237
        break;
1238
    case 1:
1239
        printf("\n");
1240
        fflush(stdout);
1241
        break;
1242
    case 2:
1243
        printf("Set loglevel to %04" PRIx32 "\n", val);
1244
        cpu_set_log(val | 0x100);
1245
        break;
1246
    }
1247
}
1248

    
1249
/*****************************************************************************/
1250
/* NVRAM helpers */
1251
static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
1252
{
1253
    return (*nvram->read_fn)(nvram->opaque, addr);;
1254
}
1255

    
1256
static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
1257
{
1258
    (*nvram->write_fn)(nvram->opaque, addr, val);
1259
}
1260

    
1261
void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
1262
{
1263
    nvram_write(nvram, addr, value);
1264
}
1265

    
1266
uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr)
1267
{
1268
    return nvram_read(nvram, addr);
1269
}
1270

    
1271
void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value)
1272
{
1273
    nvram_write(nvram, addr, value >> 8);
1274
    nvram_write(nvram, addr + 1, value & 0xFF);
1275
}
1276

    
1277
uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr)
1278
{
1279
    uint16_t tmp;
1280

    
1281
    tmp = nvram_read(nvram, addr) << 8;
1282
    tmp |= nvram_read(nvram, addr + 1);
1283

    
1284
    return tmp;
1285
}
1286

    
1287
void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value)
1288
{
1289
    nvram_write(nvram, addr, value >> 24);
1290
    nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
1291
    nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
1292
    nvram_write(nvram, addr + 3, value & 0xFF);
1293
}
1294

    
1295
uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
1296
{
1297
    uint32_t tmp;
1298

    
1299
    tmp = nvram_read(nvram, addr) << 24;
1300
    tmp |= nvram_read(nvram, addr + 1) << 16;
1301
    tmp |= nvram_read(nvram, addr + 2) << 8;
1302
    tmp |= nvram_read(nvram, addr + 3);
1303

    
1304
    return tmp;
1305
}
1306

    
1307
void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
1308
                       const unsigned char *str, uint32_t max)
1309
{
1310
    int i;
1311

    
1312
    for (i = 0; i < max && str[i] != '\0'; i++) {
1313
        nvram_write(nvram, addr + i, str[i]);
1314
    }
1315
    nvram_write(nvram, addr + i, str[i]);
1316
    nvram_write(nvram, addr + max - 1, '\0');
1317
}
1318

    
1319
int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
1320
{
1321
    int i;
1322

    
1323
    memset(dst, 0, max);
1324
    for (i = 0; i < max; i++) {
1325
        dst[i] = NVRAM_get_byte(nvram, addr + i);
1326
        if (dst[i] == '\0')
1327
            break;
1328
    }
1329

    
1330
    return i;
1331
}
1332

    
1333
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1334
{
1335
    uint16_t tmp;
1336
    uint16_t pd, pd1, pd2;
1337

    
1338
    tmp = prev >> 8;
1339
    pd = prev ^ value;
1340
    pd1 = pd & 0x000F;
1341
    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1342
    tmp ^= (pd1 << 3) | (pd1 << 8);
1343
    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1344

    
1345
    return tmp;
1346
}
1347

    
1348
uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
1349
{
1350
    uint32_t i;
1351
    uint16_t crc = 0xFFFF;
1352
    int odd;
1353

    
1354
    odd = count & 1;
1355
    count &= ~1;
1356
    for (i = 0; i != count; i++) {
1357
        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1358
    }
1359
    if (odd) {
1360
        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1361
    }
1362

    
1363
    return crc;
1364
}
1365

    
1366
#define CMDLINE_ADDR 0x017ff000
1367

    
1368
int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
1369
                          const unsigned char *arch,
1370
                          uint32_t RAM_size, int boot_device,
1371
                          uint32_t kernel_image, uint32_t kernel_size,
1372
                          const char *cmdline,
1373
                          uint32_t initrd_image, uint32_t initrd_size,
1374
                          uint32_t NVRAM_image,
1375
                          int width, int height, int depth)
1376
{
1377
    uint16_t crc;
1378

    
1379
    /* Set parameters for Open Hack'Ware BIOS */
1380
    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1381
    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
1382
    NVRAM_set_word(nvram,   0x14, NVRAM_size);
1383
    NVRAM_set_string(nvram, 0x20, arch, 16);
1384
    NVRAM_set_lword(nvram,  0x30, RAM_size);
1385
    NVRAM_set_byte(nvram,   0x34, boot_device);
1386
    NVRAM_set_lword(nvram,  0x38, kernel_image);
1387
    NVRAM_set_lword(nvram,  0x3C, kernel_size);
1388
    if (cmdline) {
1389
        /* XXX: put the cmdline in NVRAM too ? */
1390
        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
1391
        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
1392
        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
1393
    } else {
1394
        NVRAM_set_lword(nvram,  0x40, 0);
1395
        NVRAM_set_lword(nvram,  0x44, 0);
1396
    }
1397
    NVRAM_set_lword(nvram,  0x48, initrd_image);
1398
    NVRAM_set_lword(nvram,  0x4C, initrd_size);
1399
    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
1400

    
1401
    NVRAM_set_word(nvram,   0x54, width);
1402
    NVRAM_set_word(nvram,   0x56, height);
1403
    NVRAM_set_word(nvram,   0x58, depth);
1404
    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1405
    NVRAM_set_word(nvram,   0xFC, crc);
1406

    
1407
    return 0;
1408
}