7254 Commits

Author SHA1 Message Date
Michael Brown
9bc559850c [fdt] Allow an initrd to be specified when creating a device tree
Allow an initrd location to be specified in our constructed device
tree via the "linux,initrd-start" and "linux,initrd-end" properties.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-21 14:31:18 +01:00
Michael Brown
c1cd54ad74 [initrd] Move initrd reshuffling to be architecture-independent code
There is nothing x86-specific in initrd.c, and a variant of the
reshuffling logic will be required for executing bare-metal kernels on
RISC-V and AArch64.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-21 12:12:16 +01:00
Michael Brown
d15a11f3a4 [image] Use image replacement when executing extracted images
Use image_replace() to transfer execution to the extracted image,
rather than calling image_exec() directly.  This allows the original
archive image to be freed immediately if it was marked as an
automatically freeable image (e.g. via "chain --autofree").

In particular, this ensures that in the case of an archive image
containing another archive image (such as an EFI zboot kernel wrapper
image containing a gzip-compressed kernel image), the intermediate
extracted image will be freed as early as possible, since extracted
images are always marked as automatically freeable.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-20 15:34:49 +01:00
Michael Brown
e2f4dba2b7 [lkrn] Add support for EFI zboot compressed kernel images
Current RISC-V and AArch64 kernels found in the wild tend not to be in
the documented kernel format, but are instead "EFI zboot" kernels
comprising a small EFI executable that decompresses and executes the
inner payload (which is a kernel in the expected format).

The EFI zboot header includes a recognisable magic value "zimg" along
with two fields describing the offset and length of the compressed
payload.  We can therefore treat this as an archive image format,
extracting the payload as-is and then relying on our existing ability
to execute compressed images.

This is sufficient to allow iPXE to execute the Fedora 42 RISC-V
kernel binary as currently published.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-20 14:29:57 +01:00
Michael Brown
ecac4a34c7 [lkrn] Add basic support for the RISC-V Linux kernel image format
The RISC-V and AArch64 bare-metal kernel images share a common header
format, and require essentially the same execution environment: loaded
close to the start of RAM, entered with paging disabled, and passed a
pointer to a flattened device tree that describes the hardware and any
boot arguments.

Implement basic support for executing bare-metal RISC-V and AArch64
kernel images.  The (trivial) AArch64-specific code path is untested
since we do not yet have the ability to build for any bare-metal
AArch64 platforms.  Constructing and passing an initramfs image is not
yet supported.

Rename the IMAGE_BZIMAGE build configuration option to IMAGE_LKRN,
since "bzImage" is specific to x86.  To retain backwards compatibility
with existing local build configurations, we leave IMAGE_BZIMAGE as
the enabled option in config/default/pcbios.h and treat IMAGE_LKRN as
a synonym for IMAGE_BZIMAGE when building for x86 BIOS.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-20 13:08:38 +01:00
Michael Brown
d0c35b6823 [bios] Use generic external heap based on the system memory map
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-19 20:47:21 +01:00
Michael Brown
140ceeeb08 [riscv] Use generic external heap based on the system memory map
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-19 19:36:25 +01:00
Michael Brown
4d560af2b0 [uheap] Add a generic external heap based on the system memory map
Add an implementation of umalloc() using the generalised model of a
heap, placing the external heap in the largest usable region obtained
from the system memory map.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-19 19:36:25 +01:00
Michael Brown
490f1ecad8 [malloc] Allow heap to specify block and pointer alignments
Size-tracked pointers allocated via umalloc() have historically been
aligned to a page boundary, as have the edges of the hidden memory
region covering the external heap.

Allow the block and size-tracked pointer alignments to be specified as
heap configuration parameters.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-19 19:36:23 +01:00
Michael Brown
c6ca3d3af8 [malloc] Allow for the existence of multiple heaps
Create a generic model of a heap as a list of free blocks with
optional methods for growing and shrinking the heap.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-19 19:35:56 +01:00
Michael Brown
83449702e0 [memmap] Remove now-obsolete get_memmap()
All memory map users have been updated to use the new system memory
map API.  Remove get_memmap() and its associated definitions.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 18:16:41 +01:00
Michael Brown
624d76e26d [bios] Use memmap_describe() to find an external heap location
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 18:04:27 +01:00
Michael Brown
79c30b92a3 [settings] Use memmap_describe() to construct memory map settings
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 17:39:36 +01:00
Michael Brown
c8d64ecd87 [bios] Use memmap_describe() to find a relocation address
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 17:39:29 +01:00
Michael Brown
dbc86458e5 [comboot] Use memmap_describe() to obtain available memory
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 17:02:55 +01:00
Michael Brown
d0adf3b4cc [multiboot] Use memmap_describe() to construct Multiboot memory map
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 17:02:55 +01:00
Michael Brown
25ab8f4629 [image] Use memmap_describe() to check loadable image segments
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 16:55:35 +01:00
Michael Brown
a353e70800 [memmap] Use memmap_dump_all() to dump debug memory maps
There are several places where get_memmap() is called solely to
produce debug output.  Replace these with calls to memmap_dump_all()
(which will be a no-op unless debugging is enabled).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 16:18:36 +01:00
Michael Brown
3812860e39 [bios] Describe umalloc() heap as an in-use memory area
Use the concept of an in-use memory region defined as part of the
system memory map API to describe the umalloc() heap.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 16:18:36 +01:00
Michael Brown
4c4c94ca09 [bios] Update to use the generic system memory map API
Provide an implementation of the system memory map API based on the
assorted BIOS INT 15 calls, and a temporary implementation of the
legacy get_memmap() function using the new API.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 16:18:36 +01:00
Michael Brown
3f6ee95737 [fdtmem] Update to use the generic system memory map API
Provide an implementation of the system memory map API based on the
system device tree, excluding any memory outside the size of the
accessible physical address space and defining an in-use region to
cover the relocated copy of iPXE and the system device tree.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-16 16:18:36 +01:00
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
f6f11c101c [tests] Remove prehistoric umalloc() test code
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-15 15:47:08 +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
64ad1d03c3 [bios] Rename memmap.c to int15.c
Create namespace for an architecture-independent memmap.c by renaming
the BIOS-specific memmap.c to int15.c.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-14 22:02:46 +01:00
Joseph Wong
1dd9ac13fd [bnxt] Use updated DMA APIs
Replace malloc_phys with dma_alloc, free_phys with dma_free, alloc_iob
with alloc_rx_iob, free_iob with free_rx_iob, virt_to_bus with dma or
iob_dma.  Replace dma_addr_t with physaddr_t.

Signed-off-by: Joseph Wong <joseph.wong@broadcom.com>
2025-05-14 14:21:02 +01:00
Joseph Wong
08edad7ca3 [bnxt] Return proper error codes in probe
Return the proper error codes in bnxt_init_one, to indicate the
correct return status upon completion.  Failure paths could
incorrectly indicate a success.  Correct assertion condition to check
for non-NULL pointer.

Signed-off-by: Joseph Wong <joseph.wong@broadcom.com>
2025-05-14 14:08:27 +01:00
Michael Brown
4d39b2dcc6 [crypto] Remove redundant null pointer check
Coverity reports a spurious potential null pointer dereference in
cms_decrypt(), since the null pointer check takes place after the
pointer has already been dereferenced.  The pointer can never be null,
since it is initialised to point to cipher_null at the point that the
containing structure is allocated.

Remove the redundant null pointer check, and for symmetry ensure that
the digest and public-key algorithm pointers are similarly initialised
at the point of allocation.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-14 12:46:23 +01:00
Michael Brown
d1c1e578af [riscv] Add a .pf32 build target for padded parallel flash images
QEMU's -pflash option requires an image that has been padded to the
exact expected size (32MB for all of the supported RISC-V virtual
machines).

Add a .pf32 build target which is simply the equivalent .sbi target
padded to 32MB in size, to simplify testing.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-13 18:25:24 +01:00
Michael Brown
6fd927f929 [riscv] Perform a writability test before applying relocations
If paging is not supported, then we will attempt to apply dynamic
relocations to fix up the runtime addresses.  If the image is
currently executing directly from flash memory, this can result in
effectively sending an undefined sequence of commands to the flash
device, which can cause unwanted side effects.

Perform an explicit writability test before applying relocations,
using a write value chosen to be safe for at least any devices
conforming to the JEDEC Common Flash Interface (CFI01).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-13 17:42:53 +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
8e38af800b [riscv] Add a .lkrn build target resembling a Linux kernel binary
On x86 BIOS, it has been useful to be able to build iPXE to resemble a
Linux kernel, so that it can be loaded by programs such as syslinux
which already know how to handle Linux kernel binaries.

Add an equivalent .lkrn build target for RISC-V SBI, allowing for
build targets such as:

  make bin-riscv64/ipxe.lkrn

  make bin-riscv64/cgem.lkrn

The Linux kernel header format allows us to specify a required length
(including uninitialised-data portions) and defines that the image
will be loaded at a fixed offset from the start of RAM.  We can
therefore use known-safe areas of memory (within our own .bss) for the
initial temporary page table and stack.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-13 13:03:08 +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
3dfc88158c [riscv] Construct page tables based on link-time virtual addresses
Always construct the page tables based on the link-time address values
even if relocations have already been applied, on the assumption that
relocations will be reapplied after paging has been enabled.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-12 13:59:42 +01:00
Michael Brown
c45dc4a55d [riscv] Allow apply_relocs() to use non-inline relocation records
The address of the compressed relocation records is currently
calculated implicitly relative to the program counter.  This requires
the relocation records to be copied as part of relocation to a new
physical address, so that they can be reapplied (if needed) after
copying iPXE to the new physical address.

Since the relocation destination will never overlap the original iPXE
image, and since the relocation records will not be needed further
after completing relocation, we can avoid the need to copy the records
by passing in a pointer to the relocation records present in the
original iPXE image.

Pass the compressed relocation record address as an explicit parameter
to apply_relocs(), rather than being implicit in the program counter.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-12 12:23:23 +01:00
Michael Brown
420e475b11 [riscv] Return accessible physical address space size from enable_paging()
Relocation requires knowledge of the size of the accessible physical
address space, which for 64-bit CPUs will vary according to the paging
level supported by the processor.

Update enable_paging_64() and enable_paging_32() to calculate and
return the size of the accessible physical address space.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-12 11:47:25 +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
2e45106c0a [riscv] Ensure that prefix_virt is aligned on an xlen boundary
Ensure that the prefix_virt dynamic relocation ends up on a suitably
aligned boundary for a compressed relocation.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-11 14:17:39 +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
3027864f13 [riscv] Use load and store pseudo-instructions where possible
The pattern of "load address to register" followed by "load value from
address in register" generally results in three instructions: two to
load the address and one to load the value.

This can be reduced to two instructions by allowing the assembler to
incorporate the low bits of the address within the load (or store)
instruction itself.  In the case of a store, this requires specifying
a second register that can be temporarily used to hold the high bits
of the address.  (In the case of a load, the destination register is
reused for this purpose.)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-09 15:23:41 +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
1d58d928fe [libc] Display assertion failure message before incrementing counter
During early initialisation on some platforms, the .data and .bss
sections may not yet be writable.

Display the assertion message before attempting to increment the
assertion failure counter, since writing to the assertion counter may
trigger a CPU exception that ends up resetting the system.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-09 14:36:00 +01:00
Michael Brown
8fe3c68b31 [riscv] Add support for disabling 64-bit and 32-bit paging
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-08 16:17:21 +01:00
Michael Brown
5b19ddbb3c [riscv] Return virtual address offset from enable_paging()
Once paging has been enabled, there is no direct way to determine the
virtual address offset without external knowledge.  (The paging mode,
if needed, can be read directly from the SATP CSR.)

Change the return value from enable_paging() to provide the virtual
address offset.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-08 14:37:30 +01:00
Michael Brown
5e518c744e [riscv] Restore temporarily modified PTE within 32-bit transition code
If the virtual address offset is precisely one page (i.e. each virtual
address maps to a physical address one page higher), and if the 32-bit
transition code happens to end up at the end of a page (which would
require an unrealistic 2MB of content in .prefix), then it would be
possible for the program counter to cross into the portion of the
virtual address space still borrowed for use as the temporary physical
map.

Avoid this remote possibility by moving the restoration of the
temporarily modified PTE within the transition code block (which is
guaranteed to remain within a single page since it is aligned on its
own size).

This unfortunately requires increasing the alignment of the transition
code (and hence the maximum number of NOPs inserted).  The assembler
syntax theoretically allows us to avoid inserting any NOPs via a
directive such as:

   .balign PAGE_SIZE, , enable_paging_32_max_len

(i.e. relying on the fact that if the transition code is already
sufficiently far away from the end of a page, then no padding needs to
be inserted).  However, alignment on RISC-V is implemented using the
R_RISCV_ALIGN relaxing relocation, which doesn't encode any concept of
a maximum padding length, and so the maximum padding length value is
effectively ignored.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-08 12:45:37 +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
e8a6c26571 [build] Constrain PHYS_CODE() and REAL_CODE() to use i386 registers
Inline assembly using PHYS_CODE() or REAL_CODE() must use the "R"
constraint rather than the "r" constraint to ensure that the compiler
chooses registers that will be valid for the 32-bit or 16-bit assembly
code fragment.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-07 23:03:02 +01:00
Michael Brown
12dee2dab2 [riscv] Add debug printing of hexadecimal values in libprefix.S
Add millicode routines to print hexadecimal values (with any number of
digits), and macros to print register contents or symbol addresses.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-07 14:23:56 +01:00
Michael Brown
72c81419b1 [riscv] Move prefix system reset code to libprefix.S
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2025-05-07 13:10:40 +01:00