xref: /haiku/src/add-ons/kernel/cpu/x86/generic_x86.cpp (revision 58481f0f6ef1a61ba07283f012cafbc2ed874ead)
1 /*
2  * Copyright 2005-2007, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "generic_x86.h"
11 #include "intel.h"
12 #include "amd.h"
13 #include "via.h"
14 
15 #include <KernelExport.h>
16 #include <arch_system_info.h>
17 #include <arch/x86/arch_cpu.h>
18 
19 
20 //#define TRACE_MTRR
21 #ifdef TRACE_MTRR
22 #	define TRACE(x) dprintf x
23 #else
24 #	define TRACE(x) ;
25 #endif
26 
27 
28 #define IA32_MTRR_ENABLE				(1UL << 11)
29 #define IA32_MTRR_ENABLE_FIXED			(1UL << 10)
30 #define IA32_MTRR_VALID_RANGE			(1UL << 11)
31 
32 
33 struct mtrr_capabilities {
34 	mtrr_capabilities(uint64 value) { *(uint64 *)this = value; }
35 
36 	uint64	variable_ranges : 8;
37 	uint64	supports_fixed : 1;
38 	uint64	_reserved0 : 1;
39 	uint64	supports_write_combined : 1;
40 	uint64	_reserved1 : 53;
41 };
42 
43 
44 uint64 gPhysicalMask = 0;
45 
46 
47 uint32
48 generic_count_mtrrs(void)
49 {
50 	if (!x86_check_feature(IA32_FEATURE_MTRR, FEATURE_COMMON)
51 		|| !x86_check_feature(IA32_FEATURE_MSR, FEATURE_COMMON))
52 		return 0;
53 
54 	mtrr_capabilities capabilities(x86_read_msr(IA32_MSR_MTRR_CAPABILITIES));
55 	TRACE(("CPU has %u variable range MTRs.\n", (uint8)capabilities.variable_ranges));
56 	return capabilities.variable_ranges;
57 }
58 
59 
60 void
61 generic_init_mtrrs(uint32 count)
62 {
63 	if (count == 0)
64 		return;
65 
66 	// disable and clear all MTRRs
67 	// (we leave the fixed MTRRs as is)
68 	// TODO: check if the fixed MTRRs are set on all CPUs identically?
69 	TRACE(("generic_init_mtrrs(count = %ld)\n", count));
70 
71 	x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE,
72 		x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & ~IA32_MTRR_ENABLE);
73 
74 	for (uint32 i = count; i-- > 0;) {
75 		if (x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + i * 2) & IA32_MTRR_VALID_RANGE)
76 			x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + i * 2, 0);
77 	}
78 
79 	// but turn on variable MTRR functionality
80 
81 	x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE,
82 		x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) | IA32_MTRR_ENABLE);
83 }
84 
85 
86 void
87 generic_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type)
88 {
89 	index *= 2;
90 		// there are two registers per slot
91 
92 	uint64 mask = length - 1;
93 	mask = ~mask & gPhysicalMask;
94 
95 	TRACE(("MTRR %ld: new mask %Lx)\n", index, mask));
96 	TRACE(("  mask test base: %Lx)\n", mask & base));
97 	TRACE(("  mask test middle: %Lx)\n", mask & (base + length / 2)));
98 	TRACE(("  mask test end: %Lx)\n", mask & (base + length)));
99 
100 	// First, disable MTRR
101 
102 	x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, 0);
103 
104 	if (base != 0 || mask != 0 || type != 0) {
105 		// then fill in the new values, and enable it again
106 
107 		x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index,
108 			(base & ~(B_PAGE_SIZE - 1)) | type);
109 		x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index,
110 			mask | IA32_MTRR_VALID_RANGE);
111 	} else {
112 		// reset base as well
113 		x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, 0);
114 	}
115 }
116 
117 
118 status_t
119 generic_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type)
120 {
121 	uint64 mask = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index * 2);
122 	if ((mask & IA32_MTRR_VALID_RANGE) == 0)
123 		return B_ERROR;
124 
125 	uint64 base = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index * 2);
126 
127 	*_base = base & ~(B_PAGE_SIZE - 1);
128 	*_length = (~mask & gPhysicalMask) + 1;
129 	*_type = base & 0xff;
130 
131 	return B_OK;
132 }
133 
134 
135 status_t
136 generic_mtrr_compute_physical_mask(void)
137 {
138 	uint32 bits = 36;
139 
140 	cpuid_info cpuInfo;
141 	if (get_current_cpuid(&cpuInfo, 0x80000000) == B_OK
142 		&& (cpuInfo.eax_0.max_eax & 0xff) >= 8) {
143 		get_current_cpuid(&cpuInfo, 0x80000008);
144 		bits = cpuInfo.regs.eax & 0xff;
145 
146 		// Obviously, the bits are not always reported correctly
147 		if (bits < 36)
148 			bits = 36;
149 	}
150 
151 	gPhysicalMask = ((1ULL << bits) - 1) & ~(B_PAGE_SIZE - 1);
152 
153 	TRACE(("CPU has %ld physical address bits, physical mask is %016Lx\n",
154 		bits, gPhysicalMask));
155 
156 	return B_OK;
157 }
158 
159 
160 void
161 generic_dump_mtrrs(uint32 count)
162 {
163 	if (count == 0)
164 		return;
165 
166 	if (x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & IA32_MTRR_ENABLE) {
167 		TRACE(("MTRR enabled\n"));
168 	} else {
169 		TRACE(("MTRR disabled\n"));
170 	}
171 
172 	for (uint32 i = 0; i < count; i++) {
173 		uint64 base;
174 		uint64 length;
175 		uint8 type;
176 		if (generic_get_mtrr(i, &base, &length, &type) == B_OK) {
177 			TRACE(("  %ld: 0x%Lx, 0x%Lx, %u\n", i, base, length, type));
178 		} else {
179 			TRACE(("  %ld: empty\n", i));
180 		}
181 	}
182 }
183 
184 
185 module_info *modules[] = {
186 	(module_info *)&gIntelModule,
187 	(module_info *)&gAMDModule,
188 	(module_info *)&gVIAModule,
189 	NULL
190 };
191