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