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#ifndef _DTB_HH_
34#define _DTB_HH_
35#include <map>
36#include <string>
37
38#include <assert.h>
39
40#include "input_buffer.hh"
41#include "util.hh"
42
43namespace dtc
44{
45/**
46 * The dtb namespace contains code related to the generation of device tree
47 * blobs, the binary representation of flattened device trees.  The abstract
48 * tree representation calls into this code to generate the output.
49 */
50namespace dtb
51{
52/** The token types in the DTB, as defined by ��7.4.1 of the ePAPR
53 * specification.  All of these values are written in big-endian format in the
54 * output.
55 */
56enum token_type
57{
58	/**
59	 * Marker indicating the start of a node in the tree.  This is followed
60	 * by the nul-terminated name.  If a unit address is specified, then
61	 * the name also contains the address, with an @ symbol between the end
62	 * of the name and the start of the address.
63	 *
64	 * The name is then padded such that the next token begins on a 4-byte
65	 * boundary.  The node may contain properties, other nodes, both, or be
66	 * empty.
67	 */
68	FDT_BEGIN_NODE = 0x00000001,
69	/**
70	 * Marker indicating the end of a node.
71	 */
72	FDT_END_NODE   = 0x00000002,
73	/**
74	 * The start of a property.  This is followed by two 32-bit big-endian
75	 * values.  The first indicates the length of the property value, the
76	 * second its index in the strings table.  It is then followed by the
77	 * property value, if the value is of non-zero length.
78	 */
79	FDT_PROP       = 0x00000003,
80	/**
81	 * Ignored token.  May be used for padding inside DTB nodes.
82	 */
83	FDT_NOP        = 0x00000004,
84	/**
85	 * Marker indicating the end of the tree.
86	 */
87	FDT_END        = 0x00000009
88};
89
90/**
91 * Returns the token as a string.  This is used for debugging and for printing
92 * human-friendly error messages about malformed DTB input.
93 */
94inline const char *token_type_name(token_type t)
95{
96	switch(t)
97	{
98		case FDT_BEGIN_NODE:
99			return "FDT_BEGIN_NODE";
100		case FDT_END_NODE:
101			return "FDT_END_NODE";
102		case FDT_PROP:
103			return "FDT_PROP";
104		case FDT_NOP:
105			return "FDT_NOP";
106		case FDT_END:
107			return "FDT_END";
108	}
109	assert(0);
110	// Not reached.
111	return nullptr;
112}
113
114/**
115 * Abstract class for writing a section of the output.  We create one
116 * of these for each section that needs to be written.  It is intended to build
117 * a temporary buffer of the output in memory and then write it to a file
118 * stream.  The size can be returned after all of the data has been written
119 * into the internal buffer, so the sizes of the three tables can be calculated
120 * before storing them in the buffer.
121 */
122struct output_writer
123{
124	/**
125	 * Writes a label into the output stream.  This is only applicable for
126	 * assembly output, where the labels become symbols that can be
127	 * resolved at link time.
128	 */
129	virtual void write_label(const std::string &name)   = 0;
130	/**
131	 * Writes a comment into the output stream.  Useful only when debugging
132	 * the output.
133	 */
134	virtual void write_comment(const std::string &name) = 0;
135	/**
136	 * Writes a string.  A nul terminator is implicitly added.
137	 */
138	virtual void write_string(const std::string &name)  = 0;
139	/**
140	 * Writes a single 8-bit value.
141	 */
142	virtual void write_data(uint8_t)        = 0;
143	/**
144	 * Writes a single 32-bit value.  The value is written in big-endian
145	 * format, but should be passed in the host's native endian.
146	 */
147	virtual void write_data(uint32_t)       = 0;
148	/**
149	 * Writes a single 64-bit value.  The value is written in big-endian
150	 * format, but should be passed in the host's native endian.
151	 */
152	virtual void write_data(uint64_t)       = 0;
153	/**
154	 * Writes the collected output to the specified file descriptor.
155	 */
156	virtual void write_to_file(int fd)      = 0;
157	/**
158	 * Returns the number of bytes.
159	 */
160	virtual uint32_t size()                 = 0;
161	/**
162	 * Helper for writing tokens to the output stream.  This writes a
163	 * comment above the token describing its value, for easier debugging
164	 * of the output.
165	 */
166	inline void write_token(token_type t)
167	{
168		write_comment(token_type_name(t));
169		write_data((uint32_t)t);
170	}
171	/**
172	 * Helper function that writes a byte buffer to the output, one byte at
173	 * a time.
174	 */
175	void write_data(byte_buffer b);
176};
177
178/**
179 * Binary file writer.  This class is responsible for writing the DTB output
180 * directly in blob format.
181 */
182class binary_writer : public output_writer
183{
184	/**
185	 * The internal buffer used to store the blob while it is being
186	 * constructed.
187	 */
188	byte_buffer buffer;
189	public:
190	/**
191	 *  The binary format does not support labels, so this method
192	 * does nothing.
193	 */
194	void write_label(const std::string &) override {}
195	/**
196	 * Comments are ignored by the binary writer.
197	 */
198	void write_comment(const std::string&)  override {}
199	void write_string(const std::string &name) override;
200	void write_data(uint8_t v) override;
201	void write_data(uint32_t v) override;
202	void write_data(uint64_t v) override;
203	void write_to_file(int fd) override;
204	uint32_t size() override;
205};
206/**
207 * Assembly writer.  This class is responsible for writing the output in an
208 * assembly format that is suitable for linking into a kernel, loader, and so
209 * on.
210 */
211class asm_writer : public output_writer
212{
213	/**
214	 * The internal buffer for temporary values.  Note that this actually
215	 * contains ASCII text, but it is a byte buffer so that we can just
216	 * copy strings across as-is.
217	 */
218	byte_buffer buffer;
219	/**
220	 * The number of bytes written to the current line.  This is used to
221	 * allow line wrapping, where we aim to write four .byte directives to
222	 * make the alignment clearer.
223	 */
224	int byte_count;
225	/**
226	 * The current number of bytes written.  This is the number in binary
227	 * format, not the number of bytes in the buffer.
228	 */
229	uint32_t bytes_written;
230
231	/**
232	 * Writes a string directly to the output as-is.  This is the function that
233	 * performs the real output.
234	 */
235	void write_string(const char *c);
236	/**
237	 * Write a string to the output.
238	 */
239	void write_string(const std::string &c) override;
240	/**
241	 * Writes the string, starting on a new line.
242	 */
243	void write_line(const char *c);
244	/**
245	 * Writes a byte in binary format.  This will emit a single .byte
246	 * directive, with up to four per line.
247	 */
248	void write_byte(uint8_t b);
249	public:
250	asm_writer() : byte_count(0), bytes_written(0) {}
251	void write_label(const std::string &name) override;
252	void write_comment(const std::string &name) override;
253	void write_data(uint8_t v) override;
254	void write_data(uint32_t v) override;
255	void write_data(uint64_t v) override;
256	void write_to_file(int fd) override;
257	uint32_t size() override;
258};
259
260/**
261 * Class encapsulating the device tree blob header.  This class stores all of
262 * the values found in the header and is responsible for writing them to the
263 * output.
264 */
265struct header
266{
267	/**
268	 * Magic value, used to validate that this really is a device tree
269	 * blob.  Should always be set to 0xd00dfeed.
270	 */
271	uint32_t magic;
272	/**
273	 * The total size of the blob, including header, reservations, strings
274	 * table, and padding.
275	 */
276	uint32_t totalsize;
277	/**
278	 * The offset from the start of the blob of the struct table (i.e. the
279	 * part of the blob containing the entire device tree).
280	 */
281	uint32_t off_dt_struct;
282	/**
283	 * The offset from the start of the blob of the strings table.
284	 */
285	uint32_t off_dt_strings;
286	/**
287	 * The offset of the reservation map from the start of the blob.
288	 */
289	uint32_t off_mem_rsvmap;
290	/**
291	 * The version of the blob.  This should always be 17.
292	 */
293	uint32_t version;
294	/**
295	 * The earliest version of the DTB specification with which this blob
296	 * is backwards compatible.  This should always be 16.
297	 */
298	uint32_t last_comp_version;
299	/**
300	 * The ID of the CPU where this boots.
301	 */
302	uint32_t boot_cpuid_phys;
303	/**
304	 * The size of the strings table.
305	 */
306	uint32_t size_dt_strings;
307	/**
308	 * The size of the struct table.
309	 */
310	uint32_t size_dt_struct;
311	/**
312	 * Writes the entire header to the specified output buffer.
313	 */
314	void write(output_writer &out);
315	/**
316	 * Reads the header from bits binary representation in a blob.
317	 */
318	bool read_dtb(input_buffer &input);
319	/**
320	 * Default constructor.  Initialises the values that have sensible
321	 * defaults, leaves the others blank.
322	 */
323	header() : magic(0xd00dfeed), version(17), last_comp_version(16),
324		boot_cpuid_phys(0) {}
325};
326
327/**
328 * Class encapsulating the string table.  FDT strings are stored in a string
329 * section.  This maintains a map from strings to their offsets in the strings
330 * section.
331 *
332 * Note: We don't currently do suffix matching, which may save a small amount
333 * of space.
334 */
335class string_table {
336	/**
337	 * Map from strings to their offset.
338	 */
339	std::map<std::string, uint32_t> string_offsets;
340	/**
341	 * The strings, in the order in which they should be written to the
342	 * output.  The order must be stable - adding another string must not
343	 * change the offset of any that we have already referenced - and so we
344	 * simply write the strings in the order that they are passed.
345	 */
346	std::vector<std::string> strings;
347	/**
348	 * The current size of the strings section.
349	 */
350	uint32_t size;
351	public:
352	/**
353	 * Default constructor, creates an empty strings table.
354	 */
355	string_table() : size(0) {}
356	/**
357	 * Adds a string to the table, returning the offset from the start
358	 * where it will be written.  If the string is already present, this
359	 * will return its existing offset, otherwise it will return a new
360	 * offset.
361	 */
362	uint32_t add_string(const std::string &str);
363	/**
364	 * Writes the strings table to the specified output.
365	 */
366	void write(dtb::output_writer &writer);
367};
368
369} // namespace dtb
370
371} // namespace dtc
372
373#endif // !_DTB_HH_
374