HV: Register S5 pio handler for dm-launched RTVM

The virtual pm port of RTVM is intercepted by HV. But the HV needs to inform the DM as well.
So we will forward the virtual S5 request to DM too

The handler in HV just set the pm state flag (VM_POWERING_OFF) which indicate that the RTVM is powering
off by itself. Meanwhile, there are data resources in VHM and DM should be released once we handle the PM
of RTVM in HV. So, return to DM to go through the entire VM destroy cycles to release the resources.
During the cycles, the DM will try to pause vm through hypercall. In the hypercall handler in HV, we will
check the pm state flag. If it is set, pause all the vCPUs of the vm. Otherwise, reject the request.

In this way, we can make sure that RTVM can only trigger its s5 by itself. All
other S5 request from external will be rejected.

Here is sequence chart of RTVM s5.

   poweroff
+-----------+              +----------+           +-----------+         +----------+
|    vBSP   |              |    vAPs  |           |    HV     |         |    DM    |
+-----+-----+              +----------+           +-----+-----+         +-----+----+
      |                         |                       |                     |
      |   Stop all other cpus   |                       |                     |
      +----------------------------+                    |                     |
      |                         |  |Disable LAPIC       |                     |
      |                         +<-+                    |                     |
      |                         |                       |                     |
      |                         +--+                    |                     |
      |                         |  |HLT in              |                     |
      | All other cpus stopped  |  |non-root mode       |                     |
      +----------------------------+                    |                     |
      |     Call ACPI method to enter s5                |                     |
      +-------------------------+---------------------> |                     |
      |                         |   Set s5 flag         |                     |
      |                         | <---------------------+                     |
      |                         |   APs paused          | Re-inject IOREQ TO DM
      |                         | +-------------------> +-------------------> +
      |                         |                       |   Pause VM          |
      |                         |   Check S5 flag:      | <-------------------+
      |                         |    - If set, pause vm |  VM paused          |
      |                         |    - If no, reject    | +-----------------> +--+
      |                         |                       |  Destroy VM         |  |Deinit works
      |                         |                       | <--------------------<-+
      |                         |                       |  VM destroyed       |
      |                         |                       | +-----------------> |
      +                         +                       +                     +

Tracked-On: #2865
Signed-off-by: Kaige Fu <kaige.fu@intel.com>
This commit is contained in:
Kaige Fu 2019-03-24 09:52:28 +00:00 committed by ACRN System Integration
parent 1c0d7f78d0
commit 83d11bbff8
5 changed files with 36 additions and 1 deletions

View File

@ -213,3 +213,28 @@ void register_pm1ab_handler(struct acrn_vm *vm)
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_vm *vm, __unused struct acrn_vcpu *vcpu,
__unused uint16_t addr, __unused size_t width)
{
return false;
}
static bool rt_vm_pm1a_io_write(__unused struct acrn_vm *vm, __unused uint16_t addr,
__unused size_t width, __unused uint32_t v)
{
/* TODO: Check if the vm is trying to powering off itself */
return false;
}
void register_rt_vm_pm1a_ctl_handler(struct acrn_vm *vm)
{
struct vm_io_range io_range;
io_range.flags = IO_ATTR_RW;
io_range.base = RT_VM_PM1A_CNT_ADDR;
io_range.len = 1U;
register_pio_emulation_handler(vm, RT_VM_PM1A_CNT_PIO_IDX, &io_range,
&rt_vm_pm1a_io_read, &rt_vm_pm1a_io_write);
}

View File

@ -421,6 +421,11 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_
/* Init full emulated vIOAPIC instance */
vioapic_init(vm);
/* Intercept the virtual pm port for RTVM */
if (is_rt_vm(vm)) {
register_rt_vm_pm1a_ctl_handler(vm);
}
/* Populate return VM handle */
*rtn_vm = vm;
vm->sw.io_shared_page = NULL;

View File

@ -11,5 +11,6 @@ void vm_setup_cpu_state(struct acrn_vm *vm);
int32_t vm_load_pm_s_state(struct acrn_vm *vm);
int32_t validate_pstate(const struct acrn_vm *vm, uint64_t perf_ctl);
void register_pm1ab_handler(struct acrn_vm *vm);
void register_rt_vm_pm1a_ctl_handler(struct acrn_vm *vm);
#endif /* PM_H */

View File

@ -21,7 +21,8 @@
#define PM1B_EVT_PIO_IDX (PM1A_CNT_PIO_IDX + 1U)
#define PM1B_CNT_PIO_IDX (PM1B_EVT_PIO_IDX + 1U)
#define RTC_PIO_IDX (PM1B_CNT_PIO_IDX + 1U)
#define EMUL_PIO_IDX_MAX (RTC_PIO_IDX + 1U)
#define RT_VM_PM1A_CNT_PIO_IDX (RTC_PIO_IDX + 1U)
#define EMUL_PIO_IDX_MAX (RT_VM_PM1A_CNT_PIO_IDX + 1U)
/**
* @brief The handler of VM exits on I/O instructions

View File

@ -54,6 +54,9 @@
#define GUEST_FLAG_HIDE_MTRR (1UL << 4U) /* Whether hide MTRR from VM */
#define GUEST_FLAG_RT (1UL << 5U) /* Whether the vm is RT-VM */
/* TODO: We may need to get this addr from guest ACPI instead of hardcode here */
#define RT_VM_PM1A_CNT_ADDR 0x404U
/**
* @brief Hypercall
*