diff --git a/src/kernel/core/disk_device_manager/KDiskDevice.cpp b/src/kernel/core/disk_device_manager/KDiskDevice.cpp index 67216120a3..e1e62aad71 100644 --- a/src/kernel/core/disk_device_manager/KDiskDevice.cpp +++ b/src/kernel/core/disk_device_manager/KDiskDevice.cpp @@ -344,6 +344,7 @@ KDiskDevice::WriteUserData(UserDataWriter &writer, bool shadow) if (data) { data->device_flags = DeviceFlags(); data->path = path; + writer.AddRelocationEntry(&data->path); partition->WriteUserData(writer, &data->device_partition_data); } else partition->WriteUserData(writer, NULL); diff --git a/src/kernel/core/disk_device_manager/KPartition.cpp b/src/kernel/core/disk_device_manager/KPartition.cpp index d30e3f3531..b3c8865948 100644 --- a/src/kernel/core/disk_device_manager/KPartition.cpp +++ b/src/kernel/core/disk_device_manager/KPartition.cpp @@ -938,13 +938,22 @@ KPartition::WriteUserData(UserDataWriter &writer, user_partition_data *data) data->parameters = parameters; data->content_parameters = contentParameters; data->child_count = CountChildren(); + // make buffer relocatable + writer.AddRelocationEntry(&data->name); + writer.AddRelocationEntry(&data->content_name); + writer.AddRelocationEntry(&data->type); + writer.AddRelocationEntry(&data->content_type); + writer.AddRelocationEntry(&data->parameters); + writer.AddRelocationEntry(&data->content_parameters); } // children for (int32 i = 0; KPartition *child = ChildAt(i); i++) { user_partition_data *childData = writer.AllocatePartitionData(child->CountChildren()); - if (data) + if (data) { data->children[i] = childData; + writer.AddRelocationEntry(&data->children[i]); + } child->WriteUserData(writer, childData); } } diff --git a/src/kernel/core/disk_device_manager/UserDataWriter.cpp b/src/kernel/core/disk_device_manager/UserDataWriter.cpp index aaaf20883f..9053d63adf 100644 --- a/src/kernel/core/disk_device_manager/UserDataWriter.cpp +++ b/src/kernel/core/disk_device_manager/UserDataWriter.cpp @@ -1,43 +1,87 @@ // UserDataWriter.cpp +#include + #include +#include #include "UserDataWriter.h" +using namespace std; + +typedef uint8 *addr; + +// RelocationEntryList +struct UserDataWriter::RelocationEntryList : Vector {}; + // constructor UserDataWriter::UserDataWriter() : fBuffer(NULL), fBufferSize(0), - fAllocatedSize(0) + fAllocatedSize(0), + fRelocationEntries(NULL) { } // constructor UserDataWriter::UserDataWriter(user_disk_device_data *buffer, size_t bufferSize) - : fBuffer(buffer), - fBufferSize(bufferSize), - fAllocatedSize(0) + : fBuffer(NULL), + fBufferSize(0), + fAllocatedSize(0), + fRelocationEntries(NULL) { + SetTo(buffer, bufferSize); } // destructor UserDataWriter::~UserDataWriter() { + delete fRelocationEntries; +} + +// SetTo +status_t +UserDataWriter::SetTo(user_disk_device_data *buffer, size_t bufferSize) +{ + Unset(); + fBuffer = buffer; + fBufferSize = bufferSize; + fAllocatedSize = 0; + if (fBuffer && fBufferSize > 0) { + fRelocationEntries = new(nothrow) RelocationEntryList; + if (!fRelocationEntries) + return B_NO_MEMORY; + } + return B_OK; +} + +// Unset +void +UserDataWriter::Unset() +{ + delete fRelocationEntries; + fBuffer = NULL; + fBufferSize = 0; + fAllocatedSize = 0; + fRelocationEntries = NULL; } // AllocateData void * UserDataWriter::AllocateData(size_t size, size_t align = 1) { - if (size == 0) - return NULL; + // handles size == 0 gracefully + // get a properly aligned offset + size_t offset = fAllocatedSize; if (align > 1) - fAllocatedSize = (fAllocatedSize + align - 1) / align * align; + offset = (fAllocatedSize + align - 1) / align * align; + // get the result pointer void *result = NULL; - if (fAllocatedSize + size <= fBufferSize) - result = (uint8*)fBuffer + fAllocatedSize; - fAllocatedSize += size; + if (fBuffer && offset + size <= fBufferSize) + result = (uint8*)fBuffer + offset; + // always update the allocated size, even if there wasn't enough space + fAllocatedSize = offset + size; return result; } @@ -81,3 +125,29 @@ UserDataWriter::AllocatedSize() const return fAllocatedSize; } +// AddRelocationEntry +status_t +UserDataWriter::AddRelocationEntry(void *address) +{ + if (fRelocationEntries && (addr)address >= (addr)fBuffer + && (addr)address < (addr)fBuffer + fBufferSize - sizeof(void*)) { + return fRelocationEntries->PushBack((addr*)address); + } + return B_ERROR; +} + +// Relocate +status_t +UserDataWriter::Relocate(void *address) +{ + if (!fRelocationEntries || !fBuffer) + return B_BAD_VALUE; + int32 count = fRelocationEntries->Count(); + for (int32 i = 0; i < count; i++) { + addr *entry = fRelocationEntries->ElementAt(i); + if (*entry) + *entry += (addr)address - (addr)fBuffer; + } + return B_OK; +} + diff --git a/src/kernel/core/disk_device_manager/UserDataWriter.h b/src/kernel/core/disk_device_manager/UserDataWriter.h index 0f312d9116..ebb883c133 100644 --- a/src/kernel/core/disk_device_manager/UserDataWriter.h +++ b/src/kernel/core/disk_device_manager/UserDataWriter.h @@ -17,6 +17,9 @@ public: UserDataWriter(user_disk_device_data *buffer, size_t bufferSize); ~UserDataWriter(); + status_t SetTo(user_disk_device_data *buffer, size_t bufferSize); + void Unset(); + void *AllocateData(size_t size, size_t align = 1); user_partition_data *AllocatePartitionData(size_t childCount); user_disk_device_data *AllocateDeviceData(size_t childCount); @@ -25,10 +28,16 @@ public: size_t AllocatedSize() const; + status_t AddRelocationEntry(void *address); + status_t Relocate(void *address); + private: + struct RelocationEntryList; + user_disk_device_data *fBuffer; size_t fBufferSize; size_t fAllocatedSize; + RelocationEntryList *fRelocationEntries; }; } // namespace DiskDevice