Example #1
0
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;
}
Example #2
0
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;
}