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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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, ¶meter);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 -
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user