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