1393fceb5SAxel Dörfler /*
2dac21d8bSIngo Weinhold * Copyright 2009-2010, 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
15dac21d8bSIngo Weinhold #include <algorithm>
16dac21d8bSIngo Weinhold #include <new>
17dac21d8bSIngo Weinhold
18393fceb5SAxel Dörfler #include <KernelExport.h>
1974785e79SIngo Weinhold
2045bd7bb3SIngo Weinhold #include <boot/kernel_args.h>
21393fceb5SAxel Dörfler #include <smp.h>
22393fceb5SAxel Dörfler #include <util/AutoLock.h>
23e50cf876SIngo Weinhold #include <vm/vm.h>
24e50cf876SIngo Weinhold #include <vm/vm_page.h>
25e50cf876SIngo Weinhold #include <vm/vm_priv.h>
26e50cf876SIngo Weinhold #include <vm/VMAddressSpace.h>
27f34a1dd5SIngo Weinhold #include <vm/VMArea.h>
28393fceb5SAxel Dörfler
29393fceb5SAxel Dörfler #include <arch/vm.h>
30393fceb5SAxel Dörfler #include <arch/int.h>
31393fceb5SAxel Dörfler #include <arch/cpu.h>
32393fceb5SAxel Dörfler
33393fceb5SAxel Dörfler #include <arch/x86/bios.h>
34393fceb5SAxel Dörfler
35393fceb5SAxel Dörfler
36393fceb5SAxel Dörfler //#define TRACE_ARCH_VM
37393fceb5SAxel Dörfler #ifdef TRACE_ARCH_VM
38393fceb5SAxel Dörfler # define TRACE(x) dprintf x
39393fceb5SAxel Dörfler #else
40393fceb5SAxel Dörfler # define TRACE(x) ;
41393fceb5SAxel Dörfler #endif
42393fceb5SAxel Dörfler
43dac21d8bSIngo Weinhold // 0: disabled, 1: some, 2: more
44dac21d8bSIngo Weinhold #define TRACE_MTRR_ARCH_VM 1
45dac21d8bSIngo Weinhold
46dac21d8bSIngo Weinhold #if TRACE_MTRR_ARCH_VM >= 1
474f893e39SJérôme Duval # define TRACE_MTRR(x...) dprintf(x)
484f893e39SJérôme Duval #else
494f893e39SJérôme Duval # define TRACE_MTRR(x...)
504f893e39SJérôme Duval #endif
514f893e39SJérôme Duval
52dac21d8bSIngo Weinhold #if TRACE_MTRR_ARCH_VM >= 2
53dac21d8bSIngo Weinhold # define TRACE_MTRR2(x...) dprintf(x)
54dac21d8bSIngo Weinhold #else
55dac21d8bSIngo Weinhold # define TRACE_MTRR2(x...)
56dac21d8bSIngo Weinhold #endif
57bb163c02SIngo Weinhold
58bb163c02SIngo Weinhold
59dac21d8bSIngo Weinhold void *gDmaAddress;
60bb163c02SIngo Weinhold
61bb163c02SIngo Weinhold
62c73d1301SMichael Lotz namespace {
63c73d1301SMichael Lotz
64dac21d8bSIngo Weinhold struct memory_type_range : DoublyLinkedListLinkImpl<memory_type_range> {
65bb163c02SIngo Weinhold uint64 base;
66bb163c02SIngo Weinhold uint64 size;
67bb163c02SIngo Weinhold uint32 type;
68bb163c02SIngo Weinhold area_id area;
69bb163c02SIngo Weinhold };
70bb163c02SIngo Weinhold
71393fceb5SAxel Dörfler
72dac21d8bSIngo Weinhold struct memory_type_range_point
73dac21d8bSIngo Weinhold : DoublyLinkedListLinkImpl<memory_type_range_point> {
74dac21d8bSIngo Weinhold uint64 address;
75dac21d8bSIngo Weinhold memory_type_range* range;
76393fceb5SAxel Dörfler
IsStart__anonb4926a8e0111::memory_type_range_point77dac21d8bSIngo Weinhold bool IsStart() const { return range->base == address; }
78bb163c02SIngo Weinhold
operator <__anonb4926a8e0111::memory_type_range_point79dac21d8bSIngo Weinhold bool operator<(const memory_type_range_point& other) const
80dac21d8bSIngo Weinhold {
81dac21d8bSIngo Weinhold return address < other.address;
82dac21d8bSIngo Weinhold }
83dac21d8bSIngo Weinhold };
84bb163c02SIngo Weinhold
85dac21d8bSIngo Weinhold
86fa0c1e96SIngo Weinhold struct update_mtrr_info {
87fa0c1e96SIngo Weinhold uint64 ignoreUncacheableSize;
88fa0c1e96SIngo Weinhold uint64 shortestUncacheableSize;
89fa0c1e96SIngo Weinhold };
90fa0c1e96SIngo Weinhold
91fa0c1e96SIngo Weinhold
92dac21d8bSIngo Weinhold typedef DoublyLinkedList<memory_type_range> MemoryTypeRangeList;
93dac21d8bSIngo Weinhold
94c73d1301SMichael Lotz } // namespace
95c73d1301SMichael Lotz
96c73d1301SMichael Lotz
97dac21d8bSIngo Weinhold static mutex sMemoryTypeLock = MUTEX_INITIALIZER("memory type ranges");
98dac21d8bSIngo Weinhold static MemoryTypeRangeList sMemoryTypeRanges;
99dac21d8bSIngo Weinhold static int32 sMemoryTypeRangeCount = 0;
100dac21d8bSIngo Weinhold
101dac21d8bSIngo Weinhold static const uint32 kMaxMemoryTypeRegisters = 32;
102bb163c02SIngo Weinhold static x86_mtrr_info sMemoryTypeRegisters[kMaxMemoryTypeRegisters];
103393fceb5SAxel Dörfler static uint32 sMemoryTypeRegisterCount;
104bb163c02SIngo Weinhold static uint32 sMemoryTypeRegistersUsed;
105bb163c02SIngo Weinhold
106dac21d8bSIngo Weinhold static memory_type_range* sTemporaryRanges = NULL;
107dac21d8bSIngo Weinhold static memory_type_range_point* sTemporaryRangePoints = NULL;
108dac21d8bSIngo Weinhold static int32 sTemporaryRangeCount = 0;
109dac21d8bSIngo Weinhold static int32 sTemporaryRangePointCount = 0;
110393fceb5SAxel Dörfler
111393fceb5SAxel Dörfler
112bb163c02SIngo Weinhold static void
set_mtrrs()113bb163c02SIngo Weinhold set_mtrrs()
114393fceb5SAxel Dörfler {
115dac21d8bSIngo Weinhold x86_set_mtrrs(IA32_MTR_WRITE_BACK, sMemoryTypeRegisters,
116dac21d8bSIngo Weinhold sMemoryTypeRegistersUsed);
117393fceb5SAxel Dörfler
118dac21d8bSIngo Weinhold #if TRACE_MTRR_ARCH_VM
119bb163c02SIngo Weinhold TRACE_MTRR("set MTRRs to:\n");
120bb163c02SIngo Weinhold for (uint32 i = 0; i < sMemoryTypeRegistersUsed; i++) {
121bb163c02SIngo Weinhold const x86_mtrr_info& info = sMemoryTypeRegisters[i];
122dac21d8bSIngo Weinhold TRACE_MTRR(" mtrr: %2" B_PRIu32 ": base: %#10" B_PRIx64 ", size: %#10"
123dac21d8bSIngo Weinhold B_PRIx64 ", type: %u\n", i, info.base, info.size,
124dac21d8bSIngo Weinhold info.type);
125393fceb5SAxel Dörfler }
126bb163c02SIngo Weinhold #endif
127393fceb5SAxel Dörfler }
128393fceb5SAxel Dörfler
129393fceb5SAxel Dörfler
130dac21d8bSIngo Weinhold static bool
add_used_mtrr(uint64 base,uint64 size,uint32 type)131bb163c02SIngo Weinhold add_used_mtrr(uint64 base, uint64 size, uint32 type)
132393fceb5SAxel Dörfler {
1338271b4a8SMichael Lotz switch (type) {
1345c1f2319SAugustin Cavalier case B_UNCACHED_MEMORY:
1358271b4a8SMichael Lotz type = IA32_MTR_UNCACHED;
1368271b4a8SMichael Lotz break;
1375c1f2319SAugustin Cavalier case B_WRITE_COMBINING_MEMORY:
1388271b4a8SMichael Lotz type = IA32_MTR_WRITE_COMBINING;
1398271b4a8SMichael Lotz break;
1405c1f2319SAugustin Cavalier case B_WRITE_THROUGH_MEMORY:
1418271b4a8SMichael Lotz type = IA32_MTR_WRITE_THROUGH;
1428271b4a8SMichael Lotz break;
1435c1f2319SAugustin Cavalier case B_WRITE_PROTECTED_MEMORY:
1448271b4a8SMichael Lotz type = IA32_MTR_WRITE_PROTECTED;
1458271b4a8SMichael Lotz break;
1465c1f2319SAugustin Cavalier case B_WRITE_BACK_MEMORY:
1478271b4a8SMichael Lotz type = IA32_MTR_WRITE_BACK;
1488271b4a8SMichael Lotz break;
1498271b4a8SMichael Lotz default:
1508271b4a8SMichael Lotz return false;
1518271b4a8SMichael Lotz }
1528271b4a8SMichael Lotz
153fa0c1e96SIngo Weinhold if (sMemoryTypeRegistersUsed == sMemoryTypeRegisterCount)
154dac21d8bSIngo Weinhold return false;
155393fceb5SAxel Dörfler
156dac21d8bSIngo Weinhold x86_mtrr_info& mtrr = sMemoryTypeRegisters[sMemoryTypeRegistersUsed++];
157dac21d8bSIngo Weinhold mtrr.base = base;
158dac21d8bSIngo Weinhold mtrr.size = size;
159dac21d8bSIngo Weinhold mtrr.type = type;
160dac21d8bSIngo Weinhold
161dac21d8bSIngo Weinhold return true;
162dac21d8bSIngo Weinhold }
163dac21d8bSIngo Weinhold
164dac21d8bSIngo Weinhold
165dac21d8bSIngo Weinhold static bool
add_mtrrs_for_range(uint64 base,uint64 size,uint32 type)166dac21d8bSIngo Weinhold add_mtrrs_for_range(uint64 base, uint64 size, uint32 type)
167dac21d8bSIngo Weinhold {
168dac21d8bSIngo Weinhold for (uint64 interval = B_PAGE_SIZE; size > 0; interval <<= 1) {
169dac21d8bSIngo Weinhold if ((base & interval) != 0) {
170dac21d8bSIngo Weinhold if (!add_used_mtrr(base, interval, type))
171dac21d8bSIngo Weinhold return false;
172dac21d8bSIngo Weinhold base += interval;
173affb4716SIngo Weinhold size -= interval;
174dac21d8bSIngo Weinhold }
175dac21d8bSIngo Weinhold
176affb4716SIngo Weinhold if ((size & interval) != 0) {
177affb4716SIngo Weinhold if (!add_used_mtrr(base + size - interval, interval, type))
178affb4716SIngo Weinhold return false;
179dac21d8bSIngo Weinhold size -= interval;
180dac21d8bSIngo Weinhold }
181dac21d8bSIngo Weinhold }
182dac21d8bSIngo Weinhold
183dac21d8bSIngo Weinhold return true;
184dac21d8bSIngo Weinhold }
185dac21d8bSIngo Weinhold
186dac21d8bSIngo Weinhold
187dac21d8bSIngo Weinhold static memory_type_range*
find_range(area_id areaID)188dac21d8bSIngo Weinhold find_range(area_id areaID)
189dac21d8bSIngo Weinhold {
190dac21d8bSIngo Weinhold for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator();
191dac21d8bSIngo Weinhold memory_type_range* range = it.Next();) {
192dac21d8bSIngo Weinhold if (range->area == areaID)
193dac21d8bSIngo Weinhold return range;
194dac21d8bSIngo Weinhold }
195dac21d8bSIngo Weinhold
196dac21d8bSIngo Weinhold return NULL;
197393fceb5SAxel Dörfler }
198393fceb5SAxel Dörfler
199393fceb5SAxel Dörfler
2004f893e39SJérôme Duval static void
optimize_memory_ranges(MemoryTypeRangeList & ranges,uint32 type,bool removeRanges)201dac21d8bSIngo Weinhold optimize_memory_ranges(MemoryTypeRangeList& ranges, uint32 type,
202dac21d8bSIngo Weinhold bool removeRanges)
2034f893e39SJérôme Duval {
204bb163c02SIngo Weinhold uint64 previousEnd = 0;
205dac21d8bSIngo Weinhold uint64 nextStart = 0;
206dac21d8bSIngo Weinhold MemoryTypeRangeList::Iterator it = ranges.GetIterator();
207dac21d8bSIngo Weinhold memory_type_range* range = it.Next();
208dac21d8bSIngo Weinhold while (range != NULL) {
209dac21d8bSIngo Weinhold if (range->type != type) {
210dac21d8bSIngo Weinhold previousEnd = range->base + range->size;
211dac21d8bSIngo Weinhold nextStart = 0;
212dac21d8bSIngo Weinhold range = it.Next();
213dac21d8bSIngo Weinhold continue;
214bb163c02SIngo Weinhold }
215bb163c02SIngo Weinhold
216dac21d8bSIngo Weinhold // find the start of the next range we cannot join this one with
217dac21d8bSIngo Weinhold if (nextStart == 0) {
218dac21d8bSIngo Weinhold MemoryTypeRangeList::Iterator nextIt = it;
219dac21d8bSIngo Weinhold while (memory_type_range* nextRange = nextIt.Next()) {
220dac21d8bSIngo Weinhold if (nextRange->type != range->type) {
221dac21d8bSIngo Weinhold nextStart = nextRange->base;
222dac21d8bSIngo Weinhold break;
223dac21d8bSIngo Weinhold }
224dac21d8bSIngo Weinhold }
225bb163c02SIngo Weinhold
226dac21d8bSIngo Weinhold if (nextStart == 0) {
227dac21d8bSIngo Weinhold // no upper limit -- set an artificial one, so we don't need to
228dac21d8bSIngo Weinhold // special case below
229dac21d8bSIngo Weinhold nextStart = (uint64)1 << 32;
230dac21d8bSIngo Weinhold }
231dac21d8bSIngo Weinhold }
232dac21d8bSIngo Weinhold
233dac21d8bSIngo Weinhold // Align the range's base and end to the greatest power of two possible.
234dac21d8bSIngo Weinhold // As long as we can align both without intersecting any differently
235dac21d8bSIngo Weinhold // range, we can extend the range without making it more complicated.
236dac21d8bSIngo Weinhold // Once one side hit a limit we need to be careful. We can still
237dac21d8bSIngo Weinhold // continue aligning the other side, if the range crosses the power of
238dac21d8bSIngo Weinhold // two boundary.
239dac21d8bSIngo Weinhold uint64 rangeBase = range->base;
240dac21d8bSIngo Weinhold uint64 rangeEnd = rangeBase + range->size;
241dac21d8bSIngo Weinhold uint64 interval = B_PAGE_SIZE * 2;
242dac21d8bSIngo Weinhold while (true) {
243dac21d8bSIngo Weinhold uint64 alignedBase = rangeBase & ~(interval - 1);
244dac21d8bSIngo Weinhold uint64 alignedEnd = (rangeEnd + interval - 1) & ~(interval - 1);
245dac21d8bSIngo Weinhold
246dac21d8bSIngo Weinhold if (alignedBase < previousEnd)
247dac21d8bSIngo Weinhold alignedBase += interval;
248dac21d8bSIngo Weinhold
249dac21d8bSIngo Weinhold if (alignedEnd > nextStart)
250dac21d8bSIngo Weinhold alignedEnd -= interval;
251dac21d8bSIngo Weinhold
252dac21d8bSIngo Weinhold if (alignedBase >= alignedEnd)
253dac21d8bSIngo Weinhold break;
254dac21d8bSIngo Weinhold
255dac21d8bSIngo Weinhold rangeBase = std::min(rangeBase, alignedBase);
256dac21d8bSIngo Weinhold rangeEnd = std::max(rangeEnd, alignedEnd);
257dac21d8bSIngo Weinhold
258dac21d8bSIngo Weinhold interval <<= 1;
259dac21d8bSIngo Weinhold }
260dac21d8bSIngo Weinhold
261dac21d8bSIngo Weinhold range->base = rangeBase;
262dac21d8bSIngo Weinhold range->size = rangeEnd - rangeBase;
263dac21d8bSIngo Weinhold
264dac21d8bSIngo Weinhold if (removeRanges)
265dac21d8bSIngo Weinhold it.Remove();
266dac21d8bSIngo Weinhold
267dac21d8bSIngo Weinhold previousEnd = rangeEnd;
268dac21d8bSIngo Weinhold
269dac21d8bSIngo Weinhold // Skip the subsequent ranges we have swallowed and possible cut one
270dac21d8bSIngo Weinhold // we now partially intersect with.
271dac21d8bSIngo Weinhold while ((range = it.Next()) != NULL) {
272dac21d8bSIngo Weinhold if (range->base >= rangeEnd)
273dac21d8bSIngo Weinhold break;
274dac21d8bSIngo Weinhold
275dac21d8bSIngo Weinhold if (range->base + range->size > rangeEnd) {
276dac21d8bSIngo Weinhold // we partially intersect -- cut the range
277dac21d8bSIngo Weinhold range->size = range->base + range->size - rangeEnd;
278dac21d8bSIngo Weinhold range->base = rangeEnd;
279dac21d8bSIngo Weinhold break;
280dac21d8bSIngo Weinhold }
281dac21d8bSIngo Weinhold
282dac21d8bSIngo Weinhold // we have swallowed this range completely
283dac21d8bSIngo Weinhold range->size = 0;
284dac21d8bSIngo Weinhold it.Remove();
285dac21d8bSIngo Weinhold }
286dac21d8bSIngo Weinhold }
287dac21d8bSIngo Weinhold }
288dac21d8bSIngo Weinhold
289dac21d8bSIngo Weinhold
290dac21d8bSIngo Weinhold static bool
ensure_temporary_ranges_space(int32 count)291dac21d8bSIngo Weinhold ensure_temporary_ranges_space(int32 count)
292dac21d8bSIngo Weinhold {
293dac21d8bSIngo Weinhold if (sTemporaryRangeCount >= count && sTemporaryRangePointCount >= count)
294dac21d8bSIngo Weinhold return true;
295dac21d8bSIngo Weinhold
296dac21d8bSIngo Weinhold // round count to power of 2
297dac21d8bSIngo Weinhold int32 unalignedCount = count;
298dac21d8bSIngo Weinhold count = 8;
299dac21d8bSIngo Weinhold while (count < unalignedCount)
300dac21d8bSIngo Weinhold count <<= 1;
301dac21d8bSIngo Weinhold
302dac21d8bSIngo Weinhold // resize ranges array
303dac21d8bSIngo Weinhold if (sTemporaryRangeCount < count) {
304dac21d8bSIngo Weinhold memory_type_range* ranges = new(std::nothrow) memory_type_range[count];
305dac21d8bSIngo Weinhold if (ranges == NULL)
306dac21d8bSIngo Weinhold return false;
307dac21d8bSIngo Weinhold
308dac21d8bSIngo Weinhold delete[] sTemporaryRanges;
309dac21d8bSIngo Weinhold
310dac21d8bSIngo Weinhold sTemporaryRanges = ranges;
311dac21d8bSIngo Weinhold sTemporaryRangeCount = count;
312dac21d8bSIngo Weinhold }
313dac21d8bSIngo Weinhold
314dac21d8bSIngo Weinhold // resize points array
315dac21d8bSIngo Weinhold if (sTemporaryRangePointCount < count) {
316dac21d8bSIngo Weinhold memory_type_range_point* points
317dac21d8bSIngo Weinhold = new(std::nothrow) memory_type_range_point[count];
318dac21d8bSIngo Weinhold if (points == NULL)
319dac21d8bSIngo Weinhold return false;
320dac21d8bSIngo Weinhold
321dac21d8bSIngo Weinhold delete[] sTemporaryRangePoints;
322dac21d8bSIngo Weinhold
323dac21d8bSIngo Weinhold sTemporaryRangePoints = points;
324dac21d8bSIngo Weinhold sTemporaryRangePointCount = count;
325dac21d8bSIngo Weinhold }
326dac21d8bSIngo Weinhold
327dac21d8bSIngo Weinhold return true;
328dac21d8bSIngo Weinhold }
329dac21d8bSIngo Weinhold
330dac21d8bSIngo Weinhold
3318271b4a8SMichael Lotz static status_t
update_mtrrs(update_mtrr_info & updateInfo)332fa0c1e96SIngo Weinhold update_mtrrs(update_mtrr_info& updateInfo)
333dac21d8bSIngo Weinhold {
334dac21d8bSIngo Weinhold // resize the temporary points/ranges arrays, if necessary
335dac21d8bSIngo Weinhold if (!ensure_temporary_ranges_space(sMemoryTypeRangeCount * 2))
336dac21d8bSIngo Weinhold return B_NO_MEMORY;
337dac21d8bSIngo Weinhold
338dac21d8bSIngo Weinhold // get the range points and sort them
339dac21d8bSIngo Weinhold memory_type_range_point* rangePoints = sTemporaryRangePoints;
340dac21d8bSIngo Weinhold int32 pointCount = 0;
341dac21d8bSIngo Weinhold for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator();
342dac21d8bSIngo Weinhold memory_type_range* range = it.Next();) {
3435c1f2319SAugustin Cavalier if (range->type == B_UNCACHED_MEMORY) {
344fa0c1e96SIngo Weinhold // Ignore uncacheable ranges below a certain size, if requested.
345fa0c1e96SIngo Weinhold // Since we always enforce uncacheability via the PTE attributes,
346fa0c1e96SIngo Weinhold // this is no problem (though not recommended for performance
347fa0c1e96SIngo Weinhold // reasons).
348fa0c1e96SIngo Weinhold if (range->size <= updateInfo.ignoreUncacheableSize)
349fa0c1e96SIngo Weinhold continue;
350fa0c1e96SIngo Weinhold if (range->size < updateInfo.shortestUncacheableSize)
351fa0c1e96SIngo Weinhold updateInfo.shortestUncacheableSize = range->size;
352fa0c1e96SIngo Weinhold }
353fa0c1e96SIngo Weinhold
354dac21d8bSIngo Weinhold rangePoints[pointCount].address = range->base;
355dac21d8bSIngo Weinhold rangePoints[pointCount++].range = range;
356dac21d8bSIngo Weinhold rangePoints[pointCount].address = range->base + range->size;
357dac21d8bSIngo Weinhold rangePoints[pointCount++].range = range;
358dac21d8bSIngo Weinhold }
359dac21d8bSIngo Weinhold
360dac21d8bSIngo Weinhold std::sort(rangePoints, rangePoints + pointCount);
361dac21d8bSIngo Weinhold
362dac21d8bSIngo Weinhold #if TRACE_MTRR_ARCH_VM >= 2
363dac21d8bSIngo Weinhold TRACE_MTRR2("memory type range points:\n");
364dac21d8bSIngo Weinhold for (int32 i = 0; i < pointCount; i++) {
365dac21d8bSIngo Weinhold TRACE_MTRR2("%12" B_PRIx64 " (%p)\n", rangePoints[i].address,
366dac21d8bSIngo Weinhold rangePoints[i].range);
367dac21d8bSIngo Weinhold }
368dac21d8bSIngo Weinhold #endif
369dac21d8bSIngo Weinhold
370dac21d8bSIngo Weinhold // Compute the effective ranges. When ranges overlap, we go with the
371dac21d8bSIngo Weinhold // stricter requirement. The types are not necessarily totally ordered, so
372dac21d8bSIngo Weinhold // the order we use below is not always correct. To keep it simple we
373dac21d8bSIngo Weinhold // consider it the reponsibility of the callers not to define overlapping
374dac21d8bSIngo Weinhold // memory ranges with uncomparable types.
375dac21d8bSIngo Weinhold
376dac21d8bSIngo Weinhold memory_type_range* ranges = sTemporaryRanges;
377dac21d8bSIngo Weinhold typedef DoublyLinkedList<memory_type_range_point> PointList;
378dac21d8bSIngo Weinhold PointList pendingPoints;
379dac21d8bSIngo Weinhold memory_type_range* activeRange = NULL;
380dac21d8bSIngo Weinhold int32 rangeCount = 0;
381dac21d8bSIngo Weinhold
382dac21d8bSIngo Weinhold for (int32 i = 0; i < pointCount; i++) {
383dac21d8bSIngo Weinhold memory_type_range_point* point = &rangePoints[i];
384dac21d8bSIngo Weinhold bool terminateRange = false;
385dac21d8bSIngo Weinhold if (point->IsStart()) {
386dac21d8bSIngo Weinhold // a range start point
387dac21d8bSIngo Weinhold pendingPoints.Add(point);
388dac21d8bSIngo Weinhold if (activeRange != NULL && activeRange->type > point->range->type)
389dac21d8bSIngo Weinhold terminateRange = true;
390dac21d8bSIngo Weinhold } else {
391dac21d8bSIngo Weinhold // a range end point -- remove the pending start point
392dac21d8bSIngo Weinhold for (PointList::Iterator it = pendingPoints.GetIterator();
393dac21d8bSIngo Weinhold memory_type_range_point* pendingPoint = it.Next();) {
394dac21d8bSIngo Weinhold if (pendingPoint->range == point->range) {
395dac21d8bSIngo Weinhold it.Remove();
396dac21d8bSIngo Weinhold break;
397dac21d8bSIngo Weinhold }
398dac21d8bSIngo Weinhold }
399dac21d8bSIngo Weinhold
400dac21d8bSIngo Weinhold if (point->range == activeRange)
401dac21d8bSIngo Weinhold terminateRange = true;
402dac21d8bSIngo Weinhold }
403dac21d8bSIngo Weinhold
404dac21d8bSIngo Weinhold if (terminateRange) {
405dac21d8bSIngo Weinhold ranges[rangeCount].size = point->address - ranges[rangeCount].base;
406dac21d8bSIngo Weinhold rangeCount++;
407dac21d8bSIngo Weinhold activeRange = NULL;
408dac21d8bSIngo Weinhold }
409dac21d8bSIngo Weinhold
410dac21d8bSIngo Weinhold if (activeRange != NULL || pendingPoints.IsEmpty())
411dac21d8bSIngo Weinhold continue;
412dac21d8bSIngo Weinhold
413dac21d8bSIngo Weinhold // we need to start a new range -- find the strictest pending range
414dac21d8bSIngo Weinhold for (PointList::Iterator it = pendingPoints.GetIterator();
415dac21d8bSIngo Weinhold memory_type_range_point* pendingPoint = it.Next();) {
416dac21d8bSIngo Weinhold memory_type_range* pendingRange = pendingPoint->range;
417dac21d8bSIngo Weinhold if (activeRange == NULL || activeRange->type > pendingRange->type)
418dac21d8bSIngo Weinhold activeRange = pendingRange;
419dac21d8bSIngo Weinhold }
420dac21d8bSIngo Weinhold
421dac21d8bSIngo Weinhold memory_type_range* previousRange = rangeCount > 0
422dac21d8bSIngo Weinhold ? &ranges[rangeCount - 1] : NULL;
423dac21d8bSIngo Weinhold if (previousRange == NULL || previousRange->type != activeRange->type
424dac21d8bSIngo Weinhold || previousRange->base + previousRange->size
425dac21d8bSIngo Weinhold < activeRange->base) {
426dac21d8bSIngo Weinhold // we can't join with the previous range -- add a new one
427dac21d8bSIngo Weinhold ranges[rangeCount].base = point->address;
428dac21d8bSIngo Weinhold ranges[rangeCount].type = activeRange->type;
429dac21d8bSIngo Weinhold } else
430dac21d8bSIngo Weinhold rangeCount--;
431dac21d8bSIngo Weinhold }
432dac21d8bSIngo Weinhold
433dac21d8bSIngo Weinhold #if TRACE_MTRR_ARCH_VM >= 2
434dac21d8bSIngo Weinhold TRACE_MTRR2("effective memory type ranges:\n");
435dac21d8bSIngo Weinhold for (int32 i = 0; i < rangeCount; i++) {
436dac21d8bSIngo Weinhold TRACE_MTRR2("%12" B_PRIx64 " - %12" B_PRIx64 ": %" B_PRIu32 "\n",
437dac21d8bSIngo Weinhold ranges[i].base, ranges[i].base + ranges[i].size, ranges[i].type);
438dac21d8bSIngo Weinhold }
439dac21d8bSIngo Weinhold #endif
440dac21d8bSIngo Weinhold
441dac21d8bSIngo Weinhold // Extend ranges to be more MTRR-friendly. A range is MTRR friendly, when it
442dac21d8bSIngo Weinhold // has a power of two size and a base address aligned to the size. For
443dac21d8bSIngo Weinhold // ranges without this property we need more than one MTRR. We improve
444dac21d8bSIngo Weinhold // MTRR-friendliness by aligning a range's base and end address to the
445dac21d8bSIngo Weinhold // greatest power of two (base rounded down, end up) such that the extended
446dac21d8bSIngo Weinhold // range does not intersect with any other differently typed range. We join
447dac21d8bSIngo Weinhold // equally typed ranges, if possible. There are two exceptions to the
448dac21d8bSIngo Weinhold // intersection requirement: Uncached ranges may intersect with any other
449dac21d8bSIngo Weinhold // range; the resulting type will still be uncached. Hence we can ignore
450fa0c1e96SIngo Weinhold // uncached ranges when extending the other ranges. Write-through ranges may
451dac21d8bSIngo Weinhold // intersect with write-back ranges; the resulting type will be
452dac21d8bSIngo Weinhold // write-through. Hence we can ignore write-through ranges when extending
453dac21d8bSIngo Weinhold // write-back ranges.
454dac21d8bSIngo Weinhold
455dac21d8bSIngo Weinhold MemoryTypeRangeList rangeList;
456dac21d8bSIngo Weinhold for (int32 i = 0; i < rangeCount; i++)
457dac21d8bSIngo Weinhold rangeList.Add(&ranges[i]);
458dac21d8bSIngo Weinhold
459dac21d8bSIngo Weinhold static const uint32 kMemoryTypes[] = {
4605c1f2319SAugustin Cavalier B_UNCACHED_MEMORY,
4615c1f2319SAugustin Cavalier B_WRITE_COMBINING_MEMORY,
4625c1f2319SAugustin Cavalier B_WRITE_PROTECTED_MEMORY,
4635c1f2319SAugustin Cavalier B_WRITE_THROUGH_MEMORY,
4645c1f2319SAugustin Cavalier B_WRITE_BACK_MEMORY
465dac21d8bSIngo Weinhold };
4665c1f2319SAugustin Cavalier static const int32 kMemoryTypeCount = B_COUNT_OF(kMemoryTypes);
467dac21d8bSIngo Weinhold
468dac21d8bSIngo Weinhold for (int32 i = 0; i < kMemoryTypeCount; i++) {
469dac21d8bSIngo Weinhold uint32 type = kMemoryTypes[i];
470dac21d8bSIngo Weinhold
471dac21d8bSIngo Weinhold // Remove uncached and write-through ranges after processing them. This
472dac21d8bSIngo Weinhold // let's us leverage their intersection property with any other
473dac21d8bSIngo Weinhold // respectively write-back ranges.
4745c1f2319SAugustin Cavalier bool removeRanges = type == B_UNCACHED_MEMORY || type == B_WRITE_THROUGH_MEMORY;
475dac21d8bSIngo Weinhold
476dac21d8bSIngo Weinhold optimize_memory_ranges(rangeList, type, removeRanges);
477dac21d8bSIngo Weinhold }
478dac21d8bSIngo Weinhold
479dac21d8bSIngo Weinhold #if TRACE_MTRR_ARCH_VM >= 2
480dac21d8bSIngo Weinhold TRACE_MTRR2("optimized memory type ranges:\n");
481dac21d8bSIngo Weinhold for (int32 i = 0; i < rangeCount; i++) {
482dac21d8bSIngo Weinhold if (ranges[i].size > 0) {
483dac21d8bSIngo Weinhold TRACE_MTRR2("%12" B_PRIx64 " - %12" B_PRIx64 ": %" B_PRIu32 "\n",
484dac21d8bSIngo Weinhold ranges[i].base, ranges[i].base + ranges[i].size,
485dac21d8bSIngo Weinhold ranges[i].type);
486dac21d8bSIngo Weinhold }
487dac21d8bSIngo Weinhold }
488dac21d8bSIngo Weinhold #endif
489dac21d8bSIngo Weinhold
490dac21d8bSIngo Weinhold // compute the mtrrs from the ranges
491bb163c02SIngo Weinhold sMemoryTypeRegistersUsed = 0;
492dac21d8bSIngo Weinhold for (int32 i = 0; i < kMemoryTypeCount; i++) {
493dac21d8bSIngo Weinhold uint32 type = kMemoryTypes[i];
494bb163c02SIngo Weinhold
495dac21d8bSIngo Weinhold // skip write-back ranges -- that'll be the default type anyway
4965c1f2319SAugustin Cavalier if (type == B_WRITE_BACK_MEMORY)
497dac21d8bSIngo Weinhold continue;
498dac21d8bSIngo Weinhold
499dac21d8bSIngo Weinhold for (int32 i = 0; i < rangeCount; i++) {
500dac21d8bSIngo Weinhold if (ranges[i].size == 0 || ranges[i].type != type)
501dac21d8bSIngo Weinhold continue;
502dac21d8bSIngo Weinhold
503fa0c1e96SIngo Weinhold if (!add_mtrrs_for_range(ranges[i].base, ranges[i].size, type))
504fa0c1e96SIngo Weinhold return B_BUSY;
505dac21d8bSIngo Weinhold }
506bb163c02SIngo Weinhold }
507bb163c02SIngo Weinhold
508bb163c02SIngo Weinhold set_mtrrs();
509bb163c02SIngo Weinhold
510bb163c02SIngo Weinhold return B_OK;
511bb163c02SIngo Weinhold }
512bb163c02SIngo Weinhold
513bb163c02SIngo Weinhold
5148271b4a8SMichael Lotz static status_t
update_mtrrs()515fa0c1e96SIngo Weinhold update_mtrrs()
516fa0c1e96SIngo Weinhold {
517fa0c1e96SIngo Weinhold // Until we know how many MTRRs we have, pretend everything is OK.
518fa0c1e96SIngo Weinhold if (sMemoryTypeRegisterCount == 0)
519fa0c1e96SIngo Weinhold return B_OK;
520fa0c1e96SIngo Weinhold
521fa0c1e96SIngo Weinhold update_mtrr_info updateInfo;
522fa0c1e96SIngo Weinhold updateInfo.ignoreUncacheableSize = 0;
523fa0c1e96SIngo Weinhold
524fa0c1e96SIngo Weinhold while (true) {
525fa0c1e96SIngo Weinhold TRACE_MTRR2("update_mtrrs(): Trying with ignoreUncacheableSize %#"
526fa0c1e96SIngo Weinhold B_PRIx64 ".\n", updateInfo.ignoreUncacheableSize);
527fa0c1e96SIngo Weinhold
528fa0c1e96SIngo Weinhold updateInfo.shortestUncacheableSize = ~(uint64)0;
529fa0c1e96SIngo Weinhold status_t error = update_mtrrs(updateInfo);
530fa0c1e96SIngo Weinhold if (error != B_BUSY) {
531fa0c1e96SIngo Weinhold if (error == B_OK && updateInfo.ignoreUncacheableSize > 0) {
532fa0c1e96SIngo Weinhold TRACE_MTRR("update_mtrrs(): Succeeded setting MTRRs after "
533fa0c1e96SIngo Weinhold "ignoring uncacheable ranges up to size %#" B_PRIx64 ".\n",
534fa0c1e96SIngo Weinhold updateInfo.ignoreUncacheableSize);
535fa0c1e96SIngo Weinhold }
536fa0c1e96SIngo Weinhold return error;
537fa0c1e96SIngo Weinhold }
538fa0c1e96SIngo Weinhold
539fa0c1e96SIngo Weinhold // Not enough MTRRs. Retry with less uncacheable ranges.
540fa0c1e96SIngo Weinhold if (updateInfo.shortestUncacheableSize == ~(uint64)0) {
541fa0c1e96SIngo Weinhold // Ugh, even without any uncacheable ranges the available MTRRs do
542fa0c1e96SIngo Weinhold // not suffice.
543fa0c1e96SIngo Weinhold panic("update_mtrrs(): Out of MTRRs!");
544fa0c1e96SIngo Weinhold return B_BUSY;
545fa0c1e96SIngo Weinhold }
546fa0c1e96SIngo Weinhold
547fa0c1e96SIngo Weinhold ASSERT(updateInfo.ignoreUncacheableSize
548fa0c1e96SIngo Weinhold < updateInfo.shortestUncacheableSize);
549fa0c1e96SIngo Weinhold
550fa0c1e96SIngo Weinhold updateInfo.ignoreUncacheableSize = updateInfo.shortestUncacheableSize;
551fa0c1e96SIngo Weinhold }
552fa0c1e96SIngo Weinhold }
553fa0c1e96SIngo Weinhold
554fa0c1e96SIngo Weinhold
555bb163c02SIngo Weinhold static status_t
add_memory_type_range(area_id areaID,uint64 base,uint64 size,uint32 type,uint32 * effectiveType)5568271b4a8SMichael Lotz add_memory_type_range(area_id areaID, uint64 base, uint64 size, uint32 type,
5578271b4a8SMichael Lotz uint32 *effectiveType)
558bb163c02SIngo Weinhold {
559393fceb5SAxel Dörfler if (type == 0)
560393fceb5SAxel Dörfler return B_OK;
561393fceb5SAxel Dörfler
562b5d23373SAugustin Cavalier TRACE_MTRR2("add_memory_type_range(%" B_PRId32 ", %#" B_PRIx64 ", %#"
563dac21d8bSIngo Weinhold B_PRIx64 ", %" B_PRIu32 ")\n", areaID, base, size, type);
564393fceb5SAxel Dörfler
565bb163c02SIngo Weinhold MutexLocker locker(sMemoryTypeLock);
566bb163c02SIngo Weinhold
5678271b4a8SMichael Lotz for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator();
5688271b4a8SMichael Lotz memory_type_range* range = it.Next(); ) {
5698271b4a8SMichael Lotz
5708271b4a8SMichael Lotz if (range->area == areaID || range->type == type
5718271b4a8SMichael Lotz || base + size <= range->base
5728271b4a8SMichael Lotz || base >= range->base + range->size) {
5738271b4a8SMichael Lotz continue;
5748271b4a8SMichael Lotz }
5758271b4a8SMichael Lotz
576*95d8739fSAugustin Cavalier if (range->area == -1 && !x86_use_pat()) {
577*95d8739fSAugustin Cavalier // Physical memory range in MTRRs; permit overlapping.
578*95d8739fSAugustin Cavalier continue;
579*95d8739fSAugustin Cavalier }
580*95d8739fSAugustin Cavalier
5818271b4a8SMichael Lotz if (effectiveType != NULL) {
5828271b4a8SMichael Lotz type = *effectiveType = range->type;
5838271b4a8SMichael Lotz effectiveType = NULL;
5848271b4a8SMichael Lotz
5858271b4a8SMichael Lotz dprintf("assuming memory type %" B_PRIx32 " for overlapping %#"
5868271b4a8SMichael Lotz B_PRIx64 ", %#" B_PRIx64 " area %" B_PRId32 " from existing %#"
5878271b4a8SMichael Lotz B_PRIx64 ", %#" B_PRIx64 " area %" B_PRId32 "\n", type,
5888271b4a8SMichael Lotz base, size, areaID, range->base, range->size, range->area);
5898271b4a8SMichael Lotz continue;
5908271b4a8SMichael Lotz }
5918271b4a8SMichael Lotz
5928271b4a8SMichael Lotz (KDEBUG ? panic : dprintf)("incompatible overlapping memory %#" B_PRIx64
5938271b4a8SMichael Lotz ", %#" B_PRIx64 " type %" B_PRIx32 " area %" B_PRId32
5948271b4a8SMichael Lotz " with existing %#" B_PRIx64 ", %#" B_PRIx64 " type %" B_PRIx32
5958271b4a8SMichael Lotz " area %" B_PRId32 "\n", base, size, type, areaID, range->base,
5968271b4a8SMichael Lotz range->size, range->type, range->area);
5978271b4a8SMichael Lotz return B_BUSY;
5988271b4a8SMichael Lotz }
5998271b4a8SMichael Lotz
600dac21d8bSIngo Weinhold memory_type_range* range = areaID >= 0 ? find_range(areaID) : NULL;
601dac21d8bSIngo Weinhold int32 oldRangeType = -1;
602dac21d8bSIngo Weinhold if (range != NULL) {
603dac21d8bSIngo Weinhold if (range->base != base || range->size != size)
604393fceb5SAxel Dörfler return B_BAD_VALUE;
605dac21d8bSIngo Weinhold if (range->type == type)
606393fceb5SAxel Dörfler return B_OK;
607dac21d8bSIngo Weinhold
608dac21d8bSIngo Weinhold oldRangeType = range->type;
609dac21d8bSIngo Weinhold range->type = type;
610dac21d8bSIngo Weinhold } else {
611dac21d8bSIngo Weinhold range = new(std::nothrow) memory_type_range;
612dac21d8bSIngo Weinhold if (range == NULL)
613dac21d8bSIngo Weinhold return B_NO_MEMORY;
614dac21d8bSIngo Weinhold
615dac21d8bSIngo Weinhold range->area = areaID;
616dac21d8bSIngo Weinhold range->base = base;
617dac21d8bSIngo Weinhold range->size = size;
618dac21d8bSIngo Weinhold range->type = type;
619dac21d8bSIngo Weinhold sMemoryTypeRanges.Add(range);
620dac21d8bSIngo Weinhold sMemoryTypeRangeCount++;
621393fceb5SAxel Dörfler }
622393fceb5SAxel Dörfler
623dac21d8bSIngo Weinhold status_t error = update_mtrrs();
624dac21d8bSIngo Weinhold if (error != B_OK) {
625dac21d8bSIngo Weinhold // revert the addition of the range/change of its type
626dac21d8bSIngo Weinhold if (oldRangeType < 0) {
627dac21d8bSIngo Weinhold sMemoryTypeRanges.Remove(range);
628dac21d8bSIngo Weinhold sMemoryTypeRangeCount--;
629dac21d8bSIngo Weinhold delete range;
630dac21d8bSIngo Weinhold } else
631dac21d8bSIngo Weinhold range->type = oldRangeType;
632393fceb5SAxel Dörfler
633dac21d8bSIngo Weinhold update_mtrrs();
634bb163c02SIngo Weinhold return error;
635bb163c02SIngo Weinhold }
6364f893e39SJérôme Duval
637dac21d8bSIngo Weinhold return B_OK;
638dac21d8bSIngo Weinhold }
639dac21d8bSIngo Weinhold
6404f893e39SJérôme Duval
6414f893e39SJérôme Duval static void
remove_memory_type_range(area_id areaID)642bb163c02SIngo Weinhold remove_memory_type_range(area_id areaID)
6434f893e39SJérôme Duval {
644bb163c02SIngo Weinhold MutexLocker locker(sMemoryTypeLock);
645bb163c02SIngo Weinhold
646dac21d8bSIngo Weinhold memory_type_range* range = find_range(areaID);
647dac21d8bSIngo Weinhold if (range != NULL) {
648b5d23373SAugustin Cavalier TRACE_MTRR2("remove_memory_type_range(%" B_PRId32 ", %#" B_PRIx64 ", %#"
649dac21d8bSIngo Weinhold B_PRIx64 ", %" B_PRIu32 ")\n", range->area, range->base,
650dac21d8bSIngo Weinhold range->size, range->type);
651dac21d8bSIngo Weinhold
652dac21d8bSIngo Weinhold sMemoryTypeRanges.Remove(range);
653dac21d8bSIngo Weinhold sMemoryTypeRangeCount--;
654dac21d8bSIngo Weinhold delete range;
655dac21d8bSIngo Weinhold
656dac21d8bSIngo Weinhold update_mtrrs();
657dac21d8bSIngo Weinhold } else {
658dac21d8bSIngo Weinhold dprintf("remove_memory_type_range(): no range known for area %" B_PRId32
659dac21d8bSIngo Weinhold "\n", areaID);
6604f893e39SJérôme Duval }
6614f893e39SJérôme Duval }
6624f893e39SJérôme Duval
6634f893e39SJérôme Duval
66444ea1250SMichael Lotz static const char *
memory_type_to_string(uint32 type)66544ea1250SMichael Lotz memory_type_to_string(uint32 type)
66644ea1250SMichael Lotz {
66744ea1250SMichael Lotz switch (type) {
6685c1f2319SAugustin Cavalier case B_UNCACHED_MEMORY:
66944ea1250SMichael Lotz return "uncacheable";
6705c1f2319SAugustin Cavalier case B_WRITE_COMBINING_MEMORY:
67144ea1250SMichael Lotz return "write combining";
6725c1f2319SAugustin Cavalier case B_WRITE_THROUGH_MEMORY:
67344ea1250SMichael Lotz return "write-through";
6745c1f2319SAugustin Cavalier case B_WRITE_PROTECTED_MEMORY:
67544ea1250SMichael Lotz return "write-protected";
6765c1f2319SAugustin Cavalier case B_WRITE_BACK_MEMORY:
67744ea1250SMichael Lotz return "write-back";
67844ea1250SMichael Lotz default:
67944ea1250SMichael Lotz return "unknown";
68044ea1250SMichael Lotz }
68144ea1250SMichael Lotz }
68244ea1250SMichael Lotz
68344ea1250SMichael Lotz
68444ea1250SMichael Lotz static int
dump_memory_type_ranges(int argc,char ** argv)68544ea1250SMichael Lotz dump_memory_type_ranges(int argc, char **argv)
68644ea1250SMichael Lotz {
68744ea1250SMichael Lotz kprintf(
68844ea1250SMichael Lotz "start end size area type\n");
68944ea1250SMichael Lotz
69044ea1250SMichael Lotz for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator();
69144ea1250SMichael Lotz memory_type_range* range = it.Next();) {
69244ea1250SMichael Lotz
69344ea1250SMichael Lotz kprintf("%#16" B_PRIx64 " %#16" B_PRIx64 " %#16" B_PRIx64 " % 8"
69444ea1250SMichael Lotz B_PRId32 " %#" B_PRIx32 " %s\n", range->base,
69544ea1250SMichael Lotz range->base + range->size, range->size, range->area, range->type,
69644ea1250SMichael Lotz memory_type_to_string(range->type));
69744ea1250SMichael Lotz }
69844ea1250SMichael Lotz
69944ea1250SMichael Lotz return 0;
70044ea1250SMichael Lotz }
70144ea1250SMichael Lotz
70244ea1250SMichael Lotz
703393fceb5SAxel Dörfler // #pragma mark -
704393fceb5SAxel Dörfler
705393fceb5SAxel Dörfler
706393fceb5SAxel Dörfler status_t
arch_vm_init(kernel_args * args)707393fceb5SAxel Dörfler arch_vm_init(kernel_args *args)
708393fceb5SAxel Dörfler {
709393fceb5SAxel Dörfler TRACE(("arch_vm_init: entry\n"));
710393fceb5SAxel Dörfler return 0;
711393fceb5SAxel Dörfler }
712393fceb5SAxel Dörfler
713393fceb5SAxel Dörfler
714393fceb5SAxel Dörfler /*! Marks DMA region as in-use, and maps it into the kernel space */
715393fceb5SAxel Dörfler status_t
arch_vm_init_post_area(kernel_args * args)716393fceb5SAxel Dörfler arch_vm_init_post_area(kernel_args *args)
717393fceb5SAxel Dörfler {
718393fceb5SAxel Dörfler area_id id;
719393fceb5SAxel Dörfler
720393fceb5SAxel Dörfler TRACE(("arch_vm_init_post_area: entry\n"));
721393fceb5SAxel Dörfler
722393fceb5SAxel Dörfler // account for DMA area and mark the pages unusable
723393fceb5SAxel Dörfler vm_mark_page_range_inuse(0x0, 0xa0000 / B_PAGE_SIZE);
724393fceb5SAxel Dörfler
725393fceb5SAxel Dörfler // map 0 - 0xa0000 directly
72664d79effSIngo Weinhold id = map_physical_memory("dma_region", 0x0, 0xa0000,
7275c1f2319SAugustin Cavalier B_ANY_KERNEL_ADDRESS | B_WRITE_BACK_MEMORY,
728dac21d8bSIngo Weinhold B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, &gDmaAddress);
729393fceb5SAxel Dörfler if (id < 0) {
730393fceb5SAxel Dörfler panic("arch_vm_init_post_area: unable to map dma region\n");
731393fceb5SAxel Dörfler return B_NO_MEMORY;
732393fceb5SAxel Dörfler }
733393fceb5SAxel Dörfler
73444ea1250SMichael Lotz add_debugger_command_etc("memory_type_ranges", &dump_memory_type_ranges,
73544ea1250SMichael Lotz "List all configured memory type ranges",
73644ea1250SMichael Lotz "\n"
73744ea1250SMichael Lotz "Lists all memory type ranges with their types and areas.\n", 0);
73844ea1250SMichael Lotz
7394988ca58SAlex Smith #ifndef __x86_64__
740393fceb5SAxel Dörfler return bios_init();
7414988ca58SAlex Smith #else
7424988ca58SAlex Smith return B_OK;
7434988ca58SAlex Smith #endif
744393fceb5SAxel Dörfler }
745393fceb5SAxel Dörfler
746393fceb5SAxel Dörfler
747393fceb5SAxel Dörfler /*! Gets rid of all yet unmapped (and therefore now unused) page tables */
748393fceb5SAxel Dörfler status_t
arch_vm_init_end(kernel_args * args)749393fceb5SAxel Dörfler arch_vm_init_end(kernel_args *args)
750393fceb5SAxel Dörfler {
751393fceb5SAxel Dörfler TRACE(("arch_vm_init_endvm: entry\n"));
752393fceb5SAxel Dörfler
753393fceb5SAxel Dörfler // throw away anything in the kernel_args.pgtable[] that's not yet mapped
754cc248cf2SAlex Smith vm_free_unused_boot_loader_range(KERNEL_LOAD_BASE,
755cc248cf2SAlex Smith args->arch_args.virtual_end - KERNEL_LOAD_BASE);
756393fceb5SAxel Dörfler
757393fceb5SAxel Dörfler return B_OK;
758393fceb5SAxel Dörfler }
759393fceb5SAxel Dörfler
760393fceb5SAxel Dörfler
761393fceb5SAxel Dörfler status_t
arch_vm_init_post_modules(kernel_args * args)762393fceb5SAxel Dörfler arch_vm_init_post_modules(kernel_args *args)
763393fceb5SAxel Dörfler {
764393fceb5SAxel Dörfler // the x86 CPU modules are now accessible
765393fceb5SAxel Dörfler
766393fceb5SAxel Dörfler sMemoryTypeRegisterCount = x86_count_mtrrs();
76753ff60f2SMichael Lotz if (sMemoryTypeRegisterCount == 0)
76853ff60f2SMichael Lotz return B_OK;
769393fceb5SAxel Dörfler
770393fceb5SAxel Dörfler // not very likely, but play safe here
771393fceb5SAxel Dörfler if (sMemoryTypeRegisterCount > kMaxMemoryTypeRegisters)
772393fceb5SAxel Dörfler sMemoryTypeRegisterCount = kMaxMemoryTypeRegisters;
773393fceb5SAxel Dörfler
774393fceb5SAxel Dörfler // set the physical memory ranges to write-back mode
775393fceb5SAxel Dörfler for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) {
776bb163c02SIngo Weinhold add_memory_type_range(-1, args->physical_memory_range[i].start,
7775c1f2319SAugustin Cavalier args->physical_memory_range[i].size, B_WRITE_BACK_MEMORY, NULL);
778393fceb5SAxel Dörfler }
779393fceb5SAxel Dörfler
780393fceb5SAxel Dörfler return B_OK;
781393fceb5SAxel Dörfler }
782393fceb5SAxel Dörfler
783393fceb5SAxel Dörfler
784393fceb5SAxel Dörfler void
arch_vm_aspace_swap(struct VMAddressSpace * from,struct VMAddressSpace * to)785b0db552cSIngo Weinhold arch_vm_aspace_swap(struct VMAddressSpace *from, struct VMAddressSpace *to)
786393fceb5SAxel Dörfler {
7879a42ad7aSIngo Weinhold // This functions is only invoked when a userland thread is in the process
7889a42ad7aSIngo Weinhold // of dying. It switches to the kernel team and does whatever cleanup is
7899a42ad7aSIngo Weinhold // necessary (in case it is the team's main thread, it will delete the
7909a42ad7aSIngo Weinhold // team).
7919a42ad7aSIngo Weinhold // It is however not necessary to change the page directory. Userland team's
7929a42ad7aSIngo Weinhold // page directories include all kernel mappings as well. Furthermore our
7939a42ad7aSIngo Weinhold // arch specific translation map data objects are ref-counted, so they won't
7949a42ad7aSIngo Weinhold // go away as long as they are still used on any CPU.
795393fceb5SAxel Dörfler }
796393fceb5SAxel Dörfler
797393fceb5SAxel Dörfler
798393fceb5SAxel Dörfler bool
arch_vm_supports_protection(uint32 protection)799393fceb5SAxel Dörfler arch_vm_supports_protection(uint32 protection)
800393fceb5SAxel Dörfler {
801393fceb5SAxel Dörfler // x86 always has the same read/write properties for userland and the
802393fceb5SAxel Dörfler // kernel.
803393fceb5SAxel Dörfler // That's why we do not support user-read/kernel-write access. While the
804393fceb5SAxel Dörfler // other way around is not supported either, we don't care in this case
805393fceb5SAxel Dörfler // and give the kernel full access.
806393fceb5SAxel Dörfler if ((protection & (B_READ_AREA | B_WRITE_AREA)) == B_READ_AREA
80740f1dd84SIngo Weinhold && (protection & B_KERNEL_WRITE_AREA) != 0) {
808393fceb5SAxel Dörfler return false;
80940f1dd84SIngo Weinhold }
810393fceb5SAxel Dörfler
811966f2076SPawel Dziepak // Userland and the kernel have the same setting of NX-bit.
812966f2076SPawel Dziepak // That's why we do not allow any area that user can access, but not execute
813966f2076SPawel Dziepak // and the kernel can execute.
814966f2076SPawel Dziepak if ((protection & (B_READ_AREA | B_WRITE_AREA)) != 0
815966f2076SPawel Dziepak && (protection & B_EXECUTE_AREA) == 0
816966f2076SPawel Dziepak && (protection & B_KERNEL_EXECUTE_AREA) != 0) {
817966f2076SPawel Dziepak return false;
818966f2076SPawel Dziepak }
819966f2076SPawel Dziepak
820393fceb5SAxel Dörfler return true;
821393fceb5SAxel Dörfler }
822393fceb5SAxel Dörfler
823393fceb5SAxel Dörfler
824393fceb5SAxel Dörfler void
arch_vm_unset_memory_type(struct VMArea * area)825a99eb6b5SIngo Weinhold arch_vm_unset_memory_type(struct VMArea *area)
826393fceb5SAxel Dörfler {
8273b0c1b52SIngo Weinhold if (area->MemoryType() == 0)
828393fceb5SAxel Dörfler return;
829393fceb5SAxel Dörfler
830bb163c02SIngo Weinhold remove_memory_type_range(area->id);
831393fceb5SAxel Dörfler }
832393fceb5SAxel Dörfler
833393fceb5SAxel Dörfler
834393fceb5SAxel Dörfler status_t
arch_vm_set_memory_type(struct VMArea * area,phys_addr_t physicalBase,uint32 type,uint32 * effectiveType)835147133b7SIngo Weinhold arch_vm_set_memory_type(struct VMArea *area, phys_addr_t physicalBase,
8368271b4a8SMichael Lotz uint32 type, uint32 *effectiveType)
837393fceb5SAxel Dörfler {
8388271b4a8SMichael Lotz return add_memory_type_range(area->id, physicalBase, area->Size(), type,
8398271b4a8SMichael Lotz effectiveType);
840393fceb5SAxel Dörfler }
841