Virtualizing the Generic Timers
The Arm architecture includes the Generic Timer, which is a standardized set of timers available in each processor. The Generic Timer consists of a set of comparators that compare against a common system count. A comparator generates an interrupt when its value is equal to or less than the system count. In the following diagram, we can see the Generic Timer in a system (orange), and its components of comparators and a counter module.
The following diagram shows an example system with a hypervisor that hosts two virtual CPUs (vCPUs):
Note: In the example, we ignore the overhead of running the hypervisor to context switch between the vCPUs.
After 4ms of physical time, or wall-clock time, each vCPU has run for 2ms. If vCPU0 had set up its comparator at T=0 to generate an interrupt after 3ms, would you expect the interrupt to have fired?
Alternatively, do you want an interrupt after 2ms of virtual time, which is time experienced by the vCPU, or after 2ms of wall-clock time?
The Arm architecture provides the ability to do both, depending on what virtualization is being used for. Let's see how it does this.
Software running on a vCPU has access to two timers:
- EL1 Physical Timer
- EL1 Virtual Timer
The EL1 Physical Timer compares against the count generated by the system counter module. Using this timer gives wall-clock time.
The EL1 Virtual Timer compares against a virtual count. The virtual count is the physical count minus an offset. The hypervisor specifies the offset for the currently scheduled vCPU in a register. This allows it to hide the passage of time while the vCPU was not scheduled to run:
To illustrate this concept, we can extend the earlier example as shown in the following diagram:
Over a period of 6ms, each vCPU gets to run for 3ms. A hypervisor could use the offset register to present a virtual count that only shows time the vCPU was running. Or the hypervisor could keep the offset at 0, which would mean that virtual time was the same as physical time.
Note: The example shows the frequency of the System Count as 1ms. In practice, this frequency value is very unlikely. We recommend that you set the System Count to use a frequency of between 1MHz and 50MHz.