900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Linux 驱动开发 三十四:Linux 内核定时器原理

Linux 驱动开发 三十四:Linux 内核定时器原理

时间:2019-08-11 17:58:40

相关推荐

Linux 驱动开发 三十四:Linux 内核定时器原理

参考文档:

《Cortex -A7 MPCore Technical Reference Manual》Chapter 9:Generic Timer

《ARM ® Architecture Reference Manual ARMv7-A and ARMv7-R edition》Chapter B8:The Generic Timer

一、Chapter B8 The Generic Timer 翻译

这一章节描述ARM通用定时器的实现ARM通用定时器实现对于ARMv7-AARMv7-R架构处理器是一个可扩展选项。它包括定义了ARM通用寄存器的系统控制接口。

包含以下章节:

关于通用定时器B8-1960页)通用定时器寄存器摘要B8-1969页)

Appendix D5 System Level Implementation of the Generic Timer描述通用定时器系统实现等级

注:Chapter B4 System Control Registers in a VMSA implementationChapter B6 System Control Registers in a PMSA implementation都描述通用定时器CP15寄存器大多数寄存器被包含在VMSAPMSA实现中,对于这些寄存器,VMSAPMSA实现中的位分配是相同的。但是,本章中的大多数寄存器引用都链接到Chapter B4中的寄存器描述。

1、关于通用定时器

B8-1中展示使用通用定时器作为系统定时器的一个片上系统的示例。在这个图片中:

本手册定义了多处理器块中各个处理器的体系结构。

《ARM Generic Interrupt Controller Architecture Specification》GIC定义了一个可能的架构。

通用计时器功能分布在多个组件中。

本章:

给出通用定时器一般描述

定义通用计时器的系统控制寄存器接口。图B8-1中所示的每个处理器都包含此接口的实现。

通用定时器:

提供一个系统计数器,实时测量时间的流逝。在支持虚拟化的系统中,支持测量虚拟时间流逝的虚拟计数器。也就是说,虚拟计数器可以测量特定虚拟机上的时间流逝。提供定时器,它可以在一段时间过去后断言计时器输出信号。计时器: 可以向上向下计数。在支持虚拟化的组件中,可以实时或虚拟运行。

注:定时器输出信号可以用作电平敏感中断信号。

1、系统计数器

通用定时器提供了一个具有以下规范的系统计数器:

Width:至少56位宽。计数器的任何64位读取返回的值都是零扩展为64位。

Frequency固定频率的增量,通常在1-50MHz范围内。可以支持一种或多种可选的工作模式,在这种模式下,它以较低的频率递增较大的数量,通常用于节省功耗。

Roll-over:周转时间不少于40年。

AccuracyARM没有指定所需的精度,但建议计数器在24小时周期内增益或损失不超过10秒。低频模式的使用不能影响实现的精度。

Start-up:从零开始运行。

系统计数器必须提供系统时间的统一视图。更准确地说,以下事件序列必须无法显示系统时间的倒退:

设备A从系统计数器读取时间。设备A与系统中的另一个设备B通信。设备B识别出与设备A的通信后,从系统计数器中读取时间。

系统计数器必须在始终接通的电源域中实现。

为了支持低功耗工作模式,计数器可以在较低频率下以更大的数量递增。例如,一个10MHz的系统计数器可以增加:

10MHz增加1。在20kHz增加500,当系统降低时钟频率时,降低功耗

在这种情况下,计数器必须支持高频率高精度低频率低精度之间的转换,而不影响计数器所需的精度

软件可以访问CNTFRQ寄存器以读取系统计数器的时钟频率,并且具有足够权限的软件可以修改该寄存器的值。详细信息见Initializing and reading the system counter frequency

从系统计数器的计数被分配到系统组件的机制是由具体实现定义的,但是每个具有系统控制寄存器接口到系统计数器的处理器必须包含一个计数器输入,该输入可以捕获计数器的每个增量。

注:因此,系统计数器可以独立于处理器进行计时,计数值可以使用Gray代码序列进行分配。Gray-count scheme for timer distribution scheme on page D5-2427给出更多信息。

初始化和读取系统计数器频率

通常,系统以固定频率驱动系统计数器,在系统引导过程中,CNTFRQ寄存器必须编程为这个值。在一个支持ARM安全扩展的实现中,只有在安全PL1模式下执行的软件才能写入CNTFRQ。如果系统允许对系统计数器频率进行任何配置,则必须确保CNTFRQ始终编程为正确的系统计数器频率。

注:CNTFRQ寄存器在复位时是未知的,因此计数器频率必须写入CNTFRQ作为系统引导过程的一部分。

软件可以读取CNTFRQ寄存器,以确定当前系统计数器频率,处于以下状态和模式:

不安全的PL2模式。安全和非安全PL1模式。当CNTKCTL.PL0PCTEN设置为1时,“安全"和"不安全”PL0模式。

系统计数器的内存映射控件

某些系统计数器控件只能通过与系统计数器的内存映射接口进行访问。这些控件包括:

启用和禁用计数器。设置计数器值。更改操作模式,以更改更新频率和增量值。启用调试时暂停,然后调试器可以使用该调试器挂起计数。

对于更多描述见Appendix D5 System Level Implementation of the Generic Timer

2、物理计数器

处理器提供一个物理计数器,该计数器包含系统计数器的计数值。CNTPCT寄存器保存当前的物理计数器值。

访问物理计数器

具有足够权限的软件可以使用64位系统控制寄存器读取CNTPCT

不包括虚拟化扩展的实现中,无论安全状态如何,始终可以从PL1模式访问CNTPCT

包含虚拟化扩展的实现中,CNTPCT

始终可以从安全PL1模式和非安全Hyp模式访问。仅当CNTHCTL.PL1PCTEN设置为1时,才能从非安全PL1模式访问。当CNTHCTL.PL1PCTEN设置为0时,任何从非安全PL1模式访问CNTPCT的尝试都会产生一个Hyp Trap异常。详细信息见Hyp Trap exception on page B1-1209

此外,当CNTHCTL.PL1PCTEN设置为1时,如果在当前安全状态下可以从PL1模式访问CNTPCT,那么在该安全状态下也可以从PL0模式访问CNTPCT

CNTKCTL.PL0PCTEN设置为0时,任何从PL0模式访问CNTPCT的尝试都会产生一个Undefined Instruction异常。

在包含虚拟化扩展的实现中:

CNTKCTL控件的优先级高于CNTHCTL控件。当下面两个都适用时,这意味着尝试从非安全PL0模式访问CNTPCT会产生一个Undefined Instruction异常:CNTHCTL.PL1PCTEN设置为0,表示禁止非安全PL1模式访问。CNTHCTL.PL0PCTEN设置为0,表示禁止PL0模式访问。 启用PL0访问后,CNTHCTL将应用于不安全的PL0访问。当同时满足以下两种情况时,这意味着尝试从非安全PL0模式访问CNTPCT将生成Hyp Trap异常:CNTHCTL.PL1PCTEN设置为0,禁用非安全PL1模式访问。CNTHCTL.PL0PCTEN设置为1,以允许从PL0模式访问。

CNTPCT的读取可以推测性地发生,并且相对于在同一处理器上执行的其他指令而言是无序的。例如,如果从内存中读取用于从另一个代理获取信号,该信号指示必须读取CNTPCT,必须使用ISB来确保在从存储器读取信号后读取CNTPCT,如以下代码序列所示:

3、虚拟计数器

通用计时器的实现始终包括一个虚拟计数器,该计数器指示虚拟时间:

不包括虚拟化扩展的处理器实现中,虚拟时间与物理时间相同,并且虚拟计数器包含与物理计数器相同的值。在包含虚拟化扩展的处理器实现中,虚拟计数器包含物理计数器的值减去64位虚拟偏移量。在不安全的PL1PL0模式下执行时,虚拟偏移量值与当前虚拟机相关。

包含虚拟化扩展的处理器实现中,CNTVOFF寄存器包含虚拟偏移。CNTVOFF只能从Hyp模式访问,当SCR.NS设置为1时,只能从监视器模式访问。

注:通用计时器的所有实现都包括虚拟计数器。但是,只有支持虚拟化的系统才能明确区分物理时间和虚拟时间,并且:

支持虚拟化的系统中,CNTVOFF作为RW寄存器实现。在不支持虚拟化的系统中: 如果系统包含安全扩展,则从安全监视器模式访问CNTVOFF是不可预测的。虚拟计数器的行为就像CNTVOFF为零一样。

更多信息看Status of the CNTVOFF register on page B8-1970

CNTVCT寄存器保存当前虚拟计数器值。

访问虚拟计数器

具有足够权限的软件可以使用64位系统控制寄存器读取CNTVCT

CNTVCT始终可从安全PL1模式以及非安全PL1PL2模式访问。

此外,当CNTKCTL.PL0VCTEN设置为1时,可以从PL0模式访问CNTVCT

CNTKCTL.PL0VCTEN设置为0时,任何从PL0模式访问CNTVCT的尝试都会生成Undefined Instruction异常。

CNTVCT的读取可以推测性地发生,并且相对于在同一处理器上执行的其他指令而言是无序的。例如,如果从内存中读取用于从另一个代理获取指示必须读取CNTVCT的信号,必须使用ISB来确保在从内存读取信号后读取CNTVCT,如以下代码序列所示:

4、事件流

包含通用计时器的实现可以使用系统计数器生成一个或多个事件流,以生成定期唤醒事件,作为Wait For Event and Send Event on page B1-1200中描述的机制的一部分。

注:可以使用事件流:

对等待事件轮询循环施加超时。防止任何导致不会生成预期事件的编程错误。

事件流通过以下方式配置:

从计数器的底部16位中选择哪个位将生成事件。这决定了流中事件的频率。选择是在所选计数器位的每个01转换或每个10转换时生成事件。

CNTKCTL.{EVNTEN, EVNTDIR, EVNTI}字段定义从虚拟计数器生成的事件流。

在包含虚拟化扩展的实现中,CNTHCTL.{EVNTEN, EVNTDIR, EVNTI}字段定义从物理计数器生成的事件流。

事件流的操作如下:

伪代码变量PreviousCNTVCTPreviousCNTPCT声明为:

// Variables used for generation of the timer event stream. bits(64) PreviousCNTVCT; bits(64) PreviousCNTPCT;

伪代码函数TestEventCNTV()TestEventCNTP()在处理器时钟的每个周期上调用。TestEventCNTx()伪代码模板定义了函数TestEventCNTV()TestEventCNTP()

5、定时器

通用计时器的实现提供的计时器数取决于实现是否包括安全扩展和虚拟化扩展,如下所示:

未实现安全扩展插件

该实现提供了物理计时器和虚拟计时器。

已实现安全扩展,未实施虚拟化扩展

该实现提供:

不安全的物理计时器。安全的物理计时器。虚拟计时器。

实现的虚拟化扩展

该实现提供:

不安全的PL1物理计时器。安全PL1物理计时器。不安全的PL2物理计时器。虚拟计时器。

每个已实现计时器的输出:

向系统提供输出信号。如果处理器连接到通用中断控制器 (GIC),则向该 GIC 发出专用外设中断 (PPI) 信号。在多处理器实现中,每个处理器必须为每个计时器使用相同的中断号。

每个计时器实现为三个寄存器:

64CompareValue寄存器,提供64位无符号upcounter。一个32位的TimerValue寄存器,它提供了一个32位的签名下行计数器。32位控制寄存器。

在包含安全扩展的处理器实现中,PL1物理计时器的寄存器被存放,以提供计时器的安全和非安全实现。表B8-1显示了定时器寄存器。

Table B8-2 on page B8-1969包括对这些寄存器的描述的引用。

以下各节介绍计时器的操作:

访问计时器寄存器定时器的CompareValue视图的操作定时器的TimerValue视图的操作操作时输出定时器信号

访问计时器寄存器

对于每个计时器,所有计时器寄存器都具有相同的访问权限,如下所示:

PL1 physical timer

PL1模式访问,除非实现包括虚拟化扩展,否则执行在PL2上的非安全软件控制从非安全PL1模式访问。

当允许从PL1模式访问时,CNTKCTL.PL0PTEN确定寄存器是否可以从PL0模式访问。如果因为CNTKCTL.PL0PTEN被设置为0而不允许访问,尝试从PL0模式访问会产生一个Undefined Instruction异常。

如果实现包括安全扩展插件:

除了从Monitor模式访问外,访问都是针对当前安全状态的寄存器。对于Monitor模式的访问,SCR.NS的值决定访问的是安全寄存器还是非安全寄存器。

如果实现包括虚拟化扩展:

非安全寄存器可从Hyp模式访问。

CNTHCTL.PL1PCEN确定非安全寄存器是否可以从非安全PL1模式访问。如果此位设置为1,则启用从非安全PL1模式的访问,CNTKCTL.PL0PTEN将确定寄存器是否可以从非安全PL0模式访问。

如果因为CNTHCTL.PL1PCEN设置为0而不允许访问,则从非安全PL1或PL0模式访问时,会产生Hyp Trap异常。但是,如果CNTKCTL.PL0PTEN设置为0,这个控件优先,并且试图从PL0访问会产生一个Undefined Instruction异常。

Virtual timer

可从安全和非安全PL1模式以及Hyp模式访问。

CNTKCTL.PL0VTEN确定寄存器是否可以从PL0模式访问。如果因为CNTKCTL.PL0VTEN被设置为0而不允许访问,尝试从PL0模式访问会产生一个Undefined Instruction异常。

PL2 physical timer

SCR.NS设置为1时,可从非安全催眠模式以及从安全监视器模式访问。

定时器的CompareValue视图的操作

计时器的CompareValue视图作为64upcounter运行。当相应的计数器达到编程到CompareValue寄存器中的值时,满足定时器条件。当计时器条件满足时,只有当计时器启用,且该信号在相应的计时器控制寄存器CNTP_CTLCNTHP_CTLCNTV_CTL中没有被屏蔽时,才会断言定时器输出信号。

注:

定时器输出信号可用作电平敏感中断信号。在CompareValue视图操作的伪代码描述中,EventTriggered指示是否满足计时器条件。它不指示是否断言定时器输出信号。

计时器的此视图的操作是:

EventTriggered = (((Counter[63:0] – Offset[63:0])[63:0] - CompareValue[63:0]) >= 0)

EventTriggered:如果满足此计时器的条件,则为TRUE,否则为FALSE

Counter:物理计数器值,可以从CNTPCT寄存器读取。(注:可以从CNTVCT寄存器中读取的虚拟计数器值就是这个值)。

Offset:对于物理计时器,以及不包含虚拟化扩展的实现中的虚拟计时器,偏移量为零。对于包含虚拟化扩展的实现中的虚拟计时器,Offset是保存在CNTVOFF寄存器中的虚拟偏移量。

CompareValue:相应的CompareValue寄存器、CNTP_CVALCNTHP_CVALCNTV_CVAL的值。

在此计时器视图中,计数器、偏移量和比较值都是64位无符号值。

这意味着可能永远不会满足CompareValue等于或接近0xFFFFFFFFFFFFFFFF的计时器的计时器条件。但是,没有实际要求使用接近计数器包装值的值。

定时器的TimerValue视图的操作

定时器的TimerValue视图作为带符号的32downcounter操作。一个TimerValue寄存器是用一个计数值编程的。这个值随着相应计数器的每一次增量而递减,当该值为零时,计时器条件就满足了。当计时器条件满足时,只有当计时器启用,且该信号在相应的计时器控制寄存器CNTP_CTLCNTHP_CTLCNTV_CTL中没有被屏蔽时,才会断言定时器输出信号。

注:

定时器输出信号可用作电平敏感中断信号。在CompareValue视图操作的伪代码说明中,EventTriggered指示是否满足计时器条件。它不指示定时器输出信号是否被置位。

定时器的这个视图依赖于以下访问TimerValue寄存器的行为:

ReadsTimerValue = (CompareValue – (Counter - Offset))[31:0]WritesCompareValue = ((Counter - Offset)[63:0] + SignExtend(TimerValue))[63:0]

其中参数具有Operation of the CompareValue views of the timers on page B8-1966中使用的定义,此外:

TimerValueTimerValue寄存器的值,CNTP_TVALCNTHP_TVALCNTV_TVAL

这个定时器视图的操作是有效的:EventTriggered = (TimerValue ≤ 0)

在计时器的这个视图中,所有值都是有符号的,采用标准的2的补码形式。

在满足计时器条件之后,读取TimerValue寄存器将指示自满足该条件以来的时间。

注:将TimerValue编程为一个大小大于(Counter-Offset)的负数可能会导致算术溢出,从而导致CompareValue成为一个非常大的正值。这可能意味着在极长的一段时间内不满足计时器条件。

定时器输出信号的操作

只要满足以下所有条件,定时器输出信号就会置位:

至少满足其中一个计时器条件,详细信息看Operation of the CompareValue views of the timers on page B8-1966Operation of the TimerValue views of the timers on page B8-1967。在定时器控制寄存器CNTP_CTLCNTHP_CTLCNTV_CTL中: 启用定时器。定时器输出信号没有被屏蔽。

这意味着,要取消定时器输出信号的断言,软件必须执行以下操作之一:

对计时器寄存器重新编程,以便不满足任何计时器条件。屏蔽定时器输出信号,在定时器控制寄存器中。在计时器控制寄存器中禁用计时器。

2、通用定时器寄存器摘要

B8-2显示了包含通用计时器扩展的实现中的CP15寄存器。实现的寄存器集取决于实现是否也包括虚拟化扩展。

1、CNTVOFF 状态寄存器

通用计时器扩展的所有实现都包括虚拟计数器。因此,从概念上讲,所有实现都包括CNTVOFF寄存器,该寄存器定义物理计数和虚拟计数之间的虚拟偏移。在不支持虚拟化的实现中,这个偏移量为零。CNTVOFF被定义为PL2模式寄存器,详细信息见Banked PL2-mode CP15 read/write registers on page B3-1454。这意味着:

在包含虚拟化扩展的实现中,CNTVOFF是一个RW寄存器,当SCR.NS设置为1时,可以从非安全Hyp模式和从安全监视器模式访问。CNTVOFF编码的MCRRMRRC未定义: 当SCR.NS设置为0时,以Monitor模式执行。如果不是在Monitor模式或Hyp模式下执行。 在包含安全扩展但不包括虚拟化扩展的实现中,CNTVOFF编码的MCRRMRRC是: 如果在监视模式下执行,则不可预知,而不考虑SCR.NS的值。如果在非Monitor模式下执行,则未定义。 在不包括安全扩展插件(包括任何PMSA实现)的实现中,尽管寄存器在概念上存在,但无法访问它。寄存器的MCRRMRRC指令编码未定义。

在所有CNTVOFF寄存器没有定义为RW寄存器的情况下,虚拟计数器使用固定的虚拟偏移值0

二、Chapter 9:Generic Timer 翻译

本章介绍Cortex-A7 MPCore处理器的通用计时器。它包含以下部分:

关于通用计时器通用计时器功能说明定时器编程模型

1、关于通用定时器

通用定时器可以根据递增的计数器值调度事件和触发中断。它提供了:

生成定时器事件作为中断输出。生成事件流。支持虚拟化扩展。

Cortex-A7 MPCore定时器符合ARM架构参考手册。

本章仅介绍特定于Cortex-A7 MPCore实现的功能。

2、通用计时器功能说明

Cortex-A7 MPCore处理器为集群中的每个处理器提供了一组四个计时器。

物理计时器,用于安全和非安全PL1模式。物理计时器的寄存器被存入以提供安全和非安全副本。虚拟计时器,用于非安全PL1模式。物理定时器使用在Hyp模式。

计数器值通过同步二进制编码的64位总线分发到处理器,CNTVALUEB[63:0]

A-6中表A-4显示了外部中断输出引脚的信号。

3、定时器编程模型

在每个处理器中,一组定时器寄存器被分配到CP15协处理器空间。定时器寄存器的宽度为32位或64位宽。

9-1显示了系统定时器寄存器。

三、通用定时器总结

参考博客:Linux时间子系统之(十七):ARM generic timer驱动代码分析 ()

1、通用定时器框架

上图为ARMv7-AARMv7-R架构使用通用定时器作为系统定时器的一个示例。

generic timer相关硬件包括System counterCounter interfaceTimer_xSystem events组成。

System counter:用来记录时间的流逝,多个处理器共享。主要功能是统计输入时钟已经过了多少个clock

Counter interfaceSystem counterTimer_x信息交互接口。

Timer_x:用来触发timer事件。

System countercounter value需要分发到各个timer中,也就是说,从各个timer的角度看,system counter value应该是一致的。Timer其实就是定时器,它可以定义一段指定的时间,当时间到了,就会触发一个外部的输出信号(可以输出到GIC,作为一个interrupt源)。

2、System Counter 要求

1、System counter的计数器有多少bit

至少56bit,和具体的实现相关。

2、输出频率范围?

典型值是1M~50MHz

3、操作模式?

正常的时候,每个clock都会加一,但是,在power saving mode的时候,我们希望功耗可以更低一些,这时候会考虑将system clock的输入频率降低下来,例如降低4倍。为了保证system counter的计时是准确的,可以设定每个clock增加4,而不是加1,这样system counter的计时仍然保持准确。

4、溢出时间?

至少40年。

5、精度要求?

未规定,推荐是每24小时在正负10秒的误差。

6、reset值?

0

7、是否支持debug

可以设定enable halt-on-debug。这个和JTAG调试相关。如果你使用JTAG调试,在单步运行的时候当然系统counter停下来,否则timer的中断就会来了,导致你无法正常的进行程序代码跟踪。

3、定时器使用

各个cputimer是根据system counter的值来触发timer event的,因此,系统中一定有一个机制让System counter的值广播到各个CPUtimer上,同时运行在各个processor上的软件可以通过接口获取System counter的值。

处理器可以通过CNTPCT寄存器来获取system counter的当前值,我们称之physical counter(物理计数器) 。有physical就有virtualprocessor可以通过CNTVCT寄存器访问virtual counter(虚拟计数器),不过,对于不支持security extension(安全扩展) 和virtualization extension(虚拟扩展) 的系统,virtual counterphysical counter是一样的值。

系统中每个processor都会附着多个timer,具体如下:

1、对于不支持security extensionSOC(不支持security extension也就意味着 不支持virtualization extension),timer实际上有两个,一个是physical timer,另外一个是virtual timer。虽然有两个,不过从行为上看,virtual timerphysical timer行为一致。

2、对于支持security extension但不支持virtualization extensionSOC,每个cpu有三个timerNon-secure physical timerSecure physical timervirtual timer

3、对于支持virtualization extensionSOC,每个cpu有四个timerNon-secure PL1 physical timerSecure PL1 physical timerNon-secure PL2 physical timervirtual timer

每个timer都会有三个寄存器(我们用physical timer为例描述):

1、64-bit CompareValue register

该寄存器配合system counter可以实现一个64 bit unsigned upcounter。如果physical counter - CompareValue >= 0的话,触发中断。也就是说,CompareValue register其实就是一个64比特的upcounter,设定为一个比当前system counter要大的值,随着system counter的不断累加,当system counter value触及CompareValue register设定的值的时候,便会向GIC触发中断。

2、32-bit TimerValue register

该寄存器配合system counter可以实现一个32 bit signed downcounter(有的时候,使用downcounter会让软件逻辑更容易,看ARM generic timer的设计人员考虑的多么周到)。开始的时候,我们可以设定TimerValue寄存器的值为1000(假设我们想down count 1000,然后触发中断),向该寄存器写入1000实际上也就是设定了CompareValue register的值是system counter值加上1000。随着system counter的值不断累加,TimerValue register的值在递减,当值<=0的时候,便会向GIC触发中断。

3、32-bit控制寄存器

该寄存器主要对timer进行控制,具体包括:enable或是disabletimermask或者unmasktimeroutput signal(timer interrupt)

四、软件编程接口

ARM generic timer的硬件包括两个部分:一个是每个cputimer硬件,另外一个就是system levelcounter硬件。对于每个cputimer硬件,使用system control register(CP15)来访问是最合适的,而且速度也快。要访问system levelcounter硬件,当然使用memory mapped IO的形式(请注意架构图中的APB总线,很多system level的外设都是通过APB访问的)。

五、Linux 内核 generic timer 相关源码分析

未完成

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。