* The EFI partitioning module is now able to detect partitions and file systems

(currently, only the HFS+ GUID is known).
* The header and partition table CRCs are not yet validated, though.
* Enabled EFI in the boot loader test app.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21540 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-07-02 18:53:55 +00:00
parent 516236818d
commit 5cb688f8c0
4 changed files with 244 additions and 27 deletions
@@ -16,6 +16,7 @@
#include <util/kernel_cpp.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
@@ -31,12 +32,31 @@
#define EFI_PARTITION_NAME "EFI GUID Partition Table"
struct static_guid {
uint32 data1;
uint16 data2;
uint16 data3;
uint64 data4;
inline bool operator==(const guid &other) const;
};
const static struct type_map {
static_guid guid;
const char *type;
} kTypeMap[] = {
{{0x48465300, 0x0000, 0x11aa, 0xaa1100306543ECACLL}, "HFS+ File System"}
};
namespace EFI {
class Header {
public:
Header(int fd, off_t block, uint32 blockSize);
~Header();
status_t InitCheck();
status_t InitCheck() const;
bool IsPrimary() const
{ return fBlock == EFI_HEADER_LOCATION; }
@@ -46,11 +66,14 @@ class Header {
{ return *(const efi_partition_entry*)
(fEntries + fHeader.EntrySize() * index); }
void Dump();
private:
bool _ValidateCRC(uint8 *data, size_t size);
#ifdef TRACE_EFI_GPT
const char *_PrintGUID(const guid_t &id);
void _Dump();
void _DumpPartitions();
#endif
bool _ValidateCRC(uint8 *data, size_t size) const;
size_t _EntryArraySize() const
{ return fHeader.EntrySize() * fHeader.EntryCount(); }
@@ -61,6 +84,80 @@ class Header {
uint8 *fEntries;
};
} // namespace EFI
const static guid_t kEmptyGUID = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
inline bool
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;
// the last 8 bytes are in big-endian order
}
static void
put_utf8_byte(char *&to, size_t &left, char c)
{
if (left <= 1)
return;
*(to++) = c;
left--;
}
static void
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]);
if (!c)
break;
if (c < 0x80)
put_utf8_byte(to, toSize, c);
else if (c < 0x800) {
put_utf8_byte(to, toSize, 0xc0 | (c >> 6));
put_utf8_byte(to, toSize, 0x80 | (c & 0x3f));
} else if (c < 0x10000) {
put_utf8_byte(to, toSize, 0xe0 | (c >> 12));
put_utf8_byte(to, toSize, 0x80 | ((c >> 6) & 0x3f));
put_utf8_byte(to, toSize, 0x80 | (c & 0x3f));
} else if (c <= 0x10ffff) {
put_utf8_byte(to, toSize, 0xf0 | (c >> 18));
put_utf8_byte(to, toSize, 0x80 | ((c >> 12) & 0x3f));
put_utf8_byte(to, toSize, 0x80 | ((c >> 6) & 0x3f));
put_utf8_byte(to, toSize, 0x80 | (c & 0x3f));
}
}
if (toSize > 0)
*to = '\0';
}
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)
return kTypeMap[i].type;
}
return NULL;
}
// #pragma mark -
namespace EFI {
Header::Header(int fd, off_t block, uint32 blockSize)
:
@@ -118,8 +215,12 @@ Header::Header(int fd, off_t block, uint32 blockSize)
return;
}
#ifdef TRACE_EFI_GPT
_Dump();
_DumpPartitions();
#endif
fStatus = B_OK;
Dump();
}
@@ -130,28 +231,79 @@ Header::~Header()
status_t
Header::InitCheck()
Header::InitCheck() const
{
return fStatus;
}
bool
Header::_ValidateCRC(uint8 *data, size_t size)
Header::_ValidateCRC(uint8 *data, size_t size) const
{
// TODO: implement!
return true;
}
void
Header::Dump()
#ifdef TRACE_EFI_GPT
const char *
Header::_PrintGUID(const guid_t &id)
{
static char guid[48];
snprintf(guid, sizeof(guid), "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
B_LENDIAN_TO_HOST_INT32(id.data1), B_LENDIAN_TO_HOST_INT16(id.data2),
B_LENDIAN_TO_HOST_INT16(id.data3), id.data4[0], id.data4[1], id.data4[2],
id.data4[3], id.data4[4], id.data4[5], id.data4[6], id.data4[7]);
return guid;
}
void
Header::_Dump()
{
dprintf("EFI header: %.8s\n", fHeader.header);
dprintf("EFI revision: %ld\n", fHeader.Revision());
dprintf("header size: %ld\n", fHeader.HeaderSize());
dprintf("header CRC: %ld\n", fHeader.HeaderCRC());
dprintf("absolute block: %Ld\n", fHeader.AbsoluteBlock());
dprintf("alternate block: %Ld\n", fHeader.AlternateBlock());
dprintf("first usable block: %Ld\n", fHeader.FirstUsableBlock());
dprintf("last usable block: %Ld\n", fHeader.LastUsableBlock());
dprintf("disk GUID: %s\n", _PrintGUID(fHeader.disk_guid));
dprintf("entries block: %Ld\n", fHeader.EntriesBlock());
dprintf("entry size: %ld\n", fHeader.EntrySize());
dprintf("entry count: %ld\n", fHeader.EntryCount());
dprintf("entries CRC: %ld\n", fHeader.EntriesCRC());
}
void
Header::_DumpPartitions()
{
for (uint32 i = 0; i < EntryCount(); i++) {
const efi_partition_entry &entry = EntryAt(i);
if (entry.partition_type == kEmptyGUID)
continue;
dprintf("[%3ld] partition type: %s\n", i, _PrintGUID(entry.partition_type));
dprintf(" unique id: %s\n", _PrintGUID(entry.unique_guid));
dprintf(" start block: %Ld\n", entry.StartBlock());
dprintf(" end block: %Ld\n", entry.EndBlock());
dprintf(" size: %g MB\n", (entry.EndBlock() - entry.StartBlock())
* 512 / 1024.0 / 1024.0);
dprintf(" attributes: %Lx\n", entry.Attributes());
char name[64];
to_utf8(entry.name, EFI_PARTITION_NAME_LENGTH, name, sizeof(name));
dprintf(" name: %s\n", name);
}
}
#endif // TRACE_EFI_GPT
} // namespace EFI
// #pragma mark - public module interface
@@ -171,7 +323,16 @@ efi_gpt_std_ops(int32 op, ...)
static float
efi_gpt_identify_partition(int fd, partition_data *partition, void **_cookie)
{
return B_ERROR;
EFI::Header *header = new (std::nothrow) EFI::Header(fd, EFI_HEADER_LOCATION,
partition->block_size);
status_t status = header->InitCheck();
if (status < B_OK) {
delete header;
return status;
}
*_cookie = header;
return 0.7;
}
@@ -179,25 +340,52 @@ static status_t
efi_gpt_scan_partition(int fd, partition_data *partition, void *_cookie)
{
TRACE(("efi_gpt_scan_partition(cookie = %p)\n", _cookie));
EFI::Header *header = (EFI::Header *)_cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
| B_PARTITION_READ_ONLY;
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM | B_PARTITION_READ_ONLY;
partition->content_size = partition->size;
// scan all children
status_t status = B_ERROR;
if (status == B_ENTRY_NOT_FOUND)
return B_OK;
uint32 index = 0;
return status;
for (uint32 i = 0; i < header->EntryCount(); i++) {
const efi_partition_entry &entry = header->EntryAt(i);
if (entry.partition_type == kEmptyGUID)
continue;
if (entry.EndBlock() * partition->block_size > (uint64)partition->size) {
TRACE(("efi_gpt: child partition exceeds existing space (%Ld MB)\n",
(entry.EndBlock() - entry.StartBlock()) * partition->block_size / 1024 / 1024));
continue;
}
partition_data *child = create_child_partition(partition->id, index++, -1);
if (child == NULL) {
TRACE(("efi_gpt: Creating child at index %ld failed\n", index - 1));
return B_ERROR;
}
char name[B_OS_NAME_LENGTH];
to_utf8(entry.name, EFI_PARTITION_NAME_LENGTH, name, sizeof(name));
child->name = strdup(name);
child->type = strdup(get_partition_type(entry.partition_type));
child->offset = partition->offset + entry.StartBlock() * partition->block_size;
child->size = (entry.EndBlock() - entry.StartBlock()) * partition->block_size;
child->block_size = partition->block_size;
}
return B_OK;
}
static void
efi_gpt_free_identify_partition_cookie(partition_data *partition, void *_cookie)
{
delete (EFI::Header *)_cookie;
}
@@ -219,8 +407,6 @@ partition_module_info gEFIPartitionModule = {
efi_gpt_scan_partition,
efi_gpt_free_identify_partition_cookie,
NULL,
// efi_gpt_free_partition_cookie,
// efi_gpt_free_partition_content_cookie,
};
#ifndef _BOOT_MODE
@@ -55,7 +55,7 @@ struct efi_table_header {
{ return B_LENDIAN_TO_HOST_INT32(entry_size); }
uint32 EntriesCRC() const
{ return B_LENDIAN_TO_HOST_INT32(entries_crc); }
};
} _PACKED;
#define EFI_PARTITION_HEADER "EFI PART"
#define EFI_HEADER_LOCATION 1
@@ -65,11 +65,18 @@ struct efi_table_header {
struct efi_partition_entry {
guid_t partition_type;
guid_t unique_guid;
uint64 start_lba;
uint64 end_lba;
uint64 start_block;
uint64 end_block;
uint64 attributes;
uint16 name[EFI_PARTITION_NAME_LENGTH];
};
uint64 StartBlock() const
{ return B_LENDIAN_TO_HOST_INT64(start_block); }
uint64 EndBlock() const
{ return B_LENDIAN_TO_HOST_INT64(end_block); }
uint64 Attributes() const
{ return B_LENDIAN_TO_HOST_INT64(attributes); }
} _PACKED;
#endif /* EFI_GPT_H */
@@ -10,11 +10,34 @@
typedef struct guid {
uint32 a;
uint16 b;
uint16 c;
uint8 d[8];
uint32 data1;
uint16 data2;
uint16 data3;
uint8 data4[8];
inline bool operator==(const guid &other) const;
inline bool operator!=(const guid &other) const;
} _PACKED guid_t;
inline bool
guid_t::operator==(const guid_t &other) const
{
return data1 == other.data1
&& data2 == other.data2
&& data3 == other.data3
&& *(uint64 *)data4 == *(uint64 *)other.data4;
}
inline bool
guid_t::operator!=(const guid_t &other) const
{
return data1 != other.data1
|| data2 != other.data2
|| data3 != other.data3
|| *(uint64 *)data4 != *(uint64 *)other.data4;
}
#endif /* GUID_H */
+1
View File
@@ -52,6 +52,7 @@ ObjectDefines
BOOT_SUPPORT_PARTITION_AMIGA
BOOT_SUPPORT_PARTITION_APPLE
BOOT_SUPPORT_PARTITION_EFI
BOOT_SUPPORT_PARTITION_INTEL
BOOT_SUPPORT_FILE_SYSTEM_BFS