mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 15:32:25 +00:00
part_block: support for AHDI partition scheme
This patch enhances part_block with support for parsing the AHDI partition scheme, and the detection of the GEMDOS variant of FAT as used by Atari TOS. As a side effect of the implementation, the patch improves the MBR parsing code by avoiding pointers and using const qualifiers. Fixes #3470
This commit is contained in:
parent
23c2606ce0
commit
ceae637416
98
repos/os/src/server/part_block/ahdi.h
Normal file
98
repos/os/src/server/part_block/ahdi.h
Normal file
@ -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<Root_sector const *>();
|
||||
for (unsigned i = 0; i < MAX_PARTITIONS; i++)
|
||||
if (root.partitions[i].valid())
|
||||
any_partition_valid = true;
|
||||
|
||||
return any_partition_valid;
|
||||
}
|
||||
|
||||
template <typename FN>
|
||||
static void for_each_partition(Sector const §or, FN const &fn)
|
||||
{
|
||||
Root_sector &root = *sector.addr<Root_sector *>();
|
||||
|
||||
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_ */
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 <typename FUNC>
|
||||
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 *>();
|
||||
Mbr const &ebr = *s.addr<Mbr *>();
|
||||
|
||||
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 <typename FUNC>
|
||||
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 <typename FN>
|
||||
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<Mbr *>();
|
||||
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<Mbr *>();
|
||||
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<uint8_t*>(), 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<Genode::uint8_t*>(), 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<Genode::uint8_t*>(), 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -67,7 +67,7 @@ struct Block::Partition_table : Genode::Interface
|
||||
|
||||
~Sector() { _session.tx()->release_packet(_p); }
|
||||
|
||||
template <typename T> T addr() {
|
||||
template <typename T> T addr() const {
|
||||
return reinterpret_cast<T>(_session.tx()->packet_content(_p)); }
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user