1#!/usr/bin/awk -f 2#- 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright 2019 Ian Lepore <ian@freebsd.org> 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29BEGIN { 30 # Init global vars. 31 gBytesOut = 0; # How many output bytes we've written so far 32 gKernbase = 0; # Address of first byte of loaded kernel image 33 gStart = 0; # Address of _start symbol 34 gStartOff = 0; # Offset of _start symbol from start of image 35 gEnd = 0; # Address of _end symbol 36 gEndOff = 0; # Offset of _end symbol from start of image 37 38 # The type of header we're writing is set using -v hdrtype= on 39 # the command line, ensure we got a valid value for it. 40 if (hdrtype != "v7jump" && 41 hdrtype != "v8jump" && 42 hdrtype != "v8booti") { 43 print "arm_kernel_boothdr.awk: " \ 44 "missing or invalid '-v hdrtype=' argument" >"/dev/stderr" 45 gHdrType = "error_reported" 46 exit 1 47 } 48 49 gHdrType = hdrtype 50} 51 52function addr_to_offset(addr) { 53 # Turn an address into an offset from the start of the loaded image. 54 return addr % gKernbase 55} 56 57function hexstr_to_num(str) { 58 59 # Prepend a 0x onto the string, then coerce it to a number by doing 60 # arithmetic with it, which makes awk run it through strtod(), 61 # which handles hex numbers that have a 0x prefix. 62 63 return 0 + ("0x" str) 64} 65 66function write_le32(num) { 67 68 for (i = 0; i < 4; i++) { 69 printf("%c", num % 256); 70 num /= 256 71 } 72 gBytesOut += 4 73} 74 75function write_le64(num) { 76 77 for (i = 0; i < 8; i++) { 78 printf("%c", num % 256); 79 num /= 256 80 } 81 gBytesOut += 8 82} 83 84function write_padding() { 85 86 # Write enough padding bytes so that the header fills all the 87 # remaining space before the _start symbol. 88 89 while (gBytesOut++ < gStartOff) { 90 printf("%c", 0); 91 } 92} 93 94function write_v7jump() { 95 96 # Write the machine code for "b _start"... 97 # 0xea is armv7 "branch always" and the low 24 bits is the signed 98 # offset from the current PC, in words. We know the gStart offset 99 # is in the first 2mb, so it'll fit in 24 bits. 100 101 write_le32(hexstr_to_num("ea000000") + (gStartOff / 4) - 2) 102} 103 104function write_v8jump() { 105 106 # Write the machine code for "b _start"... 107 # 0x14 is armv8 "branch always" and the low 26 bits is the signed 108 # offset from the current PC, in words. We know the gStart offset 109 # is in the first 2mb, so it'll fit in 26 bits. 110 111 write_le32(hexstr_to_num("14000000") + (gStartOff / 4)) 112} 113 114function write_v8booti() { 115 116 # We are writing this struct... 117 # 118 # struct Image_header { 119 # uint32_t code0; /* Executable code */ 120 # uint32_t code1; /* Executable code */ 121 # uint64_t text_offset; /* Image load offset, LE */ 122 # uint64_t image_size; /* Effective Image size, LE */ 123 # uint64_t flags; /* Kernel flags, LE */ 124 # uint64_t res1[3]; /* reserved */ 125 # uint32_t magic; /* Magic number */ 126 # uint32_t res2; 127 # }; 128 # 129 # We write 'b _start' into code0. The image size is everything from 130 # the start of the loaded image to the offset given by the _end symbol. 131 132 write_v8jump() # code0 133 write_le32(0) # code1 134 write_le64(0) # text_offset 135 write_le64(gEndOff) # image_size 136 write_le64(hexstr_to_num("8")) # flags 137 write_le64(0) # res1[0] 138 write_le64(0) # res1[1] 139 write_le64(0) # res1[2] 140 write_le32(hexstr_to_num("644d5241")) # magic (LE "ARMd" (d is 0x64)) 141 write_le32(0) # res2 142} 143 144/kernbase/ { 145 # If the symbol name is exactly "kernbase" save its address. 146 if ($3 == "kernbase") { 147 gKernbase = hexstr_to_num($1) 148 } 149} 150 151/_start/ { 152 # If the symbol name is exactly "_start" save its address. 153 if ($3 == "_start") { 154 gStart = hexstr_to_num($1) 155 } 156} 157 158/_end/ { 159 # If the symbol name is exactly "_end" remember its value. 160 if ($3 == "_end") { 161 gEnd = hexstr_to_num($1) 162 } 163} 164 165END { 166 # Note that this function runs even if BEGIN calls exit(1)! 167 if (gHdrType == "error_reported") { 168 exit 1 169 } 170 171 # Make sure we got all three required symbols. 172 if (gKernbase == 0 || gStart == 0 || gEnd == 0) { 173 print "arm_kernel_boothdr.awk: " \ 174 "missing kernbase/_start/_end symbol(s)" >"/dev/stderr" 175 exit 1 176 } 177 178 gStartOff = addr_to_offset(gStart) 179 gEndOff = addr_to_offset(gEnd) 180 181 if (gHdrType == "v7jump") { 182 write_v7jump() 183 } else if (gHdrType == "v8jump") { 184 write_v8jump() 185 } else if (gHdrType == "v8booti") { 186 write_v8booti() 187 } 188 write_padding() 189} 190