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,6 +412,13 @@ struct ppc_tb_t { | ||
| 412 | /* Decrementer management */ | 412 | /* Decrementer management */ |
| 413 | uint64_t decr_next; /* Tick for next decr interrupt */ | 413 | uint64_t decr_next; /* Tick for next decr interrupt */ |
| 414 | struct QEMUTimer *decr_timer; | 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 | void *opaque; | 422 | void *opaque; |
| 416 | }; | 423 | }; |
| 417 | 424 | ||
| @@ -489,7 +496,7 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) | @@ -489,7 +496,7 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) | ||
| 489 | ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); | 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 | ppc_tb_t *tb_env = env->tb_env; | 501 | ppc_tb_t *tb_env = env->tb_env; |
| 495 | uint32_t decr; | 502 | uint32_t decr; |
| @@ -509,6 +516,32 @@ uint32_t cpu_ppc_load_decr (CPUState *env) | @@ -509,6 +516,32 @@ uint32_t cpu_ppc_load_decr (CPUState *env) | ||
| 509 | return decr; | 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 | /* When decrementer expires, | 545 | /* When decrementer expires, |
| 513 | * all we need to do is generate or queue a CPU exception | 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,8 +556,22 @@ static inline void cpu_ppc_decr_excp (CPUState *env) | ||
| 523 | ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); | 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 | ppc_tb_t *tb_env = env->tb_env; | 576 | ppc_tb_t *tb_env = env->tb_env; |
| 530 | uint64_t now, next; | 577 | uint64_t now, next; |
| @@ -537,17 +584,27 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, | @@ -537,17 +584,27 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, | ||
| 537 | now = qemu_get_clock(vm_clock); | 584 | now = qemu_get_clock(vm_clock); |
| 538 | next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); | 585 | next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); |
| 539 | if (is_excp) | 586 | if (is_excp) |
| 540 | - next += tb_env->decr_next - now; | 587 | + next += *nextp - now; |
| 541 | if (next == now) | 588 | if (next == now) |
| 542 | next++; | 589 | next++; |
| 543 | - tb_env->decr_next = next; | 590 | + *nextp = next; |
| 544 | /* Adjust timer */ | 591 | /* Adjust timer */ |
| 545 | - qemu_mod_timer(tb_env->decr_timer, next); | 592 | + qemu_mod_timer(timer, next); |
| 546 | /* If we set a negative value and the decrementer was positive, | 593 | /* If we set a negative value and the decrementer was positive, |
| 547 | * raise an exception. | 594 | * raise an exception. |
| 548 | */ | 595 | */ |
| 549 | if ((value & 0x80000000) && !(decr & 0x80000000)) | 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 | void cpu_ppc_store_decr (CPUState *env, uint32_t value) | 610 | void cpu_ppc_store_decr (CPUState *env, uint32_t value) |
| @@ -560,6 +617,35 @@ static void cpu_ppc_decr_cb (void *opaque) | @@ -560,6 +617,35 @@ static void cpu_ppc_decr_cb (void *opaque) | ||
| 560 | _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); | 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 | static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) | 649 | static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) |
| 564 | { | 650 | { |
| 565 | CPUState *env = opaque; | 651 | CPUState *env = opaque; |
| @@ -571,6 +657,10 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) | @@ -571,6 +657,10 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) | ||
| 571 | * it's not ready to handle it... | 657 | * it's not ready to handle it... |
| 572 | */ | 658 | */ |
| 573 | _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); | 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 | /* Set up (once) timebase frequency (in Hz) */ | 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,6 +674,9 @@ clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq) | ||
| 584 | env->tb_env = tb_env; | 674 | env->tb_env = tb_env; |
| 585 | /* Create new timer */ | 675 | /* Create new timer */ |
| 586 | tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); | 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 | cpu_ppc_set_tb_clk(env, freq); | 680 | cpu_ppc_set_tb_clk(env, freq); |
| 588 | 681 | ||
| 589 | return &cpu_ppc_set_tb_clk; | 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,6 +627,12 @@ void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); | ||
| 627 | void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); | 627 | void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); |
| 628 | uint32_t cpu_ppc_load_decr (CPUPPCState *env); | 628 | uint32_t cpu_ppc_load_decr (CPUPPCState *env); |
| 629 | void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); | 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 | uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env); | 636 | uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env); |
| 631 | uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env); | 637 | uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env); |
| 632 | #if !defined(CONFIG_USER_ONLY) | 638 | #if !defined(CONFIG_USER_ONLY) |