1#!/usr/bin/awk -f 2#- 3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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# $FreeBSD$ 29 30BEGIN { 31 # Init global vars. 32 gBytesOut = 0; # How many output bytes we've written so far 33 gKernbase = 0; # Address of first byte of loaded kernel image 34 gStart = 0; # Address of _start symbol 35 gStartOff = 0; # Offset of _start symbol from start of image 36 gEnd = 0; # Address of _end symbol 37 gEndOff = 0; # Offset of _end symbol from start of image 38 39 # The type of header we're writing is set using -v hdrtype= on 40 # the command line, ensure we got a valid value for it. 41 if (hdrtype != "v7jump" && 42 hdrtype != "v8jump" && 43 hdrtype != "v8booti") { 44 print "arm_kernel_boothdr.awk: " \ 45 "missing or invalid '-v hdrtype=' argument" >"/dev/stderr" 46 gHdrType = "error_reported" 47 exit 1 48 } 49 50 gHdrType = hdrtype 51} 52 53function addr_to_offset(addr) { 54 # Turn an address into an offset from the start of the loaded image. 55 return addr % gKernbase 56} 57 58function hexstr_to_num(str) { 59 60 # Prepend a 0x onto the string, then coerce it to a number by doing 61 # arithmetic with it, which makes awk run it through strtod(), 62 # which handles hex numbers that have a 0x prefix. 63 64 return 0 + ("0x" str) 65} 66 67function write_le32(num) { 68 69 for (i = 0; i < 4; i++) { 70 printf("%c", num % 256); 71 num /= 256 72 } 73 gBytesOut += 4 74} 75 76function write_le64(num) { 77 78 for (i = 0; i < 8; i++) { 79 printf("%c", num % 256); 80 num /= 256 81 } 82 gBytesOut += 8 83} 84 85function write_padding() { 86 87 # Write enough padding bytes so that the header fills all the 88 # remaining space before the _start symbol. 89 90 while (gBytesOut++ < gStartOff) { 91 printf("%c", 0); 92 } 93} 94 95function write_v7jump() { 96 97 # Write the machine code for "b _start"... 98 # 0xea is armv7 "branch always" and the low 24 bits is the signed 99 # offset from the current PC, in words. We know the gStart offset 100 # is in the first 2mb, so it'll fit in 24 bits. 101 102 write_le32(hexstr_to_num("ea000000") + (gStartOff / 4) - 2) 103} 104 105function write_v8jump() { 106 107 # Write the machine code for "b _start"... 108 # 0x14 is armv8 "branch always" and the low 26 bits is the signed 109 # offset from the current PC, in words. We know the gStart offset 110 # is in the first 2mb, so it'll fit in 26 bits. 111 112 write_le32(hexstr_to_num("14000000") + (gStartOff / 4)) 113} 114 115function write_v8booti() { 116 117 # We are writing this struct... 118 # 119 # struct Image_header { 120 # uint32_t code0; /* Executable code */ 121 # uint32_t code1; /* Executable code */ 122 # uint64_t text_offset; /* Image load offset, LE */ 123 # uint64_t image_size; /* Effective Image size, LE */ 124 # uint64_t flags; /* Kernel flags, LE */ 125 # uint64_t res1[3]; /* reserved */ 126 # uint32_t magic; /* Magic number */ 127 # uint32_t res2; 128 # }; 129 # 130 # We write 'b _start' into code0. The image size is everything from 131 # the start of the loaded image to the offset given by the _end symbol. 132 133 write_v8jump() # code0 134 write_le32(0) # code1 135 write_le64(0) # text_offset 136 write_le64(gEndOff) # image_size 137 write_le64(hexstr_to_num("8")) # flags 138 write_le64(0) # res1[0] 139 write_le64(0) # res1[1] 140 write_le64(0) # res1[2] 141 write_le32(hexstr_to_num("644d5241")) # magic (LE "ARMd" (d is 0x64)) 142 write_le32(0) # res2 143} 144 145/kernbase/ { 146 # If the symbol name is exactly "kernbase" save its address. 147 if ($8 == "kernbase") { 148 gKernbase = hexstr_to_num($2) 149 } 150} 151 152/_start/ { 153 # If the symbol name is exactly "_start" save its address. 154 if ($8 == "_start") { 155 gStart = hexstr_to_num($2) 156 } 157} 158 159/_end/ { 160 # If the symbol name is exactly "_end" remember its value. 161 if ($8 == "_end") { 162 gEnd = hexstr_to_num($2) 163 } 164} 165 166END { 167 # Note that this function runs even if BEGIN calls exit(1)! 168 if (gHdrType == "error_reported") { 169 exit 1 170 } 171 172 # Make sure we got all three required symbols. 173 if (gKernbase == 0 || gStart == 0 || gEnd == 0) { 174 print "arm_kernel_boothdr.awk: " \ 175 "missing kernbase/_start/_end symbol(s)" >"/dev/stderr" 176 exit 1 177 } 178 179 gStartOff = addr_to_offset(gStart) 180 gEndOff = addr_to_offset(gEnd) 181 182 if (gHdrType == "v7jump") { 183 write_v7jump() 184 } else if (gHdrType == "v8jump") { 185 write_v8jump() 186 } else if (gHdrType == "v8booti") { 187 write_v8booti() 188 } 189 write_padding() 190} 191