xref: /haiku/src/system/kernel/arch/x86/64/errata.cpp (revision d2edfdd11dd22c213b65974b03c410b0c77c1d16)
1 /*
2  * Copyright 2019-2023, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Augustin Cavalier <waddlesplash>
7  */
8 
9 #include <cpu.h>
10 #include <arch_cpu.h>
11 
12 
13 static bool
14 needs_zenbleed_patch(const uint32 family, const uint32 model, const uint64 microcode)
15 {
16 	if (family != 0x17)
17 		return false;
18 
19 	// https://github.com/torvalds/linux/blob/522b1d6921/arch/x86/kernel/cpu/amd.c#L986
20 	if (model >= 0x30 && model <= 0x3f)
21 		return (microcode < 0x0830107a);
22 	if (model >= 0x60 && model <= 0x67)
23 		return (microcode < 0x0860010b);
24 	if (model >= 0x68 && model <= 0x6f)
25 		return (microcode < 0x08608105);
26 	if (model >= 0x70 && model <= 0x7f)
27 		return (microcode < 0x08701032);
28 	if (model >= 0xa0 && model <= 0xaf)
29 		return (microcode < 0x08a00008);
30 
31 	return false;
32 }
33 
34 
35 static status_t
36 patch_errata_percpu_amd(int currentCPU, const cpu_ent* cpu)
37 {
38 	// There are no errata to patch on a hypervisor, the host will have
39 	// already taken care of everything for us.
40 	if (x86_check_feature(IA32_FEATURE_EXT_HYPERVISOR, FEATURE_EXT))
41 		return B_OK;
42 
43 	const uint32 family = cpu->arch.family + cpu->arch.extended_family,
44 		model = (cpu->arch.extended_model << 4) | cpu->arch.model;
45 	const uint64 microcode = x86_read_msr(IA32_MSR_UCODE_REV);
46 
47 	// Family 10h and 12h, Erratum 721:
48 	//
49 	// "Under a highly specific and detailed set of internal timing conditions,
50 	// the processor may incorrectly update the stack pointer after a long
51 	// series of push and/or near-call instructions, or a long series of pop
52 	// and/or near-return instructions.
53 	//
54 	// https://www.amd.com/system/files/TechDocs/41322_10h_Rev_Gd.pdf
55 	// https://www.amd.com/system/files/TechDocs/44739_12h_Rev_Gd.pdf
56 	switch (family) {
57 	case 0x10:
58 	case 0x12:
59 		x86_write_msr(0xc0011029, x86_read_msr(0xc0011029) | 1);
60 		break;
61 	}
62 
63 	// Family 16h ("Jaguar"), Erratum 793:
64 	//
65 	// "Under a highly specific and detailed set of internal timing conditions,
66 	// a locked instruction may trigger a timing sequence whereby the write to
67 	// a write combined memory type is not flushed, causing the locked instruction
68 	// to stall indefinitely."
69 	//
70 	// https://www.amd.com/system/files/TechDocs/53072_Rev_Guide_16h_Models_30h-3Fh.pdf
71 	if (family == 0x16 && model <= 0xf) {
72 		x86_write_msr(0xc0011020, x86_read_msr(0xc0011020) | ((uint64)1 << 15));
73 	}
74 
75 	// Family 17h ("Zen") Model 1h
76 	// https://www.amd.com/system/files/TechDocs/55449_Fam_17h_M_00h-0Fh_Rev_Guide.pdf
77 	if (family == 0x17 && model == 0x1) {
78 		// Erratum 1021:
79 		//
80 		// "Under a highly specific and detailed set of internal timing
81 		// conditions, a load operation may incorrectly receive stale data
82 		// from an older store operation."
83 		x86_write_msr(0xc0011029, x86_read_msr(0xc0011029) | (1 << 13));
84 
85 		// Erratum 1033:
86 		//
87 		// "Under a highly specific and detailed set of internal timing
88 		// conditions, a Lock operation may cause the system to hang."
89 		x86_write_msr(0xc0011020, x86_read_msr(0xc0011020) | (1 << 4));
90 
91 		// Erratum 1049:
92 		//
93 		// "Under a highly specific and detailed set of internal timing
94 		// conditions, an FCMOV instruction may yield incorrect data if the
95 		// following sequence of events occurs:
96 		//  * An FCOMI instruction
97 		//  * A non-FP instruction that modifies RFLAGS
98 		//  * An FCMOV instruction."
99 		x86_write_msr(0xc0011028, x86_read_msr(0xc0011028) | (1 << 4));
100 
101 		// Erratum 1095:
102 		//
103 		// Under a highly detailed and specific set of internal timing
104 		// conditions, a lock operation may not fence a younger load operation
105 		// correctly when the following conditions are met:
106 		//  * SMT (Simultaneous Multithreading) is enabled, and
107 		//  * a lock operation on memory location A, followed by a load
108 		//    operation on memory location B are executing on one thread while
109 		//  * a lock operation on memory location B, followed by a load operation
110 		//    on memory location A are executing on the second thread on the
111 		//    same core.
112 		// This may result in the load operations on both threads incorrectly
113 		// receiving pre-lock data."
114 		x86_write_msr(0xc0011020, x86_read_msr(0xc0011020) | ((uint64)1 << 57));
115 	}
116 
117 	// Family 17h ("Zen")
118 	// Cross-Process Information Leak (aka. "Zenbleed")
119 	// https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7008.html
120 	if (needs_zenbleed_patch(family, model, microcode)) {
121 		x86_write_msr(MSR_F10H_DE_CFG, x86_read_msr(MSR_F10H_DE_CFG) | (1 << 9));
122 	}
123 
124 	return B_OK;
125 }
126 
127 
128 status_t
129 __x86_patch_errata_percpu(int currentCPU)
130 {
131 	const cpu_ent* cpu = get_cpu_struct();
132 	if (cpu->arch.vendor == VENDOR_AMD
133 		|| cpu->arch.vendor == VENDOR_HYGON) {
134 		return patch_errata_percpu_amd(currentCPU, cpu);
135 	}
136 	return B_OK;
137 }
138