Created
September 19, 2018 02:27
-
-
Save drew-gpf/7c2d4c0f03aa3c06ed9c94ec435355c1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
purpose: update the control register value and read shadow based off of the host mask, and determine if an invalid bit was set | |
new_value: the new value of the control register that the guest wants to set | |
host_mask_must_be_set: host bits which the guest should not change | |
host_mask_dont_care: host bits which can be any value, but only change for the read shadow (generally should be set to the bits required by the cpu) | |
host_mask_trap: host bits which are updated in the actual control register and are trapped on | |
read_shadow_encoding: VMCS field for the read shadow | |
control_register_encoding: VMCS field for the control register | |
different_bits_buffer (optional): pointer to variable which will be filled out with all the bits which were changed | |
return value: returns false if a #GP(0) should be injected into the guest | |
*/ | |
static bool handle_cr_change(uint64_t new_value, uint64_t host_mask_must_be_set, uint64_t host_mask_dont_care, uint64_t host_mask_trap, uint64_t read_shadow_encoding, uint64_t control_register_encoding, uint64_t *different_bits_buffer) | |
{ | |
//calculate different bits based off of what the guest sees when it performs a cr read | |
//bits not inside the host mask come from the actual value; bits which are in the host mask come from the read shadow | |
const uint64_t control_register = vmx_vmread(control_register_encoding); | |
const uint64_t read_shadow = vmx_vmread(read_shadow_encoding); | |
const uint64_t full_host_mask = host_mask_must_be_set | host_mask_dont_care | host_mask_trap; | |
const uint64_t different_bits = ((control_register & ~full_host_mask) | (read_shadow & full_host_mask)) ^ new_value; | |
if (different_bits_buffer) | |
*different_bits_buffer = different_bits; | |
//if a different bit is one which can't be changed, inject a gp | |
if (different_bits & host_mask_must_be_set) | |
return false; | |
//update read shadow bits | |
{ | |
//the 'dont care' bits only update the read shadow; trap bits still need to be updated since they're read from the read shadow | |
const uint64_t updateable_bits = host_mask_dont_care | host_mask_trap; | |
const uint64_t different_updateable_bits = different_bits & updateable_bits; | |
const uint64_t different_updated_bits = new_value & updateable_bits; | |
uint64_t read_shadow_buffer = read_shadow; | |
//remove updateable bits which are different | |
read_shadow_buffer &= ~different_updateable_bits; | |
//add in bits which have changed and can be updated | |
read_shadow_buffer |= different_updated_bits; | |
vmx_vmwrite(read_shadow_encoding, read_shadow_buffer); | |
} | |
//update the actual register, ignoring bits from the mask which must be set or the mask which only modifies the read shadow | |
{ | |
const uint64_t updateable_bits = ~(host_mask_must_be_set | host_mask_dont_care); | |
const uint64_t different_updateable_bits = different_bits & updateable_bits; | |
const uint64_t different_updated_bits = new_value & updateable_bits; | |
uint64_t control_register_buffer = control_register; | |
//remove updateable bits which are different | |
control_register_buffer &= ~different_updateable_bits; | |
//add in bits which have changed and can be updated | |
control_register_buffer |= different_updated_bits; | |
vmx_vmwrite(control_register_encoding, control_register_buffer); | |
} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment