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