From 4f893e39ab9363aac919466fd5044afa78a97e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Mon, 17 Mar 2008 19:50:46 +0000 Subject: [PATCH] algorithm to find best suited mtrr values to match a memory region. tested ok with 3071MB. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24424 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/arch/x86/arch_vm.cpp | 129 ++++++++++++++++++++----- 1 file changed, 104 insertions(+), 25 deletions(-) diff --git a/src/system/kernel/arch/x86/arch_vm.cpp b/src/system/kernel/arch/x86/arch_vm.cpp index 01796ab7f6..6ffd32a042 100644 --- a/src/system/kernel/arch/x86/arch_vm.cpp +++ b/src/system/kernel/arch/x86/arch_vm.cpp @@ -31,6 +31,13 @@ # define TRACE(x) ; #endif +#define TRACE_MTRR_ARCH_VM +#ifdef TRACE_MTRR_ARCH_VM +# define TRACE_MTRR(x...) dprintf(x) +#else +# define TRACE_MTRR(x...) +#endif + #define kMaxMemoryTypeRegisters 32 @@ -83,6 +90,22 @@ nearest_power(addr_t value) } +static void +nearest_powers(uint64 value, uint64 *lower, uint64 *upper) +{ + uint64 power = 1UL << 12; + *lower = power; + // 12 bits is the smallest supported alignment/length + + while (value >= power) { + *lower = power; + power <<= 1; + } + + *upper = power; +} + + static status_t set_memory_type(int32 id, uint64 base, uint64 length, uint32 type) { @@ -91,23 +114,21 @@ set_memory_type(int32 id, uint64 base, uint64 length, uint32 type) if (type == 0) return B_OK; - uint32 newType; - switch (type) { case B_MTR_UC: - newType = IA32_MTR_UNCACHED; + type = IA32_MTR_UNCACHED; break; case B_MTR_WC: - newType = IA32_MTR_WRITE_COMBINING; + type = IA32_MTR_WRITE_COMBINING; break; case B_MTR_WT: - newType = IA32_MTR_WRITE_THROUGH; + type = IA32_MTR_WRITE_THROUGH; break; case B_MTR_WP: - newType = IA32_MTR_WRITE_PROTECTED; + type = IA32_MTR_WRITE_PROTECTED; break; case B_MTR_WB: - newType = IA32_MTR_WRITE_BACK; + type = IA32_MTR_WRITE_BACK; break; default: @@ -118,41 +139,99 @@ set_memory_type(int32 id, uint64 base, uint64 length, uint32 type) return B_NOT_SUPPORTED; // length must be a power of 2; just round it up to the next value - uint64 newLength = nearest_power(length); + length = nearest_power(length); - // avoids more than 2GB slots - if (newLength > 0x80000000) - newLength = 0x80000000; - - if (newLength + base <= base) { + if (length + base <= base) { // 4GB overflow return B_BAD_VALUE; } // base must be aligned to the length - if (base & (newLength - 1)) + if (base & (length - 1)) return B_BAD_VALUE; index = allocate_mtrr(); if (index < 0) return B_ERROR; - TRACE(("allocate MTRR slot %ld, base = %Lx, length = %Lx\n", index, - base, newLength)); + TRACE_MTRR("allocate MTRR slot %ld, base = %Lx, length = %Lx\n", index, base, length); sMemoryTypeIDs[index] = id; - x86_set_mtrr(index, base, newLength, newType); - - // now handle remaining memory - if (length > newLength) { - // TODO iterate over smaller lengths to avoid the PCI hole after the physical memory. - set_memory_type(id, base + newLength, length - newLength, type); - } + x86_set_mtrr(index, base, length, type); return B_OK; } +static int64 sols[5]; +static int solCount; +static int64 props[5]; + + +static void +find_nearest(uint64 value, int iteration) +{ + TRACE_MTRR("find_nearest %Lx %d\n", value, iteration); + if (iteration > 4 || (iteration + 1) >= solCount) + return; + uint64 down, up; + int i; + nearest_powers(value, &down, &up); + props[iteration] = down; + if (value - down < 0x100000) { + for (i=0; i<=iteration; i++) + sols[i] = props[i]; + solCount = iteration + 1; + return; + } + find_nearest(value - down, iteration + 1); + props[iteration] = -up; + if (up - value < 0x100000) { + for (i=0; i<=iteration; i++) + sols[i] = props[i]; + solCount = iteration + 1; + return; + } + find_nearest(up - value, iteration + 1); +} + + +static status_t +set_memory_write_back(int32 id, uint64 base, uint64 length) +{ + int i; + TRACE_MTRR("set_memory_write_back base %Lx length %Lx\n", base, length); + solCount = 5; + find_nearest(length, 0); + +#ifdef TRACE_MTRR + dprintf("sols: "); + for (i=0; inum_physical_memory_ranges; i++) { - set_memory_type(-1, args->physical_memory_range[i].start, - args->physical_memory_range[i].size, B_MTR_WB); + set_memory_write_back(-1, args->physical_memory_range[i].start, + args->physical_memory_range[i].size); } return B_OK;