Commit 58a7d32872badb7b94d2010e0100a25443e0ef77
1 parent
47c4d8f0
Code provision for hypervisor timers resources,
as described in PowerPC 2.04 specification. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3264 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
106 additions
and
7 deletions
hw/ppc.c
| ... | ... | @@ -412,6 +412,13 @@ struct ppc_tb_t { |
| 412 | 412 | /* Decrementer management */ |
| 413 | 413 | uint64_t decr_next; /* Tick for next decr interrupt */ |
| 414 | 414 | struct QEMUTimer *decr_timer; |
| 415 | +#if defined(TARGET_PPC64H) | |
| 416 | + /* Hypervisor decrementer management */ | |
| 417 | + uint64_t hdecr_next; /* Tick for next hdecr interrupt */ | |
| 418 | + struct QEMUTimer *hdecr_timer; | |
| 419 | + uint64_t purr_load; | |
| 420 | + uint64_t purr_start; | |
| 421 | +#endif | |
| 415 | 422 | void *opaque; |
| 416 | 423 | }; |
| 417 | 424 | |
| ... | ... | @@ -489,7 +496,7 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) |
| 489 | 496 | ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); |
| 490 | 497 | } |
| 491 | 498 | |
| 492 | -uint32_t cpu_ppc_load_decr (CPUState *env) | |
| 499 | +static inline uint32_t _cpu_ppc_load_decr (CPUState *env, uint64_t *next) | |
| 493 | 500 | { |
| 494 | 501 | ppc_tb_t *tb_env = env->tb_env; |
| 495 | 502 | uint32_t decr; |
| ... | ... | @@ -509,6 +516,32 @@ uint32_t cpu_ppc_load_decr (CPUState *env) |
| 509 | 516 | return decr; |
| 510 | 517 | } |
| 511 | 518 | |
| 519 | +uint32_t cpu_ppc_load_decr (CPUState *env) | |
| 520 | +{ | |
| 521 | + ppc_tb_t *tb_env = env->tb_env; | |
| 522 | + | |
| 523 | + return _cpu_ppc_load_decr(env, &tb_env->decr_next); | |
| 524 | +} | |
| 525 | + | |
| 526 | +#if defined(TARGET_PPC64H) | |
| 527 | +uint32_t cpu_ppc_load_hdecr (CPUState *env) | |
| 528 | +{ | |
| 529 | + ppc_tb_t *tb_env = env->tb_env; | |
| 530 | + | |
| 531 | + return _cpu_ppc_load_decr(env, &tb_env->hdecr_next); | |
| 532 | +} | |
| 533 | + | |
| 534 | +uint64_t cpu_ppc_load_purr (CPUState *env) | |
| 535 | +{ | |
| 536 | + ppc_tb_t *tb_env = env->tb_env; | |
| 537 | + uint64_t diff; | |
| 538 | + | |
| 539 | + diff = qemu_get_clock(vm_clock) - tb_env->purr_start; | |
| 540 | + | |
| 541 | + return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec); | |
| 542 | +} | |
| 543 | +#endif /* defined(TARGET_PPC64H) */ | |
| 544 | + | |
| 512 | 545 | /* When decrementer expires, |
| 513 | 546 | * all we need to do is generate or queue a CPU exception |
| 514 | 547 | */ |
| ... | ... | @@ -523,8 +556,22 @@ static inline void cpu_ppc_decr_excp (CPUState *env) |
| 523 | 556 | ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); |
| 524 | 557 | } |
| 525 | 558 | |
| 526 | -static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, | |
| 527 | - uint32_t value, int is_excp) | |
| 559 | +static inline void cpu_ppc_hdecr_excp (CPUState *env) | |
| 560 | +{ | |
| 561 | + /* Raise it */ | |
| 562 | +#ifdef PPC_DEBUG_TB | |
| 563 | + if (loglevel != 0) { | |
| 564 | + fprintf(logfile, "raise decrementer exception\n"); | |
| 565 | + } | |
| 566 | +#endif | |
| 567 | + ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1); | |
| 568 | +} | |
| 569 | + | |
| 570 | +static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, | |
| 571 | + struct QEMUTimer *timer, | |
| 572 | + void (*raise_excp)(CPUState *), | |
| 573 | + uint32_t decr, uint32_t value, | |
| 574 | + int is_excp) | |
| 528 | 575 | { |
| 529 | 576 | ppc_tb_t *tb_env = env->tb_env; |
| 530 | 577 | uint64_t now, next; |
| ... | ... | @@ -537,17 +584,27 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, |
| 537 | 584 | now = qemu_get_clock(vm_clock); |
| 538 | 585 | next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); |
| 539 | 586 | if (is_excp) |
| 540 | - next += tb_env->decr_next - now; | |
| 587 | + next += *nextp - now; | |
| 541 | 588 | if (next == now) |
| 542 | 589 | next++; |
| 543 | - tb_env->decr_next = next; | |
| 590 | + *nextp = next; | |
| 544 | 591 | /* Adjust timer */ |
| 545 | - qemu_mod_timer(tb_env->decr_timer, next); | |
| 592 | + qemu_mod_timer(timer, next); | |
| 546 | 593 | /* If we set a negative value and the decrementer was positive, |
| 547 | 594 | * raise an exception. |
| 548 | 595 | */ |
| 549 | 596 | if ((value & 0x80000000) && !(decr & 0x80000000)) |
| 550 | - cpu_ppc_decr_excp(env); | |
| 597 | + (*raise_excp)(env); | |
| 598 | +} | |
| 599 | + | |
| 600 | + | |
| 601 | +static inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, | |
| 602 | + uint32_t value, int is_excp) | |
| 603 | +{ | |
| 604 | + ppc_tb_t *tb_env = env->tb_env; | |
| 605 | + | |
| 606 | + __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer, | |
| 607 | + &cpu_ppc_decr_excp, decr, value, is_excp); | |
| 551 | 608 | } |
| 552 | 609 | |
| 553 | 610 | void cpu_ppc_store_decr (CPUState *env, uint32_t value) |
| ... | ... | @@ -560,6 +617,35 @@ static void cpu_ppc_decr_cb (void *opaque) |
| 560 | 617 | _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); |
| 561 | 618 | } |
| 562 | 619 | |
| 620 | +#if defined(TARGET_PPC64H) | |
| 621 | +static inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr, | |
| 622 | + uint32_t value, int is_excp) | |
| 623 | +{ | |
| 624 | + ppc_tb_t *tb_env = env->tb_env; | |
| 625 | + | |
| 626 | + __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer, | |
| 627 | + &cpu_ppc_hdecr_excp, hdecr, value, is_excp); | |
| 628 | +} | |
| 629 | + | |
| 630 | +void cpu_ppc_store_hdecr (CPUState *env, uint32_t value) | |
| 631 | +{ | |
| 632 | + _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0); | |
| 633 | +} | |
| 634 | + | |
| 635 | +static void cpu_ppc_hdecr_cb (void *opaque) | |
| 636 | +{ | |
| 637 | + _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1); | |
| 638 | +} | |
| 639 | + | |
| 640 | +void cpu_ppc_store_purr (CPUState *env, uint64_t value) | |
| 641 | +{ | |
| 642 | + ppc_tb_t *tb_env = env->tb_env; | |
| 643 | + | |
| 644 | + tb_env->purr_load = value; | |
| 645 | + tb_env->purr_start = qemu_get_clock(vm_clock); | |
| 646 | +} | |
| 647 | +#endif /* defined(TARGET_PPC64H) */ | |
| 648 | + | |
| 563 | 649 | static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) |
| 564 | 650 | { |
| 565 | 651 | CPUState *env = opaque; |
| ... | ... | @@ -571,6 +657,10 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) |
| 571 | 657 | * it's not ready to handle it... |
| 572 | 658 | */ |
| 573 | 659 | _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); |
| 660 | +#if defined(TARGET_PPC64H) | |
| 661 | + _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); | |
| 662 | + cpu_ppc_store_purr(env, 0x0000000000000000ULL); | |
| 663 | +#endif /* defined(TARGET_PPC64H) */ | |
| 574 | 664 | } |
| 575 | 665 | |
| 576 | 666 | /* Set up (once) timebase frequency (in Hz) */ |
| ... | ... | @@ -584,6 +674,9 @@ clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq) |
| 584 | 674 | env->tb_env = tb_env; |
| 585 | 675 | /* Create new timer */ |
| 586 | 676 | tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); |
| 677 | +#if defined(TARGET_PPC64H) | |
| 678 | + tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env); | |
| 679 | +#endif /* defined(TARGET_PPC64H) */ | |
| 587 | 680 | cpu_ppc_set_tb_clk(env, freq); |
| 588 | 681 | |
| 589 | 682 | return &cpu_ppc_set_tb_clk; | ... | ... |
target-ppc/cpu.h
| ... | ... | @@ -627,6 +627,12 @@ void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); |
| 627 | 627 | void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); |
| 628 | 628 | uint32_t cpu_ppc_load_decr (CPUPPCState *env); |
| 629 | 629 | void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); |
| 630 | +#if defined(TARGET_PPC64H) | |
| 631 | +uint32_t cpu_ppc_load_hdecr (CPUPPCState *env); | |
| 632 | +void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value); | |
| 633 | +uint64_t cpu_ppc_load_purr (CPUPPCState *env); | |
| 634 | +void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value); | |
| 635 | +#endif | |
| 630 | 636 | uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env); |
| 631 | 637 | uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env); |
| 632 | 638 | #if !defined(CONFIG_USER_ONLY) | ... | ... |