dtb.cc revision 358206
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 358206 2020-02-21 04:38:59Z kevans $
33 */
34
35#include "dtb.hh"
36#include <sys/types.h>
37#include <inttypes.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <errno.h>
42
43using std::string;
44
45namespace {
46
47void write(dtc::byte_buffer &buffer, int fd)
48{
49	size_t size = buffer.size();
50	uint8_t *data = buffer.data();
51	while (size > 0)
52	{
53		ssize_t r = ::write(fd, data, size);
54		if (r >= 0)
55		{
56			data += r;
57			size -= r;
58		}
59		else if (errno != EAGAIN)
60		{
61			fprintf(stderr, "Writing to file failed\n");
62			exit(-1);
63		}
64	}
65}
66}
67
68namespace dtc
69{
70namespace dtb
71{
72
73void output_writer::write_data(byte_buffer b)
74{
75	for (auto i : b)
76	{
77		write_data(i);
78	}
79}
80
81void
82binary_writer::write_string(const string &name)
83{
84	push_string(buffer, name);
85	// Trailing nul
86	buffer.push_back(0);
87}
88
89void
90binary_writer::write_data(uint8_t v)
91{
92	buffer.push_back(v);
93}
94
95void
96binary_writer::write_data(uint32_t v)
97{
98	while (buffer.size() % 4 != 0)
99	{
100		buffer.push_back(0);
101	}
102	push_big_endian(buffer, v);
103}
104
105void
106binary_writer::write_data(uint64_t v)
107{
108	while (buffer.size() % 8 != 0)
109	{
110		buffer.push_back(0);
111	}
112	push_big_endian(buffer, v);
113}
114
115void
116binary_writer::write_to_file(int fd)
117{
118	write(buffer, fd);
119}
120
121uint32_t
122binary_writer::size()
123{
124	return buffer.size();
125}
126
127void
128asm_writer::write_line(const char *c)
129{
130	if (byte_count != 0)
131	{
132		byte_count = 0;
133		buffer.push_back('\n');
134	}
135	write_string(c);
136}
137
138void
139asm_writer::write_byte(uint8_t b)
140{
141	char out[3] = {0};
142	if (byte_count++ == 0)
143	{
144		buffer.push_back('\t');
145	}
146	write_string(".byte 0x");
147	snprintf(out, 3, "%.2hhx", b);
148	buffer.push_back(out[0]);
149	buffer.push_back(out[1]);
150	if (byte_count == 4)
151	{
152		buffer.push_back('\n');
153		byte_count = 0;
154	}
155	else
156	{
157		buffer.push_back(';');
158		buffer.push_back(' ');
159	}
160}
161
162void
163asm_writer::write_label(const string &name)
164{
165	write_line("\t.globl ");
166	push_string(buffer, name);
167	buffer.push_back('\n');
168	push_string(buffer, name);
169	buffer.push_back(':');
170	buffer.push_back('\n');
171	buffer.push_back('_');
172	push_string(buffer, name);
173	buffer.push_back(':');
174	buffer.push_back('\n');
175
176}
177
178void
179asm_writer::write_comment(const string &name)
180{
181	write_line("\t/* ");
182	push_string(buffer, name);
183	write_string(" */\n");
184}
185
186void
187asm_writer::write_string(const char *c)
188{
189	while (*c)
190	{
191		buffer.push_back((uint8_t)*(c++));
192	}
193}
194
195
196void
197asm_writer::write_string(const string &name)
198{
199	write_line("\t.string \"");
200	push_string(buffer, name);
201	write_line("\"\n");
202	bytes_written += name.size() + 1;
203}
204
205void
206asm_writer::write_data(uint8_t v)
207{
208	write_byte(v);
209	bytes_written++;
210}
211
212void
213asm_writer::write_data(uint32_t v)
214{
215	if (bytes_written % 4 != 0)
216	{
217		write_line("\t.balign 4\n");
218		bytes_written += (4 - (bytes_written % 4));
219	}
220	write_byte((v >> 24) & 0xff);
221	write_byte((v >> 16) & 0xff);
222	write_byte((v >> 8) & 0xff);
223	write_byte((v >> 0) & 0xff);
224	bytes_written += 4;
225}
226
227void
228asm_writer::write_data(uint64_t v)
229{
230	if (bytes_written % 8 != 0)
231	{
232		write_line("\t.balign 8\n");
233		bytes_written += (8 - (bytes_written % 8));
234	}
235	write_byte((v >> 56) & 0xff);
236	write_byte((v >> 48) & 0xff);
237	write_byte((v >> 40) & 0xff);
238	write_byte((v >> 32) & 0xff);
239	write_byte((v >> 24) & 0xff);
240	write_byte((v >> 16) & 0xff);
241	write_byte((v >> 8) & 0xff);
242	write_byte((v >> 0) & 0xff);
243	bytes_written += 8;
244}
245
246void
247asm_writer::write_to_file(int fd)
248{
249	write(buffer, fd);
250}
251
252uint32_t
253asm_writer::size()
254{
255	return bytes_written;
256}
257
258void
259header::write(output_writer &out)
260{
261	out.write_label("dt_blob_start");
262	out.write_label("dt_header");
263	out.write_comment("magic");
264	out.write_data(magic);
265	out.write_comment("totalsize");
266	out.write_data(totalsize);
267	out.write_comment("off_dt_struct");
268	out.write_data(off_dt_struct);
269	out.write_comment("off_dt_strings");
270	out.write_data(off_dt_strings);
271	out.write_comment("off_mem_rsvmap");
272	out.write_data(off_mem_rsvmap);
273	out.write_comment("version");
274	out.write_data(version);
275	out.write_comment("last_comp_version");
276	out.write_data(last_comp_version);
277	out.write_comment("boot_cpuid_phys");
278	out.write_data(boot_cpuid_phys);
279	out.write_comment("size_dt_strings");
280	out.write_data(size_dt_strings);
281	out.write_comment("size_dt_struct");
282	out.write_data(size_dt_struct);
283}
284
285bool
286header::read_dtb(input_buffer &input)
287{
288	if (!input.consume_binary(magic))
289	{
290		fprintf(stderr, "Missing magic token in header.");
291		return false;
292	}
293	if (magic != 0xd00dfeed)
294	{
295		fprintf(stderr, "Bad magic token in header.  Got %" PRIx32
296		                " expected 0xd00dfeed\n", magic);
297		return false;
298	}
299	return input.consume_binary(totalsize) &&
300	       input.consume_binary(off_dt_struct) &&
301	       input.consume_binary(off_dt_strings) &&
302	       input.consume_binary(off_mem_rsvmap) &&
303	       input.consume_binary(version) &&
304	       input.consume_binary(last_comp_version) &&
305	       input.consume_binary(boot_cpuid_phys) &&
306	       input.consume_binary(size_dt_strings) &&
307	       input.consume_binary(size_dt_struct);
308}
309uint32_t
310string_table::add_string(const string &str)
311{
312	auto old = string_offsets.find(str);
313	if (old == string_offsets.end())
314	{
315		uint32_t start = size;
316		// Don't forget the trailing nul
317		size += str.size() + 1;
318		string_offsets.insert(std::make_pair(str, start));
319		strings.push_back(str);
320		return start;
321	}
322	else
323	{
324		return old->second;
325	}
326}
327
328void
329string_table::write(dtb::output_writer &writer)
330{
331	writer.write_comment("Strings table.");
332	writer.write_label("dt_strings_start");
333	for (auto &i : strings)
334	{
335		writer.write_string(i);
336	}
337	writer.write_label("dt_strings_end");
338}
339
340} // namespace dtb
341
342} // namespace dtc
343
344