part_block: modernize implementation

Fixes #4790
This commit is contained in:
Christian Helmuth
2023-03-16 15:50:55 +01:00
parent 082d1780cf
commit 927d71ad59
24 changed files with 906 additions and 468 deletions

View File

@ -0,0 +1 @@
Test part_block server with Atari AHDI disk.

View File

@ -0,0 +1,7 @@
_/src/init
_/src/report_rom
_/src/part_block
_/src/vfs
_/src/vfs_block
_/src/block_tester
_/raw/test-part_block_ahdi

View File

@ -0,0 +1 @@
2023-03-17-d 6690319be80b9b24b647c36303dde6ece6048cb8

View File

@ -0,0 +1,81 @@
<runtime ram="72M" caps="1000" binary="init">
<requires> <timer/> </requires>
<events>
<timeout meaning="failed" sec="70" />
<log meaning="succeeded">
child "test-part*" exited with exit value 0
</log>
<log meaning="failed">Error: </log>
</events>
<content>
<rom label="ld.lib.so"/>
<rom label="vfs_block"/>
<rom label="vfs.lib.so"/>
<rom label="part_block"/>
<rom label="block_tester"/>
<rom label="report_rom"/>
<rom label="ata.ahdi.raw"/>
</content>
<config prio_levels="1" verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="vfs_block">
<resource name="RAM" quantum="32M"/>
<provides><service name="Block"/></provides>
<config>
<vfs>
<rom name="ata.ahdi.raw"/>
</vfs>
<default-policy file="/ata.ahdi.raw" block_size="512"/>
</config>
</start>
<start name="part_block">
<resource name="RAM" quantum="10M" />
<provides><service name="Block" /></provides>
<route>
<any-service><child name="vfs_block"/> <parent/><any-child/></any-service>
</route>
<config>
<report partitions="yes"/>
<policy label_prefix="test-part1" partition="1"/>
</config>
</start>
<start name="report_rom">
<provides>
<service name="Report"/>
<service name="ROM"/>
</provides>
<resource name="RAM" quantum="5M" />
<config verbose="yes"/>
</start>
<start name="test-part1">
<binary name="block_tester"/>
<resource name="RAM" quantum="5M" />
<config verbose="no" log="yes" stop_on_error="no">
<tests>
<sequential length="256K" size="1K" io_buffer="128K" batch="4"/>
</tests>
</config>
<route>
<any-service> <child name="part_block" /> <parent/> <any-child/> </any-service>
</route>
</start>
</config>
</runtime>

View File

@ -0,0 +1 @@
Test part_block server with GPT disk.

View File

@ -0,0 +1,7 @@
_/src/init
_/src/report_rom
_/src/part_block
_/src/vfs
_/src/vfs_block
_/src/block_tester
_/raw/test-part_block_gpt

View File

@ -0,0 +1 @@
2023-03-17 0d6f7581b18066825dd6e9db06faf2c6edb31331

View File

@ -0,0 +1,81 @@
<runtime ram="72M" caps="1000" binary="init">
<requires> <timer/> </requires>
<events>
<timeout meaning="failed" sec="70" />
<log meaning="succeeded">
child "test-part*" exited with exit value 0
</log>
<log meaning="failed">Error: </log>
</events>
<content>
<rom label="ld.lib.so"/>
<rom label="vfs_block"/>
<rom label="vfs.lib.so"/>
<rom label="part_block"/>
<rom label="block_tester"/>
<rom label="report_rom"/>
<rom label="ata.gpt.raw"/>
</content>
<config prio_levels="1" verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="vfs_block">
<resource name="RAM" quantum="32M"/>
<provides><service name="Block"/></provides>
<config>
<vfs>
<rom name="ata.gpt.raw"/>
</vfs>
<default-policy file="/ata.gpt.raw" block_size="512"/>
</config>
</start>
<start name="part_block">
<resource name="RAM" quantum="10M" />
<provides><service name="Block" /></provides>
<route>
<any-service><child name="vfs_block"/> <parent/><any-child/></any-service>
</route>
<config ignore_gpt="true">
<report partitions="yes"/>
<policy label_prefix="test-part0" partition="0"/>
</config>
</start>
<start name="report_rom">
<provides>
<service name="Report"/>
<service name="ROM"/>
</provides>
<resource name="RAM" quantum="5M" />
<config verbose="yes"/>
</start>
<start name="test-part0">
<binary name="block_tester"/>
<resource name="RAM" quantum="5M" />
<config verbose="no" log="yes" stop_on_error="no">
<tests>
<sequential length="1M" size="1K" io_buffer="128K" batch="4"/>
</tests>
</config>
<route>
<any-service> <child name="part_block" /> <parent/> <any-child/> </any-service>
</route>
</start>
</config>
</runtime>

View File

@ -53,7 +53,7 @@
<route> <route>
<any-service><child name="vfs_block"/> <parent/><any-child/></any-service> <any-service><child name="vfs_block"/> <parent/><any-child/></any-service>
</route> </route>
<config use_gpt="yes"> <config>
<report partitions="yes"/> <report partitions="yes"/>
<policy label_prefix="test-part1" partition="2"/> <policy label_prefix="test-part1" partition="2"/>
<policy label_prefix="test-part2" partition="1"/> <policy label_prefix="test-part2" partition="1"/>

View File

@ -3,7 +3,7 @@
<requires> <timer/> </requires> <requires> <timer/> </requires>
<events> <events>
<timeout meaning="failed" sec="60" /> <timeout meaning="failed" sec="70" />
<log meaning="succeeded"> <log meaning="succeeded">
child "test-part*" exited with exit value 0* child "test-part*" exited with exit value 0*
child "test-part*" exited with exit value 0* child "test-part*" exited with exit value 0*

View File

@ -0,0 +1,4 @@
content: ata.ahdi.raw
ata.ahdi.raw:
tar -xzvf $(REP_DIR)/recipes/raw/test-part_block_ahdi/$@.tar.gz 1>/dev/null

View File

@ -0,0 +1 @@
2023-03-17 9c4b6f3d932b62b0c8d49ebd670aa2cada723988

View File

@ -50,6 +50,10 @@ looks like follows (for MBR resp. GPT).
Clients have read-only access to partitions unless overriden by a 'writeable' Clients have read-only access to partitions unless overriden by a 'writeable'
policy attribute. policy attribute.
part_block requests a block session to access the storage device with a
4 MiB I/O buffer per default. The buffer size can be tweaked with the
'io_buffer' config attribute.
Usage Usage
----- -----
@ -71,7 +75,7 @@ Configuration snippet with two clients and an (hypothetical) IDE driver:
! !
! <!-- allow program 'test-part1' to access logical partition '6', while program ! <!-- allow program 'test-part1' to access logical partition '6', while program
! 'test-part2' receives access to primary partition 1, the buffer between ! 'test-part2' receives access to primary partition 1, the buffer between
! the 'ata_driver' and 'part_block' is 1 MeB ('io_buffer') --> ! the 'ata_driver' and 'part_block' is 1 MiB ('io_buffer') -->
! <config io_buffer="1M"> ! <config io_buffer="1M">
! <report partitions="yes"/> ! <report partitions="yes"/>
! <policy label_prefix="test-part1" partition="6" writeable="yes"/> ! <policy label_prefix="test-part1" partition="6" writeable="yes"/>

View File

@ -1,6 +1,7 @@
/* /*
* \brief Atari ST partition scheme (AHDI) * \brief Atari ST partition scheme (AHDI)
* \author Norman Feske * \author Norman Feske
* \author Christian Helmuth
* \date 2019-08-09 * \date 2019-08-09
*/ */
@ -16,84 +17,184 @@
#include "partition_table.h" #include "partition_table.h"
namespace Block {
struct Ahdi_partition;
struct Ahdi;
}
struct Ahdi
struct Block::Ahdi_partition : Partition
{ {
typedef Block::Partition_table::Sector Sector; using Type = String<4>;
Type type;
typedef Genode::uint32_t uint32_t; Ahdi_partition(block_number_t lba,
typedef Genode::uint8_t uint8_t; block_number_t sectors,
Fs::Type fs_type,
Type const &type)
:
Partition(lba, sectors, fs_type),
type(type)
{ }
};
/**
* 32-bit big-endian value
*/
struct Be32
{
uint8_t b0, b1, b2, b3;
uint32_t value() const { class Block::Ahdi : public Partition_table
return ((uint32_t)b0 << 24) | ((uint32_t)b1 << 16) {
| ((uint32_t)b2 << 8) | ((uint32_t)b3 << 0); } private:
} __attribute__((packed)); /**
* 32-bit big-endian value
struct Partition_record */
{ struct Be32
uint8_t _flags;
uint8_t _id0, _id1, _id2;
Be32 start; /* first block */
Be32 length; /* in blocks */
typedef Genode::String<4> Id;
Id id() const
{ {
using Genode::Char; uint8_t b0, b1, b2, b3;
return Id(Char(_id0), Char(_id1), Char(_id2));
uint32_t value() const {
return ((uint32_t)b0 << 24) | ((uint32_t)b1 << 16)
| ((uint32_t)b2 << 8) | ((uint32_t)b3 << 0); }
} __attribute__((packed));
struct Partition_record
{
uint8_t _flags;
uint8_t _id0, _id1, _id2;
Be32 start; /* first block */
Be32 length; /* in blocks */
Ahdi_partition::Type id() const
{
return { Char(_id0), Char(_id1), Char(_id2) };
}
bool bootable() const { return _flags & 1; }
bool valid() const
{
return start.value() > 0
&& (id() == "BGM" || id() == "GEM" || id() == "LNX");
}
} __attribute__((packed));
enum { MAX_PARTITIONS = 4 };
struct Root_sector
{
uint8_t boot_code[0x156];
Partition_record icd_partitions[8];
uint8_t unused[0xc];
Be32 disk_blocks;
Partition_record partitions[MAX_PARTITIONS];
} __attribute__((packed));
Constructible<Ahdi_partition> _part_list[MAX_PARTITIONS];
bool _valid(Sync_read const &sector)
{
bool any_partition_valid = false;
Root_sector const root = *sector.addr<Root_sector const *>();
for (unsigned i = 0; i < MAX_PARTITIONS; i++)
if (root.partitions[i].valid())
any_partition_valid = true;
return any_partition_valid;
} }
bool bootable() const { return _flags & 1; } template <typename FUNC>
void _parse_ahdi(Sync_read const &sector, FUNC const &fn)
{
Root_sector &root = *sector.addr<Root_sector *>();
bool valid() const { return id() == "BGM" && start.value() > 0; } for (unsigned i = 0; i < MAX_PARTITIONS; i++) {
Partition_record const &part = root.partitions[i];
if (!part.valid())
continue;
} __attribute__((packed)); fn(i, part);
}
enum { MAX_PARTITIONS = 4 }; }
struct Root_sector template <typename FN>
{ void _for_each_valid_partition(FN const &fn) const
uint8_t boot_code[0x156]; {
Partition_record icd_partitions[8]; for (unsigned i = 0; i < MAX_PARTITIONS; i++)
uint8_t unused[0xc]; if (_part_list[i].constructed())
Be32 disk_blocks; fn(i);
Partition_record partitions[MAX_PARTITIONS]; };
} __attribute__((packed)); public:
static bool valid(Sector const &sector) using Partition_table::Partition_table;
{
bool any_partition_valid = false; bool parse()
{
Root_sector const root = *sector.addr<Root_sector const *>(); Sync_read s(_handler, _alloc, 0, 1);
for (unsigned i = 0; i < MAX_PARTITIONS; i++)
if (root.partitions[i].valid()) if (!s.success() || !_valid(s))
any_partition_valid = true; return false;
return any_partition_valid; _parse_ahdi(s, [&] (unsigned i, Partition_record const &r) {
} block_number_t lba = r.start.value();
block_number_t length = r.length.value();
template <typename FN>
static void for_each_partition(Sector const &sector, FN const &fn) Ahdi_partition::Type type = r.id();
{
Root_sector &root = *sector.addr<Root_sector *>(); _part_list[i].construct(lba, length, _fs_type(lba), type);
for (unsigned i = 0; i < MAX_PARTITIONS; i++) { log("AHDI Partition ", i + 1, ": LBA ", lba, " (", length,
Partition_record const &part = root.partitions[i]; " blocks) type: '", type, "'");
if (part.valid()) });
fn(i + 1, Block::Partition(part.start.value(), part.length.value(),
Fs::Type(), 0)); return true;
}
bool partition_valid(long num) const override
{
/* 1-based partition number to 0-based array index */
num -= 1;
if (num < 0 || num >= MAX_PARTITIONS)
return false;
return _part_list[num].constructed();
}
block_number_t partition_lba(long num) const override
{
return partition_valid(num) ? _part_list[num - 1]->lba : 0;
}
block_number_t partition_sectors(long num) const override
{
return partition_valid(num) ? _part_list[num - 1]->sectors : 0;
}
void generate_report(Xml_generator &xml) const override
{
auto gen_partition_attr = [&] (Xml_generator &xml, unsigned i)
{
Ahdi_partition const &part = *_part_list[i];
xml.attribute("number", i + 1);
xml.attribute("start", part.lba);
xml.attribute("length", part.sectors);
xml.attribute("block_size", _info.block_size);
xml.attribute("type", part.type);
if (part.fs_type.valid())
xml.attribute("file_system", part.fs_type);
};
xml.attribute("type", "ahdi");
_for_each_valid_partition([&] (unsigned i) {
xml.node("partition", [&] {
gen_partition_attr(xml, i); }); });
} }
}
}; };
#endif /* _PART_BLOCK__AHDI_H_ */ #endif /* _PART_BLOCK__AHDI_H_ */

View File

@ -0,0 +1,134 @@
/*
* \brief Block I/O utilities
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \author Christian Helmuth
* \date 2023-03-16
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _PART_BLOCK__BLOCK_H_
#define _PART_BLOCK__BLOCK_H_
#include "types.h"
namespace Block {
struct Job;
struct Sync_read;
}
struct Block::Job : public Block_connection::Job
{
Registry<Job>::Element registry_element;
addr_t const index; /* job index */
long const number; /* parition number */
Request request;
addr_t const addr; /* target payload address */
Job(Block_connection &connection,
Operation operation,
Registry<Job> &registry,
addr_t const index,
addr_t const number,
Request request,
addr_t addr)
:
Block_connection::Job(connection, operation),
registry_element(registry, *this),
index(index), number(number), request(request), addr(addr)
{ }
};
/*
* Synchronous block I/O (for reading table info)
*/
class Block::Sync_read : Noncopyable
{
public:
struct Handler : Interface
{
virtual Block_connection & connection() = 0;
virtual void block_for_io() = 0;
};
private:
Handler &_handler;
Allocator &_alloc;
size_t _size { 0 };
void *_buffer { nullptr };
bool _success { false };
/*
* Noncopyable
*/
Sync_read(Sync_read const &) = delete;
Sync_read & operator = (Sync_read const &) = delete;
public:
Sync_read(Handler &handler,
Allocator &alloc,
block_number_t block_number,
block_count_t count)
: _handler(handler), _alloc(alloc)
{
Operation const operation {
.type = Operation::Type::READ,
.block_number = block_number,
.count = count
};
Block_connection::Job job { _handler.connection(), operation };
_handler.connection().update_jobs(*this);
while (!job.completed()) {
_handler.block_for_io();
_handler.connection().update_jobs(*this);
}
}
~Sync_read()
{
_alloc.free(_buffer, _size);
}
bool success() const { return _success; }
void consume_read_result(Block_connection::Job &, off_t offset,
char const *src, size_t length)
{
_buffer = _alloc.alloc(length);
memcpy((char *)_buffer + offset, src, length);
_size += length;
}
void produce_write_content(Block_connection::Job &, off_t,
char *, size_t)
{
}
void completed(Block_connection::Job &, bool success)
{
if (!success)
error("IO error during partition parsing");
_success = success;
}
template <typename T> T addr() const {
return reinterpret_cast<T>(_buffer); }
};
#endif /* _PART_BLOCK__BLOCK_H_ */

View File

@ -0,0 +1,70 @@
/*
* \brief Entire disk a partition 0
* \author Christian Helmuth
* \date 2023-03-17
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _PART_BLOCK__DISK_H_
#define _PART_BLOCK__DISK_H_
#include "partition_table.h"
namespace Block { struct Disk; }
class Block::Disk : public Partition_table
{
private:
Partition _part { 0, _info.block_count, _fs_type(0) };
public:
Disk(Sync_read::Handler &handler,
Allocator &alloc,
Session::Info info)
:
Partition_table(handler, alloc, info)
{
log("DISK Partition 0: LBA ", _part.lba, " (", _part.sectors, " blocks)");
}
bool partition_valid(long num) const override
{
return num == 0;
}
block_number_t partition_lba(long num) const override
{
return partition_valid(num) ? _part.lba : 0;
}
block_number_t partition_sectors(long num) const override
{
return partition_valid(num) ? _part.sectors : 0;
}
void generate_report(Xml_generator &xml) const override
{
xml.attribute("type", "disk");
xml.node("partition", [&] {
xml.attribute("number", 0);
xml.attribute("start", _part.lba);
xml.attribute("length", _part.sectors);
xml.attribute("block_size", _info.block_size);
if (_part.fs_type.valid())
xml.attribute("file_system", _part.fs_type);
});
}
};
#endif /* _PART_BLOCK__DISK_H_ */

View File

@ -1,6 +1,7 @@
/* /*
* \brief Poor man's partition probe for known file system * \brief Poor man's partition probe for known file system
* \author Josef Soentgen * \author Josef Soentgen
* \author Christian Helmuth
* \date 2018-05-03 * \date 2018-05-03
*/ */
@ -24,64 +25,68 @@ namespace Fs {
using Type = Genode::String<32>; using Type = Genode::String<32>;
Type _probe_extfs(uint8_t *p, size_t len);
Type _probe_fatfs(uint8_t *p, size_t len);
Type probe(uint8_t *buffer, size_t len); Type probe(uint8_t *buffer, size_t len);
}
/**
* Probe for Ext2/3/4
*/
Type _probe_extfs(uint8_t *p, size_t len)
{
if (len < 4096) { return Type(); }
/* super block starts a byte offset 1024 */ /**
p += 0x400; * Probe for Ext2/3/4
*/
Fs::Type Fs::_probe_extfs(uint8_t *p, size_t len)
{
if (len < 4096) { return Type(); }
bool const found_ext_sig = p[0x38] == 0x53 && p[0x39] == 0xEF; /* super block starts a byte offset 1024 */
p += 0x400;
enum { bool const found_ext_sig = p[0x38] == 0x53 && p[0x39] == 0xEF;
COMPAT_HAS_JOURNAL = 0x004u,
INCOMPAT_EXTENTS = 0x040u,
RO_COMPAT_METADATA_CSUM = 0x400u,
};
uint32_t const compat = *(uint32_t*)(p + 0x5C); enum {
uint32_t const incompat = *(uint32_t*)(p + 0x60); COMPAT_HAS_JOURNAL = 0x004u,
uint32_t const ro_compat = *(uint32_t*)(p + 0x64); INCOMPAT_EXTENTS = 0x040u,
RO_COMPAT_METADATA_CSUM = 0x400u,
};
/* the feature flags should denote a given Ext version */ uint32_t const compat = *(uint32_t*)(p + 0x5C);
uint32_t const incompat = *(uint32_t*)(p + 0x60);
uint32_t const ro_compat = *(uint32_t*)(p + 0x64);
bool const ext3 = compat & COMPAT_HAS_JOURNAL; /* the feature flags should denote a given Ext version */
bool const ext4 = ext3 && ((incompat & INCOMPAT_EXTENTS)
&& (ro_compat & RO_COMPAT_METADATA_CSUM));
if (found_ext_sig && ext4) { return Type("Ext4"); } bool const ext3 = compat & COMPAT_HAS_JOURNAL;
else if (found_ext_sig && ext3) { return Type("Ext3"); } bool const ext4 = ext3 && ((incompat & INCOMPAT_EXTENTS)
else if (found_ext_sig) { return Type("Ext2"); } && (ro_compat & RO_COMPAT_METADATA_CSUM));
return Type(); if (found_ext_sig && ext4) { return Type("Ext4"); }
} else if (found_ext_sig && ext3) { return Type("Ext3"); }
else if (found_ext_sig) { return Type("Ext2"); }
/** return Type();
* Probe for FAT16/32 }
*/
Type _probe_fatfs(uint8_t *p, size_t len)
{
if (len < 512) { return Type(); }
/* at least the checks ring true when mkfs.vfat is used... */
bool const found_boot_sig = p[510] == 0x55 && p[511] == 0xAA;
bool const fat16 = p[38] == 0x28 || p[38] == 0x29; /**
bool const fat32 = (p[66] == 0x28 || p[66] == 0x29) * Probe for FAT16/32
&& (p[82] == 'F' && p[83] == 'A'); */
bool const gemdos = (p[0] == 0xe9); Fs::Type Fs::_probe_fatfs(uint8_t *p, size_t len)
{
if (len < 512) { return Type(); }
if (found_boot_sig && fat32) { return Type("FAT32"); } /* at least the checks ring true when mkfs.vfat is used... */
if (found_boot_sig && fat16) { return Type("FAT16"); } bool const found_boot_sig = p[510] == 0x55 && p[511] == 0xAA;
if (gemdos) { return Type("GEMDOS"); }
return Type(); bool const fat16 = p[38] == 0x28 || p[38] == 0x29;
} bool const fat32 = (p[66] == 0x28 || p[66] == 0x29)
&& (p[82] == 'F' && p[83] == 'A');
bool const gemdos = (p[0] == 0xe9);
if (found_boot_sig && fat32) { return Type("FAT32"); }
if (found_boot_sig && fat16) { return Type("FAT16"); }
if (gemdos) { return Type("GEMDOS"); }
return Type();
} }

View File

@ -2,6 +2,7 @@
* \brief GUID Partition table definitions * \brief GUID Partition table definitions
* \author Josef Soentgen * \author Josef Soentgen
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \author Christian Helmuth
* \date 2014-09-19 * \date 2014-09-19
*/ */
@ -15,21 +16,38 @@
#ifndef _PART_BLOCK__GPT_H_ #ifndef _PART_BLOCK__GPT_H_
#define _PART_BLOCK__GPT_H_ #define _PART_BLOCK__GPT_H_
#include <base/env.h>
#include <base/log.h>
#include <block_session/client.h>
#include <util/misc_math.h>
#include <util/mmio.h>
#include <util/utf8.h>
#include "partition_table.h" #include "partition_table.h"
static bool constexpr verbose = false; static bool constexpr verbose = false;
namespace Block { namespace Block {
class Gpt_partition;
class Gpt; class Gpt;
}; };
struct Block::Gpt_partition : Partition
{
using Uuid = String<40>;
Uuid guid;
Uuid type;
using Name = String<72>; /* use GPT name entry length */
Name name;
Gpt_partition(block_number_t lba,
block_number_t sectors,
Fs::Type fs_type,
Uuid const &guid,
Uuid const &type,
Name const &name)
:
Partition(lba, sectors, fs_type),
guid(guid), type(type), name(name)
{ }
};
class Block::Gpt : public Block::Partition_table class Block::Gpt : public Block::Partition_table
{ {
private: private:
@ -37,9 +55,7 @@ class Block::Gpt : public Block::Partition_table
enum { MAX_PARTITIONS = 128 }; enum { MAX_PARTITIONS = 128 };
/* contains valid partitions or not constructed */ /* contains valid partitions or not constructed */
Constructible<Partition> _part_list[MAX_PARTITIONS]; Constructible<Gpt_partition> _part_list[MAX_PARTITIONS];
typedef Block::Partition_table::Sector Sector;
/** /**
* DCE uuid struct * DCE uuid struct
@ -83,7 +99,6 @@ class Block::Gpt : public Block::Partition_table
* GUID parition table header * GUID parition table header
*/ */
struct Gpt_hdr : Mmio struct Gpt_hdr : Mmio
{ {
struct Sig : Register<0, 64> { }; /* identifies GUID Partition Table */ struct Sig : Register<0, 64> { }; /* identifies GUID Partition Table */
struct Revision : Register<8, 32> { }; /* GPT specification revision */ struct Revision : Register<8, 32> { }; /* GPT specification revision */
@ -147,7 +162,8 @@ class Block::Gpt : public Block::Partition_table
log(" gpe crc: ", Hex(read<Gpe_crc>(), Hex::OMIT_PREFIX)); log(" gpe crc: ", Hex(read<Gpe_crc>(), Hex::OMIT_PREFIX));
} }
bool valid(Partition_table::Sector_data &data, bool check_primary = true) bool valid(Sync_read::Handler &handler, Allocator &alloc,
size_t block_size, bool check_primary = true)
{ {
dump_hdr(check_primary); dump_hdr(check_primary);
@ -172,17 +188,20 @@ class Block::Gpt : public Block::Partition_table
/* check GPT entry array */ /* check GPT entry array */
size_t length = entries() * entry_size(); size_t length = entries() * entry_size();
Sector gpe(data, gpe_lba(), length / data.block.info().block_size); Sync_read gpe(handler, alloc, gpe_lba(), length / block_size);
if (crc32(gpe.addr<addr_t>(), length) != read<Gpe_crc>()) if (!gpe.success()
|| crc32(gpe.addr<addr_t>(), length) != read<Gpe_crc>())
return false; return false;
if (check_primary) { if (check_primary) {
/* check backup gpt header */ /* check backup gpt header */
Sector backup_hdr(data, read<Backup_hdr_lba>(), 1); Sync_read backup_hdr(handler, alloc, read<Backup_hdr_lba>(), 1);
if (!backup_hdr.success())
return false;
Gpt_hdr backup(backup_hdr.addr<addr_t>()); Gpt_hdr backup(backup_hdr.addr<addr_t>());
if (!backup.valid(data, false)) { if (!backup.valid(handler, alloc, block_size, false))
warning("Backup GPT header is corrupted"); warning("Backup GPT header is corrupted");
}
} }
return true; return true;
@ -336,13 +355,15 @@ class Block::Gpt : public Block::Partition_table
/** /**
* Parse the GPT header * Parse the GPT header
*/ */
void _parse_gpt(Gpt_hdr &gpt) bool _parse_gpt(Gpt_hdr &gpt)
{ {
if (!(gpt.valid(data))) if (!gpt.valid(_handler, _alloc, _info.block_size))
throw Exception(); return false;
Sector entry_array(data, gpt.gpe_lba(), Sync_read entry_array(_handler, _alloc, gpt.gpe_lba(),
gpt.entries() * gpt.entry_size() / block.info().block_size); gpt.entries() * gpt.entry_size() / _info.block_size);
if (!entry_array.success())
return false;
Gpt_entry entries(entry_array.addr<addr_t>()); Gpt_entry entries(entry_array.addr<addr_t>());
_gpt_part_lba_end = gpt.part_lba_end(); _gpt_part_lba_end = gpt.part_lba_end();
@ -356,51 +377,37 @@ class Block::Gpt : public Block::Partition_table
if (!e.valid()) if (!e.valid())
continue; continue;
block_number_t const lba_start = e.lba_start(); block_number_t const lba = e.lba_start();
block_count_t const length = (block_count_t)(e.lba_end() - lba_start + 1); /* [...) */ block_number_t const length = e.lba_end() - lba + 1;
enum { BYTES = 4096, };
Sector fs(data, lba_start, BYTES / block.info().block_size);
Fs::Type fs_type = Fs::probe(fs.addr<uint8_t*>(), BYTES);
String<40> guid { e.guid() }; String<40> guid { e.guid() };
String<40> type { e.type() }; String<40> type { e.type() };
String<Gpt_entry::NAME_LEN> name { e }; String<Gpt_entry::NAME_LEN> name { e };
_part_list[i].construct(lba_start, length, fs_type, _part_list[i].construct(lba, length, _fs_type(lba), guid, type, name);
guid, type, name);
log("GPT Partition ", i + 1, ": LBA ", lba_start, " (", length, log("GPT Partition ", i + 1, ": LBA ", lba, " (", length,
" blocks) type: '", type, " blocks) type: '", type,
"' name: '", name, "'"); "' name: '", name, "'");
} }
return true;
} }
public: public:
using Partition_table::Partition_table; using Partition_table::Partition_table;
Partition &partition(long num) override bool parse()
{ {
num -= 1; Sync_read s(_handler, _alloc, Gpt_hdr::Hdr_lba::LBA, 1);
if (!s.success())
return false;
if (num < 0 || num > MAX_PARTITIONS)
throw -1;
if (!_part_list[num].constructed())
throw -1;
return *_part_list[num];
}
bool parse() override
{
block.sigh(io_sigh);
Sector s(data, Gpt_hdr::Hdr_lba::LBA, 1);
Gpt_hdr gpt_hdr(s.addr<addr_t>()); Gpt_hdr gpt_hdr(s.addr<addr_t>());
_parse_gpt(gpt_hdr); if (!_parse_gpt(gpt_hdr))
return false;
for (unsigned num = 0; num < MAX_PARTITIONS; num++) for (unsigned num = 0; num < MAX_PARTITIONS; num++)
if (_part_list[num].constructed()) if (_part_list[num].constructed())
@ -408,30 +415,49 @@ class Block::Gpt : public Block::Partition_table
return false; return false;
} }
bool partition_valid(long num) const override
{
/* 1-based partition number to 0-based array index */
num -= 1;
if (num < 0 || num >= MAX_PARTITIONS)
return false;
return _part_list[num].constructed();
}
block_number_t partition_lba(long num) const override
{
return partition_valid(num) ? _part_list[num - 1]->lba : 0;
}
block_number_t partition_sectors(long num) const override
{
return partition_valid(num) ? _part_list[num - 1]->sectors : 0;
}
void generate_report(Xml_generator &xml) const override void generate_report(Xml_generator &xml) const override
{ {
xml.attribute("type", "gpt"); xml.attribute("type", "gpt");
uint64_t const total_blocks = block.info().block_count; uint64_t const total_blocks = _info.block_count;
xml.attribute("total_blocks", total_blocks); xml.attribute("total_blocks", total_blocks);
xml.attribute("gpt_total", _gpt_total); xml.attribute("gpt_total", _gpt_total);
xml.attribute("gpt_used", _gpt_used); xml.attribute("gpt_used", _gpt_used);
size_t const block_size = block.info().block_size;
_for_each_valid_partition([&] (unsigned i) { _for_each_valid_partition([&] (unsigned i) {
Block::Partition const &part = *_part_list[i]; Gpt_partition const &part = *_part_list[i];
xml.node("partition", [&] () { xml.node("partition", [&] () {
xml.attribute("number", i + 1); xml.attribute("number", i + 1);
xml.attribute("name", part.name); xml.attribute("name", part.name);
xml.attribute("type", part.gpt_type); xml.attribute("type", part.type);
xml.attribute("guid", part.guid); xml.attribute("guid", part.guid);
xml.attribute("start", part.lba); xml.attribute("start", part.lba);
xml.attribute("length", part.sectors); xml.attribute("length", part.sectors);
xml.attribute("block_size", block_size); xml.attribute("block_size", _info.block_size);
uint64_t const gap = uint64_t const gap =
_calculate_gap(i, total_blocks); _calculate_gap(i, total_blocks);

View File

@ -3,16 +3,18 @@
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \author Stefan Kalkowski * \author Stefan Kalkowski
* \author Josef Soentgen * \author Josef Soentgen
* \author Christian Helmuth
* \date 2011-05-30 * \date 2011-05-30
*/ */
/* /*
* Copyright (C) 2011-2020 Genode Labs GmbH * Copyright (C) 2011-2023 Genode Labs GmbH
* *
* This file is part of the Genode OS framework, which is distributed * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
*/ */
/* Genode includes */
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <base/attached_ram_dataspace.h> #include <base/attached_ram_dataspace.h>
#include <base/component.h> #include <base/component.h>
@ -20,10 +22,13 @@
#include <block_session/rpc_object.h> #include <block_session/rpc_object.h>
#include <block/request_stream.h> #include <block/request_stream.h>
#include <os/session_policy.h> #include <os/session_policy.h>
#include <os/reporter.h>
#include <util/bit_allocator.h> #include <util/bit_allocator.h>
#include "gpt.h" #include "gpt.h"
#include "mbr.h" #include "mbr.h"
#include "ahdi.h"
#include "disk.h"
namespace Block { namespace Block {
class Session_component; class Session_component;
@ -202,7 +207,7 @@ class Block::Session_component : public Rpc_object<Block::Session>,
class Block::Main : Rpc_object<Typed_root<Session>>, class Block::Main : Rpc_object<Typed_root<Session>>,
Dispatch Dispatch, public Sync_read::Handler
{ {
private: private:
@ -221,10 +226,15 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
Allocator_avl _block_alloc { &_heap }; Allocator_avl _block_alloc { &_heap };
Block_connection _block { _env, &_block_alloc, _io_buffer_size }; Block_connection _block { _env, &_block_alloc, _io_buffer_size };
Session::Info _info { _block.info() };
Io_signal_handler<Main> _io_sigh { _env.ep(), *this, &Main::_handle_io }; Io_signal_handler<Main> _io_sigh { _env.ep(), *this, &Main::_handle_io };
Mbr_partition_table _mbr { _env, _block, _heap }; Mbr _mbr { *this, _heap, _info };
Gpt _gpt { _env, _block, _heap }; Gpt _gpt { *this, _heap, _info };
Partition_table &_partition_table { _table() }; Ahdi _ahdi { *this, _heap, _info };
Constructible<Disk> _disk { };
Partition_table & _partition_table { _table() };
enum { MAX_SESSIONS = 128 }; enum { MAX_SESSIONS = 128 };
Session_component *_sessions[MAX_SESSIONS] { }; Session_component *_sessions[MAX_SESSIONS] { };
@ -289,6 +299,7 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
Main(Env &env) : _env(env) Main(Env &env) : _env(env)
{ {
/* register final handler after initially synchronous block I/O */
_block.sigh(_io_sigh); _block.sigh(_io_sigh);
/* announce at parent */ /* announce at parent */
@ -326,10 +337,7 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
throw Service_denied(); throw Service_denied();
} }
try { if (!_partition_table.partition_valid(num)) {
_partition_table.partition(num);
}
catch (...) {
error("Partition ", num, " unavailable for '", label, "'"); error("Partition ", num, " unavailable for '", label, "'");
throw Service_denied(); throw Service_denied();
} }
@ -360,7 +368,7 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
Session::Info info { Session::Info info {
.block_size = _block.info().block_size, .block_size = _block.info().block_size,
.block_count = _partition_table.partition(num).sectors, .block_count = _partition_table.partition_sectors(num),
.align_log2 = 0, .align_log2 = 0,
.writeable = writeable, .writeable = writeable,
}; };
@ -405,7 +413,6 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
void completed(Job &job, bool success) void completed(Job &job, bool success)
{ {
job.request.success = success; job.request.success = success;
job.completed = true;
} }
@ -417,10 +424,9 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
Response submit(long number, Request const &request, addr_t addr) override Response submit(long number, Request const &request, addr_t addr) override
{ {
Partition &partition = _partition_table.partition(number); block_number_t last = request.operation.block_number + request.operation.count;
block_number_t last = request.operation.block_number + request.operation.count;
if (last > partition.sectors) if (last > _partition_table.partition_sectors(number))
return Response::REJECTED; return Response::REJECTED;
addr_t index = 0; addr_t index = 0;
@ -431,7 +437,7 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
_job_queue.with_job(index, [&](Job_object &job) { _job_queue.with_job(index, [&](Job_object &job) {
Operation op = request.operation; Operation op = request.operation;
op.block_number += partition.lba; op.block_number += _partition_table.partition_lba(number);
job.construct(_block, op, _job_registry, index, number, request, addr); job.construct(_block, op, _job_registry, index, number, request, addr);
}); });
@ -457,7 +463,7 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
void acknowledge_completed(bool all = true, long number = -1) override void acknowledge_completed(bool all = true, long number = -1) override
{ {
_job_registry.for_each([&] (Job &job) { _job_registry.for_each([&] (Job &job) {
if (!job.completed) return; if (!job.completed()) return;
addr_t index = job.index; addr_t index = job.index;
@ -474,6 +480,17 @@ class Block::Main : Rpc_object<Typed_root<Session>>,
_job_queue.free(index); _job_queue.free(index);
}); });
} }
/************************
** Sync_read::Handler **
************************/
Block_connection & connection() override { return _block; }
void block_for_io() override
{
_env.ep().wait_and_dispatch_one_io_signal();
}
}; };
@ -487,6 +504,7 @@ Block::Partition_table & Block::Main::_table()
bool valid_mbr = false; bool valid_mbr = false;
bool valid_gpt = false; bool valid_gpt = false;
bool pmbr_found = false; bool pmbr_found = false;
bool valid_ahdi = false;
bool report = false; bool report = false;
if (ignore_gpt && ignore_mbr) { if (ignore_gpt && ignore_mbr) {
@ -505,22 +523,39 @@ Block::Partition_table & Block::Main::_table()
throw; throw;
} }
/*
* The initial signal handler can be empty as it's only used to deblock
* wait_and_dispatch_one_io_signal() in Sync_read.
*/
struct Io_dummy { void fn() { }; } io_dummy;
Io_signal_handler<Io_dummy> handler(_env.ep(), io_dummy, &Io_dummy::fn);
_block.sigh(handler);
/* /*
* Try to parse MBR as well as GPT first if not instructued * Try to parse MBR as well as GPT first if not instructued
* to ignore either one of them. * to ignore either one of them.
*/ */
if (!ignore_mbr) { if (!ignore_mbr) {
try { valid_mbr = _mbr.parse(); } using Parse_result = Mbr::Parse_result;
catch (Mbr_partition_table::Protective_mbr_found) {
switch (_mbr.parse()) {
case Parse_result::MBR:
valid_mbr = true;
break;
case Parse_result::PROTECTIVE_MBR:
pmbr_found = true; pmbr_found = true;
} catch (...) { }; break;
case Parse_result::NO_MBR:
break;
}
} }
if (!ignore_gpt) { if (!ignore_gpt)
try { valid_gpt = _gpt.parse(); } valid_gpt = _gpt.parse();
catch (...) { }
} valid_ahdi = _ahdi.parse();
/* /*
* Both tables are valid (although we would have expected a PMBR in * Both tables are valid (although we would have expected a PMBR in
@ -536,27 +571,31 @@ Block::Partition_table & Block::Main::_table()
warning("will use GPT without proper protective MBR"); warning("will use GPT without proper protective MBR");
} }
/* PMBR missing, i.e, MBR part[0] contains whole disk and GPT valid */
if (pmbr_found && ignore_gpt) { if (pmbr_found && ignore_gpt) {
warning("found protective MBR but GPT is to be ignored"); warning("found protective MBR but GPT is to be ignored");
} }
auto pick_final_table = [&] () -> Partition_table & {
if (valid_gpt) return _gpt;
if (valid_mbr) return _mbr;
if (valid_ahdi) return _ahdi;
/* fall back to entire disk in partition 0 */
_disk.construct(*this, _heap, _info);
return *_disk;
};
Partition_table &table = pick_final_table();
/* generate appropriate report */ /* generate appropriate report */
if (_reporter.constructed()) if (_reporter.constructed()) {
_reporter->generate([&] (Xml_generator &xml) { _reporter->generate([&] (Xml_generator &xml) {
if (valid_gpt) _gpt.generate_report(xml); table.generate_report(xml);
if (valid_mbr) _mbr.generate_report(xml);
}); });
}
/* return table;
* Return the appropriate table or abort if none is found.
*/
if (valid_gpt) return _gpt;
if (valid_mbr) return _mbr;
error("Aborting: no partition table found.");
throw No_partition_table();
} }
void Component::construct(Genode::Env &env) { static Block::Main main(env); } void Component::construct(Genode::Env &env) { static Block::Main main(env); }

View File

@ -4,6 +4,7 @@
* \author Stefan Kalkowski * \author Stefan Kalkowski
* \author Josef Soentgen * \author Josef Soentgen
* \author Norman Feske * \author Norman Feske
* \author Christian Helmuth
* \date 2013-12-04 * \date 2013-12-04
*/ */
@ -17,29 +18,37 @@
#ifndef _PART_BLOCK__MBR_H_ #ifndef _PART_BLOCK__MBR_H_
#define _PART_BLOCK__MBR_H_ #define _PART_BLOCK__MBR_H_
#include <base/env.h>
#include <base/log.h>
#include <block_session/client.h>
#include <util/mmio.h>
#include "partition_table.h" #include "partition_table.h"
#include "fsprobe.h"
#include "ahdi.h"
namespace Block { namespace Block {
struct Mbr_partition_table; struct Mbr_partition;
struct Mbr;
}; };
struct Block::Mbr_partition_table : public Block::Partition_table
struct Block::Mbr_partition : Partition
{
uint8_t const type;
Mbr_partition(block_number_t lba,
block_number_t sectors,
Fs::Type fs_type,
uint8_t type)
:
Partition(lba, sectors, fs_type),
type(type)
{ }
};
class Block::Mbr : public Partition_table
{ {
public: public:
class Protective_mbr_found { }; enum class Parse_result { MBR, PROTECTIVE_MBR, NO_MBR };
private: private:
typedef Block::Partition_table::Sector Sector;
/** /**
* Partition table entry format * Partition table entry format
*/ */
@ -74,16 +83,16 @@ struct Block::Mbr_partition_table : public Block::Partition_table
/** /**
* Master/Extented boot record format * Master/Extented boot record format
*/ */
struct Mbr : Mmio struct Boot_record : Mmio
{ {
struct Magic : Register<510, 16> struct Magic : Register<510, 16>
{ {
enum { NUMBER = 0xaa55 }; enum { NUMBER = 0xaa55 };
}; };
Mbr() = delete; Boot_record() = delete;
Mbr(addr_t base) : Mmio(base) { } Boot_record(addr_t base) : Mmio(base) { }
bool valid() const bool valid() const
{ {
@ -97,11 +106,9 @@ struct Block::Mbr_partition_table : public Block::Partition_table
} }
}; };
enum { MAX_PARTITIONS = 32 }; enum { MAX_PARTITIONS = 32 };
/* contains pointers to valid partitions or 0 */ Constructible<Mbr_partition> _part_list[MAX_PARTITIONS];
Constructible<Partition> _part_list[MAX_PARTITIONS];
template <typename FUNC> template <typename FUNC>
void _parse_extended(Partition_record const &record, FUNC const &f) const void _parse_extended(Partition_record const &record, FUNC const &f) const
@ -113,9 +120,11 @@ struct Block::Mbr_partition_table : public Block::Partition_table
/* first logical partition number */ /* first logical partition number */
int nr = 5; int nr = 5;
do { do {
Sector s(const_cast<Sector_data&>(data), lba, 1); Sync_read s(_handler, _alloc, lba, 1);
Mbr const ebr(s.addr<addr_t>()); if (!s.success())
return;
Boot_record const ebr(s.addr<addr_t>());
if (!ebr.valid()) if (!ebr.valid())
return; return;
@ -140,7 +149,7 @@ struct Block::Mbr_partition_table : public Block::Partition_table
} }
template <typename FUNC> template <typename FUNC>
void _parse_mbr(Mbr const &mbr, FUNC const &f) const Parse_result _parse_mbr(Boot_record const &mbr, FUNC const &f) const
{ {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
Partition_record const r(mbr.record(i)); Partition_record const r(mbr.record(i));
@ -149,32 +158,15 @@ struct Block::Mbr_partition_table : public Block::Partition_table
continue; continue;
if (r.protective()) if (r.protective())
throw Protective_mbr_found(); return Parse_result::PROTECTIVE_MBR;
f(i + 1, r, 0); f(i + 1, r, 0);
if (r.extended()) if (r.extended())
_parse_extended(r, f); _parse_extended(r, f);
} }
}
/* state for partitions report */ return Parse_result::MBR;
bool _mbr_valid { false };
bool _ahdi_valid { false };
public:
using Partition_table::Partition_table;
Partition &partition(long num) override
{
if (num < 0 || num > MAX_PARTITIONS)
throw -1;
if (!_part_list[num].constructed())
throw -1;
return *_part_list[num];
} }
template <typename FN> template <typename FN>
@ -185,96 +177,78 @@ struct Block::Mbr_partition_table : public Block::Partition_table
fn(i); fn(i);
}; };
bool parse() override public:
{
block.sigh(io_sigh);
Sector s(data, 0, 1); using Partition_table::Partition_table;
Parse_result parse()
{
Sync_read s(_handler, _alloc, 0, 1);
if (!s.success())
return Parse_result::NO_MBR;
/* check for MBR */ /* check for MBR */
Mbr const mbr(s.addr<addr_t>()); Boot_record const mbr(s.addr<addr_t>());
_mbr_valid = mbr.valid(); if (!mbr.valid())
if (_mbr_valid) { return Parse_result::NO_MBR;
_parse_mbr(mbr, [&] (int i, Partition_record const &r, unsigned offset) {
log("MBR Partition ", i, ": LBA ",
r.lba() + offset, " (",
r.sectors(), " blocks) type: ",
Hex(r.type(), Hex::OMIT_PREFIX));
if (!r.extended()) { return _parse_mbr(mbr, [&] (int nr, Partition_record const &r, unsigned offset)
{
if (!r.extended()) {
block_number_t const lba = r.lba() + offset;
block_number_t const lba = r.lba() + offset; _part_list[nr - 1].construct(lba, r.sectors(), _fs_type(lba), r.type());
}
/* probe for known file-system types */ log("MBR Partition ", nr, ": LBA ",
enum { PROBE_BYTES = 4096, }; r.lba() + offset, " (",
Sector fs(data, lba , PROBE_BYTES / block.info().block_size); r.sectors(), " blocks) type: ",
Fs::Type const fs_type = Hex(r.type(), Hex::OMIT_PREFIX));
Fs::probe(fs.addr<uint8_t*>(), PROBE_BYTES); });
}
_part_list[i].construct( bool partition_valid(long num) const override
Partition(lba, r.sectors(), fs_type, r.type())); {
} /* 1-based partition number to 0-based array index */
}); num -= 1;
}
/* check for AHDI partition table */ if (num < 0 || num >= MAX_PARTITIONS)
_ahdi_valid = !_mbr_valid && Ahdi::valid(s); return false;
if (_ahdi_valid)
Ahdi::for_each_partition(s, [&] (unsigned i, Partition info) {
if (i < MAX_PARTITIONS)
_part_list[i].construct(
Partition(info.lba, info.sectors, Fs::Type(), 0));
});
/* no partition table, use whole disc as partition 0 */ return _part_list[num].constructed();
if (!_mbr_valid && !_ahdi_valid) }
_part_list[0].construct(
Partition(0, (block_count_t)(block.info().block_count - 1),
Fs::Type(), 0));
bool any_partition_valid = false; block_number_t partition_lba(long num) const override
_for_each_valid_partition([&] (unsigned) { {
any_partition_valid = true; }); return partition_valid(num) ? _part_list[num - 1]->lba : 0;
}
return any_partition_valid; block_number_t partition_sectors(long num) const override
{
return partition_valid(num) ? _part_list[num - 1]->sectors : 0;
} }
void generate_report(Xml_generator &xml) const override void generate_report(Xml_generator &xml) const override
{ {
auto gen_partition_attr = [&] (Xml_generator &xml, unsigned i) auto gen_partition_attr = [&] (Xml_generator &xml, unsigned i)
{ {
Partition const &part = *_part_list[i]; Mbr_partition const &part = *_part_list[i];
size_t const block_size = block.info().block_size; xml.attribute("number", i + 1);
xml.attribute("number", i);
xml.attribute("start", part.lba); xml.attribute("start", part.lba);
xml.attribute("length", part.sectors); xml.attribute("length", part.sectors);
xml.attribute("block_size", block_size); xml.attribute("block_size", _info.block_size);
xml.attribute("type", part.type);
if (_mbr_valid)
xml.attribute("type", part.mbr_type);
else if (_ahdi_valid)
xml.attribute("type", "bgm");
if (part.fs_type.valid()) if (part.fs_type.valid())
xml.attribute("file_system", part.fs_type); xml.attribute("file_system", part.fs_type);
}; };
xml.attribute("type", _mbr_valid ? "mbr" : xml.attribute("type", "mbr");
_ahdi_valid ? "ahdi" :
"disk");
if (_mbr_valid || _ahdi_valid) {
_for_each_valid_partition([&] (unsigned i) {
xml.node("partition", [&] {
gen_partition_attr(xml, i); }); });
} else {
_for_each_valid_partition([&] (unsigned i) {
xml.node("partition", [&] { xml.node("partition", [&] {
gen_partition_attr(xml, 0); }); gen_partition_attr(xml, i); }); });
}
} }
}; };

View File

@ -2,6 +2,7 @@
* \brief Partition table definitions * \brief Partition table definitions
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \author Stefan Kalkowski * \author Stefan Kalkowski
* \author Christian Helmuth
* \date 2013-12-04 * \date 2013-12-04
*/ */
@ -15,193 +16,59 @@
#ifndef _PART_BLOCK__PARTITION_TABLE_H_ #ifndef _PART_BLOCK__PARTITION_TABLE_H_
#define _PART_BLOCK__PARTITION_TABLE_H_ #define _PART_BLOCK__PARTITION_TABLE_H_
#include <base/env.h> #include "block.h"
#include <base/log.h>
#include <base/registry.h>
#include <block_session/connection.h>
#include <os/reporter.h>
#include "fsprobe.h" #include "fsprobe.h"
#include "types.h"
namespace Block { namespace Block {
struct Partition; struct Partition;
class Partition_table; class Partition_table;
struct Job;
using namespace Genode;
typedef Block::Connection<Job> Block_connection;
} }
struct Block::Partition struct Block::Partition : Noncopyable
{ {
block_number_t lba; /* logical block address on device */ block_number_t const lba; /* logical block address on device */
block_count_t sectors; /* number of sectors in patitions */ block_number_t const sectors; /* number of sectors in partitions */
Fs::Type fs_type { }; Fs::Type fs_type { };
uint8_t mbr_type { 0 };
using Uuid = String<40>;
Uuid guid { };
Uuid gpt_type { };
using Name = String<72>; /* use GPT name antry length */
Name name { };
Partition(block_number_t lba, Partition(block_number_t lba,
block_count_t sectors, block_number_t sectors,
Fs::Type fs_type, Fs::Type fs_type)
uint8_t mbr_type) : lba(lba), sectors(sectors), fs_type(fs_type) { }
:
lba(lba), sectors(sectors), fs_type(fs_type),
mbr_type(mbr_type)
{ }
Partition(block_number_t lba,
block_count_t sectors,
Fs::Type fs_type,
Uuid const &guid, Uuid const &gpt_type,
Name const &name)
:
lba(lba), sectors(sectors), fs_type(fs_type),
guid(guid), gpt_type(gpt_type), name(name)
{ }
}; };
struct Block::Job : public Block_connection::Job class Block::Partition_table : Interface, Noncopyable
{ {
Registry<Job>::Element registry_element; protected:
addr_t const index; /* job index */ Sync_read::Handler &_handler;
long const number; /* parition number */ Allocator &_alloc;
Request request; Session::Info const _info;
addr_t const addr; /* target payload address */
bool completed { false };
Job(Block_connection &connection, Fs::Type _fs_type(block_number_t lba)
Operation operation,
Registry<Job> &registry,
addr_t const index,
addr_t const number,
Request request,
addr_t addr)
: Block_connection::Job(connection, operation),
registry_element(registry, *this),
index(index), number(number), request(request), addr(addr) { }
};
struct Block::Partition_table : Interface
{
struct Sector;
struct Sector_data
{ {
Env &env; /* probe for known file-system types */
Block_connection &block; enum { BYTES = 4096 };
Allocator &alloc; Sync_read fs(_handler, _alloc, lba, BYTES / _info.block_size);
Sector *current = nullptr; if (fs.success())
return Fs::probe(fs.addr<uint8_t*>(), BYTES);
Sector_data(Env &env, Block_connection &block, Allocator &alloc) else
: env(env), block(block), alloc(alloc) { } return Fs::Type();
};
/**
* Read sectors synchronously
*/
class Sector
{
private:
Sector_data &_data;
bool _completed { false };
size_t _size { 0 };
void *_buffer { nullptr };
Sector(Sector const &);
Sector &operator = (Sector const &);
public:
Sector(Sector_data &data,
block_number_t block_number,
block_count_t count)
: _data(data)
{
Operation const operation {
.type = Operation::Type::READ,
.block_number = block_number,
.count = count
};
Block_connection::Job job { data.block, operation };
_data.block.update_jobs(*this);
_data.current = this;
while (!_completed)
data.env.ep().wait_and_dispatch_one_io_signal();
_data.current = nullptr;
}
~Sector()
{
_data.alloc.free(_buffer, _size);
}
void handle_io()
{
_data.block.update_jobs(*this);
}
void consume_read_result(Block_connection::Job &, off_t offset,
char const *src, size_t length)
{
_buffer = _data.alloc.alloc(length);
memcpy((char *)_buffer + offset, src, length);
_size += length;
}
void produce_write_content(Block_connection::Job &, off_t,
char *, size_t) { }
void completed(Block_connection::Job &, bool success)
{
_completed = true;
if (!success) {
error("IO error during partition parsing");
throw -1;
}
}
template <typename T> T addr() const {
return reinterpret_cast<T>(_buffer); }
};
Env &env;
Block_connection &block;
Sector_data data;
Io_signal_handler<Partition_table> io_sigh {
env.ep(), *this, &Partition_table::handle_io };
void handle_io()
{
if (data.current) { data.current->handle_io(); }
} }
Partition_table(Env &env, public:
Block_connection &block,
Allocator &alloc)
: env(env), block(block), data(env, block, alloc)
{ }
virtual Partition &partition(long num) = 0; Partition_table(Sync_read::Handler &handler,
Allocator &alloc,
Session::Info info)
: _handler(handler), _alloc(alloc), _info(info) { }
virtual bool parse() = 0; virtual bool partition_valid(long num) const = 0;
virtual block_number_t partition_lba(long num) const = 0;
virtual block_number_t partition_sectors(long num) const = 0;
virtual void generate_report(Xml_generator &xml) const = 0; virtual void generate_report(Xml_generator &xml) const = 0;
}; };

View File

@ -0,0 +1,33 @@
/*
* \brief Types used by part_block
* \author Christian Helmuth
* \date 2023-03-16
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _PART_BLOCK__TYPES_H_
#define _PART_BLOCK__TYPES_H_
/* Genode includes */
#include <base/registry.h>
#include <base/log.h>
#include <util/xml_generator.h>
#include <util/mmio.h>
#include <util/misc_math.h>
#include <util/utf8.h>
#include <block_session/connection.h>
namespace Block {
using namespace Genode;
struct Job;
typedef Block::Connection<Job> Block_connection;
}
#endif /* _PART_BLOCK__TYPES_H_ */