* Added "boolean getNewReference" parameter to the vm_address_space*
versions of the AddressSpaceReadLocker constructor and SetTo(). When true it will get a new reference to the address space. * Changed vm_soft_fault(): Now it gets the address space as a parameter (for page faults getting it happens in vm_page_fault()). This should fix lock_memory_etc() for other teams -- it used the correct address space before, but the invoked vm_soft_fault() always used the current team's address space. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26628 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+65
-43
@@ -64,12 +64,12 @@
|
|||||||
class AddressSpaceReadLocker {
|
class AddressSpaceReadLocker {
|
||||||
public:
|
public:
|
||||||
AddressSpaceReadLocker(team_id team);
|
AddressSpaceReadLocker(team_id team);
|
||||||
AddressSpaceReadLocker(vm_address_space* space);
|
AddressSpaceReadLocker(vm_address_space* space, bool getNewReference);
|
||||||
AddressSpaceReadLocker();
|
AddressSpaceReadLocker();
|
||||||
~AddressSpaceReadLocker();
|
~AddressSpaceReadLocker();
|
||||||
|
|
||||||
status_t SetTo(team_id team);
|
status_t SetTo(team_id team);
|
||||||
void SetTo(vm_address_space* space);
|
void SetTo(vm_address_space* space, bool getNewReference);
|
||||||
status_t SetFromArea(area_id areaID, vm_area*& area);
|
status_t SetFromArea(area_id areaID, vm_area*& area);
|
||||||
|
|
||||||
bool IsLocked() const { return fLocked; }
|
bool IsLocked() const { return fLocked; }
|
||||||
@@ -212,7 +212,8 @@ static cache_info* sCacheInfoTable;
|
|||||||
// function declarations
|
// function declarations
|
||||||
static void delete_area(vm_address_space *addressSpace, vm_area *area);
|
static void delete_area(vm_address_space *addressSpace, vm_area *area);
|
||||||
static vm_address_space *get_address_space_by_area_id(area_id id);
|
static vm_address_space *get_address_space_by_area_id(area_id id);
|
||||||
static status_t vm_soft_fault(addr_t address, bool isWrite, bool isUser);
|
static status_t vm_soft_fault(vm_address_space *addressSpace, addr_t address,
|
||||||
|
bool isWrite, bool isUser);
|
||||||
static status_t map_backing_store(vm_address_space *addressSpace,
|
static status_t map_backing_store(vm_address_space *addressSpace,
|
||||||
vm_cache *cache, void **_virtualAddress, off_t offset, addr_t size,
|
vm_cache *cache, void **_virtualAddress, off_t offset, addr_t size,
|
||||||
uint32 addressSpec, int wiring, int protection, int mapping,
|
uint32 addressSpec, int wiring, int protection, int mapping,
|
||||||
@@ -231,13 +232,16 @@ AddressSpaceReadLocker::AddressSpaceReadLocker(team_id team)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Takes over the reference of the address space
|
/*! Takes over the reference of the address space, if \a getNewReference is
|
||||||
AddressSpaceReadLocker::AddressSpaceReadLocker(vm_address_space* space)
|
\c false.
|
||||||
|
*/
|
||||||
|
AddressSpaceReadLocker::AddressSpaceReadLocker(vm_address_space* space,
|
||||||
|
bool getNewReference)
|
||||||
:
|
:
|
||||||
fSpace(NULL),
|
fSpace(NULL),
|
||||||
fLocked(false)
|
fLocked(false)
|
||||||
{
|
{
|
||||||
SetTo(space);
|
SetTo(space, getNewReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -277,11 +281,17 @@ AddressSpaceReadLocker::SetTo(team_id team)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Takes over the reference of the address space
|
/*! Takes over the reference of the address space, if \a getNewReference is
|
||||||
|
\c false.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
AddressSpaceReadLocker::SetTo(vm_address_space* space)
|
AddressSpaceReadLocker::SetTo(vm_address_space* space, bool getNewReference)
|
||||||
{
|
{
|
||||||
fSpace = space;
|
fSpace = space;
|
||||||
|
|
||||||
|
if (getNewReference)
|
||||||
|
atomic_add(&fSpace->ref_count, 1);
|
||||||
|
|
||||||
rw_lock_read_lock(&fSpace->lock);
|
rw_lock_read_lock(&fSpace->lock);
|
||||||
fLocked = true;
|
fLocked = true;
|
||||||
}
|
}
|
||||||
@@ -3965,7 +3975,38 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
|
|||||||
|
|
||||||
*newIP = 0;
|
*newIP = 0;
|
||||||
|
|
||||||
status_t status = vm_soft_fault(address, isWrite, isUser);
|
addr_t pageAddress = ROUNDOWN(address, B_PAGE_SIZE);
|
||||||
|
|
||||||
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
vm_address_space *addressSpace;
|
||||||
|
|
||||||
|
if (IS_KERNEL_ADDRESS(pageAddress)) {
|
||||||
|
addressSpace = vm_get_kernel_address_space();
|
||||||
|
} else if (IS_USER_ADDRESS(pageAddress)) {
|
||||||
|
addressSpace = vm_get_current_user_address_space();
|
||||||
|
if (addressSpace == NULL) {
|
||||||
|
if (!isUser) {
|
||||||
|
dprintf("vm_page_fault: kernel thread accessing invalid user "
|
||||||
|
"memory!\n");
|
||||||
|
status = B_BAD_ADDRESS;
|
||||||
|
} else {
|
||||||
|
// XXX weird state.
|
||||||
|
panic("vm_page_fault: non kernel thread accessing user memory "
|
||||||
|
"that doesn't exist!\n");
|
||||||
|
status = B_BAD_ADDRESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the hit was probably in the 64k DMZ between kernel and user space
|
||||||
|
// this keeps a user space thread from passing a buffer that crosses
|
||||||
|
// into kernel space
|
||||||
|
status = B_BAD_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == B_OK)
|
||||||
|
status = vm_soft_fault(addressSpace, pageAddress, isWrite, isUser);
|
||||||
|
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n",
|
dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n",
|
||||||
strerror(status), address, faultAddress, isWrite, isUser,
|
strerror(status), address, faultAddress, isWrite, isUser,
|
||||||
@@ -3984,17 +4025,16 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if 1
|
#if 1
|
||||||
// ToDo: remove me once we have proper userland debugging support (and tools)
|
|
||||||
vm_address_space *addressSpace = vm_get_current_user_address_space();
|
|
||||||
vm_area *area;
|
|
||||||
|
|
||||||
rw_lock_read_lock(&addressSpace->lock);
|
rw_lock_read_lock(&addressSpace->lock);
|
||||||
|
|
||||||
|
// TODO: remove me once we have proper userland debugging support
|
||||||
|
// (and tools)
|
||||||
|
vm_area *area = vm_area_lookup(addressSpace, faultAddress);
|
||||||
|
|
||||||
// TODO: The user_memcpy() below can cause a deadlock, if it causes a page
|
// TODO: The user_memcpy() below can cause a deadlock, if it causes a page
|
||||||
// fault and someone is already waiting for a write lock on the same address
|
// fault and someone is already waiting for a write lock on the same address
|
||||||
// space. This thread will then try to acquire the semaphore again and will
|
// space. This thread will then try to acquire the semaphore again and will
|
||||||
// be queued after the writer.
|
// be queued after the writer.
|
||||||
area = vm_area_lookup(addressSpace, faultAddress);
|
|
||||||
|
|
||||||
dprintf("vm_page_fault: sending team \"%s\" 0x%lx SIGSEGV, ip %#lx (\"%s\" +%#lx)\n",
|
dprintf("vm_page_fault: sending team \"%s\" 0x%lx SIGSEGV, ip %#lx (\"%s\" +%#lx)\n",
|
||||||
thread_get_current_thread()->team->name,
|
thread_get_current_thread()->team->name,
|
||||||
thread_get_current_thread()->team->id, faultAddress,
|
thread_get_current_thread()->team->id, faultAddress,
|
||||||
@@ -4051,8 +4091,8 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
|
|||||||
#endif // 0 (stack trace)
|
#endif // 0 (stack trace)
|
||||||
|
|
||||||
rw_lock_read_unlock(&addressSpace->lock);
|
rw_lock_read_unlock(&addressSpace->lock);
|
||||||
vm_put_address_space(addressSpace);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct thread *thread = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
// TODO: the fault_callback is a temporary solution for vm86
|
// TODO: the fault_callback is a temporary solution for vm86
|
||||||
if (thread->fault_callback == NULL
|
if (thread->fault_callback == NULL
|
||||||
@@ -4063,6 +4103,8 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm_put_address_space(addressSpace);
|
||||||
|
|
||||||
return B_HANDLED_INTERRUPT;
|
return B_HANDLED_INTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4448,41 +4490,20 @@ if (cacheOffset == 0x12000)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
|
vm_soft_fault(vm_address_space *addressSpace, addr_t originalAddress,
|
||||||
|
bool isWrite, bool isUser)
|
||||||
{
|
{
|
||||||
vm_address_space *addressSpace;
|
|
||||||
|
|
||||||
FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n",
|
FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n",
|
||||||
thread_get_current_thread_id(), originalAddress, isWrite, isUser));
|
thread_get_current_thread_id(), originalAddress, isWrite, isUser));
|
||||||
|
|
||||||
addr_t address = ROUNDOWN(originalAddress, B_PAGE_SIZE);
|
AddressSpaceReadLocker locker(addressSpace, true);
|
||||||
|
|
||||||
if (IS_KERNEL_ADDRESS(address)) {
|
|
||||||
addressSpace = vm_get_kernel_address_space();
|
|
||||||
} else if (IS_USER_ADDRESS(address)) {
|
|
||||||
addressSpace = vm_get_current_user_address_space();
|
|
||||||
if (addressSpace == NULL) {
|
|
||||||
if (!isUser) {
|
|
||||||
dprintf("vm_soft_fault: kernel thread accessing invalid user memory!\n");
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
} else {
|
|
||||||
// XXX weird state.
|
|
||||||
panic("vm_soft_fault: non kernel thread accessing user memory that doesn't exist!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// the hit was probably in the 64k DMZ between kernel and user space
|
|
||||||
// this keeps a user space thread from passing a buffer that crosses
|
|
||||||
// into kernel space
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddressSpaceReadLocker locker(addressSpace);
|
|
||||||
|
|
||||||
atomic_add(&addressSpace->fault_count, 1);
|
atomic_add(&addressSpace->fault_count, 1);
|
||||||
|
|
||||||
// Get the area the fault was in
|
// Get the area the fault was in
|
||||||
|
|
||||||
|
addr_t address = ROUNDOWN(originalAddress, B_PAGE_SIZE);
|
||||||
|
|
||||||
vm_area *area = vm_area_lookup(addressSpace, address);
|
vm_area *area = vm_area_lookup(addressSpace, address);
|
||||||
if (area == NULL) {
|
if (area == NULL) {
|
||||||
dprintf("vm_soft_fault: va 0x%lx not covered by area in address space\n",
|
dprintf("vm_soft_fault: va 0x%lx not covered by area in address space\n",
|
||||||
@@ -5000,7 +5021,8 @@ lock_memory_etc(team_id team, void *address, size_t numBytes, uint32 flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = vm_soft_fault(base, (flags & B_READ_DEVICE) != 0, isUser);
|
status = vm_soft_fault(addressSpace, base, (flags & B_READ_DEVICE) != 0,
|
||||||
|
isUser);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) failed: %s\n",
|
dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) failed: %s\n",
|
||||||
(void *)unalignedBase, numBytes, flags, strerror(status));
|
(void *)unalignedBase, numBytes, flags, strerror(status));
|
||||||
|
|||||||
Reference in New Issue
Block a user