blob: fa823593c57179426b3f06835b5836cfc7b1b7fc [file] [log] [blame]
package gpt
import (
"encoding/binary"
"fmt"
"io"
"math"
)
// See UEFI Specification 2.9 Table 5-3
type mbr struct {
BootCode [440]byte
DiskSignature [4]byte
_ [2]byte
PartitionRecords [4]mbrPartitionRecord
Signature [2]byte
}
// See UEFI Specification 2.9 Table 5-4
type mbrPartitionRecord struct {
BootIndicator byte
StartingCHS [3]byte
Type byte
EndingCHS [3]byte
StartingBlock uint32
SizeInBlocks uint32
}
var mbrSignature = [2]byte{0x55, 0xaa}
func makeProtectiveMBR(w io.Writer, blockCount int64, bootCode []byte) error {
var representedBlockCount = uint32(math.MaxUint32)
if blockCount < math.MaxUint32 {
representedBlockCount = uint32(blockCount)
}
m := mbr{
DiskSignature: [4]byte{0, 0, 0, 0},
PartitionRecords: [4]mbrPartitionRecord{
{
StartingCHS: toCHS(1),
Type: 0xEE, // Table/Protective MBR
StartingBlock: 1,
SizeInBlocks: representedBlockCount - 1,
EndingCHS: toCHS(blockCount + 1),
},
{},
{},
{},
},
Signature: mbrSignature,
}
if len(bootCode) > len(m.BootCode) {
return fmt.Errorf("BootCode is %d bytes, can only store %d", len(bootCode), len(m.BootCode))
}
copy(m.BootCode[:], bootCode)
if err := binary.Write(w, binary.LittleEndian, &m); err != nil {
return fmt.Errorf("failed to write MBR: %w", err)
}
return nil
}
// toCHS converts a LBA to a "logical" CHS, i.e. what a legacy BIOS 13h
// interface would use. This has nothing to do with the actual CHS geometry
// which depends on the disk and interface used.
func toCHS(lba int64) (chs [3]byte) {
const maxCylinders = (1 << 10) - 1
const maxHeadsPerCylinder = (1 << 8) - 1
const maxSectorsPerTrack = (1 << 6) - 2 // Sector is 1-based
cylinder := lba / (maxHeadsPerCylinder * maxSectorsPerTrack)
head := (lba / maxSectorsPerTrack) % maxHeadsPerCylinder
sector := (lba % maxSectorsPerTrack) + 1
if cylinder > maxCylinders {
cylinder = maxCylinders
head = maxHeadsPerCylinder
sector = maxSectorsPerTrack + 1
}
chs[0] = uint8(head)
chs[1] = uint8(sector)
chs[1] |= uint8(cylinder>>2) & 0xc0
chs[2] = uint8(cylinder)
return
}