feat: support for USB mass storage devices, hotplugging
This commit is contained in:
@@ -62,6 +62,18 @@ namespace Drivers::Storage::Gpt {
|
||||
a.Data4[6] == b.Data4[6] && a.Data4[7] == b.Data4[7];
|
||||
}
|
||||
|
||||
static int FindExistingPartition(int blockDevIndex, uint64_t startLba, uint64_t endLba) {
|
||||
for (int i = 0; i < g_partitionCount; i++) {
|
||||
if (g_partitions[i].BlockDevIndex == blockDevIndex &&
|
||||
g_partitions[i].StartLba == startLba &&
|
||||
g_partitions[i].EndLba == endLba) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// UTF-16LE to ASCII narrowing
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -76,6 +88,53 @@ namespace Drivers::Storage::Gpt {
|
||||
dst[j] = '\0';
|
||||
}
|
||||
|
||||
static void CopyAsciiName(const char* src, char* dst, int dstMax) {
|
||||
int i = 0;
|
||||
for (; src && src[i] && i < dstMax - 1; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
static bool IsExtendedMbrType(uint8_t type) {
|
||||
return type == 0x05 || type == 0x0F || type == 0x85;
|
||||
}
|
||||
|
||||
static Guid GuidForMbrType(uint8_t type) {
|
||||
switch (type) {
|
||||
case 0x82:
|
||||
return GUID_LINUX_SWAP;
|
||||
case 0x83:
|
||||
return GUID_LINUX_FS;
|
||||
default:
|
||||
return GUID_BASIC_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int AppendMbrPartition(int blockDevIndex, uint64_t diskSectorCount,
|
||||
uint64_t startLba, uint64_t sectorCount,
|
||||
uint8_t type, const char* name) {
|
||||
if (sectorCount == 0 || g_partitionCount >= MaxPartitions) return 0;
|
||||
if (startLba >= diskSectorCount || sectorCount > diskSectorCount - startLba) return 0;
|
||||
|
||||
uint64_t endLba = startLba + sectorCount - 1;
|
||||
if (endLba < startLba) return 0;
|
||||
if (FindExistingPartition(blockDevIndex, startLba, endLba) >= 0) return 0;
|
||||
|
||||
PartitionInfo& part = g_partitions[g_partitionCount];
|
||||
part.BlockDevIndex = blockDevIndex;
|
||||
part.StartLba = startLba;
|
||||
part.EndLba = endLba;
|
||||
part.SectorCount = sectorCount;
|
||||
part.TypeGuid = GuidForMbrType(type);
|
||||
part.UniqueGuid = GUID_UNUSED;
|
||||
part.Attributes = 0;
|
||||
CopyAsciiName(name, part.Name, 72);
|
||||
|
||||
g_partitionCount++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Validate protective MBR
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -237,6 +296,7 @@ namespace Drivers::Storage::Gpt {
|
||||
if (GuidIsZero(entry->TypeGuid)) continue;
|
||||
if (entry->StartingLba == 0 || entry->EndingLba == 0) continue;
|
||||
if (entry->StartingLba > entry->EndingLba) continue;
|
||||
if (FindExistingPartition(blockDevIndex, entry->StartingLba, entry->EndingLba) >= 0) continue;
|
||||
|
||||
PartitionInfo& part = g_partitions[g_partitionCount];
|
||||
part.BlockDevIndex = blockDevIndex;
|
||||
@@ -258,6 +318,88 @@ namespace Drivers::Storage::Gpt {
|
||||
return found;
|
||||
}
|
||||
|
||||
static int ParseExtendedMbr(const BlockDevice* dev, int blockDevIndex,
|
||||
uint64_t extendedBase, int& logicalNumber) {
|
||||
int found = 0;
|
||||
uint64_t ebrLba = extendedBase;
|
||||
|
||||
for (int guard = 0; guard < 32 && g_partitionCount < MaxPartitions; guard++) {
|
||||
uint8_t ebr[512];
|
||||
if (!dev->ReadSectors(dev->Ctx, ebrLba, 1, ebr)) break;
|
||||
|
||||
const ProtectiveMbr* mbr = (const ProtectiveMbr*)ebr;
|
||||
if (mbr->Signature != 0xAA55) break;
|
||||
|
||||
const MbrPartitionEntry& logical = mbr->Partitions[0];
|
||||
if (logical.Type != 0 && logical.SectorCount != 0 &&
|
||||
!IsExtendedMbrType(logical.Type)) {
|
||||
char name[16] = {};
|
||||
name[0] = 'M'; name[1] = 'B'; name[2] = 'R';
|
||||
int n = logicalNumber++;
|
||||
name[3] = (char)('0' + ((n / 10) % 10));
|
||||
name[4] = (char)('0' + (n % 10));
|
||||
name[5] = '\0';
|
||||
|
||||
found += AppendMbrPartition(blockDevIndex,
|
||||
dev->SectorCount,
|
||||
ebrLba + logical.LbaFirst,
|
||||
logical.SectorCount,
|
||||
logical.Type,
|
||||
name);
|
||||
}
|
||||
|
||||
const MbrPartitionEntry& next = mbr->Partitions[1];
|
||||
if (next.Type == 0 || next.SectorCount == 0 || !IsExtendedMbrType(next.Type)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ebrLba = extendedBase + next.LbaFirst;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static int ParseMbrPartitions(const BlockDevice* dev, const uint8_t* sector0,
|
||||
int blockDevIndex) {
|
||||
const ProtectiveMbr* mbr = (const ProtectiveMbr*)sector0;
|
||||
if (mbr->Signature != 0xAA55) {
|
||||
KernelLogStream(INFO, "MBR") << "No partition table on device "
|
||||
<< blockDevIndex << " (LBA 0 signature absent)";
|
||||
return 0;
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
int logicalNumber = 5;
|
||||
|
||||
for (int i = 0; i < 4 && g_partitionCount < MaxPartitions; i++) {
|
||||
const MbrPartitionEntry& entry = mbr->Partitions[i];
|
||||
if (entry.Type == 0 || entry.SectorCount == 0) continue;
|
||||
|
||||
if (IsExtendedMbrType(entry.Type)) {
|
||||
found += ParseExtendedMbr(dev, blockDevIndex, entry.LbaFirst, logicalNumber);
|
||||
continue;
|
||||
}
|
||||
|
||||
char name[8] = {};
|
||||
name[0] = 'M'; name[1] = 'B'; name[2] = 'R';
|
||||
name[3] = (char)('1' + i);
|
||||
name[4] = '\0';
|
||||
|
||||
found += AppendMbrPartition(blockDevIndex, dev->SectorCount, entry.LbaFirst,
|
||||
entry.SectorCount, entry.Type, name);
|
||||
}
|
||||
|
||||
if (found > 0) {
|
||||
KernelLogStream(OK, "MBR") << "Found " << found
|
||||
<< " partition(s) on device " << blockDevIndex;
|
||||
} else {
|
||||
KernelLogStream(INFO, "MBR") << "Device " << blockDevIndex
|
||||
<< " has MBR signature but no partition entries";
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public API
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -281,12 +423,15 @@ namespace Drivers::Storage::Gpt {
|
||||
uint8_t sectorBuf[1024];
|
||||
|
||||
if (!dev->ReadSectors(dev->Ctx, 0, 2, sectorBuf)) {
|
||||
KernelLogStream(ERROR, "GPT") << "Failed to read LBA 0-1 from device "
|
||||
<< blockDevIndex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Validate protective MBR
|
||||
// Validate protective MBR. If this is a legacy-partitioned disk instead
|
||||
// of GPT, keep using the same partition registry for MBR entries.
|
||||
if (!ValidateProtectiveMbr(sectorBuf)) {
|
||||
return 0;
|
||||
return ParseMbrPartitions(dev, sectorBuf, blockDevIndex);
|
||||
}
|
||||
|
||||
// Validate primary GPT header (LBA 1)
|
||||
@@ -375,6 +520,36 @@ namespace Drivers::Storage::Gpt {
|
||||
return &g_partitions[index];
|
||||
}
|
||||
|
||||
int RemovePartitionsForBlockDevice(int blockDevIndex) {
|
||||
int removed = 0;
|
||||
int dst = 0;
|
||||
|
||||
for (int src = 0; src < g_partitionCount; src++) {
|
||||
if (g_partitions[src].BlockDevIndex == blockDevIndex) {
|
||||
removed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dst != src) {
|
||||
g_partitions[dst] = g_partitions[src];
|
||||
}
|
||||
dst++;
|
||||
}
|
||||
|
||||
for (int i = dst; i < g_partitionCount; i++) {
|
||||
g_partitions[i] = {};
|
||||
}
|
||||
|
||||
g_partitionCount = dst;
|
||||
|
||||
if (removed > 0) {
|
||||
KernelLogStream(INFO, "GPT") << "Removed " << removed
|
||||
<< " partition record(s) for device " << blockDevIndex;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ASCII to UTF-16LE for partition names
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user