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) |