xref: /freebsd/sys/riscv/vmm/vmm_vtimer.c (revision 9be0058ea0fc6fd098b9e2ab54f94c86fe7eb69a)
1*9be0058eSRuslan Bukin /*-
2*9be0058eSRuslan Bukin  * SPDX-License-Identifier: BSD-2-Clause
3*9be0058eSRuslan Bukin  *
4*9be0058eSRuslan Bukin  * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
5*9be0058eSRuslan Bukin  *
6*9be0058eSRuslan Bukin  * This software was developed by the University of Cambridge Computer
7*9be0058eSRuslan Bukin  * Laboratory (Department of Computer Science and Technology) under Innovate
8*9be0058eSRuslan Bukin  * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
9*9be0058eSRuslan Bukin  * Prototype".
10*9be0058eSRuslan Bukin  *
11*9be0058eSRuslan Bukin  * Redistribution and use in source and binary forms, with or without
12*9be0058eSRuslan Bukin  * modification, are permitted provided that the following conditions
13*9be0058eSRuslan Bukin  * are met:
14*9be0058eSRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
15*9be0058eSRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
16*9be0058eSRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
17*9be0058eSRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
18*9be0058eSRuslan Bukin  *    documentation and/or other materials provided with the distribution.
19*9be0058eSRuslan Bukin  *
20*9be0058eSRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*9be0058eSRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*9be0058eSRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*9be0058eSRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
24*9be0058eSRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*9be0058eSRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*9be0058eSRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*9be0058eSRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*9be0058eSRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*9be0058eSRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*9be0058eSRuslan Bukin  * SUCH DAMAGE.
31*9be0058eSRuslan Bukin  */
32*9be0058eSRuslan Bukin 
33*9be0058eSRuslan Bukin #include <sys/param.h>
34*9be0058eSRuslan Bukin #include <sys/kernel.h>
35*9be0058eSRuslan Bukin #include <sys/lock.h>
36*9be0058eSRuslan Bukin #include <sys/mutex.h>
37*9be0058eSRuslan Bukin 
38*9be0058eSRuslan Bukin #include <dev/ofw/ofw_bus.h>
39*9be0058eSRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
40*9be0058eSRuslan Bukin #include <dev/ofw/openfirm.h>
41*9be0058eSRuslan Bukin 
42*9be0058eSRuslan Bukin #include "riscv.h"
43*9be0058eSRuslan Bukin 
44*9be0058eSRuslan Bukin #define	VTIMER_DEFAULT_FREQ	1000000
45*9be0058eSRuslan Bukin 
46*9be0058eSRuslan Bukin static int
vtimer_get_timebase(uint32_t * freq)47*9be0058eSRuslan Bukin vtimer_get_timebase(uint32_t *freq)
48*9be0058eSRuslan Bukin {
49*9be0058eSRuslan Bukin 	phandle_t node;
50*9be0058eSRuslan Bukin 	int len;
51*9be0058eSRuslan Bukin 
52*9be0058eSRuslan Bukin 	node = OF_finddevice("/cpus");
53*9be0058eSRuslan Bukin 	if (node == -1)
54*9be0058eSRuslan Bukin 		return (ENXIO);
55*9be0058eSRuslan Bukin 
56*9be0058eSRuslan Bukin 	len = OF_getproplen(node, "timebase-frequency");
57*9be0058eSRuslan Bukin 	if (len != 4)
58*9be0058eSRuslan Bukin 		return (ENXIO);
59*9be0058eSRuslan Bukin 
60*9be0058eSRuslan Bukin 	OF_getencprop(node, "timebase-frequency", freq, len);
61*9be0058eSRuslan Bukin 
62*9be0058eSRuslan Bukin 	return (0);
63*9be0058eSRuslan Bukin }
64*9be0058eSRuslan Bukin 
65*9be0058eSRuslan Bukin void
vtimer_cpuinit(struct hypctx * hypctx)66*9be0058eSRuslan Bukin vtimer_cpuinit(struct hypctx *hypctx)
67*9be0058eSRuslan Bukin {
68*9be0058eSRuslan Bukin 	struct vtimer *vtimer;
69*9be0058eSRuslan Bukin 	uint32_t freq;
70*9be0058eSRuslan Bukin 	int error;
71*9be0058eSRuslan Bukin 
72*9be0058eSRuslan Bukin 	vtimer = &hypctx->vtimer;
73*9be0058eSRuslan Bukin 	mtx_init(&vtimer->mtx, "vtimer callout mutex", NULL, MTX_DEF);
74*9be0058eSRuslan Bukin 	callout_init_mtx(&vtimer->callout, &vtimer->mtx, 0);
75*9be0058eSRuslan Bukin 
76*9be0058eSRuslan Bukin 	error = vtimer_get_timebase(&freq);
77*9be0058eSRuslan Bukin 	if (error)
78*9be0058eSRuslan Bukin 		freq = VTIMER_DEFAULT_FREQ;
79*9be0058eSRuslan Bukin 
80*9be0058eSRuslan Bukin 	vtimer->freq = freq;
81*9be0058eSRuslan Bukin }
82*9be0058eSRuslan Bukin 
83*9be0058eSRuslan Bukin static void
vtimer_inject_irq_callout(void * arg)84*9be0058eSRuslan Bukin vtimer_inject_irq_callout(void *arg)
85*9be0058eSRuslan Bukin {
86*9be0058eSRuslan Bukin 	struct hypctx *hypctx;
87*9be0058eSRuslan Bukin 	struct hyp *hyp;
88*9be0058eSRuslan Bukin 
89*9be0058eSRuslan Bukin 	hypctx = arg;
90*9be0058eSRuslan Bukin 	hyp = hypctx->hyp;
91*9be0058eSRuslan Bukin 
92*9be0058eSRuslan Bukin 	atomic_set_32(&hypctx->interrupts_pending, HVIP_VSTIP);
93*9be0058eSRuslan Bukin 	vcpu_notify_event(vm_vcpu(hyp->vm, hypctx->cpu_id));
94*9be0058eSRuslan Bukin }
95*9be0058eSRuslan Bukin 
96*9be0058eSRuslan Bukin int
vtimer_set_timer(struct hypctx * hypctx,uint64_t next_val)97*9be0058eSRuslan Bukin vtimer_set_timer(struct hypctx *hypctx, uint64_t next_val)
98*9be0058eSRuslan Bukin {
99*9be0058eSRuslan Bukin 	struct vtimer *vtimer;
100*9be0058eSRuslan Bukin 	sbintime_t time;
101*9be0058eSRuslan Bukin 	uint64_t curtime;
102*9be0058eSRuslan Bukin 	uint64_t delta;
103*9be0058eSRuslan Bukin 
104*9be0058eSRuslan Bukin 	vtimer = &hypctx->vtimer;
105*9be0058eSRuslan Bukin 
106*9be0058eSRuslan Bukin 	curtime = rdtime();
107*9be0058eSRuslan Bukin 	if (curtime < next_val) {
108*9be0058eSRuslan Bukin 		delta = next_val - curtime;
109*9be0058eSRuslan Bukin 		time = delta * SBT_1S / vtimer->freq;
110*9be0058eSRuslan Bukin 		atomic_clear_32(&hypctx->interrupts_pending, HVIP_VSTIP);
111*9be0058eSRuslan Bukin 		callout_reset_sbt(&vtimer->callout, time, 0,
112*9be0058eSRuslan Bukin 		    vtimer_inject_irq_callout, hypctx, 0);
113*9be0058eSRuslan Bukin 	} else
114*9be0058eSRuslan Bukin 		atomic_set_32(&hypctx->interrupts_pending, HVIP_VSTIP);
115*9be0058eSRuslan Bukin 
116*9be0058eSRuslan Bukin 	return (0);
117*9be0058eSRuslan Bukin }
118