个人技术分享

ARMv8/v9 system counter

所有使用Arm处理器的系统中都会包含一个标准化的通用定时器(Generic Timer)框架。这个通用定时器系统提供了一个系统计数器(System Counter)和一组定时器(Timer)。其结构类似下图:
在这里插入图片描述
系统计数器是全局唯一的,并且全局共享,对系统中的所有Arm核心进行广播。

  • ARMv8.0 到 ARMv8.5(含):位宽:至少56位宽。任何64位读取的计数器值都会被零扩展到64位。频率:以固定频率递增,该频率通常在1-50MHz范围内。它可以支持一个或多个备选操作模式,在这些模式中,计数器以较大的数额递增,频率较低,通常用于节能。
  • 从 ARMv8.6 开始 位宽:必须是64位宽,频率:以固定的1GHz频率递增,翻转时间:不少于40年。

这个系统计数器还是一直存在的,哪怕系统处于待机状态,所有内核都被关闭了,它仍然可以工作。

需要注意的是system counter必须实现于always-on power domian. 在 ARMv8.0 到 ARMv8.5期间,为了配合低功耗的工作,system counter 如果运行低频率下,那么每个时钟周期可以增长一个相对较大的值,例如:在10M的时候每个时钟周期增长步长为1,但是在低功耗模式下运行在20KHz的时候,每个时钟周期增长步长为500。

从ARMv8.6 开始system counter运在固定的1GHz, ARM 解释说 尽管它的时钟周期为1ns,但是这并不需要每过1ns counter的值就增加1,它的增长步长不能低于200。

system counter读取函数实现

global syscnt
syscnt:
    STP X29, X30, [SP, #-16]!
    MOV X29, SP
	MRS X0, CNTPCT_EL0
    LDP X29, X30, [SP], #16
	RET

syscnt 使用举例

void syscnt_test(void)
{
        uint64_t start, end;

        start = syscnt();
        asm ("isb");
        end = syscnt();
        log_info("end:0x%llx - start:0x%llx = 0x%llx\n", start, end, end-start);
}

测试结果

[info]: syscnt_test(671): end:0xda8e32 - start:0xda8f54 = 0x122