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
13static bool
14needs_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
35static status_t
36patch_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
128status_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