Update Sparc parts in documentation
[qemu/qemu_0_9_1_stable.git] / hw / ppc.c
blob742d3de59152cef05bf996960453451eb0455ffd
1 /*
2 * QEMU generic PowerPC hardware System Emulator
4 * Copyright (c) 2003-2007 Jocelyn Mayer
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #include "vl.h"
25 #include "m48t59.h"
27 //#define PPC_DEBUG_IRQ
28 //#define PPC_DEBUG_TB
30 extern FILE *logfile;
31 extern int loglevel;
33 static void cpu_ppc_tb_stop (CPUState *env);
34 static void cpu_ppc_tb_start (CPUState *env);
36 static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
38 if (level) {
39 env->pending_interrupts |= 1 << n_IRQ;
40 cpu_interrupt(env, CPU_INTERRUPT_HARD);
41 } else {
42 env->pending_interrupts &= ~(1 << n_IRQ);
43 if (env->pending_interrupts == 0)
44 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
46 #if defined(PPC_DEBUG_IRQ)
47 if (loglevel & CPU_LOG_INT) {
48 fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08x req %08x\n",
49 __func__, env, n_IRQ, level,
50 env->pending_interrupts, env->interrupt_request);
52 #endif
55 /* PowerPC 6xx / 7xx internal IRQ controller */
56 static void ppc6xx_set_irq (void *opaque, int pin, int level)
58 CPUState *env = opaque;
59 int cur_level;
61 #if defined(PPC_DEBUG_IRQ)
62 if (loglevel & CPU_LOG_INT) {
63 fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
64 env, pin, level);
66 #endif
67 cur_level = (env->irq_input_state >> pin) & 1;
68 /* Don't generate spurious events */
69 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
70 switch (pin) {
71 case PPC6xx_INPUT_TBEN:
72 /* Level sensitive - active high */
73 #if defined(PPC_DEBUG_IRQ)
74 if (loglevel & CPU_LOG_INT) {
75 fprintf(logfile, "%s: %s the time base\n",
76 __func__, level ? "start" : "stop");
78 #endif
79 if (level) {
80 cpu_ppc_tb_start(env);
81 } else {
82 cpu_ppc_tb_stop(env);
84 case PPC6xx_INPUT_INT:
85 /* Level sensitive - active high */
86 #if defined(PPC_DEBUG_IRQ)
87 if (loglevel & CPU_LOG_INT) {
88 fprintf(logfile, "%s: set the external IRQ state to %d\n",
89 __func__, level);
91 #endif
92 ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
93 break;
94 case PPC6xx_INPUT_SMI:
95 /* Level sensitive - active high */
96 #if defined(PPC_DEBUG_IRQ)
97 if (loglevel & CPU_LOG_INT) {
98 fprintf(logfile, "%s: set the SMI IRQ state to %d\n",
99 __func__, level);
101 #endif
102 ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
103 break;
104 case PPC6xx_INPUT_MCP:
105 /* Negative edge sensitive */
106 /* XXX: TODO: actual reaction may depends on HID0 status
107 * 603/604/740/750: check HID0[EMCP]
109 if (cur_level == 1 && level == 0) {
110 #if defined(PPC_DEBUG_IRQ)
111 if (loglevel & CPU_LOG_INT) {
112 fprintf(logfile, "%s: raise machine check state\n",
113 __func__);
115 #endif
116 ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
118 break;
119 case PPC6xx_INPUT_CKSTP_IN:
120 /* Level sensitive - active low */
121 /* XXX: TODO: relay the signal to CKSTP_OUT pin */
122 /* XXX: Note that the only way to restart the CPU is to reset it */
123 if (level) {
124 #if defined(PPC_DEBUG_IRQ)
125 if (loglevel & CPU_LOG_INT) {
126 fprintf(logfile, "%s: stop the CPU\n", __func__);
128 #endif
129 env->halted = 1;
131 break;
132 case PPC6xx_INPUT_HRESET:
133 /* Level sensitive - active low */
134 if (level) {
135 #if 0 // XXX: TOFIX
136 #if defined(PPC_DEBUG_IRQ)
137 if (loglevel & CPU_LOG_INT) {
138 fprintf(logfile, "%s: reset the CPU\n", __func__);
140 #endif
141 cpu_reset(env);
142 #endif
144 break;
145 case PPC6xx_INPUT_SRESET:
146 #if defined(PPC_DEBUG_IRQ)
147 if (loglevel & CPU_LOG_INT) {
148 fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
149 __func__, level);
151 #endif
152 ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
153 break;
154 default:
155 /* Unknown pin - do nothing */
156 #if defined(PPC_DEBUG_IRQ)
157 if (loglevel & CPU_LOG_INT) {
158 fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
160 #endif
161 return;
163 if (level)
164 env->irq_input_state |= 1 << pin;
165 else
166 env->irq_input_state &= ~(1 << pin);
170 void ppc6xx_irq_init (CPUState *env)
172 env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
175 #if defined(TARGET_PPC64)
176 /* PowerPC 970 internal IRQ controller */
177 static void ppc970_set_irq (void *opaque, int pin, int level)
179 CPUState *env = opaque;
180 int cur_level;
182 #if defined(PPC_DEBUG_IRQ)
183 if (loglevel & CPU_LOG_INT) {
184 fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
185 env, pin, level);
187 #endif
188 cur_level = (env->irq_input_state >> pin) & 1;
189 /* Don't generate spurious events */
190 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
191 switch (pin) {
192 case PPC970_INPUT_INT:
193 /* Level sensitive - active high */
194 #if defined(PPC_DEBUG_IRQ)
195 if (loglevel & CPU_LOG_INT) {
196 fprintf(logfile, "%s: set the external IRQ state to %d\n",
197 __func__, level);
199 #endif
200 ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
201 break;
202 case PPC970_INPUT_THINT:
203 /* Level sensitive - active high */
204 #if defined(PPC_DEBUG_IRQ)
205 if (loglevel & CPU_LOG_INT) {
206 fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__,
207 level);
209 #endif
210 ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
211 break;
212 case PPC970_INPUT_MCP:
213 /* Negative edge sensitive */
214 /* XXX: TODO: actual reaction may depends on HID0 status
215 * 603/604/740/750: check HID0[EMCP]
217 if (cur_level == 1 && level == 0) {
218 #if defined(PPC_DEBUG_IRQ)
219 if (loglevel & CPU_LOG_INT) {
220 fprintf(logfile, "%s: raise machine check state\n",
221 __func__);
223 #endif
224 ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
226 break;
227 case PPC970_INPUT_CKSTP:
228 /* Level sensitive - active low */
229 /* XXX: TODO: relay the signal to CKSTP_OUT pin */
230 if (level) {
231 #if defined(PPC_DEBUG_IRQ)
232 if (loglevel & CPU_LOG_INT) {
233 fprintf(logfile, "%s: stop the CPU\n", __func__);
235 #endif
236 env->halted = 1;
237 } else {
238 #if defined(PPC_DEBUG_IRQ)
239 if (loglevel & CPU_LOG_INT) {
240 fprintf(logfile, "%s: restart the CPU\n", __func__);
242 #endif
243 env->halted = 0;
245 break;
246 case PPC970_INPUT_HRESET:
247 /* Level sensitive - active low */
248 if (level) {
249 #if 0 // XXX: TOFIX
250 #if defined(PPC_DEBUG_IRQ)
251 if (loglevel & CPU_LOG_INT) {
252 fprintf(logfile, "%s: reset the CPU\n", __func__);
254 #endif
255 cpu_reset(env);
256 #endif
258 break;
259 case PPC970_INPUT_SRESET:
260 #if defined(PPC_DEBUG_IRQ)
261 if (loglevel & CPU_LOG_INT) {
262 fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
263 __func__, level);
265 #endif
266 ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
267 break;
268 case PPC970_INPUT_TBEN:
269 #if defined(PPC_DEBUG_IRQ)
270 if (loglevel & CPU_LOG_INT) {
271 fprintf(logfile, "%s: set the TBEN state to %d\n", __func__,
272 level);
274 #endif
275 /* XXX: TODO */
276 break;
277 default:
278 /* Unknown pin - do nothing */
279 #if defined(PPC_DEBUG_IRQ)
280 if (loglevel & CPU_LOG_INT) {
281 fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
283 #endif
284 return;
286 if (level)
287 env->irq_input_state |= 1 << pin;
288 else
289 env->irq_input_state &= ~(1 << pin);
293 void ppc970_irq_init (CPUState *env)
295 env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7);
297 #endif /* defined(TARGET_PPC64) */
299 /* PowerPC 40x internal IRQ controller */
300 static void ppc40x_set_irq (void *opaque, int pin, int level)
302 CPUState *env = opaque;
303 int cur_level;
305 #if defined(PPC_DEBUG_IRQ)
306 if (loglevel & CPU_LOG_INT) {
307 fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
308 env, pin, level);
310 #endif
311 cur_level = (env->irq_input_state >> pin) & 1;
312 /* Don't generate spurious events */
313 if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
314 switch (pin) {
315 case PPC40x_INPUT_RESET_SYS:
316 if (level) {
317 #if defined(PPC_DEBUG_IRQ)
318 if (loglevel & CPU_LOG_INT) {
319 fprintf(logfile, "%s: reset the PowerPC system\n",
320 __func__);
322 #endif
323 ppc40x_system_reset(env);
325 break;
326 case PPC40x_INPUT_RESET_CHIP:
327 if (level) {
328 #if defined(PPC_DEBUG_IRQ)
329 if (loglevel & CPU_LOG_INT) {
330 fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
332 #endif
333 ppc40x_chip_reset(env);
335 break;
336 case PPC40x_INPUT_RESET_CORE:
337 /* XXX: TODO: update DBSR[MRR] */
338 if (level) {
339 #if defined(PPC_DEBUG_IRQ)
340 if (loglevel & CPU_LOG_INT) {
341 fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
343 #endif
344 ppc40x_core_reset(env);
346 break;
347 case PPC40x_INPUT_CINT:
348 /* Level sensitive - active high */
349 #if defined(PPC_DEBUG_IRQ)
350 if (loglevel & CPU_LOG_INT) {
351 fprintf(logfile, "%s: set the critical IRQ state to %d\n",
352 __func__, level);
354 #endif
355 ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
356 break;
357 case PPC40x_INPUT_INT:
358 /* Level sensitive - active high */
359 #if defined(PPC_DEBUG_IRQ)
360 if (loglevel & CPU_LOG_INT) {
361 fprintf(logfile, "%s: set the external IRQ state to %d\n",
362 __func__, level);
364 #endif
365 ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
366 break;
367 case PPC40x_INPUT_HALT:
368 /* Level sensitive - active low */
369 if (level) {
370 #if defined(PPC_DEBUG_IRQ)
371 if (loglevel & CPU_LOG_INT) {
372 fprintf(logfile, "%s: stop the CPU\n", __func__);
374 #endif
375 env->halted = 1;
376 } else {
377 #if defined(PPC_DEBUG_IRQ)
378 if (loglevel & CPU_LOG_INT) {
379 fprintf(logfile, "%s: restart the CPU\n", __func__);
381 #endif
382 env->halted = 0;
384 break;
385 case PPC40x_INPUT_DEBUG:
386 /* Level sensitive - active high */
387 #if defined(PPC_DEBUG_IRQ)
388 if (loglevel & CPU_LOG_INT) {
389 fprintf(logfile, "%s: set the debug pin state to %d\n",
390 __func__, level);
392 #endif
393 ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
394 break;
395 default:
396 /* Unknown pin - do nothing */
397 #if defined(PPC_DEBUG_IRQ)
398 if (loglevel & CPU_LOG_INT) {
399 fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
401 #endif
402 return;
404 if (level)
405 env->irq_input_state |= 1 << pin;
406 else
407 env->irq_input_state &= ~(1 << pin);
411 void ppc40x_irq_init (CPUState *env)
413 env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
414 env, PPC40x_INPUT_NB);
417 /*****************************************************************************/
418 /* PowerPC time base and decrementer emulation */
419 struct ppc_tb_t {
420 /* Time base management */
421 int64_t tb_offset; /* Compensation */
422 int64_t atb_offset; /* Compensation */
423 uint32_t tb_freq; /* TB frequency */
424 /* Decrementer management */
425 uint64_t decr_next; /* Tick for next decr interrupt */
426 uint32_t decr_freq; /* decrementer frequency */
427 struct QEMUTimer *decr_timer;
428 #if defined(TARGET_PPC64H)
429 /* Hypervisor decrementer management */
430 uint64_t hdecr_next; /* Tick for next hdecr interrupt */
431 struct QEMUTimer *hdecr_timer;
432 uint64_t purr_load;
433 uint64_t purr_start;
434 #endif
435 void *opaque;
438 static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, uint64_t vmclk,
439 int64_t tb_offset)
441 /* TB time in tb periods */
442 return muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec) + tb_offset;
445 uint32_t cpu_ppc_load_tbl (CPUState *env)
447 ppc_tb_t *tb_env = env->tb_env;
448 uint64_t tb;
450 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
451 #if defined(PPC_DEBUG_TB)
452 if (loglevel != 0) {
453 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
455 #endif
457 return tb & 0xFFFFFFFF;
460 static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env)
462 ppc_tb_t *tb_env = env->tb_env;
463 uint64_t tb;
465 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
466 #if defined(PPC_DEBUG_TB)
467 if (loglevel != 0) {
468 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
470 #endif
472 return tb >> 32;
475 uint32_t cpu_ppc_load_tbu (CPUState *env)
477 return _cpu_ppc_load_tbu(env);
480 static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t vmclk,
481 int64_t *tb_offsetp,
482 uint64_t value)
484 *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec);
485 #ifdef PPC_DEBUG_TB
486 if (loglevel != 0) {
487 fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
488 *tb_offsetp);
490 #endif
493 void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
495 ppc_tb_t *tb_env = env->tb_env;
496 uint64_t tb;
498 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
499 tb &= 0xFFFFFFFF00000000ULL;
500 cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
501 &tb_env->tb_offset, tb | (uint64_t)value);
504 static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
506 ppc_tb_t *tb_env = env->tb_env;
507 uint64_t tb;
509 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
510 tb &= 0x00000000FFFFFFFFULL;
511 cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
512 &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
515 void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
517 _cpu_ppc_store_tbu(env, value);
520 uint32_t cpu_ppc_load_atbl (CPUState *env)
522 ppc_tb_t *tb_env = env->tb_env;
523 uint64_t tb;
525 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
526 #if defined(PPC_DEBUG_TB)
527 if (loglevel != 0) {
528 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
530 #endif
532 return tb & 0xFFFFFFFF;
535 uint32_t cpu_ppc_load_atbu (CPUState *env)
537 ppc_tb_t *tb_env = env->tb_env;
538 uint64_t tb;
540 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
541 #if defined(PPC_DEBUG_TB)
542 if (loglevel != 0) {
543 fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
545 #endif
547 return tb >> 32;
550 void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
552 ppc_tb_t *tb_env = env->tb_env;
553 uint64_t tb;
555 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
556 tb &= 0xFFFFFFFF00000000ULL;
557 cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
558 &tb_env->atb_offset, tb | (uint64_t)value);
561 void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
563 ppc_tb_t *tb_env = env->tb_env;
564 uint64_t tb;
566 tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
567 tb &= 0x00000000FFFFFFFFULL;
568 cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
569 &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
572 static void cpu_ppc_tb_stop (CPUState *env)
574 ppc_tb_t *tb_env = env->tb_env;
575 uint64_t tb, atb, vmclk;
577 /* If the time base is already frozen, do nothing */
578 if (tb_env->tb_freq != 0) {
579 vmclk = qemu_get_clock(vm_clock);
580 /* Get the time base */
581 tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
582 /* Get the alternate time base */
583 atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
584 /* Store the time base value (ie compute the current offset) */
585 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
586 /* Store the alternate time base value (compute the current offset) */
587 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
588 /* Set the time base frequency to zero */
589 tb_env->tb_freq = 0;
590 /* Now, the time bases are frozen to tb_offset / atb_offset value */
594 static void cpu_ppc_tb_start (CPUState *env)
596 ppc_tb_t *tb_env = env->tb_env;
597 uint64_t tb, atb, vmclk;
599 /* If the time base is not frozen, do nothing */
600 if (tb_env->tb_freq == 0) {
601 vmclk = qemu_get_clock(vm_clock);
602 /* Get the time base from tb_offset */
603 tb = tb_env->tb_offset;
604 /* Get the alternate time base from atb_offset */
605 atb = tb_env->atb_offset;
606 /* Restore the tb frequency from the decrementer frequency */
607 tb_env->tb_freq = tb_env->decr_freq;
608 /* Store the time base value */
609 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
610 /* Store the alternate time base value */
611 cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
615 static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env,
616 uint64_t *next)
618 ppc_tb_t *tb_env = env->tb_env;
619 uint32_t decr;
620 int64_t diff;
622 diff = tb_env->decr_next - qemu_get_clock(vm_clock);
623 if (diff >= 0)
624 decr = muldiv64(diff, tb_env->decr_freq, ticks_per_sec);
625 else
626 decr = -muldiv64(-diff, tb_env->decr_freq, ticks_per_sec);
627 #if defined(PPC_DEBUG_TB)
628 if (loglevel != 0) {
629 fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
631 #endif
633 return decr;
636 uint32_t cpu_ppc_load_decr (CPUState *env)
638 ppc_tb_t *tb_env = env->tb_env;
640 return _cpu_ppc_load_decr(env, &tb_env->decr_next);
643 #if defined(TARGET_PPC64H)
644 uint32_t cpu_ppc_load_hdecr (CPUState *env)
646 ppc_tb_t *tb_env = env->tb_env;
648 return _cpu_ppc_load_decr(env, &tb_env->hdecr_next);
651 uint64_t cpu_ppc_load_purr (CPUState *env)
653 ppc_tb_t *tb_env = env->tb_env;
654 uint64_t diff;
656 diff = qemu_get_clock(vm_clock) - tb_env->purr_start;
658 return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
660 #endif /* defined(TARGET_PPC64H) */
662 /* When decrementer expires,
663 * all we need to do is generate or queue a CPU exception
665 static always_inline void cpu_ppc_decr_excp (CPUState *env)
667 /* Raise it */
668 #ifdef PPC_DEBUG_TB
669 if (loglevel != 0) {
670 fprintf(logfile, "raise decrementer exception\n");
672 #endif
673 ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
676 static always_inline void cpu_ppc_hdecr_excp (CPUState *env)
678 /* Raise it */
679 #ifdef PPC_DEBUG_TB
680 if (loglevel != 0) {
681 fprintf(logfile, "raise decrementer exception\n");
683 #endif
684 ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
687 static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
688 struct QEMUTimer *timer,
689 void (*raise_excp)(CPUState *),
690 uint32_t decr, uint32_t value,
691 int is_excp)
693 ppc_tb_t *tb_env = env->tb_env;
694 uint64_t now, next;
696 #ifdef PPC_DEBUG_TB
697 if (loglevel != 0) {
698 fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
700 #endif
701 now = qemu_get_clock(vm_clock);
702 next = now + muldiv64(value, ticks_per_sec, tb_env->decr_freq);
703 if (is_excp)
704 next += *nextp - now;
705 if (next == now)
706 next++;
707 *nextp = next;
708 /* Adjust timer */
709 qemu_mod_timer(timer, next);
710 /* If we set a negative value and the decrementer was positive,
711 * raise an exception.
713 if ((value & 0x80000000) && !(decr & 0x80000000))
714 (*raise_excp)(env);
717 static always_inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
718 uint32_t value, int is_excp)
720 ppc_tb_t *tb_env = env->tb_env;
722 __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
723 &cpu_ppc_decr_excp, decr, value, is_excp);
726 void cpu_ppc_store_decr (CPUState *env, uint32_t value)
728 _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
731 static void cpu_ppc_decr_cb (void *opaque)
733 _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
736 #if defined(TARGET_PPC64H)
737 static always_inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr,
738 uint32_t value, int is_excp)
740 ppc_tb_t *tb_env = env->tb_env;
742 __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
743 &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
746 void cpu_ppc_store_hdecr (CPUState *env, uint32_t value)
748 _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
751 static void cpu_ppc_hdecr_cb (void *opaque)
753 _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
756 void cpu_ppc_store_purr (CPUState *env, uint64_t value)
758 ppc_tb_t *tb_env = env->tb_env;
760 tb_env->purr_load = value;
761 tb_env->purr_start = qemu_get_clock(vm_clock);
763 #endif /* defined(TARGET_PPC64H) */
765 static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
767 CPUState *env = opaque;
768 ppc_tb_t *tb_env = env->tb_env;
770 tb_env->tb_freq = freq;
771 tb_env->decr_freq = freq;
772 /* There is a bug in Linux 2.4 kernels:
773 * if a decrementer exception is pending when it enables msr_ee at startup,
774 * it's not ready to handle it...
776 _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
777 #if defined(TARGET_PPC64H)
778 _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
779 cpu_ppc_store_purr(env, 0x0000000000000000ULL);
780 #endif /* defined(TARGET_PPC64H) */
783 /* Set up (once) timebase frequency (in Hz) */
784 clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
786 ppc_tb_t *tb_env;
788 tb_env = qemu_mallocz(sizeof(ppc_tb_t));
789 if (tb_env == NULL)
790 return NULL;
791 env->tb_env = tb_env;
792 /* Create new timer */
793 tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
794 #if defined(TARGET_PPC64H)
795 tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env);
796 #endif /* defined(TARGET_PPC64H) */
797 cpu_ppc_set_tb_clk(env, freq);
799 return &cpu_ppc_set_tb_clk;
802 /* Specific helpers for POWER & PowerPC 601 RTC */
803 clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
805 return cpu_ppc_tb_init(env, 7812500);
808 void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
810 _cpu_ppc_store_tbu(env, value);
813 uint32_t cpu_ppc601_load_rtcu (CPUState *env)
815 return _cpu_ppc_load_tbu(env);
818 void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
820 cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
823 uint32_t cpu_ppc601_load_rtcl (CPUState *env)
825 return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
828 /*****************************************************************************/
829 /* Embedded PowerPC timers */
831 /* PIT, FIT & WDT */
832 typedef struct ppcemb_timer_t ppcemb_timer_t;
833 struct ppcemb_timer_t {
834 uint64_t pit_reload; /* PIT auto-reload value */
835 uint64_t fit_next; /* Tick for next FIT interrupt */
836 struct QEMUTimer *fit_timer;
837 uint64_t wdt_next; /* Tick for next WDT interrupt */
838 struct QEMUTimer *wdt_timer;
841 /* Fixed interval timer */
842 static void cpu_4xx_fit_cb (void *opaque)
844 CPUState *env;
845 ppc_tb_t *tb_env;
846 ppcemb_timer_t *ppcemb_timer;
847 uint64_t now, next;
849 env = opaque;
850 tb_env = env->tb_env;
851 ppcemb_timer = tb_env->opaque;
852 now = qemu_get_clock(vm_clock);
853 switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
854 case 0:
855 next = 1 << 9;
856 break;
857 case 1:
858 next = 1 << 13;
859 break;
860 case 2:
861 next = 1 << 17;
862 break;
863 case 3:
864 next = 1 << 21;
865 break;
866 default:
867 /* Cannot occur, but makes gcc happy */
868 return;
870 next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
871 if (next == now)
872 next++;
873 qemu_mod_timer(ppcemb_timer->fit_timer, next);
874 env->spr[SPR_40x_TSR] |= 1 << 26;
875 if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
876 ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
877 #ifdef PPC_DEBUG_TB
878 if (loglevel != 0) {
879 fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
880 (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
881 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
883 #endif
886 /* Programmable interval timer */
887 static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
889 ppcemb_timer_t *ppcemb_timer;
890 uint64_t now, next;
892 ppcemb_timer = tb_env->opaque;
893 if (ppcemb_timer->pit_reload <= 1 ||
894 !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
895 (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
896 /* Stop PIT */
897 #ifdef PPC_DEBUG_TB
898 if (loglevel != 0) {
899 fprintf(logfile, "%s: stop PIT\n", __func__);
901 #endif
902 qemu_del_timer(tb_env->decr_timer);
903 } else {
904 #ifdef PPC_DEBUG_TB
905 if (loglevel != 0) {
906 fprintf(logfile, "%s: start PIT 0x" REGX "\n",
907 __func__, ppcemb_timer->pit_reload);
909 #endif
910 now = qemu_get_clock(vm_clock);
911 next = now + muldiv64(ppcemb_timer->pit_reload,
912 ticks_per_sec, tb_env->decr_freq);
913 if (is_excp)
914 next += tb_env->decr_next - now;
915 if (next == now)
916 next++;
917 qemu_mod_timer(tb_env->decr_timer, next);
918 tb_env->decr_next = next;
922 static void cpu_4xx_pit_cb (void *opaque)
924 CPUState *env;
925 ppc_tb_t *tb_env;
926 ppcemb_timer_t *ppcemb_timer;
928 env = opaque;
929 tb_env = env->tb_env;
930 ppcemb_timer = tb_env->opaque;
931 env->spr[SPR_40x_TSR] |= 1 << 27;
932 if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
933 ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
934 start_stop_pit(env, tb_env, 1);
935 #ifdef PPC_DEBUG_TB
936 if (loglevel != 0) {
937 fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
938 "%016" PRIx64 "\n", __func__,
939 (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
940 (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
941 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
942 ppcemb_timer->pit_reload);
944 #endif
947 /* Watchdog timer */
948 static void cpu_4xx_wdt_cb (void *opaque)
950 CPUState *env;
951 ppc_tb_t *tb_env;
952 ppcemb_timer_t *ppcemb_timer;
953 uint64_t now, next;
955 env = opaque;
956 tb_env = env->tb_env;
957 ppcemb_timer = tb_env->opaque;
958 now = qemu_get_clock(vm_clock);
959 switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
960 case 0:
961 next = 1 << 17;
962 break;
963 case 1:
964 next = 1 << 21;
965 break;
966 case 2:
967 next = 1 << 25;
968 break;
969 case 3:
970 next = 1 << 29;
971 break;
972 default:
973 /* Cannot occur, but makes gcc happy */
974 return;
976 next = now + muldiv64(next, ticks_per_sec, tb_env->decr_freq);
977 if (next == now)
978 next++;
979 #ifdef PPC_DEBUG_TB
980 if (loglevel != 0) {
981 fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
982 env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
984 #endif
985 switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
986 case 0x0:
987 case 0x1:
988 qemu_mod_timer(ppcemb_timer->wdt_timer, next);
989 ppcemb_timer->wdt_next = next;
990 env->spr[SPR_40x_TSR] |= 1 << 31;
991 break;
992 case 0x2:
993 qemu_mod_timer(ppcemb_timer->wdt_timer, next);
994 ppcemb_timer->wdt_next = next;
995 env->spr[SPR_40x_TSR] |= 1 << 30;
996 if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
997 ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
998 break;
999 case 0x3:
1000 env->spr[SPR_40x_TSR] &= ~0x30000000;
1001 env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
1002 switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
1003 case 0x0:
1004 /* No reset */
1005 break;
1006 case 0x1: /* Core reset */
1007 ppc40x_core_reset(env);
1008 break;
1009 case 0x2: /* Chip reset */
1010 ppc40x_chip_reset(env);
1011 break;
1012 case 0x3: /* System reset */
1013 ppc40x_system_reset(env);
1014 break;
1019 void store_40x_pit (CPUState *env, target_ulong val)
1021 ppc_tb_t *tb_env;
1022 ppcemb_timer_t *ppcemb_timer;
1024 tb_env = env->tb_env;
1025 ppcemb_timer = tb_env->opaque;
1026 #ifdef PPC_DEBUG_TB
1027 if (loglevel != 0) {
1028 fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
1030 #endif
1031 ppcemb_timer->pit_reload = val;
1032 start_stop_pit(env, tb_env, 0);
1035 target_ulong load_40x_pit (CPUState *env)
1037 return cpu_ppc_load_decr(env);
1040 void store_booke_tsr (CPUState *env, target_ulong val)
1042 #ifdef PPC_DEBUG_TB
1043 if (loglevel != 0) {
1044 fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
1046 #endif
1047 env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
1048 if (val & 0x80000000)
1049 ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
1052 void store_booke_tcr (CPUState *env, target_ulong val)
1054 ppc_tb_t *tb_env;
1056 tb_env = env->tb_env;
1057 #ifdef PPC_DEBUG_TB
1058 if (loglevel != 0) {
1059 fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
1061 #endif
1062 env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1063 start_stop_pit(env, tb_env, 1);
1064 cpu_4xx_wdt_cb(env);
1067 static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
1069 CPUState *env = opaque;
1070 ppc_tb_t *tb_env = env->tb_env;
1072 #ifdef PPC_DEBUG_TB
1073 if (loglevel != 0) {
1074 fprintf(logfile, "%s set new frequency to %u\n", __func__, freq);
1076 #endif
1077 tb_env->tb_freq = freq;
1078 tb_env->decr_freq = freq;
1079 /* XXX: we should also update all timers */
1082 clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
1084 ppc_tb_t *tb_env;
1085 ppcemb_timer_t *ppcemb_timer;
1087 tb_env = qemu_mallocz(sizeof(ppc_tb_t));
1088 if (tb_env == NULL) {
1089 return NULL;
1091 env->tb_env = tb_env;
1092 ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
1093 tb_env->tb_freq = freq;
1094 tb_env->decr_freq = freq;
1095 tb_env->opaque = ppcemb_timer;
1096 #ifdef PPC_DEBUG_TB
1097 if (loglevel != 0) {
1098 fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer,
1099 &ppc_emb_set_tb_clk);
1101 #endif
1102 if (ppcemb_timer != NULL) {
1103 /* We use decr timer for PIT */
1104 tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
1105 ppcemb_timer->fit_timer =
1106 qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
1107 ppcemb_timer->wdt_timer =
1108 qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
1111 return &ppc_emb_set_tb_clk;
1114 /*****************************************************************************/
1115 /* Embedded PowerPC Device Control Registers */
1116 typedef struct ppc_dcrn_t ppc_dcrn_t;
1117 struct ppc_dcrn_t {
1118 dcr_read_cb dcr_read;
1119 dcr_write_cb dcr_write;
1120 void *opaque;
1123 /* XXX: on 460, DCR addresses are 32 bits wide,
1124 * using DCRIPR to get the 22 upper bits of the DCR address
1126 #define DCRN_NB 1024
1127 struct ppc_dcr_t {
1128 ppc_dcrn_t dcrn[DCRN_NB];
1129 int (*read_error)(int dcrn);
1130 int (*write_error)(int dcrn);
1133 int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
1135 ppc_dcrn_t *dcr;
1137 if (dcrn < 0 || dcrn >= DCRN_NB)
1138 goto error;
1139 dcr = &dcr_env->dcrn[dcrn];
1140 if (dcr->dcr_read == NULL)
1141 goto error;
1142 *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1144 return 0;
1146 error:
1147 if (dcr_env->read_error != NULL)
1148 return (*dcr_env->read_error)(dcrn);
1150 return -1;
1153 int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
1155 ppc_dcrn_t *dcr;
1157 if (dcrn < 0 || dcrn >= DCRN_NB)
1158 goto error;
1159 dcr = &dcr_env->dcrn[dcrn];
1160 if (dcr->dcr_write == NULL)
1161 goto error;
1162 (*dcr->dcr_write)(dcr->opaque, dcrn, val);
1164 return 0;
1166 error:
1167 if (dcr_env->write_error != NULL)
1168 return (*dcr_env->write_error)(dcrn);
1170 return -1;
1173 int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
1174 dcr_read_cb dcr_read, dcr_write_cb dcr_write)
1176 ppc_dcr_t *dcr_env;
1177 ppc_dcrn_t *dcr;
1179 dcr_env = env->dcr_env;
1180 if (dcr_env == NULL)
1181 return -1;
1182 if (dcrn < 0 || dcrn >= DCRN_NB)
1183 return -1;
1184 dcr = &dcr_env->dcrn[dcrn];
1185 if (dcr->opaque != NULL ||
1186 dcr->dcr_read != NULL ||
1187 dcr->dcr_write != NULL)
1188 return -1;
1189 dcr->opaque = opaque;
1190 dcr->dcr_read = dcr_read;
1191 dcr->dcr_write = dcr_write;
1193 return 0;
1196 int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
1197 int (*write_error)(int dcrn))
1199 ppc_dcr_t *dcr_env;
1201 dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
1202 if (dcr_env == NULL)
1203 return -1;
1204 dcr_env->read_error = read_error;
1205 dcr_env->write_error = write_error;
1206 env->dcr_env = dcr_env;
1208 return 0;
1211 #if 0
1212 /*****************************************************************************/
1213 /* Handle system reset (for now, just stop emulation) */
1214 void cpu_ppc_reset (CPUState *env)
1216 printf("Reset asked... Stop emulation\n");
1217 abort();
1219 #endif
1221 /*****************************************************************************/
1222 /* Debug port */
1223 void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
1225 addr &= 0xF;
1226 switch (addr) {
1227 case 0:
1228 printf("%c", val);
1229 break;
1230 case 1:
1231 printf("\n");
1232 fflush(stdout);
1233 break;
1234 case 2:
1235 printf("Set loglevel to %04x\n", val);
1236 cpu_set_log(val | 0x100);
1237 break;
1241 /*****************************************************************************/
1242 /* NVRAM helpers */
1243 void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
1245 m48t59_write(nvram, addr, value);
1248 uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
1250 return m48t59_read(nvram, addr);
1253 void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
1255 m48t59_write(nvram, addr, value >> 8);
1256 m48t59_write(nvram, addr + 1, value & 0xFF);
1259 uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
1261 uint16_t tmp;
1263 tmp = m48t59_read(nvram, addr) << 8;
1264 tmp |= m48t59_read(nvram, addr + 1);
1265 return tmp;
1268 void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
1270 m48t59_write(nvram, addr, value >> 24);
1271 m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
1272 m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
1273 m48t59_write(nvram, addr + 3, value & 0xFF);
1276 uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
1278 uint32_t tmp;
1280 tmp = m48t59_read(nvram, addr) << 24;
1281 tmp |= m48t59_read(nvram, addr + 1) << 16;
1282 tmp |= m48t59_read(nvram, addr + 2) << 8;
1283 tmp |= m48t59_read(nvram, addr + 3);
1285 return tmp;
1288 void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
1289 const unsigned char *str, uint32_t max)
1291 int i;
1293 for (i = 0; i < max && str[i] != '\0'; i++) {
1294 m48t59_write(nvram, addr + i, str[i]);
1296 m48t59_write(nvram, addr + max - 1, '\0');
1299 int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
1301 int i;
1303 memset(dst, 0, max);
1304 for (i = 0; i < max; i++) {
1305 dst[i] = NVRAM_get_byte(nvram, addr + i);
1306 if (dst[i] == '\0')
1307 break;
1310 return i;
1313 static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1315 uint16_t tmp;
1316 uint16_t pd, pd1, pd2;
1318 tmp = prev >> 8;
1319 pd = prev ^ value;
1320 pd1 = pd & 0x000F;
1321 pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1322 tmp ^= (pd1 << 3) | (pd1 << 8);
1323 tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1325 return tmp;
1328 uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
1330 uint32_t i;
1331 uint16_t crc = 0xFFFF;
1332 int odd;
1334 odd = count & 1;
1335 count &= ~1;
1336 for (i = 0; i != count; i++) {
1337 crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1339 if (odd) {
1340 crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1343 return crc;
1346 #define CMDLINE_ADDR 0x017ff000
1348 int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
1349 const unsigned char *arch,
1350 uint32_t RAM_size, int boot_device,
1351 uint32_t kernel_image, uint32_t kernel_size,
1352 const char *cmdline,
1353 uint32_t initrd_image, uint32_t initrd_size,
1354 uint32_t NVRAM_image,
1355 int width, int height, int depth)
1357 uint16_t crc;
1359 /* Set parameters for Open Hack'Ware BIOS */
1360 NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1361 NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
1362 NVRAM_set_word(nvram, 0x14, NVRAM_size);
1363 NVRAM_set_string(nvram, 0x20, arch, 16);
1364 NVRAM_set_lword(nvram, 0x30, RAM_size);
1365 NVRAM_set_byte(nvram, 0x34, boot_device);
1366 NVRAM_set_lword(nvram, 0x38, kernel_image);
1367 NVRAM_set_lword(nvram, 0x3C, kernel_size);
1368 if (cmdline) {
1369 /* XXX: put the cmdline in NVRAM too ? */
1370 strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
1371 NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
1372 NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
1373 } else {
1374 NVRAM_set_lword(nvram, 0x40, 0);
1375 NVRAM_set_lword(nvram, 0x44, 0);
1377 NVRAM_set_lword(nvram, 0x48, initrd_image);
1378 NVRAM_set_lword(nvram, 0x4C, initrd_size);
1379 NVRAM_set_lword(nvram, 0x50, NVRAM_image);
1381 NVRAM_set_word(nvram, 0x54, width);
1382 NVRAM_set_word(nvram, 0x56, height);
1383 NVRAM_set_word(nvram, 0x58, depth);
1384 crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1385 NVRAM_set_word(nvram, 0xFC, crc);
1387 return 0;