status_t Header::Write(int fd) { // Try to write the protective MBR PartitionMap partitionMap; PrimaryPartition *partition = NULL; uint32 index = 0; while ((partition = partitionMap.PrimaryPartitionAt(index)) != NULL) { if (index == 0) { uint64 deviceSize = fHeader.AlternateBlock() * fBlockSize; partition->SetTo(fBlockSize, deviceSize, 0xEE, false, fBlockSize); } else partition->Unset(); ++index; } PartitionMapWriter writer(fd, fBlockSize); writer.WriteMBR(&partitionMap, true); // We also write the bootcode, so we can boot GPT disks from BIOS status_t status = _Write(fd, fHeader.EntriesBlock() * fBlockSize, fEntries, _EntryArraySize()); if (status != B_OK) return status; // First write the header, so that we have at least one completely correct // data set status = _WriteHeader(fd); // Write backup entries status_t backupStatus = _Write(fd, fBackupHeader.EntriesBlock() * fBlockSize, fEntries, _EntryArraySize()); return status == B_OK ? backupStatus : status; }
void Header::_UpdateCRC(efi_table_header& header) { header.SetEntriesCRC(crc32(fEntries, _EntryArraySize())); header.SetHeaderCRC(0); header.SetHeaderCRC(crc32((uint8*)&header, sizeof(efi_table_header))); }
void Header::_SetBackupHeaderFromPrimary(uint64 lastBlock) { fBackupHeader = fHeader; fBackupHeader.SetAbsoluteBlock(lastBlock); fBackupHeader.SetEntriesBlock( lastBlock - _EntryArraySize() / fBlockSize); fBackupHeader.SetAlternateBlock(1); }
status_t Header::Write(int fd) { status_t status = _Write(fd, fHeader.EntriesBlock() * fBlockSize, fEntries, _EntryArraySize()); if (status != B_OK) return status; // First write the header, so that we have at least one completely correct // data set status = _WriteHeader(fd); // Write backup entries status_t backupStatus = _Write(fd, fBackupHeader.EntriesBlock() * fBlockSize, fEntries, _EntryArraySize()); return status == B_OK ? backupStatus : status; }
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; }
bool Header::_ValidateEntriesCRC() const { return fHeader.EntriesCRC() == crc32(fEntries, _EntryArraySize()); }