Skip to content

Commit

Permalink
hv: emulate reset register 0xcf9 and 0x64
Browse files Browse the repository at this point in the history
- post-launched RTVM: intercept both PIO ports so that hypervisor has a
  chance to set VM_POWERING_OFF flag.
- all other type of VMs: deny these 2 ports from guest access so that
  guests are not able to reset host.

Tracked-On: #2700
Signed-off-by: Zide Chen <zide.chen@intel.com>
Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
  • Loading branch information
ZideChen0 authored and wenlingz committed May 15, 2019
1 parent 8ad0fd9 commit 9aa3fe6
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 2 deletions.
3 changes: 3 additions & 0 deletions hypervisor/arch/x86/guest/vm.c
Expand Up @@ -8,6 +8,7 @@
#include <errno.h>
#include <sprintf.h>
#include <vm.h>
#include <vm_reset.h>
#include <bits.h>
#include <e820.h>
#include <multiboot.h>
Expand Down Expand Up @@ -423,6 +424,8 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_

vpci_init(vm);

register_reset_port_handler(vm);

/* vpic wire_mode default is INTR */
vm->wire_mode = VPIC_WIRE_INTR;

Expand Down
96 changes: 95 additions & 1 deletion hypervisor/arch/x86/guest/vm_reset.c
Expand Up @@ -5,8 +5,102 @@
*/

#include <vm.h>
#include <vm_reset.h>
#include <io.h>
#include <logmsg.h>
#include <per_cpu.h>
#include <vm_reset.h>

/**
* @pre vcpu != NULL && vm != NULL
*/
static bool handle_reset_reg_read(struct acrn_vm *vm, struct acrn_vcpu *vcpu, __unused uint16_t addr,
__unused size_t bytes)
{
bool ret = true;

if (is_postlaunched_vm(vm)) {
/* re-inject to DM */
ret = false;
} else {
/*
* - keyboard control/status register 0x64: ACRN doesn't expose kbd controller to the guest.
* - reset control register 0xcf9: hide this from guests for now.
*/
vcpu->req.reqs.pio.value = ~0U;
}

return ret;
}

/**
* @pre vm != NULL
*/
static bool handle_common_reset_reg_write(struct acrn_vm *vm, bool reset)
{
bool ret = true;

if (is_postlaunched_vm(vm)) {
/* re-inject to DM */
ret = false;

if (reset && is_rt_vm(vm)) {
vm->state = VM_POWERING_OFF;
}
} else {
/*
* ignore writes from SOS or pre-launched VMs.
* equivalent to hide this port from guests.
*/
}

return ret;
}

/**
* @pre vm != NULL
*/
static bool handle_kb_write(struct acrn_vm *vm, __unused uint16_t addr, size_t bytes, uint32_t val)
{
/* ignore commands other than system reset */
return handle_common_reset_reg_write(vm, ((bytes == 1U) && (val == 0xfeU)));
}

/*
* Reset Control register at I/O port 0xcf9.
* Bit 1 - 0: "soft" reset. Force processor begin execution at power-on reset vector.
* 1: "hard" reset. e.g. assert PLTRST# (if implemented) to do a host reset.
* Bit 2 - initiates a system reset when it transitions from 0 to 1.
* Bit 3 - 1: full reset (aka code reset), SLP_S3#/4#/5# or similar pins are asserted for full power cycle.
* 0: will be dropped if system in S3/S4/S5.
*/
/**
* @pre vm != NULL
*/
static bool handle_cf9_write(struct acrn_vm *vm, __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(vm, ((bytes == 1U) && ((val & 0x4U) == 0x4U) && ((val & 0xaU) != 0U)));
}

/**
* @pre vm != NULL
*/
void register_reset_port_handler(struct acrn_vm *vm)
{
/* Don't support SOS and pre-launched VM re-launch for now. */
if (!is_postlaunched_vm(vm) || is_rt_vm(vm)) {
struct vm_io_range io_range = {
.flags = IO_ATTR_RW,
.len = 1U
};

io_range.base = 0x64U;
register_pio_emulation_handler(vm, KB_PIO_IDX, &io_range, handle_reset_reg_read, handle_kb_write);

io_range.base = 0xcf9U;
register_pio_emulation_handler(vm, CF9_PIO_IDX, &io_range, handle_reset_reg_read, handle_cf9_write);
}
}

void shutdown_vm_from_idle(uint16_t pcpu_id)
{
Expand Down
1 change: 1 addition & 0 deletions hypervisor/include/arch/x86/guest/vm_reset.h
Expand Up @@ -7,6 +7,7 @@
#ifndef VM_RESET_H_
#define VM_RESET_H_

void register_reset_port_handler(struct acrn_vm *vm);
void shutdown_vm_from_idle(uint16_t pcpu_id);

#endif /* VM_RESET_H_ */
4 changes: 3 additions & 1 deletion hypervisor/include/arch/x86/guest/vmx_io.h
Expand Up @@ -24,7 +24,9 @@
#define PM1B_CNT_PIO_IDX (PM1B_EVT_PIO_IDX + 1U)
#define RTC_PIO_IDX (PM1B_CNT_PIO_IDX + 1U)
#define VIRTUAL_PM1A_CNT_PIO_IDX (RTC_PIO_IDX + 1U)
#define EMUL_PIO_IDX_MAX (VIRTUAL_PM1A_CNT_PIO_IDX + 1U)
#define KB_PIO_IDX (VIRTUAL_PM1A_CNT_PIO_IDX + 1U)
#define CF9_PIO_IDX (KB_PIO_IDX + 1U)
#define EMUL_PIO_IDX_MAX (CF9_PIO_IDX + 1U)

/**
* @brief The handler of VM exits on I/O instructions
Expand Down

0 comments on commit 9aa3fe6

Please sign in to comment.