Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hypervisor/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ COMMON_C_SRCS += boot/bare.c

# dm componment
COMMON_C_SRCS += dm/vuart.c
COMMON_C_SRCS += dm/io_req.c

ifeq ($(ARCH),x86)
COMMON_C_SRCS += common/efi_mmap.c
Expand All @@ -215,7 +216,6 @@ COMMON_C_SRCS += common/hv_main.c
COMMON_C_SRCS += common/hypercall.c
COMMON_C_SRCS += common/ptdev.c
COMMON_C_SRCS += dm/vrtc.c
COMMON_C_SRCS += dm/io_req.c
COMMON_C_SRCS += dm/vpci/vdev.c
COMMON_C_SRCS += dm/vpci/vpci.c
COMMON_C_SRCS += dm/vpci/vroot_port.c
Expand Down
38 changes: 38 additions & 0 deletions hypervisor/arch/riscv/guest/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,43 @@ static void fdt_set_hart_isa_str_all(void *fdt, const char *isa_str)
}
}

static int fdt_set_hsm(void *fdt)
{
int soc_offset, plic_offset, new_offset, child, ret = 0;
const char *comp;

soc_offset = fdt_path_offset(fdt, "/soc");
if (soc_offset < 0) {
ret = soc_offset;
} else {
child = fdt_first_subnode(fdt, soc_offset);
while (child >= 0) {
comp = fdt_getprop(fdt, child, "compatible", NULL);
if (comp && strstr_s(comp, 8, "plic", 8)) {
plic_offset = child;
break;
}
child = fdt_next_subnode(fdt, child);
}

if (plic_offset < 0) {
ret = -FDT_ERR_NOTFOUND;
} else {
new_offset = fdt_add_subnode(fdt, soc_offset, "hsm");
if (new_offset < 0) {
ret = new_offset;
} else {
fdt_setprop_string(fdt, new_offset, "compatible", "riscv,hsm");
fdt_setprop_cell(fdt, new_offset, "interrupts", HYPERVISOR_CALLBACK_HSM_VECTOR);
fdt_setprop_cell(fdt, new_offset, "interrupt-parent", 0x9);
}
}
}

return ret;

}

void arch_init_service_vm_vfdt(struct acrn_vm *vm)
{
/* TODO: For now hardcode the isa string.
Expand All @@ -131,4 +168,5 @@ void arch_init_service_vm_vfdt(struct acrn_vm *vm)
*/
const char *isa_str = "rv64imafdc_zicsr_zifencei_sstc";
fdt_set_hart_isa_str_all(vm_get_vfdt(vm), isa_str);
fdt_set_hsm(vm_get_vfdt(vm));
}
135 changes: 58 additions & 77 deletions hypervisor/arch/x86/guest/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,18 +141,9 @@ static inline uint8_t get_slp_typx(uint32_t pm1_cnt)
return (uint8_t)((pm1_cnt & 0x1fffU) >> BIT_SLP_TYPx);
}

static bool pm1ab_io_read(struct acrn_vcpu *vcpu, uint16_t addr, size_t width)
static inline void enter_s5(struct acrn_vm *vm, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val)
{
struct acrn_pio_request *pio_req = &vcpu->req.reqs.pio_request;

pio_req->value = pio_read(addr, width);

return true;
}

static inline void enter_s5(struct acrn_vcpu *vcpu, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val)
{
struct acrn_vm *vm = vcpu->vm;
struct acrn_vcpu *vcpu = vcpu_from_vid(vm, BSP_CPU_ID);
uint16_t pcpu_id = pcpuid_from_vcpu(vcpu);

get_vm_lock(vm);
Expand Down Expand Up @@ -190,15 +181,13 @@ static inline void enter_s3(struct acrn_vm *vm, uint32_t pm1a_cnt_val, uint32_t
}

/**
* @pre vcpu != NULL
* @pre vcpu->vm != NULL
* @pre vm != NULL
*/
static bool pm1ab_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width, uint32_t v)
static bool pm1ab_io_write(struct acrn_vm *vm, uint16_t addr, size_t width, uint32_t v)
{
static uint32_t pm1a_cnt_ready = 0U;
uint32_t pm1a_cnt_val;
bool to_write = true;
struct acrn_vm *vm = vcpu->vm;

if (width == 2U) {
uint8_t val = get_slp_typx(v);
Expand All @@ -211,7 +200,7 @@ static bool pm1ab_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
if (vm->arch_vm.pm.sx_state_data->s3_pkg.val_pm1a == val) {
enter_s3(vm, v, 0U);
} else if (vm->arch_vm.pm.sx_state_data->s5_pkg.val_pm1a == val) {
enter_s5(vcpu, v, 0U);
enter_s5(vm, v, 0U);
} else {
/* other Sx value should be ignored */
}
Expand All @@ -227,7 +216,7 @@ static bool pm1ab_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
if (vm->arch_vm.pm.sx_state_data->s3_pkg.val_pm1b == val) {
enter_s3(vm, pm1a_cnt_val, v);
} else if (vm->arch_vm.pm.sx_state_data->s5_pkg.val_pm1b == val) {
enter_s5(vcpu, pm1a_cnt_val, v);
enter_s5(vm, pm1a_cnt_val, v);
} else {
/* other Sx value should be ignored */
}
Expand All @@ -249,88 +238,74 @@ static bool pm1ab_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
return true;
}

static void register_gas_io_handler(struct acrn_vm *vm, uint32_t pio_idx, const struct acrn_acpi_generic_address *gas)
static int32_t pm1ab_pio_handler(struct io_request *io_req, void *private_data)
{
struct vm_io_range gas_io;
struct acrn_pio_request *pio_req = &io_req->reqs.pio_request;
struct acrn_vm *vm = (struct acrn_vm *)private_data;

if ((gas->address != 0UL) && (gas->space_id == SPACE_SYSTEM_IO) && (gas->bit_width != 0U)) {
gas_io.base = (uint16_t)gas->address;
gas_io.len = gas->bit_width / 8;
if (pio_req->direction == ACRN_IOREQ_DIR_WRITE) {
pm1ab_io_write(vm, pio_req->address, pio_req->size, pio_req->value);
} else {
pio_req->value = pio_read(pio_req->address, pio_req->size);
}

register_pio_emulation_handler(vm, pio_idx, &gas_io, &pm1ab_io_read, &pm1ab_io_write);
return 0;
}

pr_dbg("Enable PM1A trap for VM %d, port 0x%x, size %d\n", vm->vm_id, gas_io.base, gas_io.len);
static void register_gas_io_handler(struct acrn_vm *vm, const struct acrn_acpi_generic_address *gas)
{
if ((gas->address != 0UL) && (gas->space_id == SPACE_SYSTEM_IO) && (gas->bit_width != 0U)) {
register_pio_emulation_handler(vm, (uint16_t)gas->address, gas->bit_width / 8, pm1ab_pio_handler, vm);
pr_dbg("Enable PM1A trap for VM %d, port 0x%x, size %d\n", vm->vm_id, gas->address, gas->bit_width / 8);
}
}

static void register_pm1ab_handler(struct acrn_vm *vm)
{
struct pm_s_state_data *sx_data = vm->arch_vm.pm.sx_state_data;

register_gas_io_handler(vm, PM1A_EVT_PIO_IDX, &(sx_data->pm1a_evt));
register_gas_io_handler(vm, PM1B_EVT_PIO_IDX, &(sx_data->pm1b_evt));
register_gas_io_handler(vm, PM1A_CNT_PIO_IDX, &(sx_data->pm1a_cnt));
register_gas_io_handler(vm, PM1B_CNT_PIO_IDX, &(sx_data->pm1b_cnt));
}

static bool rt_vm_pm1a_io_read(__unused struct acrn_vcpu *vcpu,
__unused uint16_t addr, __unused size_t width)
{
return false;
register_gas_io_handler(vm, &(sx_data->pm1a_evt));
register_gas_io_handler(vm, &(sx_data->pm1b_evt));
register_gas_io_handler(vm, &(sx_data->pm1a_cnt));
register_gas_io_handler(vm, &(sx_data->pm1b_cnt));
}

/*
* retval true means that we complete the emulation in HV and no need to re-inject the request to DM.
* retval false means that we should re-inject the request to DM.
* retval -ENODEV means that we should re-inject the request to DM.
*/
/**
* @pre vcpu != NULL
* @pre vcpu->vm != NULL
*/
static bool rt_vm_pm1a_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width, uint32_t v)
static int32_t rtvm_pm1a_pio_handler(struct io_request *io_req, void *private_data)
{
if (width != 2U) {
pr_dbg("Invalid address (0x%x) or width (0x%x)", addr, width);
} else {
if (((v & VIRTUAL_PM1A_SLP_EN) != 0U) && (((v & VIRTUAL_PM1A_SLP_TYP) >> 10U) == 5U)) {
poweroff_if_rt_vm(vcpu->vm);
struct acrn_pio_request *pio_req = &io_req->reqs.pio_request;
struct acrn_vm *vm = (struct acrn_vm *)private_data;

if (pio_req->direction == ACRN_IOREQ_DIR_WRITE) {
if (pio_req->size != 2U) {
pr_dbg("%s Invalid width (0x%x)", __func__, pio_req->size);
} else {
if (((pio_req->value & VIRTUAL_PM1A_SLP_EN) != 0U) &&
(((pio_req->value & VIRTUAL_PM1A_SLP_TYP) >> 10U) == 5U)) {
poweroff_if_rt_vm(vm);
}
}
}

return false;
}

static void register_rt_vm_pm1a_ctl_handler(struct acrn_vm *vm)
{
struct vm_io_range io_range;

io_range.base = VIRTUAL_PM1A_CNT_ADDR;
io_range.len = 1U;

register_pio_emulation_handler(vm, VIRTUAL_PM1A_CNT_PIO_IDX, &io_range,
&rt_vm_pm1a_io_read, &rt_vm_pm1a_io_write);
return -ENODEV;
}

/*
* @pre vcpu != NULL
*/
static bool prelaunched_vm_sleep_io_read(struct acrn_vcpu *vcpu, __unused uint16_t addr, __unused size_t width)
static inline void register_rt_vm_pm1a_ctl_handler(struct acrn_vm *vm)
{
vcpu->req.reqs.pio_request.value = 0U;

return true;
register_pio_emulation_handler(vm, VIRTUAL_PM1A_CNT_ADDR, 1U, rtvm_pm1a_pio_handler, vm);
}

/*
* @pre vcpu != NULL
* @pre vcpu->vm != NULL
* @pre vm != NULL
*/
static bool prelaunched_vm_sleep_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width, uint32_t v)
static void prelaunched_vm_sleep_io_write(struct acrn_vm *vm, uint16_t addr, size_t width, uint32_t v)
{
if ((width == 1U) && (addr == VIRTUAL_SLEEP_CTL_ADDR)) {
bool slp_en;
uint32_t slp_type;
struct acrn_vm *vm = vcpu->vm;
struct acrn_vcpu *vcpu = vcpu_from_vid(vm, BSP_CPU_ID);

/* ACPI sleep control register:
*
Expand All @@ -356,26 +331,32 @@ static bool prelaunched_vm_sleep_io_write(struct acrn_vcpu *vcpu, uint16_t addr,
make_shutdown_vm_request(pcpuid_from_vcpu(vcpu));
}
}
}

return true;
static int32_t prelaunched_vm_sleep_pio_handler(struct io_request *io_req, void *private_data)
{
struct acrn_pio_request *pio_req = &io_req->reqs.pio_request;
struct acrn_vm *vm = (struct acrn_vm *)private_data;

if (pio_req->direction == ACRN_IOREQ_DIR_WRITE) {
prelaunched_vm_sleep_io_write(vm, pio_req->address, pio_req->size, pio_req->value);
} else {
pio_req->value = 0U;
}

return 0;
}

static void register_prelaunched_vm_sleep_handler(struct acrn_vm *vm)
{
struct vm_io_range io_range;

/* ACPI reduced HW mode is used for pre-launched VM
*
* The optional ACPI sleep registers (SLEEP_CONTROL_REG and SLEEP_STATUS_REG) specify
* a standard mechanism for system sleep state entry on HW-Reduced ACPI systems. When
* implemented, the Sleep registers are a replacement for the SLP_TYP, SLP_EN and WAK_STS
* registers in the PM1_BLK.
*/
io_range.base = VIRTUAL_SLEEP_CTL_ADDR;
io_range.len = 2U;

register_pio_emulation_handler(vm, SLEEP_CTL_PIO_IDX, &io_range,
&prelaunched_vm_sleep_io_read, &prelaunched_vm_sleep_io_write);
register_pio_emulation_handler(vm, VIRTUAL_SLEEP_CTL_ADDR, 2U, prelaunched_vm_sleep_pio_handler, vm);
}

void init_guest_pm(struct acrn_vm *vm)
Expand Down
Loading