Browse Source

[fdt] Add ability to parse a MAC address from a flattened device tree

The Raspberry Pi NIC has no EEPROM to hold the MAC address.  The
platform firmware (e.g. UEFI or U-Boot) will typically obtain the MAC
address from the VideoCore firmware and add it to the device tree,
which is then made available to subsequent programs such as iPXE or
the Linux kernel.

Add the ability to parse a flattened device tree and to extract the
MAC address.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 4 years ago
parent
commit
e520a51df1
5 changed files with 643 additions and 0 deletions
  1. 38
    0
      src/config/config_fdt.c
  2. 16
    0
      src/config/fdt.h
  3. 486
    0
      src/core/fdt.c
  4. 1
    0
      src/include/ipxe/errfile.h
  5. 102
    0
      src/include/ipxe/fdt.h

+ 38
- 0
src/config/config_fdt.c View File

@@ -0,0 +1,38 @@
1
+/*
2
+ * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <config/fdt.h>
27
+
28
+/** @file
29
+ *
30
+ * Flattened Device Tree configuration options
31
+ *
32
+ */
33
+
34
+PROVIDE_REQUIRING_SYMBOL();
35
+
36
+/*
37
+ * Drag in devicetree sources
38
+ */

+ 16
- 0
src/config/fdt.h View File

@@ -0,0 +1,16 @@
1
+#ifndef CONFIG_FDT_H
2
+#define CONFIG_FDT_H
3
+
4
+/** @file
5
+ *
6
+ * Flattened Device Tree configuration
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include <config/defaults.h>
13
+
14
+#include <config/local/fdt.h>
15
+
16
+#endif /* CONFIG_FDT_H */

+ 486
- 0
src/core/fdt.c View File

@@ -0,0 +1,486 @@
1
+/*
2
+ * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <string.h>
27
+#include <errno.h>
28
+#include <assert.h>
29
+#include <byteswap.h>
30
+#include <ipxe/netdevice.h>
31
+#include <ipxe/fdt.h>
32
+
33
+/** @file
34
+ *
35
+ * Flattened Device Tree
36
+ *
37
+ */
38
+
39
+/** The system flattened device tree (if present) */
40
+static struct fdt fdt;
41
+
42
+/** A position within a device tree */
43
+struct fdt_cursor {
44
+	/** Offset within structure block */
45
+	unsigned int offset;
46
+	/** Tree depth */
47
+	int depth;
48
+};
49
+
50
+/** A lexical descriptor */
51
+struct fdt_descriptor {
52
+	/** Node or property name (if applicable) */
53
+	const char *name;
54
+	/** Property data (if applicable) */
55
+	const void *data;
56
+	/** Length of property data (if applicable) */
57
+	size_t len;
58
+};
59
+
60
+/**
61
+ * Check if device tree exists
62
+ *
63
+ * @v has_fdt		Device tree exists
64
+ */
65
+static inline __attribute__ (( always_inline )) int fdt_exists ( void ) {
66
+
67
+	return ( fdt.hdr != NULL );
68
+}
69
+
70
+/**
71
+ * Traverse device tree
72
+ *
73
+ * @v pos		Position within device tree
74
+ * @v desc		Lexical descriptor to fill in
75
+ * @ret rc		Return status code
76
+ */
77
+static int fdt_traverse ( struct fdt_cursor *pos,
78
+			  struct fdt_descriptor *desc ) {
79
+	const fdt_token_t *token;
80
+	const void *data;
81
+	const struct fdt_prop *prop;
82
+	unsigned int name_off;
83
+	size_t remaining;
84
+	size_t len;
85
+
86
+	/* Sanity checks */
87
+	assert ( pos->offset < fdt.len );
88
+	assert ( ( pos->offset & ( FDT_STRUCTURE_ALIGN - 1 ) ) == 0 );
89
+
90
+	/* Clear descriptor */
91
+	memset ( desc, 0, sizeof ( *desc ) );
92
+
93
+	/* Locate token and calculate remaining space */
94
+	token = ( fdt.raw + fdt.structure + pos->offset );
95
+	remaining = ( fdt.len - pos->offset );
96
+	if ( remaining < sizeof ( *token ) ) {
97
+		DBGC ( &fdt, "FDT truncated tree at +%#04x\n", pos->offset );
98
+		return -EINVAL;
99
+	}
100
+	remaining -= sizeof ( *token );
101
+	data = ( ( ( const void * ) token ) + sizeof ( *token ) );
102
+	len = 0;
103
+
104
+	/* Handle token */
105
+	switch ( *token ) {
106
+
107
+	case cpu_to_be32 ( FDT_BEGIN_NODE ):
108
+
109
+		/* Start of node */
110
+		desc->name = data;
111
+		len = ( strnlen ( desc->name, remaining ) + 1 /* NUL */ );
112
+		if ( remaining < len ) {
113
+			DBGC ( &fdt, "FDT unterminated node name at +%#04x\n",
114
+			       pos->offset );
115
+			return -EINVAL;
116
+		}
117
+		pos->depth++;
118
+		break;
119
+
120
+	case cpu_to_be32 ( FDT_END_NODE ):
121
+
122
+		/* End of node */
123
+		if ( pos->depth < 0 ) {
124
+			DBGC ( &fdt, "FDT spurious node end at +%#04x\n",
125
+			       pos->offset );
126
+			return -EINVAL;
127
+		}
128
+		pos->depth--;
129
+		if ( pos->depth < 0 ) {
130
+			/* End of (sub)tree */
131
+			return -ENOENT;
132
+		}
133
+		break;
134
+
135
+	case cpu_to_be32 ( FDT_PROP ):
136
+
137
+		/* Property */
138
+		prop = data;
139
+		if ( remaining < sizeof ( *prop ) ) {
140
+			DBGC ( &fdt, "FDT truncated property at +%#04x\n",
141
+			       pos->offset );
142
+			return -EINVAL;
143
+		}
144
+		desc->data = ( ( ( const void * ) prop ) + sizeof ( *prop ) );
145
+		desc->len = be32_to_cpu ( prop->len );
146
+		len = ( sizeof ( *prop ) + desc->len );
147
+		if ( remaining < len ) {
148
+			DBGC ( &fdt, "FDT overlength property at +%#04x\n",
149
+			       pos->offset );
150
+			return -EINVAL;
151
+		}
152
+		name_off = be32_to_cpu ( prop->name_off );
153
+		if ( name_off > fdt.strings_len ) {
154
+			DBGC ( &fdt, "FDT property name outside strings "
155
+			       "block at +%#04x\n", pos->offset );
156
+			return -EINVAL;
157
+		}
158
+		desc->name = ( fdt.raw + fdt.strings + name_off );
159
+		break;
160
+
161
+	case cpu_to_be32 ( FDT_NOP ):
162
+
163
+		/* Do nothing */
164
+		break;
165
+
166
+	default:
167
+
168
+		/* Unrecognised or unexpected token */
169
+		DBGC ( &fdt, "FDT unexpected token %#08x at +%#04x\n",
170
+		       be32_to_cpu ( *token ), pos->offset );
171
+		return -EINVAL;
172
+	}
173
+
174
+	/* Update cursor */
175
+	len = ( ( len + FDT_STRUCTURE_ALIGN - 1 ) &
176
+		~( FDT_STRUCTURE_ALIGN - 1 ) );
177
+	pos->offset += ( sizeof ( *token ) + len );
178
+
179
+	/* Sanity checks */
180
+	assert ( pos->offset <= fdt.len );
181
+
182
+	return 0;
183
+}
184
+
185
+/**
186
+ * Find child node
187
+ *
188
+ * @v offset		Starting node offset
189
+ * @v name		Node name
190
+ * @v child		Child node offset to fill in
191
+ * @ret rc		Return status code
192
+ */
193
+static int fdt_child ( unsigned int offset, const char *name,
194
+		       unsigned int *child ) {
195
+	struct fdt_cursor pos;
196
+	struct fdt_descriptor desc;
197
+	unsigned int orig_offset;
198
+	int rc;
199
+
200
+	/* Record original offset (for debugging) */
201
+	orig_offset = offset;
202
+
203
+	/* Initialise cursor */
204
+	pos.offset = offset;
205
+	pos.depth = -1;
206
+
207
+	/* Find child node */
208
+	while ( 1 ) {
209
+
210
+		/* Record current offset */
211
+		*child = pos.offset;
212
+
213
+		/* Traverse tree */
214
+		if ( ( rc = fdt_traverse ( &pos, &desc ) ) != 0 ) {
215
+			DBGC ( &fdt, "FDT +%#04x has no child node \"%s\": "
216
+			       "%s\n", orig_offset, name, strerror ( rc ) );
217
+			return rc;
218
+		}
219
+
220
+		/* Check for matching immediate child node */
221
+		if ( ( pos.depth == 1 ) && desc.name && ( ! desc.data ) ) {
222
+			DBGC2 ( &fdt, "FDT +%#04x has child node \"%s\"\n",
223
+				orig_offset, desc.name );
224
+			if ( strcmp ( name, desc.name ) == 0 ) {
225
+				DBGC2 ( &fdt, "FDT +%#04x found child node "
226
+					"\"%s\" at +%#04x\n", orig_offset,
227
+					desc.name, *child );
228
+				return 0;
229
+			}
230
+		}
231
+	}
232
+}
233
+
234
+/**
235
+ * Find node by path
236
+ *
237
+ * @v path		Node path
238
+ * @v offset		Offset to fill in
239
+ * @ret rc		Return status code
240
+ */
241
+int fdt_path ( const char *path, unsigned int *offset ) {
242
+	char *tmp = ( ( char * ) path );
243
+	char *del;
244
+	int rc;
245
+
246
+	/* Initialise offset */
247
+	*offset = 0;
248
+
249
+	/* Traverse tree one path segment at a time */
250
+	while ( *tmp ) {
251
+
252
+		/* Skip any leading '/' */
253
+		while ( *tmp == '/' )
254
+			tmp++;
255
+
256
+		/* Find next '/' delimiter and convert to NUL */
257
+		del = strchr ( tmp, '/' );
258
+		if ( del )
259
+			*del = '\0';
260
+
261
+		/* Find child and restore delimiter */
262
+		rc = fdt_child ( *offset, tmp, offset );
263
+		if ( del )
264
+			*del = '/';
265
+		if ( rc != 0 )
266
+			return rc;
267
+
268
+		/* Move to next path component, if any */
269
+		while ( *tmp && ( *tmp != '/' ) )
270
+			tmp++;
271
+	}
272
+
273
+	DBGC2 ( &fdt, "FDT found path \"%s\" at +%#04x\n", path, *offset );
274
+	return 0;
275
+}
276
+
277
+/**
278
+ * Find node by alias
279
+ *
280
+ * @v name		Alias name
281
+ * @v offset		Offset to fill in
282
+ * @ret rc		Return status code
283
+ */
284
+int fdt_alias ( const char *name, unsigned int *offset ) {
285
+	const char *alias;
286
+	int rc;
287
+
288
+	/* Locate "/aliases" node */
289
+	if ( ( rc = fdt_child ( 0, "aliases", offset ) ) != 0 )
290
+		return rc;
291
+
292
+	/* Locate alias property */
293
+	if ( ( alias = fdt_string ( *offset, name ) ) == NULL )
294
+		return -ENOENT;
295
+	DBGC ( &fdt, "FDT alias \"%s\" is \"%s\"\n", name, alias );
296
+
297
+	/* Locate aliased node */
298
+	if ( ( rc = fdt_path ( alias, offset ) ) != 0 )
299
+		return rc;
300
+
301
+	return 0;
302
+}
303
+
304
+/**
305
+ * Find property
306
+ *
307
+ * @v offset		Starting node offset
308
+ * @v name		Property name
309
+ * @v desc		Lexical descriptor to fill in
310
+ * @ret rc		Return status code
311
+ */
312
+static int fdt_property ( unsigned int offset, const char *name,
313
+			  struct fdt_descriptor *desc ) {
314
+	struct fdt_cursor pos;
315
+	int rc;
316
+
317
+	/* Initialise cursor */
318
+	pos.offset = offset;
319
+	pos.depth = -1;
320
+
321
+	/* Find property */
322
+	while ( 1 ) {
323
+
324
+		/* Traverse tree */
325
+		if ( ( rc = fdt_traverse ( &pos, desc ) ) != 0 ) {
326
+			DBGC ( &fdt, "FDT +%#04x has no property \"%s\": %s\n",
327
+			       offset, name, strerror ( rc ) );
328
+			return rc;
329
+		}
330
+
331
+		/* Check for matching immediate child property */
332
+		if ( ( pos.depth == 0 ) && desc->data ) {
333
+			DBGC2 ( &fdt, "FDT +%#04x has property \"%s\" len "
334
+				"%#zx\n", offset, desc->name, desc->len );
335
+			if ( strcmp ( name, desc->name ) == 0 ) {
336
+				DBGC2 ( &fdt, "FDT +%#04x found property "
337
+					"\"%s\"\n", offset, desc->name );
338
+				DBGC2_HDA ( &fdt, 0, desc->data, desc->len );
339
+				return 0;
340
+			}
341
+		}
342
+	}
343
+}
344
+
345
+/**
346
+ * Find string property
347
+ *
348
+ * @v offset		Starting node offset
349
+ * @v name		Property name
350
+ * @ret string		String property, or NULL on error
351
+ */
352
+const char * fdt_string ( unsigned int offset, const char *name ) {
353
+	struct fdt_descriptor desc;
354
+	int rc;
355
+
356
+	/* Find property */
357
+	if ( ( rc = fdt_property ( offset, name, &desc ) ) != 0 )
358
+		return NULL;
359
+
360
+	/* Check NUL termination */
361
+	if ( strnlen ( desc.data, desc.len ) == desc.len ) {
362
+		DBGC ( &fdt, "FDT unterminated string property \"%s\"\n",
363
+		       name );
364
+		return NULL;
365
+	}
366
+
367
+	return desc.data;
368
+}
369
+
370
+/**
371
+ * Get MAC address from property
372
+ *
373
+ * @v offset		Starting node offset
374
+ * @v netdev		Network device
375
+ * @ret rc		Return status code
376
+ */
377
+int fdt_mac ( unsigned int offset, struct net_device *netdev ) {
378
+	struct fdt_descriptor desc;
379
+	size_t len;
380
+	int rc;
381
+
382
+	/* Find applicable MAC address property */
383
+	if ( ( ( rc = fdt_property ( offset, "mac-address", &desc ) ) != 0 ) &&
384
+	     ( ( rc = fdt_property ( offset, "local-mac-address",
385
+				     &desc ) ) != 0 ) ) {
386
+		return rc;
387
+	}
388
+
389
+	/* Check length */
390
+	len = netdev->ll_protocol->hw_addr_len;
391
+	if ( len != desc.len ) {
392
+		DBGC ( &fdt, "FDT malformed MAC address \"%s\":\n",
393
+		       desc.name );
394
+		DBGC_HDA ( &fdt, 0, desc.data, desc.len );
395
+		return -ERANGE;
396
+	}
397
+
398
+	/* Fill in MAC address */
399
+	memcpy ( netdev->hw_addr, desc.data, len );
400
+
401
+	return 0;
402
+}
403
+
404
+/**
405
+ * Register device tree
406
+ *
407
+ * @v fdt		Device tree header
408
+ * @ret rc		Return status code
409
+ */
410
+int register_fdt ( const struct fdt_header *hdr ) {
411
+	const uint8_t *end;
412
+
413
+	/* Record device tree location */
414
+	fdt.hdr = hdr;
415
+	fdt.len = be32_to_cpu ( hdr->totalsize );
416
+	DBGC ( &fdt, "FDT version %d at %p+%#04zx\n",
417
+	       be32_to_cpu ( hdr->version ), fdt.hdr, fdt.len );
418
+
419
+	/* Check signature */
420
+	if ( hdr->magic != cpu_to_be32 ( FDT_MAGIC ) ) {
421
+		DBGC ( &fdt, "FDT has invalid magic value %#08x\n",
422
+		       be32_to_cpu ( hdr->magic ) );
423
+		goto err;
424
+	}
425
+
426
+	/* Check version */
427
+	if ( hdr->last_comp_version != cpu_to_be32 ( FDT_VERSION ) ) {
428
+		DBGC ( &fdt, "FDT unsupported version %d\n",
429
+		       be32_to_cpu ( hdr->last_comp_version ) );
430
+		goto err;
431
+	}
432
+
433
+	/* Record structure block location */
434
+	fdt.structure = be32_to_cpu ( hdr->off_dt_struct );
435
+	fdt.structure_len = be32_to_cpu ( hdr->size_dt_struct );
436
+	DBGC ( &fdt, "FDT structure block at +[%#04x,%#04zx)\n",
437
+	       fdt.structure, ( fdt.structure + fdt.structure_len ) );
438
+	if ( ( fdt.structure > fdt.len ) ||
439
+	     ( fdt.structure_len > ( fdt.len - fdt.structure ) ) ) {
440
+		DBGC ( &fdt, "FDT structure block exceeds table\n" );
441
+		goto err;
442
+	}
443
+	if ( ( fdt.structure | fdt.structure_len ) &
444
+	     ( FDT_STRUCTURE_ALIGN - 1 ) ) {
445
+		DBGC ( &fdt, "FDT structure block is misaligned\n" );
446
+		goto err;
447
+	}
448
+
449
+	/* Record strings block location */
450
+	fdt.strings = be32_to_cpu ( hdr->off_dt_strings );
451
+	fdt.strings_len = be32_to_cpu ( hdr->size_dt_strings );
452
+	DBGC ( &fdt, "FDT strings block at +[%#04x,%#04zx)\n",
453
+	       fdt.strings, ( fdt.strings + fdt.strings_len ) );
454
+	if ( ( fdt.strings > fdt.len ) ||
455
+	     ( fdt.strings_len > ( fdt.len - fdt.strings ) ) ) {
456
+		DBGC ( &fdt, "FDT strings block exceeds table\n" );
457
+		goto err;
458
+	}
459
+
460
+	/* Shrink strings block to ensure NUL termination safety */
461
+	end = ( fdt.raw + fdt.strings + fdt.strings_len );
462
+	for ( ; fdt.strings_len ; fdt.strings_len-- ) {
463
+		if ( *(--end) == '\0' )
464
+			break;
465
+	}
466
+	if ( fdt.strings_len != be32_to_cpu ( hdr->size_dt_strings ) ) {
467
+		DBGC ( &fdt, "FDT strings block shrunk to +[%#04x,%#04zx)\n",
468
+		       fdt.strings, ( fdt.strings + fdt.strings_len ) );
469
+	}
470
+
471
+	/* Print model name (for debugging) */
472
+	DBGC ( &fdt, "FDT model is \"%s\"\n", fdt_string ( 0, "model" ) );
473
+
474
+	return 0;
475
+
476
+ err:
477
+	DBGC_HDA ( &fdt, 0, hdr, sizeof ( *hdr ) );
478
+	fdt.hdr = NULL;
479
+	return -EINVAL;
480
+}
481
+
482
+/* Drag in objects via register_fdt */
483
+REQUIRING_SYMBOL ( register_fdt );
484
+
485
+/* Drag in device tree configuration */
486
+REQUIRE_OBJECT ( config_fdt );

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -74,6 +74,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
74 74
 #define ERRFILE_efi_block	       ( ERRFILE_CORE | 0x00220000 )
75 75
 #define ERRFILE_sanboot		       ( ERRFILE_CORE | 0x00230000 )
76 76
 #define ERRFILE_dummy_sanboot	       ( ERRFILE_CORE | 0x00240000 )
77
+#define ERRFILE_fdt		       ( ERRFILE_CORE | 0x00250000 )
77 78
 
78 79
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
79 80
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

+ 102
- 0
src/include/ipxe/fdt.h View File

@@ -0,0 +1,102 @@
1
+#ifndef _IPXE_FDT_H
2
+#define _IPXE_FDT_H
3
+
4
+/** @file
5
+ *
6
+ * Flattened Device Tree
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include <stdint.h>
13
+
14
+struct net_device;
15
+
16
+/** Device tree header */
17
+struct fdt_header {
18
+	/** Magic signature */
19
+	uint32_t magic;
20
+	/** Total size of device tree */
21
+	uint32_t totalsize;
22
+	/** Offset to structure block */
23
+	uint32_t off_dt_struct;
24
+	/** Offset to strings block */
25
+	uint32_t off_dt_strings;
26
+	/** Offset to memory reservation block */
27
+	uint32_t off_mem_rsvmap;
28
+	/** Version of this data structure */
29
+	uint32_t version;
30
+	/** Lowest version to which this structure is compatible */
31
+	uint32_t last_comp_version;
32
+	/** Physical ID of the boot CPU */
33
+	uint32_t boot_cpuid_phys;
34
+	/** Length of string block */
35
+	uint32_t size_dt_strings;
36
+	/** Length of structure block */
37
+	uint32_t size_dt_struct;
38
+} __attribute__ (( packed ));
39
+
40
+/** Magic signature */
41
+#define FDT_MAGIC 0xd00dfeed
42
+
43
+/** Expected device tree version */
44
+#define FDT_VERSION 16
45
+
46
+/** Device tree token */
47
+typedef uint32_t fdt_token_t;
48
+
49
+/** Begin node token */
50
+#define FDT_BEGIN_NODE 0x00000001
51
+
52
+/** End node token */
53
+#define FDT_END_NODE 0x00000002
54
+
55
+/** Property token */
56
+#define FDT_PROP 0x00000003
57
+
58
+/** Property fragment */
59
+struct fdt_prop {
60
+	/** Data length */
61
+	uint32_t len;
62
+	/** Name offset */
63
+	uint32_t name_off;
64
+} __attribute__ (( packed ));
65
+
66
+/** NOP token */
67
+#define FDT_NOP 0x00000004
68
+
69
+/** End of structure block */
70
+#define FDT_END 0x00000009
71
+
72
+/** Alignment of structure block */
73
+#define FDT_STRUCTURE_ALIGN ( sizeof ( fdt_token_t ) )
74
+
75
+/** A device tree */
76
+struct fdt {
77
+	/** Tree data */
78
+	union {
79
+		/** Tree header */
80
+		const struct fdt_header *hdr;
81
+		/** Raw data */
82
+		const void *raw;
83
+	};
84
+	/** Length of tree */
85
+	size_t len;
86
+	/** Offset to structure block */
87
+	unsigned int structure;
88
+	/** Length of structure block */
89
+	size_t structure_len;
90
+	/** Offset to strings block */
91
+	unsigned int strings;
92
+	/** Length of strings block */
93
+	size_t strings_len;
94
+};
95
+
96
+extern int fdt_path ( const char *path, unsigned int *offset );
97
+extern int fdt_alias ( const char *name, unsigned int *offset );
98
+extern const char * fdt_string ( unsigned int offset, const char *name );
99
+extern int fdt_mac ( unsigned int offset, struct net_device *netdev );
100
+extern int register_fdt ( const struct fdt_header *hdr );
101
+
102
+#endif /* _IPXE_FDT_H */

Loading…
Cancel
Save