mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-11 20:01:48 +00:00
1
repos/os/recipes/pkg/test-part_block_ahdi/README
Normal file
1
repos/os/recipes/pkg/test-part_block_ahdi/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
Test part_block server with Atari AHDI disk.
|
7
repos/os/recipes/pkg/test-part_block_ahdi/archives
Normal file
7
repos/os/recipes/pkg/test-part_block_ahdi/archives
Normal 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
|
1
repos/os/recipes/pkg/test-part_block_ahdi/hash
Normal file
1
repos/os/recipes/pkg/test-part_block_ahdi/hash
Normal file
@ -0,0 +1 @@
|
|||||||
|
2023-03-17-d 6690319be80b9b24b647c36303dde6ece6048cb8
|
81
repos/os/recipes/pkg/test-part_block_ahdi/runtime
Normal file
81
repos/os/recipes/pkg/test-part_block_ahdi/runtime
Normal 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>
|
1
repos/os/recipes/pkg/test-part_block_disk/README
Normal file
1
repos/os/recipes/pkg/test-part_block_disk/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
Test part_block server with GPT disk.
|
7
repos/os/recipes/pkg/test-part_block_disk/archives
Normal file
7
repos/os/recipes/pkg/test-part_block_disk/archives
Normal 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
|
1
repos/os/recipes/pkg/test-part_block_disk/hash
Normal file
1
repos/os/recipes/pkg/test-part_block_disk/hash
Normal file
@ -0,0 +1 @@
|
|||||||
|
2023-03-17 0d6f7581b18066825dd6e9db06faf2c6edb31331
|
81
repos/os/recipes/pkg/test-part_block_disk/runtime
Normal file
81
repos/os/recipes/pkg/test-part_block_disk/runtime
Normal 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>
|
@ -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"/>
|
||||||
|
@ -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*
|
||||||
|
BIN
repos/os/recipes/raw/test-part_block_ahdi/ata.ahdi.raw.tar.gz
Normal file
BIN
repos/os/recipes/raw/test-part_block_ahdi/ata.ahdi.raw.tar.gz
Normal file
Binary file not shown.
4
repos/os/recipes/raw/test-part_block_ahdi/content.mk
Normal file
4
repos/os/recipes/raw/test-part_block_ahdi/content.mk
Normal 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
|
1
repos/os/recipes/raw/test-part_block_ahdi/hash
Normal file
1
repos/os/recipes/raw/test-part_block_ahdi/hash
Normal file
@ -0,0 +1 @@
|
|||||||
|
2023-03-17 9c4b6f3d932b62b0c8d49ebd670aa2cada723988
|
Binary file not shown.
@ -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"/>
|
||||||
|
@ -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 §or)
|
||||||
|
{
|
||||||
|
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 §or, 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 §or)
|
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 §or, 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_ */
|
||||||
|
134
repos/os/src/server/part_block/block.h
Normal file
134
repos/os/src/server/part_block/block.h
Normal 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> ®istry,
|
||||||
|
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_ */
|
70
repos/os/src/server/part_block/disk.h
Normal file
70
repos/os/src/server/part_block/disk.h
Normal 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_ */
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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); }
|
||||||
|
@ -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); }); });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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> ®istry,
|
|
||||||
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 █
|
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 █
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
33
repos/os/src/server/part_block/types.h
Normal file
33
repos/os/src/server/part_block/types.h
Normal 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_ */
|
Reference in New Issue
Block a user