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