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