From ef2558c0aea88aa525b9ede73710a513dc47de6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 26 Jan 2013 20:43:59 +0100 Subject: [PATCH] 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 ;-)). --- .../partitioning_systems/gpt/Header.cpp | 43 ++++++++++++------- .../kernel/partitioning_systems/gpt/Header.h | 13 +++--- .../partitioning_systems/gpt/efi_gpt.cpp | 32 +++++++------- .../gpt/gpt_known_guids.h | 23 ++++++++-- .../partitioning_systems/gpt/utility.cpp | 24 ++++++----- .../kernel/partitioning_systems/gpt/utility.h | 2 +- 6 files changed, 84 insertions(+), 53 deletions(-) diff --git a/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp b/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp index 6bcd288c0c..c47b64c3a1 100644 --- a/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp +++ b/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp @@ -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()); diff --git a/src/add-ons/kernel/partitioning_systems/gpt/Header.h b/src/add-ons/kernel/partitioning_systems/gpt/Header.h index d87dd12b83..486a5e2aba 100644 --- a/src/add-ons/kernel/partitioning_systems/gpt/Header.h +++ b/src/add-ons/kernel/partitioning_systems/gpt/Header.h @@ -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; diff --git a/src/add-ons/kernel/partitioning_systems/gpt/efi_gpt.cpp b/src/add-ons/kernel/partitioning_systems/gpt/efi_gpt.cpp index 12e88c787b..3f76591133 100644 --- a/src/add-ons/kernel/partitioning_systems/gpt/efi_gpt.cpp +++ b/src/add-ons/kernel/partitioning_systems/gpt/efi_gpt.cpp @@ -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 diff --git a/src/add-ons/kernel/partitioning_systems/gpt/gpt_known_guids.h b/src/add-ons/kernel/partitioning_systems/gpt/gpt_known_guids.h index 1fb1ceff07..249f63975e 100644 --- a/src/add-ons/kernel/partitioning_systems/gpt/gpt_known_guids.h +++ b/src/add-ons/kernel/partitioning_systems/gpt/gpt_known_guids.h @@ -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"}, diff --git a/src/add-ons/kernel/partitioning_systems/gpt/utility.cpp b/src/add-ons/kernel/partitioning_systems/gpt/utility.cpp index c43718d1db..4564377d8c 100644 --- a/src/add-ons/kernel/partitioning_systems/gpt/utility.cpp +++ b/src/add-ons/kernel/partitioning_systems/gpt/utility.cpp @@ -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 diff --git a/src/add-ons/kernel/partitioning_systems/gpt/utility.h b/src/add-ons/kernel/partitioning_systems/gpt/utility.h index 17f9fe0741..c89db23984 100644 --- a/src/add-ons/kernel/partitioning_systems/gpt/utility.h +++ b/src/add-ons/kernel/partitioning_systems/gpt/utility.h @@ -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