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