Revision 55d284af target-arm/helper.c

b/target-arm/helper.c
695 695
    REGINFO_SENTINEL
696 696
};
697 697

  
698
#ifndef CONFIG_USER_ONLY
699

  
700
static uint64_t gt_get_countervalue(CPUARMState *env)
701
{
702
    return qemu_get_clock_ns(vm_clock) / GTIMER_SCALE;
703
}
704

  
705
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
706
{
707
    ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
708

  
709
    if (gt->ctl & 1) {
710
        /* Timer enabled: calculate and set current ISTATUS, irq, and
711
         * reset timer to when ISTATUS next has to change
712
         */
713
        uint64_t count = gt_get_countervalue(&cpu->env);
714
        /* Note that this must be unsigned 64 bit arithmetic: */
715
        int istatus = count >= gt->cval;
716
        uint64_t nexttick;
717

  
718
        gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
719
        qemu_set_irq(cpu->gt_timer_outputs[timeridx],
720
                     (istatus && !(gt->ctl & 2)));
721
        if (istatus) {
722
            /* Next transition is when count rolls back over to zero */
723
            nexttick = UINT64_MAX;
724
        } else {
725
            /* Next transition is when we hit cval */
726
            nexttick = gt->cval;
727
        }
728
        /* Note that the desired next expiry time might be beyond the
729
         * signed-64-bit range of a QEMUTimer -- in this case we just
730
         * set the timer for as far in the future as possible. When the
731
         * timer expires we will reset the timer for any remaining period.
732
         */
733
        if (nexttick > INT64_MAX / GTIMER_SCALE) {
734
            nexttick = INT64_MAX / GTIMER_SCALE;
735
        }
736
        qemu_mod_timer(cpu->gt_timer[timeridx], nexttick);
737
    } else {
738
        /* Timer disabled: ISTATUS and timer output always clear */
739
        gt->ctl &= ~4;
740
        qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0);
741
        qemu_del_timer(cpu->gt_timer[timeridx]);
742
    }
743
}
744

  
745
static int gt_cntfrq_read(CPUARMState *env, const ARMCPRegInfo *ri,
746
                          uint64_t *value)
747
{
748
    /* Not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */
749
    if (arm_current_pl(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) {
750
        return EXCP_UDEF;
751
    }
752
    *value = env->cp15.c14_cntfrq;
753
    return 0;
754
}
755

  
756
static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri)
757
{
758
    ARMCPU *cpu = arm_env_get_cpu(env);
759
    int timeridx = ri->opc1 & 1;
760

  
761
    qemu_del_timer(cpu->gt_timer[timeridx]);
762
}
763

  
764
static int gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri,
765
                       uint64_t *value)
766
{
767
    int timeridx = ri->opc1 & 1;
768

  
769
    if (arm_current_pl(env) == 0 &&
770
        !extract32(env->cp15.c14_cntkctl, timeridx, 1)) {
771
        return EXCP_UDEF;
772
    }
773
    *value = gt_get_countervalue(env);
774
    return 0;
775
}
776

  
777
static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri,
778
                        uint64_t *value)
779
{
780
    int timeridx = ri->opc1 & 1;
781

  
782
    if (arm_current_pl(env) == 0 &&
783
        !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
784
        return EXCP_UDEF;
785
    }
786
    *value = env->cp15.c14_timer[timeridx].cval;
787
    return 0;
788
}
789

  
790
static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
791
                         uint64_t value)
792
{
793
    int timeridx = ri->opc1 & 1;
794

  
795
    env->cp15.c14_timer[timeridx].cval = value;
796
    gt_recalc_timer(arm_env_get_cpu(env), timeridx);
797
    return 0;
798
}
799
static int gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
800
                        uint64_t *value)
801
{
802
    int timeridx = ri->crm & 1;
803

  
804
    if (arm_current_pl(env) == 0 &&
805
        !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
806
        return EXCP_UDEF;
807
    }
808
    *value = (uint32_t)(env->cp15.c14_timer[timeridx].cval -
809
                        gt_get_countervalue(env));
810
    return 0;
811
}
812

  
813
static int gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
814
                         uint64_t value)
815
{
816
    int timeridx = ri->crm & 1;
817

  
818
    env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) +
819
        + sextract64(value, 0, 32);
820
    gt_recalc_timer(arm_env_get_cpu(env), timeridx);
821
    return 0;
822
}
823

  
824
static int gt_ctl_read(CPUARMState *env, const ARMCPRegInfo *ri,
825
                       uint64_t *value)
826
{
827
    int timeridx = ri->crm & 1;
828

  
829
    if (arm_current_pl(env) == 0 &&
830
        !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
831
        return EXCP_UDEF;
832
    }
833
    *value = env->cp15.c14_timer[timeridx].ctl;
834
    return 0;
835
}
836

  
837
static int gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
838
                        uint64_t value)
839
{
840
    ARMCPU *cpu = arm_env_get_cpu(env);
841
    int timeridx = ri->crm & 1;
842
    uint32_t oldval = env->cp15.c14_timer[timeridx].ctl;
843

  
844
    env->cp15.c14_timer[timeridx].ctl = value & 3;
845
    if ((oldval ^ value) & 1) {
846
        /* Enable toggled */
847
        gt_recalc_timer(cpu, timeridx);
848
    } else if ((oldval & value) & 2) {
849
        /* IMASK toggled: don't need to recalculate,
850
         * just set the interrupt line based on ISTATUS
851
         */
852
        qemu_set_irq(cpu->gt_timer_outputs[timeridx],
853
                     (oldval & 4) && (value & 2));
854
    }
855
    return 0;
856
}
857

  
858
void arm_gt_ptimer_cb(void *opaque)
859
{
860
    ARMCPU *cpu = opaque;
861

  
862
    gt_recalc_timer(cpu, GTIMER_PHYS);
863
}
864

  
865
void arm_gt_vtimer_cb(void *opaque)
866
{
867
    ARMCPU *cpu = opaque;
868

  
869
    gt_recalc_timer(cpu, GTIMER_VIRT);
870
}
871

  
698 872
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
699
    /* Dummy implementation: RAZ/WI the whole crn=14 space */
700
    { .name = "GENERIC_TIMER", .cp = 15, .crn = 14,
701
      .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
702
      .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_NO_MIGRATE,
703
      .resetvalue = 0 },
873
    /* Note that CNTFRQ is purely reads-as-written for the benefit
874
     * of software; writing it doesn't actually change the timer frequency.
875
     * Our reset value matches the fixed frequency we implement the timer at.
876
     */
877
    { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0,
878
      .access = PL1_RW | PL0_R,
879
      .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
880
      .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
881
      .readfn = gt_cntfrq_read, .raw_readfn = raw_read,
882
    },
883
    /* overall control: mostly access permissions */
884
    { .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0,
885
      .access = PL1_RW,
886
      .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
887
      .resetvalue = 0,
888
    },
889
    /* per-timer control */
890
    { .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
891
      .type = ARM_CP_IO, .access = PL1_RW | PL0_R,
892
      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
893
      .resetvalue = 0,
894
      .readfn = gt_ctl_read, .writefn = gt_ctl_write,
895
      .raw_readfn = raw_read, .raw_writefn = raw_write,
896
    },
897
    { .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1,
898
      .type = ARM_CP_IO, .access = PL1_RW | PL0_R,
899
      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
900
      .resetvalue = 0,
901
      .readfn = gt_ctl_read, .writefn = gt_ctl_write,
902
      .raw_readfn = raw_read, .raw_writefn = raw_write,
903
    },
904
    /* TimerValue views: a 32 bit downcounting view of the underlying state */
905
    { .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0,
906
      .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
907
      .readfn = gt_tval_read, .writefn = gt_tval_write,
908
    },
909
    { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0,
910
      .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
911
      .readfn = gt_tval_read, .writefn = gt_tval_write,
912
    },
913
    /* The counter itself */
914
    { .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0,
915
      .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
916
      .readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
917
    },
918
    { .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
919
      .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
920
      .readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
921
    },
922
    /* Comparison value, indicating when the timer goes off */
923
    { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
924
      .access = PL1_RW | PL0_R,
925
      .type = ARM_CP_64BIT | ARM_CP_IO,
926
      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
927
      .resetvalue = 0,
928
      .readfn = gt_cval_read, .writefn = gt_cval_write,
929
      .raw_readfn = raw_read, .raw_writefn = raw_write,
930
    },
931
    { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3,
932
      .access = PL1_RW | PL0_R,
933
      .type = ARM_CP_64BIT | ARM_CP_IO,
934
      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
935
      .resetvalue = 0,
936
      .readfn = gt_cval_read, .writefn = gt_cval_write,
937
      .raw_readfn = raw_read, .raw_writefn = raw_write,
938
    },
704 939
    REGINFO_SENTINEL
705 940
};
706 941

  
942
#else
943
/* In user-mode none of the generic timer registers are accessible,
944
 * and their implementation depends on vm_clock and qdev gpio outputs,
945
 * so instead just don't register any of them.
946
 */
947
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
948
    REGINFO_SENTINEL
949
};
950

  
951
#endif
952

  
707 953
static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
708 954
{
709 955
    if (arm_feature(env, ARM_FEATURE_LPAE)) {

Also available in: Unified diff