From 927d71ad59f254dfc9a2b51ab49113c4fa8bc0fb Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Thu, 16 Mar 2023 15:50:55 +0100 Subject: [PATCH] part_block: modernize implementation Fixes #4790 --- .../recipes/pkg/test-part_block_ahdi/README | 1 + .../recipes/pkg/test-part_block_ahdi/archives | 7 + .../os/recipes/pkg/test-part_block_ahdi/hash | 1 + .../recipes/pkg/test-part_block_ahdi/runtime | 81 ++++++ .../recipes/pkg/test-part_block_disk/README | 1 + .../recipes/pkg/test-part_block_disk/archives | 7 + .../os/recipes/pkg/test-part_block_disk/hash | 1 + .../recipes/pkg/test-part_block_disk/runtime | 81 ++++++ .../recipes/pkg/test-part_block_gpt/runtime | 2 +- .../recipes/pkg/test-part_block_mbr/runtime | 2 +- .../test-part_block_ahdi/ata.ahdi.raw.tar.gz | Bin 0 -> 1185 bytes .../raw/test-part_block_ahdi/content.mk | 4 + .../os/recipes/raw/test-part_block_ahdi/hash | 1 + .../test-part_block_mbr/ata.mbr.raw.tar.gz | Bin 10493 -> 11480 bytes repos/os/src/server/part_block/README | 6 +- repos/os/src/server/part_block/ahdi.h | 233 +++++++++++++----- repos/os/src/server/part_block/block.h | 134 ++++++++++ repos/os/src/server/part_block/disk.h | 70 ++++++ repos/os/src/server/part_block/fsprobe.h | 91 +++---- repos/os/src/server/part_block/gpt.h | 134 ++++++---- repos/os/src/server/part_block/main.cc | 111 ++++++--- repos/os/src/server/part_block/mbr.h | 180 ++++++-------- .../src/server/part_block/partition_table.h | 193 +++------------ repos/os/src/server/part_block/types.h | 33 +++ 24 files changed, 906 insertions(+), 468 deletions(-) create mode 100644 repos/os/recipes/pkg/test-part_block_ahdi/README create mode 100644 repos/os/recipes/pkg/test-part_block_ahdi/archives create mode 100644 repos/os/recipes/pkg/test-part_block_ahdi/hash create mode 100644 repos/os/recipes/pkg/test-part_block_ahdi/runtime create mode 100644 repos/os/recipes/pkg/test-part_block_disk/README create mode 100644 repos/os/recipes/pkg/test-part_block_disk/archives create mode 100644 repos/os/recipes/pkg/test-part_block_disk/hash create mode 100644 repos/os/recipes/pkg/test-part_block_disk/runtime create mode 100644 repos/os/recipes/raw/test-part_block_ahdi/ata.ahdi.raw.tar.gz create mode 100644 repos/os/recipes/raw/test-part_block_ahdi/content.mk create mode 100644 repos/os/recipes/raw/test-part_block_ahdi/hash create mode 100644 repos/os/src/server/part_block/block.h create mode 100644 repos/os/src/server/part_block/disk.h create mode 100644 repos/os/src/server/part_block/types.h diff --git a/repos/os/recipes/pkg/test-part_block_ahdi/README b/repos/os/recipes/pkg/test-part_block_ahdi/README new file mode 100644 index 0000000000..b7bfcc3b4e --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_ahdi/README @@ -0,0 +1 @@ +Test part_block server with Atari AHDI disk. diff --git a/repos/os/recipes/pkg/test-part_block_ahdi/archives b/repos/os/recipes/pkg/test-part_block_ahdi/archives new file mode 100644 index 0000000000..f993cb647c --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_ahdi/archives @@ -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 diff --git a/repos/os/recipes/pkg/test-part_block_ahdi/hash b/repos/os/recipes/pkg/test-part_block_ahdi/hash new file mode 100644 index 0000000000..8dc8a31e22 --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_ahdi/hash @@ -0,0 +1 @@ +2023-03-17-d 6690319be80b9b24b647c36303dde6ece6048cb8 diff --git a/repos/os/recipes/pkg/test-part_block_ahdi/runtime b/repos/os/recipes/pkg/test-part_block_ahdi/runtime new file mode 100644 index 0000000000..9411bc1ec3 --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_ahdi/runtime @@ -0,0 +1,81 @@ + + + + + + + + child "test-part*" exited with exit value 0 + + Error: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/recipes/pkg/test-part_block_disk/README b/repos/os/recipes/pkg/test-part_block_disk/README new file mode 100644 index 0000000000..a93a200584 --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_disk/README @@ -0,0 +1 @@ +Test part_block server with GPT disk. diff --git a/repos/os/recipes/pkg/test-part_block_disk/archives b/repos/os/recipes/pkg/test-part_block_disk/archives new file mode 100644 index 0000000000..488aebe2b2 --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_disk/archives @@ -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 diff --git a/repos/os/recipes/pkg/test-part_block_disk/hash b/repos/os/recipes/pkg/test-part_block_disk/hash new file mode 100644 index 0000000000..e8139aa653 --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_disk/hash @@ -0,0 +1 @@ +2023-03-17 0d6f7581b18066825dd6e9db06faf2c6edb31331 diff --git a/repos/os/recipes/pkg/test-part_block_disk/runtime b/repos/os/recipes/pkg/test-part_block_disk/runtime new file mode 100644 index 0000000000..fc186d3e59 --- /dev/null +++ b/repos/os/recipes/pkg/test-part_block_disk/runtime @@ -0,0 +1,81 @@ + + + + + + + + child "test-part*" exited with exit value 0 + + Error: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/recipes/pkg/test-part_block_gpt/runtime b/repos/os/recipes/pkg/test-part_block_gpt/runtime index 35243625e5..40d07b3f51 100644 --- a/repos/os/recipes/pkg/test-part_block_gpt/runtime +++ b/repos/os/recipes/pkg/test-part_block_gpt/runtime @@ -53,7 +53,7 @@ - + diff --git a/repos/os/recipes/pkg/test-part_block_mbr/runtime b/repos/os/recipes/pkg/test-part_block_mbr/runtime index 7e48de58af..a37c83661b 100644 --- a/repos/os/recipes/pkg/test-part_block_mbr/runtime +++ b/repos/os/recipes/pkg/test-part_block_mbr/runtime @@ -3,7 +3,7 @@ - + child "test-part*" exited with exit value 0* child "test-part*" exited with exit value 0* diff --git a/repos/os/recipes/raw/test-part_block_ahdi/ata.ahdi.raw.tar.gz b/repos/os/recipes/raw/test-part_block_ahdi/ata.ahdi.raw.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..88eabdb7e95fe00400360ffe94705fdcc72de5df GIT binary patch literal 1185 zcmb2|=3tO;7fE4YetXU^%gIrI?SWyhJ5T4^UHf*H+P+/dev/null diff --git a/repos/os/recipes/raw/test-part_block_ahdi/hash b/repos/os/recipes/raw/test-part_block_ahdi/hash new file mode 100644 index 0000000000..37beac48d5 --- /dev/null +++ b/repos/os/recipes/raw/test-part_block_ahdi/hash @@ -0,0 +1 @@ +2023-03-17 9c4b6f3d932b62b0c8d49ebd670aa2cada723988 diff --git a/repos/os/recipes/raw/test-part_block_mbr/ata.mbr.raw.tar.gz b/repos/os/recipes/raw/test-part_block_mbr/ata.mbr.raw.tar.gz index b63836a0f43a0cdce9fa6043681ac67a1482c284..725610f3cecb03eeefd59010b3eeb4dfe55c6b73 100644 GIT binary patch delta 1454 zcmaLVeK^wz00;1~4o6-t%I*q@UWq(vURGY_t`{n#BbGQs@=~|SW^4OZmk^S-)-}f= zZwb%O%c6M;k7Re|HO83Nw&mT-HnaWiuK)VyzW;u|e|?^>+;hYiFiKW~IcXt6VDN?U zs2l!a2Cx+#M;}KkK7p$Y*-oz+qNYyI6(bj&l9Tuj=RayPB+kzGhztu;H`k@3JAQxR zYqOG_pZFwca^rf3*4Ey~iGF$^ltU8d)#Q}yo$SP#0=Vp59Qk5&f6;M&h8i}*&?SQfa+&x#^Bvr!u8x`She2@ORM8zPwY8dT z235p{wjLVc6~WeiGlW9lJhy>kCv4dDKrw|KyL+g8*XEQNUVhx7pVpp)xuu!EgBd^E z7xhx78=sZgYs73fPO*rM$$)(ou;nuxxGL&j*#B+5rNyDz=jlk)l8hcMvcs5y6e8YV-1yVXZXJ*t7xt473Q{ z;8E&5HvHC7kEAhBlj{5_H;FxCjoG{m8&O{*jrs_oxgZpDKj+XLlCslq7tm!X)t2su zj9X?MXQ^8WTN%*PfHk8vH-!u3!rUNueG8_=Lne7Aqld|%HtTI0k!t* zR7RRbEb##dO8&JT-wZbIAh@NJA?6StMpeR5n?BylW5{E>(B*d|SF1UdO%wFdTe9x3 z3B#G;cu7N%PBS#APZ3eA@d=skj@XUj7V>-`kIr9fR;1C#wj$jvHt~7y zWYd9D)Ko}!FL4YldLaGBi(9Id*L)R_s4wrOuXHYmdJrC2W)8JTe{+Y7&6q%!zEm6d zUq@*j5>mQ%H(V4WvwV6#TClOI`qf)u^@HRwl}_*A^3JURf|_M&2RgiIHJJ&e**@%E zi&%Ede9ivm9Am8b?#f>W90M~QM2kyLpl&JyrFa*Le-HU_obT^4d>rpr79&tlUoQX< zBLZ34GDV{83Czs38yR0UD|w4juqb+MWeXB7%(BEw4bEhW(j3WF-LySGXpQQzbP%)i zTGbh1TT<2fBafuH*;Krdf8(^ZG6)jj#)^QGAS#D|#j9oOJgO0Kv(Rzj?rP!Y;%E*z z1}v1jL7X z>85`EvFUsDB2&HUD&e`a?JMy}jVU^h=EAj$!4q%HR%(~@8JLK*mQtC2*vQv(wR0Qi zF5_hHDUCwjsi_#~AXU*UUJ&?~R0V9Zn#AtNe#t58vGenSbT&Iw-nCA!N3x&4Di)j? zm=Sdn?Ck~+d5ls@kS%dz1eDe~Sknu|BOF5EcgaG*pycjo&IK9{{B(niJy79YE_gDr zB%iEQFHGiPDx%#VSggrZLGUKrzy=iB3mRz}>3FG}gH>KclLZN7Fa6WF0YVgCTeR1HP| delta 390 zcmcZ+`8Tj$zMF%gys9mRf%(lj$1LGQ3AP92i=2HB6|-mYRx_Kpj^ z57gF{MDy%;VfZG`rh)x~hF&$>LC(7+sUk89zg0eXT>pRO|K{?_jW#v^%Sv}d#Vyk> zeSWoOpJn>-?qC0Qu6UnPW-|Z$v%A-SDt*l<3z1I``F`!iJVXBH;-{}>OevrKe1FaM zxAuRWY>xw_iy}GHR011olUo&PF|8(t;@Ojp~@R}c?Jds8@AKp zH!WwYgii0yv$ON8H1;c-JUQ!k)#Y!o0-HYym$3*{7}&i{skQZ4r6*p$@7|XBy@DG* zRxrza2&j=uuQm2t^(3YE|2LDTZyk+ZeJTKHyu}AMy@F@o{xiS6DXiRO^J1A!cTs-S z62En;-oEy|UG4~0WCC=;gZ<_+MPBdCoT#<))}8aqG}pJE+ +! the 'ata_driver' and 'part_block' is 1 MiB ('io_buffer') --> ! ! ! diff --git a/repos/os/src/server/part_block/ahdi.h b/repos/os/src/server/part_block/ahdi.h index 27d7cc1f1a..e14f4b2cba 100644 --- a/repos/os/src/server/part_block/ahdi.h +++ b/repos/os/src/server/part_block/ahdi.h @@ -1,6 +1,7 @@ /* * \brief Atari ST partition scheme (AHDI) * \author Norman Feske + * \author Christian Helmuth * \date 2019-08-09 */ @@ -16,84 +17,184 @@ #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; - typedef Genode::uint8_t uint8_t; + Ahdi_partition(block_number_t lba, + 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 { - return ((uint32_t)b0 << 24) | ((uint32_t)b1 << 16) - | ((uint32_t)b2 << 8) | ((uint32_t)b3 << 0); } +class Block::Ahdi : public Partition_table +{ + private: - } __attribute__((packed)); - - struct Partition_record - { - uint8_t _flags; - uint8_t _id0, _id1, _id2; - Be32 start; /* first block */ - Be32 length; /* in blocks */ - - typedef Genode::String<4> Id; - - Id id() const + /** + * 32-bit big-endian value + */ + struct Be32 { - using Genode::Char; - return Id(Char(_id0), Char(_id1), Char(_id2)); + uint8_t b0, b1, b2, b3; + + 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 _part_list[MAX_PARTITIONS]; + + bool _valid(Sync_read const §or) + { + bool any_partition_valid = false; + + Root_sector const root = *sector.addr(); + 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 + void _parse_ahdi(Sync_read const §or, FUNC const &fn) + { + Root_sector &root = *sector.addr(); - 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)); - - 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)); - - static bool valid(Sector const §or) - { - bool any_partition_valid = false; - - Root_sector const root = *sector.addr(); - for (unsigned i = 0; i < MAX_PARTITIONS; i++) - if (root.partitions[i].valid()) - any_partition_valid = true; - - return any_partition_valid; - } - - template - static void for_each_partition(Sector const §or, FN const &fn) - { - Root_sector &root = *sector.addr(); - - for (unsigned i = 0; i < MAX_PARTITIONS; i++) { - Partition_record const &part = root.partitions[i]; - if (part.valid()) - fn(i + 1, Block::Partition(part.start.value(), part.length.value(), - Fs::Type(), 0)); + fn(i, part); + } + } + + template + void _for_each_valid_partition(FN const &fn) const + { + for (unsigned i = 0; i < MAX_PARTITIONS; i++) + if (_part_list[i].constructed()) + fn(i); + }; + + public: + + using Partition_table::Partition_table; + + bool parse() + { + Sync_read s(_handler, _alloc, 0, 1); + + if (!s.success() || !_valid(s)) + return false; + + _parse_ahdi(s, [&] (unsigned i, Partition_record const &r) { + block_number_t lba = r.start.value(); + block_number_t length = r.length.value(); + + Ahdi_partition::Type type = r.id(); + + _part_list[i].construct(lba, length, _fs_type(lba), type); + + log("AHDI Partition ", i + 1, ": LBA ", lba, " (", length, + " blocks) type: '", type, "'"); + }); + + 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_ */ diff --git a/repos/os/src/server/part_block/block.h b/repos/os/src/server/part_block/block.h new file mode 100644 index 0000000000..deb70f8de4 --- /dev/null +++ b/repos/os/src/server/part_block/block.h @@ -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::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 ®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 T addr() const { + return reinterpret_cast(_buffer); } +}; + + +#endif /* _PART_BLOCK__BLOCK_H_ */ diff --git a/repos/os/src/server/part_block/disk.h b/repos/os/src/server/part_block/disk.h new file mode 100644 index 0000000000..c7e206e0e1 --- /dev/null +++ b/repos/os/src/server/part_block/disk.h @@ -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_ */ diff --git a/repos/os/src/server/part_block/fsprobe.h b/repos/os/src/server/part_block/fsprobe.h index 354129b8e7..3b3b5c2291 100644 --- a/repos/os/src/server/part_block/fsprobe.h +++ b/repos/os/src/server/part_block/fsprobe.h @@ -1,6 +1,7 @@ /* * \brief Poor man's partition probe for known file system * \author Josef Soentgen + * \author Christian Helmuth * \date 2018-05-03 */ @@ -24,64 +25,68 @@ namespace Fs { 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); +} - /** - * 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 { - COMPAT_HAS_JOURNAL = 0x004u, - INCOMPAT_EXTENTS = 0x040u, - RO_COMPAT_METADATA_CSUM = 0x400u, - }; + bool const found_ext_sig = p[0x38] == 0x53 && p[0x39] == 0xEF; - 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); + enum { + COMPAT_HAS_JOURNAL = 0x004u, + 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; - bool const ext4 = ext3 && ((incompat & INCOMPAT_EXTENTS) - && (ro_compat & RO_COMPAT_METADATA_CSUM)); + /* the feature flags should denote a given Ext version */ - 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"); } + bool const ext3 = compat & COMPAT_HAS_JOURNAL; + bool const ext4 = ext3 && ((incompat & INCOMPAT_EXTENTS) + && (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"); } - /** - * Probe for FAT16/32 - */ - Type _probe_fatfs(uint8_t *p, size_t len) - { - if (len < 512) { return Type(); } + 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) - && (p[82] == 'F' && p[83] == 'A'); - bool const gemdos = (p[0] == 0xe9); +/** + * Probe for FAT16/32 + */ +Fs::Type Fs::_probe_fatfs(uint8_t *p, size_t len) +{ + if (len < 512) { return Type(); } - if (found_boot_sig && fat32) { return Type("FAT32"); } - if (found_boot_sig && fat16) { return Type("FAT16"); } - if (gemdos) { return Type("GEMDOS"); } + /* at least the checks ring true when mkfs.vfat is used... */ + bool const found_boot_sig = p[510] == 0x55 && p[511] == 0xAA; - 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(); } diff --git a/repos/os/src/server/part_block/gpt.h b/repos/os/src/server/part_block/gpt.h index ce8084a98f..3559929187 100644 --- a/repos/os/src/server/part_block/gpt.h +++ b/repos/os/src/server/part_block/gpt.h @@ -2,6 +2,7 @@ * \brief GUID Partition table definitions * \author Josef Soentgen * \author Sebastian Sumpf + * \author Christian Helmuth * \date 2014-09-19 */ @@ -15,21 +16,38 @@ #ifndef _PART_BLOCK__GPT_H_ #define _PART_BLOCK__GPT_H_ -#include -#include -#include -#include -#include -#include - #include "partition_table.h" static bool constexpr verbose = false; namespace Block { + class Gpt_partition; 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 { private: @@ -37,9 +55,7 @@ class Block::Gpt : public Block::Partition_table enum { MAX_PARTITIONS = 128 }; /* contains valid partitions or not constructed */ - Constructible _part_list[MAX_PARTITIONS]; - - typedef Block::Partition_table::Sector Sector; + Constructible _part_list[MAX_PARTITIONS]; /** * DCE uuid struct @@ -83,7 +99,6 @@ class Block::Gpt : public Block::Partition_table * GUID parition table header */ struct Gpt_hdr : Mmio - { struct Sig : Register<0, 64> { }; /* identifies GUID Partition Table */ struct Revision : Register<8, 32> { }; /* GPT specification revision */ @@ -147,7 +162,8 @@ class Block::Gpt : public Block::Partition_table log(" gpe crc: ", Hex(read(), 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); @@ -172,17 +188,20 @@ class Block::Gpt : public Block::Partition_table /* check GPT entry array */ size_t length = entries() * entry_size(); - Sector gpe(data, gpe_lba(), length / data.block.info().block_size); - if (crc32(gpe.addr(), length) != read()) + Sync_read gpe(handler, alloc, gpe_lba(), length / block_size); + if (!gpe.success() + || crc32(gpe.addr(), length) != read()) return false; if (check_primary) { /* check backup gpt header */ - Sector backup_hdr(data, read(), 1); + Sync_read backup_hdr(handler, alloc, read(), 1); + if (!backup_hdr.success()) + return false; + Gpt_hdr backup(backup_hdr.addr()); - if (!backup.valid(data, false)) { + if (!backup.valid(handler, alloc, block_size, false)) warning("Backup GPT header is corrupted"); - } } return true; @@ -336,13 +355,15 @@ class Block::Gpt : public Block::Partition_table /** * Parse the GPT header */ - void _parse_gpt(Gpt_hdr &gpt) + bool _parse_gpt(Gpt_hdr &gpt) { - if (!(gpt.valid(data))) - throw Exception(); + if (!gpt.valid(_handler, _alloc, _info.block_size)) + return false; - Sector entry_array(data, gpt.gpe_lba(), - gpt.entries() * gpt.entry_size() / block.info().block_size); + Sync_read entry_array(_handler, _alloc, gpt.gpe_lba(), + gpt.entries() * gpt.entry_size() / _info.block_size); + if (!entry_array.success()) + return false; Gpt_entry entries(entry_array.addr()); _gpt_part_lba_end = gpt.part_lba_end(); @@ -356,51 +377,37 @@ class Block::Gpt : public Block::Partition_table if (!e.valid()) continue; - block_number_t const lba_start = e.lba_start(); - block_count_t const length = (block_count_t)(e.lba_end() - lba_start + 1); /* [...) */ - - enum { BYTES = 4096, }; - Sector fs(data, lba_start, BYTES / block.info().block_size); - Fs::Type fs_type = Fs::probe(fs.addr(), BYTES); + block_number_t const lba = e.lba_start(); + block_number_t const length = e.lba_end() - lba + 1; String<40> guid { e.guid() }; String<40> type { e.type() }; String name { e }; - _part_list[i].construct(lba_start, length, fs_type, - guid, type, name); + _part_list[i].construct(lba, length, _fs_type(lba), guid, type, name); - log("GPT Partition ", i + 1, ": LBA ", lba_start, " (", length, + log("GPT Partition ", i + 1, ": LBA ", lba, " (", length, " blocks) type: '", type, "' name: '", name, "'"); } + + return true; } public: 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()); - _parse_gpt(gpt_hdr); + if (!_parse_gpt(gpt_hdr)) + return false; for (unsigned num = 0; num < MAX_PARTITIONS; num++) if (_part_list[num].constructed()) @@ -408,30 +415,49 @@ class Block::Gpt : public Block::Partition_table 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 { 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("gpt_total", _gpt_total); xml.attribute("gpt_used", _gpt_used); - size_t const block_size = block.info().block_size; - _for_each_valid_partition([&] (unsigned i) { - Block::Partition const &part = *_part_list[i]; + Gpt_partition const &part = *_part_list[i]; xml.node("partition", [&] () { xml.attribute("number", i + 1); xml.attribute("name", part.name); - xml.attribute("type", part.gpt_type); + xml.attribute("type", part.type); xml.attribute("guid", part.guid); xml.attribute("start", part.lba); xml.attribute("length", part.sectors); - xml.attribute("block_size", block_size); + xml.attribute("block_size", _info.block_size); uint64_t const gap = _calculate_gap(i, total_blocks); diff --git a/repos/os/src/server/part_block/main.cc b/repos/os/src/server/part_block/main.cc index b64300911c..0bdb0085e3 100644 --- a/repos/os/src/server/part_block/main.cc +++ b/repos/os/src/server/part_block/main.cc @@ -3,16 +3,18 @@ * \author Sebastian Sumpf * \author Stefan Kalkowski * \author Josef Soentgen + * \author Christian Helmuth * \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 * under the terms of the GNU Affero General Public License version 3. */ +/* Genode includes */ #include #include #include @@ -20,10 +22,13 @@ #include #include #include +#include #include #include "gpt.h" #include "mbr.h" +#include "ahdi.h" +#include "disk.h" namespace Block { class Session_component; @@ -202,7 +207,7 @@ class Block::Session_component : public Rpc_object, class Block::Main : Rpc_object>, - Dispatch + Dispatch, public Sync_read::Handler { private: @@ -221,10 +226,15 @@ class Block::Main : Rpc_object>, Allocator_avl _block_alloc { &_heap }; Block_connection _block { _env, &_block_alloc, _io_buffer_size }; + Session::Info _info { _block.info() }; Io_signal_handler
_io_sigh { _env.ep(), *this, &Main::_handle_io }; - Mbr_partition_table _mbr { _env, _block, _heap }; - Gpt _gpt { _env, _block, _heap }; - Partition_table &_partition_table { _table() }; + Mbr _mbr { *this, _heap, _info }; + Gpt _gpt { *this, _heap, _info }; + Ahdi _ahdi { *this, _heap, _info }; + + Constructible _disk { }; + + Partition_table & _partition_table { _table() }; enum { MAX_SESSIONS = 128 }; Session_component *_sessions[MAX_SESSIONS] { }; @@ -289,6 +299,7 @@ class Block::Main : Rpc_object>, Main(Env &env) : _env(env) { + /* register final handler after initially synchronous block I/O */ _block.sigh(_io_sigh); /* announce at parent */ @@ -326,10 +337,7 @@ class Block::Main : Rpc_object>, throw Service_denied(); } - try { - _partition_table.partition(num); - } - catch (...) { + if (!_partition_table.partition_valid(num)) { error("Partition ", num, " unavailable for '", label, "'"); throw Service_denied(); } @@ -360,7 +368,7 @@ class Block::Main : Rpc_object>, Session::Info info { .block_size = _block.info().block_size, - .block_count = _partition_table.partition(num).sectors, + .block_count = _partition_table.partition_sectors(num), .align_log2 = 0, .writeable = writeable, }; @@ -405,7 +413,6 @@ class Block::Main : Rpc_object>, void completed(Job &job, bool success) { job.request.success = success; - job.completed = true; } @@ -417,10 +424,9 @@ class Block::Main : Rpc_object>, 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; addr_t index = 0; @@ -431,7 +437,7 @@ class Block::Main : Rpc_object>, _job_queue.with_job(index, [&](Job_object &job) { 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); }); @@ -457,7 +463,7 @@ class Block::Main : Rpc_object>, void acknowledge_completed(bool all = true, long number = -1) override { _job_registry.for_each([&] (Job &job) { - if (!job.completed) return; + if (!job.completed()) return; addr_t index = job.index; @@ -474,6 +480,17 @@ class Block::Main : Rpc_object>, _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_gpt = false; bool pmbr_found = false; + bool valid_ahdi = false; bool report = false; if (ignore_gpt && ignore_mbr) { @@ -505,22 +523,39 @@ Block::Partition_table & Block::Main::_table() 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 handler(_env.ep(), io_dummy, &Io_dummy::fn); + _block.sigh(handler); + /* * Try to parse MBR as well as GPT first if not instructued * to ignore either one of them. */ if (!ignore_mbr) { - try { valid_mbr = _mbr.parse(); } - catch (Mbr_partition_table::Protective_mbr_found) { + using Parse_result = Mbr::Parse_result; + + switch (_mbr.parse()) { + case Parse_result::MBR: + valid_mbr = true; + break; + case Parse_result::PROTECTIVE_MBR: pmbr_found = true; - } catch (...) { }; + break; + case Parse_result::NO_MBR: + break; + } } - if (!ignore_gpt) { - try { valid_gpt = _gpt.parse(); } - catch (...) { } - } + if (!ignore_gpt) + valid_gpt = _gpt.parse(); + + valid_ahdi = _ahdi.parse(); /* * 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"); } - /* PMBR missing, i.e, MBR part[0] contains whole disk and GPT valid */ if (pmbr_found && ignore_gpt) { 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 */ - if (_reporter.constructed()) + if (_reporter.constructed()) { _reporter->generate([&] (Xml_generator &xml) { - if (valid_gpt) _gpt.generate_report(xml); - if (valid_mbr) _mbr.generate_report(xml); + table.generate_report(xml); }); + } - /* - * 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(); + return table; } void Component::construct(Genode::Env &env) { static Block::Main main(env); } diff --git a/repos/os/src/server/part_block/mbr.h b/repos/os/src/server/part_block/mbr.h index 2998c1983d..b7ce3edf81 100644 --- a/repos/os/src/server/part_block/mbr.h +++ b/repos/os/src/server/part_block/mbr.h @@ -4,6 +4,7 @@ * \author Stefan Kalkowski * \author Josef Soentgen * \author Norman Feske + * \author Christian Helmuth * \date 2013-12-04 */ @@ -17,29 +18,37 @@ #ifndef _PART_BLOCK__MBR_H_ #define _PART_BLOCK__MBR_H_ -#include -#include -#include -#include - #include "partition_table.h" -#include "fsprobe.h" -#include "ahdi.h" 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: - class Protective_mbr_found { }; + enum class Parse_result { MBR, PROTECTIVE_MBR, NO_MBR }; private: - typedef Block::Partition_table::Sector Sector; - /** * Partition table entry format */ @@ -74,16 +83,16 @@ struct Block::Mbr_partition_table : public Block::Partition_table /** * Master/Extented boot record format */ - struct Mbr : Mmio + struct Boot_record : Mmio { struct Magic : Register<510, 16> { enum { NUMBER = 0xaa55 }; }; - Mbr() = delete; + Boot_record() = delete; - Mbr(addr_t base) : Mmio(base) { } + Boot_record(addr_t base) : Mmio(base) { } bool valid() const { @@ -97,11 +106,9 @@ struct Block::Mbr_partition_table : public Block::Partition_table } }; - enum { MAX_PARTITIONS = 32 }; - /* contains pointers to valid partitions or 0 */ - Constructible _part_list[MAX_PARTITIONS]; + Constructible _part_list[MAX_PARTITIONS]; template 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 */ int nr = 5; do { - Sector s(const_cast(data), lba, 1); - Mbr const ebr(s.addr()); + Sync_read s(_handler, _alloc, lba, 1); + if (!s.success()) + return; + Boot_record const ebr(s.addr()); if (!ebr.valid()) return; @@ -140,7 +149,7 @@ struct Block::Mbr_partition_table : public Block::Partition_table } template - 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++) { Partition_record const r(mbr.record(i)); @@ -149,32 +158,15 @@ struct Block::Mbr_partition_table : public Block::Partition_table continue; if (r.protective()) - throw Protective_mbr_found(); + return Parse_result::PROTECTIVE_MBR; f(i + 1, r, 0); if (r.extended()) _parse_extended(r, f); } - } - /* state for partitions report */ - 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]; + return Parse_result::MBR; } template @@ -185,96 +177,78 @@ struct Block::Mbr_partition_table : public Block::Partition_table fn(i); }; - bool parse() override - { - block.sigh(io_sigh); + public: - 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 */ - Mbr const mbr(s.addr()); - _mbr_valid = mbr.valid(); - if (_mbr_valid) { - _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)); + Boot_record const mbr(s.addr()); + if (!mbr.valid()) + return Parse_result::NO_MBR; - 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 */ - enum { PROBE_BYTES = 4096, }; - Sector fs(data, lba , PROBE_BYTES / block.info().block_size); - Fs::Type const fs_type = - Fs::probe(fs.addr(), PROBE_BYTES); + log("MBR Partition ", nr, ": LBA ", + r.lba() + offset, " (", + r.sectors(), " blocks) type: ", + Hex(r.type(), Hex::OMIT_PREFIX)); + }); + } - _part_list[i].construct( - Partition(lba, r.sectors(), fs_type, r.type())); - } - }); - } + bool partition_valid(long num) const override + { + /* 1-based partition number to 0-based array index */ + num -= 1; - /* check for AHDI partition table */ - _ahdi_valid = !_mbr_valid && Ahdi::valid(s); - 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)); - }); + if (num < 0 || num >= MAX_PARTITIONS) + return false; - /* no partition table, use whole disc as partition 0 */ - if (!_mbr_valid && !_ahdi_valid) - _part_list[0].construct( - Partition(0, (block_count_t)(block.info().block_count - 1), - Fs::Type(), 0)); + return _part_list[num].constructed(); + } - bool any_partition_valid = false; - _for_each_valid_partition([&] (unsigned) { - any_partition_valid = true; }); + block_number_t partition_lba(long num) const override + { + 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 { 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); + xml.attribute("number", i + 1); xml.attribute("start", part.lba); xml.attribute("length", part.sectors); - xml.attribute("block_size", block_size); - - if (_mbr_valid) - xml.attribute("type", part.mbr_type); - else if (_ahdi_valid) - xml.attribute("type", "bgm"); + 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", _mbr_valid ? "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 { + xml.attribute("type", "mbr"); + _for_each_valid_partition([&] (unsigned i) { xml.node("partition", [&] { - gen_partition_attr(xml, 0); }); - } + gen_partition_attr(xml, i); }); }); } }; diff --git a/repos/os/src/server/part_block/partition_table.h b/repos/os/src/server/part_block/partition_table.h index 7b1e1cecf6..3a1190465a 100644 --- a/repos/os/src/server/part_block/partition_table.h +++ b/repos/os/src/server/part_block/partition_table.h @@ -2,6 +2,7 @@ * \brief Partition table definitions * \author Sebastian Sumpf * \author Stefan Kalkowski + * \author Christian Helmuth * \date 2013-12-04 */ @@ -15,193 +16,59 @@ #ifndef _PART_BLOCK__PARTITION_TABLE_H_ #define _PART_BLOCK__PARTITION_TABLE_H_ -#include -#include -#include -#include -#include - +#include "block.h" #include "fsprobe.h" +#include "types.h" namespace Block { struct Partition; class Partition_table; - struct Job; - using namespace Genode; - typedef Block::Connection Block_connection; } -struct Block::Partition +struct Block::Partition : Noncopyable { - block_number_t lba; /* logical block address on device */ - block_count_t sectors; /* number of sectors in patitions */ + block_number_t const lba; /* logical block address on device */ + block_number_t const sectors; /* number of sectors in partitions */ 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, - block_count_t sectors, - Fs::Type fs_type, - uint8_t mbr_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) - { } + block_number_t sectors, + Fs::Type fs_type) + : lba(lba), sectors(sectors), fs_type(fs_type) { } }; -struct Block::Job : public Block_connection::Job +class Block::Partition_table : Interface, Noncopyable { - Registry::Element registry_element; + protected: - addr_t const index; /* job index */ - long const number; /* parition number */ - Request request; - addr_t const addr; /* target payload address */ - bool completed { false }; + Sync_read::Handler &_handler; + Allocator &_alloc; + Session::Info const _info; - Job(Block_connection &connection, - Operation operation, - Registry ®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 + Fs::Type _fs_type(block_number_t lba) { - Env &env; - Block_connection █ - Allocator &alloc; - Sector *current = nullptr; - - Sector_data(Env &env, Block_connection &block, Allocator &alloc) - : env(env), block(block), alloc(alloc) { } - }; - - /** - * 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 T addr() const { - return reinterpret_cast(_buffer); } - }; - - Env &env; - Block_connection █ - Sector_data data; - - Io_signal_handler io_sigh { - env.ep(), *this, &Partition_table::handle_io }; - - void handle_io() - { - if (data.current) { data.current->handle_io(); } + /* probe for known file-system types */ + enum { BYTES = 4096 }; + Sync_read fs(_handler, _alloc, lba, BYTES / _info.block_size); + if (fs.success()) + return Fs::probe(fs.addr(), BYTES); + else + return Fs::Type(); } - Partition_table(Env &env, - Block_connection &block, - Allocator &alloc) - : env(env), block(block), data(env, block, alloc) - { } + public: - 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; }; diff --git a/repos/os/src/server/part_block/types.h b/repos/os/src/server/part_block/types.h new file mode 100644 index 0000000000..a88c815855 --- /dev/null +++ b/repos/os/src/server/part_block/types.h @@ -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 +#include +#include +#include +#include +#include +#include + +namespace Block { + using namespace Genode; + + struct Job; + typedef Block::Connection Block_connection; +} + +#endif /* _PART_BLOCK__TYPES_H_ */