mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-02 21:46:58 +00:00
hv: handle reboot from Service VM properly
Service VM may write 0x6 to port 0xcf9 to trigger a warm reset, but current hypervisor always performs a cold reset by writing 0xE to CF9. Hypervisor should reboot the system in the same mode as Service VM specified. Specific OS features (like linux pstore) requires warm reset to keep data across reboot. The behavior of hv console's reboot command (cold reset) remains unchanged. Tracked-On: #8539 Signed-off-by: Jiaqing Zhao <jiaqing.zhao@linux.intel.com> Reviewed-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
17c4ce75a1
commit
eae668268e
hypervisor
@ -95,7 +95,7 @@ static bool handle_reset_reg_read(struct acrn_vcpu *vcpu, __unused uint16_t addr
|
||||
/**
|
||||
* @pre vm != NULL
|
||||
*/
|
||||
static bool handle_common_reset_reg_write(struct acrn_vcpu *vcpu, bool reset)
|
||||
static bool handle_common_reset_reg_write(struct acrn_vcpu *vcpu, bool reset, bool warm)
|
||||
{
|
||||
struct acrn_vm *vm = vcpu->vm;
|
||||
bool ret = true;
|
||||
@ -105,7 +105,7 @@ static bool handle_common_reset_reg_write(struct acrn_vcpu *vcpu, bool reset)
|
||||
poweroff_if_rt_vm(vm);
|
||||
|
||||
if (get_highest_severity_vm(true) == vm) {
|
||||
reset_host();
|
||||
reset_host(warm);
|
||||
} else if (is_postlaunched_vm(vm)) {
|
||||
/* re-inject to DM */
|
||||
ret = false;
|
||||
@ -142,7 +142,7 @@ static bool handle_common_reset_reg_write(struct acrn_vcpu *vcpu, bool reset)
|
||||
static bool handle_kb_write(struct acrn_vcpu *vcpu, __unused uint16_t addr, size_t bytes, uint32_t val)
|
||||
{
|
||||
/* ignore commands other than system reset */
|
||||
return handle_common_reset_reg_write(vcpu, ((bytes == 1U) && (val == 0xfeU)));
|
||||
return handle_common_reset_reg_write(vcpu, ((bytes == 1U) && (val == 0xfeU)), false);
|
||||
}
|
||||
|
||||
static bool handle_kb_read(struct acrn_vcpu *vcpu, uint16_t addr, size_t bytes)
|
||||
@ -172,9 +172,9 @@ static bool handle_kb_read(struct acrn_vcpu *vcpu, uint16_t addr, size_t bytes)
|
||||
*/
|
||||
static bool handle_cf9_write(struct acrn_vcpu *vcpu, __unused uint16_t addr, size_t bytes, uint32_t val)
|
||||
{
|
||||
/* We don't differentiate among hard/soft/warm/cold reset */
|
||||
return handle_common_reset_reg_write(vcpu,
|
||||
((bytes == 1U) && ((val & 0x4U) == 0x4U) && ((val & 0xaU) != 0U)));
|
||||
((bytes == 1U) && ((val & 0x4U) == 0x4U) && ((val & 0xaU) != 0U)),
|
||||
((val & 0x8U) == 0U));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,7 +189,7 @@ static bool handle_reset_reg_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t
|
||||
struct acpi_reset_reg *reset_reg = get_host_reset_reg_data();
|
||||
|
||||
if (val == reset_reg->val) {
|
||||
ret = handle_common_reset_reg_write(vcpu, true);
|
||||
ret = handle_common_reset_reg_write(vcpu, true, false);
|
||||
} else {
|
||||
/*
|
||||
* ACPI defines the reset value but doesn't specify the meaning of other values.
|
||||
|
@ -244,10 +244,10 @@ void host_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_
|
||||
resume_console();
|
||||
}
|
||||
|
||||
void reset_host(void)
|
||||
void reset_host(bool warm)
|
||||
{
|
||||
struct acrn_acpi_generic_address *gas = &(host_reset_reg.reg);
|
||||
|
||||
uint8_t reboot_code = warm ? CF9_RESET_WARM : CF9_RESET_COLD;
|
||||
|
||||
/* TODO: gracefully shut down all guests before doing host reset. */
|
||||
|
||||
@ -256,11 +256,6 @@ void reset_host(void)
|
||||
* The platform we are running must support at least one of reset method:
|
||||
* - ACPI reset
|
||||
* - 0xcf9 reset
|
||||
*
|
||||
* UEFI more likely sets the reset value as 0x6 (not 0xe) for 0xcf9 port.
|
||||
* This asserts PLTRST# to reset devices on the platform, but not the
|
||||
* SLP_S3#/4#/5# signals, which power down the systems. This might not be
|
||||
* enough for us.
|
||||
*/
|
||||
if ((gas->space_id == SPACE_SYSTEM_IO) &&
|
||||
(gas->bit_width == 8U) && (gas->bit_offset == 0U) &&
|
||||
@ -270,7 +265,8 @@ void reset_host(void)
|
||||
/* making sure bit 2 (RST_CPU) is '0', when the reset command is issued. */
|
||||
pio_write8(0x2U, 0xcf9U);
|
||||
udelay(50U);
|
||||
pio_write8(0xeU, 0xcf9U);
|
||||
pio_write8(reboot_code, 0xcf9U);
|
||||
udelay(50U);
|
||||
}
|
||||
|
||||
pr_fatal("%s(): can't reset host.", __func__);
|
||||
|
@ -1531,7 +1531,7 @@ static int32_t shell_cpuid(int32_t argc, char **argv)
|
||||
|
||||
static int32_t shell_reboot(__unused int32_t argc, __unused char **argv)
|
||||
{
|
||||
reset_host();
|
||||
reset_host(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
#define BIT_SLP_EN 13U
|
||||
#define BIT_WAK_STS 15U
|
||||
|
||||
#define CF9_RESET_WARM 0x6
|
||||
#define CF9_RESET_COLD 0xE
|
||||
|
||||
struct cpu_state_info {
|
||||
uint8_t px_cnt; /* count of all Px states */
|
||||
const struct acrn_pstate_data *px_data;
|
||||
@ -38,7 +41,7 @@ extern void asm_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1
|
||||
extern void restore_s3_context(void);
|
||||
struct cpu_state_info *get_cpu_pm_state_info(void);
|
||||
struct acpi_reset_reg *get_host_reset_reg_data(void);
|
||||
void reset_host(void);
|
||||
void reset_host(bool warm);
|
||||
void init_frequency_policy(void);
|
||||
void apply_frequency_policy(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user