gpt partition table parsing

This commit is contained in:
nakst 2021-09-15 13:50:23 +01:00
parent d005957fc5
commit dad8952e87
9 changed files with 116 additions and 12 deletions

View File

@ -78,8 +78,10 @@ run_kernel64:
mov rcx,[rbx + 24]
; Map the first MB at 0xFFFFFE0000000000 --> 0xFFFFFE0000100000
mov rax,[0xFFFFFF7FBFDFE000]
mov [0xFFFFFF7FBFDFEFE0],rax
mov rdi,0xFFFFFF7FBFDFE000
mov rax,[rdi]
mov rdi,0xFFFFFF7FBFDFEFE0
mov [rdi],rax
mov rax,cr3
mov cr3,rax

View File

@ -1882,7 +1882,6 @@ struct EsFontInformation {
struct EsBlockDeviceInformation {
size_t sectorSize;
EsFileOffset sectorCount;
bool noMBR;
bool readOnly;
uint8_t nestLevel;
uint8_t driveType;

View File

@ -488,7 +488,6 @@ static void DeviceAttach(KDevice *parent) {
}
}
volume->rootDirectory->driverNode = volume->root;
volume->directoryEntryDataBytes = sizeof(DirectoryEntryReference);
volume->nodeDataBytes = sizeof(FSNode);

View File

@ -90,7 +90,7 @@ struct ElfSectionHeader {
uint64_t entrySize;
};
struct ElfProgramHeader{
struct ElfProgramHeader {
uint32_t type; // 0 = unused, 1 = load, 2 = dynamic, 3 = interp, 4 = note
uint32_t flags; // 1 = executable, 2 = writable, 4 = readable
uint64_t fileOffset;

View File

@ -1679,7 +1679,8 @@ void FSPartitionDeviceAccess(KBlockDeviceAccessRequest request) {
FSBlockDeviceAccess(request);
}
void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *model, size_t modelBytes) {
void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, uint32_t flags, const char *model, size_t modelBytes) {
(void) flags;
PartitionDevice *child = (PartitionDevice *) KDeviceCreate("Partition", parent, sizeof(PartitionDevice));
if (!child) return;
@ -1691,7 +1692,6 @@ void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOf
child->maxAccessSectorCount = parent->maxAccessSectorCount;
child->sectorOffset = offset;
child->information.sectorCount = sectorCount;
child->information.noMBR = flags & FS_PARTITION_DEVICE_NO_MBR ? true : false;
child->information.readOnly = parent->information.readOnly;
child->access = FSPartitionDeviceAccess;
child->information.modelBytes = modelBytes;
@ -1739,7 +1739,26 @@ bool FSCheckMBR(KBlockDevice *device) {
if (partitions[i].present) {
KernelLog(LOG_INFO, "FS", "MBR partition", "Found MBR partition %d with offset %d and count %d.\n",
i, partitions[i].offset, partitions[i].count);
FSPartitionDeviceCreate(device, partitions[i].offset, partitions[i].count, FS_PARTITION_DEVICE_NO_MBR, EsLiteral("MBR partition"));
FSPartitionDeviceCreate(device, partitions[i].offset, partitions[i].count, ES_FLAGS_DEFAULT, EsLiteral("MBR partition"));
}
}
return true;
} else {
return false;
}
}
bool FSCheckGPT(KBlockDevice *device) {
GPTPartition *partitions = (GPTPartition *) EsHeapAllocate(sizeof(GPTPartition) * GPT_PARTITION_COUNT, false, K_FIXED);
EsDefer(EsHeapFree(partitions, sizeof(GPTPartition) * GPT_PARTITION_COUNT, K_FIXED));
if (GPTGetPartitions(device->signatureBlock, device->information.sectorCount, device->information.sectorSize, partitions)) {
for (uintptr_t i = 0; i < GPT_PARTITION_COUNT; i++) {
if (partitions[i].present) {
KernelLog(LOG_INFO, "FS", "GPT partition", "Found GPT partition %d with offset %d and count %d%z.\n",
i, partitions[i].offset, partitions[i].count, partitions[i].isESP ? "; this is the ESP" : "");
FSPartitionDeviceCreate(device, partitions[i].offset, partitions[i].count, ES_FLAGS_DEFAULT, EsLiteral("GPT partition"));
}
}
@ -1809,7 +1828,9 @@ void FSDetectFileSystem(KBlockDevice *device) {
// We could not access the block device.
KernelLog(LOG_ERROR, "FS", "detect fileSystem read failure", "The signature block could not be read on block device %x.\n", device);
} else {
if (!device->information.noMBR && FSCheckMBR(device)) {
if (!device->information.nestLevel && FSCheckGPT(device)) {
// Found a GPT.
} else if (!device->information.nestLevel && FSCheckMBR(device)) {
// Found an MBR.
} else {
KDeviceAttach(device, "Files", FSSignatureCheck);

View File

@ -640,8 +640,7 @@ struct KBlockDevice : KDevice {
KMutex detectFileSystemMutex;
};
#define FS_PARTITION_DEVICE_NO_MBR (1 << 0)
void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *name, size_t nameBytes);
void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, uint32_t flags, const char *name, size_t nameBytes);
// ---------------------------------------------------------------------------------------------------------------
// PCI.

View File

@ -1,9 +1,13 @@
#ifndef K_SIGNATURE_BLOCK_SIZE
#define K_SIGNATURE_BLOCK_SIZE (65536)
#endif
typedef struct MBRPartition {
uint32_t offset, count;
bool present;
} MBRPartition;
bool MBRGetPartitions(uint8_t *firstBlock, EsFileOffset sectorCount, MBRPartition *partitions) {
bool MBRGetPartitions(uint8_t *firstBlock, EsFileOffset sectorCount, MBRPartition *partitions /* 4 */) {
if (firstBlock[510] != 0x55 || firstBlock[511] != 0xAA) {
return false;
}
@ -53,3 +57,76 @@ void MBRFixPartition(uint32_t *partitions) {
partitions[0] |= (partitionOffsetHead << 8) | (partitionOffsetSector << 16) | (partitionOffsetCylinder << 24) | ((partitionOffsetCylinder >> 8) << 16);
partitions[1] |= (partitionSizeHead << 8) | (partitionSizeSector << 16) | (partitionSizeCylinder << 24) | ((partitionSizeCylinder >> 8) << 16);
}
#define GPT_PARTITION_COUNT (0x80)
typedef struct GPTPartition {
uint64_t offset, count;
bool present, isESP;
} GPTPartition;
bool GPTGetPartitions(uint8_t *block /* K_SIGNATURE_BLOCK_SIZE */, EsFileOffset sectorCount,
EsFileOffset sectorBytes, GPTPartition *partitions /* GPT_PARTITION_COUNT */) {
for (uintptr_t i = 0; i < GPT_PARTITION_COUNT; i++) {
partitions[i].present = false;
}
if (sectorBytes * 2 >= K_SIGNATURE_BLOCK_SIZE || sectorCount <= 2 || sectorBytes < 0x200) {
return false;
}
const char *signature = "EFI PART";
for (uintptr_t i = 0; i < 8; i++) {
if (block[sectorBytes + i] != signature[i]) {
return false;
}
}
uint32_t partitionEntryCount = *(uint32_t *) (block + sectorBytes + 80);
uint32_t partitionEntryBytes = *(uint32_t *) (block + sectorBytes + 84);
if (partitionEntryBytes < 0x80 || partitionEntryBytes > sectorBytes || sectorBytes % partitionEntryBytes
|| partitionEntryCount == 0 || partitionEntryBytes > 0x1000 || partitionEntryCount > 0x1000
|| partitionEntryBytes * partitionEntryCount / sectorBytes + 2 >= sectorCount) {
return false;
}
if (partitionEntryCount > GPT_PARTITION_COUNT) {
partitionEntryCount = GPT_PARTITION_COUNT;
}
bool foundESP = false;
for (uintptr_t i = 0; i < partitionEntryCount; i++) {
uint8_t *entry = block + sectorBytes * 2 + i * partitionEntryBytes;
uint64_t guidLow = *(uint64_t *) (entry + 0);
uint64_t guidHigh = *(uint64_t *) (entry + 8);
uint64_t firstLBA = *(uint64_t *) (entry + 32);
uint64_t lastLBA = *(uint64_t *) (entry + 40);
if (!guidLow && !guidHigh) {
continue;
}
if ((!guidLow && !guidHigh) || firstLBA >= sectorCount || lastLBA >= sectorCount || firstLBA >= lastLBA) {
return false;
}
partitions[i].present = true;
partitions[i].offset = firstLBA;
partitions[i].count = lastLBA - firstLBA;
partitions[i].isESP = guidLow == 0x11D2F81FC12A7328 && guidHigh == 0x3BC93EC9A0004BBA;
if (partitions[i].isESP) {
if (foundESP) {
return false;
} else {
foundESP = true;
}
}
}
return true;
}

View File

@ -1051,6 +1051,8 @@ void BuildBootloader(Application *application) {
ExecuteForApp(application, toolchainNasm, "-MD", "bin/boot3.d", "-fbin",
"boot/x86/loader.s", "-obin/stage2",
"-Pboot/x86/esfs-stage2.s", (forEmulator && !bootUseVBE) ? "" : "-D BOOT_USE_VBE");
ExecuteForApp(application, toolchainNasm, "-MD", "bin/boot4.d", "-fbin",
"boot/x86/uefi_loader.s", "-obin/uefi_loader");
}
File _drive;
@ -1098,6 +1100,10 @@ void Install(const char *driveFile, uint64_t partitionSize, const char *partitio
installationIdentifier.d[i] = rand();
}
File iid = FileOpen("bin/iid.dat", 'w');
FileWrite(iid, 16, &installationIdentifier);
FileClose(iid);
File f = FileOpen(driveFile, 'w');
File mbr = FileOpen("bin/mbr", 'r');
@ -1446,6 +1452,7 @@ int main(int argc, char **argv) {
ADD_DEPENDENCY_FILE(application, "bin/boot1.d", "Boot1");
ADD_DEPENDENCY_FILE(application, "bin/boot2.d", "Boot2");
ADD_DEPENDENCY_FILE(application, "bin/boot3.d", "Boot3");
ADD_DEPENDENCY_FILE(application, "bin/boot4.d", "Boot4");
arrput(applications, application);
}