Header::Header(uint64 lastBlock, uint32 blockSize) : fBlockSize(blockSize), fStatus(B_NO_INIT), fEntries(NULL) { 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(EFI_HEADER_LOCATION); fHeader.SetAlternateBlock(lastBlock); uuid_t uuid; uuid_generate_random(uuid); memcpy((uint8*)&fHeader.disk_guid, uuid, sizeof(guid_t)); 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 uint32 entryBlocks = (arraySize + fBlockSize - 1) / fBlockSize; fHeader.SetFirstUsableBlock(EFI_PARTITION_ENTRIES_BLOCK + entryBlocks); fHeader.SetLastUsableBlock(lastBlock - 1 - entryBlocks); _SetBackupHeaderFromPrimary(lastBlock); #ifdef TRACE_EFI_GPT _Dump(fHeader); _DumpPartitions(); #endif fStatus = B_OK; }
Header::Header(int fd, uint64 lastBlock, uint32 blockSize) : fBlockSize(blockSize), fStatus(B_NO_INIT), fEntries(NULL) { // TODO: check the correctness of the protective MBR and warn if invalid // Read and check the partition table header fStatus = _Read(fd, (uint64)EFI_HEADER_LOCATION * blockSize, &fHeader, sizeof(efi_table_header)); if (fStatus == B_OK) { if (!_IsHeaderValid(fHeader, EFI_HEADER_LOCATION)) fStatus = B_BAD_DATA; } if (fStatus == B_OK && lastBlock != fHeader.AlternateBlock()) { dprintf("gpt: alternate header not in last block (%" B_PRIu64 " vs. %" B_PRIu64 ")\n", fHeader.AlternateBlock(), lastBlock); lastBlock = fHeader.AlternateBlock(); } // Read backup header, too status_t status = _Read(fd, lastBlock * blockSize, &fBackupHeader, sizeof(efi_table_header)); if (status == B_OK) { if (!_IsHeaderValid(fBackupHeader, lastBlock)) status = B_BAD_DATA; } // If both headers are invalid, bail out -- this is probably not a GPT disk if (status != B_OK && fStatus != B_OK) return; if (fStatus != B_OK) { // Recreate primary header from the backup fHeader = fBackupHeader; fHeader.SetAbsoluteBlock(EFI_HEADER_LOCATION); fHeader.SetEntriesBlock(EFI_PARTITION_ENTRIES_BLOCK); fHeader.SetAlternateBlock(lastBlock); } else if (status != B_OK) { // Recreate backup header from primary _SetBackupHeaderFromPrimary(lastBlock); } // allocate, read, and check partition entry array fEntries = new (std::nothrow) uint8[_EntryArraySize()]; if (fEntries == NULL) { // TODO: if there cannot be allocated enough (ie. the boot loader's // heap is limited), try a smaller size before failing fStatus = B_NO_MEMORY; return; } fStatus = _Read(fd, fHeader.EntriesBlock() * blockSize, fEntries, _EntryArraySize()); if (fStatus != B_OK || !_ValidateEntriesCRC()) { // Read backup entries instead fStatus = _Read(fd, fBackupHeader.EntriesBlock() * blockSize, fEntries, _EntryArraySize()); if (fStatus != B_OK) return; if (!_ValidateEntriesCRC()) { fStatus = B_BAD_DATA; return; } } // TODO: check overlapping or out of range partitions #ifdef TRACE_EFI_GPT _Dump(fHeader); _Dump(fBackupHeader); _DumpPartitions(); #endif fStatus = B_OK; }