159f46e34SMichal Meloun#!/usr/bin/awk -f 259f46e34SMichal Meloun#- 359f46e34SMichal Meloun# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 459f46e34SMichal Meloun# 559f46e34SMichal Meloun# Copyright 2019 Ian Lepore <ian@freebsd.org> 659f46e34SMichal Meloun# 759f46e34SMichal Meloun# Redistribution and use in source and binary forms, with or without 859f46e34SMichal Meloun# modification, are permitted provided that the following conditions 959f46e34SMichal Meloun# are met: 1059f46e34SMichal Meloun# 1. Redistributions of source code must retain the above copyright 1159f46e34SMichal Meloun# notice, this list of conditions and the following disclaimer. 1259f46e34SMichal Meloun# 2. Redistributions in binary form must reproduce the above copyright 1359f46e34SMichal Meloun# notice, this list of conditions and the following disclaimer in the 1459f46e34SMichal Meloun# documentation and/or other materials provided with the distribution. 1559f46e34SMichal Meloun# 1659f46e34SMichal Meloun# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1759f46e34SMichal Meloun# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1859f46e34SMichal Meloun# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1959f46e34SMichal Meloun# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2059f46e34SMichal Meloun# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2159f46e34SMichal Meloun# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2259f46e34SMichal Meloun# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2359f46e34SMichal Meloun# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2459f46e34SMichal Meloun# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2559f46e34SMichal Meloun# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2659f46e34SMichal Meloun# SUCH DAMAGE. 2759f46e34SMichal Meloun# 2859f46e34SMichal Meloun# $FreeBSD$ 2959f46e34SMichal Meloun 3059f46e34SMichal MelounBEGIN { 3159f46e34SMichal Meloun # Init global vars. 3259f46e34SMichal Meloun gBytesOut = 0; # How many output bytes we've written so far 3359f46e34SMichal Meloun gKernbase = 0; # Address of first byte of loaded kernel image 3459f46e34SMichal Meloun gStart = 0; # Address of _start symbol 3559f46e34SMichal Meloun gStartOff = 0; # Offset of _start symbol from start of image 3659f46e34SMichal Meloun gEnd = 0; # Address of _end symbol 3759f46e34SMichal Meloun gEndOff = 0; # Offset of _end symbol from start of image 3859f46e34SMichal Meloun 3959f46e34SMichal Meloun # The type of header we're writing is set using -v hdrtype= on 4059f46e34SMichal Meloun # the command line, ensure we got a valid value for it. 4159f46e34SMichal Meloun if (hdrtype != "v7jump" && 4259f46e34SMichal Meloun hdrtype != "v8jump" && 4359f46e34SMichal Meloun hdrtype != "v8booti") { 4459f46e34SMichal Meloun print "arm_kernel_boothdr.awk: " \ 4559f46e34SMichal Meloun "missing or invalid '-v hdrtype=' argument" >"/dev/stderr" 4659f46e34SMichal Meloun gHdrType = "error_reported" 4759f46e34SMichal Meloun exit 1 4859f46e34SMichal Meloun } 4959f46e34SMichal Meloun 5059f46e34SMichal Meloun gHdrType = hdrtype 5159f46e34SMichal Meloun} 5259f46e34SMichal Meloun 5359f46e34SMichal Melounfunction addr_to_offset(addr) { 5459f46e34SMichal Meloun # Turn an address into an offset from the start of the loaded image. 5559f46e34SMichal Meloun return addr % gKernbase 5659f46e34SMichal Meloun} 5759f46e34SMichal Meloun 5859f46e34SMichal Melounfunction hexstr_to_num(str) { 5959f46e34SMichal Meloun 6059f46e34SMichal Meloun # Prepend a 0x onto the string, then coerce it to a number by doing 6159f46e34SMichal Meloun # arithmetic with it, which makes awk run it through strtod(), 6259f46e34SMichal Meloun # which handles hex numbers that have a 0x prefix. 6359f46e34SMichal Meloun 6459f46e34SMichal Meloun return 0 + ("0x" str) 6559f46e34SMichal Meloun} 6659f46e34SMichal Meloun 6759f46e34SMichal Melounfunction write_le32(num) { 6859f46e34SMichal Meloun 6959f46e34SMichal Meloun for (i = 0; i < 4; i++) { 7059f46e34SMichal Meloun printf("%c", num % 256); 7159f46e34SMichal Meloun num /= 256 7259f46e34SMichal Meloun } 7359f46e34SMichal Meloun gBytesOut += 4 7459f46e34SMichal Meloun} 7559f46e34SMichal Meloun 7659f46e34SMichal Melounfunction write_le64(num) { 7759f46e34SMichal Meloun 7859f46e34SMichal Meloun for (i = 0; i < 8; i++) { 7959f46e34SMichal Meloun printf("%c", num % 256); 8059f46e34SMichal Meloun num /= 256 8159f46e34SMichal Meloun } 8259f46e34SMichal Meloun gBytesOut += 8 8359f46e34SMichal Meloun} 8459f46e34SMichal Meloun 8559f46e34SMichal Melounfunction write_padding() { 8659f46e34SMichal Meloun 8759f46e34SMichal Meloun # Write enough padding bytes so that the header fills all the 8859f46e34SMichal Meloun # remaining space before the _start symbol. 8959f46e34SMichal Meloun 9059f46e34SMichal Meloun while (gBytesOut++ < gStartOff) { 9159f46e34SMichal Meloun printf("%c", 0); 9259f46e34SMichal Meloun } 9359f46e34SMichal Meloun} 9459f46e34SMichal Meloun 9559f46e34SMichal Melounfunction write_v7jump() { 9659f46e34SMichal Meloun 9759f46e34SMichal Meloun # Write the machine code for "b _start"... 9859f46e34SMichal Meloun # 0xea is armv7 "branch always" and the low 24 bits is the signed 9959f46e34SMichal Meloun # offset from the current PC, in words. We know the gStart offset 10059f46e34SMichal Meloun # is in the first 2mb, so it'll fit in 24 bits. 10159f46e34SMichal Meloun 10259f46e34SMichal Meloun write_le32(hexstr_to_num("ea000000") + (gStartOff / 4) - 2) 10359f46e34SMichal Meloun} 10459f46e34SMichal Meloun 10559f46e34SMichal Melounfunction write_v8jump() { 10659f46e34SMichal Meloun 10759f46e34SMichal Meloun # Write the machine code for "b _start"... 10859f46e34SMichal Meloun # 0x14 is armv8 "branch always" and the low 26 bits is the signed 10959f46e34SMichal Meloun # offset from the current PC, in words. We know the gStart offset 11059f46e34SMichal Meloun # is in the first 2mb, so it'll fit in 26 bits. 11159f46e34SMichal Meloun 11259f46e34SMichal Meloun write_le32(hexstr_to_num("14000000") + (gStartOff / 4)) 11359f46e34SMichal Meloun} 11459f46e34SMichal Meloun 11559f46e34SMichal Melounfunction write_v8booti() { 11659f46e34SMichal Meloun 11759f46e34SMichal Meloun # We are writing this struct... 11859f46e34SMichal Meloun # 11959f46e34SMichal Meloun # struct Image_header { 12059f46e34SMichal Meloun # uint32_t code0; /* Executable code */ 12159f46e34SMichal Meloun # uint32_t code1; /* Executable code */ 12259f46e34SMichal Meloun # uint64_t text_offset; /* Image load offset, LE */ 12359f46e34SMichal Meloun # uint64_t image_size; /* Effective Image size, LE */ 12459f46e34SMichal Meloun # uint64_t flags; /* Kernel flags, LE */ 12559f46e34SMichal Meloun # uint64_t res1[3]; /* reserved */ 12659f46e34SMichal Meloun # uint32_t magic; /* Magic number */ 12759f46e34SMichal Meloun # uint32_t res2; 12859f46e34SMichal Meloun # }; 12959f46e34SMichal Meloun # 13059f46e34SMichal Meloun # We write 'b _start' into code0. The image size is everything from 13159f46e34SMichal Meloun # the start of the loaded image to the offset given by the _end symbol. 13259f46e34SMichal Meloun 13359f46e34SMichal Meloun write_v8jump() # code0 13459f46e34SMichal Meloun write_le32(0) # code1 13559f46e34SMichal Meloun write_le64(0) # text_offset 13659f46e34SMichal Meloun write_le64(gEndOff) # image_size 137b07a6bd1SMichal Meloun write_le64(hexstr_to_num("8")) # flags 13859f46e34SMichal Meloun write_le64(0) # res1[0] 13959f46e34SMichal Meloun write_le64(0) # res1[1] 14059f46e34SMichal Meloun write_le64(0) # res1[2] 14159f46e34SMichal Meloun write_le32(hexstr_to_num("644d5241")) # magic (LE "ARMd" (d is 0x64)) 14259f46e34SMichal Meloun write_le32(0) # res2 14359f46e34SMichal Meloun} 14459f46e34SMichal Meloun 14559f46e34SMichal Meloun/kernbase/ { 14659f46e34SMichal Meloun # If the symbol name is exactly "kernbase" save its address. 147*1846bbd1SJessica Clarke if ($3 == "kernbase") { 148*1846bbd1SJessica Clarke gKernbase = hexstr_to_num($1) 14959f46e34SMichal Meloun } 15059f46e34SMichal Meloun} 15159f46e34SMichal Meloun 15259f46e34SMichal Meloun/_start/ { 15359f46e34SMichal Meloun # If the symbol name is exactly "_start" save its address. 154*1846bbd1SJessica Clarke if ($3 == "_start") { 155*1846bbd1SJessica Clarke gStart = hexstr_to_num($1) 15659f46e34SMichal Meloun } 15759f46e34SMichal Meloun} 15859f46e34SMichal Meloun 15959f46e34SMichal Meloun/_end/ { 16059f46e34SMichal Meloun # If the symbol name is exactly "_end" remember its value. 161*1846bbd1SJessica Clarke if ($3 == "_end") { 162*1846bbd1SJessica Clarke gEnd = hexstr_to_num($1) 16359f46e34SMichal Meloun } 16459f46e34SMichal Meloun} 16559f46e34SMichal Meloun 16659f46e34SMichal MelounEND { 16759f46e34SMichal Meloun # Note that this function runs even if BEGIN calls exit(1)! 16859f46e34SMichal Meloun if (gHdrType == "error_reported") { 16959f46e34SMichal Meloun exit 1 17059f46e34SMichal Meloun } 17159f46e34SMichal Meloun 17259f46e34SMichal Meloun # Make sure we got all three required symbols. 17359f46e34SMichal Meloun if (gKernbase == 0 || gStart == 0 || gEnd == 0) { 17459f46e34SMichal Meloun print "arm_kernel_boothdr.awk: " \ 17559f46e34SMichal Meloun "missing kernbase/_start/_end symbol(s)" >"/dev/stderr" 17659f46e34SMichal Meloun exit 1 17759f46e34SMichal Meloun } 17859f46e34SMichal Meloun 17959f46e34SMichal Meloun gStartOff = addr_to_offset(gStart) 18059f46e34SMichal Meloun gEndOff = addr_to_offset(gEnd) 18159f46e34SMichal Meloun 18259f46e34SMichal Meloun if (gHdrType == "v7jump") { 18359f46e34SMichal Meloun write_v7jump() 18459f46e34SMichal Meloun } else if (gHdrType == "v8jump") { 18559f46e34SMichal Meloun write_v8jump() 18659f46e34SMichal Meloun } else if (gHdrType == "v8booti") { 18759f46e34SMichal Meloun write_v8booti() 18859f46e34SMichal Meloun } 18959f46e34SMichal Meloun write_padding() 19059f46e34SMichal Meloun} 191