Skip to content

Commit 9aa3fe6

Browse files
ZideChen0wenlingz
authored andcommitted
hv: emulate reset register 0xcf9 and 0x64
- 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>
1 parent 8ad0fd9 commit 9aa3fe6

File tree

4 files changed

+102
-2
lines changed

4 files changed

+102
-2
lines changed

hypervisor/arch/x86/guest/vm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <errno.h>
99
#include <sprintf.h>
1010
#include <vm.h>
11+
#include <vm_reset.h>
1112
#include <bits.h>
1213
#include <e820.h>
1314
#include <multiboot.h>
@@ -423,6 +424,8 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_
423424

424425
vpci_init(vm);
425426

427+
register_reset_port_handler(vm);
428+
426429
/* vpic wire_mode default is INTR */
427430
vm->wire_mode = VPIC_WIRE_INTR;
428431

hypervisor/arch/x86/guest/vm_reset.c

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,102 @@
55
*/
66

77
#include <vm.h>
8-
#include <vm_reset.h>
8+
#include <io.h>
9+
#include <logmsg.h>
910
#include <per_cpu.h>
11+
#include <vm_reset.h>
12+
13+
/**
14+
* @pre vcpu != NULL && vm != NULL
15+
*/
16+
static bool handle_reset_reg_read(struct acrn_vm *vm, struct acrn_vcpu *vcpu, __unused uint16_t addr,
17+
__unused size_t bytes)
18+
{
19+
bool ret = true;
20+
21+
if (is_postlaunched_vm(vm)) {
22+
/* re-inject to DM */
23+
ret = false;
24+
} else {
25+
/*
26+
* - keyboard control/status register 0x64: ACRN doesn't expose kbd controller to the guest.
27+
* - reset control register 0xcf9: hide this from guests for now.
28+
*/
29+
vcpu->req.reqs.pio.value = ~0U;
30+
}
31+
32+
return ret;
33+
}
34+
35+
/**
36+
* @pre vm != NULL
37+
*/
38+
static bool handle_common_reset_reg_write(struct acrn_vm *vm, bool reset)
39+
{
40+
bool ret = true;
41+
42+
if (is_postlaunched_vm(vm)) {
43+
/* re-inject to DM */
44+
ret = false;
45+
46+
if (reset && is_rt_vm(vm)) {
47+
vm->state = VM_POWERING_OFF;
48+
}
49+
} else {
50+
/*
51+
* ignore writes from SOS or pre-launched VMs.
52+
* equivalent to hide this port from guests.
53+
*/
54+
}
55+
56+
return ret;
57+
}
58+
59+
/**
60+
* @pre vm != NULL
61+
*/
62+
static bool handle_kb_write(struct acrn_vm *vm, __unused uint16_t addr, size_t bytes, uint32_t val)
63+
{
64+
/* ignore commands other than system reset */
65+
return handle_common_reset_reg_write(vm, ((bytes == 1U) && (val == 0xfeU)));
66+
}
67+
68+
/*
69+
* Reset Control register at I/O port 0xcf9.
70+
* Bit 1 - 0: "soft" reset. Force processor begin execution at power-on reset vector.
71+
* 1: "hard" reset. e.g. assert PLTRST# (if implemented) to do a host reset.
72+
* Bit 2 - initiates a system reset when it transitions from 0 to 1.
73+
* Bit 3 - 1: full reset (aka code reset), SLP_S3#/4#/5# or similar pins are asserted for full power cycle.
74+
* 0: will be dropped if system in S3/S4/S5.
75+
*/
76+
/**
77+
* @pre vm != NULL
78+
*/
79+
static bool handle_cf9_write(struct acrn_vm *vm, __unused uint16_t addr, size_t bytes, uint32_t val)
80+
{
81+
/* We don't differentiate among hard/soft/warm/cold reset */
82+
return handle_common_reset_reg_write(vm, ((bytes == 1U) && ((val & 0x4U) == 0x4U) && ((val & 0xaU) != 0U)));
83+
}
84+
85+
/**
86+
* @pre vm != NULL
87+
*/
88+
void register_reset_port_handler(struct acrn_vm *vm)
89+
{
90+
/* Don't support SOS and pre-launched VM re-launch for now. */
91+
if (!is_postlaunched_vm(vm) || is_rt_vm(vm)) {
92+
struct vm_io_range io_range = {
93+
.flags = IO_ATTR_RW,
94+
.len = 1U
95+
};
96+
97+
io_range.base = 0x64U;
98+
register_pio_emulation_handler(vm, KB_PIO_IDX, &io_range, handle_reset_reg_read, handle_kb_write);
99+
100+
io_range.base = 0xcf9U;
101+
register_pio_emulation_handler(vm, CF9_PIO_IDX, &io_range, handle_reset_reg_read, handle_cf9_write);
102+
}
103+
}
10104

11105
void shutdown_vm_from_idle(uint16_t pcpu_id)
12106
{

hypervisor/include/arch/x86/guest/vm_reset.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef VM_RESET_H_
88
#define VM_RESET_H_
99

10+
void register_reset_port_handler(struct acrn_vm *vm);
1011
void shutdown_vm_from_idle(uint16_t pcpu_id);
1112

1213
#endif /* VM_RESET_H_ */

hypervisor/include/arch/x86/guest/vmx_io.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
#define PM1B_CNT_PIO_IDX (PM1B_EVT_PIO_IDX + 1U)
2525
#define RTC_PIO_IDX (PM1B_CNT_PIO_IDX + 1U)
2626
#define VIRTUAL_PM1A_CNT_PIO_IDX (RTC_PIO_IDX + 1U)
27-
#define EMUL_PIO_IDX_MAX (VIRTUAL_PM1A_CNT_PIO_IDX + 1U)
27+
#define KB_PIO_IDX (VIRTUAL_PM1A_CNT_PIO_IDX + 1U)
28+
#define CF9_PIO_IDX (KB_PIO_IDX + 1U)
29+
#define EMUL_PIO_IDX_MAX (CF9_PIO_IDX + 1U)
2830

2931
/**
3032
* @brief The handler of VM exits on I/O instructions

0 commit comments

Comments
 (0)