diff --git a/Makefile b/Makefile index 0b4ab1030..cb485f34f 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,7 @@ C_SRCS += arch/x86/guest/vpic.c C_SRCS += arch/x86/guest/vmsr.c C_SRCS += arch/x86/guest/vioapic.c C_SRCS += arch/x86/guest/instr_emul.c +C_SRCS += arch/x86/guest/ucode.c C_SRCS += lib/spinlock.c C_SRCS += lib/udelay.c C_SRCS += lib/strnlen.c diff --git a/arch/x86/guest/instr_emul_wrapper.h b/arch/x86/guest/instr_emul_wrapper.h index 3581e9bd7..48e311f0f 100644 --- a/arch/x86/guest/instr_emul_wrapper.h +++ b/arch/x86/guest/instr_emul_wrapper.h @@ -200,4 +200,3 @@ int vm_get_seg_desc(struct vcpu *vcpu, int reg, int vm_set_seg_desc(struct vcpu *vcpu, int reg, struct seg_desc *desc); int vm_restart_instruction(struct vcpu *vcpu); -void vm_gva2gpa(struct vcpu *vcpu, uint64_t gla, uint64_t *gpa); diff --git a/arch/x86/guest/ucode.c b/arch/x86/guest/ucode.c new file mode 100644 index 000000000..b8b86e3de --- /dev/null +++ b/arch/x86/guest/ucode.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +uint64_t get_microcode_version(void) +{ + uint64_t val; + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; + + msr_write(MSR_IA32_BIOS_SIGN_ID, 0); + native_cpuid_count(CPUID_FEATURES, 0, &eax, &ebx, &ecx, &edx); + val = msr_read(MSR_IA32_BIOS_SIGN_ID); + + return val; +} + +/* + * According to SDM vol 3 Table 9-7. If data_size field of uCode + * header is zero, the ucode length is 2000 + */ +#define GET_DATA_SIZE(hdptr) ((hdptr)->data_size ? : 2000) +void acrn_update_ucode(struct vcpu *vcpu, uint64_t v) +{ + uint64_t hva, gpa, gva; + struct ucode_header *uhdr; + int data_size, data_page_num; + uint8_t *ucode_ptr, *ptr; + int chunk_size; + + gva = v - sizeof(struct ucode_header); + + vm_gva2gpa(vcpu, gva, &gpa); + uhdr = (struct ucode_header *)GPA2HVA(vcpu->vm, gpa); + + data_size = GET_DATA_SIZE(uhdr) + sizeof(struct ucode_header); + data_page_num = + (data_size + CPU_PAGE_SIZE - 1) >> CPU_PAGE_SHIFT; + + ptr = ucode_ptr = alloc_pages(data_page_num); + if (ptr == NULL) + return; + + hva = (uint64_t)uhdr; + while (true) { + chunk_size = CPU_PAGE_SIZE - (hva & (CPU_PAGE_SIZE - 1)); + chunk_size = (chunk_size < data_size) ? chunk_size : data_size; + + memcpy_s(ucode_ptr, chunk_size, (uint8_t *)hva, chunk_size); + + data_size -= chunk_size; + if (data_size <= 0) + break; + + ucode_ptr += chunk_size; + gva += chunk_size; + + vm_gva2gpa(vcpu, gva, &gpa); + hva = (uint64_t)GPA2HVA(vcpu->vm, gpa); + } + + msr_write(MSR_IA32_BIOS_UPDT_TRIG, + (uint64_t)ptr + sizeof(struct ucode_header)); + get_microcode_version(); + + free(ucode_ptr); +} diff --git a/arch/x86/guest/vmsr.c b/arch/x86/guest/vmsr.c index edc456ccd..eb5ab6c3a 100644 --- a/arch/x86/guest/vmsr.c +++ b/arch/x86/guest/vmsr.c @@ -32,10 +32,14 @@ #include #include #include +#include /*MRS need to be emulated, the order in this array better as freq of ops*/ static const uint32_t emulated_msrs[] = { MSR_IA32_TSC_DEADLINE, /* Enable TSC_DEADLINE VMEXIT */ + MSR_IA32_BIOS_UPDT_TRIG, /* Enable MSR_IA32_BIOS_UPDT_TRIG */ + MSR_IA32_BIOS_SIGN_ID, /* Enable MSR_IA32_BIOS_SIGN_ID */ + /* following MSR not emulated now */ /* @@ -51,6 +55,8 @@ static const uint32_t emulated_msrs[] = { /* the index is matched with emulated msrs array*/ enum { IDX_TSC_DEADLINE, + IDX_BIOS_UPDT_TRIG, + IDX_BIOS_SIGN_ID, IDX_MAX_MSR }; @@ -185,6 +191,11 @@ int rdmsr_handler(struct vcpu *vcpu) vcpu_inject_gp(vcpu); break; } + case MSR_IA32_BIOS_SIGN_ID: + { + v = get_microcode_version(); + break; + } /* following MSR not emulated now just left for future */ case MSR_IA32_SYSENTER_CS: @@ -273,6 +284,17 @@ int wrmsr_handler(struct vcpu *vcpu) vcpu_inject_gp(vcpu); break; } + case MSR_IA32_BIOS_SIGN_ID: + { + break; + } + case MSR_IA32_BIOS_UPDT_TRIG: + { + /* We only allow SOS to do uCode update */ + if (is_vm0(vcpu->vm)) + acrn_update_ucode(vcpu, v); + break; + } /* following MSR not emulated now just left for future */ case MSR_IA32_SYSENTER_CS: diff --git a/include/arch/x86/guest/guest.h b/include/arch/x86/guest/guest.h index 20877a435..4a2d424a5 100644 --- a/include/arch/x86/guest/guest.h +++ b/include/arch/x86/guest/guest.h @@ -84,6 +84,7 @@ bool vm_lapic_disabled(struct vm *vm); uint64_t vcpumask2pcpumask(struct vm *vm, uint64_t vdmask); uint64_t gva2gpa(struct vm *vm, uint64_t cr3, uint64_t gva); +void vm_gva2gpa(struct vcpu *vcpu, uint64_t gla, uint64_t *gpa); struct vcpu *get_primary_vcpu(struct vm *vm); struct vcpu *vcpu_from_vid(struct vm *vm, int vcpu_id); diff --git a/include/arch/x86/guest/ucode.h b/include/arch/x86/guest/ucode.h new file mode 100644 index 000000000..a49c43ba6 --- /dev/null +++ b/include/arch/x86/guest/ucode.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ARCH_X86_UCODE_H +#define _ARCH_X86_UCODE_H + +struct ucode_header { + uint32_t header_ver; + uint32_t update_ver; + uint32_t date; + uint32_t proc_sig; + uint32_t checksum; + uint32_t loader_ver; + uint32_t proc_flags; + uint32_t data_size; + uint32_t total_size; + uint32_t reserved[3]; +}; + +void acrn_update_ucode(struct vcpu *vcpu, uint64_t v); +uint64_t get_microcode_version(void); + +#endif