From 40a0fe934916608935d82113077194128d4effda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Thu, 3 May 2018 15:34:08 +0200 Subject: [PATCH] part_blk: add minimal file system probing For now it is enough to differentiate the most commonly used file system on Genode, e.g. Ext2 for the Genode partition and FAT32 for (U)EFI partitions. Issue #2803. --- repos/os/src/server/part_blk/fsprobe.h | 104 +++++++++++++++++++++++++ repos/os/src/server/part_blk/gpt.h | 8 ++ repos/os/src/server/part_blk/mbr.h | 10 +++ 3 files changed, 122 insertions(+) create mode 100644 repos/os/src/server/part_blk/fsprobe.h diff --git a/repos/os/src/server/part_blk/fsprobe.h b/repos/os/src/server/part_blk/fsprobe.h new file mode 100644 index 0000000000..11de3af6f8 --- /dev/null +++ b/repos/os/src/server/part_blk/fsprobe.h @@ -0,0 +1,104 @@ +/* + * \brief Poor man's partition probe for known file system + * \author Josef Soentgen + * \date 2018-05-03 + */ + +/* + * Copyright (C) 2018 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_BLK__FSPROBE_H_ +#define _PART_BLK__FSPROBE_H_ + +/* Genode includes */ +#include +#include + +namespace Fs { + + using namespace Genode; + + using Type = Genode::String<32>; + + 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; + + bool const found_ext_sig = p[0x38] == 0x53 && p[0x39] == 0xEF; + + enum { + COMPAT_HAS_JOURNAL = 0x004u, + INCOMPAT_EXTENTS = 0x040u, + RO_COMPAT_METADATA_CSUM = 0x400u, + }; + + 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); + + /* the feature flags should denote a given Ext version */ + + bool const ext3 = compat & COMPAT_HAS_JOURNAL; + bool const ext4 = ext3 && ((incompat & INCOMPAT_EXTENTS) + && (ro_compat & RO_COMPAT_METADATA_CSUM)); + + if (found_ext_sig && ext4) { return Type("Ext4"); } + else if (found_ext_sig && ext3) { return Type("Ext3"); } + else if (found_ext_sig) { return Type("Ext2"); } + + return Type(); + } + + /** + * Probe for FAT16/32 + */ + Type _probe_fatfs(uint8_t *p, size_t len) + { + if (len < 512) { return Type(); } + + /* at least the checks ring true when mkfs.vfat is used... */ + + bool const found_boot_sig = p[510] == 0x55 && p[511] == 0xAA; + + bool const fat16 = p[38] == 0x28 || p[38] == 0x29; + bool const fat32 = (p[66] == 0x28 || p[66] == 0x29) + && (p[82] == 'F' && p[83] == 'A'); + + if (found_boot_sig && fat32) { return Type("FAT32"); } + if (found_boot_sig && fat16) { return Type("FAT16"); } + + return Type(); + } +} + + +Fs::Type Fs::probe(uint8_t *p, size_t len) +{ + /* Ext2/3/4 */ + { + Type t = _probe_extfs(p, len); + if (t.valid()) { return t; } + } + + /* FAT16/32 */ + { + Type t = _probe_fatfs(p, len); + if (t.valid()) { return t; } + } + + return Type(); +} + +#endif /* _PART_BLK__FSPROBE_H_ */ diff --git a/repos/os/src/server/part_blk/gpt.h b/repos/os/src/server/part_blk/gpt.h index 63c5a8044f..38b0f576a5 100644 --- a/repos/os/src/server/part_blk/gpt.h +++ b/repos/os/src/server/part_blk/gpt.h @@ -20,6 +20,7 @@ #include "driver.h" #include "partition_table.h" +#include "fsprobe.h" namespace { @@ -265,6 +266,10 @@ class Gpt : public Block::Partition_table continue; } + enum { BYTES = 4096, }; + Sector fs(driver, e->_lba_start, BYTES / driver.blk_size()); + Fs::Type fs_type = Fs::probe(fs.addr(), BYTES); + xml.node("partition", [&] () { xml.attribute("number", i + 1); xml.attribute("name", e->name()); @@ -272,6 +277,9 @@ class Gpt : public Block::Partition_table xml.attribute("guid", e->_guid.to_string()); xml.attribute("start", e->_lba_start); xml.attribute("length", e->_lba_end - e->_lba_start + 1); + if (fs_type.valid()) { + xml.attribute("file_system", fs_type); + } }); } }); diff --git a/repos/os/src/server/part_blk/mbr.h b/repos/os/src/server/part_blk/mbr.h index 1cf8cb7968..a867057708 100644 --- a/repos/os/src/server/part_blk/mbr.h +++ b/repos/os/src/server/part_blk/mbr.h @@ -21,6 +21,7 @@ #include #include "partition_table.h" +#include "fsprobe.h" struct Mbr_partition_table : public Block::Partition_table @@ -165,11 +166,20 @@ struct Mbr_partition_table : public Block::Partition_table xml.attribute("type", "mbr"); _parse_mbr(mbr, [&] (int i, Partition_record *r, unsigned offset) { + + enum { BYTES = 4096, }; + Sector fs(driver, r->_lba + offset, BYTES / driver.blk_size()); + Fs::Type fs_type = Fs::probe(fs.addr(), BYTES); + xml.node("partition", [&] { xml.attribute("number", i); xml.attribute("type", r->_type); xml.attribute("start", r->_lba + offset); xml.attribute("length", r->_sectors); + + if (fs_type.valid()) { + xml.attribute("file_system", fs_type); + } }); }); });