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. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31032 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -6,4 +6,5 @@ UsePrivateHeaders [ FDirName storage ] ;
|
|||||||
|
|
||||||
KernelAddon efi_gpt :
|
KernelAddon efi_gpt :
|
||||||
efi_gpt.cpp
|
efi_gpt.cpp
|
||||||
|
PartitionLocker.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2007, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Tomas Kucera, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PartitionLocker.h"
|
||||||
|
|
||||||
|
// #pragma mark - PartitionLocker
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
PartitionLocker::PartitionLocker(partition_id partitionID)
|
||||||
|
: fDevice(NULL),
|
||||||
|
fPartitionID(partitionID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
PartitionLocker::~PartitionLocker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLocked
|
||||||
|
bool
|
||||||
|
PartitionLocker::IsLocked() const
|
||||||
|
{
|
||||||
|
return fDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PartitionId
|
||||||
|
partition_id
|
||||||
|
PartitionLocker::PartitionId() const
|
||||||
|
{
|
||||||
|
return fPartitionID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PartitionReadLocker
|
||||||
|
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
PartitionReadLocker::PartitionReadLocker(partition_id partitionID)
|
||||||
|
: PartitionLocker(partitionID)
|
||||||
|
{
|
||||||
|
fDevice = read_lock_disk_device(partitionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
PartitionReadLocker::~PartitionReadLocker()
|
||||||
|
{
|
||||||
|
if (IsLocked())
|
||||||
|
read_unlock_disk_device(PartitionId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PartitionWriteLocker
|
||||||
|
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
PartitionWriteLocker::PartitionWriteLocker(partition_id partitionID)
|
||||||
|
: PartitionLocker(partitionID)
|
||||||
|
{
|
||||||
|
fDevice = write_lock_disk_device(partitionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
PartitionWriteLocker::~PartitionWriteLocker()
|
||||||
|
{
|
||||||
|
if (IsLocked())
|
||||||
|
write_unlock_disk_device(PartitionId());
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2007, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Tomas Kucera, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\file PartitionLocker.h
|
||||||
|
\ingroup intel_module
|
||||||
|
\brief Structures for easy locking and automatic unlocking partitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PARTITION_LOCKER_H
|
||||||
|
#define _PARTITION_LOCKER_H
|
||||||
|
|
||||||
|
#include <disk_device_manager.h>
|
||||||
|
|
||||||
|
|
||||||
|
class PartitionLocker {
|
||||||
|
public:
|
||||||
|
PartitionLocker(partition_id partitionID);
|
||||||
|
~PartitionLocker();
|
||||||
|
|
||||||
|
bool IsLocked() const;
|
||||||
|
partition_id PartitionId() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const disk_device_data *fDevice;
|
||||||
|
|
||||||
|
private:
|
||||||
|
partition_id fPartitionID;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Structure which locks given partition for reading.
|
||||||
|
|
||||||
|
When this structure is going to be destroyed, it automatically unlocks
|
||||||
|
that partition.
|
||||||
|
*/
|
||||||
|
class PartitionReadLocker : public PartitionLocker {
|
||||||
|
public:
|
||||||
|
PartitionReadLocker(partition_id partitionID);
|
||||||
|
~PartitionReadLocker();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Structure which locks given partition for writing.
|
||||||
|
|
||||||
|
When this structure is going to be destroyed, it automatically unlocks
|
||||||
|
that partition.
|
||||||
|
*/
|
||||||
|
class PartitionWriteLocker : public PartitionLocker {
|
||||||
|
public:
|
||||||
|
PartitionWriteLocker(partition_id partitionID);
|
||||||
|
~PartitionWriteLocker();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _PARTITION_LOCKER_H
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright 2009, Michael Lotz, [email protected]. All rights reserved.
|
||||||
* Copyright 2007-2008, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2007-2008, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
# include <boot/partitions.h>
|
# include <boot/partitions.h>
|
||||||
#else
|
#else
|
||||||
# include <DiskDeviceTypes.h>
|
# include <DiskDeviceTypes.h>
|
||||||
|
# include "PartitionLocker.h"
|
||||||
#endif
|
#endif
|
||||||
#include <util/kernel_cpp.h>
|
#include <util/kernel_cpp.h>
|
||||||
|
|
||||||
@@ -53,18 +55,32 @@ namespace EFI {
|
|||||||
class Header {
|
class Header {
|
||||||
public:
|
public:
|
||||||
Header(int fd, off_t block, uint32 blockSize);
|
Header(int fd, off_t block, uint32 blockSize);
|
||||||
|
#ifndef _BOOT_MODE
|
||||||
|
// constructor for empty header
|
||||||
|
Header(off_t block, uint32 blockSize);
|
||||||
|
#endif
|
||||||
~Header();
|
~Header();
|
||||||
|
|
||||||
status_t InitCheck() const;
|
status_t InitCheck() const;
|
||||||
bool IsPrimary() const
|
bool IsPrimary() const
|
||||||
{ return fBlock == EFI_HEADER_LOCATION; }
|
{ return fBlock == EFI_HEADER_LOCATION; }
|
||||||
|
|
||||||
|
uint64 FirstUsableBlock() const
|
||||||
|
{ return fHeader.FirstUsableBlock(); }
|
||||||
|
uint64 LastUsableBlock() const
|
||||||
|
{ return fHeader.LastUsableBlock(); }
|
||||||
|
|
||||||
uint32 EntryCount() const
|
uint32 EntryCount() const
|
||||||
{ return fHeader.EntryCount(); }
|
{ return fHeader.EntryCount(); }
|
||||||
const efi_partition_entry &EntryAt(int32 index) const
|
efi_partition_entry &EntryAt(int32 index) const
|
||||||
{ return *(const efi_partition_entry*)
|
{ return *(efi_partition_entry *)
|
||||||
(fEntries + fHeader.EntrySize() * index); }
|
(fEntries + fHeader.EntrySize() * index); }
|
||||||
|
|
||||||
|
#ifndef _BOOT_MODE
|
||||||
|
status_t WriteEntry(int fd, uint32 entryIndex);
|
||||||
|
status_t Write(int fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef TRACE_EFI_GPT
|
#ifdef TRACE_EFI_GPT
|
||||||
const char *_PrintGUID(const guid_t &id);
|
const char *_PrintGUID(const guid_t &id);
|
||||||
@@ -141,7 +157,16 @@ to_utf8(const uint16 *from, size_t maxFromLength, char *to, size_t toSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
get_partition_type(const guid_t &guid)
|
||||||
{
|
{
|
||||||
for (uint32 i = 0; i < sizeof(kTypeMap) / sizeof(kTypeMap[0]); i++) {
|
for (uint32 i = 0; i < sizeof(kTypeMap) / sizeof(kTypeMap[0]); i++) {
|
||||||
@@ -153,6 +178,32 @@ get_partition_type(const guid_t &guid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -224,6 +275,51 @@ Header::Header(int fd, off_t block, uint32 blockSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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()
|
Header::~Header()
|
||||||
{
|
{
|
||||||
delete[] fEntries;
|
delete[] fEntries;
|
||||||
@@ -237,6 +333,24 @@ Header::InitCheck() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
bool
|
||||||
Header::_ValidateCRC(uint8 *data, size_t size) const
|
Header::_ValidateCRC(uint8 *data, size_t size) const
|
||||||
{
|
{
|
||||||
@@ -348,6 +462,7 @@ efi_gpt_scan_partition(int fd, partition_data *partition, void *_cookie)
|
|||||||
partition->status = B_PARTITION_VALID;
|
partition->status = B_PARTITION_VALID;
|
||||||
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM | B_PARTITION_READ_ONLY;
|
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM | B_PARTITION_READ_ONLY;
|
||||||
partition->content_size = partition->size;
|
partition->content_size = partition->size;
|
||||||
|
partition->content_cookie = header;
|
||||||
|
|
||||||
// scan all children
|
// scan all children
|
||||||
|
|
||||||
@@ -381,9 +496,9 @@ efi_gpt_scan_partition(int fd, partition_data *partition, void *_cookie)
|
|||||||
|
|
||||||
child->offset = partition->offset + entry.StartBlock()
|
child->offset = partition->offset + entry.StartBlock()
|
||||||
* partition->block_size;
|
* partition->block_size;
|
||||||
child->size = (entry.EndBlock() - entry.StartBlock())
|
child->size = entry.BlockCount() * partition->block_size;
|
||||||
* partition->block_size;
|
|
||||||
child->block_size = partition->block_size;
|
child->block_size = partition->block_size;
|
||||||
|
child->cookie = (void *)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -391,12 +506,694 @@ efi_gpt_scan_partition(int fd, partition_data *partition, void *_cookie)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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
|
#ifndef _BOOT_MODE
|
||||||
static partition_module_info sEFIPartitionModule = {
|
static partition_module_info sEFIPartitionModule = {
|
||||||
#else
|
#else
|
||||||
@@ -409,13 +1206,68 @@ partition_module_info gEFIPartitionModule = {
|
|||||||
},
|
},
|
||||||
"efi", // short_name
|
"efi", // short_name
|
||||||
EFI_PARTITION_NAME, // pretty_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
|
// scanning
|
||||||
efi_gpt_identify_partition,
|
efi_gpt_identify_partition,
|
||||||
efi_gpt_scan_partition,
|
efi_gpt_scan_partition,
|
||||||
efi_gpt_free_identify_partition_cookie,
|
NULL, // free_identify_partition_cookie
|
||||||
NULL,
|
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
|
#ifndef _BOOT_MODE
|
||||||
|
|||||||
@@ -31,36 +31,62 @@ struct efi_table_header {
|
|||||||
|
|
||||||
// the rest of the block is reserved
|
// the rest of the block is reserved
|
||||||
|
|
||||||
|
void SetRevision(uint32 revision)
|
||||||
|
{ revision = B_HOST_TO_LENDIAN_INT32(revision); }
|
||||||
uint32 Revision() const
|
uint32 Revision() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT32(revision); }
|
{ return B_LENDIAN_TO_HOST_INT32(revision); }
|
||||||
|
void SetHeaderSize(uint32 size)
|
||||||
|
{ header_size = B_HOST_TO_LENDIAN_INT32(size); }
|
||||||
uint32 HeaderSize() const
|
uint32 HeaderSize() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT32(header_size); }
|
{ return B_LENDIAN_TO_HOST_INT32(header_size); }
|
||||||
|
void SetHeaderCRC(uint32 crc)
|
||||||
|
{ header_crc = B_HOST_TO_LENDIAN_INT32(crc); }
|
||||||
uint32 HeaderCRC() const
|
uint32 HeaderCRC() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT32(header_crc); }
|
{ return B_LENDIAN_TO_HOST_INT32(header_crc); }
|
||||||
|
|
||||||
|
void SetAbsoluteBlock(uint64 block)
|
||||||
|
{ absolute_block = B_HOST_TO_LENDIAN_INT64(block); }
|
||||||
uint64 AbsoluteBlock() const
|
uint64 AbsoluteBlock() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(absolute_block); }
|
{ return B_LENDIAN_TO_HOST_INT64(absolute_block); }
|
||||||
|
void SetAlternateBlock(uint64 block)
|
||||||
|
{ alternate_block = B_HOST_TO_LENDIAN_INT64(block); }
|
||||||
uint64 AlternateBlock() const
|
uint64 AlternateBlock() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(alternate_block); }
|
{ return B_LENDIAN_TO_HOST_INT64(alternate_block); }
|
||||||
|
void SetFirstUsableBlock(uint64 block)
|
||||||
|
{ first_usable_block = B_HOST_TO_LENDIAN_INT64(block); }
|
||||||
uint64 FirstUsableBlock() const
|
uint64 FirstUsableBlock() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(first_usable_block); }
|
{ return B_LENDIAN_TO_HOST_INT64(first_usable_block); }
|
||||||
|
void SetLastUsableBlock(uint64 block)
|
||||||
|
{ last_usable_block = B_HOST_TO_LENDIAN_INT64(block); }
|
||||||
uint64 LastUsableBlock() const
|
uint64 LastUsableBlock() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(last_usable_block); }
|
{ return B_LENDIAN_TO_HOST_INT64(last_usable_block); }
|
||||||
|
|
||||||
|
void SetEntriesBlock(uint64 block)
|
||||||
|
{ entries_block = B_HOST_TO_LENDIAN_INT64(block); }
|
||||||
uint64 EntriesBlock() const
|
uint64 EntriesBlock() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(entries_block); }
|
{ return B_LENDIAN_TO_HOST_INT64(entries_block); }
|
||||||
|
void SetEntryCount(uint32 count)
|
||||||
|
{ entry_count = B_HOST_TO_LENDIAN_INT32(count); }
|
||||||
uint32 EntryCount() const
|
uint32 EntryCount() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT32(entry_count); }
|
{ return B_LENDIAN_TO_HOST_INT32(entry_count); }
|
||||||
|
void SetEntrySize(uint32 size)
|
||||||
|
{ entry_size = B_HOST_TO_LENDIAN_INT32(size); }
|
||||||
uint32 EntrySize() const
|
uint32 EntrySize() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT32(entry_size); }
|
{ return B_LENDIAN_TO_HOST_INT32(entry_size); }
|
||||||
|
void SetEntriesCRC(uint32 crc)
|
||||||
|
{ entries_crc = B_HOST_TO_LENDIAN_INT32(crc); }
|
||||||
uint32 EntriesCRC() const
|
uint32 EntriesCRC() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT32(entries_crc); }
|
{ return B_LENDIAN_TO_HOST_INT32(entries_crc); }
|
||||||
} _PACKED;
|
} _PACKED;
|
||||||
|
|
||||||
#define EFI_PARTITION_HEADER "EFI PART"
|
#define EFI_PARTITION_HEADER "EFI PART"
|
||||||
#define EFI_HEADER_LOCATION 1
|
#define EFI_HEADER_LOCATION 1
|
||||||
|
#define EFI_TABLE_REVISION 0x00010000
|
||||||
|
|
||||||
#define EFI_PARTITION_NAME_LENGTH 36
|
#define EFI_PARTITION_NAME_LENGTH 36
|
||||||
|
#define EFI_PARTITION_ENTRIES_BLOCK 2
|
||||||
|
#define EFI_PARTITION_ENTRY_COUNT 128
|
||||||
|
#define EFI_PARTITION_ENTRY_SIZE 128
|
||||||
|
|
||||||
struct efi_partition_entry {
|
struct efi_partition_entry {
|
||||||
guid_t partition_type;
|
guid_t partition_type;
|
||||||
@@ -70,12 +96,24 @@ struct efi_partition_entry {
|
|||||||
uint64 attributes;
|
uint64 attributes;
|
||||||
uint16 name[EFI_PARTITION_NAME_LENGTH];
|
uint16 name[EFI_PARTITION_NAME_LENGTH];
|
||||||
|
|
||||||
|
void SetStartBlock(uint64 block)
|
||||||
|
{ start_block = B_HOST_TO_LENDIAN_INT64(block); }
|
||||||
uint64 StartBlock() const
|
uint64 StartBlock() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(start_block); }
|
{ return B_LENDIAN_TO_HOST_INT64(start_block); }
|
||||||
|
void SetEndBlock(uint64 block)
|
||||||
|
{ end_block = B_HOST_TO_LENDIAN_INT64(block); }
|
||||||
uint64 EndBlock() const
|
uint64 EndBlock() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(end_block); }
|
{ return B_LENDIAN_TO_HOST_INT64(end_block); }
|
||||||
|
void SetAttributes(uint64 _attributes)
|
||||||
|
{ attributes = B_HOST_TO_LENDIAN_INT64(_attributes); }
|
||||||
uint64 Attributes() const
|
uint64 Attributes() const
|
||||||
{ return B_LENDIAN_TO_HOST_INT64(attributes); }
|
{ return B_LENDIAN_TO_HOST_INT64(attributes); }
|
||||||
|
|
||||||
|
// convenience functions
|
||||||
|
void SetBlockCount(uint64 blockCount)
|
||||||
|
{ SetEndBlock(StartBlock() + blockCount - 1); }
|
||||||
|
uint64 BlockCount() const
|
||||||
|
{ return EndBlock() - StartBlock(); }
|
||||||
} _PACKED;
|
} _PACKED;
|
||||||
|
|
||||||
#endif /* EFI_GPT_H */
|
#endif /* EFI_GPT_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user