Revision 00108f2d
b/target-arm/helper.c | ||
---|---|---|
743 | 743 |
|
744 | 744 |
#ifndef CONFIG_USER_ONLY |
745 | 745 |
|
746 |
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri) |
|
747 |
{ |
|
748 |
/* CNTFRQ: 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 CP_ACCESS_TRAP; |
|
751 |
} |
|
752 |
return CP_ACCESS_OK; |
|
753 |
} |
|
754 |
|
|
755 |
static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx) |
|
756 |
{ |
|
757 |
/* CNT[PV]CT: not visible from PL0 if ELO[PV]CTEN is zero */ |
|
758 |
if (arm_current_pl(env) == 0 && |
|
759 |
!extract32(env->cp15.c14_cntkctl, timeridx, 1)) { |
|
760 |
return CP_ACCESS_TRAP; |
|
761 |
} |
|
762 |
return CP_ACCESS_OK; |
|
763 |
} |
|
764 |
|
|
765 |
static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx) |
|
766 |
{ |
|
767 |
/* CNT[PV]_CVAL, CNT[PV]_CTL, CNT[PV]_TVAL: not visible from PL0 if |
|
768 |
* EL0[PV]TEN is zero. |
|
769 |
*/ |
|
770 |
if (arm_current_pl(env) == 0 && |
|
771 |
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { |
|
772 |
return CP_ACCESS_TRAP; |
|
773 |
} |
|
774 |
return CP_ACCESS_OK; |
|
775 |
} |
|
776 |
|
|
777 |
static CPAccessResult gt_pct_access(CPUARMState *env, |
|
778 |
const ARMCPRegInfo *ri) |
|
779 |
{ |
|
780 |
return gt_counter_access(env, GTIMER_PHYS); |
|
781 |
} |
|
782 |
|
|
783 |
static CPAccessResult gt_vct_access(CPUARMState *env, |
|
784 |
const ARMCPRegInfo *ri) |
|
785 |
{ |
|
786 |
return gt_counter_access(env, GTIMER_VIRT); |
|
787 |
} |
|
788 |
|
|
789 |
static CPAccessResult gt_ptimer_access(CPUARMState *env, const ARMCPRegInfo *ri) |
|
790 |
{ |
|
791 |
return gt_timer_access(env, GTIMER_PHYS); |
|
792 |
} |
|
793 |
|
|
794 |
static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri) |
|
795 |
{ |
|
796 |
return gt_timer_access(env, GTIMER_VIRT); |
|
797 |
} |
|
798 |
|
|
746 | 799 |
static uint64_t gt_get_countervalue(CPUARMState *env) |
747 | 800 |
{ |
748 | 801 |
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; |
... | ... | |
788 | 841 |
} |
789 | 842 |
} |
790 | 843 |
|
791 |
static int gt_cntfrq_read(CPUARMState *env, const ARMCPRegInfo *ri, |
|
792 |
uint64_t *value) |
|
793 |
{ |
|
794 |
/* Not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */ |
|
795 |
if (arm_current_pl(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) { |
|
796 |
return EXCP_UDEF; |
|
797 |
} |
|
798 |
*value = env->cp15.c14_cntfrq; |
|
799 |
return 0; |
|
800 |
} |
|
801 |
|
|
802 | 844 |
static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri) |
803 | 845 |
{ |
804 | 846 |
ARMCPU *cpu = arm_env_get_cpu(env); |
... | ... | |
810 | 852 |
static int gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri, |
811 | 853 |
uint64_t *value) |
812 | 854 |
{ |
813 |
int timeridx = ri->opc1 & 1; |
|
814 |
|
|
815 |
if (arm_current_pl(env) == 0 && |
|
816 |
!extract32(env->cp15.c14_cntkctl, timeridx, 1)) { |
|
817 |
return EXCP_UDEF; |
|
818 |
} |
|
819 | 855 |
*value = gt_get_countervalue(env); |
820 | 856 |
return 0; |
821 | 857 |
} |
822 | 858 |
|
823 |
static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri, |
|
824 |
uint64_t *value) |
|
825 |
{ |
|
826 |
int timeridx = ri->opc1 & 1; |
|
827 |
|
|
828 |
if (arm_current_pl(env) == 0 && |
|
829 |
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { |
|
830 |
return EXCP_UDEF; |
|
831 |
} |
|
832 |
*value = env->cp15.c14_timer[timeridx].cval; |
|
833 |
return 0; |
|
834 |
} |
|
835 |
|
|
836 | 859 |
static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, |
837 | 860 |
uint64_t value) |
838 | 861 |
{ |
... | ... | |
847 | 870 |
{ |
848 | 871 |
int timeridx = ri->crm & 1; |
849 | 872 |
|
850 |
if (arm_current_pl(env) == 0 && |
|
851 |
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { |
|
852 |
return EXCP_UDEF; |
|
853 |
} |
|
854 | 873 |
*value = (uint32_t)(env->cp15.c14_timer[timeridx].cval - |
855 | 874 |
gt_get_countervalue(env)); |
856 | 875 |
return 0; |
... | ... | |
867 | 886 |
return 0; |
868 | 887 |
} |
869 | 888 |
|
870 |
static int gt_ctl_read(CPUARMState *env, const ARMCPRegInfo *ri, |
|
871 |
uint64_t *value) |
|
872 |
{ |
|
873 |
int timeridx = ri->crm & 1; |
|
874 |
|
|
875 |
if (arm_current_pl(env) == 0 && |
|
876 |
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { |
|
877 |
return EXCP_UDEF; |
|
878 |
} |
|
879 |
*value = env->cp15.c14_timer[timeridx].ctl; |
|
880 |
return 0; |
|
881 |
} |
|
882 |
|
|
883 | 889 |
static int gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, |
884 | 890 |
uint64_t value) |
885 | 891 |
{ |
... | ... | |
924 | 930 |
.access = PL1_RW | PL0_R, |
925 | 931 |
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq), |
926 | 932 |
.resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE, |
927 |
.readfn = gt_cntfrq_read, .raw_readfn = raw_read,
|
|
933 |
.accessfn = gt_cntfrq_access,
|
|
928 | 934 |
}, |
929 | 935 |
/* overall control: mostly access permissions */ |
930 | 936 |
{ .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0, |
... | ... | |
937 | 943 |
.type = ARM_CP_IO, .access = PL1_RW | PL0_R, |
938 | 944 |
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), |
939 | 945 |
.resetvalue = 0, |
940 |
.readfn = gt_ctl_read, .writefn = gt_ctl_write,
|
|
941 |
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
|
946 |
.accessfn = gt_ptimer_access,
|
|
947 |
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
|
942 | 948 |
}, |
943 | 949 |
{ .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1, |
944 | 950 |
.type = ARM_CP_IO, .access = PL1_RW | PL0_R, |
945 | 951 |
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), |
946 | 952 |
.resetvalue = 0, |
947 |
.readfn = gt_ctl_read, .writefn = gt_ctl_write,
|
|
948 |
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
|
953 |
.accessfn = gt_vtimer_access,
|
|
954 |
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
|
949 | 955 |
}, |
950 | 956 |
/* TimerValue views: a 32 bit downcounting view of the underlying state */ |
951 | 957 |
{ .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0, |
952 | 958 |
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, |
959 |
.accessfn = gt_ptimer_access, |
|
953 | 960 |
.readfn = gt_tval_read, .writefn = gt_tval_write, |
954 | 961 |
}, |
955 | 962 |
{ .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0, |
956 | 963 |
.type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, |
964 |
.accessfn = gt_vtimer_access, |
|
957 | 965 |
.readfn = gt_tval_read, .writefn = gt_tval_write, |
958 | 966 |
}, |
959 | 967 |
/* The counter itself */ |
960 | 968 |
{ .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0, |
961 | 969 |
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, |
970 |
.accessfn = gt_pct_access, |
|
962 | 971 |
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset, |
963 | 972 |
}, |
964 | 973 |
{ .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1, |
965 | 974 |
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, |
975 |
.accessfn = gt_vct_access, |
|
966 | 976 |
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset, |
967 | 977 |
}, |
968 | 978 |
/* Comparison value, indicating when the timer goes off */ |
... | ... | |
971 | 981 |
.type = ARM_CP_64BIT | ARM_CP_IO, |
972 | 982 |
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), |
973 | 983 |
.resetvalue = 0, |
974 |
.readfn = gt_cval_read, .writefn = gt_cval_write,
|
|
975 |
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
|
984 |
.accessfn = gt_ptimer_access,
|
|
985 |
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
|
976 | 986 |
}, |
977 | 987 |
{ .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3, |
978 | 988 |
.access = PL1_RW | PL0_R, |
979 | 989 |
.type = ARM_CP_64BIT | ARM_CP_IO, |
980 | 990 |
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), |
981 | 991 |
.resetvalue = 0, |
982 |
.readfn = gt_cval_read, .writefn = gt_cval_write,
|
|
983 |
.raw_readfn = raw_read, .raw_writefn = raw_write,
|
|
992 |
.accessfn = gt_vtimer_access,
|
|
993 |
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
|
984 | 994 |
}, |
985 | 995 |
REGINFO_SENTINEL |
986 | 996 |
}; |
Also available in: Unified diff