本文节选自孙陈伟著《嵌入式Hypervisor架构、原里与应用》Hypervisor 的关键功能之一是提供虚拟时钟服务。PRTOS 中的虚拟时钟可以为每个分区提供时钟计时,并独立于主机系统时钟,旨在允许虚拟机运行自己的操作系统和应用程序,并协调分区的内部任务,且不会干扰其他分区。虚拟时钟通过截获硬件时钟事件并模拟与时间相关的事件(例如使用定时器中断和时钟滴答)来实现。当分区请求虚拟时钟服务(例如获取当前时间)时,虚拟时钟服务会读取硬件时钟的实时值,并根据分区调度等因素进行调整计算,再返回虚拟时间。在 PRTOS 系统中,分区通过调用 PRTOS 提供的虚拟时钟接口获取当前的时间戳,用于满足以下 5 种需求。1)分区系统可以发现某个陷入死循环(由编程错误引起)的任务,并做出相应处理。2)在分区实时系统中,按要求的时间间隔,为实时控制设备输出正确的时间信号。3)PRTOS 调度程序按照事先给定的时间定时唤醒对应的分区。5)PRTOS 系统记录用户和系统所需要的绝对时间。PRTOS 使用数据结构 hw_clock_t 来管理硬件时钟,具体实现请参考源码 core/include/ktimer.h。硬件时钟是全局时钟,不管是单处理器硬件平台,还是 SMP 硬件平台,都只使用一个全局硬件时钟。针对 Intel X86 硬件平台的 3 种不同的时钟硬件,PRTOS 提供了 3 种时钟驱动,分别是 Intel 8253 时钟驱动、TSC 时钟驱动、HPET(High Precision Event Timer,高精度事件时钟)时钟驱动,如图 3-2 所示。Intel 8253 是一种常见的可编程间隔定时器,常用作计算机系统中的时钟驱动,用于生成精确的时间间隔和周期性中断。Intel 8253 通常由系统软件通过编程来配置和控制,包含 3 个独立的计数器通道,并且每个通道都可以用作定时器或计数器。每个通道都有一个 16 位计数器,可以根据需要进行加载和读取。PRTOS 可以将 Intel 8253 用作系统的时钟源,通过设定计数器的初始值和工作模式生成固定的时钟间隔,用于操作系统的调度和计时。在 X86 单核硬件平台上,PRTOS将 Intel 8253 PIT 的通道 0 作为计时通道,通道 0 的定时器设置为(Binary, Mode 2, LSB/MSB),即周期为 1ms 的周期触发模式,并定义一个全局结构 struct pit_clock_data 来记录PRTOS 启动后的定时中断发生次数,再结合当前通道 0 中计数器的值,可以计算出 PRTOS自启动后到当前时刻的精确到微秒的时间戳。具体实现参考 PRTOS 源码 core/kernel/x86/pit.c。
TSC 是一个 64 位的寄存器,从 Intel Pentium 开始,在所有的 X86 平台上均会提供。它存放的是 CPU 从启动以来执行的时钟周期,因此可以用来精确地测量程序的执行时间。TSC 由处理器硬件提供,因此它的计时操作比使用软件定时器要快得多,这使得 TSC 成为性能分析和调试工具中的一个重要组件。在某些情况下,使用 TSC 进行时间测量可以提高精度,并且不会受到操作系统时钟频率调整的影响。要使用 TSC,需要使用相关的 CPU 指令来读取 TSC 寄存器的值。例如,在 X86 架构中,可以使用 rdtsc 指令来读取 TSC 寄存器的值。rdtsc 指令将 TSC 寄存器的值读取到EDX:EAX 寄存器中(高 32 位保存在 EDX 寄存器中,低 32 位保存在 EAX 寄存器中)。由于 TSC 是对驱动 CPU 的时钟脉冲进行计数的,因此 TSC 的频率就是 CPU 的时钟频率。基于 TSC 的时钟驱动实现,请参考 PRTOS 源码 core/kernel/x86/tsc.c。
提示:TSC 也存在一些限制。由于 TSC 基于 CPU 主频(记录 CPU 的时钟脉冲),因此在多核 CPU 或 CPU 频率变化的情况下,不同处理器核心或不同 CPU 之间的 TSC 可能不同步,导致计时不准确。为了解决这个问题,一些处理器提供了 TSC 同步机制,例如 Intel 的 TSC 同步引擎(TSC Sync Engine)和 AMD 的 TSC 同步模式(TSC SyncMode)。另外,TSC 还可能受到频率变化、睡眠模式和动态频率调整等因素的影响。比如,空闲的操作系统内核可能会调用 HALT 指令,使处理器完全停止,直到接收到外部中断被唤醒,在此期间 TSC 停止计数。
HPET 是一种高精度定时器。它是一种系统级别的硬件设备,通常用于代替早期的定时器,如 Intel 8253 PIT。与早期的定时器相比,HPET 具有更高的分辨率和更准确的时钟频率,并且可以更精确地测量和记录系统事件和时间间隔。HPET 通常由系统主板上的芯片提供支持,并且可以在 BIOS 中进行配置。具体实现可参考 PRTOS 源码 core/kernel/x86/hpet.c。
提示:在 X86 单处理器硬件平台中,PRTOS 用 Intel 8253 PIT 或者 TSC 定时器作为时钟源;在 X86 多处理器硬件平台中,PRTOS 用 HEPT 定时器作为时钟源。
PRTOS 的定时器组件用于分区调度、追踪分区中的时间以及处理虚拟机中的事件。类似 PRTOS 的时钟硬件,PRTOS 也为硬件定时器定义了一组驱动。PRTOS 使用定时器驱动数据结构 hw_timer_t 来管理硬件定时器,具体定义请参考源码core/include/ktimer.h。硬件定时器资源属于 Per-CPU 资源。不管是单处理器硬件平台还是多处理器硬件平台,硬件定时器和 pCPU 都是一一对应关系,每个 pCPU 独占一个硬件定时器。PRTOS 的 hw_timer_t 定时器接口基于 3 种不同的定时器硬件提供了 3 种类型的定时器驱动,分别是 Intel 8253 定时器驱动、HPET 定时器驱动和 LAPIC(Local AdvancedProgrammable Interrupt Controller,本地高级可编程中断控制器)定时器驱动,如图 3-3所示。
提示:Per-CPU 资源是每个 CPU 专用的资源,只有所属的 CPU 才可以访问。如果 PRTOS 选中 Intel 8253 PIT 作为硬件时钟源(即 CONFIG_PC_PIT_CLOCK 宏将被定义),PIT 的通道 1 定时器工作在周期性触发模式,PRTOS 使用全局变量 pit_clock_data来记录时钟中断的触发次数,以辅助实现 PRTOS 的时钟驱动。Intel 8253 PIT 定时器驱动的实现,请参考 PRTOS 源码 core/kernel/x86/pit.c。
提示:32 位 X86 单核处理器硬件平台(基于 QEMU 或者 VMware Workstation 创建)均采用 Intel 8253 作为定时器硬件。
HPET 定时器驱动用于操作和管理 HPET 硬件定时器。使用 HPET 定时器驱动可以在PRTOS 中实现高精度的定时功能,从而满足实时性要求高的应用程序和系统的需求。在PRTOS 内核中,HPET 的管理机制和 Intel 8253(或 Intel 8254)PIT 类似,具体实现可参考源码 core/kernel/x86/hpet.c。LAPIC 定时器是集成在 pCPU 中的本地定时器,用于提供处理器级别的定时和中断功能。LAPIC 定时器驱动用于操作和管理 LAPIC 定时器,它对于实现处理器级别的定时和中断功能非常重要,在操作系统和应用程序中应用广泛,用于实现定时任务、计时、事件触发和性能测量等功能。LAPIC 定时器的具体实现可参考 PRTOS 源码 core/kernel/x86/lapic_timer.c。
提示:硬件定时器是 Per-CPU 专用的硬件资源。在单处理器硬件平台上,无论选择Intel 8253 PIT 定时器,还是选择 HPET 硬件定时器,定时器资源都是 Per-CPU 类型的;在多处理器硬件平台上,LAPIC 定时器集成在 CPU 内部。当 PRTOS 配置成支持 SMP模式时,只能选择 LAPIC 定时器。
7月21号(本周日)晚20:00,本书作者在阅码场有一场直播分享,欢迎大家届时观看,加微信入群:linuxer2016