Skip to content

Commit 5b43521

Browse files
fyin1NanlinXie
authored andcommitted
hv: trap vm0 write/read pm1a/pm1b registers
ACRN needs to trap the pm1a/pm1b written/read from VM0. So we could know when should we put the system to S3. We will have two path back to VM0: - S3 enter/exit sucess. Will reset VM0 and jump to VM0 wakeup vec with real mode - S3 enter/exit failed. Will return to the next instruction of pm1a/pm1b register writing. VM0 will read the pm1a/pm1b evt register to check whether it's waked up or not. Signed-off-by: Victor Sun <victor.sun@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
1 parent baacfdb commit 5b43521

File tree

5 files changed

+109
-1
lines changed

5 files changed

+109
-1
lines changed

hypervisor/arch/x86/guest/pm.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,98 @@ int vm_load_pm_s_state(struct vm *vm)
121121
return -1;
122122
}
123123
}
124+
125+
static inline uint16_t s3_enabled(uint16_t pm1_cnt)
126+
{
127+
return pm1_cnt & (1 << BIT_SLP_EN);
128+
}
129+
130+
static inline uint8_t get_slp_typx(uint16_t pm1_cnt)
131+
{
132+
return (pm1_cnt & 0x1fff) >> BIT_SLP_TYPx;
133+
}
134+
135+
static uint32_t pm1ab_io_read(__unused struct vm_io_handler *hdlr,
136+
__unused struct vm *vm, uint16_t addr, size_t width)
137+
{
138+
uint32_t val = io_read(addr, width);
139+
140+
if (host_enter_s3_success == 0) {
141+
/* If host S3 enter failes, we should set BIT_WAK_STS
142+
* bit for vm0 and let vm0 back from S3 failure path.
143+
*/
144+
if (addr == vm->pm.sx_state_data->pm1a_evt.address) {
145+
val |= (1 << BIT_WAK_STS);
146+
}
147+
}
148+
return val;
149+
}
150+
151+
static void pm1ab_io_write(__unused struct vm_io_handler *hdlr,
152+
__unused struct vm *vm, uint16_t addr, size_t width,
153+
uint32_t v)
154+
{
155+
static uint32_t pm1a_cnt_ready = 0;
156+
157+
if (width == 2) {
158+
uint8_t val = get_slp_typx(v);
159+
160+
if ((addr == vm->pm.sx_state_data->pm1a_cnt.address)
161+
&& (val == vm->pm.sx_state_data->s3_pkg.val_pm1a)
162+
&& s3_enabled(v)) {
163+
164+
if (vm->pm.sx_state_data->pm1b_cnt.address) {
165+
pm1a_cnt_ready = v;
166+
} else {
167+
enter_s3(vm, v, 0);
168+
}
169+
return;
170+
}
171+
172+
if ((addr == vm->pm.sx_state_data->pm1b_cnt.address)
173+
&& (val == vm->pm.sx_state_data->s3_pkg.val_pm1b)
174+
&& s3_enabled(v)) {
175+
176+
if (pm1a_cnt_ready) {
177+
enter_s3(vm, pm1a_cnt_ready, v);
178+
pm1a_cnt_ready = 0;
179+
} else {
180+
/* the case broke ACPI spec */
181+
pr_err("PM1B_CNT write error!");
182+
}
183+
return;
184+
}
185+
}
186+
187+
io_write(v, addr, width);
188+
}
189+
190+
void register_gas_io_handler(struct vm *vm, struct acpi_generic_address *gas)
191+
{
192+
uint8_t io_len[5] = {0, 1, 2, 4, 8};
193+
struct vm_io_range gas_io;
194+
195+
if ((gas->address == 0)
196+
|| (gas->space_id != SPACE_SYSTEM_IO)
197+
|| (gas->access_size == 0)
198+
|| (gas->access_size > 4))
199+
return;
200+
201+
gas_io.flags = IO_ATTR_RW,
202+
gas_io.base = gas->address,
203+
gas_io.len = io_len[gas->access_size];
204+
205+
register_io_emulation_handler(vm, &gas_io,
206+
&pm1ab_io_read, &pm1ab_io_write);
207+
208+
pr_dbg("Enable PM1A trap for VM %d, port 0x%x, size %d\n",
209+
vm->attr.id, gas_io.base, gas_io.len);
210+
}
211+
212+
void register_pm1ab_handler(struct vm *vm)
213+
{
214+
register_gas_io_handler(vm, &vm->pm.sx_state_data->pm1a_evt);
215+
register_gas_io_handler(vm, &vm->pm.sx_state_data->pm1b_evt);
216+
register_gas_io_handler(vm, &vm->pm.sx_state_data->pm1a_cnt);
217+
register_gas_io_handler(vm, &vm->pm.sx_state_data->pm1b_cnt);
218+
}

hypervisor/arch/x86/guest/vm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ int create_vm(struct vm_description *vm_desc, struct vm **rtn_vm)
143143

144144
if (is_vm0(vm)) {
145145
/* Load pm S state data */
146-
vm_load_pm_s_state(vm);
146+
if (vm_load_pm_s_state(vm) == 0)
147+
register_pm1ab_handler(vm);
147148

148149
/* Create virtual uart */
149150
vm->vuart = vuart_init(vm);

hypervisor/arch/x86/pm.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
struct run_context cpu_ctx;
88

9+
/* whether the host enter s3 success */
10+
uint8_t host_enter_s3_success = 1;
11+
912
void restore_msrs(void)
1013
{
1114
#ifdef STACK_PROTECTOR
@@ -71,12 +74,16 @@ int enter_s3(struct vm *vm, uint32_t pm1a_cnt_val,
7174
uint32_t pm1b_cnt_val)
7275
{
7376
uint32_t pcpu_id;
77+
int ret;
7478
uint64_t pmain_entry_saved;
7579
uint32_t guest_wakeup_vec32;
7680
uint64_t *pmain_entry;
7781

82+
/* We assume enter s3 success by default */
83+
host_enter_s3_success = 1;
7884
if (vm->pm.sx_state_data == NULL) {
7985
pr_err("No Sx state info avaiable. No Sx support");
86+
host_enter_s3_success = 0;
8087
return -1;
8188
}
8289

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ void vm_setup_cpu_state(struct vm *vm);
1111
int vm_load_pm_s_state(struct vm *vm);
1212
int validate_pstate(struct vm *vm, uint64_t perf_ctl);
1313
struct cpu_cx_data* get_target_cx(struct vm *vm, uint8_t cn);
14+
void register_pm1ab_handler(struct vm *vm);
1415

1516
#endif /* PM_H */

hypervisor/include/arch/x86/host_pm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55

66
#ifndef HOST_PM_H
77

8+
#define BIT_SLP_TYPx 10U
9+
#define BIT_SLP_EN 13U
810
#define BIT_WAK_STS 15U
911

12+
extern uint8_t host_enter_s3_success;
13+
1014
int enter_s3(struct vm *vm, uint32_t pm1a_cnt_val,
1115
uint32_t pm1b_cnt_val);
1216
extern void __enter_s3(struct vm *vm, uint32_t pm1a_cnt_val,

0 commit comments

Comments
 (0)