21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/Spinlock.h"
24#include "pedigree/kernel/machine/Disk.h"
25#include "pedigree/kernel/utilities/StaticString.h"
26#include "pedigree/kernel/utilities/String.h"
27#include "pedigree/kernel/utilities/utility.h"
35static const char* g_pPartitionTypes[256] = {
"Empty",
293static int gNextPartition = 0;
295static bool extended(uint8_t type) {
296 return type == 5 || type == 0x0f || type == 0x85;
299static bool sectorRange(
Disk* disk, uint64_t start, uint64_t count) {
301 const uint64_t sectors = sectorBytes ? disk->
getSize() / sectorBytes : 0;
302 return count && start < sectors && count <= sectors - start;
305static void registerPartition(
const MsdosPartitionInfo& entry,
Disk* disk, uint64_t start) {
306 const uint64_t count = LITTLE_TO_HOST32(entry.size);
307 if (!sectorRange(disk, start, count) || !start) {
308 WARNING(
"MS-DOS: partition outside disk");
314 number = gNextPartition++;
319 label += g_pPartitionTypes[entry.type];
321 auto* partition =
new Partition(
String(label), start * bytes, count * bytes);
322 partition->setParent(disk);
326static bool readEntries(
Disk* disk, uint64_t lba, MsdosPartitionInfo* entries) {
327 if (!sectorRange(disk, lba, 1))
333 const bool valid = view.size() >= 512 && view[510] == MSDOS_IDENT_1 && view[511] == MSDOS_IDENT_2;
335 MemoryCopy(entries, view.as<uint8_t>(MSDOS_PARTTAB_START),
sizeof(MsdosPartitionInfo) * 4);
340static void readExtended(
Disk* disk, uint64_t base, uint64_t count) {
341 if (!sectorRange(disk, base, count) || !base)
343 uint64_t visited[128];
345 uint64_t current = base;
346 while (depth < 128) {
347 for (
size_t i = 0; i < depth; ++i)
348 if (visited[i] == current)
350 visited[depth++] = current;
351 MsdosPartitionInfo entries[4];
352 if (!readEntries(disk, current, entries))
354 const auto& data = entries[0];
355 const uint64_t start = current + LITTLE_TO_HOST32(data.start_lba);
356 const uint64_t length = LITTLE_TO_HOST32(data.size);
357 if ((data.active == 0 || data.active == 0x80) && data.type && !extended(data.type) &&
358 data.type != 0xee && start > current && start >= base && start < base + count &&
359 length <= base + count - start)
360 registerPartition(data, disk, start);
361 const auto& link = entries[1];
362 if (!extended(link.type) || (link.active != 0 && link.active != 0x80))
364 const uint64_t relative = LITTLE_TO_HOST32(link.start_lba);
365 if (!relative || relative >= count)
367 current = base + relative;
369 WARNING(
"MS-DOS: extended partition chain exceeds 128 records");
372bool msdosReadTable(MsdosPartitionInfo* entries,
Disk* disk) {
374 for (
size_t i = 0; i < 4; ++i)
375 if (entries[i].type == 0xee)
377 for (
size_t i = 0; i < 4; ++i) {
378 const auto& entry = entries[i];
379 if (entry.active != 0 && entry.active != 0x80)
381 const uint64_t start = LITTLE_TO_HOST32(entry.start_lba);
382 if (extended(entry.type))
383 readExtended(disk, start, LITTLE_TO_HOST32(entry.size));
385 registerPartition(entry, disk, start);
390bool msdosProbeDisk(
Disk* disk) {
392 if (bytes < 512 || bytes > 4096 || (bytes & (bytes - 1)))
394 MsdosPartitionInfo entries[4];
395 return readEntries(disk, 0, entries) && msdosReadTable(entries, disk);
void addChild(Device *pDevice)
virtual BufferView read(uint64_t location)
virtual size_t getSize() const
Gets the size of the disk.
virtual void unpin(uint64_t location)=0
virtual size_t getNativeBlockSize() const