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  }