IORequest: Add ClearData()

This commit is contained in:
Ingo Weinhold
2013-11-11 22:27:53 +01:00
parent 426fe7db1d
commit c63b3de665
2 changed files with 113 additions and 0 deletions
@@ -13,6 +13,7 @@
#include <debug.h>
#include <heap.h>
#include <kernel.h>
#include <team.h>
#include <thread.h>
#include <util/AutoLock.h>
#include <vm/vm.h>
@@ -1153,6 +1154,60 @@ IORequest::CopyData(const void* buffer, off_t offset, size_t size)
}
status_t
IORequest::ClearData(off_t offset, generic_size_t size)
{
if (size == 0)
return B_OK;
if (offset < fOffset || offset + (off_t)size > fOffset + (off_t)fLength) {
panic("IORequest::ClearData(): invalid range: (%" B_PRIdOFF
", %" B_PRIuGENADDR ")", offset, size);
return B_BAD_VALUE;
}
// If we can, we directly copy from/to the virtual buffer. The memory is
// locked in this case.
status_t (*clearFunction)(generic_addr_t, generic_size_t, team_id);
if (fBuffer->IsPhysical()) {
clearFunction = &IORequest::_ClearDataPhysical;
} else {
clearFunction = fBuffer->IsUser() && fTeam != team_get_current_team_id()
? &IORequest::_ClearDataUser : &IORequest::_ClearDataSimple;
}
// skip bytes if requested
generic_io_vec* vecs = fBuffer->Vecs();
generic_size_t skipBytes = offset - fOffset;
generic_size_t vecOffset = 0;
while (skipBytes > 0) {
if (vecs[0].length > skipBytes) {
vecOffset = skipBytes;
break;
}
skipBytes -= vecs[0].length;
vecs++;
}
// clear vector-wise
while (size > 0) {
generic_size_t toClear = min_c(size, vecs[0].length - vecOffset);
status_t error = clearFunction(vecs[0].base + vecOffset, toClear,
fTeam);
if (error != B_OK)
return error;
size -= toClear;
vecs++;
vecOffset = 0;
}
return B_OK;
}
status_t
IORequest::_CopyData(void* _buffer, off_t offset, size_t size, bool copyIn)
{
@@ -1271,6 +1326,57 @@ IORequest::_CopyUser(void* _bounceBuffer, generic_addr_t _external, size_t size,
}
/*static*/ status_t
IORequest::_ClearDataSimple(generic_addr_t external, generic_size_t size,
team_id team)
{
memset((void*)(addr_t)external, 0, (size_t)size);
return B_OK;
}
/*static*/ status_t
IORequest::_ClearDataPhysical(generic_addr_t external, generic_size_t size,
team_id team)
{
return vm_memset_physical((phys_addr_t)external, 0, (phys_size_t)size);
}
/*static*/ status_t
IORequest::_ClearDataUser(generic_addr_t _external, generic_size_t size,
team_id team)
{
uint8* external = (uint8*)(addr_t)_external;
while (size > 0) {
static const int32 kEntryCount = 8;
physical_entry entries[kEntryCount];
uint32 count = kEntryCount;
status_t error = get_memory_map_etc(team, external, size, entries,
&count);
if (error != B_OK && error != B_BUFFER_OVERFLOW) {
panic("IORequest::_ClearDataUser(): Failed to get physical memory "
"for user memory %p\n", external);
return B_BAD_ADDRESS;
}
for (uint32 i = 0; i < count; i++) {
const physical_entry& entry = entries[i];
error = _ClearDataPhysical(entry.address, entry.size, team);
if (error != B_OK)
return error;
size -= entry.size;
external += entry.size;
}
}
return B_OK;
}
void
IORequest::Dump() const
{
@@ -302,6 +302,7 @@ struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
size_t size);
status_t CopyData(const void* buffer, off_t offset,
size_t size);
status_t ClearData(off_t offset, generic_size_t size);
void Dump() const;
@@ -317,6 +318,12 @@ private:
static status_t _CopyUser(void* bounceBuffer,
generic_addr_t external, size_t size,
team_id team, bool copyIn);
static status_t _ClearDataSimple(generic_addr_t external,
generic_size_t size, team_id team);
static status_t _ClearDataPhysical(generic_addr_t external,
generic_size_t size, team_id team);
static status_t _ClearDataUser(generic_addr_t external,
generic_size_t size, team_id team);
mutex fLock;
IORequestOwner* fOwner;