xref: /freebsd/sys/tools/arm_kernel_boothdr.awk (revision 1846bbd1b34e0269e0edd829dcff4729b37a149b)
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