159f46e34SMichal Meloun#!/usr/bin/awk -f 259f46e34SMichal Meloun#- 34d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause 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 2959f46e34SMichal MelounBEGIN { 3059f46e34SMichal Meloun # Init global vars. 3159f46e34SMichal Meloun gBytesOut = 0; # How many output bytes we've written so far 3259f46e34SMichal Meloun gKernbase = 0; # Address of first byte of loaded kernel image 3359f46e34SMichal Meloun gStart = 0; # Address of _start symbol 3459f46e34SMichal Meloun gStartOff = 0; # Offset of _start symbol from start of image 3559f46e34SMichal Meloun gEnd = 0; # Address of _end symbol 3659f46e34SMichal Meloun gEndOff = 0; # Offset of _end symbol from start of image 3759f46e34SMichal Meloun 3859f46e34SMichal Meloun # The type of header we're writing is set using -v hdrtype= on 3959f46e34SMichal Meloun # the command line, ensure we got a valid value for it. 4059f46e34SMichal Meloun if (hdrtype != "v7jump" && 4159f46e34SMichal Meloun hdrtype != "v8jump" && 4259f46e34SMichal Meloun hdrtype != "v8booti") { 4359f46e34SMichal Meloun print "arm_kernel_boothdr.awk: " \ 4459f46e34SMichal Meloun "missing or invalid '-v hdrtype=' argument" >"/dev/stderr" 4559f46e34SMichal Meloun gHdrType = "error_reported" 4659f46e34SMichal Meloun exit 1 4759f46e34SMichal Meloun } 4859f46e34SMichal Meloun 4959f46e34SMichal Meloun gHdrType = hdrtype 50*de222511SWarner Losh for (i = 0; i < 16; i++) { 51*de222511SWarner Losh hex[sprintf("%x", i)] = i; 52*de222511SWarner Losh hex[sprintf("%X", i)] = i; 53*de222511SWarner Losh } 5459f46e34SMichal Meloun} 5559f46e34SMichal Meloun 5659f46e34SMichal Melounfunction addr_to_offset(addr) { 5759f46e34SMichal Meloun # Turn an address into an offset from the start of the loaded image. 5859f46e34SMichal Meloun return addr % gKernbase 5959f46e34SMichal Meloun} 6059f46e34SMichal Meloun 6159f46e34SMichal Melounfunction hexstr_to_num(str) { 6259f46e34SMichal Meloun 63*de222511SWarner Losh sum = 0; 64*de222511SWarner Losh len = length(str); 65*de222511SWarner Losh for (i = 1; i <= len; i++) { 66*de222511SWarner Losh sum = sum * 16 + hex[substr(str, i, 1)]; 67*de222511SWarner Losh } 6859f46e34SMichal Meloun 69*de222511SWarner Losh return sum; 7059f46e34SMichal Meloun} 7159f46e34SMichal Meloun 7259f46e34SMichal Melounfunction write_le32(num) { 7359f46e34SMichal Meloun 7459f46e34SMichal Meloun for (i = 0; i < 4; i++) { 7559f46e34SMichal Meloun printf("%c", num % 256); 7659f46e34SMichal Meloun num /= 256 7759f46e34SMichal Meloun } 7859f46e34SMichal Meloun gBytesOut += 4 7959f46e34SMichal Meloun} 8059f46e34SMichal Meloun 8159f46e34SMichal Melounfunction write_le64(num) { 8259f46e34SMichal Meloun 8359f46e34SMichal Meloun for (i = 0; i < 8; i++) { 8459f46e34SMichal Meloun printf("%c", num % 256); 8559f46e34SMichal Meloun num /= 256 8659f46e34SMichal Meloun } 8759f46e34SMichal Meloun gBytesOut += 8 8859f46e34SMichal Meloun} 8959f46e34SMichal Meloun 9059f46e34SMichal Melounfunction write_padding() { 9159f46e34SMichal Meloun 9259f46e34SMichal Meloun # Write enough padding bytes so that the header fills all the 9359f46e34SMichal Meloun # remaining space before the _start symbol. 9459f46e34SMichal Meloun 9559f46e34SMichal Meloun while (gBytesOut++ < gStartOff) { 9659f46e34SMichal Meloun printf("%c", 0); 9759f46e34SMichal Meloun } 9859f46e34SMichal Meloun} 9959f46e34SMichal Meloun 10059f46e34SMichal Melounfunction write_v7jump() { 10159f46e34SMichal Meloun 10259f46e34SMichal Meloun # Write the machine code for "b _start"... 10359f46e34SMichal Meloun # 0xea is armv7 "branch always" and the low 24 bits is the signed 10459f46e34SMichal Meloun # offset from the current PC, in words. We know the gStart offset 10559f46e34SMichal Meloun # is in the first 2mb, so it'll fit in 24 bits. 10659f46e34SMichal Meloun 10759f46e34SMichal Meloun write_le32(hexstr_to_num("ea000000") + (gStartOff / 4) - 2) 10859f46e34SMichal Meloun} 10959f46e34SMichal Meloun 11059f46e34SMichal Melounfunction write_v8jump() { 11159f46e34SMichal Meloun 11259f46e34SMichal Meloun # Write the machine code for "b _start"... 11359f46e34SMichal Meloun # 0x14 is armv8 "branch always" and the low 26 bits is the signed 11459f46e34SMichal Meloun # offset from the current PC, in words. We know the gStart offset 11559f46e34SMichal Meloun # is in the first 2mb, so it'll fit in 26 bits. 11659f46e34SMichal Meloun 11759f46e34SMichal Meloun write_le32(hexstr_to_num("14000000") + (gStartOff / 4)) 11859f46e34SMichal Meloun} 11959f46e34SMichal Meloun 12059f46e34SMichal Melounfunction write_v8booti() { 12159f46e34SMichal Meloun 12259f46e34SMichal Meloun # We are writing this struct... 12359f46e34SMichal Meloun # 12459f46e34SMichal Meloun # struct Image_header { 12559f46e34SMichal Meloun # uint32_t code0; /* Executable code */ 12659f46e34SMichal Meloun # uint32_t code1; /* Executable code */ 12759f46e34SMichal Meloun # uint64_t text_offset; /* Image load offset, LE */ 12859f46e34SMichal Meloun # uint64_t image_size; /* Effective Image size, LE */ 12959f46e34SMichal Meloun # uint64_t flags; /* Kernel flags, LE */ 13059f46e34SMichal Meloun # uint64_t res1[3]; /* reserved */ 13159f46e34SMichal Meloun # uint32_t magic; /* Magic number */ 13259f46e34SMichal Meloun # uint32_t res2; 13359f46e34SMichal Meloun # }; 13459f46e34SMichal Meloun # 13559f46e34SMichal Meloun # We write 'b _start' into code0. The image size is everything from 13659f46e34SMichal Meloun # the start of the loaded image to the offset given by the _end symbol. 13759f46e34SMichal Meloun 13859f46e34SMichal Meloun write_v8jump() # code0 13959f46e34SMichal Meloun write_le32(0) # code1 14059f46e34SMichal Meloun write_le64(0) # text_offset 14159f46e34SMichal Meloun write_le64(gEndOff) # image_size 142b07a6bd1SMichal Meloun write_le64(hexstr_to_num("8")) # flags 14359f46e34SMichal Meloun write_le64(0) # res1[0] 14459f46e34SMichal Meloun write_le64(0) # res1[1] 14559f46e34SMichal Meloun write_le64(0) # res1[2] 14659f46e34SMichal Meloun write_le32(hexstr_to_num("644d5241")) # magic (LE "ARMd" (d is 0x64)) 14759f46e34SMichal Meloun write_le32(0) # res2 14859f46e34SMichal Meloun} 14959f46e34SMichal Meloun 15059f46e34SMichal Meloun/kernbase/ { 15159f46e34SMichal Meloun # If the symbol name is exactly "kernbase" save its address. 1521846bbd1SJessica Clarke if ($3 == "kernbase") { 1531846bbd1SJessica Clarke gKernbase = hexstr_to_num($1) 15459f46e34SMichal Meloun } 15559f46e34SMichal Meloun} 15659f46e34SMichal Meloun 15759f46e34SMichal Meloun/_start/ { 15859f46e34SMichal Meloun # If the symbol name is exactly "_start" save its address. 1591846bbd1SJessica Clarke if ($3 == "_start") { 1601846bbd1SJessica Clarke gStart = hexstr_to_num($1) 16159f46e34SMichal Meloun } 16259f46e34SMichal Meloun} 16359f46e34SMichal Meloun 16459f46e34SMichal Meloun/_end/ { 16559f46e34SMichal Meloun # If the symbol name is exactly "_end" remember its value. 1661846bbd1SJessica Clarke if ($3 == "_end") { 1671846bbd1SJessica Clarke gEnd = hexstr_to_num($1) 16859f46e34SMichal Meloun } 16959f46e34SMichal Meloun} 17059f46e34SMichal Meloun 17159f46e34SMichal MelounEND { 17259f46e34SMichal Meloun # Note that this function runs even if BEGIN calls exit(1)! 17359f46e34SMichal Meloun if (gHdrType == "error_reported") { 17459f46e34SMichal Meloun exit 1 17559f46e34SMichal Meloun } 17659f46e34SMichal Meloun 17759f46e34SMichal Meloun # Make sure we got all three required symbols. 17859f46e34SMichal Meloun if (gKernbase == 0 || gStart == 0 || gEnd == 0) { 17959f46e34SMichal Meloun print "arm_kernel_boothdr.awk: " \ 18059f46e34SMichal Meloun "missing kernbase/_start/_end symbol(s)" >"/dev/stderr" 18159f46e34SMichal Meloun exit 1 18259f46e34SMichal Meloun } 18359f46e34SMichal Meloun 18459f46e34SMichal Meloun gStartOff = addr_to_offset(gStart) 18559f46e34SMichal Meloun gEndOff = addr_to_offset(gEnd) 18659f46e34SMichal Meloun 18759f46e34SMichal Meloun if (gHdrType == "v7jump") { 18859f46e34SMichal Meloun write_v7jump() 18959f46e34SMichal Meloun } else if (gHdrType == "v8jump") { 19059f46e34SMichal Meloun write_v8jump() 19159f46e34SMichal Meloun } else if (gHdrType == "v8booti") { 19259f46e34SMichal Meloun write_v8booti() 19359f46e34SMichal Meloun } 19459f46e34SMichal Meloun write_padding() 19559f46e34SMichal Meloun} 196