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
40namespace dtc
41{
42namespace dtb
43{
44
45void output_writer::write_data(byte_buffer b)
46{
47	for (byte_buffer::iterator i=b.begin(), e=b.end(); i!=e ; i++)
48	{
49		write_data(*i);
50	}
51}
52
53void
54binary_writer::write_string(string name)
55{
56	name.push_to_buffer(buffer);
57	// Trailing nul
58	buffer.push_back(0);
59}
60
61void
62binary_writer::write_data(uint8_t v)
63{
64	buffer.push_back(v);
65}
66
67void
68binary_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
77void
78binary_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
87void
88binary_writer::write_to_file(int fd)
89{
90	// FIXME: Check return
91	write(fd, buffer.data(), buffer.size());
92}
93
94uint32_t
95binary_writer::size()
96{
97	return buffer.size();
98}
99
100void
101asm_writer::write_string(const char *c)
102{
103	while (*c)
104	{
105		buffer.push_back((uint8_t)*(c++));
106	}
107}
108
109void
110asm_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
120void
121asm_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
144void
145asm_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
160void
161asm_writer::write_comment(string name)
162{
163	write_line("\t/* ");
164	name.push_to_buffer(buffer);
165	write_string(" */\n");
166}
167
168void
169asm_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
177void
178asm_writer::write_data(uint8_t v)
179{
180	write_byte(v);
181	bytes_written++;
182}
183
184void
185asm_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
199void
200asm_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
218void
219asm_writer::write_to_file(int fd)
220{
221	// FIXME: Check return
222	write(fd, buffer.data(), buffer.size());
223}
224
225uint32_t
226asm_writer::size()
227{
228	return bytes_written;
229}
230
231void
232header::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
258bool
259header::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}
277uint32_t
278string_table::add_string(string str)
279{
280	std::map<string, uint32_t>::iterator 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
296void
297string_table::write(dtb::output_writer &writer)
298{
299	writer.write_comment(string("Strings table."));
300	writer.write_label(string("dt_strings_start"));
301	for (std::vector<string>::iterator i=strings.begin(), e=strings.end() ;
302	     i!=e ; ++i)
303	{
304		writer.write_string(*i);
305	}
306	writer.write_label(string("dt_strings_end"));
307}
308
309} // namespace dtb
310
311} // namespace dtc
312
313