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 for (i = 0; i < 16; i++) { 51 hex[sprintf("%x", i)] = i; 52 hex[sprintf("%X", i)] = i; 53 } 54} 55 56function addr_to_offset(addr) { 57 # Turn an address into an offset from the start of the loaded image. 58 return addr % gKernbase 59} 60 61function hexstr_to_num(str) { 62 63 sum = 0; 64 len = length(str); 65 for (i = 1; i <= len; i++) { 66 sum = sum * 16 + hex[substr(str, i, 1)]; 67 } 68 69 return sum; 70} 71 72function write_le32(num) { 73 74 for (i = 0; i < 4; i++) { 75 printf("%c", num % 256); 76 num /= 256 77 } 78 gBytesOut += 4 79} 80 81function write_le64(num) { 82 83 for (i = 0; i < 8; i++) { 84 printf("%c", num % 256); 85 num /= 256 86 } 87 gBytesOut += 8 88} 89 90function write_padding() { 91 92 # Write enough padding bytes so that the header fills all the 93 # remaining space before the _start symbol. 94 95 while (gBytesOut++ < gStartOff) { 96 printf("%c", 0); 97 } 98} 99 100function write_v7jump() { 101 102 # Write the machine code for "b _start"... 103 # 0xea is armv7 "branch always" and the low 24 bits is the signed 104 # offset from the current PC, in words. We know the gStart offset 105 # is in the first 2mb, so it'll fit in 24 bits. 106 107 write_le32(hexstr_to_num("ea000000") + (gStartOff / 4) - 2) 108} 109 110function write_v8jump() { 111 112 # Write the machine code for "b _start"... 113 # 0x14 is armv8 "branch always" and the low 26 bits is the signed 114 # offset from the current PC, in words. We know the gStart offset 115 # is in the first 2mb, so it'll fit in 26 bits. 116 117 write_le32(hexstr_to_num("14000000") + (gStartOff / 4)) 118} 119 120function write_v8booti() { 121 122 # We are writing this struct... 123 # 124 # struct Image_header { 125 # uint32_t code0; /* Executable code */ 126 # uint32_t code1; /* Executable code */ 127 # uint64_t text_offset; /* Image load offset, LE */ 128 # uint64_t image_size; /* Effective Image size, LE */ 129 # uint64_t flags; /* Kernel flags, LE */ 130 # uint64_t res1[3]; /* reserved */ 131 # uint32_t magic; /* Magic number */ 132 # uint32_t res2; 133 # }; 134 # 135 # We write 'b _start' into code0. The image size is everything from 136 # the start of the loaded image to the offset given by the _end symbol. 137 138 write_v8jump() # code0 139 write_le32(0) # code1 140 write_le64(0) # text_offset 141 write_le64(gEndOff) # image_size 142 write_le64(hexstr_to_num("8")) # flags 143 write_le64(0) # res1[0] 144 write_le64(0) # res1[1] 145 write_le64(0) # res1[2] 146 write_le32(hexstr_to_num("644d5241")) # magic (LE "ARMd" (d is 0x64)) 147 write_le32(0) # res2 148} 149 150/kernbase/ { 151 # If the symbol name is exactly "kernbase" save its address. 152 if ($3 == "kernbase") { 153 gKernbase = hexstr_to_num($1) 154 } 155} 156 157/_start/ { 158 # If the symbol name is exactly "_start" save its address. 159 if ($3 == "_start") { 160 gStart = hexstr_to_num($1) 161 } 162} 163 164/_end/ { 165 # If the symbol name is exactly "_end" remember its value. 166 if ($3 == "_end") { 167 gEnd = hexstr_to_num($1) 168 } 169} 170 171END { 172 # Note that this function runs even if BEGIN calls exit(1)! 173 if (gHdrType == "error_reported") { 174 exit 1 175 } 176 177 # Make sure we got all three required symbols. 178 if (gKernbase == 0 || gStart == 0 || gEnd == 0) { 179 print "arm_kernel_boothdr.awk: " \ 180 "missing kernbase/_start/_end symbol(s)" >"/dev/stderr" 181 exit 1 182 } 183 184 gStartOff = addr_to_offset(gStart) 185 gEndOff = addr_to_offset(gEnd) 186 187 if (gHdrType == "v7jump") { 188 write_v7jump() 189 } else if (gHdrType == "v8jump") { 190 write_v8jump() 191 } else if (gHdrType == "v8booti") { 192 write_v8booti() 193 } 194 write_padding() 195} 196