Newer
Older
vvd / src / fs / mbr.c
@dd86k dd86k on 9 Nov 2019 3 KB INIT
#include <stdio.h>
#include <stdint.h>
#include "mbr.h"
#include "gpt.h"
#include "../vdisk.h"

// Maps CHS geometry to an LBA (sector index)
// LBA = (C × HPC + H) × SPT + (S − 1)
// HPC	Max heads per cylinders, typically 16 (28-bit LBA)
// SPT	Max sectors per strack, typically 63 (28-bit LBA)
uint32_t mbr_lba(CHS_ENTRY *chs) {
	uint8_t sector = chs->sector & 0x3F;
	uint16_t cylinder = chs->cylinder | ((chs->sector & 0xC0) << 2);
	return (cylinder * 16 * chs->head) * 63 + (sector - 1);
}

// LBA-ASSISTED TRANSLATION for disks under 8032.5 MiB
// SIZE (MiB)	S/T	H	C
// < 504	63	16	63 * H * 512
// 504-1008	63	32	63 * H * 512
// 1008-2016	63	64	63 * H * 512
// 2016-4032	63	128	63 * H * 512
// 4032-8032.5	63	255	63 * H * 512
uint32_t mbr_lba_a(CHS_ENTRY *chs, uint64_t bsize) {
	uint8_t H;
	if (bsize <= 0x1F800000) // 504 MiB
		H = 16;
	else if (bsize <= 0x3F000000) // 1008 MiB
		H = 32;
	else if (bsize <= 0x7E000000) // 2016 MiB
		H = 64;
	else if (bsize <= 0xFC000000) // 4032 MiB
		H = 128;
	else if (bsize <= 0x1F6080000ULL) // 8032.5 MiB
		H = 255;
	else
		H = 16; //TODO: Verify H when >8.5G
	
	uint8_t sector = chs->sector & 0x3F;
	uint16_t cylinder = chs->cylinder | ((chs->sector & 0xC0) << 2);
	return (cylinder * H * chs->head) * 63 + (sector - 1);
}

// Checks for MBR signature
int mbr_check(MBR *mbr) {
	return mbr->sig == MBR_SIG;
}

// And also checks GPT automatically
void mbr_info_auto(VDISK *vd) {
	MBR mbr;
	if (vdisk_read_lba(vd, &mbr, 0)) return;
	if (mbr_check(&mbr) == 0) return;
	mbr_info(&mbr);
	// EFI GPT Protective or EFI System Partition
	if (mbr.pe1.partition < 0xEE || mbr.pe1.partition > 0xEF)
		return;
	if (vdisk_read_lba(vd, &mbr, 1)) return;
	if (gpt_check((GPT *)&mbr)) {
		gpt_info((GPT *)&mbr);
		gpt_list_pe_vd(vd, (GPT *)&mbr);
	}
}

void mbr_info(MBR *mbr) {
	char size[BIN_FLENGTH];
	uint64_t dtsize = SECTOR_TO_BYTE(
		(uint64_t)mbr->pe1.sectors + (uint64_t)mbr->pe2.sectors +
		(uint64_t)mbr->pe3.sectors + (uint64_t)mbr->pe4.sectors
	);
	fbins(dtsize, size);
	printf(
	"\n* MBR, SERIAL %08X, USED %s, TYPE %04u\n"
	"PARTITIONS  STATUS  TYPE        LBA       SIZE  C:H:S->C:H:S\n"
	"ENTRY 1       %3XH  %3XH  %9u  %9u  %u:%u:%u->%u:%u:%u\n"
	"ENTRY 2       %3XH  %3XH  %9u  %9u  %u:%u:%u->%u:%u:%u\n"
	"ENTRY 3       %3XH  %3XH  %9u  %9u  %u:%u:%u->%u:%u:%u\n"
	"ENTRY 4       %3XH  %3XH  %9u  %9u  %u:%u:%u->%u:%u:%u\n"
	,
	mbr->serial, size, mbr->type,
	// PE 1
	mbr->pe1.status,
	mbr->pe1.partition,
	mbr->pe1.lba,
	mbr->pe1.sectors,
	mbr->pe1.chsfirst.cylinder |
	((mbr->pe1.chsfirst.sector & 0xC0) << 2),
	mbr->pe1.chsfirst.head,
	mbr->pe1.chsfirst.sector & 0x3F,
	mbr->pe1.chslast.cylinder |
	((mbr->pe1.chslast.sector & 0xC0) << 2),
	mbr->pe1.chslast.head,
	mbr->pe1.chslast.sector & 0x3F,
	// PE 2
	mbr->pe2.status,
	mbr->pe2.partition,
	mbr->pe2.lba,
	mbr->pe2.sectors,
	mbr->pe2.chsfirst.cylinder |
	((mbr->pe2.chsfirst.sector & 0xC0) << 2),
	mbr->pe2.chsfirst.head,
	mbr->pe2.chsfirst.sector & 0x3F,
	mbr->pe2.chslast.cylinder |
	((mbr->pe2.chslast.sector & 0xC0) << 2),
	mbr->pe2.chslast.head,
	mbr->pe2.chslast.sector & 0x3F,
	// PE 3
	mbr->pe3.status,
	mbr->pe3.partition,
	mbr->pe3.lba,
	mbr->pe3.sectors,
	mbr->pe3.chsfirst.cylinder |
	((mbr->pe3.chsfirst.sector & 0xC0) << 2),
	mbr->pe3.chsfirst.head,
	mbr->pe3.chsfirst.sector & 0x3F,
	mbr->pe3.chslast.cylinder |
	((mbr->pe3.chslast.sector & 0xC0) << 2),
	mbr->pe3.chslast.head,
	mbr->pe3.chslast.sector & 0x3F,
	// PE 4
	mbr->pe4.status,
	mbr->pe4.partition,
	mbr->pe4.lba,
	mbr->pe4.sectors,
	mbr->pe4.chsfirst.cylinder |
	((mbr->pe4.chsfirst.sector & 0xC0) << 2),
	mbr->pe4.chsfirst.head,
	mbr->pe4.chsfirst.sector & 0x3F,
	mbr->pe4.chslast.cylinder |
	((mbr->pe4.chslast.sector & 0xC0) << 2),
	mbr->pe4.chslast.head,
	mbr->pe4.chslast.sector & 0x3F
	);
}