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