|
| 1 | +.. _timer-hld: |
| 2 | + |
| 3 | +Timer |
| 4 | +##### |
| 5 | + |
| 6 | +Because ACRN is a flexible, lightweight reference hypervisor, we provide |
| 7 | +limited timer management services: |
| 8 | + |
| 9 | +- Only lapic tsc-deadline timer is supported as the clock source. |
| 10 | + |
| 11 | +- A timer can only be added on the logical CPU for a process or thread. Timer |
| 12 | + scheduling or timer migrating are not supported. |
| 13 | + |
| 14 | +How it works |
| 15 | +************ |
| 16 | + |
| 17 | +When the system boots, we check that the hardware supports lapic |
| 18 | +tsc-deadline timer by checking CPUID.01H:ECX.TSC_Deadline[bit 24]. If |
| 19 | +support is missing, we output an error message and panic the hypervisor. |
| 20 | +If supported, we register the timer interrupt callback that raises a |
| 21 | +timer softirq on each logical CPU and set the lapic timer mode to |
| 22 | +tsc-deadline timer mode by writing the local APIC LVT register. |
| 23 | + |
| 24 | +Data Structures and APIs |
| 25 | +************************ |
| 26 | + |
| 27 | +.. note:: API link to hv_timer and per_cpu_timer structs in include/arch/x86/timer.h |
| 28 | + And to the function APIs there too. |
| 29 | + |
| 30 | +Before adding a timer, we must initialize the timer with |
| 31 | +*initialize_timer*. The processor generates a timer interrupt when the |
| 32 | +value of timer-stamp counter is greater than or equal to the *fire_tsc* |
| 33 | +field. If you want to add a periodic timer, you should also pass the |
| 34 | +period (unit in tsc cycles), otherwise, period_in_cycle will be ignored. |
| 35 | +When the timer interrupt is generated, it will call the callback |
| 36 | +function *func* with parameter *priv_data*. |
| 37 | + |
| 38 | +The *initialize_timer* function only initialize the timer data |
| 39 | +structure; it will not program the ``IA32_TSC_DEADLINE_MSR`` to generate |
| 40 | +the timer interrupt. If you want to generate a timer interrupt, you must |
| 41 | +call *add_timer* to add the timer to the *per_cpu_timer* timer_list. In |
| 42 | +return, we will chose the nearest expired timer on the timer_list and |
| 43 | +program ``IA32_TSC_DEADLINE_MSR`` by writing its value to fire_ts. Then |
| 44 | +when the fire_tsc expires, it raises the interrupt whose callback raises |
| 45 | +a softirq. We will handle the software interrupt before the VM reenters |
| 46 | +the guest. (Currently, the hypervisor only uses the timer for the |
| 47 | +console). |
| 48 | + |
| 49 | +The timer softirq handler will check each expired timer on its |
| 50 | +timer_list. Before calling the expired timer callback handler, it will |
| 51 | +remove the timer from its logical cpu timer_list. After calling the |
| 52 | +timer callback handler, it will re-add the timer to the timer_list if |
| 53 | +it’s a periodic timer. If you want to modify a timer before it expires, |
| 54 | +you should call del_timer to remove the timer from the timer_list, then |
| 55 | +call add_timer again after updating the timer fields. |
| 56 | + |
| 57 | +.. note:: |
| 58 | + |
| 59 | + Only call initialize_timer only once for each timer. |
| 60 | + Don't call add_timer or del_timer in the timer callback function. |
0 commit comments