mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2026-07-28 10:13:43 +00:00
Initialize the VM's time_delta to provide a consistent time offset for guests, and properly initialize vcpu timer-related CSRs (htimedelta and vstimecmp) to enable guest timer virtualization. Changes: - Add time_delta field to vm_arch structure to track VM time offset - Initialize time_delta to -cpu_ticks() at VM creation, making guest time start from 0 - Save/restore htimedelta CSR in vcpu load/unload paths - Initialize vcpu's htimedelta from VM's time_delta - Reset vstimecmp to invalid value (0xffffffffffffffff) on vcpu reset - Add SSTC (Sstc extension) capability check Tracked-On: #8851 Signed-off-by: Haoyu Tang <haoyu.tang@intel.com> Acked-by: Wang Yu1 <yu1.wang@intel.com>
135 lines
2.9 KiB
C
135 lines
2.9 KiB
C
/*
|
|
* Copyright (C) 2023-2025 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
* Author: Yifan Liu <yifan1.liu@intel.com>
|
|
* Haicheng Li <haicheng.li@intel.com>
|
|
*/
|
|
|
|
#include <vm.h>
|
|
#include <vcpu.h>
|
|
#include <fdt.h>
|
|
#include <vcpu.h>
|
|
#include <reloc.h>
|
|
#include <cpu.h>
|
|
#include <per_cpu.h>
|
|
#include <vfdt.h>
|
|
#include <libfdt.h>
|
|
#include <asm/guest/vcpu_priv.h>
|
|
|
|
static void riscv_vm_time_delta_init(struct acrn_vm *vm)
|
|
{
|
|
/* FIXME: move SSTC checking to platform caps */
|
|
ASSERT(!!(cpu_csr_read(CSR_HENVCFG) & ENVCFG_STCE), "SSTC must be enabled");
|
|
|
|
/* initialize VM startup time to 0 */
|
|
vm->arch_vm.time_delta = -cpu_ticks();
|
|
}
|
|
|
|
uint32_t vcpu_get_vhartid(struct acrn_vcpu *vcpu)
|
|
{
|
|
uint32_t vhartid = vcpu->vcpu_id;
|
|
|
|
if (is_service_vm(vcpu->vm)) {
|
|
/* vhartid == phartid */
|
|
vhartid = per_cpu(arch.hart_id, pcpuid_from_vcpu(vcpu));
|
|
}
|
|
|
|
/* RISC-V requires that at least one hart has hart ID 0,
|
|
* so we use logical ID (vcpu_id) for non-service vms.
|
|
*/
|
|
|
|
return vhartid;
|
|
}
|
|
|
|
struct acrn_vcpu *vcpu_from_vhartid(struct acrn_vm *vm, uint32_t vhartid)
|
|
{
|
|
struct acrn_vcpu *vcpu;
|
|
|
|
if (is_service_vm(vm)) {
|
|
/* vhartid == phartid */
|
|
vcpu = vcpu_from_pid(vm, get_pcpu_id_from_hart_id(vhartid));
|
|
} else {
|
|
/* vhartid == vcpu_id */
|
|
vcpu = vcpu_from_vid(vm, vhartid);
|
|
}
|
|
return vcpu;
|
|
}
|
|
|
|
int32_t arch_init_vm(struct acrn_vm *vm, struct acrn_vm_config *vm_config)
|
|
{
|
|
init_vsbi(vm);
|
|
|
|
(void)vm_config;
|
|
|
|
if (is_service_vm(vm)) {
|
|
init_service_vm_vfdt(vm);
|
|
}
|
|
|
|
riscv_vm_time_delta_init(vm);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t arch_deinit_vm(struct acrn_vm *vm)
|
|
{
|
|
(void)vm;
|
|
return 0;
|
|
}
|
|
|
|
int32_t arch_reset_vm(struct acrn_vm *vm)
|
|
{
|
|
uint16_t i;
|
|
struct acrn_vcpu *vcpu = NULL;
|
|
|
|
foreach_vcpu(i, vm, vcpu) {
|
|
reset_vcpu(vcpu);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void arch_vm_prepare_bsp(struct acrn_vcpu *vcpu)
|
|
{
|
|
struct acrn_vm *vm = vcpu->vm;
|
|
|
|
vcpu_set_epc(vcpu, (uint64_t)vm->sw.kernel_info.kernel_entry_addr);
|
|
|
|
vcpu->arch.regs.a0 = vcpu_get_vhartid(vcpu);
|
|
vcpu->arch.regs.a1 = (uint64_t)vm->sw.fdt_info.load_addr;
|
|
}
|
|
|
|
void arch_trigger_level_intr(__unused struct acrn_vm *vm,
|
|
__unused uint32_t irq, __unused bool assert) {}
|
|
|
|
|
|
static void fdt_set_hart_isa_str_all(void *fdt, const char *isa_str)
|
|
{
|
|
int cpus_off, cpu, ret, len;
|
|
const char *val;
|
|
|
|
cpus_off = fdt_path_offset(fdt, "/cpus");
|
|
if (cpus_off > 0) {
|
|
fdt_for_each_subnode(cpu, fdt, cpus_off) {
|
|
val = (const char *)fdt_getprop(fdt, cpu, "device_type", &len);
|
|
if ((len > 0) && (strncmp(val, "cpu", 3) == 0)) {
|
|
ret = fdt_setprop_string(fdt, cpu, "riscv,isa", isa_str);
|
|
if (ret < 0) {
|
|
pr_err("Failed to set hart isa string: %d", ret);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void arch_init_service_vm_vfdt(struct acrn_vm *vm)
|
|
{
|
|
/* TODO: For now hardcode the isa string.
|
|
*
|
|
* To do it formally, get isa string from host, remove extensions
|
|
* that we do not support (such as "h") and pass to vm.
|
|
*/
|
|
const char *isa_str = "rv64imafdc_zicsr_zifencei_sstc";
|
|
fdt_set_hart_isa_str_all(vm_get_vfdt(vm), isa_str);
|
|
}
|