diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 99094b84d..199001962 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -111,6 +111,16 @@ bool is_rt_vm(const struct acrn_vm *vm) return ((vm_config->guest_flags & GUEST_FLAG_RT) != 0U); } +/** + * @pre vm != NULL && vm_config != NULL && vm->vmid < CONFIG_MAX_VM_NUM + */ +bool is_highest_severity_vm(const struct acrn_vm *vm) +{ + struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id); + + return ((vm_config->guest_flags & GUEST_FLAG_HIGHEST_SEVERITY) != 0U); +} + /** * @pre vm != NULL && vm_config != NULL && vm->vmid < CONFIG_MAX_VM_NUM */ diff --git a/hypervisor/arch/x86/guest/vm_reset.c b/hypervisor/arch/x86/guest/vm_reset.c index 91f7e495d..ba4929855 100644 --- a/hypervisor/arch/x86/guest/vm_reset.c +++ b/hypervisor/arch/x86/guest/vm_reset.c @@ -78,6 +78,45 @@ void triple_fault_shutdown_vm(struct acrn_vm *vm) } } +static void reset_host(void) +{ + struct acpi_generic_address *gas = &(host_reset_reg.reg); + + + /* TODO: gracefully shut down all guests before doing host 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) && + (gas->address != 0U) && (gas->address != 0xcf9U)) { + pio_write8(host_reset_reg.val, (uint16_t)host_reset_reg.reg.address); + } + + /* + * Fall back + * making sure bit 2 (RST_CPU) is '0', when the reset command is issued. + */ + pio_write8(0x2U, 0xcf9U); + pio_write8(0xeU, 0xcf9U); + + /* + * Fall back + * keyboard controller might cause the INIT# being asserted, + * and not power cycle the system. + */ + pio_write8(0xfeU, 0x64U); + + pr_fatal("%s(): can't reset host.", __func__); + while (1) { + asm_pause(); + } +} + /** * @pre vcpu != NULL && vm != NULL */ @@ -108,7 +147,11 @@ static bool handle_common_reset_reg_write(struct acrn_vm *vm, bool reset) { bool ret = true; - if (is_postlaunched_vm(vm)) { + if (is_highest_severity_vm(vm)) { + if (reset) { + reset_host(); + } + } else if (is_postlaunched_vm(vm)) { /* re-inject to DM */ ret = false; @@ -155,7 +198,11 @@ static bool handle_reset_reg_write(__unused struct acrn_vm *vm, uint16_t addr, s { if (bytes == 1U) { if (val == host_reset_reg.val) { - /* ignore reset request */ + if (is_highest_severity_vm(vm)) { + reset_host(); + } else { + /* ignore reset request */ + } } else { /* * ACPI defines the reset value but doesn't specify the meaning of other values. diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 038b3a4e2..734f4996c 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -218,6 +218,7 @@ void vrtc_init(struct acrn_vm *vm); bool is_lapic_pt_configured(const struct acrn_vm *vm); bool is_rt_vm(const struct acrn_vm *vm); +bool is_highest_severity_vm(const struct acrn_vm *vm); bool vm_hide_mtrr(const struct acrn_vm *vm); #endif /* !ASSEMBLER */ diff --git a/hypervisor/include/public/acrn_common.h b/hypervisor/include/public/acrn_common.h index 70454bebb..373e353d2 100644 --- a/hypervisor/include/public/acrn_common.h +++ b/hypervisor/include/public/acrn_common.h @@ -53,6 +53,7 @@ #define GUEST_FLAG_CLOS_REQUIRED (1UL << 3U) /* Whether CLOS is required */ #define GUEST_FLAG_HIDE_MTRR (1UL << 4U) /* Whether hide MTRR from VM */ #define GUEST_FLAG_RT (1UL << 5U) /* Whether the vm is RT-VM */ +#define GUEST_FLAG_HIGHEST_SEVERITY (1UL << 6U) /* Whether has the highest severity */ /* TODO: We may need to get this addr from guest ACPI instead of hardcode here */ #define VIRTUAL_PM1A_CNT_ADDR 0x404U diff --git a/hypervisor/scenarios/industry/vm_configurations.c b/hypervisor/scenarios/industry/vm_configurations.c index f9bb2dc2c..ad39c4097 100644 --- a/hypervisor/scenarios/industry/vm_configurations.c +++ b/hypervisor/scenarios/industry/vm_configurations.c @@ -53,6 +53,9 @@ struct acrn_vm_config vm_configs[CONFIG_MAX_VM_NUM] = { .uuid = {0x49U, 0x5aU, 0xe2U, 0xe5U, 0x26U, 0x03U, 0x4dU, 0x64U, \ 0xafU, 0x76U, 0xd4U, 0xbcU, 0x5aU, 0x8eU, 0xc0U, 0xe5U}, /* 495ae2e5-2603-4d64-af76-d4bc5a8ec0e5 */ + + /* The hard RTVM must be launched as VM2 */ + .guest_flags = GUEST_FLAG_HIGHEST_SEVERITY, .vuart[0] = { .type = VUART_LEGACY_PIO, .addr.port_base = INVALID_COM_BASE, diff --git a/hypervisor/scenarios/sdc/vm_configurations.c b/hypervisor/scenarios/sdc/vm_configurations.c index 970a9d5f5..fd14f450d 100644 --- a/hypervisor/scenarios/sdc/vm_configurations.c +++ b/hypervisor/scenarios/sdc/vm_configurations.c @@ -14,7 +14,9 @@ struct acrn_vm_config vm_configs[CONFIG_MAX_VM_NUM] = { .uuid = {0xdbU, 0xbbU, 0xd4U, 0x34U, 0x7aU, 0x57U, 0x42U, 0x16U, \ 0xa1U, 0x2cU, 0x22U, 0x01U, 0xf1U, 0xabU, 0x02U, 0x40U}, /* dbbbd434-7a57-4216-a12c-2201f1ab0240 */ - .guest_flags = 0UL, + + /* Allow SOS to reboot the host since there is supposed to be the highest severity guest */ + .guest_flags = GUEST_FLAG_HIGHEST_SEVERITY, .clos = 0U, .memory = { .start_hpa = 0UL,