xref: /haiku/src/system/kernel/arch/x86/arch_vm.cpp (revision a99eb6b56f61bd847d246e44885618fdeaa313a1)
1393fceb5SAxel Dörfler /*
2bb163c02SIngo Weinhold  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3b20d05b4SJérôme Duval  * Copyright 2008, Jérôme Duval.
4bb163c02SIngo Weinhold  * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
5393fceb5SAxel Dörfler  * Distributed under the terms of the MIT License.
6393fceb5SAxel Dörfler  *
7393fceb5SAxel Dörfler  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8393fceb5SAxel Dörfler  * Distributed under the terms of the NewOS License.
9393fceb5SAxel Dörfler  */
10393fceb5SAxel Dörfler 
11393fceb5SAxel Dörfler 
1274785e79SIngo Weinhold #include <stdlib.h>
1374785e79SIngo Weinhold #include <string.h>
1474785e79SIngo Weinhold 
15393fceb5SAxel Dörfler #include <KernelExport.h>
1674785e79SIngo Weinhold 
17393fceb5SAxel Dörfler #include <smp.h>
18393fceb5SAxel Dörfler #include <util/AutoLock.h>
19393fceb5SAxel Dörfler #include <vm.h>
2074785e79SIngo Weinhold #include <vm_address_space.h>
21393fceb5SAxel Dörfler #include <vm_page.h>
22393fceb5SAxel Dörfler #include <vm_priv.h>
23393fceb5SAxel Dörfler 
24393fceb5SAxel Dörfler #include <arch/vm.h>
25393fceb5SAxel Dörfler #include <arch/int.h>
26393fceb5SAxel Dörfler #include <arch/cpu.h>
27393fceb5SAxel Dörfler 
28393fceb5SAxel Dörfler #include <arch/x86/bios.h>
29393fceb5SAxel Dörfler 
3047c40a10SIngo Weinhold #include "x86_paging.h"
3147c40a10SIngo Weinhold 
32393fceb5SAxel Dörfler 
33393fceb5SAxel Dörfler //#define TRACE_ARCH_VM
34393fceb5SAxel Dörfler #ifdef TRACE_ARCH_VM
35393fceb5SAxel Dörfler #	define TRACE(x) dprintf x
36393fceb5SAxel Dörfler #else
37393fceb5SAxel Dörfler #	define TRACE(x) ;
38393fceb5SAxel Dörfler #endif
39393fceb5SAxel Dörfler 
404f893e39SJérôme Duval #define TRACE_MTRR_ARCH_VM
414f893e39SJérôme Duval #ifdef TRACE_MTRR_ARCH_VM
424f893e39SJérôme Duval #	define TRACE_MTRR(x...) dprintf(x)
434f893e39SJérôme Duval #else
444f893e39SJérôme Duval #	define TRACE_MTRR(x...)
454f893e39SJérôme Duval #endif
464f893e39SJérôme Duval 
47393fceb5SAxel Dörfler 
48bb163c02SIngo Weinhold static const uint32 kMaxMemoryTypeRanges	= 32;
49bb163c02SIngo Weinhold static const uint32 kMaxMemoryTypeRegisters	= 32;
50bb163c02SIngo Weinhold static const uint64 kMinMemoryTypeRangeSize	= 1 << 12;
51bb163c02SIngo Weinhold 
52bb163c02SIngo Weinhold 
53bb163c02SIngo Weinhold struct memory_type_range_analysis_info {
54bb163c02SIngo Weinhold 	uint64	size;
55bb163c02SIngo Weinhold 	uint32	rangesNeeded;
56bb163c02SIngo Weinhold 	uint32	subtractiveRangesNeeded;
57bb163c02SIngo Weinhold 	uint64	bestSubtractiveRange;
58bb163c02SIngo Weinhold };
59bb163c02SIngo Weinhold 
60bb163c02SIngo Weinhold struct memory_type_range_analysis {
61bb163c02SIngo Weinhold 	uint64							base;
62bb163c02SIngo Weinhold 	uint64							size;
63bb163c02SIngo Weinhold 	uint32							type;
64bb163c02SIngo Weinhold 	uint32							rangesNeeded;
65bb163c02SIngo Weinhold 	uint64							endRange;
66bb163c02SIngo Weinhold 	memory_type_range_analysis_info	left;
67bb163c02SIngo Weinhold 	memory_type_range_analysis_info	right;
68bb163c02SIngo Weinhold };
69bb163c02SIngo Weinhold 
70bb163c02SIngo Weinhold struct memory_type_range {
71bb163c02SIngo Weinhold 	uint64						base;
72bb163c02SIngo Weinhold 	uint64						size;
73bb163c02SIngo Weinhold 	uint32						type;
74bb163c02SIngo Weinhold 	area_id						area;
75bb163c02SIngo Weinhold };
76bb163c02SIngo Weinhold 
77393fceb5SAxel Dörfler 
78393fceb5SAxel Dörfler void *gDmaAddress;
79393fceb5SAxel Dörfler 
80bb163c02SIngo Weinhold static memory_type_range sMemoryTypeRanges[kMaxMemoryTypeRanges];
81bb163c02SIngo Weinhold static uint32 sMemoryTypeRangeCount;
82bb163c02SIngo Weinhold 
83bb163c02SIngo Weinhold static memory_type_range_analysis sMemoryTypeRangeAnalysis[
84bb163c02SIngo Weinhold 	kMaxMemoryTypeRanges];
85bb163c02SIngo Weinhold 
86bb163c02SIngo Weinhold static x86_mtrr_info sMemoryTypeRegisters[kMaxMemoryTypeRegisters];
87393fceb5SAxel Dörfler static uint32 sMemoryTypeRegisterCount;
88bb163c02SIngo Weinhold static uint32 sMemoryTypeRegistersUsed;
89bb163c02SIngo Weinhold 
90bb163c02SIngo Weinhold static mutex sMemoryTypeLock = MUTEX_INITIALIZER("memory type ranges");
91393fceb5SAxel Dörfler 
92393fceb5SAxel Dörfler 
93bb163c02SIngo Weinhold static void
94bb163c02SIngo Weinhold set_mtrrs()
95393fceb5SAxel Dörfler {
96bb163c02SIngo Weinhold 	x86_set_mtrrs(sMemoryTypeRegisters, sMemoryTypeRegistersUsed);
97393fceb5SAxel Dörfler 
98bb163c02SIngo Weinhold #ifdef TRACE_MTRR_ARCH_VM
99bb163c02SIngo Weinhold 	TRACE_MTRR("set MTRRs to:\n");
100bb163c02SIngo Weinhold 	for (uint32 i = 0; i < sMemoryTypeRegistersUsed; i++) {
101bb163c02SIngo Weinhold 		const x86_mtrr_info& info = sMemoryTypeRegisters[i];
102bb163c02SIngo Weinhold 		TRACE_MTRR("  mtrr: %2lu: base: %#9llx, size: %#9llx, type: %u\n",
103bb163c02SIngo Weinhold 			i, info.base, info.size, info.type);
104393fceb5SAxel Dörfler 	}
105bb163c02SIngo Weinhold #endif
106393fceb5SAxel Dörfler }
107393fceb5SAxel Dörfler 
108393fceb5SAxel Dörfler 
109393fceb5SAxel Dörfler static void
110bb163c02SIngo Weinhold add_used_mtrr(uint64 base, uint64 size, uint32 type)
111393fceb5SAxel Dörfler {
112bb163c02SIngo Weinhold 	ASSERT(sMemoryTypeRegistersUsed < sMemoryTypeRegisterCount);
113393fceb5SAxel Dörfler 
114bb163c02SIngo Weinhold 	x86_mtrr_info& info = sMemoryTypeRegisters[sMemoryTypeRegistersUsed++];
115bb163c02SIngo Weinhold 	info.base = base;
116bb163c02SIngo Weinhold 	info.size = size;
117bb163c02SIngo Weinhold 	info.type = type;
118393fceb5SAxel Dörfler }
119393fceb5SAxel Dörfler 
120393fceb5SAxel Dörfler 
1214f893e39SJérôme Duval static void
122bb163c02SIngo Weinhold analyze_range(memory_type_range_analysis& analysis, uint64 previousEnd,
123bb163c02SIngo Weinhold 	uint64 nextBase)
1244f893e39SJérôme Duval {
125bb163c02SIngo Weinhold 	uint64 base = analysis.base;
126bb163c02SIngo Weinhold 	uint64 size = analysis.size;
1274f893e39SJérôme Duval 
128bb163c02SIngo Weinhold 	memory_type_range_analysis_info& left = analysis.left;
129bb163c02SIngo Weinhold 	memory_type_range_analysis_info& right = analysis.right;
130bb163c02SIngo Weinhold 
131bb163c02SIngo Weinhold 	uint32 leftSubtractiveRangesNeeded = 2;
132bb163c02SIngo Weinhold 	int32 leftBestSubtractiveRangeDifference = 0;
133bb163c02SIngo Weinhold 	uint32 leftBestSubtractivePositiveRangesNeeded = 0;
134bb163c02SIngo Weinhold 	uint32 leftBestSubtractiveRangesNeeded = 0;
135bb163c02SIngo Weinhold 
136bb163c02SIngo Weinhold 	uint32 rightSubtractiveRangesNeeded = 2;
137bb163c02SIngo Weinhold 	int32 rightBestSubtractiveRangeDifference = 0;
138bb163c02SIngo Weinhold 	uint32 rightBestSubtractivePositiveRangesNeeded = 0;
139bb163c02SIngo Weinhold 	uint32 rightBestSubtractiveRangesNeeded = 0;
140bb163c02SIngo Weinhold 
141bb163c02SIngo Weinhold 	uint64 range = kMinMemoryTypeRangeSize;
142bb163c02SIngo Weinhold 
143bb163c02SIngo Weinhold 	while (size > 0) {
144bb163c02SIngo Weinhold 		if ((base & range) != 0) {
145bb163c02SIngo Weinhold 			left.rangesNeeded++;
146bb163c02SIngo Weinhold 
147bb163c02SIngo Weinhold 			bool replaceBestSubtractive = false;
148bb163c02SIngo Weinhold 			int32 rangeDifference = (int32)left.rangesNeeded
149bb163c02SIngo Weinhold 				- (int32)leftSubtractiveRangesNeeded;
150bb163c02SIngo Weinhold 			if (left.bestSubtractiveRange == 0
151bb163c02SIngo Weinhold 				|| leftBestSubtractiveRangeDifference < rangeDifference) {
152bb163c02SIngo Weinhold 				// check for intersection with previous range
153bb163c02SIngo Weinhold 				replaceBestSubtractive
154bb163c02SIngo Weinhold 					= previousEnd == 0 || base - range >= previousEnd;
1554f893e39SJérôme Duval 			}
1564f893e39SJérôme Duval 
157bb163c02SIngo Weinhold 			if (replaceBestSubtractive) {
158bb163c02SIngo Weinhold 				leftBestSubtractiveRangeDifference = rangeDifference;
159bb163c02SIngo Weinhold 				leftBestSubtractiveRangesNeeded
160bb163c02SIngo Weinhold 					= leftSubtractiveRangesNeeded;
161bb163c02SIngo Weinhold 				left.bestSubtractiveRange = range;
162bb163c02SIngo Weinhold 				leftBestSubtractivePositiveRangesNeeded = 0;
163bb163c02SIngo Weinhold 			} else
164bb163c02SIngo Weinhold 				leftBestSubtractivePositiveRangesNeeded++;
165bb163c02SIngo Weinhold 
166bb163c02SIngo Weinhold 			left.size += range;
167bb163c02SIngo Weinhold 			base += range;
168bb163c02SIngo Weinhold 			size -= range;
169bb163c02SIngo Weinhold 		} else if (left.bestSubtractiveRange > 0)
170bb163c02SIngo Weinhold 			leftSubtractiveRangesNeeded++;
171bb163c02SIngo Weinhold 
172bb163c02SIngo Weinhold 		if ((size & range) != 0) {
173bb163c02SIngo Weinhold 			right.rangesNeeded++;
174bb163c02SIngo Weinhold 
175bb163c02SIngo Weinhold 			bool replaceBestSubtractive = false;
176bb163c02SIngo Weinhold 			int32 rangeDifference = (int32)right.rangesNeeded
177bb163c02SIngo Weinhold 				- (int32)rightSubtractiveRangesNeeded;
178bb163c02SIngo Weinhold 			if (right.bestSubtractiveRange == 0
179bb163c02SIngo Weinhold 				|| rightBestSubtractiveRangeDifference < rangeDifference) {
180bb163c02SIngo Weinhold 				// check for intersection with previous range
181bb163c02SIngo Weinhold 				replaceBestSubtractive
182bb163c02SIngo Weinhold 					= nextBase == 0 || base + size + range <= nextBase;
183bb163c02SIngo Weinhold 			}
184bb163c02SIngo Weinhold 
185bb163c02SIngo Weinhold 			if (replaceBestSubtractive) {
186bb163c02SIngo Weinhold 				rightBestSubtractiveRangeDifference = rangeDifference;
187bb163c02SIngo Weinhold 				rightBestSubtractiveRangesNeeded
188bb163c02SIngo Weinhold 					= rightSubtractiveRangesNeeded;
189bb163c02SIngo Weinhold 				right.bestSubtractiveRange = range;
190bb163c02SIngo Weinhold 				rightBestSubtractivePositiveRangesNeeded = 0;
191bb163c02SIngo Weinhold 			} else
192bb163c02SIngo Weinhold 				rightBestSubtractivePositiveRangesNeeded++;
193bb163c02SIngo Weinhold 
194bb163c02SIngo Weinhold 			right.size += range;
195bb163c02SIngo Weinhold 			size -= range;
196bb163c02SIngo Weinhold 		} else if (right.bestSubtractiveRange > 0)
197bb163c02SIngo Weinhold 			rightSubtractiveRangesNeeded++;
198bb163c02SIngo Weinhold 
199bb163c02SIngo Weinhold 		range <<= 1;
200bb163c02SIngo Weinhold 	}
201bb163c02SIngo Weinhold 
202bb163c02SIngo Weinhold 	analysis.endRange = range;
203bb163c02SIngo Weinhold 
204bb163c02SIngo Weinhold 	// If a subtractive setup doesn't have any advantages, don't use it.
205bb163c02SIngo Weinhold 	// Also compute analysis.rangesNeeded.
206bb163c02SIngo Weinhold 	if (leftBestSubtractiveRangesNeeded
207bb163c02SIngo Weinhold 			+ leftBestSubtractivePositiveRangesNeeded >= left.rangesNeeded) {
208bb163c02SIngo Weinhold 		left.bestSubtractiveRange = 0;
209bb163c02SIngo Weinhold 		left.subtractiveRangesNeeded = 0;
210bb163c02SIngo Weinhold 		analysis.rangesNeeded = left.rangesNeeded;
211bb163c02SIngo Weinhold 	} else {
212bb163c02SIngo Weinhold 		left.subtractiveRangesNeeded = leftBestSubtractiveRangesNeeded
213bb163c02SIngo Weinhold 			+ leftBestSubtractivePositiveRangesNeeded;
214bb163c02SIngo Weinhold 		analysis.rangesNeeded = left.subtractiveRangesNeeded;
215bb163c02SIngo Weinhold 	}
216bb163c02SIngo Weinhold 
217bb163c02SIngo Weinhold 	if (rightBestSubtractiveRangesNeeded
218bb163c02SIngo Weinhold 			+ rightBestSubtractivePositiveRangesNeeded >= right.rangesNeeded) {
219bb163c02SIngo Weinhold 		right.bestSubtractiveRange = 0;
220bb163c02SIngo Weinhold 		right.subtractiveRangesNeeded = 0;
221bb163c02SIngo Weinhold 		analysis.rangesNeeded += right.rangesNeeded;
222bb163c02SIngo Weinhold 	} else {
223bb163c02SIngo Weinhold 		right.subtractiveRangesNeeded = rightBestSubtractiveRangesNeeded
224bb163c02SIngo Weinhold 			+ rightBestSubtractivePositiveRangesNeeded;
225bb163c02SIngo Weinhold 		analysis.rangesNeeded += right.subtractiveRangesNeeded;
226bb163c02SIngo Weinhold 	}
227bb163c02SIngo Weinhold }
228bb163c02SIngo Weinhold 
229bb163c02SIngo Weinhold static void
230bb163c02SIngo Weinhold compute_mtrrs(const memory_type_range_analysis& analysis)
231bb163c02SIngo Weinhold {
232bb163c02SIngo Weinhold 	const memory_type_range_analysis_info& left = analysis.left;
233bb163c02SIngo Weinhold 	const memory_type_range_analysis_info& right = analysis.right;
234bb163c02SIngo Weinhold 
235bb163c02SIngo Weinhold 	// generate a setup for the left side
236bb163c02SIngo Weinhold 	if (left.rangesNeeded > 0) {
237bb163c02SIngo Weinhold 		uint64 base = analysis.base;
238bb163c02SIngo Weinhold 		uint64 size = left.size;
239bb163c02SIngo Weinhold 		uint64 range = analysis.endRange;
240bb163c02SIngo Weinhold 		uint64 rangeEnd = base + size;
241bb163c02SIngo Weinhold 		bool subtractive = false;
242bb163c02SIngo Weinhold 		while (size > 0) {
243bb163c02SIngo Weinhold 			if (range == left.bestSubtractiveRange) {
244bb163c02SIngo Weinhold 				base = rangeEnd - 2 * range;
245bb163c02SIngo Weinhold 				add_used_mtrr(base, range, analysis.type);
246bb163c02SIngo Weinhold 				subtractive = true;
247bb163c02SIngo Weinhold 				break;
248bb163c02SIngo Weinhold 			}
249bb163c02SIngo Weinhold 
250bb163c02SIngo Weinhold 			if ((size & range) != 0) {
251bb163c02SIngo Weinhold 				rangeEnd -= range;
252bb163c02SIngo Weinhold 				add_used_mtrr(rangeEnd, range, analysis.type);
253bb163c02SIngo Weinhold 				size -= range;
254bb163c02SIngo Weinhold 			}
255bb163c02SIngo Weinhold 
256bb163c02SIngo Weinhold 			range >>= 1;
257bb163c02SIngo Weinhold 		}
258bb163c02SIngo Weinhold 
259bb163c02SIngo Weinhold 		if (subtractive) {
260bb163c02SIngo Weinhold 			uint64 shortestRange = range;
261bb163c02SIngo Weinhold 			while (size > 0) {
262bb163c02SIngo Weinhold 				if ((size & range) != 0) {
263bb163c02SIngo Weinhold 					shortestRange = range;
264bb163c02SIngo Weinhold 					size -= range;
265bb163c02SIngo Weinhold 				} else {
266bb163c02SIngo Weinhold 					add_used_mtrr(base, range, IA32_MTR_UNCACHED);
267bb163c02SIngo Weinhold 					base += range;
268bb163c02SIngo Weinhold 				}
269bb163c02SIngo Weinhold 
270bb163c02SIngo Weinhold 				range >>= 1;
271bb163c02SIngo Weinhold 			}
272bb163c02SIngo Weinhold 
273bb163c02SIngo Weinhold 			add_used_mtrr(base, shortestRange, IA32_MTR_UNCACHED);
274bb163c02SIngo Weinhold 		}
275bb163c02SIngo Weinhold 	}
276bb163c02SIngo Weinhold 
277bb163c02SIngo Weinhold 	// generate a setup for the right side
278bb163c02SIngo Weinhold 	if (right.rangesNeeded > 0) {
279bb163c02SIngo Weinhold 		uint64 base = analysis.base + left.size;
280bb163c02SIngo Weinhold 		uint64 size = right.size;
281bb163c02SIngo Weinhold 		uint64 range = analysis.endRange;
282bb163c02SIngo Weinhold 		bool subtractive = false;
283bb163c02SIngo Weinhold 		while (size > 0) {
284bb163c02SIngo Weinhold 			if (range == right.bestSubtractiveRange) {
285bb163c02SIngo Weinhold 				add_used_mtrr(base, range * 2, analysis.type);
286bb163c02SIngo Weinhold 				subtractive = true;
287bb163c02SIngo Weinhold 				break;
288bb163c02SIngo Weinhold 			}
289bb163c02SIngo Weinhold 
290bb163c02SIngo Weinhold 			if ((size & range) != 0) {
291bb163c02SIngo Weinhold 				add_used_mtrr(base, range, analysis.type);
292bb163c02SIngo Weinhold 				base += range;
293bb163c02SIngo Weinhold 				size -= range;
294bb163c02SIngo Weinhold 			}
295bb163c02SIngo Weinhold 
296bb163c02SIngo Weinhold 			range >>= 1;
297bb163c02SIngo Weinhold 		}
298bb163c02SIngo Weinhold 
299bb163c02SIngo Weinhold 		if (subtractive) {
300bb163c02SIngo Weinhold 			uint64 rangeEnd = base + range * 2;
301bb163c02SIngo Weinhold 			uint64 shortestRange = range;
302bb163c02SIngo Weinhold 			while (size > 0) {
303bb163c02SIngo Weinhold 				if ((size & range) != 0) {
304bb163c02SIngo Weinhold 					shortestRange = range;
305bb163c02SIngo Weinhold 					size -= range;
306bb163c02SIngo Weinhold 				} else {
307bb163c02SIngo Weinhold 					rangeEnd -= range;
308bb163c02SIngo Weinhold 					add_used_mtrr(rangeEnd, range, IA32_MTR_UNCACHED);
309bb163c02SIngo Weinhold 				}
310bb163c02SIngo Weinhold 
311bb163c02SIngo Weinhold 				range >>= 1;
312bb163c02SIngo Weinhold 			}
313bb163c02SIngo Weinhold 
314bb163c02SIngo Weinhold 			rangeEnd -= shortestRange;
315bb163c02SIngo Weinhold 			add_used_mtrr(rangeEnd, shortestRange, IA32_MTR_UNCACHED);
316bb163c02SIngo Weinhold 		}
317bb163c02SIngo Weinhold 	}
3184f893e39SJérôme Duval }
3194f893e39SJérôme Duval 
3204f893e39SJérôme Duval 
321393fceb5SAxel Dörfler static status_t
322bb163c02SIngo Weinhold update_mttrs()
323393fceb5SAxel Dörfler {
324bb163c02SIngo Weinhold 	// Transfer the range array to the analysis array, dropping all uncachable
325bb163c02SIngo Weinhold 	// ranges (that's the default anyway) and joining adjacent ranges with the
326bb163c02SIngo Weinhold 	// same type.
327bb163c02SIngo Weinhold 	memory_type_range_analysis* ranges = sMemoryTypeRangeAnalysis;
328bb163c02SIngo Weinhold 	uint32 rangeCount = 0;
329bb163c02SIngo Weinhold 	{
330bb163c02SIngo Weinhold 		uint32 previousRangeType = IA32_MTR_UNCACHED;
331bb163c02SIngo Weinhold 		uint64 previousRangeEnd = 0;
332bb163c02SIngo Weinhold 		for (uint32 i = 0; i < sMemoryTypeRangeCount; i++) {
333bb163c02SIngo Weinhold 			if (sMemoryTypeRanges[i].type != IA32_MTR_UNCACHED) {
334bb163c02SIngo Weinhold 				uint64 rangeEnd = sMemoryTypeRanges[i].base
335bb163c02SIngo Weinhold 					+ sMemoryTypeRanges[i].size;
336bb163c02SIngo Weinhold 				if (previousRangeType == sMemoryTypeRanges[i].type
337bb163c02SIngo Weinhold 					&& previousRangeEnd >= sMemoryTypeRanges[i].base) {
338bb163c02SIngo Weinhold 					// the range overlaps/continues the previous range -- just
339bb163c02SIngo Weinhold 					// enlarge that one
340bb163c02SIngo Weinhold 					if (rangeEnd > previousRangeEnd)
341bb163c02SIngo Weinhold 						previousRangeEnd = rangeEnd;
342bb163c02SIngo Weinhold 					ranges[rangeCount - 1].size  = previousRangeEnd
343bb163c02SIngo Weinhold 						- ranges[rangeCount - 1].base;
344bb163c02SIngo Weinhold 				} else {
345bb163c02SIngo Weinhold 					// add the new range
346bb163c02SIngo Weinhold 					memset(&ranges[rangeCount], 0, sizeof(ranges[rangeCount]));
347bb163c02SIngo Weinhold 					ranges[rangeCount].base = sMemoryTypeRanges[i].base;
348bb163c02SIngo Weinhold 					ranges[rangeCount].size = sMemoryTypeRanges[i].size;
349bb163c02SIngo Weinhold 					ranges[rangeCount].type = sMemoryTypeRanges[i].type;
350bb163c02SIngo Weinhold 					previousRangeEnd = rangeEnd;
351bb163c02SIngo Weinhold 					previousRangeType = sMemoryTypeRanges[i].type;
352bb163c02SIngo Weinhold 					rangeCount++;
353bb163c02SIngo Weinhold 				}
354bb163c02SIngo Weinhold 			}
355bb163c02SIngo Weinhold 		}
356bb163c02SIngo Weinhold 	}
357393fceb5SAxel Dörfler 
358bb163c02SIngo Weinhold 	// analyze the ranges
359bb163c02SIngo Weinhold 	uint32 registersNeeded = 0;
360bb163c02SIngo Weinhold 	uint64 previousEnd = 0;
361bb163c02SIngo Weinhold 	for (uint32 i = 0; i < rangeCount; i++) {
362bb163c02SIngo Weinhold 		memory_type_range_analysis& range = ranges[i];
363bb163c02SIngo Weinhold 		uint64 nextBase = i + 1 < rangeCount ? ranges[i + 1].base : 0;
364bb163c02SIngo Weinhold 		analyze_range(range, previousEnd, nextBase);
365bb163c02SIngo Weinhold 		registersNeeded += range.rangesNeeded;
366bb163c02SIngo Weinhold 		previousEnd = range.base + range.size;
367bb163c02SIngo Weinhold 	}
368bb163c02SIngo Weinhold 
369bb163c02SIngo Weinhold 	// fail when we need more registers than we have
370bb163c02SIngo Weinhold 	if (registersNeeded > sMemoryTypeRegisterCount)
371bb163c02SIngo Weinhold 		return B_BUSY;
372bb163c02SIngo Weinhold 
373bb163c02SIngo Weinhold 	sMemoryTypeRegistersUsed = 0;
374bb163c02SIngo Weinhold 
375bb163c02SIngo Weinhold 	for (uint32 i = 0; i < rangeCount; i++) {
376bb163c02SIngo Weinhold 		memory_type_range_analysis& range = ranges[i];
377bb163c02SIngo Weinhold 		compute_mtrrs(range);
378bb163c02SIngo Weinhold 	}
379bb163c02SIngo Weinhold 
380bb163c02SIngo Weinhold 	set_mtrrs();
381bb163c02SIngo Weinhold 
382bb163c02SIngo Weinhold 	return B_OK;
383bb163c02SIngo Weinhold }
384bb163c02SIngo Weinhold 
385bb163c02SIngo Weinhold 
386bb163c02SIngo Weinhold static void
387bb163c02SIngo Weinhold remove_memory_type_range_locked(uint32 index)
388bb163c02SIngo Weinhold {
389bb163c02SIngo Weinhold 	sMemoryTypeRangeCount--;
390bb163c02SIngo Weinhold 	if (index < sMemoryTypeRangeCount) {
391bb163c02SIngo Weinhold 		memmove(sMemoryTypeRanges + index, sMemoryTypeRanges + index + 1,
392bb163c02SIngo Weinhold 			(sMemoryTypeRangeCount - index) * sizeof(memory_type_range));
393bb163c02SIngo Weinhold 	}
394bb163c02SIngo Weinhold }
395bb163c02SIngo Weinhold 
396bb163c02SIngo Weinhold 
397bb163c02SIngo Weinhold static status_t
398bb163c02SIngo Weinhold add_memory_type_range(area_id areaID, uint64 base, uint64 size, uint32 type)
399bb163c02SIngo Weinhold {
400bb163c02SIngo Weinhold 	// translate the type
401393fceb5SAxel Dörfler 	if (type == 0)
402393fceb5SAxel Dörfler 		return B_OK;
403393fceb5SAxel Dörfler 
404393fceb5SAxel Dörfler 	switch (type) {
405393fceb5SAxel Dörfler 		case B_MTR_UC:
4064f893e39SJérôme Duval 			type = IA32_MTR_UNCACHED;
407393fceb5SAxel Dörfler 			break;
408393fceb5SAxel Dörfler 		case B_MTR_WC:
4094f893e39SJérôme Duval 			type = IA32_MTR_WRITE_COMBINING;
410393fceb5SAxel Dörfler 			break;
411393fceb5SAxel Dörfler 		case B_MTR_WT:
4124f893e39SJérôme Duval 			type = IA32_MTR_WRITE_THROUGH;
413393fceb5SAxel Dörfler 			break;
414393fceb5SAxel Dörfler 		case B_MTR_WP:
4154f893e39SJérôme Duval 			type = IA32_MTR_WRITE_PROTECTED;
416393fceb5SAxel Dörfler 			break;
417393fceb5SAxel Dörfler 		case B_MTR_WB:
4184f893e39SJérôme Duval 			type = IA32_MTR_WRITE_BACK;
419393fceb5SAxel Dörfler 			break;
420393fceb5SAxel Dörfler 		default:
421393fceb5SAxel Dörfler 			return B_BAD_VALUE;
422393fceb5SAxel Dörfler 	}
423393fceb5SAxel Dörfler 
424bb163c02SIngo Weinhold 	TRACE_MTRR("add_memory_type_range(%ld, %#llx, %#llx, %lu)\n", areaID, base,
425bb163c02SIngo Weinhold 		size, type);
426393fceb5SAxel Dörfler 
427bb163c02SIngo Weinhold 	// base and size must at least be aligned to the minimum range size
428bb163c02SIngo Weinhold 	if (((base | size) & (kMinMemoryTypeRangeSize - 1)) != 0) {
429bb163c02SIngo Weinhold 		dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Memory base or "
430bb163c02SIngo Weinhold 			"size not minimally aligned!\n", areaID, base, size, type);
431393fceb5SAxel Dörfler 		return B_BAD_VALUE;
432393fceb5SAxel Dörfler 	}
433393fceb5SAxel Dörfler 
434bb163c02SIngo Weinhold 	MutexLocker locker(sMemoryTypeLock);
435bb163c02SIngo Weinhold 
436bb163c02SIngo Weinhold 	if (sMemoryTypeRangeCount == kMaxMemoryTypeRanges) {
437bb163c02SIngo Weinhold 		dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Out of "
438bb163c02SIngo Weinhold 			"memory ranges!\n", areaID, base, size, type);
439bb163c02SIngo Weinhold 		return B_BUSY;
440bb163c02SIngo Weinhold 	}
441bb163c02SIngo Weinhold 
442bb163c02SIngo Weinhold 	// iterate through the existing ranges and check for clashes
443bb163c02SIngo Weinhold 	bool foundInsertionIndex = false;
444bb163c02SIngo Weinhold 	uint32 index = 0;
445bb163c02SIngo Weinhold 	for (uint32 i = 0; i < sMemoryTypeRangeCount; i++) {
446bb163c02SIngo Weinhold 		const memory_type_range& range = sMemoryTypeRanges[i];
447bb163c02SIngo Weinhold 		if (range.base > base) {
448bb163c02SIngo Weinhold 			if (range.base - base < size && range.type != type) {
449bb163c02SIngo Weinhold 				dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Memory "
450bb163c02SIngo Weinhold 					"range intersects with existing one (%#llx, %#llx, %lu).\n",
451bb163c02SIngo Weinhold 					areaID, base, size, type, range.base, range.size,
452bb163c02SIngo Weinhold 					range.type);
453393fceb5SAxel Dörfler 				return B_BAD_VALUE;
454bb163c02SIngo Weinhold 			}
455393fceb5SAxel Dörfler 
456bb163c02SIngo Weinhold 			// found the insertion index
457bb163c02SIngo Weinhold 			if (!foundInsertionIndex) {
458bb163c02SIngo Weinhold 				index = i;
459bb163c02SIngo Weinhold 				foundInsertionIndex = true;
460bb163c02SIngo Weinhold 			}
461bb163c02SIngo Weinhold 			break;
462bb163c02SIngo Weinhold 		} else if (base - range.base < range.size && range.type != type) {
463bb163c02SIngo Weinhold 			dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Memory "
464bb163c02SIngo Weinhold 				"range intersects with existing one (%#llx, %#llx, %lu).\n",
465bb163c02SIngo Weinhold 				areaID, base, size, type, range.base, range.size, range.type);
466bb163c02SIngo Weinhold 			return B_BAD_VALUE;
467bb163c02SIngo Weinhold 		}
468bb163c02SIngo Weinhold 	}
469393fceb5SAxel Dörfler 
470bb163c02SIngo Weinhold 	if (!foundInsertionIndex)
471bb163c02SIngo Weinhold 		index = sMemoryTypeRangeCount;
472393fceb5SAxel Dörfler 
473bb163c02SIngo Weinhold 	// make room for the new range
474bb163c02SIngo Weinhold 	if (index < sMemoryTypeRangeCount) {
475bb163c02SIngo Weinhold 		memmove(sMemoryTypeRanges + index + 1, sMemoryTypeRanges + index,
476bb163c02SIngo Weinhold 			(sMemoryTypeRangeCount - index) * sizeof(memory_type_range));
477bb163c02SIngo Weinhold 	}
478bb163c02SIngo Weinhold 	sMemoryTypeRangeCount++;
479393fceb5SAxel Dörfler 
480bb163c02SIngo Weinhold 	memory_type_range& rangeInfo = sMemoryTypeRanges[index];
481bb163c02SIngo Weinhold 	rangeInfo.base = base;
482bb163c02SIngo Weinhold 	rangeInfo.size = size;
483bb163c02SIngo Weinhold 	rangeInfo.type = type;
484bb163c02SIngo Weinhold 	rangeInfo.area = areaID;
485bb163c02SIngo Weinhold 
486bb163c02SIngo Weinhold 	uint64 range = kMinMemoryTypeRangeSize;
487bb163c02SIngo Weinhold 	status_t error;
488bb163c02SIngo Weinhold 	do {
489bb163c02SIngo Weinhold 		error = update_mttrs();
490bb163c02SIngo Weinhold 		if (error == B_OK) {
491bb163c02SIngo Weinhold 			if (rangeInfo.size != size) {
492bb163c02SIngo Weinhold 				dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): "
493bb163c02SIngo Weinhold 					"update_mtrrs() succeeded only with simplified range: "
494bb163c02SIngo Weinhold 					"base: %#llx, size: %#llx\n", areaID, base, size, type,
495bb163c02SIngo Weinhold 					rangeInfo.base, rangeInfo.size);
496bb163c02SIngo Weinhold 			}
497393fceb5SAxel Dörfler 			return B_OK;
498393fceb5SAxel Dörfler 		}
499393fceb5SAxel Dörfler 
500bb163c02SIngo Weinhold 		// update_mttrs() failed -- try to simplify (i.e. shrink) the range
501bb163c02SIngo Weinhold 		while (rangeInfo.size != 0) {
502bb163c02SIngo Weinhold 			if ((rangeInfo.base & range) != 0) {
503bb163c02SIngo Weinhold 				rangeInfo.base += range;
504bb163c02SIngo Weinhold 				rangeInfo.size -= range;
505bb163c02SIngo Weinhold 				// don't shift the range yet -- we might still have an
506bb163c02SIngo Weinhold 				// unaligned size
507bb163c02SIngo Weinhold 				break;
508bb163c02SIngo Weinhold 			}
509bb163c02SIngo Weinhold 			if ((rangeInfo.size & range) != 0) {
510bb163c02SIngo Weinhold 				rangeInfo.size -= range;
511bb163c02SIngo Weinhold 				range <<= 1;
512bb163c02SIngo Weinhold 				break;
513bb163c02SIngo Weinhold 			}
514393fceb5SAxel Dörfler 
515bb163c02SIngo Weinhold 			range <<= 1;
516bb163c02SIngo Weinhold 		}
517bb163c02SIngo Weinhold 	} while (rangeInfo.size > 0);
518bb163c02SIngo Weinhold 
519bb163c02SIngo Weinhold 	dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): update_mtrrs() "
520bb163c02SIngo Weinhold 		"failed.\n", areaID, base, size, type);
521bb163c02SIngo Weinhold 	remove_memory_type_range_locked(index);
522bb163c02SIngo Weinhold 	return error;
523bb163c02SIngo Weinhold }
5244f893e39SJérôme Duval 
5254f893e39SJérôme Duval 
5264f893e39SJérôme Duval static void
527bb163c02SIngo Weinhold remove_memory_type_range(area_id areaID)
5284f893e39SJérôme Duval {
529bb163c02SIngo Weinhold 	MutexLocker locker(sMemoryTypeLock);
530bb163c02SIngo Weinhold 
531bb163c02SIngo Weinhold 	for (uint32 i = 0; i < sMemoryTypeRangeCount; i++) {
532bb163c02SIngo Weinhold 		if (sMemoryTypeRanges[i].area == areaID) {
533bb163c02SIngo Weinhold 			TRACE_MTRR("remove_memory_type_range(%ld, %#llx, %#llxd)\n",
534bb163c02SIngo Weinhold 				areaID, sMemoryTypeRanges[i].base, sMemoryTypeRanges[i].size);
535bb163c02SIngo Weinhold 			remove_memory_type_range_locked(i);
536bb163c02SIngo Weinhold 			update_mttrs();
537bb163c02SIngo Weinhold 				// TODO: It's actually possible that this call fails, since
538bb163c02SIngo Weinhold 				// compute_mtrrs() joins ranges and removing one might cause a
539bb163c02SIngo Weinhold 				// previously joined big simple range to be split into several
540bb163c02SIngo Weinhold 				// ranges (or just make it more complicated).
541f7c655c7SJérôme Duval 			return;
542f7c655c7SJérôme Duval 		}
5434f893e39SJérôme Duval 	}
5444f893e39SJérôme Duval }
5454f893e39SJérôme Duval 
5464f893e39SJérôme Duval 
547393fceb5SAxel Dörfler //	#pragma mark -
548393fceb5SAxel Dörfler 
549393fceb5SAxel Dörfler 
550393fceb5SAxel Dörfler status_t
551393fceb5SAxel Dörfler arch_vm_init(kernel_args *args)
552393fceb5SAxel Dörfler {
553393fceb5SAxel Dörfler 	TRACE(("arch_vm_init: entry\n"));
554393fceb5SAxel Dörfler 	return 0;
555393fceb5SAxel Dörfler }
556393fceb5SAxel Dörfler 
557393fceb5SAxel Dörfler 
558393fceb5SAxel Dörfler /*!	Marks DMA region as in-use, and maps it into the kernel space */
559393fceb5SAxel Dörfler status_t
560393fceb5SAxel Dörfler arch_vm_init_post_area(kernel_args *args)
561393fceb5SAxel Dörfler {
562393fceb5SAxel Dörfler 	area_id id;
563393fceb5SAxel Dörfler 
564393fceb5SAxel Dörfler 	TRACE(("arch_vm_init_post_area: entry\n"));
565393fceb5SAxel Dörfler 
566393fceb5SAxel Dörfler 	// account for DMA area and mark the pages unusable
567393fceb5SAxel Dörfler 	vm_mark_page_range_inuse(0x0, 0xa0000 / B_PAGE_SIZE);
568393fceb5SAxel Dörfler 
569393fceb5SAxel Dörfler 	// map 0 - 0xa0000 directly
570393fceb5SAxel Dörfler 	id = map_physical_memory("dma_region", (void *)0x0, 0xa0000,
571393fceb5SAxel Dörfler 		B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
572393fceb5SAxel Dörfler 		&gDmaAddress);
573393fceb5SAxel Dörfler 	if (id < 0) {
574393fceb5SAxel Dörfler 		panic("arch_vm_init_post_area: unable to map dma region\n");
575393fceb5SAxel Dörfler 		return B_NO_MEMORY;
576393fceb5SAxel Dörfler 	}
577393fceb5SAxel Dörfler 
578393fceb5SAxel Dörfler 	return bios_init();
579393fceb5SAxel Dörfler }
580393fceb5SAxel Dörfler 
581393fceb5SAxel Dörfler 
582393fceb5SAxel Dörfler /*!	Gets rid of all yet unmapped (and therefore now unused) page tables */
583393fceb5SAxel Dörfler status_t
584393fceb5SAxel Dörfler arch_vm_init_end(kernel_args *args)
585393fceb5SAxel Dörfler {
586393fceb5SAxel Dörfler 	TRACE(("arch_vm_init_endvm: entry\n"));
587393fceb5SAxel Dörfler 
588393fceb5SAxel Dörfler 	// throw away anything in the kernel_args.pgtable[] that's not yet mapped
589393fceb5SAxel Dörfler 	vm_free_unused_boot_loader_range(KERNEL_BASE,
590393fceb5SAxel Dörfler 		0x400000 * args->arch_args.num_pgtables);
591393fceb5SAxel Dörfler 
592393fceb5SAxel Dörfler 	return B_OK;
593393fceb5SAxel Dörfler }
594393fceb5SAxel Dörfler 
595393fceb5SAxel Dörfler 
596393fceb5SAxel Dörfler status_t
597393fceb5SAxel Dörfler arch_vm_init_post_modules(kernel_args *args)
598393fceb5SAxel Dörfler {
599393fceb5SAxel Dörfler 	// the x86 CPU modules are now accessible
600393fceb5SAxel Dörfler 
601393fceb5SAxel Dörfler 	sMemoryTypeRegisterCount = x86_count_mtrrs();
602393fceb5SAxel Dörfler 	if (sMemoryTypeRegisterCount == 0)
603393fceb5SAxel Dörfler 		return B_OK;
604393fceb5SAxel Dörfler 
605393fceb5SAxel Dörfler 	// not very likely, but play safe here
606393fceb5SAxel Dörfler 	if (sMemoryTypeRegisterCount > kMaxMemoryTypeRegisters)
607393fceb5SAxel Dörfler 		sMemoryTypeRegisterCount = kMaxMemoryTypeRegisters;
608393fceb5SAxel Dörfler 
609393fceb5SAxel Dörfler 	// set the physical memory ranges to write-back mode
610393fceb5SAxel Dörfler 	for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) {
611bb163c02SIngo Weinhold 		add_memory_type_range(-1, args->physical_memory_range[i].start,
612bb163c02SIngo Weinhold 			args->physical_memory_range[i].size, B_MTR_WB);
613393fceb5SAxel Dörfler 	}
614393fceb5SAxel Dörfler 
615393fceb5SAxel Dörfler 	return B_OK;
616393fceb5SAxel Dörfler }
617393fceb5SAxel Dörfler 
618393fceb5SAxel Dörfler 
619393fceb5SAxel Dörfler void
620b0db552cSIngo Weinhold arch_vm_aspace_swap(struct VMAddressSpace *from, struct VMAddressSpace *to)
621393fceb5SAxel Dörfler {
6229a42ad7aSIngo Weinhold 	// This functions is only invoked when a userland thread is in the process
6239a42ad7aSIngo Weinhold 	// of dying. It switches to the kernel team and does whatever cleanup is
6249a42ad7aSIngo Weinhold 	// necessary (in case it is the team's main thread, it will delete the
6259a42ad7aSIngo Weinhold 	// team).
6269a42ad7aSIngo Weinhold 	// It is however not necessary to change the page directory. Userland team's
6279a42ad7aSIngo Weinhold 	// page directories include all kernel mappings as well. Furthermore our
6289a42ad7aSIngo Weinhold 	// arch specific translation map data objects are ref-counted, so they won't
6299a42ad7aSIngo Weinhold 	// go away as long as they are still used on any CPU.
630393fceb5SAxel Dörfler }
631393fceb5SAxel Dörfler 
632393fceb5SAxel Dörfler 
633393fceb5SAxel Dörfler bool
634393fceb5SAxel Dörfler arch_vm_supports_protection(uint32 protection)
635393fceb5SAxel Dörfler {
636393fceb5SAxel Dörfler 	// x86 always has the same read/write properties for userland and the
637393fceb5SAxel Dörfler 	// kernel.
638393fceb5SAxel Dörfler 	// That's why we do not support user-read/kernel-write access. While the
639393fceb5SAxel Dörfler 	// other way around is not supported either, we don't care in this case
640393fceb5SAxel Dörfler 	// and give the kernel full access.
641393fceb5SAxel Dörfler 	if ((protection & (B_READ_AREA | B_WRITE_AREA)) == B_READ_AREA
642393fceb5SAxel Dörfler 		&& protection & B_KERNEL_WRITE_AREA)
643393fceb5SAxel Dörfler 		return false;
644393fceb5SAxel Dörfler 
645393fceb5SAxel Dörfler 	return true;
646393fceb5SAxel Dörfler }
647393fceb5SAxel Dörfler 
648393fceb5SAxel Dörfler 
649393fceb5SAxel Dörfler void
650*a99eb6b5SIngo Weinhold arch_vm_unset_memory_type(struct VMArea *area)
651393fceb5SAxel Dörfler {
652393fceb5SAxel Dörfler 	if (area->memory_type == 0)
653393fceb5SAxel Dörfler 		return;
654393fceb5SAxel Dörfler 
655bb163c02SIngo Weinhold 	remove_memory_type_range(area->id);
656393fceb5SAxel Dörfler }
657393fceb5SAxel Dörfler 
658393fceb5SAxel Dörfler 
659393fceb5SAxel Dörfler status_t
660*a99eb6b5SIngo Weinhold arch_vm_set_memory_type(struct VMArea *area, addr_t physicalBase,
661393fceb5SAxel Dörfler 	uint32 type)
662393fceb5SAxel Dörfler {
663393fceb5SAxel Dörfler 	area->memory_type = type >> MEMORY_TYPE_SHIFT;
664bb163c02SIngo Weinhold 	return add_memory_type_range(area->id, physicalBase, area->size, type);
665393fceb5SAxel Dörfler }
666