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