xref: /haiku/src/add-ons/kernel/cpu/x86/generic_x86.cpp (revision cd552c7a15cc10c36dae8d7439ba1d6c0bb168c5)
1 /*
2  * Copyright 2005-2006, 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 
18 
19 //#define TRACE_MTRR
20 #ifdef TRACE_MTRR
21 #	define TRACE(x) dprintf x
22 #else
23 #	define TRACE(x) ;
24 #endif
25 
26 
27 #define IA32_MTRR_ENABLE				(1UL << 11)
28 #define IA32_MTRR_ENABLE_FIXED			(1UL << 10)
29 #define IA32_MTRR_VALID_RANGE			(1UL << 11)
30 
31 
32 struct mtrr_capabilities {
33 	mtrr_capabilities(uint64 value) { *(uint64 *)this = value; }
34 
35 	uint64	variable_ranges : 8;
36 	uint64	supports_fixed : 1;
37 	uint64	_reserved0 : 1;
38 	uint64	supports_write_combined : 1;
39 	uint64	_reserved1 : 53;
40 };
41 
42 
43 uint64 gPhysicalMask = 0;
44 
45 
46 uint32
47 generic_count_mtrrs(void)
48 {
49 	cpuid_info cpuInfo;
50 	if (get_current_cpuid(&cpuInfo, 1) != B_OK
51 		|| (cpuInfo.eax_1.features & IA32_FEATURE_MTRR) == 0)
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_cpuid(&cpuInfo, 0x80000000, 0) == B_OK
142 		&& cpuInfo.eax_0.max_eax & 0xff >= 8) {
143 		get_cpuid(&cpuInfo, 0x80000008, 0);
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 (x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & IA32_MTRR_ENABLE) {
164 		TRACE(("MTRR enabled\n"));
165 	} else {
166 		TRACE(("MTRR disabled\n"));
167 	}
168 
169 	for (uint32 i = 0; i < count; i++) {
170 		uint64 base;
171 		uint64 length;
172 		uint8 type;
173 		if (generic_get_mtrr(i, &base, &length, &type) == B_OK) {
174 			TRACE(("  %ld: 0x%Lx, 0x%Lx, %u\n", i, base, length, type));
175 		} else {
176 			TRACE(("  %ld: empty\n", i));
177 		}
178 	}
179 }
180 
181 
182 module_info *modules[] = {
183 	(module_info *)&gIntelModule,
184 	(module_info *)&gAMDModule,
185 	(module_info *)&gVIAModule,
186 	NULL
187 };
188