Commit 58a7d32872badb7b94d2010e0100a25443e0ef77

Authored by j_mayer
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)
... ...