Page MenuHomeFreeBSD

D48133.diff
No OneTemporary

D48133.diff

diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv
--- a/sys/conf/files.riscv
+++ b/sys/conf/files.riscv
@@ -83,6 +83,7 @@
riscv/vmm/vmm_riscv.c optional vmm
riscv/vmm/vmm_sbi.c optional vmm
riscv/vmm/vmm_switch.S optional vmm
+riscv/vmm/vmm_vtimer.c optional vmm
riscv/thead/thead.c standard
diff --git a/sys/modules/vmm/Makefile b/sys/modules/vmm/Makefile
--- a/sys/modules/vmm/Makefile
+++ b/sys/modules/vmm/Makefile
@@ -154,7 +154,8 @@
SRCS+= vmm_aplic.c \
vmm_riscv.c \
vmm_sbi.c \
- vmm_switch.S
+ vmm_switch.S \
+ vmm_vtimer.c
.endif
diff --git a/sys/riscv/vmm/riscv.h b/sys/riscv/vmm/riscv.h
--- a/sys/riscv/vmm/riscv.h
+++ b/sys/riscv/vmm/riscv.h
@@ -38,6 +38,8 @@
#include <machine/pcpu.h>
#include <machine/vmm.h>
+#include <riscv/vmm/vmm_vtimer.h>
+
struct hypregs {
uint64_t hyp_ra;
uint64_t hyp_sp;
@@ -78,6 +80,8 @@
bool has_exception;
int cpu_id;
int ipi_pending;
+ int interrupts_pending;
+ struct vtimer vtimer;
};
struct hyp {
@@ -128,5 +132,6 @@
void riscv_send_ipi(struct hypctx *hypctx, int hart_id);
int riscv_check_ipi(struct hypctx *hypctx, bool clear);
+bool riscv_check_interrupts_pending(struct hypctx *hypctx);
#endif /* !_VMM_RISCV_H_ */
diff --git a/sys/riscv/vmm/vmm.c b/sys/riscv/vmm/vmm.c
--- a/sys/riscv/vmm/vmm.c
+++ b/sys/riscv/vmm/vmm.c
@@ -1414,6 +1414,9 @@
if (riscv_check_ipi(vcpu->cookie, false))
break;
+ if (riscv_check_interrupts_pending(vcpu->cookie))
+ break;
+
if (vcpu_should_yield(vcpu))
break;
diff --git a/sys/riscv/vmm/vmm_riscv.c b/sys/riscv/vmm/vmm_riscv.c
--- a/sys/riscv/vmm/vmm_riscv.c
+++ b/sys/riscv/vmm/vmm_riscv.c
@@ -107,11 +107,6 @@
return (ENXIO);
}
- if (!has_sstc) {
- printf("vmm: riscv hart doesn't support SSTC extension.\n");
- return (ENXIO);
- }
-
return (0);
}
@@ -229,6 +224,7 @@
hyp->ctx[vcpuid] = hypctx;
aplic_cpuinit(hypctx);
+ vtimer_cpuinit(hypctx);
return (hypctx);
}
@@ -561,29 +557,36 @@
return (val);
}
+bool
+riscv_check_interrupts_pending(struct hypctx *hypctx)
+{
+
+ if (hypctx->interrupts_pending)
+ return (true);
+
+ return (false);
+}
+
static void
riscv_sync_interrupts(struct hypctx *hypctx)
{
int pending;
pending = aplic_check_pending(hypctx);
-
if (pending)
hypctx->guest_csrs.hvip |= HVIP_VSEIP;
else
hypctx->guest_csrs.hvip &= ~HVIP_VSEIP;
- csr_write(hvip, hypctx->guest_csrs.hvip);
-}
-
-static void
-riscv_sync_ipi(struct hypctx *hypctx)
-{
-
/* Guest clears VSSIP bit manually. */
if (riscv_check_ipi(hypctx, true))
hypctx->guest_csrs.hvip |= HVIP_VSSIP;
+ if (riscv_check_interrupts_pending(hypctx))
+ hypctx->guest_csrs.hvip |= HVIP_VSTIP;
+ else
+ hypctx->guest_csrs.hvip &= ~HVIP_VSTIP;
+
csr_write(hvip, hypctx->guest_csrs.hvip);
}
@@ -594,6 +597,7 @@
struct vm_exit *vme;
struct vcpu *vcpu;
register_t val;
+ uint64_t hvip;
bool handled;
hypctx = (struct hypctx *)vcpui;
@@ -615,7 +619,8 @@
__asm __volatile("hfence.gvma" ::: "memory");
csr_write(hgatp, pmap->pm_satp);
- csr_write(henvcfg, HENVCFG_STCE);
+ if (has_sstc)
+ csr_write(henvcfg, HENVCFG_STCE);
csr_write(hie, HIE_VSEIE | HIE_VSSIE | HIE_SGEIE);
/* TODO: should we trap rdcycle / rdtime? */
csr_write(hcounteren, HCOUNTEREN_CY | HCOUNTEREN_TM);
@@ -653,9 +658,7 @@
*/
riscv_set_active_vcpu(hypctx);
aplic_flush_hwstate(hypctx);
-
riscv_sync_interrupts(hypctx);
- riscv_sync_ipi(hypctx);
dprintf("%s: Entering guest VM, vsatp %lx, ss %lx hs %lx\n",
__func__, csr_read(vsatp), hypctx->guest_regs.hyp_sstatus,
@@ -666,8 +669,18 @@
dprintf("%s: Leaving guest VM, hstatus %lx\n", __func__,
hypctx->guest_regs.hyp_hstatus);
+ /* Guest can clear VSSIP. It can't clear VSTIP or VSEIP. */
+ hvip = csr_read(hvip);
+ if ((hypctx->guest_csrs.hvip ^ hvip) & HVIP_VSSIP) {
+ if (hvip & HVIP_VSSIP) {
+ /* TODO: VSSIP was set by guest. */
+ } else {
+ /* VSSIP was cleared by guest. */
+ hypctx->guest_csrs.hvip &= ~HVIP_VSSIP;
+ }
+ }
+
aplic_sync_hwstate(hypctx);
- riscv_sync_interrupts(hypctx);
/*
* TODO: deactivate stage 2 pmap here if needed.
diff --git a/sys/riscv/vmm/vmm_sbi.c b/sys/riscv/vmm/vmm_sbi.c
--- a/sys/riscv/vmm/vmm_sbi.c
+++ b/sys/riscv/vmm/vmm_sbi.c
@@ -95,6 +95,31 @@
return (0);
}
+static int
+vmm_sbi_handle_time(struct vcpu *vcpu, struct hypctx *hypctx)
+{
+ uint64_t func_id;
+ uint64_t next_val;
+ int ret;
+
+ func_id = hypctx->guest_regs.hyp_a[6];
+ next_val = hypctx->guest_regs.hyp_a[0];
+
+ switch (func_id) {
+ case SBI_TIME_SET_TIMER:
+ vtimer_set_timer(hypctx, next_val);
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ hypctx->guest_regs.hyp_a[0] = ret;
+
+ return (0);
+}
+
static int
vmm_sbi_handle_ipi(struct vcpu *vcpu, struct hypctx *hypctx)
{
@@ -166,6 +191,7 @@
vmm_sbi_handle_rfnc(vcpu, hypctx);
break;
case SBI_EXT_ID_TIME:
+ vmm_sbi_handle_time(vcpu, hypctx);
break;
case SBI_EXT_ID_IPI:
vmm_sbi_handle_ipi(vcpu, hypctx);
diff --git a/sys/riscv/vmm/vmm_vtimer.h b/sys/riscv/vmm/vmm_vtimer.h
new file mode 100644
--- /dev/null
+++ b/sys/riscv/vmm/vmm_vtimer.h
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory (Department of Computer Science and Technology) under Innovate
+ * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
+ * Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _VMM_VTIMER_H_
+#define _VMM_VTIMER_H_
+
+struct hypctx;
+
+struct vtimer {
+ struct callout callout;
+ struct mtx mtx;
+ uint32_t freq;
+};
+
+void vtimer_cpuinit(struct hypctx *hypctx);
+int vtimer_set_timer(struct hypctx *hypctx, uint64_t next_val);
+
+#endif /* !_VMM_VTIMER_H_ */
diff --git a/sys/riscv/vmm/vmm_vtimer.c b/sys/riscv/vmm/vmm_vtimer.c
new file mode 100644
--- /dev/null
+++ b/sys/riscv/vmm/vmm_vtimer.c
@@ -0,0 +1,117 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory (Department of Computer Science and Technology) under Innovate
+ * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
+ * Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include "riscv.h"
+
+#define VTIMER_DEFAULT_FREQ 1000000
+
+static int
+vtimer_get_timebase(uint32_t *freq)
+{
+ phandle_t node;
+ int len;
+
+ node = OF_finddevice("/cpus");
+ if (node == -1)
+ return (ENXIO);
+
+ len = OF_getproplen(node, "timebase-frequency");
+ if (len != 4)
+ return (ENXIO);
+
+ OF_getencprop(node, "timebase-frequency", freq, len);
+
+ return (0);
+}
+
+void
+vtimer_cpuinit(struct hypctx *hypctx)
+{
+ struct vtimer *vtimer;
+ uint32_t freq;
+ int error;
+
+ vtimer = &hypctx->vtimer;
+ mtx_init(&vtimer->mtx, "vtimer callout mutex", NULL, MTX_DEF);
+ callout_init_mtx(&vtimer->callout, &vtimer->mtx, 0);
+
+ error = vtimer_get_timebase(&freq);
+ if (error)
+ freq = VTIMER_DEFAULT_FREQ;
+
+ vtimer->freq = freq;
+}
+
+static void
+vtimer_inject_irq_callout(void *arg)
+{
+ struct hypctx *hypctx;
+ struct hyp *hyp;
+
+ hypctx = arg;
+ hyp = hypctx->hyp;
+
+ atomic_set_32(&hypctx->interrupts_pending, HVIP_VSTIP);
+ vcpu_notify_event(vm_vcpu(hyp->vm, hypctx->cpu_id));
+}
+
+int
+vtimer_set_timer(struct hypctx *hypctx, uint64_t next_val)
+{
+ struct vtimer *vtimer;
+ sbintime_t time;
+ uint64_t curtime;
+ uint64_t delta;
+
+ vtimer = &hypctx->vtimer;
+
+ curtime = rdtime();
+ if (curtime < next_val) {
+ delta = next_val - curtime;
+ time = delta * SBT_1S / vtimer->freq;
+ atomic_clear_32(&hypctx->interrupts_pending, HVIP_VSTIP);
+ callout_reset_sbt(&vtimer->callout, time, 0,
+ vtimer_inject_irq_callout, hypctx, 0);
+ } else
+ atomic_set_32(&hypctx->interrupts_pending, HVIP_VSTIP);
+
+ return (0);
+}
diff --git a/usr.sbin/bhyve/riscv/fdt.c b/usr.sbin/bhyve/riscv/fdt.c
--- a/usr.sbin/bhyve/riscv/fdt.c
+++ b/usr.sbin/bhyve/riscv/fdt.c
@@ -118,7 +118,8 @@
/* XXX: Needed given the root #address-cells? */
fdt_property_u32(fdt, "#address-cells", 1);
fdt_property_u32(fdt, "#size-cells", 0);
- fdt_property_u32(fdt, "timebase-frequency", 10000000);
+ /* TODO: take timebase from kernel? */
+ fdt_property_u32(fdt, "timebase-frequency", 1000000);
for (cpuid = 0; cpuid < ncpu; cpuid++)
add_cpu(fdt, cpuid, isa);

File Metadata

Mime Type
text/plain
Expires
Tue, Jan 14, 5:59 AM (10 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15791613
Default Alt Text
D48133.diff (10 KB)

Event Timeline