Statistics
| Branch: | Revision:

root / hw / ppc.c @ b068d6a7

History | View | Annotate | Download (37.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 "vl.h"
25
#include "m48t59.h"
26

    
27
//#define PPC_DEBUG_IRQ
28
//#define PPC_DEBUG_TB
29

    
30
extern FILE *logfile;
31
extern int loglevel;
32

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

    
52
/* PowerPC 6xx / 7xx internal IRQ controller */
53
static void ppc6xx_set_irq (void *opaque, int pin, int level)
54
{
55
    CPUState *env = opaque;
56
    int cur_level;
57

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

    
160
void ppc6xx_irq_init (CPUState *env)
161
{
162
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
163
}
164

    
165
#if defined(TARGET_PPC64)
166
/* PowerPC 970 internal IRQ controller */
167
static void ppc970_set_irq (void *opaque, int pin, int level)
168
{
169
    CPUState *env = opaque;
170
    int cur_level;
171

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

    
283
void ppc970_irq_init (CPUState *env)
284
{
285
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7);
286
}
287
#endif /* defined(TARGET_PPC64) */
288

    
289
/* PowerPC 40x internal IRQ controller */
290
static void ppc40x_set_irq (void *opaque, int pin, int level)
291
{
292
    CPUState *env = opaque;
293
    int cur_level;
294

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

    
401
void ppc40x_irq_init (CPUState *env)
402
{
403
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
404
                                                  env, PPC40x_INPUT_NB);
405
}
406

    
407
/*****************************************************************************/
408
/* PowerPC time base and decrementer emulation */
409
struct ppc_tb_t {
410
    /* Time base management */
411
    int64_t  tb_offset;    /* Compensation               */
412
    int64_t  atb_offset;   /* Compensation               */
413
    uint32_t tb_freq;      /* TB frequency               */
414
    /* Decrementer management */
415
    uint64_t decr_next;    /* Tick for next decr interrupt  */
416
    struct QEMUTimer *decr_timer;
417
#if defined(TARGET_PPC64H)
418
    /* Hypervisor decrementer management */
419
    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
420
    struct QEMUTimer *hdecr_timer;
421
    uint64_t purr_load;
422
    uint64_t purr_start;
423
#endif
424
    void *opaque;
425
};
426

    
427
static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env,
428
                                              int64_t tb_offset)
429
{
430
    /* TB time in tb periods */
431
    return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
432
                    tb_env->tb_freq, ticks_per_sec);
433
}
434

    
435
uint32_t cpu_ppc_load_tbl (CPUState *env)
436
{
437
    ppc_tb_t *tb_env = env->tb_env;
438
    uint64_t tb;
439

    
440
    tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset);
441
#if defined(PPC_DEBUG_TB)
442
    if (loglevel != 0) {
443
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
444
    }
445
#endif
446

    
447
    return tb & 0xFFFFFFFF;
448
}
449

    
450
static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env)
451
{
452
    ppc_tb_t *tb_env = env->tb_env;
453
    uint64_t tb;
454

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

    
462
    return tb >> 32;
463
}
464

    
465
uint32_t cpu_ppc_load_tbu (CPUState *env)
466
{
467
    return _cpu_ppc_load_tbu(env);
468
}
469

    
470
static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env,
471
                                            int64_t *tb_offsetp,
472
                                            uint64_t value)
473
{
474
    *tb_offsetp = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
475
        - qemu_get_clock(vm_clock);
476
#ifdef PPC_DEBUG_TB
477
    if (loglevel != 0) {
478
        fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
479
                *tb_offsetp);
480
    }
481
#endif
482
}
483

    
484
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
485
{
486
    ppc_tb_t *tb_env = env->tb_env;
487
    uint64_t tb;
488

    
489
    tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset);
490
    tb &= 0xFFFFFFFF00000000ULL;
491
    cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, tb | (uint64_t)value);
492
}
493

    
494
static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
495
{
496
    ppc_tb_t *tb_env = env->tb_env;
497
    uint64_t tb;
498

    
499
    tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset);
500
    tb &= 0x00000000FFFFFFFFULL;
501
    cpu_ppc_store_tb(tb_env, &tb_env->tb_offset,
502
                     ((uint64_t)value << 32) | tb);
503
}
504

    
505
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
506
{
507
    _cpu_ppc_store_tbu(env, value);
508
}
509

    
510
uint32_t cpu_ppc_load_atbl (CPUState *env)
511
{
512
    ppc_tb_t *tb_env = env->tb_env;
513
    uint64_t tb;
514

    
515
    tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset);
516
#if defined(PPC_DEBUG_TB)
517
    if (loglevel != 0) {
518
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
519
    }
520
#endif
521

    
522
    return tb & 0xFFFFFFFF;
523
}
524

    
525
uint32_t cpu_ppc_load_atbu (CPUState *env)
526
{
527
    ppc_tb_t *tb_env = env->tb_env;
528
    uint64_t tb;
529

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

    
537
    return tb >> 32;
538
}
539

    
540
void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
541
{
542
    ppc_tb_t *tb_env = env->tb_env;
543
    uint64_t tb;
544

    
545
    tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset);
546
    tb &= 0xFFFFFFFF00000000ULL;
547
    cpu_ppc_store_tb(tb_env, &tb_env->atb_offset, tb | (uint64_t)value);
548
}
549

    
550
void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
551
{
552
    ppc_tb_t *tb_env = env->tb_env;
553
    uint64_t tb;
554

    
555
    tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset);
556
    tb &= 0x00000000FFFFFFFFULL;
557
    cpu_ppc_store_tb(tb_env, &tb_env->atb_offset,
558
                     ((uint64_t)value << 32) | tb);
559
}
560

    
561
static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env,
562
                                                  uint64_t *next)
563
{
564
    ppc_tb_t *tb_env = env->tb_env;
565
    uint32_t decr;
566
    int64_t diff;
567

    
568
    diff = tb_env->decr_next - qemu_get_clock(vm_clock);
569
    if (diff >= 0)
570
        decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
571
    else
572
        decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
573
#if defined(PPC_DEBUG_TB)
574
    if (loglevel != 0) {
575
        fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
576
    }
577
#endif
578

    
579
    return decr;
580
}
581

    
582
uint32_t cpu_ppc_load_decr (CPUState *env)
583
{
584
    ppc_tb_t *tb_env = env->tb_env;
585

    
586
    return _cpu_ppc_load_decr(env, &tb_env->decr_next);
587
}
588

    
589
#if defined(TARGET_PPC64H)
590
uint32_t cpu_ppc_load_hdecr (CPUState *env)
591
{
592
    ppc_tb_t *tb_env = env->tb_env;
593

    
594
    return _cpu_ppc_load_decr(env, &tb_env->hdecr_next);
595
}
596

    
597
uint64_t cpu_ppc_load_purr (CPUState *env)
598
{
599
    ppc_tb_t *tb_env = env->tb_env;
600
    uint64_t diff;
601

    
602
    diff = qemu_get_clock(vm_clock) - tb_env->purr_start;
603
    
604
    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
605
}
606
#endif /* defined(TARGET_PPC64H) */
607

    
608
/* When decrementer expires,
609
 * all we need to do is generate or queue a CPU exception
610
 */
611
static always_inline void cpu_ppc_decr_excp (CPUState *env)
612
{
613
    /* Raise it */
614
#ifdef PPC_DEBUG_TB
615
    if (loglevel != 0) {
616
        fprintf(logfile, "raise decrementer exception\n");
617
    }
618
#endif
619
    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
620
}
621

    
622
static always_inline void cpu_ppc_hdecr_excp (CPUState *env)
623
{
624
    /* Raise it */
625
#ifdef PPC_DEBUG_TB
626
    if (loglevel != 0) {
627
        fprintf(logfile, "raise decrementer exception\n");
628
    }
629
#endif
630
    ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
631
}
632

    
633
static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
634
                                 struct QEMUTimer *timer,
635
                                 void (*raise_excp)(CPUState *),
636
                                 uint32_t decr, uint32_t value,
637
                                 int is_excp)
638
{
639
    ppc_tb_t *tb_env = env->tb_env;
640
    uint64_t now, next;
641

    
642
#ifdef PPC_DEBUG_TB
643
    if (loglevel != 0) {
644
        fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
645
    }
646
#endif
647
    now = qemu_get_clock(vm_clock);
648
    next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
649
    if (is_excp)
650
        next += *nextp - now;
651
    if (next == now)
652
        next++;
653
    *nextp = next;
654
    /* Adjust timer */
655
    qemu_mod_timer(timer, next);
656
    /* If we set a negative value and the decrementer was positive,
657
     * raise an exception.
658
     */
659
    if ((value & 0x80000000) && !(decr & 0x80000000))
660
        (*raise_excp)(env);
661
}
662

    
663
static always_inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
664
                                               uint32_t value, int is_excp)
665
{
666
    ppc_tb_t *tb_env = env->tb_env;
667

    
668
    __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
669
                         &cpu_ppc_decr_excp, decr, value, is_excp);
670
}
671

    
672
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
673
{
674
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
675
}
676

    
677
static void cpu_ppc_decr_cb (void *opaque)
678
{
679
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
680
}
681

    
682
#if defined(TARGET_PPC64H)
683
static always_inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr,
684
                                                uint32_t value, int is_excp)
685
{
686
    ppc_tb_t *tb_env = env->tb_env;
687

    
688
    __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
689
                         &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
690
}
691

    
692
void cpu_ppc_store_hdecr (CPUState *env, uint32_t value)
693
{
694
    _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
695
}
696

    
697
static void cpu_ppc_hdecr_cb (void *opaque)
698
{
699
    _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
700
}
701

    
702
void cpu_ppc_store_purr (CPUState *env, uint64_t value)
703
{
704
    ppc_tb_t *tb_env = env->tb_env;
705

    
706
    tb_env->purr_load = value;
707
    tb_env->purr_start = qemu_get_clock(vm_clock);
708
}
709
#endif /* defined(TARGET_PPC64H) */
710

    
711
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
712
{
713
    CPUState *env = opaque;
714
    ppc_tb_t *tb_env = env->tb_env;
715

    
716
    tb_env->tb_freq = freq;
717
    /* There is a bug in Linux 2.4 kernels:
718
     * if a decrementer exception is pending when it enables msr_ee at startup,
719
     * it's not ready to handle it...
720
     */
721
    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
722
#if defined(TARGET_PPC64H)
723
    _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
724
    cpu_ppc_store_purr(env, 0x0000000000000000ULL);
725
#endif /* defined(TARGET_PPC64H) */
726
}
727

    
728
/* Set up (once) timebase frequency (in Hz) */
729
clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
730
{
731
    ppc_tb_t *tb_env;
732

    
733
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
734
    if (tb_env == NULL)
735
        return NULL;
736
    env->tb_env = tb_env;
737
    /* Create new timer */
738
    tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
739
#if defined(TARGET_PPC64H)
740
    tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env);
741
#endif /* defined(TARGET_PPC64H) */
742
    cpu_ppc_set_tb_clk(env, freq);
743

    
744
    return &cpu_ppc_set_tb_clk;
745
}
746

    
747
/* Specific helpers for POWER & PowerPC 601 RTC */
748
clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
749
{
750
    return cpu_ppc_tb_init(env, 7812500);
751
}
752

    
753
void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
754
{
755
    _cpu_ppc_store_tbu(env, value);
756
}
757

    
758
uint32_t cpu_ppc601_load_rtcu (CPUState *env)
759
{
760
    return _cpu_ppc_load_tbu(env);
761
}
762

    
763
void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
764
{
765
    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
766
}
767

    
768
uint32_t cpu_ppc601_load_rtcl (CPUState *env)
769
{
770
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
771
}
772

    
773
/*****************************************************************************/
774
/* Embedded PowerPC timers */
775

    
776
/* PIT, FIT & WDT */
777
typedef struct ppcemb_timer_t ppcemb_timer_t;
778
struct ppcemb_timer_t {
779
    uint64_t pit_reload;  /* PIT auto-reload value        */
780
    uint64_t fit_next;    /* Tick for next FIT interrupt  */
781
    struct QEMUTimer *fit_timer;
782
    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
783
    struct QEMUTimer *wdt_timer;
784
};
785

    
786
/* Fixed interval timer */
787
static void cpu_4xx_fit_cb (void *opaque)
788
{
789
    CPUState *env;
790
    ppc_tb_t *tb_env;
791
    ppcemb_timer_t *ppcemb_timer;
792
    uint64_t now, next;
793

    
794
    env = opaque;
795
    tb_env = env->tb_env;
796
    ppcemb_timer = tb_env->opaque;
797
    now = qemu_get_clock(vm_clock);
798
    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
799
    case 0:
800
        next = 1 << 9;
801
        break;
802
    case 1:
803
        next = 1 << 13;
804
        break;
805
    case 2:
806
        next = 1 << 17;
807
        break;
808
    case 3:
809
        next = 1 << 21;
810
        break;
811
    default:
812
        /* Cannot occur, but makes gcc happy */
813
        return;
814
    }
815
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
816
    if (next == now)
817
        next++;
818
    qemu_mod_timer(ppcemb_timer->fit_timer, next);
819
    env->spr[SPR_40x_TSR] |= 1 << 26;
820
    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
821
        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
822
#ifdef PPC_DEBUG_TB
823
    if (loglevel != 0) {
824
        fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
825
                (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
826
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
827
    }
828
#endif
829
}
830

    
831
/* Programmable interval timer */
832
static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
833
{
834
    ppcemb_timer_t *ppcemb_timer;
835
    uint64_t now, next;
836

    
837
    ppcemb_timer = tb_env->opaque;
838
    if (ppcemb_timer->pit_reload <= 1 ||
839
        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
840
        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
841
        /* Stop PIT */
842
#ifdef PPC_DEBUG_TB
843
        if (loglevel != 0) {
844
            fprintf(logfile, "%s: stop PIT\n", __func__);
845
        }
846
#endif
847
        qemu_del_timer(tb_env->decr_timer);
848
    } else {
849
#ifdef PPC_DEBUG_TB
850
        if (loglevel != 0) {
851
            fprintf(logfile, "%s: start PIT 0x" REGX "\n",
852
                    __func__, ppcemb_timer->pit_reload);
853
        }
854
#endif
855
        now = qemu_get_clock(vm_clock);
856
        next = now + muldiv64(ppcemb_timer->pit_reload,
857
                              ticks_per_sec, tb_env->tb_freq);
858
        if (is_excp)
859
            next += tb_env->decr_next - now;
860
        if (next == now)
861
            next++;
862
        qemu_mod_timer(tb_env->decr_timer, next);
863
        tb_env->decr_next = next;
864
    }
865
}
866

    
867
static void cpu_4xx_pit_cb (void *opaque)
868
{
869
    CPUState *env;
870
    ppc_tb_t *tb_env;
871
    ppcemb_timer_t *ppcemb_timer;
872

    
873
    env = opaque;
874
    tb_env = env->tb_env;
875
    ppcemb_timer = tb_env->opaque;
876
    env->spr[SPR_40x_TSR] |= 1 << 27;
877
    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
878
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
879
    start_stop_pit(env, tb_env, 1);
880
#ifdef PPC_DEBUG_TB
881
    if (loglevel != 0) {
882
        fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
883
                "%016" PRIx64 "\n", __func__,
884
                (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
885
                (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
886
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
887
                ppcemb_timer->pit_reload);
888
    }
889
#endif
890
}
891

    
892
/* Watchdog timer */
893
static void cpu_4xx_wdt_cb (void *opaque)
894
{
895
    CPUState *env;
896
    ppc_tb_t *tb_env;
897
    ppcemb_timer_t *ppcemb_timer;
898
    uint64_t now, next;
899

    
900
    env = opaque;
901
    tb_env = env->tb_env;
902
    ppcemb_timer = tb_env->opaque;
903
    now = qemu_get_clock(vm_clock);
904
    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
905
    case 0:
906
        next = 1 << 17;
907
        break;
908
    case 1:
909
        next = 1 << 21;
910
        break;
911
    case 2:
912
        next = 1 << 25;
913
        break;
914
    case 3:
915
        next = 1 << 29;
916
        break;
917
    default:
918
        /* Cannot occur, but makes gcc happy */
919
        return;
920
    }
921
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
922
    if (next == now)
923
        next++;
924
#ifdef PPC_DEBUG_TB
925
    if (loglevel != 0) {
926
        fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
927
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
928
    }
929
#endif
930
    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
931
    case 0x0:
932
    case 0x1:
933
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
934
        ppcemb_timer->wdt_next = next;
935
        env->spr[SPR_40x_TSR] |= 1 << 31;
936
        break;
937
    case 0x2:
938
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
939
        ppcemb_timer->wdt_next = next;
940
        env->spr[SPR_40x_TSR] |= 1 << 30;
941
        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
942
            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
943
        break;
944
    case 0x3:
945
        env->spr[SPR_40x_TSR] &= ~0x30000000;
946
        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
947
        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
948
        case 0x0:
949
            /* No reset */
950
            break;
951
        case 0x1: /* Core reset */
952
            ppc40x_core_reset(env);
953
            break;
954
        case 0x2: /* Chip reset */
955
            ppc40x_chip_reset(env);
956
            break;
957
        case 0x3: /* System reset */
958
            ppc40x_system_reset(env);
959
            break;
960
        }
961
    }
962
}
963

    
964
void store_40x_pit (CPUState *env, target_ulong val)
965
{
966
    ppc_tb_t *tb_env;
967
    ppcemb_timer_t *ppcemb_timer;
968

    
969
    tb_env = env->tb_env;
970
    ppcemb_timer = tb_env->opaque;
971
#ifdef PPC_DEBUG_TB
972
    if (loglevel != 0) {
973
        fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
974
    }
975
#endif
976
    ppcemb_timer->pit_reload = val;
977
    start_stop_pit(env, tb_env, 0);
978
}
979

    
980
target_ulong load_40x_pit (CPUState *env)
981
{
982
    return cpu_ppc_load_decr(env);
983
}
984

    
985
void store_booke_tsr (CPUState *env, target_ulong val)
986
{
987
#ifdef PPC_DEBUG_TB
988
    if (loglevel != 0) {
989
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
990
    }
991
#endif
992
    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
993
    if (val & 0x80000000)
994
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
995
}
996

    
997
void store_booke_tcr (CPUState *env, target_ulong val)
998
{
999
    ppc_tb_t *tb_env;
1000

    
1001
    tb_env = env->tb_env;
1002
#ifdef PPC_DEBUG_TB
1003
    if (loglevel != 0) {
1004
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
1005
    }
1006
#endif
1007
    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1008
    start_stop_pit(env, tb_env, 1);
1009
    cpu_4xx_wdt_cb(env);
1010
}
1011

    
1012
static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
1013
{
1014
    CPUState *env = opaque;
1015
    ppc_tb_t *tb_env = env->tb_env;
1016

    
1017
#ifdef PPC_DEBUG_TB
1018
    if (loglevel != 0) {
1019
        fprintf(logfile, "%s set new frequency to %u\n", __func__, freq);
1020
    }
1021
#endif
1022
    tb_env->tb_freq = freq;
1023
    /* XXX: we should also update all timers */
1024
}
1025

    
1026
clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
1027
{
1028
    ppc_tb_t *tb_env;
1029
    ppcemb_timer_t *ppcemb_timer;
1030

    
1031
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
1032
    if (tb_env == NULL) {
1033
        return NULL;
1034
    }
1035
    env->tb_env = tb_env;
1036
    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
1037
    tb_env->tb_freq = freq;
1038
    tb_env->opaque = ppcemb_timer;
1039
#ifdef PPC_DEBUG_TB
1040
    if (loglevel != 0) {
1041
        fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer,
1042
                &ppc_emb_set_tb_clk);
1043
    }
1044
#endif
1045
    if (ppcemb_timer != NULL) {
1046
        /* We use decr timer for PIT */
1047
        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
1048
        ppcemb_timer->fit_timer =
1049
            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
1050
        ppcemb_timer->wdt_timer =
1051
            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
1052
    }
1053

    
1054
    return &ppc_emb_set_tb_clk;
1055
}
1056

    
1057
/*****************************************************************************/
1058
/* Embedded PowerPC Device Control Registers */
1059
typedef struct ppc_dcrn_t ppc_dcrn_t;
1060
struct ppc_dcrn_t {
1061
    dcr_read_cb dcr_read;
1062
    dcr_write_cb dcr_write;
1063
    void *opaque;
1064
};
1065

    
1066
/* XXX: on 460, DCR addresses are 32 bits wide,
1067
 *      using DCRIPR to get the 22 upper bits of the DCR address
1068
 */
1069
#define DCRN_NB 1024
1070
struct ppc_dcr_t {
1071
    ppc_dcrn_t dcrn[DCRN_NB];
1072
    int (*read_error)(int dcrn);
1073
    int (*write_error)(int dcrn);
1074
};
1075

    
1076
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
1077
{
1078
    ppc_dcrn_t *dcr;
1079

    
1080
    if (dcrn < 0 || dcrn >= DCRN_NB)
1081
        goto error;
1082
    dcr = &dcr_env->dcrn[dcrn];
1083
    if (dcr->dcr_read == NULL)
1084
        goto error;
1085
    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1086

    
1087
    return 0;
1088

    
1089
 error:
1090
    if (dcr_env->read_error != NULL)
1091
        return (*dcr_env->read_error)(dcrn);
1092

    
1093
    return -1;
1094
}
1095

    
1096
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
1097
{
1098
    ppc_dcrn_t *dcr;
1099

    
1100
    if (dcrn < 0 || dcrn >= DCRN_NB)
1101
        goto error;
1102
    dcr = &dcr_env->dcrn[dcrn];
1103
    if (dcr->dcr_write == NULL)
1104
        goto error;
1105
    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
1106

    
1107
    return 0;
1108

    
1109
 error:
1110
    if (dcr_env->write_error != NULL)
1111
        return (*dcr_env->write_error)(dcrn);
1112

    
1113
    return -1;
1114
}
1115

    
1116
int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
1117
                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
1118
{
1119
    ppc_dcr_t *dcr_env;
1120
    ppc_dcrn_t *dcr;
1121

    
1122
    dcr_env = env->dcr_env;
1123
    if (dcr_env == NULL)
1124
        return -1;
1125
    if (dcrn < 0 || dcrn >= DCRN_NB)
1126
        return -1;
1127
    dcr = &dcr_env->dcrn[dcrn];
1128
    if (dcr->opaque != NULL ||
1129
        dcr->dcr_read != NULL ||
1130
        dcr->dcr_write != NULL)
1131
        return -1;
1132
    dcr->opaque = opaque;
1133
    dcr->dcr_read = dcr_read;
1134
    dcr->dcr_write = dcr_write;
1135

    
1136
    return 0;
1137
}
1138

    
1139
int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
1140
                  int (*write_error)(int dcrn))
1141
{
1142
    ppc_dcr_t *dcr_env;
1143

    
1144
    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
1145
    if (dcr_env == NULL)
1146
        return -1;
1147
    dcr_env->read_error = read_error;
1148
    dcr_env->write_error = write_error;
1149
    env->dcr_env = dcr_env;
1150

    
1151
    return 0;
1152
}
1153

    
1154

    
1155
#if 0
1156
/*****************************************************************************/
1157
/* Handle system reset (for now, just stop emulation) */
1158
void cpu_ppc_reset (CPUState *env)
1159
{
1160
    printf("Reset asked... Stop emulation\n");
1161
    abort();
1162
}
1163
#endif
1164

    
1165
/*****************************************************************************/
1166
/* Debug port */
1167
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
1168
{
1169
    addr &= 0xF;
1170
    switch (addr) {
1171
    case 0:
1172
        printf("%c", val);
1173
        break;
1174
    case 1:
1175
        printf("\n");
1176
        fflush(stdout);
1177
        break;
1178
    case 2:
1179
        printf("Set loglevel to %04x\n", val);
1180
        cpu_set_log(val | 0x100);
1181
        break;
1182
    }
1183
}
1184

    
1185
/*****************************************************************************/
1186
/* NVRAM helpers */
1187
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
1188
{
1189
    m48t59_write(nvram, addr, value);
1190
}
1191

    
1192
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
1193
{
1194
    return m48t59_read(nvram, addr);
1195
}
1196

    
1197
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
1198
{
1199
    m48t59_write(nvram, addr, value >> 8);
1200
    m48t59_write(nvram, addr + 1, value & 0xFF);
1201
}
1202

    
1203
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
1204
{
1205
    uint16_t tmp;
1206

    
1207
    tmp = m48t59_read(nvram, addr) << 8;
1208
    tmp |= m48t59_read(nvram, addr + 1);
1209
    return tmp;
1210
}
1211

    
1212
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
1213
{
1214
    m48t59_write(nvram, addr, value >> 24);
1215
    m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
1216
    m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
1217
    m48t59_write(nvram, addr + 3, value & 0xFF);
1218
}
1219

    
1220
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
1221
{
1222
    uint32_t tmp;
1223

    
1224
    tmp = m48t59_read(nvram, addr) << 24;
1225
    tmp |= m48t59_read(nvram, addr + 1) << 16;
1226
    tmp |= m48t59_read(nvram, addr + 2) << 8;
1227
    tmp |= m48t59_read(nvram, addr + 3);
1228

    
1229
    return tmp;
1230
}
1231

    
1232
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
1233
                       const unsigned char *str, uint32_t max)
1234
{
1235
    int i;
1236

    
1237
    for (i = 0; i < max && str[i] != '\0'; i++) {
1238
        m48t59_write(nvram, addr + i, str[i]);
1239
    }
1240
    m48t59_write(nvram, addr + max - 1, '\0');
1241
}
1242

    
1243
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
1244
{
1245
    int i;
1246

    
1247
    memset(dst, 0, max);
1248
    for (i = 0; i < max; i++) {
1249
        dst[i] = NVRAM_get_byte(nvram, addr + i);
1250
        if (dst[i] == '\0')
1251
            break;
1252
    }
1253

    
1254
    return i;
1255
}
1256

    
1257
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1258
{
1259
    uint16_t tmp;
1260
    uint16_t pd, pd1, pd2;
1261

    
1262
    tmp = prev >> 8;
1263
    pd = prev ^ value;
1264
    pd1 = pd & 0x000F;
1265
    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1266
    tmp ^= (pd1 << 3) | (pd1 << 8);
1267
    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1268

    
1269
    return tmp;
1270
}
1271

    
1272
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
1273
{
1274
    uint32_t i;
1275
    uint16_t crc = 0xFFFF;
1276
    int odd;
1277

    
1278
    odd = count & 1;
1279
    count &= ~1;
1280
    for (i = 0; i != count; i++) {
1281
        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1282
    }
1283
    if (odd) {
1284
        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1285
    }
1286

    
1287
    return crc;
1288
}
1289

    
1290
#define CMDLINE_ADDR 0x017ff000
1291

    
1292
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
1293
                          const unsigned char *arch,
1294
                          uint32_t RAM_size, int boot_device,
1295
                          uint32_t kernel_image, uint32_t kernel_size,
1296
                          const char *cmdline,
1297
                          uint32_t initrd_image, uint32_t initrd_size,
1298
                          uint32_t NVRAM_image,
1299
                          int width, int height, int depth)
1300
{
1301
    uint16_t crc;
1302

    
1303
    /* Set parameters for Open Hack'Ware BIOS */
1304
    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1305
    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
1306
    NVRAM_set_word(nvram,   0x14, NVRAM_size);
1307
    NVRAM_set_string(nvram, 0x20, arch, 16);
1308
    NVRAM_set_lword(nvram,  0x30, RAM_size);
1309
    NVRAM_set_byte(nvram,   0x34, boot_device);
1310
    NVRAM_set_lword(nvram,  0x38, kernel_image);
1311
    NVRAM_set_lword(nvram,  0x3C, kernel_size);
1312
    if (cmdline) {
1313
        /* XXX: put the cmdline in NVRAM too ? */
1314
        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
1315
        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
1316
        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
1317
    } else {
1318
        NVRAM_set_lword(nvram,  0x40, 0);
1319
        NVRAM_set_lword(nvram,  0x44, 0);
1320
    }
1321
    NVRAM_set_lword(nvram,  0x48, initrd_image);
1322
    NVRAM_set_lword(nvram,  0x4C, initrd_size);
1323
    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
1324

    
1325
    NVRAM_set_word(nvram,   0x54, width);
1326
    NVRAM_set_word(nvram,   0x56, height);
1327
    NVRAM_set_word(nvram,   0x58, depth);
1328
    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1329
    NVRAM_set_word(nvram,  0xFC, crc);
1330

    
1331
    return 0;
1332
}