dtb.cc revision 345881
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2013 David Chisnall
5 * All rights reserved.
6 *
7 * This software was developed by SRI International and the University of
8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9 * ("CTSRD"), as part of the DARPA CRASH research programme.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: stable/11/usr.bin/dtc/dtb.cc 345881 2019-04-04 17:27:01Z kevans $
33 */
34
35#include "dtb.hh"
36#include <sys/types.h>
37#include <inttypes.h>
38#include <stdio.h>
39#include <unistd.h>
40#include <errno.h>
41
42using std::string;
43
44namespace {
45
46void write(dtc::byte_buffer &buffer, int fd)
47{
48	size_t size = buffer.size();
49	uint8_t *data = buffer.data();
50	while (size > 0)
51	{
52		ssize_t r = ::write(fd, data, size);
53		if (r >= 0)
54		{
55			data += r;
56			size -= r;
57		}
58		else if (errno != EAGAIN)
59		{
60			fprintf(stderr, "Writing to file failed\n");
61			exit(-1);
62		}
63	}
64}
65}
66
67namespace dtc
68{
69namespace dtb
70{
71
72void output_writer::write_data(byte_buffer b)
73{
74	for (auto i : b)
75	{
76		write_data(i);
77	}
78}
79
80void
81binary_writer::write_string(const string &name)
82{
83	push_string(buffer, name);
84	// Trailing nul
85	buffer.push_back(0);
86}
87
88void
89binary_writer::write_data(uint8_t v)
90{
91	buffer.push_back(v);
92}
93
94void
95binary_writer::write_data(uint32_t v)
96{
97	while (buffer.size() % 4 != 0)
98	{
99		buffer.push_back(0);
100	}
101	push_big_endian(buffer, v);
102}
103
104void
105binary_writer::write_data(uint64_t v)
106{
107	while (buffer.size() % 8 != 0)
108	{
109		buffer.push_back(0);
110	}
111	push_big_endian(buffer, v);
112}
113
114void
115binary_writer::write_to_file(int fd)
116{
117	write(buffer, fd);
118}
119
120uint32_t
121binary_writer::size()
122{
123	return buffer.size();
124}
125
126void
127asm_writer::write_line(const char *c)
128{
129	if (byte_count != 0)
130	{
131		byte_count = 0;
132		buffer.push_back('\n');
133	}
134	write_string(c);
135}
136
137void
138asm_writer::write_byte(uint8_t b)
139{
140	char out[3] = {0};
141	if (byte_count++ == 0)
142	{
143		buffer.push_back('\t');
144	}
145	write_string(".byte 0x");
146	snprintf(out, 3, "%.2hhx", b);
147	buffer.push_back(out[0]);
148	buffer.push_back(out[1]);
149	if (byte_count == 4)
150	{
151		buffer.push_back('\n');
152		byte_count = 0;
153	}
154	else
155	{
156		buffer.push_back(';');
157		buffer.push_back(' ');
158	}
159}
160
161void
162asm_writer::write_label(const string &name)
163{
164	write_line("\t.globl ");
165	push_string(buffer, name);
166	buffer.push_back('\n');
167	push_string(buffer, name);
168	buffer.push_back(':');
169	buffer.push_back('\n');
170	buffer.push_back('_');
171	push_string(buffer, name);
172	buffer.push_back(':');
173	buffer.push_back('\n');
174
175}
176
177void
178asm_writer::write_comment(const string &name)
179{
180	write_line("\t/* ");
181	push_string(buffer, name);
182	write_string(" */\n");
183}
184
185void
186asm_writer::write_string(const char *c)
187{
188	while (*c)
189	{
190		buffer.push_back((uint8_t)*(c++));
191	}
192}
193
194
195void
196asm_writer::write_string(const string &name)
197{
198	write_line("\t.string \"");
199	push_string(buffer, name);
200	write_line("\"\n");
201	bytes_written += name.size() + 1;
202}
203
204void
205asm_writer::write_data(uint8_t v)
206{
207	write_byte(v);
208	bytes_written++;
209}
210
211void
212asm_writer::write_data(uint32_t v)
213{
214	if (bytes_written % 4 != 0)
215	{
216		write_line("\t.balign 4\n");
217		bytes_written += (4 - (bytes_written % 4));
218	}
219	write_byte((v >> 24) & 0xff);
220	write_byte((v >> 16) & 0xff);
221	write_byte((v >> 8) & 0xff);
222	write_byte((v >> 0) & 0xff);
223	bytes_written += 4;
224}
225
226void
227asm_writer::write_data(uint64_t v)
228{
229	if (bytes_written % 8 != 0)
230	{
231		write_line("\t.balign 8\n");
232		bytes_written += (8 - (bytes_written % 8));
233	}
234	write_byte((v >> 56) & 0xff);
235	write_byte((v >> 48) & 0xff);
236	write_byte((v >> 40) & 0xff);
237	write_byte((v >> 32) & 0xff);
238	write_byte((v >> 24) & 0xff);
239	write_byte((v >> 16) & 0xff);
240	write_byte((v >> 8) & 0xff);
241	write_byte((v >> 0) & 0xff);
242	bytes_written += 8;
243}
244
245void
246asm_writer::write_to_file(int fd)
247{
248	write(buffer, fd);
249}
250
251uint32_t
252asm_writer::size()
253{
254	return bytes_written;
255}
256
257void
258header::write(output_writer &out)
259{
260	out.write_label("dt_blob_start");
261	out.write_label("dt_header");
262	out.write_comment("magic");
263	out.write_data(magic);
264	out.write_comment("totalsize");
265	out.write_data(totalsize);
266	out.write_comment("off_dt_struct");
267	out.write_data(off_dt_struct);
268	out.write_comment("off_dt_strings");
269	out.write_data(off_dt_strings);
270	out.write_comment("off_mem_rsvmap");
271	out.write_data(off_mem_rsvmap);
272	out.write_comment("version");
273	out.write_data(version);
274	out.write_comment("last_comp_version");
275	out.write_data(last_comp_version);
276	out.write_comment("boot_cpuid_phys");
277	out.write_data(boot_cpuid_phys);
278	out.write_comment("size_dt_strings");
279	out.write_data(size_dt_strings);
280	out.write_comment("size_dt_struct");
281	out.write_data(size_dt_struct);
282}
283
284bool
285header::read_dtb(input_buffer &input)
286{
287	if (!input.consume_binary(magic))
288	{
289		fprintf(stderr, "Missing magic token in header.");
290		return false;
291	}
292	if (magic != 0xd00dfeed)
293	{
294		fprintf(stderr, "Bad magic token in header.  Got %" PRIx32
295		                " expected 0xd00dfeed\n", magic);
296		return false;
297	}
298	return input.consume_binary(totalsize) &&
299	       input.consume_binary(off_dt_struct) &&
300	       input.consume_binary(off_dt_strings) &&
301	       input.consume_binary(off_mem_rsvmap) &&
302	       input.consume_binary(version) &&
303	       input.consume_binary(last_comp_version) &&
304	       input.consume_binary(boot_cpuid_phys) &&
305	       input.consume_binary(size_dt_strings) &&
306	       input.consume_binary(size_dt_struct);
307}
308uint32_t
309string_table::add_string(const string &str)
310{
311	auto old = string_offsets.find(str);
312	if (old == string_offsets.end())
313	{
314		uint32_t start = size;
315		// Don't forget the trailing nul
316		size += str.size() + 1;
317		string_offsets.insert(std::make_pair(str, start));
318		strings.push_back(str);
319		return start;
320	}
321	else
322	{
323		return old->second;
324	}
325}
326
327void
328string_table::write(dtb::output_writer &writer)
329{
330	writer.write_comment("Strings table.");
331	writer.write_label("dt_strings_start");
332	for (auto &i : strings)
333	{
334		writer.write_string(i);
335	}
336	writer.write_label("dt_strings_end");
337}
338
339} // namespace dtb
340
341} // namespace dtc
342
343