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