xref: /freebsd/usr.bin/dtc/dtb.cc (revision 6be3386466ab79a84b48429ae66244f21526d3df)
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$
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 
43 using std::string;
44 
45 namespace {
46 
47 void 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 
68 namespace dtc
69 {
70 namespace dtb
71 {
72 
73 void output_writer::write_data(byte_buffer b)
74 {
75 	for (auto i : b)
76 	{
77 		write_data(i);
78 	}
79 }
80 
81 void
82 binary_writer::write_string(const string &name)
83 {
84 	push_string(buffer, name);
85 	// Trailing nul
86 	buffer.push_back(0);
87 }
88 
89 void
90 binary_writer::write_data(uint8_t v)
91 {
92 	buffer.push_back(v);
93 }
94 
95 void
96 binary_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 
105 void
106 binary_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 
115 void
116 binary_writer::write_to_file(int fd)
117 {
118 	write(buffer, fd);
119 }
120 
121 uint32_t
122 binary_writer::size()
123 {
124 	return buffer.size();
125 }
126 
127 void
128 asm_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 
138 void
139 asm_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 
162 void
163 asm_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 
178 void
179 asm_writer::write_comment(const string &name)
180 {
181 	write_line("\t/* ");
182 	push_string(buffer, name);
183 	write_string(" */\n");
184 }
185 
186 void
187 asm_writer::write_string(const char *c)
188 {
189 	while (*c)
190 	{
191 		buffer.push_back((uint8_t)*(c++));
192 	}
193 }
194 
195 
196 void
197 asm_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 
205 void
206 asm_writer::write_data(uint8_t v)
207 {
208 	write_byte(v);
209 	bytes_written++;
210 }
211 
212 void
213 asm_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 
227 void
228 asm_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 
246 void
247 asm_writer::write_to_file(int fd)
248 {
249 	write(buffer, fd);
250 }
251 
252 uint32_t
253 asm_writer::size()
254 {
255 	return bytes_written;
256 }
257 
258 void
259 header::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 
285 bool
286 header::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 }
309 uint32_t
310 string_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 
328 void
329 string_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