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>
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>
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>
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>
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>
Add the ability to reboot to the firmware setup menu (if supported) by
setting the relevant value in the OsIndications variable.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
GCC 15 defaults to C23, which reserves bool, true, and false as
keywords. Avoid using these as parameter or variable names.
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
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>
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>
Simplify the SMBIOS structure parsing code by assuming that all
structure content is fully accessible via pointer dereferences.
In particular, this allows the convoluted find_smbios_structure() and
read_smbios_structure() to be combined into a single function
smbios_structure() that just returns a direct pointer to the SMBIOS
structure, with smbios_string() similarly now returning a direct
pointer to the relevant string.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
Simplify the ASN.1 code by assuming that all objects are fully
accessible via pointer dereferences. This allows the concept of
"additional data beyond the end of the cursor" to be removed, and
simplifies parsing of all ASN.1 image formats.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
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>
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>
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>
Allow for greater control over the process used to disconnect existing
drivers from a device handle, by converting the "exclude" field from a
simple protocol GUID to a per-driver method.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
UEFI does not provide a direct method to disconnect the existing
driver of a specific protocol from a handle. We currently use
DisconnectController() to remove all drivers from a handle that we
want to drive ourselves, and then rely on recursion in the call to
ConnectController() to reconnect any drivers that did not need to be
disconnected in the first place.
Experience shows that OEMs tend not to ever test the disconnection
code paths in their UEFI drivers, and it is common to find drivers
that refuse to disconnect, fail to close opened handles, fail to
function correctly after reconnection, or lock up the entire system.
Implement a more selective form of disconnection, in which we use
OpenProtocolInformation() to identify the driver associated with a
specific protocol, and then disconnect only that driver.
Perform disconnections in reverse order of attachment priority, since
this is the order likely to minimise the number of cascaded implicit
disconnections.
This allows our MNP driver to avoid performing any disconnections at
all, since it does not require exclusive access to the MNP protocol.
It also avoids performing unnecessary disconnections and reconnections
of unrelated drivers such as the "UEFI WiFi Connection Manager" that
attaches to wireless network interfaces in order to manage wireless
network associations.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Define an ordering for internal EFI drivers on the basis of how close
the driver is to the hardware, and attempt to start drivers in this
order.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
UEFI assumes in several places that an image installs only a single
driver binding protocol instance, and that this is installed on the
image handle itself. We therefore provide a single driver binding
protocol instance, which delegates to the various internal drivers
(for EFI_PCI_IO_PROTOCOL, EFI_USB_IO_PROTOCOL, etc) as appropriate.
The debug messages produced by our Supported() method can end up
slightly misleading, since they will report only the first internal
driver that claims support for a device. In the common case of the
all-drivers build, there may be multiple drivers that claim support
for the same handle: for example, the PCI, NII, SNP, and MNP drivers
are all likely to initially find the protocols that they need on the
same device handle.
Report all internal drivers that claim support for a device, to avoid
confusing debug messages.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Return success if asked to stop driving a device that we are not
currently driving. This avoids propagating spurious errors to an
external caller of DisconnectController().
Signed-off-by: Michael Brown <mcb30@ipxe.org>
If we have a device tree available (e.g. because the user has
explicitly downloaded a device tree using the "fdt" command), then
provide it to the booted operating system as an EFI configuration
table.
Since x86 does not typically use device trees, we create weak symbols
for efi_fdt_install() and efi_fdt_uninstall() to avoid dragging FDT
support into all x86 UEFI binaries.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
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>
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>
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>
Provide wrapper macros to allow efi_open() and related functions to
accept a pointer to any pointer type as the "interface" argument, in
order to allow a substantial amount of type adjustment boilerplate to
be removed.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
It is now simpler to use efi_open() than to use HandleProtocol() to
obtain an ephemeral protocol instance. Remove all remaining uses of
HandleProtocol() to simplify the code.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The UEFI model for opening and closing protocols is broken by design
and cannot be repaired.
Calling OpenProtocol() to obtain a protocol interface pointer does
not, in general, provide any guarantees about the lifetime of that
pointer. It is theoretically possible that the pointer has already
become invalid by the time that OpenProtocol() returns the pointer to
its caller. (This can happen when a USB device is physically removed,
for example.)
Various UEFI design flaws make it occasionally necessary to hold on to
a protocol interface pointer despite the total lack of guarantees that
the pointer will remain valid.
The UEFI driver model overloads the semantics of OpenProtocol() to
accommodate the use cases of recording a driver attachment (which is
modelled as opening a protocol with EFI_OPEN_PROTOCOL_BY_DRIVER
attributes) and recording the existence of a related child controller
(which is modelled as opening a protocol with
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER attributes).
The parameters defined for CloseProtocol() are not sufficient to allow
the implementation to precisely identify the matching call to
OpenProtocol(). While the UEFI model appears to allow for matched
open and close pairs, this is merely an illusion. Calling
CloseProtocol() will delete *all* matching records in the protocol
open information tables.
Since the parameters defined for CloseProtocol() do not include the
attributes passed to OpenProtocol(), this means that a matched
open/close pair using EFI_OPEN_PROTOCOL_GET_PROTOCOL can inadvertently
end up deleting the record that defines a driver attachment or the
existence of a child controller. This in turn can cause some very
unexpected side effects, such as allowing other UEFI drivers to start
controlling hardware to which iPXE believes it has exclusive access.
This rarely ends well.
To prevent this kind of inadvertent deletion, we establish a
convention for four different types of protocol opening:
- ephemeral opens: always opened with ControllerHandle = NULL
- unsafe opens: always opened with ControllerHandle = AgentHandle
- by-driver opens: always opened with ControllerHandle = Handle
- by-child opens: always opened with ControllerHandle != Handle
This convention ensures that the four types of open never overlap
within the set of parameters defined for CloseProtocol(), and so a
close of one type cannot inadvertently delete the record corresponding
to a different type.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
In preparation for formalising the way that EFI protocols are opened
across the codebase, remove the efipci_open() wrapper.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We currently have both efipci_info() and efi_pci_info() serving
different but related purposes. Rename the latter to reduce
confusion.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Commit e727f57 ("[efi] Include a copy of the device path within struct
efi_device") neglected to delete the closure of the parent's device
path from the success code path in efi_snp_probe().
Reduce confusion by removing this (harmless) additional close.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some non-driver handles may have an installed component name protocol.
In particular, iPXE itself installs these protocols on its SNP device
handles, to simplify the process of delegating GetControllerName()
from our single-instance driver binding protocol to whatever child
controllers the relevant EFI driver may have installed.
For non-driver handles, the device path is more useful as debugging
information than the driver name. Limit the use of the component name
protocols to handles with a driver binding protocol installed, so that
we will end up using the device path for non-driver handles such as
the SNP device.
Continue to prefer the driver name to the device path for handles with
a driver binding protocol installed, since these will generally map to
things we are likely to conceptualise as drivers rather than as
devices.
Note that we deliberately do not use GetControllerName() to attempt to
get a human-readable name for a controller handle. In the normal
course of events, iPXE is likely to disconnect at least some existing
drivers from their controller handles. This would cause the name
obtained via GetControllerName() to change. By using the device path
instead, we ensure that the debug message name remains the same even
when the driver controlling the handle is changed.
Signed-off-by: Michael Brown <mcb30@ipxe.org>