dm: add S3 support for UOS

We do:
 - pause target vm
 - suspend all virtual devices
 - wait for resume notification
 - resume all virtual devices
 - reset target vm

Signed-off-by: Yin Fengwei <fengwei.yin@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Yin Fengwei 2018-05-21 16:49:57 +08:00 committed by lijinxia
parent 8ee4c0b1dd
commit a8a27d82d0
4 changed files with 71 additions and 2 deletions

View File

@ -256,6 +256,11 @@ pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
error = vm_suspend(ctx, VM_SUSPEND_POWEROFF);
assert(error == 0 || errno == EALREADY);
}
if ((pm1_control & PM1_SLP_TYP) >> 10 == 3) {
error = vm_suspend(ctx, VM_SUSPEND_SUSPEND);
assert(error == 0 || errno == EALREADY);
}
}
}
return 0;

View File

@ -59,6 +59,7 @@
#include "sw_load.h"
#include "monitor.h"
#include "ioc.h"
#include "pm.h"
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
@ -447,6 +448,22 @@ handle_vmexit(struct vmctx *ctx, struct vhm_request *vhm_req, int vcpu)
default:
exit(1);
}
/* If UOS is not in suspend or system reset mode, we don't
* need to notify request done.
*
* But there is little difference between reset and suspend:
* - We don't need to notify request done for reset because reset
* doesn't care it.
* - We don't need to notify request done for suspend because
* guest will offline all APs, write PM register to trigger
* PM. Then the PM register writting will trigger the latest
* vmexit and it doesn't care request done either.
*/
if ((VM_SUSPEND_SYSTEM_RESET == vm_get_suspend_mode()) ||
(VM_SUSPEND_SUSPEND == vm_get_suspend_mode()))
return;
vm_notify_request_done(ctx, vcpu);
}
@ -576,6 +593,39 @@ vm_system_reset(struct vmctx *ctx)
vm_set_suspend_mode(VM_SUSPEND_NONE);
}
static void
vm_suspend_resume(struct vmctx *ctx)
{
int vcpu_id = 0;
/*
* If we get warm reboot request, we don't want to exit the
* vcpu_loop/vm_loop/mevent_loop. So we do:
* 1. pause VM
* 2. notify request done to reset ioreq state in vhm
* 3. stop vm watchdog
* 4. wait for resume signal
* 5. reset vm watchdog
* 6. hypercall restart vm
*/
vm_pause(ctx);
for (vcpu_id = 0; vcpu_id < 4; vcpu_id++) {
struct vhm_request *vhm_req;
vhm_req = &vhm_req_buf[vcpu_id];
if (vhm_req->valid &&
(vhm_req->processed == REQ_STATE_PROCESSING) &&
(vhm_req->client == ctx->ioreq_client))
vm_notify_request_done(ctx, vcpu_id);
}
vm_stop_watchdog(ctx);
wait_for_resume(ctx);
vm_reset_watchdog(ctx);
vm_reset(ctx);
}
static void
vm_loop(struct vmctx *ctx)
{
@ -606,6 +656,10 @@ vm_loop(struct vmctx *ctx)
if (VM_SUSPEND_SYSTEM_RESET == vm_get_suspend_mode()) {
vm_system_reset(ctx);
}
if (VM_SUSPEND_SUSPEND == vm_get_suspend_mode()) {
vm_suspend_resume(ctx);
}
}
quit_vm_loop = 0;
printf("VM loop exit\n");

View File

@ -316,6 +316,8 @@ mevent_dispatch(void)
assert(pipev != NULL);
for (;;) {
int suspend_mode;
/*
* Block awaiting events
*/
@ -328,8 +330,11 @@ mevent_dispatch(void)
*/
mevent_handle(eventlist, ret);
if ((vm_get_suspend_mode() != VM_SUSPEND_NONE) &&
(vm_get_suspend_mode() != VM_SUSPEND_SYSTEM_RESET))
suspend_mode = vm_get_suspend_mode();
if ((suspend_mode != VM_SUSPEND_NONE) &&
(suspend_mode != VM_SUSPEND_SYSTEM_RESET) &&
(suspend_mode != VM_SUSPEND_SUSPEND))
break;
}
}

View File

@ -744,6 +744,11 @@ basl_fwrite_dsdt(FILE *fp, struct vmctx *ctx)
dsdt_line("DefinitionBlock (\"dm_dsdt.aml\", \"DSDT\", 2,"
"\"DM \", \"DMDSDT \", 0x00000001)");
dsdt_line("{");
dsdt_line(" Name (_S3, Package ()");
dsdt_line(" {");
dsdt_line(" 0x03,");
dsdt_line(" Zero,");
dsdt_line(" })");
dsdt_line(" Name (_S5, Package ()");
dsdt_line(" {");
dsdt_line(" 0x05,");