Commit Graph

1057 Commits

Author SHA1 Message Date
Michael Brown
bab3d76717 [memmap] Define an API for managing the system memory map
Define a generic system memory map API, based on the abstraction
created for parsing the FDT memory map and adding a concept of hidden
in-use memory regions as required to support patching the BIOS INT 15
memory map.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 16:12:15 +01:00
Michael Brown
e0c4cfa81e [fdtmem] Record size of accessible physical address space
The size of accessible physical address space will be required for the
runtime memory map, not just at relocation time.  Make this size an
additional parameter to fdt_register() (matching the prototype for
fdt_relocate()), and record the value for future reference.

Note that we cannot simply store the limit in fdt_relocate() since it
is called before .data is writable and before .bss is zeroed.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-14 22:09:51 +01:00
Michael Brown
4566f59757 [riscv] Avoid potentially overwriting the scratch area during relocation
We do not currently describe the temporary page table or the temporary
stack as areas to be avoided during relocation of the iPXE image to a
new physical address.

Perform the copy of the iPXE image and zeroing of the .bss within
libprefix.S, after we have no futher use for the temporary page table
or the temporary initial stack.  Perform the copy and registration of
the system device tree in C code after relocation is complete and the
new stack (within .bss) has been set up.

This provides a clean separation of responsibilities between the
RISC-V libprefix.S and the architecture-independent fdtmem.c.  The
prefix is responsible only for relocating iPXE to the new physical
address returned from fdtmem_relocate(), and doesn't need to know or
care where fdtmem.c is planning to place the copy of the device tree.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-13 14:00:34 +01:00
Michael Brown
17fd67ce03 [riscv] Relocate to a safe physical address on startup
On startup, we may be running from read-only memory.  We need to parse
the devicetree to obtain the system memory map, and identify a safe
location to which we can copy our own binary image along with a
stashed copy of the devicetree, and then transfer execution to this
new location.

Parsing the system memory map realistically requires running C code.
This in turn requires a small temporary stack, and some way to ensure
that symbol references are valid.

We first attempt to enable paging, to make the runtime virtual
addresses equal to the link-time virtual addresses.  If this fails,
then we attempt to apply the compressed relocation records.

Assuming that one of these has worked (i.e. that either the CPU
supports paging or that our image started execution in writable
memory), then we call fdtmem_relocate() to parse the system memory map
to find a suitable relocation target address.

After the copy we disable paging, jump to the relocated copy,
re-enable paging, and reapply relocation records (if needed).  At this
point, we have a full runtime environment, and can transfer control to
normal C code.

Provide this functionality as part of libprefix.S, since it is likely
to be shared by multiple prefixes.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-12 13:59:42 +01:00
Michael Brown
6fe9ce66ae [fdtmem] Add ability to parse FDT memory map for a relocation address
Add code to parse the devicetree memory nodes, memory reservations
block, and reserved memory nodes to construct an ordered and
non-overlapping description of the system memory map, and use this to
identify a suitable address to which iPXE may be relocated at runtime.

We choose to place iPXE on a superpage boundary (as required by the
paging code), and to use the highest available address within
accessible memory.  This mirrors the approach taken for x86 BIOS
builds, where we have long assumed that any image format that we might
need to support may require specific fixed addresses towards the
bottom of the memory map, but is very unlikely to require specific
fixed addresses towards the top of the memory map (since those
addresses may not exist, depending on the amount of installed RAM).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-11 18:23:08 +01:00
Michael Brown
95ede670bc [riscv] Hold virtual address offset in the thread pointer register
iPXE does not make use of any thread-local storage.  Use the otherwise
unused thread pointer register ("tp") to hold the current value of
the virtual address offset, rather than using a global variable.

This ensures that virt_offset can be made valid even during very early
initialisation (when iPXE may be executing directly from read-only
memory and so cannot update a global variable).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-11 13:46:21 +01:00
Michael Brown
f988ec09e0 [fdt] Generalise access to "reg" property
The "reg" property is also used by non-device nodes, such as the nodes
describing the system memory map.

Provide generalised functionality for parsing the "#address-cells",
"#size-cells", and "reg" properties.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-09 19:09:57 +01:00
Michael Brown
134d76379e [build] Formalise mechanism for accessing absolute symbols
In a position-dependent executable, where all addresses are fixed
at link time, we can use the standard technique as documented by
GNU ld to get the value of an absolute symbol, e.g.:

    extern char _my_symbol[];

    printf ( "Absolute symbol value is %x\n", ( ( int ) _my_symbol ) );

This technique may not work in a position-independent executable.
When dynamic relocations are applied, the runtime addresses will no
longer be equal to the link-time addresses.  If the code to obtain the
address of _my_symbol uses PC-relative addressing, then it will
calculate the runtime "address" of the absolute symbol, which will no
longer be equal the the link-time "address" (i.e. the correct value)
of the absolute symbol.

Define macros ABS_SYMBOL(), ABS_VALUE_INIT(), and ABS_VALUE() that
provide access to the correct values of absolute symbols even in
position-independent code, and use these macros wherever absolute
symbols are accessed.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-09 15:14:03 +01:00
Michael Brown
0279015d09 [uaccess] Generalise librm's virt_offset mechanism for RISC-V
The virtual offset memory model used for i386-pcbios and x86_64-pcbios
can be generalised to also cover riscv32-sbi and riscv64-sbi.  In both
architectures, the 32-bit builds will use a circular map of the 32-bit
address space, and the 64-bit builds will use an identity map for the
relevant portion of the physical address space, with iPXE itself
placed in the negative (kernel) address space.

Generalise and document the virt_offset mechanism, and set it as the
default for both PCBIOS and SBI platforms.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-08 00:12:33 +01:00
Michael Brown
1534b0a6e9 [uaccess] Remove redundant virt_to_user() and userptr_t
Remove the last remaining traces of the concept of a user pointer,
leaving iPXE with a simpler and cleaner memory model that implicitly
assumes that all memory locations can be reached through pointer
dereferences.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-30 16:26:16 +01:00
Michael Brown
a169d73593 [uaccess] Reduce scope of included uaccess.h header
The uaccess.h header is no longer required for any code that touches
external ("user") memory, since such memory accesses are now performed
through pointer dereferences.  Reduce the number of files including
this header.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-30 16:16:02 +01:00
Michael Brown
05ad7833c5 [image] Make image data read-only to most consumers
Almost all image consumers do not need to modify the content of the
image.  Now that the image data is a pointer type (rather than the
opaque userptr_t type), we can rely on the compiler to enforce this at
build time.

Change the .data field to be a const pointer, so that the compiler can
verify that image consumers do not modify the image content.  Provide
a transparent .rwdata field for consumers who have a legitimate (and
now explicit) reason to modify the image content.

We do not attempt to impose any runtime restriction on checking
whether or not an image is writable.  The only existing instances of
genuinely read-only images are the various unit test images, and it is
acceptable for defective test cases to result in a segfault rather
than a runtime error.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-30 15:38:15 +01:00
Michael Brown
cd803ff2e2 [image] Add the concept of a static image
Not all images are allocated via alloc_image().  For example: embedded
images, the static images created to hold a runtime command line, and
the images used by unit tests are all static structures.

Using image_set_cmdline() (via e.g. the "imgargs" command) to set the
command-line arguments of a static image will succeed but will leak
memory, since nothing will ever free the allocated command line.
There are no code paths that can lead to calling image_set_len() on a
static image, but there is no safety check against future code paths
attempting this.

Define a flag IMAGE_STATIC to mark an image as statically allocated,
generalise free_image() to also handle freeing dynamically allocated
portions of static images (such as the command line), and expose
free_image() for use by static images.

Define a related flag IMAGE_STATIC_NAME to mark the name as statically
allocated.  Allow a statically allocated name to be replaced with a
dynamically allocated name since this is a potentially valid use case
(e.g. if "imgdecrypt --name <name>" is used on an embedded image).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-30 15:38:15 +01:00
Michael Brown
b6f9e4bab0 [uaccess] Remove redundant copy_from_user() and copy_to_user()
Remove the now-redundant copy_from_user() and copy_to_user() wrapper
functions.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-30 15:32:03 +01:00
Michael Brown
a69c42dd9f [image] Clear recorded replacement image immediately after consuming
If an embedded script uses "chain --replace", the embedded image will
retain a reference to the replacement image in perpetuity.

Fix by clearing any recorded replacement image immediately in
image_exec(), instead of relying upon image_free() to drop the
reference.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-29 16:32:01 +01:00
Michael Brown
837b77293b [xferbuf] Simplify and generalise data transfer buffers
Since all data transfer buffer contents are now accessible via direct
pointer dereferences, remove the unnecessary abstractions for read and
write operations and create two new data transfer buffer types: a
fixed-size buffer, and a void buffer that records its size but can
never receive non-zero lengths of data.  These replace the custom data
buffer types currently implemented for EFI PXE TFTP downloads and for
block device translations.

A new operation xferbuf_detach() is required to take ownership of the
data accumulated in the data transfer buffer, since we no longer rely
on the existence of an independently owned external data pointer for
data transfer buffers allocated via umalloc().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-29 11:27:22 +01:00
Michael Brown
7eaa2daf6f [reboot] Generalise warm reboot indicator to a flags bitmask
Allow for the possibility of additional reboot types by extending the
reboot() function to use a flags bitmask rather than a single flag.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-28 13:44:53 +01:00
Michael Brown
4c8bf666f4 [pnm] Remove userptr_t from PNM image parsing
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-25 17:23:37 +01:00
Michael Brown
76a17b0986 [fbcon] Avoid redrawing unchanged characters when scrolling
Scrolling currently involves redrawing every character cell, which can
be frustratingly slow on large framebuffer consoles.  Accelerate this
operation by skipping the redraw for any unchanged character cells.

In the common case that large areas of the screen contain whitespace,
this optimises away the vast majority of the redrawing operations.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-25 13:44:18 +01:00
Michael Brown
aa3cc56ab2 [fbcon] Remove userptr_t from framebuffer console drivers
Simplify the framebuffer console drivers by assuming that the raw
framebuffer, character cell array, background picture, and glyph data
are all directly accessible via pointer dereferences.

In particular, this avoids the need to copy each glyph during drawing:
the VESA framebuffer driver can simply return a pointer to the glyph
data stored in the video ROM.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-25 12:44:28 +01:00
Michael Brown
2f11f466e6 [block] Remove userptr_t from block device abstraction
Simplify the block device code by assuming that all read/write buffers
are directly accessible via pointer dereferences.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-24 17:11:30 +01:00
Michael Brown
2742ed5d77 [uaccess] Remove now-obsolete memchr_user()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-24 16:35:49 +01:00
Michael Brown
e8ffe2cd64 [uaccess] Remove trivial uses of userptr_t
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-24 01:40:05 +01:00
Michael Brown
839540cb95 [umalloc] Remove userptr_t from user memory allocations
Use standard void pointers for umalloc(), urealloc(), and ufree(),
with the "u" prefix retained to indicate that these allocations are
made from external ("user") memory rather than from the internal heap.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-23 14:43:04 +01:00
Michael Brown
0b3fc48fef [acpi] Remove userptr_t from ACPI table parsing
Simplify the ACPI table parsing code by assuming that all table
content is fully accessible via pointer dereferences.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-22 14:21:06 +01:00
Michael Brown
b89a34b07f [image] Remove userptr_t from image definition
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-22 12:21:26 +01:00
Michael Brown
04d0b2fdf9 [uaccess] Remove redundant read_user()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-21 18:55:30 +01:00
Michael Brown
8c31270a21 [uaccess] Remove user_to_phys() and phys_to_user()
Remove the intermediate concept of a user pointer from physical
address conversions, leaving virt_to_phys() and phys_to_virt() as the
directly implemented functions.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-21 16:17:19 +01:00
Michael Brown
4535548cba [uaccess] Remove redundant user_to_virt()
The user_to_virt() function is now a straightforward wrapper around
addition, with the addend almost invariably being zero.

Remove this redundant wrapper.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-21 00:15:52 +01:00
Michael Brown
89fe788689 [uaccess] Remove redundant memcpy_user() and related string functions
The memcpy_user(), memmove_user(), memcmp_user(), memset_user(), and
strlen_user() functions are now just straightforward wrappers around
the corresponding standard library functions.

Remove these redundant wrappers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-20 23:00:13 +01:00
Michael Brown
ef03849185 [uaccess] Remove redundant userptr_add() and userptr_diff()
The userptr_add() and userptr_diff() functions are now just
straightforward wrappers around addition and subtraction.

Remove these redundant wrappers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-20 22:31:29 +01:00
Michael Brown
453acba7dc [time] Use currticks() to provide the null system time
For platforms with no real-time clock (such as RISC-V SBI) we use the
null time source, which currently just returns a constant zero.

Switch to using currticks() to provide a clock that does not represent
the real current time, but does at least advance at approximately the
correct rate.  In conjunction with the "ntp" command, this allows
these platforms to use time-dependent features such as X.509
certificate verification for HTTPS connections.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-19 13:35:23 +01:00
Michael Brown
99322fd3b3 [fdt] Add fdt_cells() to read cell-based properties such as "reg"
Add fdt_cells() to read scalar values encoded within a cell array,
reimplement fdt_u64() as a wrapper around this, and add fdt_u32() for
completeness.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-15 20:24:19 +01:00
Michael Brown
d462aeb0ca [fdt] Remove concept of a device tree cursor
Refactor device tree traversal to operate on the basis of describing
the token at a given offset, with no separate notion of a device tree
cursor.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-14 14:38:40 +01:00
Michael Brown
db49346177 [fdt] Avoid temporarily modifying path during path lookup
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-14 13:53:09 +01:00
Michael Brown
c887de208f [fdt] Provide fdt_strings() to read string list properties
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-14 11:32:17 +01:00
Michael Brown
69af6f0c30 [fdt] Allow for trailing slashes in path lookups
Using fdt_path() to find the root node "/" currently fails, since it
will attempt to find a child node with the empty name "" within the
root node.

Fix by changing fdt_path() to ignore any trailing slashes in a device
tree path.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-14 11:26:49 +01:00
Michael Brown
7e64e9b670 [fdt] Populate boot arguments in constructed device tree
When creating a device tree to pass to a booted operating system,
ensure that the "chosen" node exists, and populate the "bootargs"
property with the image command line.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-01 16:55:28 +01:00
Michael Brown
d853448887 [fdt] Identify free space (if any) at end of parsed tree
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-04-01 13:08:41 +01:00
Michael Brown
5818529f39 [iobuf] Limit automatic I/O buffer alignment to page size
Without any explicit alignment requirement, we will currently allocate
I/O buffers on their own size rounded up to the nearest power of two.
This is done to simplify driver transmit code paths, which can assume
that a standard Ethernet frame lies within a single physical page and
therefore does not need to be split even for devices with DMA engines
that cannot cross page boundaries.

Limit this automatic alignment to a maximum of the page size, to avoid
requiring excessive alignment for unusually large buffers (such as a
buffer allocated for an HTTP POST with a large parameter list).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-31 13:39:58 +01:00
Michael Brown
761f43ce12 [fdt] Provide the ability to create a device tree for a booted OS
Provide fdt_create() to create a device tree to be passed to a booted
operating system.  The device tree will be created from the FDT image
(if present), falling back to the system device tree (if present).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-28 15:29:51 +00:00
Michael Brown
666929e311 [efi] Create a copy of the system flattened device tree, if present
EFI configuration tables may be freed at any time, and there is no way
to be notified when the table becomes invalidated.  Create a copy of
the system flattened device tree (if present), so that we do not risk
being left with an invalid pointer.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-28 15:29:20 +00:00
Michael Brown
3860313dd5 [fdt] Allow for parsing device trees where the length is known in advance
Allow for parsing device trees where an external factor (such as a
downloaded image length) determines the maximum length, which must be
validated against the length within the device tree header.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-28 15:11:39 +00:00
Michael Brown
2399c79980 [fdt] Allow for the existence of multiple device trees
When running on a platform that uses FDT as its hardware description
mechanism, we are likely to have multiple device tree structures.  At
a minimum, there will be the device tree passed to us from the
previous boot stage (e.g. OpenSBI), and the device tree that we
construct to be passed to the booted operating system.

Update the internal FDT API to include an FDT pointer in all function
parameter lists.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-28 14:14:32 +00:00
Michael Brown
cfd93465ec [fdt] Add the concept of an FDT image
Define the concept of an "FDT" image, representing a Flattened Device
Tree blob that has been downloaded in order to be provided to a kernel
or other executable image.  FDT images are represented using an image
tag (as with other special-purpose images such as the UEFI shim), and
are similarly marked as hidden so that they will not be included in a
generated magic initrd or show up in a virtual filesystem directory
listing.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-27 15:36:39 +00:00
Michael Brown
da3024d257 [cpio] Allow for the construction of pure directories
Allow for the possibility of creating empty directories (without
having to include a dummy file inside the directory) using a
zero-length image and a CPIO filename with a trailing slash, such as:

  initrd emptyfile /usr/share/oem/

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-12 14:32:41 +00:00
Michael Brown
d6ee9a9242 [cpio] Fix calculation of name lengths in CPIO headers
Commit 12ea8c4 ("[cpio] Allow for construction of parent directories
as needed") introduced a regression in constructing CPIO archive
headers for relative paths (e.g. simple filenames with no leading
slash).

Fix by counting the number of path components rather than the number
of path separators, and add some test cases to cover CPIO header
construction.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-03-12 14:27:44 +00:00
Michael Brown
12ea8c4074 [cpio] Allow for construction of parent directories as needed
iPXE allows individual raw files to be automatically wrapped with
suitable CPIO headers and injected into the magic initrd image as
exposed to a booted Linux kernel.  This feature is currently limited
to placing files within directories that already exist in the initrd
filesystem.

Remove this limitation by adding the ability for iPXE to construct
CPIO headers for parent directories as needed, under control of the
"mkdir=<n>" command-line argument.  For example:

  initrd config.ign /usr/share/oem/config.ign mkdir=1

will create CPIO headers for the "/usr/share/oem" directory as well as
for the "/usr/share/oem/config.ign" file itself.

This simplifies the process of booting operating systems such as
Flatcar Linux, which otherwise require the single "config.ign" file to
be manually wrapped up as a CPIO archive solely in order to create the
relevant parent directory entries.

The value <n> may be used to control the number of parent directory
entries that are created.  For example, "mkdir=2" would cause up to
two parent directories to be created (i.e. "/usr/share" and
"/usr/share/oem" in the above example).  A negative value such as
"mkdir=-1" may be used to create all parent directories up to the root
of the tree.

Do not create any parent directory entries by default, since doing so
would potentially cause the modes and ownership information for
existing directories to be overwritten.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-02-24 14:37:26 +00:00
Michael Brown
77cc3ed108 [malloc] Ensure free memory blocks remain aligned
When allocating memory with a non-zero alignment offset, the free
memory block structure following the allocation may end up improperly
aligned.

Ensure that free memory blocks always remain aligned to the size of
the free memory block structure.

Ensure that the initial heap is also correctly aligned, thereby
allowing the logic for leaking undersized free memory blocks to be
omitted.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-02-03 14:43:03 +00:00
Michael Brown
6f076efa65 [malloc] Clean up debug messages
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-02-03 14:41:35 +00:00