mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 09:46:20 +00:00
part_blk: add GPT support
The GUID partition table (GPT) is primarily used by systems using (U)EFI and is a replacement for the legacy MBR. For now, the current implementation is able to address up to 128 GUID partition entries (GPE). To enable the GPT support in 'part_blk' it has to be configured accrodingly: ! <start name="part_blk"> ! [...] ! <config use_gpt="yes"> ! [...] ! </start> If 'part_blk' is not able to find a valid GPT header it falls back to using the MBR. Current limitations: Since no endian conversion takes place it only works on LE platforms and of all characters in the UTF-16 encoded name field of an entry only the ones included in the ASCII encoding are printed. It also ignores all GPE attributes. Issue #1429.
This commit is contained in:
parent
2694b5f9c6
commit
9b7e0ce0a5
@ -14,6 +14,10 @@ extended boot records (EBRs) are parsed and offered as separate block sessions
|
||||
to the front-end clients. The four primary partitions will receive partition
|
||||
numbers '1' to '4' whereas the first logical partition will be assigned to '5'.
|
||||
|
||||
The partition server also understands the GUID partition table (GPT). If the
|
||||
config attribute 'use_gpt' is set to 'yes' it will first try to parse any
|
||||
existing GPT. In case there is no GPT it will fall back to parsing the MBR.
|
||||
|
||||
In order to route a client to the right partition, the server parses its
|
||||
configuration section looking for 'policy' tags.
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <root/component.h>
|
||||
#include <block_session/rpc_object.h>
|
||||
|
||||
#include "partition_table.h"
|
||||
#include "gpt.h"
|
||||
|
||||
namespace Block {
|
||||
|
||||
@ -195,8 +195,9 @@ class Block::Root :
|
||||
{
|
||||
private:
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Signal_receiver &_receiver;
|
||||
Rpc_entrypoint &_ep;
|
||||
Signal_receiver &_receiver;
|
||||
Block::Partition_table &_table;
|
||||
|
||||
long _partition_num(const char *session_label)
|
||||
{
|
||||
@ -265,7 +266,7 @@ class Block::Root :
|
||||
throw Root::Invalid_args();
|
||||
}
|
||||
|
||||
if (!Partition_table::table().partition(num)) {
|
||||
if (!_table.partition(num)) {
|
||||
PERR("Partition %ld unavailable", num);
|
||||
throw Root::Unavailable();
|
||||
}
|
||||
@ -274,18 +275,19 @@ class Block::Root :
|
||||
ds_cap = Genode::env()->ram_session()->alloc(tx_buf_size);
|
||||
return new (md_alloc())
|
||||
Session_component(ds_cap,
|
||||
Partition_table::table().partition(num),
|
||||
_table.partition(num),
|
||||
_ep, _receiver);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
|
||||
Signal_receiver &receiver)
|
||||
Signal_receiver &receiver, Block::Partition_table& table)
|
||||
:
|
||||
Root_component(session_ep, md_alloc),
|
||||
_ep(*session_ep),
|
||||
_receiver(receiver)
|
||||
_receiver(receiver),
|
||||
_table(table)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
284
repos/os/src/server/part_blk/gpt.h
Normal file
284
repos/os/src/server/part_blk/gpt.h
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* \brief GUID Partition table definitions
|
||||
* \author Josef Soentgen
|
||||
* \date 2014-09-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _PART_BLK__GPT_H_
|
||||
#define _PART_BLK__GPT_H_
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/printf.h>
|
||||
#include <block_session/client.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "partition_table.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static bool const verbose = false;
|
||||
#define PLOGV(...) do { if (verbose) PLOG(__VA_ARGS__); } while (0)
|
||||
|
||||
/* simple bitwise CRC32 checking */
|
||||
static inline Genode::uint32_t crc32(void const * const buf, Genode::size_t size)
|
||||
{
|
||||
Genode::uint8_t const *p = static_cast<Genode::uint8_t const*>(buf);
|
||||
Genode::uint32_t crc = ~0U;
|
||||
|
||||
while (size--) {
|
||||
crc ^= *p++;
|
||||
for (Genode::uint32_t j = 0; j < 8; j++)
|
||||
crc = (-Genode::int32_t(crc & 1) & 0xedb88320) ^ (crc >> 1);
|
||||
}
|
||||
|
||||
return crc ^ ~0U;
|
||||
}
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
|
||||
class Gpt : public Block::Partition_table
|
||||
{
|
||||
private:
|
||||
|
||||
enum { MAX_PARTITIONS = 128 };
|
||||
|
||||
/* contains pointers to valid partitions or 0 */
|
||||
Block::Partition *_part_list[MAX_PARTITIONS] { 0 };
|
||||
|
||||
typedef Block::Partition_table::Sector Sector;
|
||||
|
||||
|
||||
/**
|
||||
* DCE uuid struct
|
||||
*/
|
||||
struct Uuid
|
||||
{
|
||||
enum { UUID_NODE_LEN = 6 };
|
||||
|
||||
Genode::uint32_t time_low;
|
||||
Genode::uint16_t time_mid;
|
||||
Genode::uint16_t time_hi_and_version;
|
||||
Genode::uint8_t clock_seq_hi_and_reserved;
|
||||
Genode::uint8_t clock_seq_low;
|
||||
Genode::uint8_t node[UUID_NODE_LEN];
|
||||
|
||||
char const *to_string()
|
||||
{
|
||||
static char buffer[37 + 1];
|
||||
|
||||
Genode::snprintf(buffer, sizeof(buffer),
|
||||
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
time_low, time_mid, time_hi_and_version,
|
||||
clock_seq_hi_and_reserved, clock_seq_low,
|
||||
node[0], node[1], node[2], node[3], node[4], node[5]);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* GUID parition table header
|
||||
*/
|
||||
struct Gpt_hdr
|
||||
{
|
||||
enum { HEADER_LBA = 1 };
|
||||
|
||||
char _sig[8]; /* identifies GUID Partition Table */
|
||||
Genode::uint32_t _revision; /* GPT specification revision */
|
||||
Genode::uint32_t _hdr_size; /* size of GPT header */
|
||||
Genode::uint32_t _hdr_crc; /* CRC32 of GPT header */
|
||||
Genode::uint32_t _reserved; /* must be zero */
|
||||
Genode::uint64_t _hdr_lba; /* LBA that contains this header */
|
||||
Genode::uint64_t _backup_hdr_lba; /* LBA of backup GPT header */
|
||||
Genode::uint64_t _part_lba_start; /* first LBA usable for partitions */
|
||||
Genode::uint64_t _part_lba_end; /* last LBA usable for partitions */
|
||||
Uuid _guid; /* GUID to identify the disk */
|
||||
Genode::uint64_t _gpe_lba; /* first LBA of GPE array */
|
||||
Genode::uint32_t _entries; /* number of entries in GPE array */
|
||||
Genode::uint32_t _entry_size; /* size of each GPE */
|
||||
Genode::uint32_t _gpe_crc; /* CRC32 of GPE array */
|
||||
|
||||
void dump_hdr(bool check_primary)
|
||||
{
|
||||
PLOGV("GPT %s header:", check_primary ? "primary" : "backup");
|
||||
PLOGV(" rev: %u", _revision);
|
||||
PLOGV(" size: %u", _hdr_size);
|
||||
PLOGV(" crc: %x", _hdr_crc);
|
||||
PLOGV(" reserved: %u", _reserved);
|
||||
PLOGV(" hdr lba: %llu", _hdr_lba);
|
||||
PLOGV(" bak lba: %llu", _backup_hdr_lba);
|
||||
PLOGV(" part start lba: %llu", _part_lba_start);
|
||||
PLOGV(" part end lba: %llu", _part_lba_end);
|
||||
PLOGV(" guid: %s", _guid.to_string());
|
||||
PLOGV(" gpe lba: %llu", _gpe_lba);
|
||||
PLOGV(" entries: %u", _entries);
|
||||
PLOGV(" entry size: %u", _entry_size);
|
||||
PLOGV(" gpe crc: %x", _gpe_crc);
|
||||
}
|
||||
|
||||
bool is_valid(bool check_primary = true)
|
||||
{
|
||||
dump_hdr(check_primary);
|
||||
|
||||
/* check sig */
|
||||
if (Genode::strcmp(_sig, "EFI PART", 8) != 0)
|
||||
return false;
|
||||
|
||||
/* check header crc */
|
||||
Genode::uint32_t crc = _hdr_crc;
|
||||
_hdr_crc = 0;
|
||||
if (crc32(this, _hdr_size) != crc) {
|
||||
PERR("Wrong GPT header checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* check header lba */
|
||||
if (check_primary)
|
||||
if (_hdr_lba != HEADER_LBA)
|
||||
return false;
|
||||
|
||||
/* check GPT entry array */
|
||||
Genode::size_t length = _entries * _entry_size;
|
||||
Sector gpe(_gpe_lba, length / Block::Driver::driver().blk_size());
|
||||
if (crc32(gpe.addr<void *>(), length) != _gpe_crc)
|
||||
return false;
|
||||
|
||||
if (check_primary) {
|
||||
/* check backup gpt header */
|
||||
Sector backup_hdr(_backup_hdr_lba, 1);
|
||||
if (!backup_hdr.addr<Gpt_hdr*>()->is_valid(false)) {
|
||||
PWRN("Backup GPT header is corrupted");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* the remainder of the LBA must be zero */
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* GUID partition entry format
|
||||
*/
|
||||
struct Gpt_entry
|
||||
{
|
||||
enum { NAME_LEN = 36 };
|
||||
Uuid _type; /* partition type GUID */
|
||||
Uuid _guid; /* unique partition GUID */
|
||||
Genode::uint64_t _lba_start; /* start of partition */
|
||||
Genode::uint64_t _lba_end; /* end of partition */
|
||||
Genode::uint64_t _attr; /* partition attributes */
|
||||
Genode::uint16_t _name[NAME_LEN]; /* partition name in UNICODE-16 */
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
if (_type.time_low == 0x00000000)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all valid ASCII characters in the name entry
|
||||
*/
|
||||
char const *name()
|
||||
{
|
||||
static char buffer[NAME_LEN + 1];
|
||||
|
||||
char *p = buffer;
|
||||
Genode::size_t i = 0;
|
||||
|
||||
for (Genode::size_t u = 0; u < NAME_LEN && _name[u] != 0; u++) {
|
||||
Genode::uint32_t utfchar = _name[i++];
|
||||
|
||||
if ((utfchar & 0xf800) == 0xd800) {
|
||||
unsigned int c = _name[i];
|
||||
if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
|
||||
utfchar = 0xfffd;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
|
||||
*p++ = (utfchar < 0x80) ? utfchar : '.';
|
||||
}
|
||||
|
||||
*p++ = 0;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* Parse the GPT header
|
||||
*/
|
||||
void _parse_gpt(Gpt_hdr *gpt)
|
||||
{
|
||||
if (!(gpt->is_valid()))
|
||||
throw Genode::Exception();
|
||||
|
||||
Sector entry_array(gpt->_gpe_lba,
|
||||
gpt->_entries * gpt->_entry_size / Block::Driver::driver().blk_size());
|
||||
Gpt_entry *entries = entry_array.addr<Gpt_entry *>();
|
||||
|
||||
for (int i = 0; i < MAX_PARTITIONS; i++) {
|
||||
Gpt_entry *e = (entries + i);
|
||||
|
||||
if (!e->is_valid())
|
||||
continue;
|
||||
|
||||
Genode::uint64_t start = e->_lba_start;
|
||||
Genode::uint64_t length = e->_lba_end - e->_lba_start + 1; /* [...) */
|
||||
|
||||
_part_list[i] = new (Genode::env()->heap()) Block::Partition(start, length);
|
||||
|
||||
PINF("Partition %d: LBA %llu (%llu blocks) type: '%s' name: '%s'",
|
||||
i + 1, start, length, e->_type.to_string(), e->name());
|
||||
}
|
||||
}
|
||||
|
||||
Gpt()
|
||||
{
|
||||
Sector s(Gpt_hdr::HEADER_LBA, 1);
|
||||
_parse_gpt(s.addr<Gpt_hdr *>());
|
||||
|
||||
/*
|
||||
* we read all partition information,
|
||||
* now it's safe to turn in asynchronous mode
|
||||
*/
|
||||
Block::Driver::driver().work_asynchronously();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Block::Partition *partition(int num) {
|
||||
return (num <= MAX_PARTITIONS && num > 0) ? _part_list[num-1] : 0; }
|
||||
|
||||
bool avail()
|
||||
{
|
||||
for (unsigned num = 0; num < MAX_PARTITIONS; num++)
|
||||
if (_part_list[num])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static Gpt& table()
|
||||
{
|
||||
static Gpt table;
|
||||
return table;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _PART_BLK__GUID_PARTITION_TABLE_H_ */
|
@ -2,11 +2,12 @@
|
||||
* \brief Front end of the partition server
|
||||
* \author Sebastian Sumpf
|
||||
* \author Stefan Kalkowski
|
||||
* \author Josef Soentgen
|
||||
* \date 2011-05-30
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
* Copyright (C) 2011-2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
@ -16,9 +17,10 @@
|
||||
#include <cap_session/connection.h>
|
||||
#include <os/config.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "partition_table.h"
|
||||
#include "component.h"
|
||||
#include "driver.h"
|
||||
#include "gpt.h"
|
||||
#include "mbr.h"
|
||||
|
||||
static Genode::Signal_receiver receiver;
|
||||
|
||||
@ -33,19 +35,48 @@ void Block::Driver::_ready_to_submit(unsigned) {
|
||||
Block::Session_component::wake_up(); }
|
||||
|
||||
|
||||
static bool _use_gpt()
|
||||
{
|
||||
try {
|
||||
return Genode::config()->xml_node().attribute("use_gpt").has_value("yes");
|
||||
} catch(...) { }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!Block::Partition_table::table().avail()) {
|
||||
PERR("No valid partition table found");
|
||||
return 1;
|
||||
bool valid_mbr = false;
|
||||
bool valid_gpt = false;
|
||||
bool use_gpt = _use_gpt();
|
||||
|
||||
if (use_gpt)
|
||||
try { valid_gpt = Gpt::table().avail(); } catch (...) { }
|
||||
|
||||
/* fall back to MBR */
|
||||
if (!valid_gpt) {
|
||||
try { valid_mbr = Mbr_partition_table::table().avail(); }
|
||||
catch (Mbr_partition_table::Protective_mbr_found) {
|
||||
if (!use_gpt)
|
||||
PERR("Aborting: found protective MBR but GPT usage was not requested.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Block::Partition_table *partition_table = 0;
|
||||
if (valid_gpt)
|
||||
partition_table = &Gpt::table();
|
||||
if (valid_mbr)
|
||||
partition_table = &Mbr_partition_table::table();
|
||||
|
||||
enum { STACK_SIZE = 1024 * sizeof(Genode::size_t) };
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "part_ep");
|
||||
static Block::Root block_root(&ep, env()->heap(), receiver);
|
||||
static Block::Root block_root(&ep, env()->heap(), receiver,
|
||||
*partition_table);
|
||||
|
||||
env()->parent()->announce(ep.manage(&block_root));
|
||||
|
||||
|
174
repos/os/src/server/part_blk/mbr.h
Normal file
174
repos/os/src/server/part_blk/mbr.h
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* \brief MBR partition table definitions
|
||||
* \author Sebastian Sumpf
|
||||
* \author Stefan Kalkowski
|
||||
* \author Josef Soentgen
|
||||
* \date 2013-12-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _PART_BLK__MBR_H_
|
||||
#define _PART_BLK__MBR_H_
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/printf.h>
|
||||
#include <block_session/client.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "partition_table.h"
|
||||
|
||||
|
||||
struct Mbr_partition_table : public Block::Partition_table
|
||||
{
|
||||
public:
|
||||
|
||||
class Protective_mbr_found { };
|
||||
|
||||
private:
|
||||
|
||||
typedef Block::Partition_table::Sector Sector;
|
||||
|
||||
/**
|
||||
* Partition table entry format
|
||||
*/
|
||||
struct Partition_record
|
||||
{
|
||||
enum { INVALID = 0, EXTENTED = 0x5, PROTECTIVE = 0xee, };
|
||||
Genode::uint8_t _unused[4];
|
||||
Genode::uint8_t _type; /* partition type */
|
||||
Genode::uint8_t _unused2[3];
|
||||
Genode::uint32_t _lba; /* logical block address */
|
||||
Genode::uint32_t _sectors; /* number of sectors */
|
||||
|
||||
bool is_valid() { return _type != INVALID; }
|
||||
bool is_extented() { return _type == EXTENTED; }
|
||||
bool is_protective() { return _type == PROTECTIVE; }
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* Master/Extented boot record format
|
||||
*/
|
||||
struct Mbr
|
||||
{
|
||||
Genode::uint8_t _unused[446];
|
||||
Partition_record _records[4];
|
||||
Genode::uint16_t _magic;
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
/* magic number of partition table */
|
||||
enum { MAGIC = 0xaa55 };
|
||||
return _magic == MAGIC;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
enum { MAX_PARTITIONS = 32 };
|
||||
|
||||
Block::Partition *_part_list[MAX_PARTITIONS]; /* contains pointers to valid
|
||||
partitions or 0 */
|
||||
|
||||
void _parse_extented(Partition_record *record)
|
||||
{
|
||||
Partition_record *r = record;
|
||||
unsigned lba = r->_lba;
|
||||
|
||||
/* first logical partition number */
|
||||
int nr = 5;
|
||||
do {
|
||||
Sector s(lba, 1);
|
||||
Mbr *ebr = s.addr<Mbr *>();
|
||||
|
||||
if (!(ebr->is_valid()))
|
||||
return;
|
||||
|
||||
/* The first record is the actual logical partition. The lba of this
|
||||
* partition is relative to the lba of the current EBR */
|
||||
Partition_record *logical = &(ebr->_records[0]);
|
||||
if (logical->is_valid() && nr < MAX_PARTITIONS) {
|
||||
_part_list[nr++] = new (Genode::env()->heap())
|
||||
Block::Partition(logical->_lba + lba, logical->_sectors);
|
||||
|
||||
PINF("Partition %d: LBA %u (%u blocks) type %x", nr - 1,
|
||||
logical->_lba + lba, logical->_sectors, logical->_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* the second record points to the next EBR
|
||||
* (relative form this EBR)
|
||||
*/
|
||||
r = &(ebr->_records[1]);
|
||||
lba += ebr->_records[1]._lba;
|
||||
|
||||
} while (r->is_valid());
|
||||
}
|
||||
|
||||
void _parse_mbr(Mbr *mbr)
|
||||
{
|
||||
/* no partition table, use whole disc as partition 0 */
|
||||
if (!(mbr->is_valid()))
|
||||
_part_list[0] = new(Genode::env()->heap())
|
||||
Block::Partition(0, Block::Driver::driver().blk_cnt() - 1);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Partition_record *r = &(mbr->_records[i]);
|
||||
|
||||
if (!r->is_valid())
|
||||
continue;
|
||||
|
||||
PINF("Partition %d: LBA %u (%u blocks) type: %x",
|
||||
i + 1, r->_lba, r->_sectors, r->_type);
|
||||
|
||||
if (r->is_protective())
|
||||
throw Protective_mbr_found();
|
||||
|
||||
if (r->is_extented()) {
|
||||
_parse_extented(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
_part_list[i + 1] = new(Genode::env()->heap())
|
||||
Block::Partition(r->_lba, r->_sectors);
|
||||
}
|
||||
}
|
||||
|
||||
Mbr_partition_table()
|
||||
{
|
||||
Sector s(0, 1);
|
||||
_parse_mbr(s.addr<Mbr *>());
|
||||
|
||||
/*
|
||||
* we read all partition information,
|
||||
* now it's safe to turn in asynchronous mode
|
||||
*/
|
||||
Block::Driver::driver().work_asynchronously();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Block::Partition *partition(int num) {
|
||||
return (num < MAX_PARTITIONS) ? _part_list[num] : 0; }
|
||||
|
||||
bool avail()
|
||||
{
|
||||
for (unsigned num = 0; num < MAX_PARTITIONS; num++)
|
||||
if (_part_list[num])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static Mbr_partition_table& table()
|
||||
{
|
||||
static Mbr_partition_table table;
|
||||
return table;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _PART_BLK__MBR_H_ */
|
@ -29,18 +29,16 @@ namespace Block {
|
||||
|
||||
struct Block::Partition
|
||||
{
|
||||
Genode::uint32_t lba; /* logical block address on device */
|
||||
Genode::uint32_t sectors; /* number of sectors in patitions */
|
||||
Genode::uint64_t lba; /* logical block address on device */
|
||||
Genode::uint64_t sectors; /* number of sectors in patitions */
|
||||
|
||||
Partition(Genode::uint32_t l, Genode::uint32_t s)
|
||||
Partition(Genode::uint64_t l, Genode::uint64_t s)
|
||||
: lba(l), sectors(s) { }
|
||||
};
|
||||
|
||||
|
||||
class Block::Partition_table
|
||||
struct Block::Partition_table
|
||||
{
|
||||
private:
|
||||
|
||||
class Sector
|
||||
{
|
||||
private:
|
||||
@ -70,137 +68,9 @@ class Block::Partition_table
|
||||
return reinterpret_cast<T>(_session.tx()->packet_content(_p)); }
|
||||
};
|
||||
|
||||
virtual Partition *partition(int num) = 0;
|
||||
|
||||
/**
|
||||
* Partition table entry format
|
||||
*/
|
||||
struct Partition_record
|
||||
{
|
||||
enum { INVALID = 0, EXTENTED = 0x5 };
|
||||
Genode::uint8_t _unused[4];
|
||||
Genode::uint8_t _type; /* partition type */
|
||||
Genode::uint8_t _unused2[3];
|
||||
Genode::uint32_t _lba; /* logical block address */
|
||||
Genode::uint32_t _sectors; /* number of sectors */
|
||||
|
||||
bool is_valid() { return _type != INVALID; }
|
||||
bool is_extented() { return _type == EXTENTED; }
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* Master/Extented boot record format
|
||||
*/
|
||||
struct Mbr
|
||||
{
|
||||
Genode::uint8_t _unused[446];
|
||||
Partition_record _records[4];
|
||||
Genode::uint16_t _magic;
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
/* magic number of partition table */
|
||||
enum { MAGIC = 0xaa55 };
|
||||
return _magic == MAGIC;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
enum { MAX_PARTITIONS = 32 };
|
||||
|
||||
Partition *_part_list[MAX_PARTITIONS]; /* contains pointers to valid
|
||||
partitions or 0 */
|
||||
|
||||
void _parse_extented(Partition_record *record)
|
||||
{
|
||||
Partition_record *r = record;
|
||||
unsigned lba = r->_lba;
|
||||
|
||||
/* first logical partition number */
|
||||
int nr = 5;
|
||||
do {
|
||||
Sector s(lba, 1);
|
||||
Mbr *ebr = s.addr<Mbr *>();
|
||||
|
||||
if (!(ebr->is_valid()))
|
||||
return;
|
||||
|
||||
/* The first record is the actual logical partition. The lba of this
|
||||
* partition is relative to the lba of the current EBR */
|
||||
Partition_record *logical = &(ebr->_records[0]);
|
||||
if (logical->is_valid() && nr < MAX_PARTITIONS) {
|
||||
_part_list[nr++] = new (Genode::env()->heap())
|
||||
Partition(logical->_lba + lba, logical->_sectors);
|
||||
|
||||
PINF("Partition %d: LBA %u (%u blocks) type %x", nr - 1,
|
||||
logical->_lba + lba, logical->_sectors, logical->_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* the second record points to the next EBR
|
||||
* (relative form this EBR)
|
||||
*/
|
||||
r = &(ebr->_records[1]);
|
||||
lba += ebr->_records[1]._lba;
|
||||
|
||||
} while (r->is_valid());
|
||||
}
|
||||
|
||||
|
||||
void _parse_mbr(Mbr *mbr)
|
||||
{
|
||||
/* no partition table, use whole disc as partition 0 */
|
||||
if (!(mbr->is_valid()))
|
||||
_part_list[0] = new(Genode::env()->heap())
|
||||
Partition(0, Driver::driver().blk_cnt() - 1);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Partition_record *r = &(mbr->_records[i]);
|
||||
|
||||
if (r->is_valid())
|
||||
PINF("Partition %d: LBA %u (%u blocks) type: %x",
|
||||
i + 1, r->_lba, r->_sectors, r->_type);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (r->is_extented())
|
||||
_parse_extented(r);
|
||||
else
|
||||
_part_list[i + 1] = new(Genode::env()->heap())
|
||||
Partition(r->_lba, r->_sectors);
|
||||
}
|
||||
}
|
||||
|
||||
Partition_table()
|
||||
{
|
||||
Sector s(0, 1);
|
||||
_parse_mbr(s.addr<Mbr *>());
|
||||
|
||||
/*
|
||||
* we read all partition information,
|
||||
* now it's safe to turn in asynchronous mode
|
||||
*/
|
||||
Driver::driver().work_asynchronously();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Partition *partition(int num) {
|
||||
return (num < MAX_PARTITIONS) ? _part_list[num] : 0; }
|
||||
|
||||
bool avail()
|
||||
{
|
||||
for (unsigned num = 0; num < MAX_PARTITIONS; num++)
|
||||
if (_part_list[num])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static Partition_table& table()
|
||||
{
|
||||
static Partition_table table;
|
||||
return table;
|
||||
}
|
||||
virtual bool avail() = 0;
|
||||
};
|
||||
|
||||
#endif /* _PART_BLK__PARTITION_TABLE_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user