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