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