Pulled the algorithm for dynamically mapping physical pages into an
"IO space" out of the x86 specific source into arch/generic. We'll use it for PPC as well. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15853 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,237 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "generic_vm_physical_page_mapper.h"
|
||||||
|
|
||||||
|
#include <vm_address_space.h>
|
||||||
|
#include <vm_page.h>
|
||||||
|
#include <vm_priv.h>
|
||||||
|
#include <smp.h>
|
||||||
|
#include <util/queue.h>
|
||||||
|
#include <memheap.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//#define TRACE_VM_PHYSICAL_PAGE_MAPPER
|
||||||
|
#ifdef TRACE_VM_PHYSICAL_PAGE_MAPPER
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// data and structures used to represent physical pages mapped into iospace
|
||||||
|
typedef struct paddr_chunk_descriptor {
|
||||||
|
struct paddr_chunk_descriptor *next_q;
|
||||||
|
// must remain first in structure, queue code uses it
|
||||||
|
int ref_count;
|
||||||
|
addr_t va;
|
||||||
|
} paddr_chunk_desc;
|
||||||
|
|
||||||
|
static paddr_chunk_desc *paddr_desc; // will be one per physical chunk
|
||||||
|
static paddr_chunk_desc **virtual_pmappings; // will be one ptr per virtual chunk in iospace
|
||||||
|
static int first_free_vmapping;
|
||||||
|
static int num_virtual_chunks;
|
||||||
|
static queue mapped_paddr_lru;
|
||||||
|
static mutex iospace_mutex;
|
||||||
|
static sem_id iospace_full_sem;
|
||||||
|
|
||||||
|
static generic_map_iospace_chunk_func sMapIOSpaceChunk;
|
||||||
|
static addr_t sIOSpaceBase;
|
||||||
|
static size_t sIOSpaceSize;
|
||||||
|
static size_t sIOSpaceChunkSize;
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
generic_get_physical_page(addr_t pa, addr_t *va, uint32 flags)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
paddr_chunk_desc *replaced_pchunk;
|
||||||
|
|
||||||
|
restart:
|
||||||
|
mutex_lock(&iospace_mutex);
|
||||||
|
|
||||||
|
// see if the page is already mapped
|
||||||
|
index = pa / sIOSpaceChunkSize;
|
||||||
|
if (paddr_desc[index].va != 0) {
|
||||||
|
if (paddr_desc[index].ref_count++ == 0) {
|
||||||
|
// pull this descriptor out of the lru list
|
||||||
|
queue_remove_item(&mapped_paddr_lru, &paddr_desc[index]);
|
||||||
|
}
|
||||||
|
*va = paddr_desc[index].va + pa % sIOSpaceChunkSize;
|
||||||
|
mutex_unlock(&iospace_mutex);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// map it
|
||||||
|
if (first_free_vmapping < num_virtual_chunks) {
|
||||||
|
// there's a free hole
|
||||||
|
paddr_desc[index].va = first_free_vmapping * sIOSpaceChunkSize + sIOSpaceBase;
|
||||||
|
*va = paddr_desc[index].va + pa % sIOSpaceChunkSize;
|
||||||
|
virtual_pmappings[first_free_vmapping] = &paddr_desc[index];
|
||||||
|
paddr_desc[index].ref_count++;
|
||||||
|
|
||||||
|
// push up the first_free_vmapping pointer
|
||||||
|
for (; first_free_vmapping < num_virtual_chunks; first_free_vmapping++) {
|
||||||
|
if(virtual_pmappings[first_free_vmapping] == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sMapIOSpaceChunk(paddr_desc[index].va,
|
||||||
|
index * sIOSpaceChunkSize);
|
||||||
|
mutex_unlock(&iospace_mutex);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace an earlier mapping
|
||||||
|
if (queue_peek(&mapped_paddr_lru) == NULL) {
|
||||||
|
// no free slots available
|
||||||
|
if (flags == PHYSICAL_PAGE_NO_WAIT) {
|
||||||
|
// punt back to the caller and let them handle this
|
||||||
|
mutex_unlock(&iospace_mutex);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
} else {
|
||||||
|
mutex_unlock(&iospace_mutex);
|
||||||
|
acquire_sem(iospace_full_sem);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
replaced_pchunk = (paddr_chunk_desc*)queue_dequeue(&mapped_paddr_lru);
|
||||||
|
paddr_desc[index].va = replaced_pchunk->va;
|
||||||
|
replaced_pchunk->va = 0;
|
||||||
|
*va = paddr_desc[index].va + pa % sIOSpaceChunkSize;
|
||||||
|
paddr_desc[index].ref_count++;
|
||||||
|
|
||||||
|
sMapIOSpaceChunk(paddr_desc[index].va, index * sIOSpaceChunkSize);
|
||||||
|
|
||||||
|
mutex_unlock(&iospace_mutex);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
generic_put_physical_page(addr_t va)
|
||||||
|
{
|
||||||
|
paddr_chunk_desc *desc;
|
||||||
|
|
||||||
|
if (va < sIOSpaceBase || va >= sIOSpaceBase + sIOSpaceSize)
|
||||||
|
panic("someone called put_physical_page on an invalid va 0x%lx\n", va);
|
||||||
|
va -= sIOSpaceBase;
|
||||||
|
|
||||||
|
mutex_lock(&iospace_mutex);
|
||||||
|
|
||||||
|
desc = virtual_pmappings[va / sIOSpaceChunkSize];
|
||||||
|
if (desc == NULL) {
|
||||||
|
mutex_unlock(&iospace_mutex);
|
||||||
|
panic("put_physical_page called on page at va 0x%lx which is not checked out\n", va);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--desc->ref_count == 0) {
|
||||||
|
// put it on the mapped lru list
|
||||||
|
queue_enqueue(&mapped_paddr_lru, desc);
|
||||||
|
// no sense rescheduling on this one, there's likely a race in the waiting
|
||||||
|
// thread to grab the iospace_mutex, which would block and eventually get back to
|
||||||
|
// this thread. waste of time.
|
||||||
|
release_sem_etc(iospace_full_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&iospace_mutex);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
// VM API
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
generic_vm_physical_page_mapper_init(kernel_args *args,
|
||||||
|
generic_map_iospace_chunk_func mapIOSpaceChunk, addr_t *ioSpaceBase,
|
||||||
|
size_t ioSpaceSize, size_t ioSpaceChunkSize)
|
||||||
|
{
|
||||||
|
TRACE(("generic_vm_physical_page_mapper_init: entry\n"));
|
||||||
|
|
||||||
|
sMapIOSpaceChunk = mapIOSpaceChunk;
|
||||||
|
sIOSpaceBase = *ioSpaceBase;
|
||||||
|
sIOSpaceSize = ioSpaceSize;
|
||||||
|
sIOSpaceChunkSize = ioSpaceChunkSize;
|
||||||
|
|
||||||
|
// allocate some space to hold physical page mapping info
|
||||||
|
paddr_desc = (paddr_chunk_desc *)vm_alloc_from_kernel_args(args,
|
||||||
|
sizeof(paddr_chunk_desc) * 1024, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
num_virtual_chunks = sIOSpaceSize / sIOSpaceChunkSize;
|
||||||
|
virtual_pmappings = (paddr_chunk_desc **)vm_alloc_from_kernel_args(args,
|
||||||
|
sizeof(paddr_chunk_desc *) * num_virtual_chunks, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
|
TRACE(("paddr_desc %p, virtual_pmappings %p"/*", iospace_pgtables %p"*/"\n",
|
||||||
|
paddr_desc, virtual_pmappings/*, iospace_pgtables*/));
|
||||||
|
|
||||||
|
// initialize our data structures
|
||||||
|
memset(paddr_desc, 0, sizeof(paddr_chunk_desc) * 1024);
|
||||||
|
memset(virtual_pmappings, 0, sizeof(paddr_chunk_desc *) * num_virtual_chunks);
|
||||||
|
first_free_vmapping = 0;
|
||||||
|
queue_init(&mapped_paddr_lru);
|
||||||
|
iospace_mutex.sem = -1;
|
||||||
|
iospace_mutex.holder = -1;
|
||||||
|
iospace_full_sem = -1;
|
||||||
|
|
||||||
|
TRACE(("generic_vm_physical_page_mapper_init: done\n"));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
generic_vm_physical_page_mapper_init_post_area(kernel_args *args)
|
||||||
|
{
|
||||||
|
void *temp;
|
||||||
|
|
||||||
|
TRACE(("generic_vm_physical_page_mapper_init_post_area: entry\n"));
|
||||||
|
|
||||||
|
temp = (void *)paddr_desc;
|
||||||
|
create_area("physical_page_mapping_descriptors", &temp, B_EXACT_ADDRESS,
|
||||||
|
ROUNDUP(sizeof(paddr_chunk_desc) * 1024, B_PAGE_SIZE),
|
||||||
|
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
|
temp = (void *)virtual_pmappings;
|
||||||
|
create_area("iospace_virtual_chunk_descriptors", &temp, B_EXACT_ADDRESS,
|
||||||
|
ROUNDUP(sizeof(paddr_chunk_desc *) * num_virtual_chunks, B_PAGE_SIZE),
|
||||||
|
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
|
TRACE(("generic_vm_physical_page_mapper_init_post_area: creating iospace\n"));
|
||||||
|
temp = (void *)sIOSpaceBase;
|
||||||
|
area_id ioSpaceArea = vm_create_null_area(vm_kernel_address_space_id(),
|
||||||
|
"iospace", &temp, B_EXACT_ADDRESS, sIOSpaceSize);
|
||||||
|
// TODO: We don't reserve the virtual address space for the IO space in
|
||||||
|
// generic_vm_physical_page_mapper_init() yet. So theoretically it could
|
||||||
|
// happen that a part of that space has been reserved by someone else in
|
||||||
|
// the meantime.
|
||||||
|
if (ioSpaceArea < 0) {
|
||||||
|
panic("generic_vm_physical_page_mapper_init_post_area(): Failed to "
|
||||||
|
"create null area for IO space!\n");
|
||||||
|
return ioSpaceArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("generic_vm_physical_page_mapper_init_post_area: done\n"));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
generic_vm_physical_page_mapper_init_post_sem(kernel_args *args)
|
||||||
|
{
|
||||||
|
mutex_init(&iospace_mutex, "iospace_mutex");
|
||||||
|
iospace_full_sem = create_sem(1, "iospace_full_sem");
|
||||||
|
|
||||||
|
return iospace_full_sem >= B_OK ? B_OK : iospace_full_sem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Ingo Weinhold <[email protected]>.
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _KERNEL_GENERIC_VM_PHYSICAL_PAGE_MAPPER_H
|
||||||
|
#define _KERNEL_GENERIC_VM_PHYSICAL_PAGE_MAPPER_H
|
||||||
|
|
||||||
|
#include <boot/kernel_args.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef status_t (*generic_map_iospace_chunk_func)(addr_t, addr_t);
|
||||||
|
|
||||||
|
status_t generic_get_physical_page(addr_t pa, addr_t *va, uint32 flags);
|
||||||
|
status_t generic_put_physical_page(addr_t va);
|
||||||
|
status_t generic_vm_physical_page_mapper_init(kernel_args *args,
|
||||||
|
generic_map_iospace_chunk_func mapIOSpaceChunk, addr_t *ioSpaceBase,
|
||||||
|
size_t ioSpaceSize, size_t ioSpaceChunkSize);
|
||||||
|
status_t generic_vm_physical_page_mapper_init_post_area(kernel_args *args);
|
||||||
|
status_t generic_vm_physical_page_mapper_init_post_sem(kernel_args *args);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _KERNEL_GENERIC_VM_PHYSICAL_PAGE_MAPPER_H
|
||||||
@@ -3,6 +3,9 @@ SubDir HAIKU_TOP src system kernel arch x86 ;
|
|||||||
SubDirHdrs [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) system kernel ] ;
|
SubDirHdrs [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) system kernel ] ;
|
||||||
# for syscall_numbers.h
|
# for syscall_numbers.h
|
||||||
SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers input ps2_hid ;
|
SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers input ps2_hid ;
|
||||||
|
SubDirHdrs $(SUBDIR) $(DOTDOT) generic ;
|
||||||
|
|
||||||
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
|
||||||
|
|
||||||
KernelStaticLibrary libx86 :
|
KernelStaticLibrary libx86 :
|
||||||
arch_cpu.c
|
arch_cpu.c
|
||||||
@@ -24,6 +27,8 @@ KernelStaticLibrary libx86 :
|
|||||||
arch_user_debugger.cpp
|
arch_user_debugger.cpp
|
||||||
bios.cpp
|
bios.cpp
|
||||||
cpuid.S
|
cpuid.S
|
||||||
|
|
||||||
|
generic_vm_physical_page_mapper.cpp
|
||||||
:
|
:
|
||||||
$(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
|
$(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "generic_vm_physical_page_mapper.h"
|
||||||
|
|
||||||
//#define TRACE_VM_TMAP
|
//#define TRACE_VM_TMAP
|
||||||
#ifdef TRACE_VM_TMAP
|
#ifdef TRACE_VM_TMAP
|
||||||
# define TRACE(x) dprintf x
|
# define TRACE(x) dprintf x
|
||||||
@@ -61,21 +63,7 @@ typedef struct page_directory_entry {
|
|||||||
uint32 addr:20;
|
uint32 addr:20;
|
||||||
} page_directory_entry;
|
} page_directory_entry;
|
||||||
|
|
||||||
// data and structures used to represent physical pages mapped into iospace
|
|
||||||
typedef struct paddr_chunk_descriptor {
|
|
||||||
struct paddr_chunk_descriptor *next_q; // must remain first in structure, queue code uses it
|
|
||||||
int ref_count;
|
|
||||||
addr_t va;
|
|
||||||
} paddr_chunk_desc;
|
|
||||||
|
|
||||||
static paddr_chunk_desc *paddr_desc; // will be one per physical chunk
|
|
||||||
static paddr_chunk_desc **virtual_pmappings; // will be one ptr per virtual chunk in iospace
|
|
||||||
static int first_free_vmapping;
|
|
||||||
static int num_virtual_chunks;
|
|
||||||
static queue mapped_paddr_lru;
|
|
||||||
static page_table_entry *iospace_pgtables = NULL;
|
static page_table_entry *iospace_pgtables = NULL;
|
||||||
static mutex iospace_mutex;
|
|
||||||
static sem_id iospace_full_sem;
|
|
||||||
|
|
||||||
#define PAGE_INVALIDATE_CACHE_SIZE 64
|
#define PAGE_INVALIDATE_CACHE_SIZE 64
|
||||||
|
|
||||||
@@ -96,6 +84,8 @@ static page_directory_entry *sKernelVirtualPageDirectory = NULL;
|
|||||||
static vm_translation_map *tmap_list;
|
static vm_translation_map *tmap_list;
|
||||||
static spinlock tmap_list_lock;
|
static spinlock tmap_list_lock;
|
||||||
|
|
||||||
|
static addr_t sIOSpaceBase;
|
||||||
|
|
||||||
#define CHATTY_TMAP 0
|
#define CHATTY_TMAP 0
|
||||||
|
|
||||||
#define ADDR_SHIFT(x) ((x)>>12)
|
#define ADDR_SHIFT(x) ((x)>>12)
|
||||||
@@ -648,11 +638,11 @@ map_iospace_chunk(addr_t va, addr_t pa)
|
|||||||
|
|
||||||
pa &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
|
pa &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
|
||||||
va &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
|
va &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
|
||||||
if (va < IOSPACE_BASE || va >= (IOSPACE_BASE + IOSPACE_SIZE))
|
if (va < sIOSpaceBase || va >= (sIOSpaceBase + IOSPACE_SIZE))
|
||||||
panic("map_iospace_chunk: passed invalid va 0x%lx\n", va);
|
panic("map_iospace_chunk: passed invalid va 0x%lx\n", va);
|
||||||
|
|
||||||
ppn = ADDR_SHIFT(pa);
|
ppn = ADDR_SHIFT(pa);
|
||||||
pt = &iospace_pgtables[(va - IOSPACE_BASE) / B_PAGE_SIZE];
|
pt = &iospace_pgtables[(va - sIOSpaceBase) / B_PAGE_SIZE];
|
||||||
for (i = 0; i < 1024; i++) {
|
for (i = 0; i < 1024; i++) {
|
||||||
init_page_table_entry(&pt[i]);
|
init_page_table_entry(&pt[i]);
|
||||||
pt[i].addr = ppn + i;
|
pt[i].addr = ppn + i;
|
||||||
@@ -676,101 +666,14 @@ map_iospace_chunk(addr_t va, addr_t pa)
|
|||||||
static status_t
|
static status_t
|
||||||
get_physical_page_tmap(addr_t pa, addr_t *va, uint32 flags)
|
get_physical_page_tmap(addr_t pa, addr_t *va, uint32 flags)
|
||||||
{
|
{
|
||||||
int index;
|
return generic_get_physical_page(pa, va, flags);
|
||||||
paddr_chunk_desc *replaced_pchunk;
|
|
||||||
|
|
||||||
restart:
|
|
||||||
mutex_lock(&iospace_mutex);
|
|
||||||
|
|
||||||
// see if the page is already mapped
|
|
||||||
index = pa / IOSPACE_CHUNK_SIZE;
|
|
||||||
if (paddr_desc[index].va != 0) {
|
|
||||||
if (paddr_desc[index].ref_count++ == 0) {
|
|
||||||
// pull this descriptor out of the lru list
|
|
||||||
queue_remove_item(&mapped_paddr_lru, &paddr_desc[index]);
|
|
||||||
}
|
|
||||||
*va = paddr_desc[index].va + pa % IOSPACE_CHUNK_SIZE;
|
|
||||||
mutex_unlock(&iospace_mutex);
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// map it
|
|
||||||
if (first_free_vmapping < num_virtual_chunks) {
|
|
||||||
// there's a free hole
|
|
||||||
paddr_desc[index].va = first_free_vmapping * IOSPACE_CHUNK_SIZE + IOSPACE_BASE;
|
|
||||||
*va = paddr_desc[index].va + pa % IOSPACE_CHUNK_SIZE;
|
|
||||||
virtual_pmappings[first_free_vmapping] = &paddr_desc[index];
|
|
||||||
paddr_desc[index].ref_count++;
|
|
||||||
|
|
||||||
// push up the first_free_vmapping pointer
|
|
||||||
for (; first_free_vmapping < num_virtual_chunks; first_free_vmapping++) {
|
|
||||||
if(virtual_pmappings[first_free_vmapping] == NULL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
map_iospace_chunk(paddr_desc[index].va, index * IOSPACE_CHUNK_SIZE);
|
|
||||||
mutex_unlock(&iospace_mutex);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace an earlier mapping
|
|
||||||
if (queue_peek(&mapped_paddr_lru) == NULL) {
|
|
||||||
// no free slots available
|
|
||||||
if (flags == PHYSICAL_PAGE_NO_WAIT) {
|
|
||||||
// punt back to the caller and let them handle this
|
|
||||||
mutex_unlock(&iospace_mutex);
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
} else {
|
|
||||||
mutex_unlock(&iospace_mutex);
|
|
||||||
acquire_sem(iospace_full_sem);
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
replaced_pchunk = queue_dequeue(&mapped_paddr_lru);
|
|
||||||
paddr_desc[index].va = replaced_pchunk->va;
|
|
||||||
replaced_pchunk->va = 0;
|
|
||||||
*va = paddr_desc[index].va + pa % IOSPACE_CHUNK_SIZE;
|
|
||||||
paddr_desc[index].ref_count++;
|
|
||||||
|
|
||||||
map_iospace_chunk(paddr_desc[index].va, index * IOSPACE_CHUNK_SIZE);
|
|
||||||
|
|
||||||
mutex_unlock(&iospace_mutex);
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
put_physical_page_tmap(addr_t va)
|
put_physical_page_tmap(addr_t va)
|
||||||
{
|
{
|
||||||
paddr_chunk_desc *desc;
|
return generic_put_physical_page(va);
|
||||||
|
|
||||||
if (va < IOSPACE_BASE || va >= IOSPACE_BASE + IOSPACE_SIZE)
|
|
||||||
panic("someone called put_physical_page on an invalid va 0x%lx\n", va);
|
|
||||||
va -= IOSPACE_BASE;
|
|
||||||
|
|
||||||
mutex_lock(&iospace_mutex);
|
|
||||||
|
|
||||||
desc = virtual_pmappings[va / IOSPACE_CHUNK_SIZE];
|
|
||||||
if (desc == NULL) {
|
|
||||||
mutex_unlock(&iospace_mutex);
|
|
||||||
panic("put_physical_page called on page at va 0x%lx which is not checked out\n", va);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (--desc->ref_count == 0) {
|
|
||||||
// put it on the mapped lru list
|
|
||||||
queue_enqueue(&mapped_paddr_lru, desc);
|
|
||||||
// no sense rescheduling on this one, there's likely a race in the waiting
|
|
||||||
// thread to grab the iospace_mutex, which would block and eventually get back to
|
|
||||||
// this thread. waste of time.
|
|
||||||
release_sem_etc(iospace_full_sem, 1, B_DO_NOT_RESCHEDULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&iospace_mutex);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -881,6 +784,7 @@ status_t
|
|||||||
arch_vm_translation_map_init(kernel_args *args)
|
arch_vm_translation_map_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
cpuid_info info;
|
cpuid_info info;
|
||||||
|
status_t error;
|
||||||
|
|
||||||
TRACE(("vm_translation_map_init: entry\n"));
|
TRACE(("vm_translation_map_init: entry\n"));
|
||||||
|
|
||||||
@@ -898,26 +802,20 @@ arch_vm_translation_map_init(kernel_args *args)
|
|||||||
tmap_list = NULL;
|
tmap_list = NULL;
|
||||||
|
|
||||||
// allocate some space to hold physical page mapping info
|
// allocate some space to hold physical page mapping info
|
||||||
paddr_desc = (paddr_chunk_desc *)vm_alloc_from_kernel_args(args,
|
|
||||||
sizeof(paddr_chunk_desc) * 1024, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
|
||||||
num_virtual_chunks = IOSPACE_SIZE / IOSPACE_CHUNK_SIZE;
|
|
||||||
virtual_pmappings = (paddr_chunk_desc **)vm_alloc_from_kernel_args(args,
|
|
||||||
sizeof(paddr_chunk_desc *) * num_virtual_chunks, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
|
||||||
iospace_pgtables = (page_table_entry *)vm_alloc_from_kernel_args(args,
|
iospace_pgtables = (page_table_entry *)vm_alloc_from_kernel_args(args,
|
||||||
B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)), B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)), B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
TRACE(("paddr_desc %p, virtual_pmappings %p, iospace_pgtables %p\n",
|
TRACE(("iospace_pgtables %p\n", iospace_pgtables));
|
||||||
paddr_desc, virtual_pmappings, iospace_pgtables));
|
|
||||||
|
// init physical page mapper
|
||||||
|
sIOSpaceBase = IOSPACE_BASE;
|
||||||
|
error = generic_vm_physical_page_mapper_init(args, map_iospace_chunk,
|
||||||
|
&sIOSpaceBase, IOSPACE_SIZE, IOSPACE_CHUNK_SIZE);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
// initialize our data structures
|
// initialize our data structures
|
||||||
memset(paddr_desc, 0, sizeof(paddr_chunk_desc) * 1024);
|
|
||||||
memset(virtual_pmappings, 0, sizeof(paddr_chunk_desc *) * num_virtual_chunks);
|
|
||||||
first_free_vmapping = 0;
|
|
||||||
queue_init(&mapped_paddr_lru);
|
|
||||||
memset(iospace_pgtables, 0, B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)));
|
memset(iospace_pgtables, 0, B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)));
|
||||||
iospace_mutex.sem = -1;
|
|
||||||
iospace_mutex.holder = -1;
|
|
||||||
iospace_full_sem = -1;
|
|
||||||
|
|
||||||
TRACE(("mapping iospace_pgtables\n"));
|
TRACE(("mapping iospace_pgtables\n"));
|
||||||
|
|
||||||
@@ -932,7 +830,7 @@ arch_vm_translation_map_init(kernel_args *args)
|
|||||||
virt_pgtable = (addr_t)iospace_pgtables;
|
virt_pgtable = (addr_t)iospace_pgtables;
|
||||||
for (i = 0; i < (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)); i++, virt_pgtable += B_PAGE_SIZE) {
|
for (i = 0; i < (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)); i++, virt_pgtable += B_PAGE_SIZE) {
|
||||||
early_query(virt_pgtable, &phys_pgtable);
|
early_query(virt_pgtable, &phys_pgtable);
|
||||||
e = &page_hole_pgdir[(IOSPACE_BASE / (B_PAGE_SIZE * 1024)) + i];
|
e = &page_hole_pgdir[(sIOSpaceBase / (B_PAGE_SIZE * 1024)) + i];
|
||||||
put_pgtable_in_pgdir(e, phys_pgtable, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
put_pgtable_in_pgdir(e, phys_pgtable, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -953,10 +851,7 @@ arch_vm_translation_map_init(kernel_args *args)
|
|||||||
status_t
|
status_t
|
||||||
arch_vm_translation_map_init_post_sem(kernel_args *args)
|
arch_vm_translation_map_init_post_sem(kernel_args *args)
|
||||||
{
|
{
|
||||||
mutex_init(&iospace_mutex, "iospace_mutex");
|
return generic_vm_physical_page_mapper_init_post_sem(args);
|
||||||
iospace_full_sem = create_sem(1, "iospace_full_sem");
|
|
||||||
|
|
||||||
return iospace_full_sem >= B_OK ? B_OK : iospace_full_sem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -966,6 +861,7 @@ arch_vm_translation_map_init_post_area(kernel_args *args)
|
|||||||
// now that the vm is initialized, create a region that represents
|
// now that the vm is initialized, create a region that represents
|
||||||
// the page hole
|
// the page hole
|
||||||
void *temp;
|
void *temp;
|
||||||
|
status_t error;
|
||||||
|
|
||||||
TRACE(("vm_translation_map_init_post_area: entry\n"));
|
TRACE(("vm_translation_map_init_post_area: entry\n"));
|
||||||
|
|
||||||
@@ -978,25 +874,14 @@ arch_vm_translation_map_init_post_area(kernel_args *args)
|
|||||||
create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, B_PAGE_SIZE,
|
create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, B_PAGE_SIZE,
|
||||||
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
temp = (void *)paddr_desc;
|
|
||||||
create_area("physical_page_mapping_descriptors", &temp, B_EXACT_ADDRESS,
|
|
||||||
ROUNDUP(sizeof(paddr_chunk_desc) * 1024, B_PAGE_SIZE),
|
|
||||||
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
|
||||||
|
|
||||||
temp = (void *)virtual_pmappings;
|
|
||||||
create_area("iospace_virtual_chunk_descriptors", &temp, B_EXACT_ADDRESS,
|
|
||||||
ROUNDUP(sizeof(paddr_chunk_desc *) * num_virtual_chunks, B_PAGE_SIZE),
|
|
||||||
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
|
||||||
|
|
||||||
temp = (void *)iospace_pgtables;
|
temp = (void *)iospace_pgtables;
|
||||||
create_area("iospace_pgtables", &temp, B_EXACT_ADDRESS,
|
create_area("iospace_pgtables", &temp, B_EXACT_ADDRESS,
|
||||||
B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)),
|
B_PAGE_SIZE * (IOSPACE_SIZE / (B_PAGE_SIZE * 1024)),
|
||||||
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
TRACE(("vm_translation_map_init_post_area: creating iospace\n"));
|
error = generic_vm_physical_page_mapper_init_post_area(args);
|
||||||
temp = (void *)IOSPACE_BASE;
|
if (error != B_OK)
|
||||||
vm_create_null_area(vm_kernel_address_space_id(), "iospace", &temp,
|
return error;
|
||||||
B_EXACT_ADDRESS, IOSPACE_SIZE);
|
|
||||||
|
|
||||||
TRACE(("vm_translation_map_init_post_area: done\n"));
|
TRACE(("vm_translation_map_init_post_area: done\n"));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user