AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/arch.h"
2#include "hv/config.h"
3#include "hv/timer.h"
4#include "hv/uart.h"
5#include "hv/vcpu.h"
6
7static uint64_t g_cntfrq;
8
9void timer_init(void)
10{
11 g_cntfrq = arch_cntfrq_el0();
12}
13
14uint64_t timer_now(void)
15{
16 return arch_cntpct_el0();
17}
18
19void timer_dump(void)
20{
21 uart_puts("timer cntfrq=");
22 uart_put_dec64(g_cntfrq);
23 uart_puts(" cntpct=");
24 uart_put_dec64(timer_now());
25 uart_puts("\n");
26}
27
28void timer_vcpu_sync(struct vcpu *vcpu)
29{
30 uint64_t now;
31 if (vcpu == (struct vcpu *)0) {
32 return;
33 }
34
35 vcpu->stats.timer_syncs++;
36 now = timer_now();
37 uint64_t ctl = vcpu->sysregs.cntv_ctl_el0;
38 bool enabled = (ctl & 1u) != 0u;
39 bool masked = (ctl & 2u) != 0u;
40 if (!enabled || masked) {
41 vcpu_clear_pending_irq(vcpu, CONFIG_VTIMER_IRQ);
42 return;
43 }
44
45 if (now >= vcpu->sysregs.cntv_cval_el0) {
46 vcpu->stats.timer_last_delta = now - vcpu->sysregs.cntv_cval_el0;
47 vcpu->sysregs.cntv_ctl_el0 |= 4u;
48 vcpu_set_pending_irq(vcpu, CONFIG_VTIMER_IRQ);
49 } else {
50 vcpu->stats.timer_last_delta = vcpu->sysregs.cntv_cval_el0 - now;
51 vcpu->sysregs.cntv_ctl_el0 &= ~4ull;
52 vcpu_clear_pending_irq(vcpu, CONFIG_VTIMER_IRQ);
53 }
54}