mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-18 11:47:30 +00:00
hv: add support for shutdown for pre-launched VMs
Currently, ACRN only support shutdown when triple fault happens, because ACRN doesn't present/emulate a virtual HW, i.e. port IO, to support shutdown. This patch emulate a virtual shutdown component, and the vACPI method for guest OS to use. Pre-launched VM uses ACPI reduced HW mode, intercept the virtual sleep control/status registers for pre-launched VMs shutdown Tracked-On: #5411 Signed-off-by: dongshen <dongsheng.x.zhang@intel.com>
This commit is contained in:
parent
8f79ceefbd
commit
ca5683f78d
@ -309,8 +309,88 @@ static void register_rt_vm_pm1a_ctl_handler(struct acrn_vm *vm)
|
||||
&rt_vm_pm1a_io_read, &rt_vm_pm1a_io_write);
|
||||
}
|
||||
|
||||
/*
|
||||
* @pre vcpu != NULL
|
||||
*/
|
||||
static bool prelaunched_vm_sleep_io_read(struct acrn_vcpu *vcpu, __unused uint16_t addr, __unused size_t width)
|
||||
{
|
||||
vcpu->req.reqs.pio.value = 0U;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* @pre vcpu != NULL
|
||||
* @pre vcpu->vm != NULL
|
||||
*/
|
||||
static bool prelaunched_vm_sleep_io_write(struct acrn_vcpu *vcpu, 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;
|
||||
|
||||
/* ACPI sleep control register:
|
||||
*
|
||||
* Bits 2~4: SLP_TYPx, defines the type of sleeping state the system enters when the
|
||||
* SLP_EN bit is set to one. This 3-bit field defines the type of hardware sleep state
|
||||
* the system enters when the SLP_EN bit is set. The \_S5 object contains 3-bit binary
|
||||
* value (0x5) associated with the S5 sleeping state
|
||||
*
|
||||
* Bit 5: SLP_EN, This is a write-only bit and reads to it always return a zero. Setting
|
||||
* this bit causes the system to sequence into the sleeping state associated with the
|
||||
* SLP_TYPx fields programmed with the values from the \_S5 object
|
||||
*/
|
||||
slp_type = (v >> 2U) & 0x7U;
|
||||
slp_en = (v >> 5U) & 0x1U;
|
||||
|
||||
if (slp_en && (slp_type == 5U)) {
|
||||
get_vm_lock(vm);
|
||||
if (is_rt_vm(vm)) {
|
||||
vm->state = VM_READY_TO_POWEROFF;
|
||||
}
|
||||
pause_vm(vm);
|
||||
put_vm_lock(vm);
|
||||
|
||||
bitmap_set_nolock(vm->vm_id, &per_cpu(shutdown_vm_bitmap, pcpuid_from_vcpu(vcpu)));
|
||||
make_shutdown_vm_request(pcpuid_from_vcpu(vcpu));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void init_guest_pm(struct acrn_vm *vm)
|
||||
{
|
||||
struct pm_s_state_data *sx_data = get_host_sstate_data();
|
||||
|
||||
/*
|
||||
* In enter_s5(), it will call save_s5_reg_val() to initialize system_pm1a_cnt_val/system_pm1b_cnt_val when the
|
||||
* vm is SOS.
|
||||
* If there is no SOS, save_s5_reg_val() will not be called and these 2 variables will not be initialized properly
|
||||
* so shutdown_system() will fail, explicitly init here to avoid this
|
||||
*/
|
||||
save_s5_reg_val((sx_data->s5_pkg.val_pm1a << BIT_SLP_TYPx) | (1U << BIT_SLP_EN),
|
||||
(sx_data->s5_pkg.val_pm1b << BIT_SLP_TYPx) | (1U << BIT_SLP_EN));
|
||||
|
||||
vm_setup_cpu_state(vm);
|
||||
|
||||
if (is_sos_vm(vm)) {
|
||||
@ -318,10 +398,11 @@ void init_guest_pm(struct acrn_vm *vm)
|
||||
if (vm_load_pm_s_state(vm) == 0) {
|
||||
register_pm1ab_handler(vm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Intercept the virtual pm port for RTVM */
|
||||
if (is_rt_vm(vm)) {
|
||||
} else if (is_postlaunched_vm(vm) && is_rt_vm(vm)) {
|
||||
/* Intercept the virtual pm port for post launched RTVM */
|
||||
register_rt_vm_pm1a_ctl_handler(vm);
|
||||
} else if (is_prelaunched_vm(vm)) {
|
||||
/* Intercept the virtual sleep control/status registers for pre-launched VM */
|
||||
register_prelaunched_vm_sleep_handler(vm);
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,8 @@
|
||||
#define KB_PIO_IDX (VIRTUAL_PM1A_CNT_PIO_IDX + 1U)
|
||||
#define CF9_PIO_IDX (KB_PIO_IDX + 1U)
|
||||
#define PIO_RESET_REG_IDX (CF9_PIO_IDX + 1U)
|
||||
#define EMUL_PIO_IDX_MAX (PIO_RESET_REG_IDX + 1U)
|
||||
|
||||
#define SLEEP_CTL_PIO_IDX (PIO_RESET_REG_IDX + 1U)
|
||||
#define EMUL_PIO_IDX_MAX (SLEEP_CTL_PIO_IDX + 1U)
|
||||
/**
|
||||
* @brief The handler of VM exits on I/O instructions
|
||||
*
|
||||
|
@ -54,6 +54,7 @@
|
||||
#define GUEST_FLAG_RT (1UL << 4U) /* Whether the vm is RT-VM */
|
||||
|
||||
/* TODO: We may need to get this addr from guest ACPI instead of hardcode here */
|
||||
#define VIRTUAL_SLEEP_CTL_ADDR 0x400U /* Pre-launched VM uses ACPI reduced HW mode and sleep control register */
|
||||
#define VIRTUAL_PM1A_CNT_ADDR 0x404U
|
||||
#define VIRTUAL_PM1A_SCI_EN 0x0001
|
||||
#define VIRTUAL_PM1A_SLP_TYP 0x1c00U
|
||||
|
Loading…
Reference in New Issue
Block a user