[Haiku-commits] r31032 - haiku/trunk/src/add-ons/kernel/partitioning_systems/efi
mmlr at mail.berlios.de
mmlr at mail.berlios.de
Sat Jun 13 17:51:23 CEST 2009
Author: mmlr
Date: 2009-06-13 17:51:19 +0200 (Sat, 13 Jun 2009)
New Revision: 31032
ViewCVS: http://svn.berlios.de/viewcvs/haiku?rev=31032&view=rev
Added:
haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/PartitionLocker.cpp
haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/PartitionLocker.h
Modified:
haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/Jamfile
haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.cpp
haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.h
Log:
Implement most of the logic for write support in the GPT partitioning system.
Actual writing is not implemented though and some key functions aren't either.
Completely untested so far.
Modified: haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/Jamfile 2009-06-13 13:56:25 UTC (rev 31031)
+++ haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/Jamfile 2009-06-13 15:51:19 UTC (rev 31032)
@@ -6,4 +6,5 @@
KernelAddon efi_gpt :
efi_gpt.cpp
+ PartitionLocker.cpp
;
Copied: haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/PartitionLocker.cpp (from rev 31031, haiku/trunk/src/add-ons/kernel/partitioning_systems/intel/PartitionLocker.cpp)
Copied: haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/PartitionLocker.h (from rev 31031, haiku/trunk/src/add-ons/kernel/partitioning_systems/intel/PartitionLocker.h)
Modified: haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.cpp 2009-06-13 13:56:25 UTC (rev 31031)
+++ haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.cpp 2009-06-13 15:51:19 UTC (rev 31032)
@@ -1,4 +1,5 @@
/*
+ * Copyright 2009, Michael Lotz, mmlr at mlotz.ch. All rights reserved.
* Copyright 2007-2008, Axel Dörfler, axeld at pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
@@ -11,6 +12,7 @@
# include <boot/partitions.h>
#else
# include <DiskDeviceTypes.h>
+# include "PartitionLocker.h"
#endif
#include <util/kernel_cpp.h>
@@ -53,18 +55,32 @@
class Header {
public:
Header(int fd, off_t block, uint32 blockSize);
+#ifndef _BOOT_MODE
+ // constructor for empty header
+ Header(off_t block, uint32 blockSize);
+#endif
~Header();
status_t InitCheck() const;
bool IsPrimary() const
{ return fBlock == EFI_HEADER_LOCATION; }
+ uint64 FirstUsableBlock() const
+ { return fHeader.FirstUsableBlock(); }
+ uint64 LastUsableBlock() const
+ { return fHeader.LastUsableBlock(); }
+
uint32 EntryCount() const
{ return fHeader.EntryCount(); }
- const efi_partition_entry &EntryAt(int32 index) const
- { return *(const efi_partition_entry*)
+ efi_partition_entry &EntryAt(int32 index) const
+ { return *(efi_partition_entry *)
(fEntries + fHeader.EntrySize() * index); }
+#ifndef _BOOT_MODE
+ status_t WriteEntry(int fd, uint32 entryIndex);
+ status_t Write(int fd);
+#endif
+
private:
#ifdef TRACE_EFI_GPT
const char *_PrintGUID(const guid_t &id);
@@ -141,7 +157,16 @@
}
-const char *
+#ifndef _BOOT_MODE
+static void
+to_ucs2(const char *from, size_t fromLength, uint16 *to, size_t maxToLength)
+{
+ // TODO: implement
+}
+#endif // !_BOOT_MODE
+
+
+static const char *
get_partition_type(const guid_t &guid)
{
for (uint32 i = 0; i < sizeof(kTypeMap) / sizeof(kTypeMap[0]); i++) {
@@ -153,6 +178,32 @@
}
+#ifndef _BOOT_MODE
+static const static_guid *
+guid_for_partition_type(const char *type)
+{
+ for (uint32 i = 0; i < sizeof(kTypeMap) / sizeof(kTypeMap[0]); i++) {
+ if (strcmp(kTypeMap[i].type, type) == 0)
+ return &kTypeMap[i].guid;
+ }
+
+ return NULL;
+}
+
+
+static off_t
+block_align(partition_data *partition, off_t offset, bool upwards)
+{
+ if (upwards) {
+ return ((offset + partition->block_size - 1) / partition->block_size)
+ * partition->block_size;
+ }
+
+ return (offset / partition->block_size) * partition->block_size;
+}
+#endif // !_BOOT_MODE
+
+
// #pragma mark -
@@ -224,6 +275,51 @@
}
+#ifndef _BOOT_MODE
+Header::Header(off_t block, uint32 blockSize)
+ :
+ fBlock(block),
+ fBlockSize(blockSize),
+ fStatus(B_NO_INIT),
+ fEntries(NULL)
+{
+ // initialize to an empty header
+ memcpy(fHeader.header, EFI_PARTITION_HEADER, sizeof(fHeader.header));
+ fHeader.SetRevision(EFI_TABLE_REVISION);
+ fHeader.SetHeaderSize(sizeof(fHeader));
+ fHeader.SetHeaderCRC(0);
+ fHeader.SetAbsoluteBlock(fBlock);
+ fHeader.SetAlternateBlock(0); // TODO
+ // TODO: set disk guid
+ fHeader.SetEntriesBlock(EFI_PARTITION_ENTRIES_BLOCK);
+ fHeader.SetEntryCount(EFI_PARTITION_ENTRY_COUNT);
+ fHeader.SetEntrySize(EFI_PARTITION_ENTRY_SIZE);
+ fHeader.SetEntriesCRC(0);
+
+ size_t arraySize = _EntryArraySize();
+ fEntries = new (std::nothrow) uint8[arraySize];
+ if (fEntries == NULL) {
+ fStatus = B_NO_MEMORY;
+ return;
+ }
+
+ memset(fEntries, 0, arraySize);
+ // TODO: initialize the entry guids
+
+ fHeader.SetFirstUsableBlock(EFI_PARTITION_ENTRIES_BLOCK
+ + (arraySize + fBlockSize - 1) / fBlockSize);
+ fHeader.SetLastUsableBlock(0); // TODO
+
+#ifdef TRACE_EFI_GPT
+ _Dump();
+ _DumpPartitions();
+#endif
+
+ fStatus = B_OK;
+}
+#endif // !_BOOT_MODE
+
+
Header::~Header()
{
delete[] fEntries;
@@ -237,6 +333,24 @@
}
+#ifndef _BOOT_MODE
+status_t
+Header::WriteEntry(int fd, uint32 entryIndex)
+{
+ // TODO: implement
+ return B_ERROR;
+}
+
+
+status_t
+Header::Write(int fd)
+{
+ // TODO: implement
+ return B_ERROR;
+}
+#endif // !_BOOT_MODE
+
+
bool
Header::_ValidateCRC(uint8 *data, size_t size) const
{
@@ -348,6 +462,7 @@
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM | B_PARTITION_READ_ONLY;
partition->content_size = partition->size;
+ partition->content_cookie = header;
// scan all children
@@ -381,9 +496,9 @@
child->offset = partition->offset + entry.StartBlock()
* partition->block_size;
- child->size = (entry.EndBlock() - entry.StartBlock())
- * partition->block_size;
+ child->size = entry.BlockCount() * partition->block_size;
child->block_size = partition->block_size;
+ child->cookie = (void *)i;
}
return B_OK;
@@ -391,13 +506,695 @@
static void
-efi_gpt_free_identify_partition_cookie(partition_data *partition, void *_cookie)
+efi_gpt_free_partition_content_cookie(partition_data *partition)
{
- delete (EFI::Header *)_cookie;
+ delete (EFI::Header *)partition->content_cookie;
}
#ifndef _BOOT_MODE
+static uint32
+efi_gpt_get_supported_operations(partition_data *partition, uint32 mask)
+{
+ uint32 flags = B_DISK_SYSTEM_SUPPORTS_INITIALIZING
+ | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
+ | B_DISK_SYSTEM_SUPPORTS_MOVING
+ | B_DISK_SYSTEM_SUPPORTS_RESIZING
+ | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD;
+ // TODO: check for available entries and partitionable space and only
+ // add creating child support if both is valid
+
+ return flags;
+}
+
+
+static uint32
+efi_gpt_get_supported_child_operations(partition_data *partition,
+ partition_data *child, uint32 mask)
+{
+ return B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
+ | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
+ | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
+ | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD;
+}
+
+
+static bool
+efi_gpt_is_sub_system_for(partition_data *partition)
+{
+ // a GUID Partition Table doesn't usually live inside another partition
+ return false;
+}
+
+
+static bool
+efi_gpt_validate_resize(partition_data *partition, off_t *size)
+{
+ off_t newSize = *size;
+ if (newSize == partition->size)
+ return true;
+
+ if (newSize < 0)
+ newSize = 0;
+ else
+ newSize = block_align(partition, newSize, false);
+
+ // growing
+ if (newSize > partition->size) {
+ *size = newSize;
+ return true;
+ }
+
+ // shrinking, only so that no child would be truncated
+ off_t newEnd = partition->offset + newSize;
+ for (int32 i = 0; i < partition->child_count; i++) {
+ partition_data *child = get_child_partition(partition->id, i);
+ if (child == NULL)
+ continue;
+
+ if (child->offset + child->size > newEnd)
+ newEnd = child->offset + child->size;
+ }
+
+ newSize = block_align(partition, newEnd - partition->offset, true);
+ *size = newSize;
+ return true;
+}
+
+
+static bool
+efi_gpt_validate_resize_child(partition_data *partition, partition_data *child,
+ off_t *size)
+{
+ off_t newSize = *size;
+ if (newSize == child->size)
+ return true;
+
+ // shrinking
+ if (newSize < child->size) {
+ if (newSize < 0)
+ newSize = 0;
+
+ *size = block_align(partition, newSize, false);
+ return true;
+ }
+
+ // growing, but only so much that the child doesn't get bigger than
+ // the parent
+ if (child->offset + newSize > partition->offset + partition->size)
+ newSize = partition->offset + partition->size - child->offset;
+
+ // make sure that the child doesn't overlap any sibling partitions
+ off_t newEnd = child->offset + newSize;
+ for (int32 i = 0; i < partition->child_count; i++) {
+ partition_data *other = get_child_partition(partition->id, i);
+ if (other == NULL || other->id == child->id
+ || other->offset < child->offset)
+ continue;
+
+ if (newEnd > other->offset)
+ newEnd = other->offset;
+ }
+
+ *size = block_align(partition, newEnd - child->offset, false);
+ return true;
+}
+
+
+static bool
+efi_gpt_validate_move(partition_data *partition, off_t *start)
+{
+ // nothing to do
+ return true;
+}
+
+
+static bool
+efi_gpt_validate_move_child(partition_data *partition, partition_data *child,
+ off_t *start)
+{
+ off_t newStart = *start;
+ if (newStart < 0)
+ newStart = 0;
+
+ if (newStart + child->size > partition->size)
+ newStart = partition->size - child->size;
+
+ newStart = block_align(partition, newStart, false);
+ if (newStart > child->offset) {
+ for (int32 i = 0; i < partition->child_count; i++) {
+ partition_data *other = get_child_partition(partition->id, i);
+ if (other == NULL || other->id == child->id
+ || other->offset < child->offset)
+ continue;
+
+ if (other->offset < newStart + child->size)
+ newStart = other->offset - child->size;
+ }
+
+ newStart = block_align(partition, newStart, false);
+ } else {
+ for (int32 i = 0; i < partition->child_count; i++) {
+ partition_data *other = get_child_partition(partition->id, i);
+ if (other == NULL || other->id == child->id
+ || other->offset > child->offset)
+ continue;
+
+ if (other->offset + other->size > newStart)
+ newStart = other->offset + other->size;
+ }
+
+ newStart = block_align(partition, newStart, true);
+ }
+
+ *start = newStart;
+ return true;
+}
+
+
+static bool
+efi_gpt_validate_set_content_name(partition_data *partition, char *name)
+{
+ // TODO: should validate that the utf-8 -> ucs-2 is valid
+ // TODO: should count actual utf-8 chars
+ if (strlen(name) > EFI_PARTITION_NAME_LENGTH)
+ name[EFI_PARTITION_NAME_LENGTH - 1] = 0;
+ return true;
+}
+
+
+static bool
+efi_gpt_validate_set_type(partition_data *partition, const char *type)
+{
+ return guid_for_partition_type(type) != NULL;
+}
+
+
+static bool
+efi_gpt_validate_initialize(partition_data *partition, char *name,
+ const char *parameters)
+{
+ if ((efi_gpt_get_supported_operations(partition, ~0)
+ & B_DISK_SYSTEM_SUPPORTS_INITIALIZING) == 0)
+ return false;
+
+ // name and parameters are ignored
+ if (name != NULL)
+ name[0] = 0;
+
+ return true;
+}
+
+
+static bool
+efi_gpt_validate_create_child(partition_data *partition, off_t *start,
+ off_t *size, const char *type, const char *parameters, int32 *index)
+{
+ if ((efi_gpt_get_supported_operations(partition, ~0)
+ & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) == 0)
+ return false;
+
+ if (guid_for_partition_type(type) == NULL)
+ return false;
+
+ EFI::Header *header = (EFI::Header *)partition->content_cookie;
+ int32 entryIndex = -1;
+ for (uint32 i = 0; i < header->EntryCount(); i++) {
+ const efi_partition_entry &entry = header->EntryAt(i);
+ if (entry.partition_type == kEmptyGUID) {
+ entryIndex = i;
+ break;
+ }
+ }
+
+ if (entryIndex < 0)
+ return false;
+ *index = entryIndex;
+
+ // ensure that child lies between first and last usable block
+ off_t firstUsable = header->FirstUsableBlock() * partition->block_size;
+ if (*start < firstUsable)
+ *start = firstUsable;
+
+ off_t lastUsable = header->LastUsableBlock() * partition->block_size;
+ if (*start + *size > lastUsable) {
+ if (*start > lastUsable)
+ return false;
+
+ *size = lastUsable - *start;
+ }
+
+ // ensure that we don't overlap any siblings
+ for (int32 i = 0; i < partition->child_count; i++) {
+ partition_data *other = get_child_partition(partition->id, i);
+ if (other == NULL)
+ continue;
+
+ if (other->offset < *start && other->offset + other->size > *start)
+ *start = other->offset + other->size;
+
+ if (other->offset > *start && other->offset < *start + *size)
+ *size = other->offset - *start;
+ }
+
+ *start = block_align(partition, *size, true);
+ *size = block_align(partition, *size, false);
+
+ // TODO: support parameters
+ return true;
+}
+
+
+static status_t
+efi_gpt_get_partitionable_spaces(partition_data *partition,
+ partitionable_space_data *buffer, int32 count, int32 *actualCount)
+{
+ // TODO: implement
+ return B_ERROR;
+}
+
+
+static status_t
+efi_gpt_get_next_supported_type(partition_data *partition, int32 *cookie,
+ char *type)
+{
+ // TODO: implement
+ return B_ERROR;
+}
+
+
+static status_t
+efi_gpt_shadow_changed(partition_data *partition, partition_data *child,
+ uint32 operation)
+{
+ // TODO: implement
+ return B_ERROR;
+}
+
+
+static status_t
+efi_gpt_repair(int fd, partition_id partition, bool checkOnly, disk_job_id job)
+{
+ // TODO: implement, validate CRCs and restore from backup area if corrupt
+ return B_ERROR;
+}
+
+
+static status_t
+efi_gpt_resize(int fd, partition_id partitionID, off_t size, disk_job_id job)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ PartitionWriteLocker locker(partitionID);
+ if (!locker.IsLocked())
+ return B_ERROR;
+
+ partition_data *partition = get_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ off_t validatedSize = size;
+ if (!efi_gpt_validate_resize(partition, &validatedSize))
+ return B_BAD_VALUE;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ partition->size = validatedSize;
+ partition->content_size = validatedSize;
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(partitionID);
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_resize_child(int fd, partition_id partitionID, off_t size,
+ disk_job_id job)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ PartitionWriteLocker locker(partitionID);
+ if (!locker.IsLocked())
+ return B_ERROR;
+
+ partition_data *child = get_partition(partitionID);
+ if (child == NULL)
+ return B_BAD_VALUE;
+
+ partition_data *partition = get_parent_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ EFI::Header *header = (EFI::Header *)partition->content_cookie;
+ if (header == NULL)
+ return B_BAD_VALUE;
+
+ uint32 entryIndex = (uint32)child->cookie;
+ if (entryIndex >= header->EntryCount())
+ return B_BAD_VALUE;
+
+ off_t validatedSize = size;
+ if (!efi_gpt_validate_resize_child(partition, child, &validatedSize))
+ return B_BAD_VALUE;
+
+ if (child->size == validatedSize)
+ return B_OK;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ efi_partition_entry &entry = header->EntryAt(entryIndex);
+ entry.SetBlockCount(validatedSize / partition->block_size);
+
+ status_t result = header->WriteEntry(fd, entryIndex);
+ if (result != B_OK) {
+ entry.SetBlockCount(child->size / partition->block_size);
+ return result;
+ }
+
+ child->size = validatedSize;
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(partitionID);
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_move(int fd, partition_id partition, off_t offset, disk_job_id job)
+{
+ // nothing to do here
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_move_child(int fd, partition_id partitionID, partition_id childID,
+ off_t offset, disk_job_id job)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ PartitionWriteLocker locker(partitionID);
+ if (!locker.IsLocked())
+ return B_ERROR;
+
+ partition_data *partition = get_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ partition_data *child = get_partition(childID);
+ if (child == NULL)
+ return B_BAD_VALUE;
+
+ EFI::Header *header = (EFI::Header *)partition->content_cookie;
+ if (header == NULL)
+ return B_BAD_VALUE;
+
+ uint32 entryIndex = (uint32)child->cookie;
+ if (entryIndex >= header->EntryCount())
+ return B_BAD_VALUE;
+
+ off_t validatedOffset = offset;
+ if (!efi_gpt_validate_move_child(partition, child, &validatedOffset))
+ return B_BAD_VALUE;
+
+ if (child->offset == validatedOffset)
+ return B_OK;
+
+ // TODO: implement actual moving, need to move the partition content
+ // (the raw data) here and need to take overlap into account
+ return B_ERROR;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ efi_partition_entry &entry = header->EntryAt(entryIndex);
+ uint64 blockCount = entry.BlockCount();
+ entry.SetStartBlock((validatedOffset - partition->offset)
+ / partition->block_size);
+ entry.SetBlockCount(blockCount);
+
+ status_t result = header->WriteEntry(fd, entryIndex);
+ if (result != B_OK) {
+ // fatal error: the data has been moved but the partition table could
+ // not be updated to reflect that change!
+ return result;
+ }
+
+ child->offset = validatedOffset;
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(childID);
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_set_content_name(int fd, partition_id partitionID, const char *name,
+ disk_job_id job)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ PartitionWriteLocker locker(partitionID);
+ if (!locker.IsLocked())
+ return B_ERROR;
+
+ partition_data *child = get_partition(partitionID);
+ if (child == NULL)
+ return B_BAD_VALUE;
+
+ partition_data *partition = get_parent_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ EFI::Header *header = (EFI::Header *)partition->content_cookie;
+ if (header == NULL)
+ return B_BAD_VALUE;
+
+ uint32 entryIndex = (uint32)child->cookie;
+ if (entryIndex >= header->EntryCount())
+ return B_BAD_VALUE;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ efi_partition_entry &entry = header->EntryAt(entryIndex);
+ to_ucs2(name, strlen(name), entry.name, EFI_PARTITION_NAME_LENGTH);
+
+ status_t result = header->WriteEntry(fd, entryIndex);
+ if (result != B_OK)
+ return result;
+
+ char newName[B_OS_NAME_LENGTH];
+ to_utf8(entry.name, EFI_PARTITION_NAME_LENGTH, newName, sizeof(newName));
+ child->name = strdup(newName);
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(partitionID);
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_set_type(int fd, partition_id partitionID, const char *type,
+ disk_job_id job)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ PartitionWriteLocker locker(partitionID);
+ if (!locker.IsLocked())
+ return B_ERROR;
+
+ partition_data *child = get_partition(partitionID);
+ if (child == NULL)
+ return B_BAD_VALUE;
+
+ partition_data *partition = get_parent_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ EFI::Header *header = (EFI::Header *)partition->content_cookie;
+ if (header == NULL)
+ return B_BAD_VALUE;
+
+ uint32 entryIndex = (uint32)child->cookie;
+ if (entryIndex >= header->EntryCount())
+ return B_BAD_VALUE;
+
+ const static_guid *newType = guid_for_partition_type(type);
+ if (newType == NULL)
+ return B_BAD_VALUE;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ efi_partition_entry &entry = header->EntryAt(entryIndex);
+ memcpy(&entry.partition_type, newType, sizeof(entry.partition_type));
+
+ status_t result = header->WriteEntry(fd, entryIndex);
+ if (result != B_OK)
+ return result;
+
+ child->type = strdup(type);
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(partitionID);
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_initialize(int fd, partition_id partitionID, const char *name,
+ const char *parameters, off_t partitionSize, disk_job_id job)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ partition_data *partition = get_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ EFI::Header header(EFI_HEADER_LOCATION, partition->block_size);
+ status_t result = header.InitCheck();
+ if (result != B_OK)
+ return result;
+
+ result = header.Write(fd);
+ if (result != B_OK)
+ return result;
+
+ result = scan_partition(partitionID);
+ if (result != B_OK)
+ return result;
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(partitionID);
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_create_child(int fd, partition_id partitionID, off_t offset,
+ off_t size, const char *type, const char *parameters, disk_job_id job,
+ partition_id *childID)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ PartitionWriteLocker locker(partitionID);
+ if (!locker.IsLocked())
+ return B_ERROR;
+
+ partition_data *partition = get_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ EFI::Header *header = (EFI::Header *)partition->content_cookie;
+ if (header == NULL)
+ return B_BAD_VALUE;
+
+ off_t validatedOffset = offset;
+ off_t validatedSize = size;
+ uint32 entryIndex = 0;
+
+ if (!efi_gpt_validate_create_child(partition, &validatedOffset,
+ &validatedSize, type, parameters, (int32 *)&entryIndex))
+ return B_BAD_VALUE;
+
+ const static_guid *newType = guid_for_partition_type(type);
+ if (newType == NULL)
+ return B_BAD_VALUE;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ partition_data *child = create_child_partition(partition->id, entryIndex,
+ *childID);
+ if (child == NULL)
+ return B_ERROR;
+
+ efi_partition_entry &entry = header->EntryAt(entryIndex);
+ memcpy(&entry.partition_type, newType, sizeof(entry.partition_type));
+ entry.SetStartBlock((validatedOffset - partition->offset)
+ / partition->block_size);
+ entry.SetBlockCount(validatedSize / partition->block_size);
+ entry.SetAttributes(0); // TODO
+
+ status_t result = header->WriteEntry(fd, entryIndex);
+ if (result != B_OK) {
+ delete_partition(child->id);
+ return result;
+ }
+
+ *childID = child->id;
+ child->offset = validatedOffset;
+ child->size = validatedSize;
+ child->block_size = partition->block_size;
+ child->type = strdup(type);
+ child->parameters = strdup(parameters);
+ child->cookie = (void *)entryIndex;
+
+ if (child->type == NULL || child->parameters == NULL) {
+ delete_partition(child->id);
+ return B_NO_MEMORY;
+ }
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(partitionID);
+ return B_OK;
+}
+
+
+static status_t
+efi_gpt_delete_child(int fd, partition_id partitionID, partition_id childID,
+ disk_job_id job)
+{
+ if (fd < 0)
+ return B_ERROR;
+
+ PartitionWriteLocker locker(partitionID);
+ if (!locker.IsLocked())
+ return B_ERROR;
+
+ partition_data *partition = get_partition(partitionID);
+ if (partition == NULL)
+ return B_BAD_VALUE;
+
+ partition_data *child = get_partition(childID);
+ if (child == NULL)
+ return B_BAD_VALUE;
+
+ EFI::Header *header = (EFI::Header *)partition->content_cookie;
+ if (header == NULL)
+ return B_BAD_VALUE;
+
+ uint32 entryIndex = (uint32)child->cookie;
+ if (entryIndex >= header->EntryCount())
+ return B_BAD_VALUE;
+
+ update_disk_device_job_progress(job, 0.0);
+
+ if (!delete_partition(childID))
+ return B_ERROR;
+
+ efi_partition_entry &entry = header->EntryAt(entryIndex);
+ entry.partition_type = kEmptyGUID;
+
+ status_t result = header->WriteEntry(fd, entryIndex);
+ if (result != B_OK)
+ return result;
+
+ update_disk_device_job_progress(job, 1.0);
+ partition_modified(partitionID);
+ return B_OK;
+}
+#endif // !_BOOT_MODE
+
+
+#ifndef _BOOT_MODE
static partition_module_info sEFIPartitionModule = {
#else
partition_module_info gEFIPartitionModule = {
@@ -409,13 +1206,68 @@
},
"efi", // short_name
EFI_PARTITION_NAME, // pretty_name
- 0, // flags
+ 0 // flags
+ | B_DISK_SYSTEM_SUPPORTS_INITIALIZING
+ | B_DISK_SYSTEM_SUPPORTS_MOVING
+ | B_DISK_SYSTEM_SUPPORTS_RESIZING
+ | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
+ | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
+ | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
+ | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
+ | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
+ | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD
+ | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD
+ ,
// scanning
efi_gpt_identify_partition,
efi_gpt_scan_partition,
- efi_gpt_free_identify_partition_cookie,
- NULL,
+ NULL, // free_identify_partition_cookie
+ NULL, // free_partition_cookie
+ efi_gpt_free_partition_content_cookie,
+
+#ifndef _BOOT_MODE
+ // querying
+ efi_gpt_get_supported_operations,
+ efi_gpt_get_supported_child_operations,
+ NULL, // supports_initializing_child
+ efi_gpt_is_sub_system_for,
+
+ efi_gpt_validate_resize,
+ efi_gpt_validate_resize_child,
+ efi_gpt_validate_move,
+ efi_gpt_validate_move_child,
+ NULL, // validate_set_name
+ efi_gpt_validate_set_content_name,
+ efi_gpt_validate_set_type,
+ NULL, // validate_set_parameters
+ NULL, // validate_set_content_parameters
+ efi_gpt_validate_initialize,
+ efi_gpt_validate_create_child,
+ efi_gpt_get_partitionable_spaces,
+ efi_gpt_get_next_supported_type,
+ NULL, // get_type_for_content_type
+
+ // shadow partition modification
+ efi_gpt_shadow_changed,
+
+ // writing
+ efi_gpt_repair,
+ efi_gpt_resize,
+ efi_gpt_resize_child,
+ efi_gpt_move,
+ efi_gpt_move_child,
+ NULL, // set_name
+ efi_gpt_set_content_name,
+ efi_gpt_set_type,
+ NULL, // set_parameters
+ NULL, // set_content_parameters
+ efi_gpt_initialize,
+ efi_gpt_create_child,
+ efi_gpt_delete_child
+#else
+ NULL
+#endif // _BOOT_MODE
};
#ifndef _BOOT_MODE
Modified: haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.h 2009-06-13 13:56:25 UTC (rev 31031)
+++ haiku/trunk/src/add-ons/kernel/partitioning_systems/efi/efi_gpt.h 2009-06-13 15:51:19 UTC (rev 31032)
@@ -31,36 +31,62 @@
// the rest of the block is reserved
+ void SetRevision(uint32 revision)
+ { revision = B_HOST_TO_LENDIAN_INT32(revision); }
uint32 Revision() const
{ return B_LENDIAN_TO_HOST_INT32(revision); }
+ void SetHeaderSize(uint32 size)
[... truncated: 83 lines follow ...]
More information about the Haiku-commits
mailing list