github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/zbi/zbi.go (about) 1 // Copyright 2022 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package zbi contains a parser for the Zircon boot image format. 6 package zbi 7 8 import ( 9 "encoding/binary" 10 "fmt" 11 "io" 12 "os" 13 14 "github.com/mvdan/u-root-coreutils/pkg/align" 15 ) 16 17 const ( 18 // ContainerMagic is Zircon image header extra magic. 19 ContainerMagic uint32 = 0x868cf7e6 20 // ItemMagic is Ziron image format magic. 21 ItemMagic uint32 = 0xb5781729 22 // VersionFlag is a default version flag that can be used when bootstrapping a Zircon image header. 23 VersionFlag uint32 = 0x00010000 24 // CRC32Flag is a flag to indicate performing CRC32 check. 25 CRC32Flag uint32 = 0x00020000 26 // NoCRC32Flag is a flag to indicate not performing CRC32 check. 27 NoCRC32Flag uint32 = 0x4a87e8d6 28 // ZBITypeKernelPrefix is kernel prefix. 29 ZBITypeKernelPrefix uint32 = 0x004e524b // KRN\0 30 // ZBITypeKernelMask is mask to extract kernel prefix bits. 31 ZBITypeKernelMask uint32 = 0x00FFFFFF // Mask to compare to the prefix. 32 ) 33 34 // ZBITypeMetadata describes a ZBI type. 35 type ZBITypeMetadata struct { 36 Name string 37 Extention string 38 } 39 40 // ZBIType is a uint32. 41 type ZBIType uint32 42 43 const ( 44 // ZBITypeContainer represents BOOT type. 45 ZBITypeContainer ZBIType = 0x544f4f42 46 // ZBITypeKernelX64 represents KRNL type, a x86 kernel. 47 ZBITypeKernelX64 ZBIType = 0x4c4e524b // KRNL 48 // ZBITypeKernelArm64 represents KRN8 type, an Arm64 kernel. 49 ZBITypeKernelArm64 ZBIType = 0x384e524b // KRN8 50 // ZBITypeDiscard represents SKIP type. 51 ZBITypeDiscard ZBIType = 0x50494b53 52 // ZBITypeStorageRamdisk represents RDSK type. 53 ZBITypeStorageRamdisk ZBIType = 0x4b534452 54 // ZBITypeStorageBootfs represents BFSB type. 55 ZBITypeStorageBootfs ZBIType = 0x42534642 56 // ZBITypeStorageKernel represents KSTR type. 57 ZBITypeStorageKernel ZBIType = 0x5254534b 58 // ZBITypeStorageBootfsFactory represents BFSF ty 59 ZBITypeStorageBootfsFactory ZBIType = 0x46534642 60 // ZBITypeCmdline represents CMDL type. 61 ZBITypeCmdline ZBIType = 0x4c444d43 62 // ZBITypeCrashlog represents BOOM type. 63 ZBITypeCrashlog ZBIType = 0x4d4f4f42 64 // ZBITypeNvram represents NVLL type. 65 ZBITypeNvram ZBIType = 0x4c4c564e 66 // ZBITypePlatformID represents PLID type. 67 ZBITypePlatformID ZBIType = 0x44494C50 68 // ZBITypeDrvBoardInfo represents mBSI type. 69 ZBITypeDrvBoardInfo ZBIType = 0x4953426D 70 // ZBITypeCPUConfig represents CPUC type. 71 ZBITypeCPUConfig ZBIType = 0x43555043 72 // ZBITypeCPUTopology represents TOPO type. 73 ZBITypeCPUTopology ZBIType = 0x544F504F 74 // ZBITypeMemConfig represents MEMC type. 75 ZBITypeMemConfig ZBIType = 0x434D454D 76 // ZBITypeKernelDriver represents KDRV type. 77 ZBITypeKernelDriver ZBIType = 0x5652444B 78 // ZBITypeAcpiRsdp represents RSDP type. 79 ZBITypeAcpiRsdp ZBIType = 0x50445352 80 // ZBITypeSMBios represents SMBI type. 81 ZBITypeSMBios ZBIType = 0x49424d53 82 // ZBITypeEFISystemTable represents EFIS type. 83 ZBITypeEFISystemTable ZBIType = 0x53494645 84 // ZBITypeFramebuffer represents SWFB type. 85 ZBITypeFramebuffer ZBIType = 0x42465753 86 // ZBITypeImageArgs represents IARG type. 87 ZBITypeImageArgs ZBIType = 0x47524149 88 // ZBITypeBootVersion represents BVRS type. 89 ZBITypeBootVersion ZBIType = 0x53525642 90 // ZBITypeDrvMacAddress represents mMAC type. 91 ZBITypeDrvMacAddress ZBIType = 0x43414D6D 92 // ZBITypeDrvPartitionMap represents mPRT type. 93 ZBITypeDrvPartitionMap ZBIType = 0x5452506D 94 // ZBITypeDrvBoardPrivate represents mBOR type. 95 ZBITypeDrvBoardPrivate ZBIType = 0x524F426D 96 // ZBITypeHwRebootReason represents HWRB type. 97 ZBITypeHwRebootReason ZBIType = 0x42525748 98 // ZBITypeSerialNumber represents SRLN type. 99 ZBITypeSerialNumber ZBIType = 0x4e4c5253 100 // ZBITypeBootloaderFile represents BTFL type. 101 ZBITypeBootloaderFile ZBIType = 0x4C465442 102 // ZBITypeDevicetree represents device tree type. 103 ZBITypeDevicetree ZBIType = 0xd00dfeed 104 // ZBITypeSecureEntropy represents RAND type. 105 ZBITypeSecureEntropy ZBIType = 0x444e4152 106 ) 107 108 var ( 109 // ZBITypes is a ZBIType to ZBITypeMetadata mapping. 110 ZBITypes = map[ZBIType]ZBITypeMetadata{ 111 ZBITypeContainer: {Name: "CONTAINER", Extention: ".bin"}, 112 ZBITypeKernelX64: {Name: "KERNEL_X64", Extention: ".bin"}, 113 ZBITypeKernelArm64: {Name: "KERNEL_ARM64", Extention: ".bin"}, 114 ZBITypeDiscard: {Name: "DISCARD", Extention: ".bin"}, 115 ZBITypeStorageKernel: {Name: "KERNEL", Extention: ".bin"}, 116 ZBITypeStorageRamdisk: {Name: "RAMDISK", Extention: ".bin"}, 117 ZBITypeStorageBootfs: {Name: "BOOTFS", Extention: ".bin"}, 118 ZBITypeStorageBootfsFactory: {Name: "BOOTFS_FACTORY", Extention: ".bin"}, 119 ZBITypeCmdline: {Name: "CMDLINE", Extention: ".txt"}, 120 ZBITypeCrashlog: {Name: "CRASHLOG", Extention: ".bin"}, 121 ZBITypeNvram: {Name: "NVRAM", Extention: ".bin"}, 122 ZBITypePlatformID: {Name: "PLATFORM_ID", Extention: ".bin"}, 123 ZBITypeCPUConfig: {Name: "CPU_CONFIG", Extention: ".bin"}, 124 ZBITypeCPUTopology: {Name: "CPU_TOPOLOGY", Extention: ".bin"}, 125 ZBITypeMemConfig: {Name: "MEM_CONFIG", Extention: ".bin"}, 126 ZBITypeKernelDriver: {Name: "KERNEL_DRIVER", Extention: ".bin"}, 127 ZBITypeAcpiRsdp: {Name: "ACPI_RSDP", Extention: ".bin"}, 128 ZBITypeSMBios: {Name: "SMBIOS", Extention: ".bin"}, 129 ZBITypeEFISystemTable: {Name: "EFI_SYSTEM_TABLE", Extention: ".bin"}, 130 ZBITypeFramebuffer: {Name: "FRAMEBUFFER", Extention: ".bin"}, 131 ZBITypeImageArgs: {Name: "IMAGE_ARGS", Extention: ".txt"}, 132 ZBITypeBootVersion: {Name: "BOOT_VERSION", Extention: ".bin"}, 133 ZBITypeDrvBoardInfo: {Name: "DRV_BOARD_INFO", Extention: ".bin"}, 134 ZBITypeDrvMacAddress: {Name: "DRV_MAC_ADDRESS", Extention: ".bin"}, 135 ZBITypeDrvPartitionMap: {Name: "DRV_PARTITION_MAP", Extention: ""}, 136 ZBITypeDrvBoardPrivate: {Name: "DRV_BOARD_PRIVATE", Extention: ""}, 137 ZBITypeHwRebootReason: {Name: "HW_REBOOT_REASON", Extention: ".bin"}, 138 ZBITypeSerialNumber: {Name: "SERIAL_NUMBER", Extention: ".txt"}, 139 ZBITypeBootloaderFile: {Name: "BOOTLOADER_FILE", Extention: ".bin"}, 140 ZBITypeDevicetree: {Name: "DEVICETREE", Extention: ".dtb"}, 141 ZBITypeSecureEntropy: {Name: "ENTROPY", Extention: ".bin"}, 142 } 143 ) 144 145 // IsKernel tells if current ZBIType is kernel. 146 func (it *ZBIType) IsKernel() bool { 147 return uint32(*it)&ZBITypeKernelMask == ZBITypeKernelPrefix 148 } 149 150 // IsDriverMetadata tells if current ZBIType contains driver meta data. 151 func (it *ZBIType) IsDriverMetadata() bool { 152 return *it&0xFF == 0x6D // 'm' 153 } 154 155 // ToString return string representation of current ZBIType. 156 func (it *ZBIType) ToString() (string, error) { 157 if typeMetadata, ok := ZBITypes[*it]; ok { 158 return typeMetadata.Name, nil 159 } 160 return "", fmt.Errorf("Can't find metadata for %#08x ZBIType", it) 161 } 162 163 // MarshalJSON returns JSON bytes of current ZBIType. 164 func (it *ZBIType) MarshalJSON() ([]byte, error) { 165 name, err := it.ToString() 166 if err != nil { 167 return nil, err 168 } 169 nameWithQuotes := fmt.Sprintf("%q", name) 170 return []byte(nameWithQuotes), nil 171 } 172 173 // Header abstracts a Zircon image header. 174 type Header struct { 175 Type ZBIType 176 Length uint32 177 Extra uint32 178 Flags uint32 179 Reserved0 uint32 180 Reserved1 uint32 181 Magic uint32 182 CRC32 uint32 183 } 184 185 // BootItem abstracts a bootable item. 186 type BootItem struct { 187 Header Header 188 PayloadAddress uint64 189 } 190 191 // NewContainerHeader returns a new image header with given image length. 192 func NewContainerHeader(length uint32) Header { 193 return Header{ 194 Type: ZBITypeContainer, 195 Length: length, 196 Extra: ContainerMagic, 197 Flags: VersionFlag, 198 Reserved0: 0, 199 Reserved1: 0, 200 Magic: ItemMagic, 201 CRC32: NoCRC32Flag, 202 } 203 } 204 205 // Image abstracts a Zircon image. 206 type Image struct { 207 Header Header 208 BootItems []BootItem 209 Bootable bool 210 } 211 212 func (i *Image) isBootable() bool { 213 if len(i.BootItems) == 0 { 214 return false 215 } 216 return i.BootItems[0].Header.Type.IsKernel() 217 } 218 219 func (i *Image) readContainerHeader(f io.ReadSeeker) error { 220 header := &i.Header 221 if _, err := f.Seek(0, io.SeekStart); err != nil { 222 return err 223 } 224 225 if err := binary.Read(f, binary.LittleEndian, header); err != nil { 226 return err 227 } 228 229 if header.Type != ZBITypeContainer { 230 return fmt.Errorf("invalid header type, expected %#08x, got %#08x", ZBITypeContainer, header.Type) 231 } 232 233 if header.Magic != ItemMagic { 234 return fmt.Errorf("invalid item magic, expected %#08x, got %#08x", ItemMagic, header.Magic) 235 } 236 237 if header.Extra != ContainerMagic { 238 return fmt.Errorf("invalid container magic, expected %#08x, got %#08x", ContainerMagic, header.Extra) 239 } 240 241 return nil 242 } 243 244 // ZBIKernel abstracts an in-memory kernel entry. 245 type ZBIKernel struct { 246 Entry uint64 247 ReserveMemorySize uint64 248 } 249 250 // ZirconKernel is the whole contiguous image loaded into memory by the boot loader. 251 type ZirconKernel struct { 252 HdrFile Header 253 HdrKernel Header 254 DataKernel ZBIKernel 255 contents []uint8 256 } 257 258 func (i *Image) readBootItems(f io.ReadSeeker) error { 259 for { 260 item := BootItem{} 261 if err := readHeader(f, &item.Header); err != nil { 262 if err == io.EOF { 263 return nil 264 } 265 return err 266 } 267 position, err := f.Seek(0, io.SeekCurrent) 268 if err != nil { 269 return err 270 } 271 item.PayloadAddress = uint64(position) 272 i.BootItems = append(i.BootItems, item) 273 274 padding := align.Up(uint(item.Header.Length), 8) 275 f.Seek(int64(padding), io.SeekCurrent) 276 } 277 } 278 279 // Read parses a Ziron Image from an io.ReadSeeker. 280 func Read(f io.ReadSeeker) (*Image, error) { 281 image := &Image{} 282 if err := image.readContainerHeader(f); err != nil { 283 return nil, err 284 } 285 if err := image.readBootItems(f); err != nil { 286 return nil, err 287 } 288 image.Bootable = image.isBootable() 289 return image, nil 290 } 291 292 // Load loads an Image from given path. 293 func Load(imagePath string) (*Image, error) { 294 imageFile, err := os.Open(imagePath) 295 defer imageFile.Close() 296 297 if err != nil { 298 return nil, fmt.Errorf("load ZBI image failed: %w", err) 299 } 300 301 image, err := Read(imageFile) 302 if err != nil { 303 return nil, fmt.Errorf("reading ZBI image failed: %w", err) 304 } 305 return image, nil 306 } 307 308 func readHeader(f io.ReadSeeker, h *Header) error { 309 if err := binary.Read(f, binary.LittleEndian, h); err != nil { 310 return err 311 } 312 return nil 313 }