Skip to content

Commit

Permalink
introduce vmexit_handler::terminate() method
Browse files Browse the repository at this point in the history
Previously, vmexit_handler::teardown() initiated the termination of VMX operation (e.g. by vmcall, which subsequently executed VMXOFF).
Now this process is moved into vmexit_handler::terminate() method (in layman's terms, "teardown" method has been renamed to "terminate").

The vmexit_handler::teardown() method hasn't been removed, though. From now, it is used as a complementary method to vmexit_handler::setup().
  • Loading branch information
wbenny committed Oct 31, 2019
1 parent a2e52fb commit f1eece7
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 57 deletions.
5 changes: 3 additions & 2 deletions src/hvpp/hvpp/hvpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ NTAPI
HvppStart(
_In_ PVMEXIT_HANDLER VmExitHandler,
_In_ PVMEXIT_HANDLER_SETUP_ROUTINE SetupRoutine,
_In_ PVMEXIT_HANDLER_TEARDOWN_ROUTINE TeardownRoutine
_In_ PVMEXIT_HANDLER_TEARDOWN_ROUTINE TeardownRoutine,
_In_ PVMEXIT_HANDLER_TERMINATE_ROUTINE TerminateRoutine
)
{
//
Expand All @@ -319,7 +320,7 @@ HvppStart(
//

hvpp_assert(c_exit_handler == nullptr);
c_exit_handler = new vmexit_c_wrapper_handler(c_handlers, SetupRoutine, TeardownRoutine, NULL);
c_exit_handler = new vmexit_c_wrapper_handler(c_handlers, SetupRoutine, TeardownRoutine, TerminateRoutine, NULL);

//
// Start the hypervisor.
Expand Down
19 changes: 18 additions & 1 deletion src/hvpp/hvpp/hvpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,17 @@ typedef VOID (NTAPI* PVMEXIT_PASSTHROUGH_TEARDOWN_ROUTINE)(
#define HvppPassthroughTeardown(Passthrough) \
(((PVMEXIT_PASSTHROUGH_TEARDOWN_ROUTINE)(((PVMEXIT_PASSTHROUGH)(Passthrough))->PassthroughRoutine))(Passthrough));

//
// Terminate.
//

typedef VOID (NTAPI* PVMEXIT_PASSTHROUGH_TERMINATE_ROUTINE)(
_In_ PVOID PassthroughContext
);

#define HvppPassthroughTerminate(Passthrough) \
(((PVMEXIT_PASSTHROUGH_TERMINATE_ROUTINE)(((PVMEXIT_PASSTHROUGH)(Passthrough))->PassthroughRoutine))(Passthrough));

//
// Handler.
//
Expand Down Expand Up @@ -889,6 +900,11 @@ typedef VOID (NTAPI* PVMEXIT_HANDLER_TEARDOWN_ROUTINE)(
_In_ PVOID Passthrough
);

typedef VOID (NTAPI* PVMEXIT_HANDLER_TERMINATE_ROUTINE)(
_In_ PVCPU Vcpu,
_In_ PVOID Passthrough
);

typedef struct _VMEXIT_HANDLER
{
PVMEXIT_HANDLER_ROUTINE HandlerRoutine[VMEXIT_REASON_MAX];
Expand Down Expand Up @@ -1290,7 +1306,8 @@ NTAPI
HvppStart(
_In_ PVMEXIT_HANDLER VmExitHandler,
_In_ PVMEXIT_HANDLER_SETUP_ROUTINE SetupRoutine,
_In_ PVMEXIT_HANDLER_TEARDOWN_ROUTINE TeardownRoutine
_In_ PVMEXIT_HANDLER_TEARDOWN_ROUTINE TeardownRoutine,
_In_ PVMEXIT_HANDLER_TERMINATE_ROUTINE TerminateRoutine
);

VOID
Expand Down
7 changes: 6 additions & 1 deletion src/hvpp/hvpp/vcpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ void vcpu_t::stop() noexcept
// handler to call vcpu_t::vmx_leave(); e.g. VMCALL with specific
// index.
//
handler_.teardown(*this);
handler_.terminate(*this);
}

auto vcpu_t::vmx_enter() noexcept -> error_code_t
Expand Down Expand Up @@ -337,6 +337,11 @@ void vcpu_t::vmx_leave() noexcept
// Signalize that this VCPU has terminated.
//
state_ = state::terminated;

//
// Finally, call teardown method.
//
handler_.teardown(*this);
}

void vcpu_t::ept_enable() noexcept
Expand Down
5 changes: 5 additions & 0 deletions src/hvpp/hvpp/vmexit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ void vmexit_handler::teardown(vcpu_t& vp) noexcept
(void)(vp);
}

void vmexit_handler::terminate(vcpu_t& vp) noexcept
{
(void)(vp);
}

void vmexit_handler::handle(vcpu_t& vp) noexcept
{
const auto handler_index = static_cast<int>(vp.exit_reason());
Expand Down
52 changes: 38 additions & 14 deletions src/hvpp/hvpp/vmexit.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ class vmexit_handler
// Constructor & destructor.
//
// Note:
// Constructor & destructor is guaranteed to NOT be called
// in VMX-root mode.
// Constructor & destructor is called in VMX-non-root mode.
// Therefore, avoid execution of any VMX instructions there.
//
vmexit_handler() noexcept;
Expand All @@ -136,29 +135,47 @@ class vmexit_handler
vmexit_handler& operator=(vmexit_handler&& other) noexcept = delete;

//
// This method allows you to set up VCPU state before VMLAUNCH.
// Use this method for setting up VMCS.
// This method is responsible for setup of VCPU state & VMCS and
// allocation of resources for the VM-exit handler.
//
// It is called after VMXON but before VMLAUNCH, from the
// vcpu_t::vmx_enter() method.
//
// Note:
// This method is guaranteed to be called in VMX-root mode.
// This method is called in VMX-root mode.
//
virtual auto setup(vcpu_t& vp) noexcept -> error_code_t;

//
// This method is called from vcpu_t::stop() method.
// It should be responsible for initiating VM tear-down
// and disabling the VMX mode.
// This method is responsible for freeing resources acquired in
// the setup() method.
//
// Note:
// This method is guaranteed to NOT be called in VMX-root mode.
// Therefore, avoid execution of any VMX instructions there
// (including VMXOFF).
// It is called after VMXOFF, from the vcpu_t::vmx_leave() method.
//
// If you wish to execute code in VMX-root mode when this method
// is called, use "vmcall".
// Note:
// This method is called in VMX-non-root mode.
//
virtual void teardown(vcpu_t& vp) noexcept;

//
// This method is responsible for initiating termination of the
// VMX operation (i.e. leaving the virtualization mode).
//
// Note:
// It must NOT execute the VMXOFF instruction directly, because
// it is NOT called from VMX-root mode - instead, it should
// perform such operation that causes distinguishable VM-exit,
// which in turn executes the VMXOFF instruction.
//
// Example might be performing VMCALL with RCX set to special
// value that handle_execute_vmcall() recognizes, and calls
// vp.vmx_leave().
//
// See implementation of vmexit_passthrough_handler::terminate()
// and vmexit_passthrough_handler::handle_execute_vmcall().
//
virtual void terminate(vcpu_t& vp) noexcept;

//
// This method is called on every VM-exit.
// By default this method delegates the execution control
Expand Down Expand Up @@ -299,6 +316,13 @@ class vmexit_compositor_handler
});
}

void terminate(vcpu_t& vp) noexcept override
{
for_each_element(handlers, [&](auto&& handler, int) {
handler.terminate(vp);
});
}

void handle(vcpu_t& vp) noexcept override
{
for_each_element(handlers, [&](auto&& handler, int) {
Expand Down
70 changes: 56 additions & 14 deletions src/hvpp/hvpp/vmexit/vmexit_c_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@

namespace hvpp {

vmexit_c_wrapper_handler::vmexit_c_wrapper_handler(const c_handler_array_t& c_handlers, c_handler_setup_fn_t setup_callback, c_handler_teardown_fn_t teardown_callback, void* context /*= nullptr */) noexcept
vmexit_c_wrapper_handler::vmexit_c_wrapper_handler(
const c_handler_array_t& c_handlers,
c_handler_setup_fn_t setup_callback,
c_handler_teardown_fn_t teardown_callback,
c_handler_terminate_fn_t terminate_callback,
void* context /*= nullptr */
) noexcept
{
//
// Make local copy of the C-handlers.
Expand All @@ -13,6 +19,7 @@ vmexit_c_wrapper_handler::vmexit_c_wrapper_handler(const c_handler_array_t& c_ha
c_handlers_ = c_handlers;
setup_callback_ = setup_callback;
teardown_callback_ = teardown_callback;
terminate_callback_ = terminate_callback;
context_ = context;
}

Expand All @@ -29,11 +36,11 @@ auto vmexit_c_wrapper_handler::setup(vcpu_t& vp) noexcept -> error_code_t
// C-handler has been defined - call that routine.
//

auto context = passthrough_setup_context{
auto context = passthrough_context{
.passthrough_routine = passthrough_fn_t(&vmexit_c_wrapper_handler::handle_passthrough_setup),
.context = context_,
.handler_instance = this,
.handler_method = &base_type::setup,
.handler_method = nullptr,
.vcpu = &vp,
};

Expand All @@ -57,11 +64,11 @@ void vmexit_c_wrapper_handler::teardown(vcpu_t& vp) noexcept
// C-handler has been defined - call that routine.
//

auto context = passthrough_teardown_context{
auto context = passthrough_context{
.passthrough_routine = passthrough_fn_t(&vmexit_c_wrapper_handler::handle_passthrough_teardown),
.context = context_,
.handler_instance = this,
.handler_method = &vmexit_c_wrapper_handler::teardown,
.handler_method = nullptr,
.vcpu = &vp,
};

Expand All @@ -73,10 +80,39 @@ void vmexit_c_wrapper_handler::teardown(vcpu_t& vp) noexcept
// C-handler has not been defined - call the pass-through handler.
//

teardown(vp);
base_type::teardown(vp);
}
}

void vmexit_c_wrapper_handler::terminate(vcpu_t& vp) noexcept
{
if (terminate_callback_)
{
//
// C-handler has been defined - call that routine.
//

auto context = passthrough_context{
.passthrough_routine = passthrough_fn_t(&vmexit_c_wrapper_handler::handle_passthrough_terminate),
.context = context_,
.handler_instance = this,
.handler_method = nullptr,
.vcpu = &vp,
};

terminate_callback_(&vp, &context);
}
else
{
//
// C-handler has not been defined - call the pass-through handler.
//

base_type::terminate(vp);
}
}


void vmexit_c_wrapper_handler::handle(vcpu_t& vp) noexcept
{
const auto exit_reason = vp.exit_reason();
Expand All @@ -91,7 +127,7 @@ void vmexit_c_wrapper_handler::handle(vcpu_t& vp) noexcept
// C-handler has been defined - call that routine.
//

auto context = passthrough_handler_context{
auto context = passthrough_context{
.passthrough_routine = passthrough_fn_t(&vmexit_c_wrapper_handler::handle_passthrough_handler),
.context = context_,
.handler_instance = this,
Expand All @@ -111,25 +147,31 @@ void vmexit_c_wrapper_handler::handle(vcpu_t& vp) noexcept
}
}

auto vmexit_c_wrapper_handler::handle_passthrough_setup(passthrough_setup_context* context) noexcept -> error_code_t
auto vmexit_c_wrapper_handler::handle_passthrough_setup(passthrough_context* context) noexcept -> error_code_t
{
const auto handler_instance = context->handler_instance;
const auto handler_method = context->handler_method;
auto& vp = *context->vcpu;

return (handler_instance->*handler_method)(vp);
return handler_instance->base_type::setup(vp);
}

void vmexit_c_wrapper_handler::handle_passthrough_teardown(passthrough_teardown_context* context) noexcept
void vmexit_c_wrapper_handler::handle_passthrough_teardown(passthrough_context* context) noexcept
{
const auto handler_instance = context->handler_instance;
const auto handler_method = context->handler_method;
auto& vp = *context->vcpu;

(handler_instance->*handler_method)(vp);
handler_instance->base_type::teardown(vp);
}

void vmexit_c_wrapper_handler::handle_passthrough_terminate(passthrough_context* context) noexcept
{
const auto handler_instance = context->handler_instance;
auto& vp = *context->vcpu;

handler_instance->base_type::terminate(vp);
}

void vmexit_c_wrapper_handler::handle_passthrough_handler(passthrough_handler_context* context) noexcept
void vmexit_c_wrapper_handler::handle_passthrough_handler(passthrough_context* context) noexcept
{
//
// Fetch the handler instance, method and vcpu_t reference
Expand Down
37 changes: 20 additions & 17 deletions src/hvpp/hvpp/vmexit/vmexit_c_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,46 +26,49 @@ class vmexit_c_wrapper_handler
void* /* passthrough_context* */
);

using c_handler_terminate_fn_t = void(*)(
void* /* vcpu_t* */,
void* /* passthrough_context* */
);

using c_handler_array_t = std::array<c_handler_fn_t, 65>;

vmexit_c_wrapper_handler(const c_handler_array_t& c_handlers, c_handler_setup_fn_t setup_callback = nullptr, c_handler_teardown_fn_t teardown_callback = nullptr, void* context = nullptr) noexcept;
vmexit_c_wrapper_handler(
const c_handler_array_t& c_handlers,
c_handler_setup_fn_t setup_callback = nullptr,
c_handler_teardown_fn_t teardown_callback = nullptr,
c_handler_terminate_fn_t terminate_callback = nullptr,
void* context = nullptr
) noexcept;
~vmexit_c_wrapper_handler() noexcept override;

auto setup(vcpu_t& vp) noexcept -> error_code_t override;
void teardown(vcpu_t& vp) noexcept override;
void terminate(vcpu_t& vp) noexcept override;

void handle(vcpu_t& vp) noexcept override;

private:
using passthrough_fn_t = void(*)(void*);

template <
typename THandlerMethod
>
struct context_base
struct passthrough_context
{
passthrough_fn_t passthrough_routine;
void* context;
vmexit_c_wrapper_handler* handler_instance;
THandlerMethod handler_method;
handler_fn_t handler_method;
vcpu_t* vcpu;
};

using handler_method_t = handler_fn_t;
using setup_method_t = error_code_t(base_type::*)(vcpu_t&);
using teardown_method_t = void (vmexit_c_wrapper_handler::*)(vcpu_t&);

using passthrough_handler_context = context_base<handler_method_t>;
using passthrough_setup_context = context_base<setup_method_t>;
using passthrough_teardown_context = context_base<teardown_method_t>;

static auto handle_passthrough_setup(passthrough_setup_context* context) noexcept -> error_code_t;
static void handle_passthrough_teardown(passthrough_teardown_context* context) noexcept;
static void handle_passthrough_handler(passthrough_handler_context* context) noexcept;
static auto handle_passthrough_setup(passthrough_context* context) noexcept -> error_code_t;
static void handle_passthrough_teardown(passthrough_context* context) noexcept;
static void handle_passthrough_terminate(passthrough_context* context) noexcept;
static void handle_passthrough_handler(passthrough_context* context) noexcept;

c_handler_array_t c_handlers_;
c_handler_setup_fn_t setup_callback_;
c_handler_teardown_fn_t teardown_callback_;
c_handler_terminate_fn_t terminate_callback_;
void* context_;
};

Expand Down
5 changes: 5 additions & 0 deletions src/hvpp/hvpp/vmexit/vmexit_passthrough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ auto vmexit_passthrough_handler::setup(vcpu_t& vp) noexcept -> error_code_t
}

void vmexit_passthrough_handler::teardown(vcpu_t& vp) noexcept
{
(void)(vp);
}

void vmexit_passthrough_handler::terminate(vcpu_t& vp) noexcept
{
(void)(vp);

Expand Down
Loading

0 comments on commit f1eece7

Please sign in to comment.