iPXE
fdtmem.c File Reference

Flattened Device Tree memory map. More...

#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <ipxe/uaccess.h>
#include <ipxe/memmap.h>
#include <ipxe/io.h>
#include <ipxe/fdt.h>
#include <ipxe/fdtmem.h>

Go to the source code of this file.

Macros

#define FDTMEM_MAX32   0xffffffff
 Maximum 32-bit physical address.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
size_t ABS_SYMBOL (_memsz)
 Total in-memory size (calculated by linker)
size_t ABS_SYMBOL (_max_align)
 Relocation required alignment (defined by prefix or linker)
static int fdtmem_update_node (struct memmap_region *region, struct fdt *fdt, unsigned int offset, const char *match, unsigned int flags)
 Update memory region descriptor based on device tree node.
static int fdtmem_update_tree (struct memmap_region *region, struct fdt *fdt)
 Update memory region descriptor based on device tree.
static void fdtmem_describe (uint64_t min, uint64_t max, struct fdt *fdt, struct memmap_region *region)
 Describe memory region.
static size_t fdtmem_len (struct fdt *fdt)
 Get length for copy of iPXE and device tree.
physaddr_t fdtmem_relocate (struct fdt_header *hdr, physaddr_t max)
 Find a relocation address for iPXE.
int fdtmem_register (struct fdt_header *hdr, physaddr_t max)
 Copy and register system device tree.
static void fdtmem_describe_region (uint64_t min, int hide, struct memmap_region *region)
 Describe memory region from system memory map.
 PROVIDE_MEMMAP (fdt, memmap_describe, fdtmem_describe_region)
 PROVIDE_MEMMAP_INLINE (fdt, memmap_sync)

Variables

char _prefix []
 Start address of the iPXE image.
char _end []
 End address of the iPXE image.
static size_t memsz = ABS_VALUE_INIT ( _memsz )
static size_t max_align = ABS_VALUE_INIT ( _max_align )
struct used_region fdtmem_used __used_region
 In-use memory region for iPXE and system device tree copy.
static physaddr_t fdtmem_max
 Maximum accessible physical address.

Detailed Description

Flattened Device Tree memory map.

Definition in file fdtmem.c.

Macro Definition Documentation

◆ FDTMEM_MAX32

#define FDTMEM_MAX32   0xffffffff

Maximum 32-bit physical address.

Definition at line 66 of file fdtmem.c.

Referenced by fdtmem_relocate().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

References _end, and _prefix.

◆ ABS_SYMBOL() [1/2]

size_t ABS_SYMBOL ( _memsz )
extern

Total in-memory size (calculated by linker)

◆ ABS_SYMBOL() [2/2]

size_t ABS_SYMBOL ( _max_align )
extern

Relocation required alignment (defined by prefix or linker)

◆ fdtmem_update_node()

int fdtmem_update_node ( struct memmap_region * region,
struct fdt * fdt,
unsigned int offset,
const char * match,
unsigned int flags )
static

Update memory region descriptor based on device tree node.

Parameters
regionMemory region of interest to be updated
fdtDevice tree
offsetStarting node offset
matchRequired device type (or NULL)
flagsRegion flags
Return values
rcReturn status code

Definition at line 78 of file fdtmem.c.

80 {
81 struct fdt_descriptor desc;
82 struct fdt_reg_cells regs;
83 const char *devtype;
86 int depth;
87 int count;
88 int index;
89 int rc;
90
91 /* Parse region cell sizes */
93
94 /* Scan through reservations */
95 for ( depth = -1 ; ; depth += desc.depth, offset = desc.next ) {
96
97 /* Describe token */
98 if ( ( rc = fdt_describe ( fdt, offset, &desc ) ) != 0 ) {
99 DBGC ( region, "FDTMEM has malformed node: %s\n",
100 strerror ( rc ) );
101 return rc;
102 }
103
104 /* Terminate when we exit this node */
105 if ( ( depth == 0 ) && ( desc.depth < 0 ) )
106 break;
107
108 /* Ignore any non-immediate child nodes */
109 if ( ! ( ( depth == 0 ) && desc.name && ( ! desc.data ) ) )
110 continue;
111
112 /* Ignore any non-matching children */
113 if ( match ) {
114 devtype = fdt_string ( fdt, desc.offset,
115 "device_type" );
116 if ( ! devtype )
117 continue;
118 if ( strcmp ( devtype, match ) != 0 )
119 continue;
120 }
121
122 /* Count regions */
123 count = fdt_reg_count ( fdt, desc.offset, &regs );
124 if ( count < 0 ) {
125 if ( flags & MEMMAP_FL_RESERVED ) {
126 /* Assume this is a non-fixed reservation */
127 continue;
128 }
129 rc = count;
130 DBGC ( region, "FDTMEM has malformed region %s: %s\n",
131 desc.name, strerror ( rc ) );
132 continue;
133 }
134
135 /* Scan through this region */
136 for ( index = 0 ; index < count ; index++ ) {
137
138 /* Get region starting address and size */
139 if ( ( rc = fdt_reg_address ( fdt, desc.offset, &regs,
140 index, &start ) ) != 0 ){
141 DBGC ( region, "FDTMEM %s region %d has "
142 "malformed start address: %s\n",
143 desc.name, index, strerror ( rc ) );
144 break;
145 }
146 if ( ( rc = fdt_reg_size ( fdt, desc.offset, &regs,
147 index, &size ) ) != 0 ) {
148 DBGC ( region, "FDTMEM %s region %d has "
149 "malformed size: %s\n",
150 desc.name, index, strerror ( rc ) );
151 break;
152 }
153
154 /* Update memory region descriptor */
155 memmap_update ( region, start, size, flags,
156 desc.name );
157 }
158 }
159
160 return 0;
161}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned long long uint64_t
Definition stdint.h:13
long index
Definition bigint.h:65
uint16_t offset
Offset to command line.
Definition bzimage.h:3
uint8_t flags
Flags.
Definition ena.h:7
struct ena_llq_option desc
Descriptor counts.
Definition ena.h:9
int fdt_describe(struct fdt *fdt, unsigned int offset, struct fdt_descriptor *desc)
Describe device tree token.
Definition fdt.c:90
const char * fdt_string(struct fdt *fdt, unsigned int offset, const char *name)
Find string property.
Definition fdt.c:579
int fdt_reg_count(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs)
Get number of regions.
Definition fdt.c:767
int fdt_reg_size(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs, unsigned int index, uint64_t *size)
Get region size.
Definition fdt.c:818
int fdt_reg_address(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs, unsigned int index, uint64_t *address)
Get region address.
Definition fdt.c:793
void fdt_reg_cells(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs)
Get region cell size specification.
Definition fdt.c:716
#define DBGC(...)
Definition compiler.h:505
uint32_t start
Starting offset.
Definition netvsc.h:1
uint16_t size
Buffer size.
Definition dwmac.h:3
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define MEMMAP_FL_RESERVED
Is reserved.
Definition memmap.h:61
void memmap_update(struct memmap_region *region, uint64_t start, uint64_t size, unsigned int flags, const char *name)
Update memory region descriptor.
Definition memmap.c:47
struct i386_regs regs
Definition registers.h:1
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int strcmp(const char *first, const char *second)
Compare strings.
Definition string.c:174
A device tree token descriptor.
Definition fdt.h:121
A device tree region cell size specification.
Definition fdt.h:137
A device tree.
Definition fdt.h:89

References count, DBGC, desc, fdt_describe(), fdt_reg_address(), fdt_reg_cells(), fdt_reg_count(), fdt_reg_size(), fdt_string(), flags, index, MEMMAP_FL_RESERVED, memmap_update(), offset, rc, regs, size, start, strcmp(), and strerror().

Referenced by fdtmem_update_tree().

◆ fdtmem_update_tree()

int fdtmem_update_tree ( struct memmap_region * region,
struct fdt * fdt )
static

Update memory region descriptor based on device tree.

Parameters
regionMemory region of interest to be updated
fdtDevice tree
Return values
rcReturn status code

Definition at line 170 of file fdtmem.c.

171 {
172 const struct fdt_reservation *rsv;
173 unsigned int offset;
174 int rc;
175
176 /* Update based on memory regions in the root node */
177 if ( ( rc = fdtmem_update_node ( region, fdt, 0, "memory",
178 MEMMAP_FL_MEMORY ) ) != 0 )
179 return rc;
180
181 /* Update based on memory reservations block */
183 memmap_update ( region, be64_to_cpu ( rsv->start ),
185 NULL );
186 }
187
188 /* Locate reserved-memory node */
189 if ( ( rc = fdt_path ( fdt, "/reserved-memory", &offset ) ) != 0 ) {
190 DBGC ( region, "FDTMEM could not locate /reserved-memory: "
191 "%s\n", strerror ( rc ) );
192 return rc;
193 }
194
195 /* Update based on memory regions in the reserved-memory node */
196 if ( ( rc = fdtmem_update_node ( region, fdt, offset, NULL,
197 MEMMAP_FL_RESERVED ) ) != 0 )
198 return rc;
199
200 return 0;
201}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
int fdt_path(struct fdt *fdt, const char *path, unsigned int *offset)
Find node by path.
Definition fdt.c:426
static int fdtmem_update_node(struct memmap_region *region, struct fdt *fdt, unsigned int offset, const char *match, unsigned int flags)
Update memory region descriptor based on device tree node.
Definition fdtmem.c:78
#define be64_to_cpu(value)
Definition byteswap.h:118
#define for_each_fdt_reservation(rsv, fdt)
Iterate over memory reservations.
Definition fdt.h:168
#define MEMMAP_FL_MEMORY
Contains memory.
Definition memmap.h:60
A memory reservation.
Definition fdt.h:81
uint64_t start
Starting address.
Definition fdt.h:83
uint64_t size
Length of reservation.
Definition fdt.h:85

References be64_to_cpu, DBGC, fdt_path(), fdtmem_update_node(), for_each_fdt_reservation, MEMMAP_FL_MEMORY, MEMMAP_FL_RESERVED, memmap_update(), NULL, offset, rc, fdt_reservation::size, fdt_reservation::start, and strerror().

Referenced by fdtmem_describe().

◆ fdtmem_describe()

void fdtmem_describe ( uint64_t min,
uint64_t max,
struct fdt * fdt,
struct memmap_region * region )
static

Describe memory region.

Parameters
minMinimum address
maxMaximum accessible physical address
fdtDevice tree
regionRegion descriptor to fill in

Definition at line 211 of file fdtmem.c.

212 {
213 uint64_t inaccessible;
214
215 /* Initialise region */
216 memmap_init ( min, region );
217
218 /* Update region based on device tree */
219 fdtmem_update_tree ( region, fdt );
220
221 /* Treat inaccessible physical memory as such */
222 inaccessible = ( max + 1 );
223 memmap_update ( region, inaccessible, -inaccessible,
225}
#define min(x, y)
Definition ath.h:36
#define max(x, y)
Definition ath.h:41
static int fdtmem_update_tree(struct memmap_region *region, struct fdt *fdt)
Update memory region descriptor based on device tree.
Definition fdtmem.c:170
#define MEMMAP_FL_INACCESSIBLE
Outside of addressable range.
Definition memmap.h:63
static void memmap_init(uint64_t min, struct memmap_region *region)
Initialise memory region descriptor.
Definition memmap.h:72

References fdtmem_update_tree(), max, MEMMAP_FL_INACCESSIBLE, memmap_init(), memmap_update(), min, and NULL.

Referenced by fdtmem_describe_region(), and fdtmem_relocate().

◆ fdtmem_len()

size_t fdtmem_len ( struct fdt * fdt)
static

Get length for copy of iPXE and device tree.

Parameters
fdtDevice tree
Return values
lenTotal length

Definition at line 233 of file fdtmem.c.

233 {
234 size_t len;
235
236 /* Calculate total length and check device tree alignment */
237 len = ( memsz + fdt->len );
238 assert ( ( memsz % FDT_MAX_ALIGN ) == 0 );
239
240 /* Align length. Not technically necessary, but keeps the
241 * resulting memory maps looking relatively sane.
242 */
243 len = ( ( len + PAGE_SIZE - 1 ) & ~( PAGE_SIZE - 1 ) );
244
245 return len;
246}
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
ring len
Length.
Definition dwmac.h:226
static size_t memsz
Definition fdtmem.c:51
#define FDT_MAX_ALIGN
Maximum alignment of any block.
Definition fdt.h:78
#define PAGE_SIZE
Page size.
Definition io.h:28
size_t len
Length of tree.
Definition fdt.h:98

References assert, FDT_MAX_ALIGN, fdt::len, len, memsz, and PAGE_SIZE.

Referenced by fdtmem_register(), and fdtmem_relocate().

◆ fdtmem_relocate()

physaddr_t fdtmem_relocate ( struct fdt_header * hdr,
physaddr_t max )

Find a relocation address for iPXE.

Parameters
hdrFDT header
maxMaximum accessible physical address
Return values
newNew physical address for relocation

Find a suitably aligned address towards the top of existent 32-bit memory to which iPXE may be relocated, along with a copy of the system device tree.

This function may be called very early in initialisation, before .data is writable or .bss has been zeroed. Neither this function nor any function that it calls may write to or rely upon the zero initialisation of any static variables.

Definition at line 264 of file fdtmem.c.

264 {
265 struct fdt fdt;
266 struct memmap_region region;
270 physaddr_t new;
271 physaddr_t try;
272 size_t len;
273 int rc;
274
275 /* Sanity check */
276 assert ( ( max_align & ( max_align - 1 ) ) == 0 );
277
278 /* Get current physical address */
279 old = virt_to_phys ( _prefix );
280
281 /* Parse FDT */
282 if ( ( rc = fdt_parse ( &fdt, hdr, -1UL ) ) != 0 ) {
283 DBGC ( hdr, "FDTMEM could not parse FDT: %s\n",
284 strerror ( rc ) );
285 /* Refuse relocation if we have no FDT */
286 return old;
287 }
288
289 /* Determine required length */
290 len = fdtmem_len ( &fdt );
291 assert ( len > 0 );
292 DBGC ( hdr, "FDTMEM requires %#zx + %#zx => %#zx bytes for "
293 "relocation\n", memsz, fdt.len, len );
294
295 /* Limit relocation to 32-bit address space
296 *
297 * Devices with only 32-bit DMA addressing are relatively
298 * common even on systems with 64-bit CPUs. Limit relocation
299 * of iPXE to 32-bit address space so that I/O buffers and
300 * other DMA allocations will be accessible by 32-bit devices.
301 */
302 if ( max > FDTMEM_MAX32 )
304
305 /* Construct memory map and choose a relocation address */
306 new = old;
307 for ( addr = 0, next = 1 ; next ; addr = next ) {
308
309 /* Describe region and in-use memory */
310 fdtmem_describe ( addr, max, &fdt, &region );
311 memmap_update ( &region, old, memsz, MEMMAP_FL_USED, "iPXE" );
312 memmap_update ( &region, virt_to_phys ( hdr ), fdt.len,
313 MEMMAP_FL_RESERVED, "FDT" );
314 next = ( region.max + 1 );
315
316 /* Dump region descriptor (for debugging) */
317 DBGC_MEMMAP ( hdr, &region );
318 assert ( region.max >= region.min );
319
320 /* Use highest possible region */
321 if ( memmap_is_usable ( &region ) &&
322 ( ( next == 0 ) || ( next >= len ) ) ) {
323
324 /* Determine candidate address after alignment */
325 try = ( ( next - len ) & ~( max_align - 1 ) );
326
327 /* Use this address if within region */
328 if ( try >= addr )
329 new = try;
330 }
331 }
332
333 DBGC ( hdr, "FDTMEM relocating %#08lx => [%#08lx,%#08lx]\n",
334 old, new, ( ( physaddr_t ) ( new + len - 1 ) ) );
335 return new;
336}
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
unsigned long physaddr_t
Definition stdint.h:20
int old
Definition bitops.h:65
uint32_t next
Next descriptor address.
Definition dwmac.h:11
uint32_t addr
Buffer address.
Definition dwmac.h:9
int fdt_parse(struct fdt *fdt, struct fdt_header *hdr, size_t max_len)
Parse device tree.
Definition fdt.c:904
static void fdtmem_describe(uint64_t min, uint64_t max, struct fdt *fdt, struct memmap_region *region)
Describe memory region.
Definition fdtmem.c:211
static size_t max_align
Definition fdtmem.c:55
static size_t fdtmem_len(struct fdt *fdt)
Get length for copy of iPXE and device tree.
Definition fdtmem.c:233
#define FDTMEM_MAX32
Maximum 32-bit physical address.
Definition fdtmem.c:66
char _prefix[]
Start address of the iPXE image.
static int memmap_is_usable(const struct memmap_region *region)
Check if memory region is usable.
Definition memmap.h:87
#define MEMMAP_FL_USED
Is in use by iPXE.
Definition memmap.h:62
#define DBGC_MEMMAP(...)
Definition memmap.h:207
A memory region descriptor.
Definition memmap.h:49

References _prefix, addr, assert, DBGC, DBGC_MEMMAP, fdt_parse(), fdtmem_describe(), fdtmem_len(), FDTMEM_MAX32, hdr, fdt::len, len, max, memmap_region::max, max_align, MEMMAP_FL_RESERVED, MEMMAP_FL_USED, memmap_is_usable(), memmap_update(), memsz, memmap_region::min, next, old, rc, and strerror().

◆ fdtmem_register()

int fdtmem_register ( struct fdt_header * hdr,
physaddr_t max )

Copy and register system device tree.

Parameters
hdrFDT header
maxMaximum accessible physical address
Return values
rcReturn status code

Definition at line 345 of file fdtmem.c.

345 {
346 struct fdt_header *copy;
347 struct fdt fdt;
348 int rc;
349
350 /* Record maximum accessible physical address */
351 fdtmem_max = max;
352
353 /* Parse FDT to obtain length */
354 if ( ( rc = fdt_parse ( &fdt, hdr, -1UL ) ) != 0 ) {
355 DBGC ( hdr, "FDTMEM could not parse FDT: %s\n",
356 strerror ( rc ) );
357 return rc;
358 }
359
360 /* Copy device tree to end of iPXE image */
361 copy = ( ( void * ) _end );
362 memcpy ( copy, hdr, fdt.len );
363
364 /* Update in-use memory region */
365 memmap_use ( &fdtmem_used, virt_to_phys ( _prefix ),
366 fdtmem_len ( &fdt ) );
367
368 /* Register copy as system device tree */
369 if ( ( rc = fdt_parse ( &sysfdt, copy, -1UL ) ) != 0 ) {
370 DBGC ( hdr, "FDTMEM could not register FDT: %s\n",
371 strerror ( rc ) );
372 return rc;
373 }
374 assert ( sysfdt.len == fdt.len );
375
376 /* Dump system memory map (for debugging) */
377 memmap_dump_all ( 1 );
378
379 return 0;
380}
struct fdt sysfdt
The system flattened device tree (if present)
Definition fdt.c:45
static physaddr_t fdtmem_max
Maximum accessible physical address.
Definition fdtmem.c:63
char _end[]
End address of the iPXE image.
static void memmap_use(struct used_region *used, physaddr_t start, size_t size)
Update an in-use memory region.
Definition memmap.h:154
static void memmap_dump_all(int hide)
Dump system memory map (for debugging)
Definition memmap.h:216
void * memcpy(void *dest, const void *src, size_t len) __nonnull
Device tree header.
Definition fdt.h:19

References _end, _prefix, assert, DBGC, fdt_parse(), fdtmem_len(), fdtmem_max, hdr, fdt::len, max, memcpy(), memmap_dump_all(), memmap_use(), rc, strerror(), and sysfdt.

◆ fdtmem_describe_region()

void fdtmem_describe_region ( uint64_t min,
int hide,
struct memmap_region * region )
static

Describe memory region from system memory map.

Parameters
minMinimum address
hideHide in-use regions from the memory map
regionRegion descriptor to fill in

Definition at line 389 of file fdtmem.c.

390 {
391
392 /* Describe memory region based on device tree */
393 fdtmem_describe ( min, fdtmem_max, &sysfdt, region );
394
395 /* Update memory region based on in-use regions, if applicable */
396 if ( hide )
397 memmap_update_used ( region );
398}
void memmap_update_used(struct memmap_region *region)
Update memory region descriptor based on all in-use memory regions.
Definition memmap.c:104

References fdtmem_describe(), fdtmem_max, memmap_update_used(), min, and sysfdt.

Referenced by PROVIDE_MEMMAP().

◆ PROVIDE_MEMMAP()

◆ PROVIDE_MEMMAP_INLINE()

PROVIDE_MEMMAP_INLINE ( fdt ,
memmap_sync  )

References memmap_sync().

Variable Documentation

◆ _prefix

char _prefix[]
extern

Start address of the iPXE image.

Referenced by fdtmem_register(), fdtmem_relocate(), and FILE_LICENCE().

◆ _end

char _end[]
extern

End address of the iPXE image.

Referenced by fdtmem_register(), and FILE_LICENCE().

◆ memsz

◆ max_align

size_t max_align = ABS_VALUE_INIT ( _max_align )
static

Definition at line 55 of file fdtmem.c.

Referenced by fdtmem_relocate().

◆ __used_region

struct used_region fdtmem_used __used_region
Initial value:
= {
.name = "iPXE/FDT",
}

In-use memory region for iPXE and system device tree copy.

Definition at line 58 of file fdtmem.c.

58 {
59 .name = "iPXE/FDT",
60};

◆ fdtmem_max

physaddr_t fdtmem_max
static

Maximum accessible physical address.

Definition at line 63 of file fdtmem.c.

Referenced by fdtmem_describe_region(), and fdtmem_register().