diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index 56412ea77..a80cd7a5c 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -270,6 +270,7 @@ static void vcpu_reset_internal(struct acrn_vcpu *vcpu, enum reset_mode mode) } init_iwkey(vcpu); + vcpu->arch.iwkey_copy_status = 0UL; } struct acrn_vcpu *get_running_vcpu(uint16_t pcpu_id) diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 8f61f10ef..89900da7c 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -468,6 +468,7 @@ int32_t create_vm(uint16_t vm_id, uint64_t pcpu_bitmap, struct acrn_vm_config *v spinlock_init(&vm->vlapic_mode_lock); spinlock_init(&vm->ept_lock); spinlock_init(&vm->emul_mmio_lock); + spinlock_init(&vm->arch_vm.iwkey_backup_lock); vm->arch_vm.vlapic_mode = VM_VLAPIC_XAPIC; vm->intr_inject_delay_delta = 0UL; @@ -717,6 +718,7 @@ int32_t reset_vm(struct acrn_vm *vm) reset_vioapics(vm); destroy_secure_world(vm, false); vm->sworld_control.flag.active = 0UL; + vm->arch_vm.iwkey_backup_status = 0UL; vm->state = VM_CREATED; return ret; diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index cf5d6dbc3..84e564e1a 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -61,6 +61,12 @@ static const uint32_t emulated_guest_msrs[NUM_GUEST_MSRS] = { MSR_IA32_XSS, + /* KeyLocker backup MSRs */ + MSR_IA32_COPY_LOCAL_TO_PLATFORM, + MSR_IA32_COPY_PLATFORM_TO_LOCAL, + MSR_IA32_COPY_STATUS, + MSR_IA32_IWKEY_BACKUP_STATUS, + MSR_TEST_CTL, }; @@ -402,6 +408,17 @@ static int32_t write_pat_msr(struct acrn_vcpu *vcpu, uint64_t value) return ret; } +/** + * @pre vcpu != NULL + */ +bool is_iwkey_backup_support(struct acrn_vcpu *vcpu) +{ + uint32_t eax = 0x19U, ebx = 0U, ecx = 0U, edx = 0U; + + guest_cpuid(vcpu, &eax, &ebx, &ecx, &edx); + return (ebx & CPUID_EBX_KL_BACKUP_MSR) == CPUID_EBX_KL_BACKUP_MSR; +} + /** * @pre vcpu != NULL */ @@ -516,6 +533,24 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu) } break; } + case MSR_IA32_COPY_STATUS: + { + if (is_iwkey_backup_support(vcpu)) { + v = vcpu->arch.iwkey_copy_status; + } else { + err = -EACCES; + } + break; + } + case MSR_IA32_IWKEY_BACKUP_STATUS: + { + if (is_iwkey_backup_support(vcpu)) { + v = vcpu->vm->arch_vm.iwkey_backup_status; + } else { + err = -EACCES; + } + break; + } case MSR_TEST_CTL: { /* If has MSR_TEST_CTL, give emulated value @@ -842,6 +877,40 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu) } break; } + case MSR_IA32_COPY_LOCAL_TO_PLATFORM: + { + if ((v == 0x1UL) && is_iwkey_backup_support(vcpu)) { + vcpu->vm->arch_vm.iwkey_backup_status = 0UL; + spinlock_obtain(&vcpu->vm->arch_vm.iwkey_backup_lock); + vcpu->vm->arch_vm.iwkey_backup = vcpu->arch.IWKey; + spinlock_release(&vcpu->vm->arch_vm.iwkey_backup_lock); + /* + * Keylocker spec 0.76 Table 4-1: + * 'Backup/restore valid' bit and 'IWKeyBackup consumed' bit + */ + vcpu->vm->arch_vm.iwkey_backup_status = 0x9UL; + vcpu->arch.iwkey_copy_status = 1UL; + } else { + err = -EINVAL; + } + break; + } + case MSR_IA32_COPY_PLATFORM_TO_LOCAL: + { + if ((v == 0x1UL) && is_iwkey_backup_support(vcpu) && + (vcpu->vm->arch_vm.iwkey_backup_status == 0x9UL)) { + spinlock_obtain(&vcpu->vm->arch_vm.iwkey_backup_lock); + vcpu->arch.IWKey = vcpu->vm->arch_vm.iwkey_backup; + spinlock_release(&vcpu->vm->arch_vm.iwkey_backup_lock); + /* Load the new iwkey for this vcpu */ + get_cpu_var(whose_iwkey) = NULL; + load_iwkey(vcpu); + vcpu->arch.iwkey_copy_status = 1UL; + } else { + err = -EINVAL; + } + break; + } case MSR_TEST_CTL: { /* If VM has MSR_TEST_CTL, ignore write operation diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index 40108b8ff..6ee965672 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -171,7 +171,7 @@ enum reset_mode; #define SECURE_WORLD 1 #define NUM_WORLD_MSRS 2U -#define NUM_COMMON_MSRS 17U +#define NUM_COMMON_MSRS 21U #define NUM_GUEST_MSRS (NUM_WORLD_MSRS + NUM_COMMON_MSRS) #define EOI_EXIT_BITMAP_SIZE 256U @@ -270,6 +270,12 @@ struct acrn_vcpu_arch { /* Keylocker */ struct iwkey IWKey; bool cr4_kl_enabled; + /* + * Keylocker spec 4.4: + * Bit 0 - Status of most recent copy to or from IWKeyBackup. + * Bit 63:1 - Reserved. + */ + uint64_t iwkey_copy_status; } __aligned(PAGE_SIZE); struct acrn_vm; diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 9994295dd..bd677ffcd 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -116,6 +116,18 @@ struct vm_arch { #endif enum vm_vlapic_mode vlapic_mode; /* Represents vLAPIC mode across vCPUs*/ + /* + * Keylocker spec 4.5: + * Bit 0 - Backup/restore valid. + * Bit 1 - Reserved. + * Bit 2 - Backup key storage read/write error. + * Bit 3 - IWKeyBackup consumed. + * Bit 63:4 - Reserved. + */ + uint64_t iwkey_backup_status; + spinlock_t iwkey_backup_lock; /* Spin-lock used to protect internal key backup/restore */ + struct iwkey iwkey_backup; + /* reference to virtual platform to come here (as needed) */ } __aligned(PAGE_SIZE); diff --git a/hypervisor/include/arch/x86/msr.h b/hypervisor/include/arch/x86/msr.h index e30184da7..4ed2185a0 100644 --- a/hypervisor/include/arch/x86/msr.h +++ b/hypervisor/include/arch/x86/msr.h @@ -353,6 +353,10 @@ #define MSR_IA32_L2_MASK_BASE 0x00000D10U #define MSR_IA32_MBA_MASK_BASE 0x00000D50U #define MSR_IA32_BNDCFGS 0x00000D90U +#define MSR_IA32_COPY_LOCAL_TO_PLATFORM 0x00000D91U +#define MSR_IA32_COPY_PLATFORM_TO_LOCAL 0x00000D92U +#define MSR_IA32_COPY_STATUS 0x00000990U +#define MSR_IA32_IWKEY_BACKUP_STATUS 0x00000991U #define MSR_IA32_EFER 0xC0000080U #define MSR_IA32_STAR 0xC0000081U #define MSR_IA32_LSTAR 0xC0000082U