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