github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/zimage/zimage.go (about) 1 // Copyright 2019 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 zimage contains a Parser for the arm zImage Linux format. It assumes 6 // little endian arm. 7 package zimage 8 9 import ( 10 "encoding/binary" 11 "fmt" 12 "io" 13 ) 14 15 // Magic values used in the zImage header and table. 16 const ( 17 Magic = 0x016f2818 18 Endianess = 0x04030201 19 TableMagic = 0x45454545 20 ) 21 22 // Tags used by TableEntry (at the time of writing, there is only one tag). 23 const ( 24 TagKernelSize Tag = 0x5a534c4b 25 ) 26 27 // Tag is used to identify a TableEntry. 28 type Tag uint32 29 30 // ZImage is one of the major formats used by Linux on ARM. This struct 31 // is only for storing the metadata. 32 type ZImage struct { 33 Header Header 34 Table []TableEntry 35 } 36 37 // Header appears near the beginning of the zImage. 38 // 39 // The layout is defined in Linux: 40 // arch/arm/boot/compressed/head.S 41 type Header struct { 42 Magic uint32 43 Start uint32 44 End uint32 45 Endianess uint32 46 TableMagic uint32 47 TableAddr uint32 48 } 49 50 // TableEntry is an extension to Header. A zImage may have 0 or more entries. 51 // 52 // The layout is defined in Linux: 53 // arch/arm/boot/compressed/vmlinux.lds.S 54 type TableEntry struct { 55 Tag Tag 56 Data []uint32 57 } 58 59 // Parse a ZImage from a file. 60 func Parse(f io.ReadSeeker) (*ZImage, error) { 61 // Parse the header. 62 if _, err := f.Seek(0x24, io.SeekStart); err != nil { 63 return nil, err 64 } 65 z := &ZImage{} 66 if err := binary.Read(f, binary.LittleEndian, &z.Header); err != nil { 67 return nil, err 68 } 69 if z.Header.Magic != Magic { 70 return z, fmt.Errorf("invalid zImage magic, got %#08x, expected %#08x", 71 z.Header.Magic, Magic) 72 } 73 if z.Header.Endianess != Endianess { 74 return z, fmt.Errorf("unsupported zImage endianess, expected little") 75 } 76 if z.Header.End < z.Header.Start { 77 return z, fmt.Errorf("invalid zImage, end is less than start, %d < %d", 78 z.Header.End, z.Header.Start) 79 } 80 81 if z.Header.TableMagic != TableMagic { 82 // No table. 83 return z, nil 84 } 85 86 // Parse the table. 87 addr := z.Header.TableAddr 88 for addr != 0 { 89 if _, err := f.Seek(int64(addr), io.SeekStart); err != nil { 90 return nil, err 91 } 92 var size uint32 93 if err := binary.Read(f, binary.LittleEndian, &size); err != nil { 94 return nil, err 95 } 96 entry := TableEntry{Data: make([]uint32, size)} 97 if err := binary.Read(f, binary.LittleEndian, &entry.Tag); err != nil { 98 return nil, err 99 } 100 if err := binary.Read(f, binary.LittleEndian, &entry.Data); err != nil { 101 return nil, err 102 } 103 z.Table = append(z.Table, entry) 104 105 // In its current form, the Linux source code does not make it 106 // super clear how multiple entries are specified in the table. Is 107 // it a zero-terminated array? Is it a linked-list? Is it similar 108 // to atags? See Linux commit c77256. Regardless, the kernel 109 // currently only has one entry, so we exit after one iteration. 110 addr = 0 111 } 112 return z, nil 113 } 114 115 // GetEntry searches through the zImage table for the given tag. 116 func (z *ZImage) GetEntry(t Tag) (*TableEntry, error) { 117 for i := range z.Table { 118 if z.Table[i].Tag == t { 119 return &z.Table[i], nil 120 } 121 } 122 return nil, fmt.Errorf("zImage table does not contain the %#08x tag", t) 123 } 124 125 // GetKernelSizes returns two kernel sizes relevant for kexec. 126 func (z *ZImage) GetKernelSizes() (piggySizeAddr uint32, kernelBSSSize uint32, err error) { 127 e, err := z.GetEntry(TagKernelSize) 128 if err != nil { 129 return 0, 0, err 130 } 131 if len(e.Data) != 2 { 132 return 0, 0, fmt.Errorf("zImage tag %#08x has incorrect size %d, expected 2", 133 TagKernelSize, len(e.Data)) 134 } 135 return e.Data[0], e.Data[1], nil 136 }