1 /*
2  * Copyright (C) 2018-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <types.h>
8 #include <errno.h>
9 #include <asm/lib/spinlock.h>
10 #include <asm/cpu.h>
11 #include <asm/msr.h>
12 #include <asm/cpuid.h>
13 #include <asm/guest/ucode.h>
14 #include <asm/guest/guest_memory.h>
15 #include <asm/guest/virq.h>
16 #include <logmsg.h>
17 
18 #define MICRO_CODE_SIZE_MAX    0x40000U
19 static uint8_t micro_code[MICRO_CODE_SIZE_MAX];
20 
get_microcode_version(void)21 uint64_t get_microcode_version(void)
22 {
23 	uint64_t val;
24 	uint32_t eax, ebx, ecx, edx;
25 
26 	msr_write(MSR_IA32_BIOS_SIGN_ID, 0U);
27 	cpuid_subleaf(CPUID_FEATURES, 0x0U, &eax, &ebx, &ecx, &edx);
28 	val = msr_read(MSR_IA32_BIOS_SIGN_ID);
29 
30 	return val;
31 }
32 
33 /*
34  * According to SDM vol 3 Table 9-7. If data_size field of uCode
35  * header is zero, the ucode length is 2000
36  */
get_ucode_data_size(const struct ucode_header * uhdr)37 static inline size_t get_ucode_data_size(const struct ucode_header *uhdr)
38 {
39 	return ((uhdr->data_size != 0U) ? uhdr->data_size : 2000U);
40 }
41 
42 /* the guest operating system should guarantee it won't issue 2nd micro code update
43  * when the 1st micro code update is on-going.
44  */
acrn_update_ucode(struct acrn_vcpu * vcpu,uint64_t v)45 void acrn_update_ucode(struct acrn_vcpu *vcpu, uint64_t v)
46 {
47 	uint64_t gva, fault_addr = 0UL;
48 	struct ucode_header uhdr;
49 	size_t data_size;
50 	int32_t err;
51 	uint32_t err_code;
52 
53 	gva = v - sizeof(struct ucode_header);
54 
55 	err_code = 0U;
56 	err = copy_from_gva(vcpu, &uhdr, gva, sizeof(uhdr), &err_code,
57 			&fault_addr);
58 	if (err < 0) {
59 		if (err == -EFAULT) {
60 			vcpu_inject_pf(vcpu, fault_addr, err_code);
61 		}
62 	} else {
63 		data_size = get_ucode_data_size(&uhdr) + sizeof(struct ucode_header);
64 		if (data_size > MICRO_CODE_SIZE_MAX) {
65 			pr_err("The size of microcode is greater than 0x%x",
66 					MICRO_CODE_SIZE_MAX);
67 		} else {
68 			err_code = 0U;
69 			err = copy_from_gva(vcpu, micro_code, gva, data_size, &err_code,
70 					&fault_addr);
71 			if (err < 0) {
72 				if (err == -EFAULT) {
73 					vcpu_inject_pf(vcpu, fault_addr, err_code);
74 				}
75 			} else {
76 				msr_write(MSR_IA32_BIOS_UPDT_TRIG,
77 					(uint64_t)micro_code + sizeof(struct ucode_header));
78 				(void)get_microcode_version();
79 			}
80 		}
81 	}
82 }
83