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