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