diff --git a/repos/os/src/server/part_block/ahdi.h b/repos/os/src/server/part_block/ahdi.h new file mode 100644 index 0000000000..abc0b4a040 --- /dev/null +++ b/repos/os/src/server/part_block/ahdi.h @@ -0,0 +1,98 @@ +/* + * \brief Atari ST partition scheme (AHDI) + * \author Norman Feske + * \date 2019-08-09 + */ + +/* + * Copyright (C) 2019 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__AHDI_H_ +#define _PART_BLOCK__AHDI_H_ + +#include "partition_table.h" + + +struct Ahdi +{ + typedef Block::Partition_table::Sector Sector; + + typedef Genode::uint32_t uint32_t; + typedef Genode::uint8_t uint8_t; + + /** + * 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); } + + } __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 + { + using Genode::Char; + return Id(Char(_id0), Char(_id1), Char(_id2)); + } + + bool bootable() const { return _flags & 1; } + + bool valid() const { return id() == "BGM" && start.value() > 0; } + + } __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())); + } + } +}; + +#endif /* _PART_BLOCK__AHDI_H_ */ diff --git a/repos/os/src/server/part_block/fsprobe.h b/repos/os/src/server/part_block/fsprobe.h index 09587c1373..354129b8e7 100644 --- a/repos/os/src/server/part_block/fsprobe.h +++ b/repos/os/src/server/part_block/fsprobe.h @@ -69,15 +69,16 @@ namespace Fs { if (len < 512) { return Type(); } /* at least the checks ring true when mkfs.vfat is used... */ - bool const found_boot_sig = p[510] == 0x55 && p[511] == 0xAA; - bool const fat16 = p[38] == 0x28 || p[38] == 0x29; - bool const fat32 = (p[66] == 0x28 || p[66] == 0x29) - && (p[82] == 'F' && p[83] == 'A'); + 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 (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/main.cc b/repos/os/src/server/part_block/main.cc index 933eae1fda..bc0f311cbc 100644 --- a/repos/os/src/server/part_block/main.cc +++ b/repos/os/src/server/part_block/main.cc @@ -67,18 +67,16 @@ Block::Partition_table & Main::_table() { using namespace Genode; + Xml_node const config = _config.xml(); + + bool const ignore_gpt = config.attribute_value("ignore_gpt", false); + bool const ignore_mbr = config.attribute_value("ignore_mbr", false); + bool valid_mbr = false; bool valid_gpt = false; - bool ignore_gpt = false; - bool ignore_mbr = false; bool pmbr_found = false; bool report = false; - try { - ignore_gpt = _config.xml().attribute_value("ignore_gpt", false); - ignore_mbr = _config.xml().attribute_value("ignore_mbr", false); - } catch(...) {} - if (ignore_gpt && ignore_mbr) { error("invalid configuration: cannot ignore GPT as well as MBR"); throw Invalid_config(); diff --git a/repos/os/src/server/part_block/mbr.h b/repos/os/src/server/part_block/mbr.h index 8c39d88784..3fa2e22ce6 100644 --- a/repos/os/src/server/part_block/mbr.h +++ b/repos/os/src/server/part_block/mbr.h @@ -3,6 +3,7 @@ * \author Sebastian Sumpf * \author Stefan Kalkowski * \author Josef Soentgen + * \author Norman Feske * \date 2013-12-04 */ @@ -22,6 +23,7 @@ #include "partition_table.h" #include "fsprobe.h" +#include "ahdi.h" struct Mbr_partition_table : public Block::Partition_table @@ -49,10 +51,10 @@ struct Mbr_partition_table : public Block::Partition_table Genode::uint32_t _lba; /* logical block address */ Genode::uint32_t _sectors; /* number of sectors */ - bool valid() { return _type != INVALID; } - bool extended() { return _type == EXTENTED_CHS - || _type == EXTENTED_LBA; } - bool protective() { return _type == PROTECTIVE; } + bool valid() const { return _type != INVALID; } + bool extended() const { return _type == EXTENTED_CHS + || _type == EXTENTED_LBA; } + bool protective() const { return _type == PROTECTIVE; } } __attribute__((packed)); @@ -65,7 +67,7 @@ struct Mbr_partition_table : public Block::Partition_table Partition_record _records[4]; Genode::uint16_t _magic; - bool valid() + bool valid() const { /* magic number of partition table */ enum { MAGIC = 0xaa55 }; @@ -76,13 +78,13 @@ struct Mbr_partition_table : public Block::Partition_table enum { MAX_PARTITIONS = 32 }; - Block::Partition *_part_list[MAX_PARTITIONS]; /* contains pointers to valid - partitions or 0 */ + /* contains pointers to valid partitions or 0 */ + Block::Partition *_part_list[MAX_PARTITIONS]; template - void _parse_extended(Partition_record *record, FUNC const &f) + void _parse_extended(Partition_record const &record, FUNC const &f) const { - Partition_record *r = record; + Partition_record const *r = &record; unsigned lba = r->_lba; unsigned last_lba = 0; @@ -90,15 +92,15 @@ struct Mbr_partition_table : public Block::Partition_table int nr = 5; do { Sector s(driver, lba, 1); - Mbr *ebr = s.addr(); + Mbr const &ebr = *s.addr(); - if (!(ebr->valid())) + if (!ebr.valid()) return; /* The first record is the actual logical partition. The lba of this * partition is relative to the lba of the current EBR */ - Partition_record *logical = &(ebr->_records[0]); - if (logical->valid() && nr < MAX_PARTITIONS) { + Partition_record const &logical = ebr._records[0]; + if (logical.valid() && nr < MAX_PARTITIONS) { f(nr++, logical, lba); } @@ -106,32 +108,30 @@ struct Mbr_partition_table : public Block::Partition_table * the second record points to the next EBR * (relative form this EBR) */ - r = &(ebr->_records[1]); - lba += ebr->_records[1]._lba - last_lba; + r = &(ebr._records[1]); + lba += ebr._records[1]._lba - last_lba; - last_lba = ebr->_records[1]._lba; + last_lba = ebr._records[1]._lba; } while (r->valid()); } template - void _parse_mbr(Mbr *mbr, FUNC const &f) + void _parse_mbr(Mbr const &mbr, FUNC const &f) const { - for (int i = 0; i < 4; i++) { - Partition_record *r = &(mbr->_records[i]); + Partition_record const &r = mbr._records[i]; - if (!r->valid()) + if (!r.valid()) continue; - if (r->protective()) + if (r.protective()) throw Protective_mbr_found(); f(i + 1, r, 0); - if (r->extended()) { + if (r.extended()) _parse_extended(r, f); - } } } @@ -142,83 +142,109 @@ struct Mbr_partition_table : public Block::Partition_table Block::Partition *partition(int num) override { return (num < MAX_PARTITIONS) ? _part_list[num] : 0; } + template + void _for_each_valid_partition(FN const &fn) const + { + for (unsigned i = 0; i < MAX_PARTITIONS; i++) + if (_part_list[i]) + fn(i); + }; + bool parse() override { - Sector s(driver, 0, 1); - Mbr *mbr = s.addr(); + using namespace Genode; - /* no partition table, use whole disc as partition 0 */ - bool const mbr_valid = mbr->valid(); - if (!mbr_valid) { - _part_list[0] = new (&heap) - Block::Partition(0, driver.blk_cnt() - 1); - } else { - _parse_mbr(mbr, [&] (int i, Partition_record *r, unsigned offset) { - Genode::log("Partition ", i, ": LBA ", - (unsigned int) r->_lba + offset, " (", - (unsigned int) r->_sectors, " blocks) type: ", - Genode::Hex(r->_type, Genode::Hex::OMIT_PREFIX)); - if (!r->extended()) - _part_list[i] = new (&heap) - Block::Partition(r->_lba + offset, r->_sectors); + Sector s(driver, 0, 1); + + /* check for MBR */ + Mbr const &mbr = *s.addr(); + bool const mbr_valid = mbr.valid(); + if (mbr_valid) { + _parse_mbr(mbr, [&] (int i, Partition_record const &r, unsigned offset) { + log("Partition ", i, ": LBA ", + (unsigned int) r._lba + offset, " (", + (unsigned int) r._sectors, " blocks) type: ", + Hex(r._type, Hex::OMIT_PREFIX)); + if (!r.extended()) + _part_list[i] = new (heap) + Block::Partition(r._lba + offset, r._sectors); }); } - /* Report the partitions */ + /* check for AHDI partition table */ + bool const ahdi_valid = !mbr_valid && Ahdi::valid(s); + if (ahdi_valid) + Ahdi::for_each_partition(s, [&] (unsigned i, Block::Partition info) { + if (i < MAX_PARTITIONS) + _part_list[i] = new (heap) + Block::Partition(info.lba, info.sectors); }); + + /* no partition table, use whole disc as partition 0 */ + if (!mbr_valid && !ahdi_valid) + _part_list[0] = new (&heap) + Block::Partition(0, driver.blk_cnt() - 1); + + /* report the partitions */ if (reporter.enabled()) { - enum { PROBE_BYTES = 4096, }; - Genode::size_t const block_size = driver.blk_size(); + auto gen_partition_attr = [&] (Xml_generator &xml, unsigned i) + { + Block::Partition const &part = *_part_list[i]; - Genode::Reporter::Xml_generator xml(reporter, [&] () { + size_t const block_size = driver.blk_size(); + + xml.attribute("number", i); + xml.attribute("start", part.lba); + xml.attribute("length", part.sectors); + xml.attribute("block_size", block_size); + + /* probe for known file-system types */ + enum { PROBE_BYTES = 4096, }; + Sector fs(driver, part.lba, PROBE_BYTES / block_size); + Fs::Type const fs_type = + Fs::probe(fs.addr(), PROBE_BYTES); + + if (fs_type.valid()) + xml.attribute("file_system", fs_type); + }; + + Reporter::Xml_generator xml(reporter, [&] () { + + xml.attribute("type", mbr_valid ? "mbr" : + ahdi_valid ? "ahdi" : + "disk"); if (mbr_valid) { - xml.attribute("type", "mbr"); + _parse_mbr(mbr, [&] (int i, Partition_record const &r, unsigned) { - _parse_mbr(mbr, [&] (int i, Partition_record *r, unsigned offset) { - - Sector fs(driver, r->_lba + offset, PROBE_BYTES / block_size); - Fs::Type fs_type = Fs::probe(fs.addr(), PROBE_BYTES); + /* nullptr if extended */ + if (!_part_list[i]) + return; xml.node("partition", [&] { - xml.attribute("number", i); - xml.attribute("type", r->_type); - xml.attribute("start", r->_lba + offset); - xml.attribute("length", r->_sectors); - xml.attribute("block_size", driver.blk_size()); - - if (fs_type.valid()) { - xml.attribute("file_system", fs_type); - } - }); + gen_partition_attr(xml, i); + xml.attribute("type", r._type); }); }); + + } else if (ahdi_valid) { + _for_each_valid_partition([&] (unsigned i) { + xml.node("partition", [&] { + gen_partition_attr(xml, i); + xml.attribute("type", "bgm"); }); }); + } else { - xml.attribute("type", "disk"); - - enum { PART_NUM = 0, }; - Block::Partition const &disk = *_part_list[PART_NUM]; - - Sector fs(driver, disk.lba, PROBE_BYTES / block_size); - Fs::Type fs_type = Fs::probe(fs.addr(), PROBE_BYTES); xml.node("partition", [&] { - xml.attribute("number", PART_NUM); - xml.attribute("start", disk.lba); - xml.attribute("length", disk.sectors + 1); - xml.attribute("block_size", driver.blk_size()); - - if (fs_type.valid()) { - xml.attribute("file_system", fs_type); - } - }); + gen_partition_attr(xml, 0); }); } }); } - for (unsigned num = 0; num < MAX_PARTITIONS; num++) - if (_part_list[num]) - return true; - return false; + bool any_partition_valid = false; + _for_each_valid_partition([&] (unsigned) { + any_partition_valid = true; }); + + return any_partition_valid; } }; diff --git a/repos/os/src/server/part_block/partition_table.h b/repos/os/src/server/part_block/partition_table.h index bd01cc9041..94d9ce02ad 100644 --- a/repos/os/src/server/part_block/partition_table.h +++ b/repos/os/src/server/part_block/partition_table.h @@ -67,7 +67,7 @@ struct Block::Partition_table : Genode::Interface ~Sector() { _session.tx()->release_packet(_p); } - template T addr() { + template T addr() const { return reinterpret_cast(_session.tx()->packet_content(_p)); } };