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 0000000000..88eabdb7e9
Binary files /dev/null and b/repos/os/recipes/raw/test-part_block_ahdi/ata.ahdi.raw.tar.gz differ
diff --git a/repos/os/recipes/raw/test-part_block_ahdi/content.mk b/repos/os/recipes/raw/test-part_block_ahdi/content.mk
new file mode 100644
index 0000000000..97a171bb6d
--- /dev/null
+++ b/repos/os/recipes/raw/test-part_block_ahdi/content.mk
@@ -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
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 b63836a0f4..725610f3ce 100644
Binary files a/repos/os/recipes/raw/test-part_block_mbr/ata.mbr.raw.tar.gz and b/repos/os/recipes/raw/test-part_block_mbr/ata.mbr.raw.tar.gz differ
diff --git a/repos/os/src/server/part_block/README b/repos/os/src/server/part_block/README
index a925726b18..b19fe4d487 100644
--- a/repos/os/src/server/part_block/README
+++ b/repos/os/src/server/part_block/README
@@ -50,6 +50,10 @@ looks like follows (for MBR resp. GPT).
Clients have read-only access to partitions unless overriden by a 'writeable'
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
-----
@@ -71,7 +75,7 @@ Configuration snippet with two clients and an (hypothetical) IDE driver:
!
!
+! 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_ */