Some work in progress of the MTRR support. Shouldn't do any harm yet :-)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15525 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-12-13 00:06:52 +00:00
parent b7e7814c79
commit 2ed21b8525
16 changed files with 299 additions and 114 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ void arch_vm_aspace_swap(vm_address_space *aspace);
bool arch_vm_supports_protection(uint32 protection);
void arch_vm_init_area(vm_area *area);
status_t arch_vm_set_memory_type(vm_area *area, uint32 type);
status_t arch_vm_set_memory_type(vm_area *area, addr_t physicalBase, uint32 type);
void arch_vm_unset_memory_type(vm_area *area);
#ifdef __cplusplus
+15 -4
View File
@@ -14,14 +14,23 @@
// MSR registers (possibly Intel specific)
#define IA32_MSR_APIC_BASE 0x1b
#define IA32_MSR_APIC_BASE 0x1b
#define IA32_MSR_MTRR_CAPABILITIES 0xfe
#define IA32_MSR_MTRR_DEFAULT_TYPE 0x2ff
#define IA32_MSR_MTRR_PHYSICAL_BASE_0 0x200
#define IA32_MSR_MTRR_PHYSICAL_MASK_0 0x201
typedef struct x86_cpu_module_info {
module_info info;
uint32 (*count_mtrrs)(void);
status_t (*set_mtrr)(uint32 index, addr_t base, addr_t length, uint32 type);
status_t (*unset_mtrr)(uint32 index);
status_t (*enable_mtrrs)(void);
void (*disable_mtrrs)(void);
void (*set_mtrr)(uint32 index, addr_t base, addr_t length, uint32 type);
status_t (*get_mtrr)(uint32 index, addr_t *_base, addr_t *_length,
uint32 *_type);
} x86_cpu_module_info;
@@ -91,8 +100,10 @@ uint64 x86_read_msr(uint32 registerNumber);
void x86_write_msr(uint32 registerNumber, uint64 value);
void x86_set_task_gate(int32 n, int32 segment);
uint32 x86_count_mtrrs(void);
status_t x86_enable_mtrrs(void);
status_t x86_disable_mtrrs(void);
status_t x86_set_mtrr(uint32 index, addr_t base, addr_t length, uint32 type);
status_t x86_unset_mtrr(uint32 index);
status_t x86_get_mtrr(uint32 index, addr_t *_base, addr_t *_length, uint32 *_type);
struct tss *x86_get_main_tss(void);
#define read_ebp(value) \
+1
View File
@@ -30,6 +30,7 @@ extern "C" {
extern status_t debug_init(struct kernel_args *args);
extern status_t debug_init_post_vm(struct kernel_args *args);
extern status_t debug_init_post_modules(struct kernel_args *args);
extern void debug_early_boot_message(const char *string);
extern void debug_puts(const char *s);
extern bool debug_debugger_running(void);
@@ -28,6 +28,7 @@ extern "C" {
bool frame_buffer_console_available(void);
status_t frame_buffer_console_init(struct kernel_args *args);
status_t frame_buffer_console_init_post_modules(struct kernel_args *args);
status_t _user_frame_buffer_update(addr_t baseAddress, int32 width, int32 height,
int32 depth, int32 bytesPerRow);
+2
View File
@@ -67,6 +67,8 @@ area_id vm_clone_area(aspace_id aid, const char *name, void **address,
status_t vm_delete_area(aspace_id aid, area_id id);
status_t vm_create_vnode_cache(void *vnode, vm_cache_ref **_cacheRef);
status_t vm_set_area_memory_type(area_id id, addr_t physicalBase, uint32 type);
status_t vm_get_page_mapping(aspace_id aid, addr_t vaddr, addr_t *paddr);
status_t vm_get_physical_page(addr_t paddr, addr_t *vaddr, int flags);
status_t vm_put_physical_page(addr_t vaddr);
+2 -2
View File
@@ -5,6 +5,6 @@ UsePrivateHeaders kernel ;
KernelAddon generic_x86 : kernel cpu :
generic_x86.cpp
intel.cpp
amd.cpp
via.cpp
# amd.cpp
# via.cpp
;
+3 -3
View File
@@ -12,9 +12,9 @@
#include "via.h"
module_info *gModules[] = {
module_info *modules[] = {
(module_info *)&gIntelModule,
(module_info *)&gAMDModule,
(module_info *)&gVIAModule,
// (module_info *)&gAMDModule,
// (module_info *)&gVIAModule,
NULL
};
+99 -7
View File
@@ -9,24 +9,95 @@
#include "intel.h"
#include <KernelExport.h>
#include <OS.h>
#include <arch_cpu.h>
#define IA32_MTRR_FEATURE (1UL << 12)
#define IA32_MTRR_ENABLE (1UL << 11)
#define IA32_MTRR_ENABLE_FIXED (1UL << 10)
#define IA32_MTRR_VALID_RANGE (1UL << 11)
struct mtrr_capabilities {
mtrr_capabilities(uint64 value) { *(uint64 *)this = value; }
uint64 variable_ranges : 8;
uint64 supports_fixed : 1;
uint64 _reserved0 : 1;
uint64 supports_write_combined : 1;
uint64 _reserved1 : 53;
};
static uint32
intel_count_mtrrs(void)
{
return 0;
cpuid_info cpuInfo;
if (get_cpuid(&cpuInfo, 1, 0) != B_OK
|| (cpuInfo.eax_1.features & IA32_MTRR_FEATURE) == 0)
return 0;
mtrr_capabilities capabilities(x86_read_msr(IA32_MSR_MTRR_CAPABILITIES));
return capabilities.variable_ranges;
}
static status_t
intel_set_mtrr(uint32 index, addr_t base, addr_t length, uint32 type)
intel_enable_mtrrs(void)
{
cpuid_info cpuInfo;
if (get_cpuid(&cpuInfo, 1, 0) != B_OK
|| (cpuInfo.eax_1.features & IA32_MTRR_FEATURE) == 0)
return B_NOT_SUPPORTED;
x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE,
x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) | IA32_MTRR_ENABLE);
return B_OK;
}
static status_t
intel_unset_mtrr(uint32 index)
static void
intel_disable_mtrrs(void)
{
x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE,
x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & ~IA32_MTRR_ENABLE);
}
static void
intel_set_mtrr(uint32 index, addr_t base, addr_t length, uint32 type)
{
if (base != 0 && length != 0) {
// enable MTRR
x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index,
(base & ~(B_PAGE_SIZE - 1)) | type);
x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index,
(length & ~(B_PAGE_SIZE - 1)) | IA32_MTRR_VALID_RANGE);
} else {
// disable MTRR
x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, 0);
x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, 0);
}
}
static status_t
intel_get_mtrr(uint32 index, addr_t *_base, addr_t *_length, uint32 *_type)
{
uint64 base = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index);
uint64 mask = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index);
if ((mask & IA32_MTRR_VALID_RANGE) == 0)
return B_ERROR;
*_base = base & ~(B_PAGE_SIZE - 1);
*_length = mask & ~(B_PAGE_SIZE - 1);
*_type = base & 0xff;
return B_OK;
}
@@ -38,10 +109,28 @@ intel_init(void)
if (get_system_info(&info) != B_OK)
return B_ERROR;
if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_INTEL_x86)
if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_INTEL_x86
|| (info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_AMD_x86)
return B_ERROR;
return B_OK;
if (x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & IA32_MTRR_ENABLE)
dprintf("MTRR enabled\n");
else
dprintf("MTRR disabled\n");
for (uint32 i = 0; i < intel_count_mtrrs(); i++) {
addr_t base;
addr_t length;
uint32 type;
if (intel_get_mtrr(i, &base, &length, &type) == B_OK)
dprintf(" %ld: %p, %p, %ld\n", i, (void *)base, (void *)length, type);
else
dprintf(" %ld: empty\n", i);
}
// don't open it just now
return B_ERROR;
// return B_OK;
}
@@ -74,6 +163,9 @@ x86_cpu_module_info gIntelModule = {
},
intel_count_mtrrs,
intel_enable_mtrrs,
intel_disable_mtrrs,
intel_set_mtrr,
intel_unset_mtrr,
intel_get_mtrr,
};
+1 -1
View File
@@ -126,7 +126,7 @@ arch_vm_unset_memory_type(vm_area *area)
status_t
arch_vm_set_memory_type(vm_area *area, uint32 type)
arch_vm_set_memory_type(vm_area *area, addr_t physicalBase, uint32 type)
{
if (type == 0)
return B_OK;
+28 -6
View File
@@ -103,22 +103,44 @@ x86_count_mtrrs(void)
status_t
x86_set_mtrr(uint32 index, addr_t base, addr_t length, uint32 type)
x86_enable_mtrrs(void)
{
if (load_cpu_module() == NULL)
return B_UNSUPPORTED;
return B_NOT_SUPPORTED;
return sCpuModule->set_mtrr(index, base, length, type);
return sCpuModule->enable_mtrrs();
}
status_t
x86_unset_mtrr(uint32 index)
x86_disable_mtrrs(void)
{
if (load_cpu_module() == NULL)
return B_UNSUPPORTED;
return B_NOT_SUPPORTED;
return sCpuModule->unset_mtrr(index);
sCpuModule->disable_mtrrs();
return B_OK;
}
status_t
x86_set_mtrr(uint32 index, addr_t base, addr_t length, uint32 type)
{
if (load_cpu_module() == NULL)
return B_NOT_SUPPORTED;
sCpuModule->set_mtrr(index, base, length, type);
return B_OK;
}
status_t
x86_get_mtrr(uint32 index, addr_t *_base, addr_t *_length, uint32 *_type)
{
if (load_cpu_module() == NULL)
return B_NOT_SUPPORTED;
return sCpuModule->get_mtrr(index, _base, _length, _type);
}
+65 -51
View File
@@ -30,26 +30,27 @@
#endif
static uint32 *sMTRRBitmap;
struct set_mtrr_parameter {
int32 index;
addr_t base;
addr_t length;
uint8 type;
};
static uint32 sMTRRBitmap;
static int32 sMTRRCount;
static spinlock sMTRRLock;
static status_t
init_mtrr_bitmap(void)
init_mtrr(void)
{
if (sMTRRBitmap != NULL)
return B_OK;
sMTRRCount = x86_count_mtrrs();
if (sMTRRCount == 0)
return B_UNSUPPORTED;
return B_NOT_SUPPORTED;
sMTRRBitmap = malloc(sMTRRCount / 8);
if (sMTRRBitmap == NULL)
return B_NO_MEMORY;
memset(sMTRRBitmap, 0, sMTRRCount / 8);
sMTRRBitmap = 0;
return B_OK;
}
@@ -57,28 +58,22 @@ init_mtrr_bitmap(void)
static int32
allocate_mtrr(void)
{
int32 count = sMTRRCount / 32;
int32 i, j;
int32 index;
cpu_status state = disable_interrupts();
acquire_spinlock(&sMTRRLock);
for (i = 0; i < count; i++) {
if (sMTRRBitmap[i] == 0xffffffff)
// find free bit
for (index = 0; index < 32; index++) {
if (sMTRRBitmap & (1UL << index))
continue;
// find free bit
sMTRRBitmap |= 1UL << index;
for (j = 0; j < 32; j++) {
if (sMTRRBitmap[i] & (1UL << j))
continue;
sMTRRBitmap[i] |= 1UL << j;
release_spinlock(&sMTRRLock);
restore_interrupts(state);
return i * 32 + j;
}
release_spinlock(&sMTRRLock);
restore_interrupts(state);
return index;
}
release_spinlock(&sMTRRLock);
@@ -91,19 +86,38 @@ allocate_mtrr(void)
static void
free_mtrr(int32 index)
{
int32 i = index / 32;
int32 j = index - i * 32;
cpu_status state = disable_interrupts();
acquire_spinlock(&sMTRRLock);
sMTRRBitmap[i] &= ~(1UL << j);
sMTRRBitmap &= ~(1UL << index);
release_spinlock(&sMTRRLock);
restore_interrupts(state);
}
static void
unset_mtrr(void *_index, int cpu)
{
int32 index = (int32)_index;
x86_set_mtrr(index, 0, 0, 0);
}
static void
set_mtrr(void *_parameter, int cpu)
{
struct set_mtrr_parameter *parameter = (struct set_mtrr_parameter *)_parameter;
x86_set_mtrr(parameter->index, parameter->base, parameter->length,
parameter->type);
}
// #pragma mark -
status_t
arch_vm_init(kernel_args *args)
{
@@ -182,58 +196,58 @@ arch_vm_unset_memory_type(vm_area *area)
if (area->memory_type.type == 0)
return;
x86_unset_mtrr(area->memory_type.index);
call_all_cpus(&unset_mtrr, (void *)(int32)area->memory_type.index);
free_mtrr(area->memory_type.index);
}
status_t
arch_vm_set_memory_type(vm_area *area, uint32 type)
arch_vm_set_memory_type(vm_area *area, addr_t physicalBase, uint32 type)
{
status_t status;
int32 index;
struct set_mtrr_parameter parameter;
if (type == 0)
return B_OK;
switch (type) {
case B_MTR_UC: // uncacheable
type = 0;
parameter.type = 0;
break;
case B_MTR_WC: // write combining
type = 1;
parameter.type = 1;
break;
case B_MTR_WT: // write through
type = 4;
parameter.type = 4;
break;
case B_MTR_WP: // write protected
type = 5;
parameter.type = 5;
break;
case B_MTR_WB: // write back
type = 6;
parameter.type = 6;
break;
default:
return B_BAD_VALUE;
}
if (sMTRRBitmap == NULL) {
status = init_mtrr_bitmap();
if (sMTRRCount == 0) {
status_t status = init_mtrr();
if (status < B_OK)
return status;
}
index = allocate_mtrr();
if (index < 0)
parameter.index = allocate_mtrr();
if (parameter.index < 0)
return B_ERROR;
status = x86_set_mtrr(index, area->base, area->size, type);
if (status != B_OK) {
area->memory_type.type = (uint16)type;
area->memory_type.index = (uint16)index;
} else
free_mtrr(index);
parameter.base = physicalBase;
parameter.length = area->size;
dprintf("memory type: %u, index: %ld\n", area->memory_type.type, index);
return status;
call_all_cpus(&set_mtrr, &parameter);
area->memory_type.type = parameter.type;
area->memory_type.index = (uint16)parameter.index;
dprintf("memory type: %u, index: %ld\n", area->memory_type.type, parameter.index);
return B_OK;
}
+7
View File
@@ -439,6 +439,13 @@ debug_init_post_vm(kernel_args *args)
}
status_t
debug_init_post_modules(struct kernel_args *args)
{
return frame_buffer_console_init_post_modules(args);
}
// #pragma mark - public API
@@ -7,6 +7,7 @@
#include <kernel.h>
#include <lock.h>
#include <boot_item.h>
#include <vm.h>
#include <fs/devfs.h>
#include <boot/kernel_args.h>
@@ -110,7 +111,7 @@ render_glyph(int32 x, int32 y, uint8 glyph, uint8 attr)
+ x * CHAR_WIDTH * sConsole.bytes_per_pixel);
uint8 *color = get_palette_entry(foreground_color(attr));
uint8 *backgroundColor = get_palette_entry(background_color(attr));
for (y = 0; y < CHAR_HEIGHT; y++) {
uint8 bits = FONT[CHAR_HEIGHT * glyph + y];
for (x = 0; x < CHAR_WIDTH; x++) {
@@ -122,7 +123,7 @@ render_glyph(int32 x, int32 y, uint8 glyph, uint8 attr)
}
bits >>= 1;
}
base += sConsole.bytes_per_row;
}
} else {
@@ -426,6 +427,19 @@ frame_buffer_console_init(kernel_args *args)
}
status_t
frame_buffer_console_init_post_modules(kernel_args *args)
{
if (sConsole.frame_buffer == NULL)
return B_OK;
// try to set frame buffer memory to write combined
return vm_set_area_memory_type(sConsole.area,
args->frame_buffer.physical_buffer.start, B_MTR_WC);
}
// #pragma mark -
+16
View File
@@ -225,6 +225,22 @@ int_io_interrupt_handler(int vector)
int status = B_UNHANDLED_INTERRUPT;
struct io_handler *io;
#if 0
{
static int low[2];
static int high[2];
static int counter;
int32 cpu = smp_get_current_cpu();
if (vector > 0xf0 - 32)
high[cpu]++;
else
low[cpu]++;
dprintf("got vector %d at CPU %ld\n", vector, cpu);
//if ((counter++ % 10) == 0)
dprintf("ints: %d/%d (high: %d/%d)\n", low[0], low[1], high[0], high[1]);
}
#endif
acquire_spinlock(&io_vectors[vector].vector_lock);
// The list can be empty at this place
+2 -21
View File
@@ -215,27 +215,8 @@ main2(void *unused)
TRACE(("Mount boot file system\n"));
vfs_mount_boot_file_system(&sKernelArgs);
//module_test();
#if 0
// XXX remove
vfs_test();
#endif
#if 0
// XXX remove
thread_test();
#endif
#if 0
vm_test();
#endif
#if 0
panic("debugger_test\n");
#endif
#if 0
cbuf_test();
#endif
#if 0
port_test();
#endif
debug_init_post_modules(&sKernelArgs);
// start the init process
{
const char *shellArgs[] = {"/bin/sh", "/boot/beos/system/boot/Bootscript", NULL};
+40 -16
View File
@@ -935,20 +935,22 @@ vm_create_anonymous_area(aspace_id aid, const char *name, void **address,
area_id
vm_map_physical_memory(aspace_id aid, const char *name, void **_address,
uint32 addressSpec, addr_t size, uint32 protection, addr_t phys_addr)
vm_map_physical_memory(aspace_id areaID, const char *name, void **_address,
uint32 addressSpec, addr_t size, uint32 protection,
addr_t physicalAddress)
{
vm_area *area;
vm_cache *cache;
vm_cache_ref *cache_ref;
vm_cache_ref *cacheRef;
vm_store *store;
addr_t map_offset;
addr_t mapOffset;
status_t status;
vm_address_space *aspace = vm_get_aspace_by_id(aid);
vm_address_space *aspace = vm_get_aspace_by_id(areaID);
TRACE(("vm_map_physical_memory(aspace = %ld, \"%s\", virtual = %p, spec = %ld,"
" size = %lu, protection = %ld, phys = %p)\n",
aid, name, _address, addressSpec, size, protection, (void *)phys_addr));
areaID, name, _address, addressSpec, size, protection,
(void *)physicalAddress));
if (!arch_vm_supports_protection(protection))
return B_NOT_SUPPORTED;
@@ -958,33 +960,36 @@ vm_map_physical_memory(aspace_id aid, const char *name, void **_address,
// if the physical address is somewhat inside a page,
// move the actual area down to align on a page boundary
map_offset = phys_addr % B_PAGE_SIZE;
size += map_offset;
phys_addr -= map_offset;
mapOffset = physicalAddress % B_PAGE_SIZE;
size += mapOffset;
physicalAddress -= mapOffset;
size = PAGE_ALIGN(size);
// create an device store object
store = vm_store_create_device(phys_addr);
// TODO: panic???
store = vm_store_create_device(physicalAddress);
if (store == NULL)
panic("vm_map_physical_memory: vm_store_create_device returned NULL");
cache = vm_cache_create(store);
if (cache == NULL)
panic("vm_map_physical_memory: vm_cache_create returned NULL");
cache_ref = vm_cache_ref_create(cache);
if (cache_ref == NULL)
cacheRef = vm_cache_ref_create(cache);
if (cacheRef == NULL)
panic("vm_map_physical_memory: vm_cache_ref_create returned NULL");
// tell the page scanner to skip over this area, it's pages are special
cache->scan_skip = 1;
vm_cache_acquire_ref(cache_ref, true);
vm_cache_acquire_ref(cacheRef, true);
status = map_backing_store(aspace, store, _address, 0, size,
addressSpec & ~B_MTR_MASK, 0, protection, REGION_NO_PRIVATE_MAP, &area, name);
vm_cache_release_ref(cache_ref);
vm_cache_release_ref(cacheRef);
if (status >= B_OK && (addressSpec & B_MTR_MASK) != 0) {
// set requested memory type
status = arch_vm_set_memory_type(area, addressSpec & B_MTR_MASK);
status = arch_vm_set_memory_type(area, physicalAddress,
addressSpec & B_MTR_MASK);
if (status < B_OK)
vm_put_area(area);
}
@@ -1003,7 +1008,7 @@ vm_map_physical_memory(aspace_id aid, const char *name, void **_address,
// modify the pointer returned to be offset back into the new area
// the same way the physical address in was offset
*_address = (void *)((addr_t)*_address + map_offset);
*_address = (void *)((addr_t)*_address + mapOffset);
return area->id;
}
@@ -2750,6 +2755,25 @@ vm_try_reserve_memory(size_t amount)
}
status_t
vm_set_area_memory_type(area_id id, addr_t physicalBase, uint32 type)
{
vm_area *area = vm_get_area(id);
if (area == NULL)
return B_BAD_VALUE;
status_t status = arch_vm_set_memory_type(area, physicalBase, type);
if (status < B_OK)
goto out;
arch_cpu_invalidate_TLB_range(area->base, area->size);
out:
vm_put_area(area);
return status;
}
/** This function enforces some protection properties:
* - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well
* - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set