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