xref: /freebsd/sys/arm64/vmm/io/vtimer.c (revision 35164034e390f56f83efe5bf073d36812b19df23)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2017 The FreeBSD Foundation
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the company nor the name of the author may be used to
15  *    endorse or promote products derived from this software without specific
16  *    prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/mutex.h>
38 #include <sys/rman.h>
39 #include <sys/sysctl.h>
40 #include <sys/time.h>
41 #include <sys/timeet.h>
42 #include <sys/timetc.h>
43 
44 #include <machine/bus.h>
45 #include <machine/machdep.h>
46 #include <machine/vmm.h>
47 
48 #include <arm64/vmm/arm64.h>
49 
50 #include <dev/vmm/vmm_vm.h>
51 
52 #include "vgic.h"
53 #include "vtimer.h"
54 
55 #define	RES1		0xffffffffffffffffUL
56 
57 #define timer_enabled(ctl)	\
58     (!((ctl) & CNTP_CTL_IMASK) && ((ctl) & CNTP_CTL_ENABLE))
59 
60 static uint32_t tmr_frq;
61 
62 #define timer_condition_met(ctl)	((ctl) & CNTP_CTL_ISTATUS)
63 
64 SYSCTL_DECL(_hw_vmm);
65 SYSCTL_NODE(_hw_vmm, OID_AUTO, vtimer, CTLFLAG_RW, NULL, NULL);
66 
67 static bool allow_ecv_phys = false;
68 SYSCTL_BOOL(_hw_vmm_vtimer, OID_AUTO, allow_ecv_phys, CTLFLAG_RW,
69     &allow_ecv_phys, 0,
70     "Enable hardware access to the physical timer if FEAT_ECV_POFF is supported");
71 
72 static void vtimer_schedule_irq(struct hypctx *hypctx, bool phys);
73 
74 static int
vtimer_virtual_timer_intr(void * arg)75 vtimer_virtual_timer_intr(void *arg)
76 {
77 	struct hypctx *hypctx;
78 	uint64_t cntpct_el0;
79 	uint32_t cntv_ctl;
80 
81 	hypctx = arm64_get_active_vcpu();
82 	cntv_ctl = READ_SPECIALREG(cntv_ctl_el0);
83 
84 	if (!hypctx) {
85 		/* vm_destroy() was called. */
86 		eprintf("No active vcpu\n");
87 		cntv_ctl = READ_SPECIALREG(cntv_ctl_el0);
88 		goto out;
89 	}
90 	if (!timer_enabled(cntv_ctl)) {
91 		eprintf("Timer not enabled\n");
92 		goto out;
93 	}
94 	if (!timer_condition_met(cntv_ctl)) {
95 		eprintf("Timer condition not met\n");
96 		goto out;
97 	}
98 
99 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
100 	    hypctx_read_sys_reg(hypctx, HOST_CNTVOFF_EL2);
101 	if (hypctx->vtimer_cpu.virt_timer.cntx_cval_el0 < cntpct_el0)
102 		vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
103 		    GT_VIRT_IRQ, true);
104 
105 	cntv_ctl = hypctx->vtimer_cpu.virt_timer.cntx_ctl_el0;
106 
107 out:
108 	/*
109 	 * Disable the timer interrupt. This will prevent the interrupt from
110 	 * being reasserted as soon as we exit the handler and getting stuck
111 	 * in an infinite loop.
112 	 *
113 	 * This is safe to do because the guest disabled the timer, and then
114 	 * enables it as part of the interrupt handling routine.
115 	 */
116 	cntv_ctl &= ~CNTP_CTL_ENABLE;
117 	WRITE_SPECIALREG(cntv_ctl_el0, cntv_ctl);
118 
119 	return (FILTER_HANDLED);
120 }
121 
122 int
vtimer_init(void)123 vtimer_init(void)
124 {
125 	/*
126 	 * The guest *MUST* use the same timer frequency as the host. The
127 	 * register CNTFRQ_EL0 is accessible to the guest and a different value
128 	 * in the guest dts file might have unforseen consequences.
129 	 */
130 	tmr_frq = READ_SPECIALREG(cntfrq_el0);
131 
132 	return (0);
133 }
134 
135 void
vtimer_cpuinit(struct hypctx * hypctx)136 vtimer_cpuinit(struct hypctx *hypctx)
137 {
138 	struct vtimer_cpu *vtimer_cpu;
139 	bool ecv_poff;
140 
141 	vtimer_cpu = &hypctx->vtimer_cpu;
142 	/*
143 	 * Configure physical timer interrupts for the VCPU.
144 	 *
145 	 * CNTP_CTL_IMASK: mask interrupts
146 	 * ~CNTP_CTL_ENABLE: disable the timer
147 	 */
148 	vtimer_cpu->phys_timer.cntx_ctl_el0 = CNTP_CTL_IMASK & ~CNTP_CTL_ENABLE;
149 
150 	mtx_init(&vtimer_cpu->phys_timer.mtx, "vtimer phys callout mutex", NULL,
151 	    MTX_DEF);
152 	callout_init_mtx(&vtimer_cpu->phys_timer.callout,
153 	    &vtimer_cpu->phys_timer.mtx, 0);
154 	vtimer_cpu->phys_timer.irqid = GT_PHYS_NS_IRQ;
155 
156 	mtx_init(&vtimer_cpu->virt_timer.mtx, "vtimer virt callout mutex", NULL,
157 	    MTX_DEF);
158 	callout_init_mtx(&vtimer_cpu->virt_timer.callout,
159 	    &vtimer_cpu->virt_timer.mtx, 0);
160 	vtimer_cpu->virt_timer.irqid = GT_VIRT_IRQ;
161 
162 	ecv_poff = false;
163 
164 	if (allow_ecv_phys && (hypctx->hyp->feats & HYP_FEAT_ECV_POFF) != 0)
165 		ecv_poff = true;
166 
167 	/*
168 	 * Configure the Counter-timer Hypervisor Control Register for the VM.
169 	 */
170 	if (in_vhe()) {
171 		/*
172 		 * CNTHCTL_E2H_EL0PCTEN: trap EL0 access to CNTP{CT,CTSS}_EL0
173 		 * CNTHCTL_E2H_EL0VCTEN: don't trap EL0 access to
174 		 *                      CNTV{CT,CTXX}_EL0
175 		 * CNTHCTL_E2H_EL0VTEN: don't trap EL0 access to
176 		 *                      CNTV_{CTL,CVAL,TVAL}_EL0
177 		 * CNTHCTL_E2H_EL0PTEN: trap EL0 access to
178 		 *                      CNTP_{CTL,CVAL,TVAL}_EL0
179 		 * CNTHCTL_E2H_EL1PCTEN: trap access to CNTPCT_EL0
180 		 * CNTHCTL_E2H_EL1PTEN: trap access to
181 		 *                      CNTP_{CTL,CVAL,TVAL}_EL0
182 		 * CNTHCTL_E2H_EL1VCTEN: don't trap EL0 access to
183 		 *                       CNTV{CT,CTSS}_EL0
184 		 * CNTHCTL_E2H_EL1PCEN: trap EL1 access to
185 		 *                      CNTP_{CTL,CVAL,TVAL}_EL0
186 		 *
187 		 * TODO: Don't trap when FEAT_ECV is present
188 		 */
189 		hypctx_write_sys_reg(hypctx, HOST_CNTHCTL_EL2,
190 		    CNTHCTL_E2H_EL0VCTEN_NOTRAP |
191 		    CNTHCTL_E2H_EL0VTEN_NOTRAP);
192 		if (ecv_poff) {
193 			*hypctx_sys_reg(hypctx, HOST_CNTHCTL_EL2) |=
194 			    CNTHCTL_E2H_EL0PCTEN_NOTRAP |
195 			    CNTHCTL_E2H_EL0PTEN_NOTRAP |
196 			    CNTHCTL_E2H_EL1PCTEN_NOTRAP |
197 			    CNTHCTL_E2H_EL1PTEN_NOTRAP;
198 		} else {
199 			*hypctx_sys_reg(hypctx, HOST_CNTHCTL_EL2) |=
200 			    CNTHCTL_E2H_EL0PCTEN_TRAP |
201 			    CNTHCTL_E2H_EL0PTEN_TRAP |
202 			    CNTHCTL_E2H_EL1PCTEN_TRAP |
203 			    CNTHCTL_E2H_EL1PTEN_TRAP;
204 		}
205 	} else {
206 		/*
207 		 * CNTHCTL_EL1PCEN: trap access to CNTP_{CTL, CVAL, TVAL}_EL0
208 		 *                  from EL1
209 		 * CNTHCTL_EL1PCTEN: trap access to CNTPCT_EL0
210 		 */
211 		if (ecv_poff) {
212 			hypctx_write_sys_reg(hypctx, HOST_CNTHCTL_EL2,
213 			    CNTHCTL_EL1PCTEN_NOTRAP |
214 			    CNTHCTL_EL1PCEN_NOTRAP);
215 		} else {
216 			hypctx_write_sys_reg(hypctx, HOST_CNTHCTL_EL2,
217 			    CNTHCTL_EL1PCTEN_TRAP |
218 			    CNTHCTL_EL1PCEN_TRAP);
219 		}
220 	}
221 
222 	if (ecv_poff)
223 		*hypctx_sys_reg(hypctx, HOST_CNTHCTL_EL2) |= CNTHCTL_ECV_EN;
224 
225 	hypctx_write_sys_reg(hypctx, HOST_CNTVOFF_EL2, hypctx->hyp->cntvoff_el2);
226 }
227 
228 void
vtimer_cpucleanup(struct hypctx * hypctx)229 vtimer_cpucleanup(struct hypctx *hypctx)
230 {
231 	struct vtimer_cpu *vtimer_cpu;
232 
233 	vtimer_cpu = &hypctx->vtimer_cpu;
234 	callout_drain(&vtimer_cpu->phys_timer.callout);
235 	callout_drain(&vtimer_cpu->virt_timer.callout);
236 	mtx_destroy(&vtimer_cpu->phys_timer.mtx);
237 	mtx_destroy(&vtimer_cpu->virt_timer.mtx);
238 }
239 
240 void
vtimer_vmcleanup(struct hyp * hyp)241 vtimer_vmcleanup(struct hyp *hyp)
242 {
243 	struct hypctx *hypctx;
244 	uint32_t cntv_ctl;
245 
246 	hypctx = arm64_get_active_vcpu();
247 	if (!hypctx) {
248 		/* The active VM was destroyed, stop the timer. */
249 		cntv_ctl = READ_SPECIALREG(cntv_ctl_el0);
250 		cntv_ctl &= ~CNTP_CTL_ENABLE;
251 		WRITE_SPECIALREG(cntv_ctl_el0, cntv_ctl);
252 	}
253 }
254 
255 void
vtimer_cleanup(void)256 vtimer_cleanup(void)
257 {
258 }
259 
260 static void
vtime_sync_timer(struct hypctx * hypctx,struct vtimer_timer * timer,uint64_t cntpct_el0)261 vtime_sync_timer(struct hypctx *hypctx, struct vtimer_timer *timer,
262     uint64_t cntpct_el0)
263 {
264 	if (!timer_enabled(timer->cntx_ctl_el0)) {
265 		vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
266 		    timer->irqid, false);
267 	} else if (timer->cntx_cval_el0 < cntpct_el0) {
268 		vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
269 		    timer->irqid, true);
270 	} else {
271 		vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
272 		    timer->irqid, false);
273 		vtimer_schedule_irq(hypctx, false);
274 	}
275 }
276 
277 void
vtimer_sync_hwstate(struct hypctx * hypctx)278 vtimer_sync_hwstate(struct hypctx *hypctx)
279 {
280 	uint64_t cntpct_el0;
281 
282 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
283 	    hypctx_read_sys_reg(hypctx, HOST_CNTVOFF_EL2);
284 	vtime_sync_timer(hypctx, &hypctx->vtimer_cpu.virt_timer, cntpct_el0);
285 	/* If FEAT_ECV_POFF is in use then we need to sync the physical timer */
286 	if ((hypctx_read_sys_reg(hypctx, HOST_CNTHCTL_EL2) & CNTHCTL_ECV_EN) != 0) {
287 		vtime_sync_timer(hypctx, &hypctx->vtimer_cpu.phys_timer,
288 		    cntpct_el0);
289 	}
290 }
291 
292 static void
vtimer_inject_irq_callout_phys(void * context)293 vtimer_inject_irq_callout_phys(void *context)
294 {
295 	struct hypctx *hypctx;
296 
297 	hypctx = context;
298 	vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
299 	    hypctx->vtimer_cpu.phys_timer.irqid, true);
300 }
301 
302 static void
vtimer_inject_irq_callout_virt(void * context)303 vtimer_inject_irq_callout_virt(void *context)
304 {
305 	struct hypctx *hypctx;
306 
307 	hypctx = context;
308 	vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
309 	    hypctx->vtimer_cpu.virt_timer.irqid, true);
310 }
311 
312 static void
vtimer_schedule_irq(struct hypctx * hypctx,bool phys)313 vtimer_schedule_irq(struct hypctx *hypctx, bool phys)
314 {
315 	sbintime_t time;
316 	struct vtimer_timer *timer;
317 	uint64_t cntpct_el0;
318 	uint64_t diff;
319 
320 	if (phys)
321 		timer = &hypctx->vtimer_cpu.phys_timer;
322 	else
323 		timer = &hypctx->vtimer_cpu.virt_timer;
324 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
325 	    hypctx_read_sys_reg(hypctx, HOST_CNTVOFF_EL2);
326 	if (timer->cntx_cval_el0 < cntpct_el0) {
327 		/* Timer set in the past, trigger interrupt */
328 		vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
329 		    timer->irqid, true);
330 	} else {
331 		diff = timer->cntx_cval_el0 - cntpct_el0;
332 		time = diff * SBT_1S / tmr_frq;
333 		if (phys)
334 			callout_reset_sbt(&timer->callout, time, 0,
335 			    vtimer_inject_irq_callout_phys, hypctx, 0);
336 		else
337 			callout_reset_sbt(&timer->callout, time, 0,
338 			    vtimer_inject_irq_callout_virt, hypctx, 0);
339 	}
340 }
341 
342 static void
vtimer_remove_irq(struct hypctx * hypctx,struct vcpu * vcpu)343 vtimer_remove_irq(struct hypctx *hypctx, struct vcpu *vcpu)
344 {
345 	struct vtimer_cpu *vtimer_cpu;
346 	struct vtimer_timer *timer;
347 
348 	vtimer_cpu = &hypctx->vtimer_cpu;
349 	timer = &vtimer_cpu->phys_timer;
350 
351 	callout_drain(&timer->callout);
352 	/*
353 	 * The interrupt needs to be deactivated here regardless of the callout
354 	 * function having been executed. The timer interrupt can be masked with
355 	 * the CNTP_CTL_EL0.IMASK bit instead of reading the IAR register.
356 	 * Masking the interrupt doesn't remove it from the list registers.
357 	 */
358 	vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(vcpu), timer->irqid, false);
359 }
360 
361 /*
362  * Timer emulation functions.
363  *
364  * The guest should use the virtual timer, however some software, e.g. u-boot,
365  * used the physical timer. Emulate this in software for the guest to use.
366  *
367  * Adjust for cntvoff_el2 so the physical and virtual timers are at similar
368  * times. This simplifies interrupt handling in the virtual timer as the
369  * adjustment will have already happened.
370  */
371 
372 int
vtimer_phys_ctl_read(struct vcpu * vcpu,uint64_t * rval,void * arg)373 vtimer_phys_ctl_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
374 {
375 	struct hypctx *hypctx;
376 	struct vtimer_cpu *vtimer_cpu;
377 	uint64_t cntpct_el0;
378 
379 	hypctx = vcpu_get_cookie(vcpu);
380 	vtimer_cpu = &hypctx->vtimer_cpu;
381 
382 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) - hypctx_read_sys_reg(hypctx, HOST_CNTVOFF_EL2);
383 	if (vtimer_cpu->phys_timer.cntx_cval_el0 < cntpct_el0)
384 		/* Timer condition met */
385 		*rval = vtimer_cpu->phys_timer.cntx_ctl_el0 | CNTP_CTL_ISTATUS;
386 	else
387 		*rval = vtimer_cpu->phys_timer.cntx_ctl_el0 & ~CNTP_CTL_ISTATUS;
388 
389 	return (0);
390 }
391 
392 int
vtimer_phys_ctl_write(struct vcpu * vcpu,uint64_t wval,void * arg)393 vtimer_phys_ctl_write(struct vcpu *vcpu, uint64_t wval, void *arg)
394 {
395 	struct hypctx *hypctx;
396 	struct vtimer_cpu *vtimer_cpu;
397 	uint64_t ctl_el0;
398 	bool timer_toggled_on;
399 
400 	hypctx = vcpu_get_cookie(vcpu);
401 	vtimer_cpu = &hypctx->vtimer_cpu;
402 
403 	timer_toggled_on = false;
404 	ctl_el0 = vtimer_cpu->phys_timer.cntx_ctl_el0;
405 
406 	if (!timer_enabled(ctl_el0) && timer_enabled(wval))
407 		timer_toggled_on = true;
408 	else if (timer_enabled(ctl_el0) && !timer_enabled(wval))
409 		vtimer_remove_irq(hypctx, vcpu);
410 
411 	vtimer_cpu->phys_timer.cntx_ctl_el0 = wval;
412 
413 	if (timer_toggled_on)
414 		vtimer_schedule_irq(hypctx, true);
415 
416 	return (0);
417 }
418 
419 int
vtimer_phys_cnt_read(struct vcpu * vcpu,uint64_t * rval,void * arg)420 vtimer_phys_cnt_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
421 {
422 	struct hypctx *hypctx;
423 
424 	hypctx = vcpu_get_cookie(vcpu);
425 	*rval = READ_SPECIALREG(cntpct_el0) - hypctx_read_sys_reg(hypctx, HOST_CNTVOFF_EL2);
426 	return (0);
427 }
428 
429 int
vtimer_phys_cnt_write(struct vcpu * vcpu,uint64_t wval,void * arg)430 vtimer_phys_cnt_write(struct vcpu *vcpu, uint64_t wval, void *arg)
431 {
432 	return (0);
433 }
434 
435 int
vtimer_phys_cval_read(struct vcpu * vcpu,uint64_t * rval,void * arg)436 vtimer_phys_cval_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
437 {
438 	struct hypctx *hypctx;
439 	struct vtimer_cpu *vtimer_cpu;
440 
441 	hypctx = vcpu_get_cookie(vcpu);
442 	vtimer_cpu = &hypctx->vtimer_cpu;
443 
444 	*rval = vtimer_cpu->phys_timer.cntx_cval_el0;
445 
446 	return (0);
447 }
448 
449 int
vtimer_phys_cval_write(struct vcpu * vcpu,uint64_t wval,void * arg)450 vtimer_phys_cval_write(struct vcpu *vcpu, uint64_t wval, void *arg)
451 {
452 	struct hypctx *hypctx;
453 	struct vtimer_cpu *vtimer_cpu;
454 
455 	hypctx = vcpu_get_cookie(vcpu);
456 	vtimer_cpu = &hypctx->vtimer_cpu;
457 
458 	vtimer_cpu->phys_timer.cntx_cval_el0 = wval;
459 
460 	vtimer_remove_irq(hypctx, vcpu);
461 	if (timer_enabled(vtimer_cpu->phys_timer.cntx_ctl_el0)) {
462 		vtimer_schedule_irq(hypctx, true);
463 	}
464 
465 	return (0);
466 }
467 
468 int
vtimer_phys_tval_read(struct vcpu * vcpu,uint64_t * rval,void * arg)469 vtimer_phys_tval_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
470 {
471 	struct hypctx *hypctx;
472 	struct vtimer_cpu *vtimer_cpu;
473 	uint32_t cntpct_el0;
474 
475 	hypctx = vcpu_get_cookie(vcpu);
476 	vtimer_cpu = &hypctx->vtimer_cpu;
477 
478 	if (!(vtimer_cpu->phys_timer.cntx_ctl_el0 & CNTP_CTL_ENABLE)) {
479 		/*
480 		 * ARMv8 Architecture Manual, p. D7-2702: the result of reading
481 		 * TVAL when the timer is disabled is UNKNOWN. I have chosen to
482 		 * return the maximum value possible on 32 bits which means the
483 		 * timer will fire very far into the future.
484 		 */
485 		*rval = (uint32_t)RES1;
486 	} else {
487 		cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
488 		    hypctx_read_sys_reg(hypctx, HOST_CNTVOFF_EL2);
489 		*rval = vtimer_cpu->phys_timer.cntx_cval_el0 - cntpct_el0;
490 	}
491 
492 	return (0);
493 }
494 
495 int
vtimer_phys_tval_write(struct vcpu * vcpu,uint64_t wval,void * arg)496 vtimer_phys_tval_write(struct vcpu *vcpu, uint64_t wval, void *arg)
497 {
498 	struct hypctx *hypctx;
499 	struct vtimer_cpu *vtimer_cpu;
500 	uint64_t cntpct_el0;
501 
502 	hypctx = vcpu_get_cookie(vcpu);
503 	vtimer_cpu = &hypctx->vtimer_cpu;
504 
505 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) - hypctx_read_sys_reg(hypctx, HOST_CNTVOFF_EL2);
506 	vtimer_cpu->phys_timer.cntx_cval_el0 = (int32_t)wval + cntpct_el0;
507 
508 	vtimer_remove_irq(hypctx, vcpu);
509 	if (timer_enabled(vtimer_cpu->phys_timer.cntx_ctl_el0)) {
510 		vtimer_schedule_irq(hypctx, true);
511 	}
512 
513 	return (0);
514 }
515 
516 struct vtimer_softc {
517 	struct resource *res;
518 	void *ihl;
519 	int rid;
520 };
521 
522 static int
vtimer_probe(device_t dev)523 vtimer_probe(device_t dev)
524 {
525 	device_set_desc(dev, "Virtual timer");
526 	return (BUS_PROBE_DEFAULT);
527 }
528 
529 static int
vtimer_attach(device_t dev)530 vtimer_attach(device_t dev)
531 {
532 	struct vtimer_softc *sc;
533 
534 	sc = device_get_softc(dev);
535 
536 	sc->rid = 0;
537 	sc->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid, RF_ACTIVE);
538 	if (sc->res == NULL)
539 		return (ENXIO);
540 
541 	bus_setup_intr(dev, sc->res, INTR_TYPE_CLK, vtimer_virtual_timer_intr,
542 	    NULL, NULL, &sc->ihl);
543 
544 	return (0);
545 }
546 
547 static device_method_t vtimer_methods[] = {
548 	/* Device interface */
549 	DEVMETHOD(device_probe,		vtimer_probe),
550 	DEVMETHOD(device_attach,	vtimer_attach),
551 
552 	/* End */
553 	DEVMETHOD_END
554 };
555 
556 DEFINE_CLASS_0(vtimer, vtimer_driver, vtimer_methods,
557     sizeof(struct vtimer_softc));
558 
559 DRIVER_MODULE(vtimer, generic_timer, vtimer_driver, 0, 0);
560