gpt: Fixed a number of remaining issues.
* The header and table is now correctly written; the backup is still missing, though. * The Header class is now responsible for both, the primary, and the backup header. * Changed the Header constructors: the block is no longer needed. Also, under GCC 4 the initialization code accidentally used the read Header constructor. * Fixed incorrectly copied GUID - the static_guid cannot be copied into a guid_t directly. * Fixed copy&paste bug that would overwrite the offset for the child partition to be created. * With all of this in place I successfully created a BFS partition with a GUID partition table. However, I have not yet tested if other systems can still read this. Also, creating two partitions doesn't seem to work yet, either (luckily I only need a single one ;-)).
This commit is contained in:
@@ -38,9 +38,8 @@
|
||||
namespace EFI {
|
||||
|
||||
|
||||
Header::Header(int fd, off_t block, uint32 blockSize)
|
||||
Header::Header(int fd, uint64 lastBlock, uint32 blockSize)
|
||||
:
|
||||
fBlock(block),
|
||||
fBlockSize(blockSize),
|
||||
fStatus(B_NO_INIT),
|
||||
fEntries(NULL)
|
||||
@@ -49,8 +48,8 @@ Header::Header(int fd, off_t block, uint32 blockSize)
|
||||
|
||||
// read and check the partition table header
|
||||
|
||||
ssize_t bytesRead = read_pos(fd, block * blockSize, &fHeader,
|
||||
sizeof(efi_table_header));
|
||||
ssize_t bytesRead = read_pos(fd, (uint64)EFI_HEADER_LOCATION * blockSize,
|
||||
&fHeader, sizeof(efi_table_header));
|
||||
if (bytesRead != (ssize_t)sizeof(efi_table_header)) {
|
||||
if (bytesRead < B_OK)
|
||||
fStatus = bytesRead;
|
||||
@@ -62,7 +61,7 @@ Header::Header(int fd, off_t block, uint32 blockSize)
|
||||
|
||||
if (memcmp(fHeader.header, EFI_PARTITION_HEADER, sizeof(fHeader.header))
|
||||
|| !_ValidateHeaderCRC()
|
||||
|| fHeader.AbsoluteBlock() != fBlock) {
|
||||
|| fHeader.AbsoluteBlock() != EFI_HEADER_LOCATION) {
|
||||
// TODO: check that partition counts are in valid bounds
|
||||
fStatus = B_BAD_DATA;
|
||||
return;
|
||||
@@ -105,19 +104,21 @@ Header::Header(int fd, off_t block, uint32 blockSize)
|
||||
|
||||
|
||||
#ifndef _BOOT_MODE
|
||||
Header::Header(off_t block, off_t lastBlock, uint32 blockSize)
|
||||
Header::Header(uint64 lastBlock, uint32 blockSize)
|
||||
:
|
||||
fBlock(block),
|
||||
fBlockSize(blockSize),
|
||||
fStatus(B_NO_INIT),
|
||||
fEntries(NULL)
|
||||
{
|
||||
// initialize to an empty header
|
||||
TRACE(("EFI::Header: Initialize GPT, block size %" B_PRIu32 "\n",
|
||||
blockSize));
|
||||
|
||||
// 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.SetAbsoluteBlock(EFI_HEADER_LOCATION);
|
||||
fHeader.SetAlternateBlock(0); // TODO
|
||||
// TODO: set disk guid
|
||||
fHeader.SetEntriesBlock(EFI_PARTITION_ENTRIES_BLOCK);
|
||||
@@ -142,9 +143,6 @@ Header::Header(off_t block, off_t lastBlock, uint32 blockSize)
|
||||
#ifdef TRACE_EFI_GPT
|
||||
_Dump();
|
||||
_DumpPartitions();
|
||||
dprintf("GPT: HERE I AM!\n");
|
||||
#else
|
||||
dprintf("GPT: Nope!\n");
|
||||
#endif
|
||||
|
||||
fStatus = B_OK;
|
||||
@@ -182,12 +180,26 @@ Header::WriteEntry(int fd, uint32 entryIndex)
|
||||
// TODO: write mirror at the end
|
||||
|
||||
// Update header, too -- the entries CRC changed
|
||||
return Write(fd);
|
||||
return _WriteHeader(fd);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Header::Write(int fd)
|
||||
{
|
||||
status_t status = _Write(fd, fHeader.EntriesBlock() * fBlockSize, fEntries,
|
||||
_EntryArraySize());
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// TODO: write mirror at the end
|
||||
|
||||
return _WriteHeader(fd);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Header::_WriteHeader(int fd)
|
||||
{
|
||||
_UpdateCRC();
|
||||
|
||||
@@ -200,7 +212,6 @@ Header::Write(int fd)
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
#endif // !_BOOT_MODE
|
||||
|
||||
|
||||
status_t
|
||||
@@ -223,6 +234,7 @@ Header::_UpdateCRC()
|
||||
fHeader.SetHeaderCRC(0);
|
||||
fHeader.SetHeaderCRC(crc32((uint8*)&fHeader, sizeof(efi_table_header)));
|
||||
}
|
||||
#endif // !_BOOT_MODE
|
||||
|
||||
|
||||
bool
|
||||
@@ -233,7 +245,6 @@ Header::_ValidateHeaderCRC()
|
||||
|
||||
bool matches = originalCRC == crc32((const uint8*)&fHeader,
|
||||
sizeof(efi_table_header));
|
||||
dprintf("GPT: MATCHES %d!\n", matches);
|
||||
|
||||
fHeader.SetHeaderCRC(originalCRC);
|
||||
return matches;
|
||||
@@ -266,7 +277,7 @@ void
|
||||
Header::_Dump()
|
||||
{
|
||||
dprintf("EFI header: %.8s\n", fHeader.header);
|
||||
dprintf("EFI revision: %ld\n", fHeader.Revision());
|
||||
dprintf("EFI revision: %" B_PRIx32 "\n", fHeader.Revision());
|
||||
dprintf("header size: %ld\n", fHeader.HeaderSize());
|
||||
dprintf("header CRC: %ld\n", fHeader.HeaderCRC());
|
||||
dprintf("absolute block: %Ld\n", fHeader.AbsoluteBlock());
|
||||
|
||||
@@ -16,17 +16,15 @@ namespace EFI {
|
||||
|
||||
class Header {
|
||||
public:
|
||||
Header(int fd, off_t block, uint32 blockSize);
|
||||
Header(int fd, uint64 lastBlock,
|
||||
uint32 blockSize);
|
||||
#ifndef _BOOT_MODE
|
||||
// constructor for empty header
|
||||
Header(off_t block, off_t lastBlock,
|
||||
uint32 blockSize);
|
||||
Header(uint64 lastBlock, uint32 blockSize);
|
||||
#endif
|
||||
~Header();
|
||||
|
||||
status_t InitCheck() const;
|
||||
bool IsPrimary() const
|
||||
{ return fBlock == EFI_HEADER_LOCATION; }
|
||||
|
||||
uint64 FirstUsableBlock() const
|
||||
{ return fHeader.FirstUsableBlock(); }
|
||||
@@ -49,9 +47,13 @@ private:
|
||||
void _Dump();
|
||||
void _DumpPartitions();
|
||||
|
||||
#ifndef _BOOT_MODE
|
||||
status_t _WriteHeader(int fd);
|
||||
status_t _Write(int fd, off_t offset, const void* data,
|
||||
size_t size) const;
|
||||
void _UpdateCRC();
|
||||
#endif
|
||||
|
||||
bool _ValidateHeaderCRC();
|
||||
bool _ValidateEntriesCRC() const;
|
||||
size_t _EntryArraySize() const
|
||||
@@ -59,7 +61,6 @@ private:
|
||||
* fHeader.EntryCount(); }
|
||||
|
||||
private:
|
||||
uint64 fBlock;
|
||||
uint32 fBlockSize;
|
||||
status_t fStatus;
|
||||
efi_table_header fHeader;
|
||||
|
||||
@@ -71,10 +71,10 @@ efi_gpt_std_ops(int32 op, ...)
|
||||
static float
|
||||
efi_gpt_identify_partition(int fd, partition_data *partition, void **_cookie)
|
||||
{
|
||||
EFI::Header *header = new (std::nothrow) EFI::Header(fd,
|
||||
EFI_HEADER_LOCATION, partition->block_size);
|
||||
EFI::Header* header = new (std::nothrow) EFI::Header(fd,
|
||||
partition->size / partition->block_size, partition->block_size);
|
||||
status_t status = header->InitCheck();
|
||||
if (status < B_OK) {
|
||||
if (status != B_OK) {
|
||||
delete header;
|
||||
return -1;
|
||||
}
|
||||
@@ -323,7 +323,8 @@ efi_gpt_validate_set_content_name(partition_data *partition, char *name)
|
||||
static bool
|
||||
efi_gpt_validate_set_type(partition_data *partition, const char *type)
|
||||
{
|
||||
return guid_for_partition_type(type) != NULL;
|
||||
guid_t typeGUID;
|
||||
return get_guid_for_partition_type(type, typeGUID);
|
||||
}
|
||||
|
||||
|
||||
@@ -352,7 +353,7 @@ efi_gpt_validate_create_child(partition_data *partition, off_t *start,
|
||||
& B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) == 0)
|
||||
return false;
|
||||
|
||||
if (guid_for_partition_type(type) == NULL)
|
||||
if (!efi_gpt_validate_set_type(partition, type))
|
||||
return false;
|
||||
|
||||
EFI::Header *header = (EFI::Header *)partition->content_cookie;
|
||||
@@ -396,7 +397,7 @@ efi_gpt_validate_create_child(partition_data *partition, off_t *start,
|
||||
*size = other->offset - *start;
|
||||
}
|
||||
|
||||
*start = block_align(partition, *size, true);
|
||||
*start = block_align(partition, *start, true);
|
||||
*size = block_align(partition, *size, false);
|
||||
|
||||
// TODO: support parameters
|
||||
@@ -663,14 +664,14 @@ efi_gpt_set_type(int fd, partition_id partitionID, const char *type,
|
||||
if (entryIndex >= header->EntryCount())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
const static_guid *newType = guid_for_partition_type(type);
|
||||
if (newType == NULL)
|
||||
guid_t typeGUID;
|
||||
if (!get_guid_for_partition_type(type, typeGUID))
|
||||
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));
|
||||
entry.partition_type = typeGUID;
|
||||
|
||||
status_t result = header->WriteEntry(fd, entryIndex);
|
||||
if (result != B_OK)
|
||||
@@ -697,8 +698,8 @@ efi_gpt_initialize(int fd, partition_id partitionID, const char *name,
|
||||
|
||||
update_disk_device_job_progress(job, 0.0);
|
||||
|
||||
EFI::Header header(EFI_HEADER_LOCATION,
|
||||
partitionSize / partition->block_size, partition->block_size);
|
||||
EFI::Header header(partitionSize / partition->block_size,
|
||||
partition->block_size);
|
||||
status_t result = header.InitCheck();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
@@ -745,8 +746,8 @@ efi_gpt_create_child(int fd, partition_id partitionID, off_t offset,
|
||||
&validatedSize, type, name, parameters, (int32 *)&entryIndex))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
const static_guid *newType = guid_for_partition_type(type);
|
||||
if (newType == NULL)
|
||||
guid_t typeGUID;
|
||||
if (!get_guid_for_partition_type(type, typeGUID))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
update_disk_device_job_progress(job, 0.0);
|
||||
@@ -757,7 +758,8 @@ efi_gpt_create_child(int fd, partition_id partitionID, off_t offset,
|
||||
return B_ERROR;
|
||||
|
||||
efi_partition_entry &entry = header->EntryAt(entryIndex);
|
||||
memcpy(&entry.partition_type, newType, sizeof(entry.partition_type));
|
||||
entry.partition_type = typeGUID;
|
||||
// TODO: set unique partition ID
|
||||
to_ucs2(name, strlen(name), entry.name, EFI_PARTITION_NAME_LENGTH);
|
||||
entry.SetStartBlock((validatedOffset - partition->offset)
|
||||
/ partition->block_size);
|
||||
@@ -844,7 +846,7 @@ partition_module_info gEFIPartitionModule = {
|
||||
0,
|
||||
efi_gpt_std_ops
|
||||
},
|
||||
"efi", // short_name
|
||||
"gpt", // short_name
|
||||
EFI_PARTITION_NAME, // pretty_name
|
||||
0 // flags
|
||||
| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
|
||||
|
||||
@@ -22,24 +22,39 @@ struct static_guid {
|
||||
uint16 data3;
|
||||
uint64 data4;
|
||||
|
||||
inline bool operator==(const guid &other) const;
|
||||
inline bool operator==(const guid& other) const;
|
||||
inline operator guid_t() const;
|
||||
} _PACKED;
|
||||
|
||||
|
||||
inline bool
|
||||
static_guid::operator==(const guid_t &other) const
|
||||
static_guid::operator==(const guid_t& other) const
|
||||
{
|
||||
return B_HOST_TO_LENDIAN_INT32(data1) == other.data1
|
||||
&& B_HOST_TO_LENDIAN_INT16(data2) == other.data2
|
||||
&& B_HOST_TO_LENDIAN_INT16(data3) == other.data3
|
||||
&& B_HOST_TO_BENDIAN_INT64(*(uint64 *)&data4) == *(uint64 *)other.data4;
|
||||
&& B_HOST_TO_BENDIAN_INT64(*(uint64*)&data4) == *(uint64*)other.data4;
|
||||
// the last 8 bytes are in big-endian order
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
static_guid::operator guid_t() const
|
||||
{
|
||||
guid_t guid;
|
||||
guid.data1 = B_HOST_TO_LENDIAN_INT32(data1);
|
||||
guid.data2 = B_HOST_TO_LENDIAN_INT16(data2);
|
||||
guid.data3 = B_HOST_TO_LENDIAN_INT16(data3);
|
||||
uint64 last = B_HOST_TO_BENDIAN_INT64(*(uint64*)&data4);
|
||||
memcpy(guid.data4, &last, sizeof(uint64));
|
||||
|
||||
return guid;
|
||||
}
|
||||
|
||||
|
||||
const static struct type_map {
|
||||
static_guid guid;
|
||||
const char *type;
|
||||
const char* type;
|
||||
} kTypeMap[] = {
|
||||
{{0xC12A7328, 0xF81F, 0x11D2, 0xBA4B00A0C93EC93BLL}, "EFI System Data"},
|
||||
{{0x21686148, 0x6449, 0x6E6F, 0x744E656564454649LL}, "BIOS Boot Data"},
|
||||
|
||||
@@ -21,7 +21,7 @@ const guid_t kEmptyGUID = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
|
||||
|
||||
static void
|
||||
put_utf8_byte(char *&to, size_t &left, char c)
|
||||
put_utf8_byte(char*& to, size_t& left, char c)
|
||||
{
|
||||
if (left <= 1)
|
||||
return;
|
||||
@@ -35,7 +35,7 @@ put_utf8_byte(char *&to, size_t &left, char c)
|
||||
|
||||
|
||||
void
|
||||
to_utf8(const uint16 *from, size_t maxFromLength, char *to, size_t toSize)
|
||||
to_utf8(const uint16* from, size_t maxFromLength, char* to, size_t toSize)
|
||||
{
|
||||
for (uint32 i = 0; i < maxFromLength; i++) {
|
||||
uint16 c = B_LENDIAN_TO_HOST_INT16(from[i]);
|
||||
@@ -66,10 +66,10 @@ to_utf8(const uint16 *from, size_t maxFromLength, char *to, size_t toSize)
|
||||
|
||||
#ifndef _BOOT_MODE
|
||||
void
|
||||
to_ucs2(const char *from, size_t fromLength, uint16 *to, size_t maxToLength)
|
||||
to_ucs2(const char* from, size_t fromLength, uint16* to, size_t maxToLength)
|
||||
{
|
||||
size_t index = 0;
|
||||
while (from[0] && index < maxToLength) {
|
||||
while (from[0] != '\0' && index < maxToLength) {
|
||||
// TODO: handle characters that are not representable in UCS-2 better
|
||||
uint32 code = UTF8ToCharCode(&from);
|
||||
if (code < 0x10000)
|
||||
@@ -82,8 +82,8 @@ to_ucs2(const char *from, size_t fromLength, uint16 *to, size_t maxToLength)
|
||||
#endif // !_BOOT_MODE
|
||||
|
||||
|
||||
const char *
|
||||
get_partition_type(const guid_t &guid)
|
||||
const char*
|
||||
get_partition_type(const guid_t& guid)
|
||||
{
|
||||
for (uint32 i = 0; i < sizeof(kTypeMap) / sizeof(kTypeMap[0]); i++) {
|
||||
if (kTypeMap[i].guid == guid)
|
||||
@@ -95,14 +95,16 @@ get_partition_type(const guid_t &guid)
|
||||
|
||||
|
||||
#ifndef _BOOT_MODE
|
||||
const static_guid *
|
||||
guid_for_partition_type(const char *type)
|
||||
bool
|
||||
get_guid_for_partition_type(const char* type, guid_t& guid)
|
||||
{
|
||||
for (uint32 i = 0; i < sizeof(kTypeMap) / sizeof(kTypeMap[0]); i++) {
|
||||
if (strcmp(kTypeMap[i].type, type) == 0)
|
||||
return &kTypeMap[i].guid;
|
||||
if (strcmp(kTypeMap[i].type, type) == 0) {
|
||||
guid = kTypeMap[i].guid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
#endif // !_BOOT_MODE
|
||||
|
||||
@@ -24,7 +24,7 @@ const char* get_partition_type(const guid_t& guid);
|
||||
#ifndef _BOOT_MODE
|
||||
void to_ucs2(const char* from, size_t fromLength, uint16* to,
|
||||
size_t maxToLength);
|
||||
const static_guid* guid_for_partition_type(const char* type);
|
||||
bool get_guid_for_partition_type(const char* type, guid_t& guid);
|
||||
#endif // !_BOOT_MODE
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user