1333549Sdes/*-
2333549Sdes * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3333549Sdes *
4333549Sdes * Copyright (c) 2013 David Chisnall
5333549Sdes * All rights reserved.
6333549Sdes *
7333549Sdes * This software was developed by SRI International and the University of
8333549Sdes * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9333549Sdes * ("CTSRD"), as part of the DARPA CRASH research programme.
10333549Sdes *
11333549Sdes * Redistribution and use in source and binary forms, with or without
12333549Sdes * modification, are permitted provided that the following conditions
13333549Sdes * are met:
14333549Sdes * 1. Redistributions of source code must retain the above copyright
15333549Sdes *    notice, this list of conditions and the following disclaimer.
16333549Sdes * 2. Redistributions in binary form must reproduce the above copyright
17333549Sdes *    notice, this list of conditions and the following disclaimer in the
18333549Sdes *    documentation and/or other materials provided with the distribution.
19333549Sdes *
20333549Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21333549Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22333549Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23333549Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24333549Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25333549Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26333549Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27333549Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28333549Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29333549Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30333549Sdes * SUCH DAMAGE.
31333549Sdes *
32333549Sdes * $FreeBSD: stable/11/usr.bin/dtc/dtb.cc 358206 2020-02-21 04:38:59Z kevans $
33333549Sdes */
34333549Sdes
35333549Sdes#include "dtb.hh"
36333549Sdes#include <sys/types.h>
37333549Sdes#include <inttypes.h>
38333549Sdes#include <stdio.h>
39333549Sdes#include <stdlib.h>
40333549Sdes#include <unistd.h>
41333549Sdes#include <errno.h>
42333549Sdes
43333549Sdesusing std::string;
44333549Sdes
45333549Sdesnamespace {
46333549Sdes
47333549Sdesvoid write(dtc::byte_buffer &buffer, int fd)
48333549Sdes{
49333549Sdes	size_t size = buffer.size();
50333549Sdes	uint8_t *data = buffer.data();
51333549Sdes	while (size > 0)
52333549Sdes	{
53333549Sdes		ssize_t r = ::write(fd, data, size);
54333549Sdes		if (r >= 0)
55333549Sdes		{
56333549Sdes			data += r;
57333549Sdes			size -= r;
58333549Sdes		}
59333549Sdes		else if (errno != EAGAIN)
60333549Sdes		{
61333549Sdes			fprintf(stderr, "Writing to file failed\n");
62333549Sdes			exit(-1);
63333549Sdes		}
64333549Sdes	}
65333549Sdes}
66333549Sdes}
67333549Sdes
68333549Sdesnamespace dtc
69333549Sdes{
70333549Sdesnamespace dtb
71333549Sdes{
72333549Sdes
73333549Sdesvoid output_writer::write_data(byte_buffer b)
74333549Sdes{
75333549Sdes	for (auto i : b)
76333549Sdes	{
77333549Sdes		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