Compare commits

..

93 Commits
edk2 ... vbox

Author SHA1 Message Date
370f086d64 WIP 2023-06-23 16:51:10 +01:00
a029f4e13b [efi] Veto the VirtualBox E1kNetDxe driver
The VirtualBox E1kNetDxe driver has a Stop() method that relies on
being passed its own child device handle.  Unfortunately, the same
driver's Start() method never opens the parent device handle with
BY_CHILD_CONTROLLER attributes on behalf of the newly installed child
device handle, with the result that the UEFI device model is
completely unaware of the nominal parent-child relationship.  This
omission can be observed via the UEFI shell "devtree" command, which
will show the child SNP device handle as a standalone top-level device
handle, with no relationship to its underlying parent PCI device
handle.

The upshot of this omission is that the VirtualBox E1kNetDxe driver's
Stop() method is a pure no-op.  Calling DisconnectController() on the
PCI device handle will return successfully, but will not have actually
disconnected anything.  A subsequent attempt to open the handle on
behalf of iPXE's native Intel driver will get stuck in an infinite
loop inside OpenProtocol(), as the firmware repeatedly calls
DisconnectController() in an attempt to disconnect the E1kNetDxe
driver from the PCI device handle.

Work around this problem by adding the buggy VirtualBox E1kNetDxe
driver to the veto list.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-23 16:51:10 +01:00
ae435cb4cc [efi] Process veto objects in reverse order of enumeration
While not guaranteed by the UEFI specification, the enumeration of
handles, protocols, and openers will generally return results in order
of creation.  Processing these objects in reverse order (as is already
done when calling DisconnectController() on the list of all handles)
will generally therefore perform the forcible uninstallation
operations in reverse order of object creation, which minimises the
number of implicit operations performed (e.g. when disconnecting a
controller that itself still has existent child controllers).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-23 16:51:10 +01:00
f8a0d1c0b8 [efi] Check for protocols opened by vetoed driver and image handles
The UEFI specification states that the AgentHandle may be either the
driving binding protocol handle or the image handle.

Check for both handles when searching for stale handles to be forcibly
closed on behalf of a vetoed driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-23 16:51:10 +01:00
f0b1025503 [efi] Unload vetoed drivers by image handle rather than driver handle
In most cases, the driver handle will be the image handle itself.
However, this is not required by the UEFI specification, and some
images will install multiple driver binding handles.

Use the image handle (extracted from the driver binding protocol
instance) when attempting to unload the driver's image.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-23 16:51:10 +01:00
c832580f19 [efi] Pass more detailed driver information to veto methods
Pass the driver binding handle, the driver binding protocol instance,
the image handle, and the loaded image protocol instance to all veto
methods.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-23 16:22:27 +01:00
9a118322a0 [efi] Show manufacturer in veto debug output
Simplify the process of adding new entries to the veto list by
including the manufacturer name within the standard debug output.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-22 23:20:37 +01:00
2689a6e776 [efi] Always poll for TX completions
Polling for TX completions is arguably redundant when there are no
transmissions currently in progress.  Commit c6c7e78 ("[efi] Poll for
TX completions only when there is an outstanding TX buffer") switched
to setting the PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS flag only when
there is an in-progress transmission awaiting completion, in order to
reduce reported TX errors and debug message noise from buggy NII
implementations that report spurious TX completions whenever the
transmit queue is empty.

Some other NII implementations (observed with the Realtek driver in a
Dell Latitude 3440) seem to have a bug in the transmit datapath
handling which results in the transmit ring freezing after sending a
few hundred packets under heavy load.  The symptoms are that the
TPPoll register's NPQ bit remains set and the 256-entry transmit ring
contains a large number of uncompleted descriptors (with the OWN bit
set), the first two of which have identical data buffer addresses.

Though iPXE will submit at most one in-progress transmission via NII,
the Dell/Realtek driver seems to make a page-aligned copy of each
transmit data buffer and to report TX completions immediately without
waiting for the packet to actually be transmitted.  These synthetic TX
completions continue even after the hardware transmit ring freezes.

Setting PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll reduces the
probability of this Dell/Realtek driver bug being triggered by a
factor of around 500, which brings the failure rate down to the point
that it can sensibly be managed by external logic such as the
"--timeout" option for image downloads.  Closing and reopening the
interface (via "ifclose"/"ifopen") will clear the error condition and
allow transmissions to resume.

Revert to setting PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll,
and silently ignore situations in which the hardware reports a
completion when no transmission is in progress.  This approximately
matches the behaviour of the SnpDxe driver, which will also generally
set PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-21 11:49:53 +01:00
4fa4052c7e [efi] Provide read-only access to EFI variables via settings mechanism
EFI variables do not map neatly to the iPXE settings mechanism, since
the EFI variable identifier includes a namespace GUID that cannot
cleanly be supplied as part of a setting name.  Creating a new EFI
variable requires the variable's attributes to be specified, which
does not fit within iPXE's settings concept.

However, EFI variable names are generally unique even without the
namespace GUID, and EFI does provide a mechanism to iterate over all
existent variables.  We can therefore provide read-only access to EFI
variables by comparing only the names and ignoring the namespace
GUIDs.

Provide an "efi" settings block that implements this mechanism using a
syntax such as:

  echo Platform language is ${efi/PlatformLang:string}

  show efi/SecureBoot:int8

Settings are returned as raw binary values by default since an EFI
variable may contain boolean flags, integer values, ASCII strings,
UCS-2 strings, EFI device paths, X.509 certificates, or any other
arbitrary blob of data.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-09 14:37:44 +01:00
25a3d3acab [efi] Veto the VMware UefiPxeBcDxe driver
The EDK2 UefiPxeBcDxe driver includes some remarkably convoluted and
unsafe logic in its driver binding protocol Start() and Stop() methods
in order to support a pair of nominally independent driver binding
protocols (one for IPv4, one for IPv6) sharing a single dynamically
allocated data structure.  This PXEBC_PRIVATE_DATA structure is
installed as a dummy protocol on the NIC handle in order to allow both
IPv4 and IPv6 driver binding protocols to locate it as needed.

The error handling code path in the UefiPxeBcDxe driver's Start()
method may attempt to uninstall the dummy protocol but fail to do so.
This failure is ignored and the containing memory is subsequently
freed anyway.  On the next invocation of the driver binding protocol,
it will find and use this already freed block of memory.  At some
point another memory allocation will occur, the PXEBC_PRIVATE_DATA
structure will be corrupted, and some undefined behaviour will occur.

The UEFI firmware used in VMware ESX 8 includes some proprietary
changes which attempt to install copies of the EFI_LOAD_FILE_PROTOCOL
and EFI_PXE_BASE_CODE_PROTOCOL instances from the IPv4 child handle
onto the NIC handle (along with a VMware-specific protocol with GUID
5190120d-453b-4d48-958d-f0bab3bc2161 and a NULL instance pointer).
This will inevitably fail with iPXE, since the NIC handle already
includes an EFI_LOAD_FILE_PROTOCOL instance.

These VMware proprietary changes end up triggering the unsafe error
handling code path described above.  The typical symptom is that an
attempt to exit from iPXE back to the UEFI firmware will crash the VM
with a General Protection fault from within the UefiPxeBcDxe driver:
this happens when the UefiPxeBcDxe driver's Stop() method attempts to
call through a function pointer in the (freed) PXEBC_PRIVATE_DATA
structure, but the function pointer has by then been overwritten by
UCS-2 character data from an unrelated memory allocation.

Work around this failure by adding the VMware UefiPxeBcDxe driver to
the driver veto list.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-08 12:24:07 +01:00
8ab9bdca4f [efi] Include protocol interface address in debug output
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-08 11:15:27 +01:00
12776acce5 [efi] Add UefiPxeBcDxe module GUID
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 13:00:24 +01:00
367e022b5e [efi] Add HttpBootDxe module GUID
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 13:00:24 +01:00
b9a60fb0b7 [efi] Add new IScsiDxe module GUID
The old IPv4-only IScsiDxe driver in MdeModulePkg/Universal/Network
was replaced by a dual-stack IScsiDxe driver in NetworkPkg.

Add the module GUID for this driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 12:57:51 +01:00
a64764d10f [efi] Add HTTP header and GUID definitions
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 12:57:51 +01:00
bc75bbaf17 [efi] Add DNS headers and GUID definitions
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 12:57:51 +01:00
e7adf5701f [efi] Add Ip4Config2 header and GUID definition
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 12:57:51 +01:00
92ab2de3a4 [efi] Add IPv6 versions of existing IPv4 headers and GUID definitions
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 12:27:06 +01:00
3184ff74eb [efi] Update to current EDK2 headers
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 12:24:42 +01:00
9cb0a4b8ec [efi] Disable static assertions in EFI headers on non-EFI platforms
The EDK2 headers may be included even in builds for non-EFI platforms.
Commits such as 9de6c45 ("[arm] Use -fno-short-enums for all 32-bit
ARM builds") have so far ensured that the compile-time checks within
the EDK2 headers will pass even when building for a non-EFI platform.

As a more general solution, temporarily disable static assertions
while including UefiBaseType.h if building on a non-EFI platform.
This avoids the need to modify the ABI on other platforms.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-07 12:24:03 +01:00
b0093571f8 [crypto] Add support for PKCS#8 private key format
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-06-02 13:54:42 +01:00
6a7f560e60 [efi] Implement "shim" as a dummy command on non-EFI platforms
The "shim" command will skip downloading the shim binary (and is
therefore a conditional no-op) if there is already a selected EFI
image that can be executed directly via LoadImage()/StartImage().
This allows the same iPXE script to be used with Secure Boot either
enabled or disabled.

Generalise this further to provide a dummy "shim" command that is an
unconditional no-op on non-EFI platforms.  This then allows the same
iPXE script to be used for BIOS, EFI with Secure Boot disabled, or EFI
with Secure Boot enabled.

The same effect could be achieved by using "iseq ${platform} efi"
within the script, but this would complicate end-user documentation.

To minimise the code size impact, the dummy "shim" command is a pure
no-op that does not call parse_options() and so will ignore even
standardised arguments such as "--help".

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-24 10:20:31 +01:00
5b43181436 [efi] Support versions of shim that perform SBAT verification
The UEFI shim implements a fairly nicely designed revocation mechanism
designed around the concept of security generations.  Unfortunately
nobody in the shim community has thus far added the relevant metadata
to the Linux kernel, with the result that current versions of shim are
incapable of booting current versions of the Linux kernel.

Experience shows that there is unfortunately no point in trying to get
a fix for this upstreamed into shim.  We therefore default to working
around this undesirable behaviour by patching data read from the
"SbatLevel" variable used to hold SBAT configuration.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-23 15:27:20 +01:00
d2e1601cf4 [efi] Separate GetMemoryMap() wrapper from shim unlocker
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-23 14:52:30 +01:00
95b8338f0d [efi] Add "shim" command
Allow a shim to be used to facilitate booting a kernel using a script
such as:

    kernel /images/vmlinuz console=ttyS0,115200n8
    initrd /images/initrd.img
    shim /images/shimx64.efi
    boot

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-22 15:37:11 +01:00
28184b7c22 [efi] Add support for executing images via a shim
Add support for using a shim as a helper to execute an EFI image.
When a shim has been specified via shim(), the shim image will be
passed to LoadImage() instead of the selected EFI image and the
command line will be prepended with the name of the selected EFI
image.  The selected EFI image will be accessible to the shim via the
virtual filesystem as a hidden file.

Reduce the Secure Boot attack surface by removing, where possible, the
spurious requirement for a third party second stage loader binary such
as GRUB to be used solely in order to call the "shim lock protocol"
entry point.

Do not install the EFI PXE APIs when using a shim, since if shim finds
EFI_PXE_BASE_CODE_PROTOCOL on the loaded image's device handle then it
will attempt to download files afresh instead of using the files
already downloaded by iPXE and exposed via the EFI_SIMPLE_FILE_SYSTEM
protocol.  (Experience shows that there is no point in trying to get a
fix for this upstreamed into shim.)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-22 15:37:11 +01:00
3c214f0465 [efi] Add definitions for the UEFI shim lock protocol
The UEFI shim includes a "shim lock protocol" that can be used by a
third party second stage loader such as GRUB to verify a kernel image.

Add definitions for the relevant portions of this protocol interface.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-22 15:37:11 +01:00
ce2200d5fb [efi] Add efi_asprintf() and efi_vasprintf()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-22 15:10:16 +01:00
c4a8d90387 [image] Generalise concept of selected image
Most image flags are independent values: any combination of flags may
be set for any image, and the flags for one image are independent of
the flags for any other image.  The "selected" flag does not follow
this pattern: at most one image may be marked as selected at any time.

When invoking a kernel via the UEFI shim, there will be multiple
"special" images: the selected kernel itself, the shim image, and
potentially a shim-signed GRUB binary to be used as a crutch to assist
shim in loading the kernel (since current versions of the UEFI shim
are not capable of directly loading a Linux kernel).

Remove the "selected" image flag and replace it with a general concept
of an image tag with the same semantics: a given tag may be assigned
to at most one image, an image may be found by its tag only while the
image is currently registered, and a tag will survive unregistration
and reregistration of an image (if it has not already been assigned to
a new image).  For visual consistency, also replace the current image
pointer with a current image tag.

The image pointer stored within the image tag holds only a weak
reference to the image, since the selection of an image should not
prevent that image from being freed.  (The strong reference to the
currently executing image is held locally within the execution scope
of image_exec(), and is logically separate from the current image
pointer.)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-17 14:42:03 +01:00
79d85e29aa [efi] Attempt to detect EFI images that fail Secure Boot verification
An EFI image that is rejected by LoadImage() due to failing Secure
Boot verification is still an EFI image.  Unfortunately, the extremely
broken UEFI Secure Boot model provides no way for us to unambiguously
determine that a valid EFI executable image was rejected only because
it failed signature verification.  We must therefore use heuristics to
guess whether not an image that was rejected by LoadImage() could
still be loaded via a separate PE loader such as the UEFI shim.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-17 14:40:50 +01:00
d27cd8196d [ci] Work around Ubuntu packaging metadata issues
The libc6-dbg:i386 package has spontaneously started failing to
install from the Azure package repositories used by the GitHub Actions
runners, with the somewhat recalcitrant error message:

 libc6:i386: Depends: libgcc-s1:i386 but it is not going to be installed

Work around this unexplained issue by explicitly requesting
installation of the libgcc-s1:i386 package.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-15 14:56:28 +01:00
03eea19c19 [efi] Allow currently selected image to be opened as "grub*.efi"
Versions 15.4 and earlier of the UEFI shim are incapable of correctly
parsing the command line in order to extract the second stage loader
filename, and will always attempt to load "grubx64.efi" or equivalent.

Versions 15.3 and later of the UEFI shim are currently incapable of
loading a Linux kernel directly anyway, since the kernel does not
include SBAT metadata.  These versions will require a genuine
shim-signed GRUB binary to be used as a crutch to assist shim in
loading a Linux kernel.

This leaves versions 15.2 and earlier of the UEFI shim (as currently
used in e.g. RHEL7) as being capable of directly loading a Linux
kernel, but incorrectly attempting to load it using the filename
"grubx64.efi" or equivalent.  To support the bugs in these older
versions of the UEFI shim, allow the currently selected image to be
opened via any filename of the form "grub*.efi".

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-05 14:54:20 +01:00
0bb0aea878 [efi] Allow currently executing image to be opened via virtual filesystem
When invoking a kernel via the UEFI shim, the kernel image must be
accessible via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL but must not be present
in the magic initrd constructed from all registered images.

Re-register a currently executing EFI image and mark it as hidden,
thereby allowing it to be accessed via the virtual filesystem exposed
via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL without appearing in the magic
initrd contents.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-05 14:54:20 +01:00
f9beb20e99 [image] Allow for images to be hidden from lists of all images
When invoking a kernel via the UEFI shim, the kernel (and potentially
also a helper binary such as GRUB) must be accessible via the virtual
filesystem exposed via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL but must not be
present in the magic initrd constructed from all registered images.

Allow for images to be flagged as hidden, which will cause them to be
excluded from API-level lists of all images such as the virtual
filesystem directory contents, the magic initrd, or the Multiboot
module list.  Hidden images remain visible to iPXE commands including
"imgstat", which will show a "[HIDDEN]" flag for such images.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-05 14:54:20 +01:00
f93e6b712f [efi] Show original filenames in debug messages
Show the original filename as used by the consumer when calling our
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL's Open() method.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-05 13:05:28 +01:00
22cc65535a [efi] Allow downloaded images to take precedence over constructed files
Try searching for a matching registered image before checking for
fixed filenames (such as "initrd.magic" for the dynamically generated
magic initrd file).  This minimises surprise by ensuring that an
explicitly downloaded image will always be used verbatim.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-05-05 13:05:28 +01:00
bd13697446 [efi] Allow for sections to be excluded from the generated PE file
Hybrid bzImage and UEFI binaries (such as wimboot) include a bzImage
header within a section starting at offset zero, with the PE header
effectively occupying unused space within this section.  This section
should not appear as a named section in the resulting PE file.

Allow for the existence of hidden sections that do not result in a
section header being written to the PE file.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-04-10 17:02:45 +01:00
9fb28080d9 [efi] Allow elf2efi to be used for hybrid binaries
Hybrid 32-bit BIOS and 64-bit UEFI binaries (such as wimboot) may
include R_X86_64_32 relocation records for the 32-bit BIOS portions.
These should be ignored when generating PE relocation records, since
they apply only to code that cannot be executed within the context of
the 64-bit UEFI binary, and creating a 4-byte relocation record is
invalid in a binary that may be relocated anywhere within the 64-bit
address space (see commit 907cffb "[efi] Disallow R_X86_64_32
relocations").

Add a "--hybrid" option to elf2efi, which will cause R_X86_64_32
relocation records to be silently discarded.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-04-10 16:51:51 +01:00
1e4c3789e9 [efi] Shrink size of data directory in PE header
Hybrid bzImage and UEFI binaries (such as wimboot) require the PE
header to be kept as small as possible, since the bzImage header
starts at a fixed offset 0x1f1.

The EFI_IMAGE_OPTIONAL_HEADER structures in PeImage.h define an
optional header containing 16 data directory entries, of which the
last eight are unused in binaries that we create.  Shrink the data
directory to contain only the first eight entries, to minimise the
overall size of the PE header.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-04-10 16:51:49 +01:00
0d04635ef0 [efi] Remove redundant zero padding in PE header
Hybrid bzImage and UEFI binaries (such as wimboot) require the PE
header to be kept as small as possible, since the bzImage header
starts at a fixed offset 0x1f1.

The PE header currently includes 128 bytes of zero padding between the
DOS and NT header portions.  This padding has been present since
commit 81d92c6 ("[efi] Add EFI image format and basic runtime
environment") first added support for EFI images in iPXE, and was
included on the basis of matching the observed behaviour of the
Microsoft toolchain.  There appears to be no requirement for this
padding to exist: EDK2 binaries built with gcc include only 64 bytes
of zero padding, Linux kernel binaries include 66 bytes of non-zero
padding, and wimboot binaries include no padding at all.

Remove the unnecessary padding between the DOS and NT header portions
to minimise the overall size of the PE header.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-04-10 16:50:10 +01:00
1d1cf74a5e [tls] Handle fragmented handshake records
Originally-implemented-by: Christopher Schenk <christopher@cschenk.net>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-30 23:38:43 +01:00
aa368ba529 [tls] Pass I/O buffer to received record handlers
Prepare for the possibility that a record handler may choose not to
consume the entire record by passing the I/O buffer and requiring the
handler to mark consumed data using iob_pull().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-30 23:37:55 +01:00
2c6a15d2a3 [tls] Clean up change cipher spec record handling
Define and use data structures and constants for the (single-byte)
change cipher spec records.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-30 16:57:12 +01:00
09e8a15408 [efi] Claim fixed device paths by uninstalling device path protocol
As documented in commits 6a004be ("[efi] Support the initrd
autodetection mechanism in newer Linux kernels") and 04e60a2 ("[efi]
Omit EFI_LOAD_FILE2_PROTOCOL for a zero-length initrd"), the choice in
Linux of using a fixed device path requires bootloaders to allow for
the fact that a previous bootloader may have already installed a
handle with the fixed device path.

We currently deal with this situation by reusing the existing handle,
replacing the EFI_LOAD_FILE2_PROTOCOL instance with our own.  Simplify
the code by instead uninstalling the EFI_DEVICE_PATH_PROTOCOL instance
from the existing handle (if present), thereby allowing the creation
of a new handle to succeed.

Create the new handle only if we have a non-empty initrd to provide.
This works around bugs in bootloaders such as the systemd EFI stub
that fail to allow for the existence of multiple-bootloader chains.
(The workaround is not comprehensive: if the user has downloaded other
images in iPXE before invoking the systemd Unified Kernel Image (UKI),
then the systemd EFI stub will still crash and burn since it fails to
allow for the fact that a previous bootloader has already installed a
handle with the fixed device path.)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-15 16:48:35 +00:00
bf25e23d07 [intel] Add workaround for I210 reset hardware bugs
The Intel I210's packet buffer size registers reset only on power up,
not when a reset signal is asserted.  This can lead to the inability
to pass traffic in the event that the DMA TX Maximum Packet Size
(which does reset to its default value on reset) is bigger than the TX
Packet Buffer Size.

For example, an operating system may be using the time sensitive
networking features of the I210 and the registers may be programmed
correctly, but then a reset signal is asserted and iPXE on the next
boot will be unable to use the I210.

Mimic what Linux does and forcibly set the registers to their default
values.

Signed-off-by: Matt Parrella <parrella.matthew@gmail.com>
2023-03-14 14:44:32 +00:00
8f1c120119 [dhcp] Unregister ProxyDHCP and PXEBS settings on a successful DHCPACK
When a DHCP transaction does not result in the registration of a new
"proxydhcp" or "pxebs" settings block, any existing settings blocks
are currently left unaltered.

This can cause surprising behaviour.  For example: when chainloading
iPXE, the "proxydhcp" and "pxebs" settings blocks may be prepopulated
using cached values from the previous PXE bootloader.  If iPXE
performs a subsequent DHCP request, then the DHCP or ProxyDHCP servers
may choose to respond differently to iPXE.  The response may choose to
omit the ProxyDHCP or PXEBS stages, in which case no new "proxydhcp"
or "pxebs" settings blocks may be registered.  This will result in
iPXE using a combination of both old and new DHCP responses.

Fix by assuming that a successful DHCPACK effectively acquires
ownership of the "proxydhcp" and "pxebs" settings blocks, and that any
existing settings blocks should therefore be unregistered.

Reported-by: Henry Tung <htung@palantir.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-14 11:35:30 +00:00
54fcb7c29c [efi] Use image name instead of pointer value in debug messages
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-07 14:18:00 +00:00
9e1f7a3659 [image] Always unregister currently executing image
We unregister script images during their execution, to prevent a
"boot" command from re-executing the containing script.  This also has
the side effect of preventing executing scripts from showing up within
the Linux magic initrd image (or the Multiboot module list).

Additional logic in bzimage.c and efi_file.c prevents a currently
executing kernel from showing up within the magic initrd image.
Similar logic in multiboot.c prevents the Multiboot kernel from
showing up as a Multiboot module.

This still leaves some corner cases that are not covered correctly.
For example: when using a gzip-compressed kernel image, nothing will
currently hide the original compressed image from the magic initrd.

Fix by moving the logic that temporarily unregisters the current image
from script_exec() to image_exec(), so that it applies to all image
types, and simplify the magic initrd and Multiboot module list
construction logic on the basis that no further filtering of the
registered image list is necessary.

This change has the side effect of hiding currently executing EFI
images from the virtual filesystem exposed by iPXE.  For example, when
using iPXE to boot wimboot, the wimboot binary itself will no longer
be visible within the virtual filesystem.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-07 12:22:19 +00:00
e51e7bbad7 [image] Consistently use for_each_image() to iterate over images
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-06 16:56:37 +00:00
523788ccda [intelx] Add PCI IDs for Intel 82599 10GBASE-T NIC
Signed-off-by: Forest Crossman <cyrozap@gmail.com>
2023-03-05 18:22:18 -06:00
96bb6ba441 [params] Allow for arbitrary HTTP request headers to be specified
Extend the request parameter mechanism to allow for arbitrary HTTP
headers to be specified via e.g.:

  params
  param --header Referer http://www.example.com
  imgfetch http://192.168.0.1/script.ipxe##params

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-01 12:20:02 +00:00
33cb56cf1b [params] Rename "form parameter" to "request parameter"
Prepare for the parameter mechanism to be generalised to specifying
request parameters that are passed via mechanisms other than an
application/x-www-form-urlencoded form.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-01 11:55:04 +00:00
60531ff6e2 [http] Use POST method only if the form parameter list is non-empty
An attempt to use an existent but empty form parameter list will
currently result in an invalid POST request since the Content-Length
header will be missing.

Fix by using GET instead of POST if the form parameter list is empty.
This is a non-breaking change (since the current behaviour produces an
invalid request), and simplifies the imminent generalisation of the
parameter list concept to handle both header and form parameters.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-03-01 11:12:44 +00:00
04e60a278a [efi] Omit EFI_LOAD_FILE2_PROTOCOL for a zero-length initrd
When the Linux kernel is being used with no initrd, iPXE will still
provide a zero-length initrd.magic file within the virtual filesystem.
As of commit 6a004be ("[efi] Support the initrd autodetection
mechanism in newer Linux kernels"), this zero-length file will also be
exposed via an EFI_LOAD_FILE2_PROTOCOL instance on a handle with a
fixed device path.

The correct handling of zero-length files via EFI_LOAD_FILE2_PROTOCOL
is unfortunately not well defined.

Linux expects the first call to LoadFile() to always fail with
EFI_BUFFER_TOO_SMALL.  When the initrd is genuinely zero-length, iPXE
will return success since the buffer is not too small to hold the
(zero-length) file.  This causes Linux to immediately report a
spurious EFI_LOAD_ERROR boot failure.

We could change the logic in iPXE's efi_file_load() to always return
EFI_BUFFER_TOO_SMALL if Buffer is NULL on entry.  Since the correct
behaviour of LoadFile() in the corner case of a zero-length file is
left undefined by the UEFI specification, this would be permissible.

Unfortunately this approach would not fix the problem.  If we return
EFI_BUFFER_TOO_SMALL and set the file length to zero, then Linux will
call the boot services AllocatePages() method with a zero length.  In
at least the EDK2 implementation, this combination of parameters will
cause AllocatePages() to return EFI_OUT_OF_RESOURCES, and Linux will
again report a boot failure.

Another approach would be to install the initrd device path handle
only if we have a non-empty initrd to offer.  Unfortunately this would
lead to a failure in yet another corner case: if a previous bootloader
has installed an initrd device path handle (e.g. to pass a boot script
to iPXE) then we must not leave that initrd in place, since then our
loaded kernel would end up seeing the wrong initrd content.

The cleanest fix seems to be to ensure that the initrd device path
handle is installed with the EFI_DEVICE_PATH_PROTOCOL instance present
but with the EFI_LOAD_FILE2_PROTOCOL instance absent (and forcibly
uninstalled if necessary), matching the state in which we leave the
handle after uninstalling our virtual filesystem.  Linux will then not
find any handle that supports EFI_LOAD_FILE2_PROTOCOL within the fixed
device path, and so will fall through to trying other mechanisms to
locate the initrd.

Reported-by: Chris Bradshaw <cwbshaw@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-28 12:30:54 +00:00
471599dc77 [efi] Split out EFI_RNG_PROTOCOL as a separate entropy source
Commit 7ca801d ("[efi] Use the EFI_RNG_PROTOCOL as an entropy source
if available") added EFI_RNG_PROTOCOL as an alternative entropy source
via an ad-hoc mechanism specific to efi_entropy.c.

Split out EFI_RNG_PROTOCOL to a separate entropy source, and allow the
entropy core to handle the selection of RDRAND, EFI_RNG_PROTOCOL, or
timer ticks as the active source.

The fault detection logic added in commit a87537d ("[efi] Detect and
disable seriously broken EFI_RNG_PROTOCOL implementations") may be
removed completely, since the failure will already be detected by the
generic ANS X9.82-mandated repetition count test and will now be
handled gracefully by the entropy core.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-20 14:53:10 +00:00
7d71cf318a [rng] Allow for entropy sources that fail during startup tests
Provide per-source state variables for the repetition count test and
adaptive proportion test, to allow for the situation in which an
entropy source can be enabled but then fails during the startup tests,
thereby requiring an alternative entropy source to be used.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-20 14:53:10 +00:00
6625e49cea [tables] Allow any lvalue to be used as a table iterator
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-20 13:46:45 +00:00
9f17d1116d [rng] Allow entropy source to be selected at runtime
As noted in commit 3c83843 ("[rng] Check for several functioning RTC
interrupts"), experimentation shows that Hyper-V cannot be trusted to
reliably generate RTC interrupts.  (As noted in commit f3ba0fb
("[hyperv] Provide timer based on the 10MHz time reference count
MSR"), Hyper-V appears to suffer from a general problem in reliably
generating any legacy interrupts.)  An alternative entropy source is
therefore required for an image that may be used in a Hyper-V Gen1
virtual machine.

The x86 RDRAND instruction provides a suitable alternative entropy
source, but may not be supported by all CPUs.  We must therefore allow
for multiple entropy sources to be compiled in, with the single active
entropy source selected only at runtime.

Restructure the internal entropy API to allow a working entropy source
to be detected and chosen at runtime.

Enable the RDRAND entropy source for all x86 builds, since it is
likely to be substantially faster than any other source.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-17 21:29:51 +00:00
2733c4763a [iscsi] Limit maximum transfer size to MaxBurstLength
We currently specify only the iSCSI default value for MaxBurstLength
and ignore any negotiated value, since our internal block device API
allows only for receiving directly into caller-allocated buffers and
so we have no intrinsic limit on burst length.

A conscientious target may however refuse to attempt a transfer that
we request for a number of blocks that would exceed the negotiated
maximum burst length.

Fix by recording the negotiated maximum burst length and using it to
limit the maximum number of blocks per transfer as reported by the
SCSI layer.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-16 13:27:25 +00:00
cff857461b [rng] Add RDRAND as an entropy source
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-15 22:43:33 +00:00
6a004be0cc [efi] Support the initrd autodetection mechanism in newer Linux kernels
Linux 5.7 added the ability to autodetect an initrd by searching for a
handle via a fixed vendor-specific "Linux initrd device path" and then
locating and using the EFI_LOAD_FILE2_PROTOCOL instance on that
handle.

This maps quite naturally onto our existing concept of a "magic
initrd" as introduced for EFI in commit e5f0255 ("[efi] Provide an
"initrd.magic" file for use by UEFI kernels").

Add an EFI_LOAD_FILE2_PROTOCOL instance to our EFI virtual files
(backed by simply calling the existing EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
method to read from the file), and install the protocol instance for
the "initrd.magic" virtual file onto a new device handle that also
provides the Linux initrd device path.

The design choice in Linux of using a single fixed device path makes
this unfortunately messy to support, since device paths must be unique
within a system.  When multiple bootloaders are used (e.g. GRUB
loading iPXE loading Linux) then only one bootloader can ever install
the device path onto a handle.  Subsequent bootloaders must locate the
existing handle and replace the load file protocol instance with their
own.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-15 17:36:47 +00:00
cf9ad00afc [efi] Fix debug message when reading from EFI virtual files
Show the requested range when a caller reads from a virtual file via
the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL interface.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-15 17:20:39 +00:00
76a286530a [image] Check delimiters when parsing command-line key-value arguments
The Linux kernel bzImage image format and the CPIO archive constructor
will parse the image command line for certain arguments of the form
"key=value".  This parsing is currently implemented using strstr() in
a way that can cause a false positive suffix match.  For example, a
command line containing "highmem=<n>" would erroneously be treated as
containing a value for "mem=<n>".

Fix by centralising the logic used for parsing such arguments, and
including a check that the argument immediately follows a whitespace
delimiter (or is at the start of the string).

Reported-by: Filippo Giunchedi <filippo@esaurito.net>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-14 11:13:45 +00:00
3c83843e11 [rng] Check for several functioning RTC interrupts
Commit 74222cd ("[rng] Check for functioning RTC interrupt") added a
check that the RTC is capable of generating interrupts via the legacy
PIC, since this mechanism appears to be broken in some Hyper-V virtual
machines.

Experimentation shows that the RTC is sometimes capable of generating
a single interrupt, but will then generate no subsequent interrupts.
This currently causes rtc_entropy_check() to falsely detect that the
entropy gathering mechanism is functional.

Fix by checking for several RTC interrupts before declaring that it is
a functional entropy source.

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-11 15:11:51 +00:00
be8ecaf805 [eisa] Check for system board presence before probing for slots
EISA expansion slot I/O port addresses overlap space that may be
assigned to PCI devices, which can lead to register reads and writes
with unwanted side effects during EISA probing.

Reduce the chances of performing EISA probing on PCI devices by
probing EISA slot vendor and product ID registers only if the EISA
system board vendor ID register indicates that the motherboard
supports EISA.

Debugged-by: Václav Ovsík <vaclav.ovsik@gmail.com>
Tested-by: Václav Ovsík <vaclav.ovsik@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-10 23:34:59 +00:00
62a1d5c0f5 [loong64] Add initial support for LoongArch64
Add support for building a LoongArch64 Linux userspace binary.

Signed-off-by: Xiaotian Wu <wuxiaotian@loongson.cn>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-06 21:14:17 +00:00
84cb774390 [test] Include build architecture in test suite banner
The test suites for the various architectures are often run back to
back, and there is currently nothing to visually distinguish one test
run from another.

Include the architecture name within the self-test startup banner, to
aid in visual identification of test results.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-06 21:06:00 +00:00
bfa5262f0e [ci] Cache downloaded packages for GitHub actions
Speed up the "Install packages" step for each CI run by caching the
downloaded packages in /var/cache/apt.

Do not include libc6-dbg:i386 within the cache, since apt seems to
complain if asked to download both gcc-aarch64-linux-gnu and
libc6-dbg:i386 at the same time.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-06 19:59:04 +00:00
ef0a6f4792 [ioapi] Move PAGE_SHIFT to bits/io.h
The PAGE_SHIFT definition is an architectural property, rather than an
aspect of a particular I/O API implementation (of which, in theory,
there may be more than one per architecture).

Reflect this by moving the definition to the top-level bits/io.h for
each architecture.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-06 12:34:21 +00:00
c6901792f0 [build] Allow for per-architecture unprefixed constant operand modifier
Over the years, the undocumented operand modifier used to produce the
unprefixed constant values in __einfo_error() has varied from "%c0" to
"%a0" in commit 1a77466 ("[build] Fix use of inline assembly on GCC
4.8 ARM64 builds") and back to "%c0" in commit 3fb3ffc ("[build] Fix
use of inline assembly on GCC 8 ARM64 builds"), according to the
evolving demands of the toolchain.

LoongArch64 suffers from a similar issue: GCC 13 will allow either,
but the currently released GCC 12 allows only the "%a0" form.

Introduce a macro ASM_NO_PREFIX, defined in bits/compiler.h, to
abstract away this difference and allow different architectures to use
different operand modifiers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-05 23:55:14 +00:00
a2bed43939 [xen] Allow for platforms that have no Xen support
The Xen headers support only x86 and ARM.  Allow for platforms such as
LoongArch64 to build despite the absence of Xen support by providing
an architecture-specific <bits/xen.h> that simply does:

  #ifndef _BITS_XEN_H
  #define _BITS_XEN_H
  #include <ipxe/nonxen.h>
  #endif /* _BITS_XEN_H */

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-05 22:21:36 +00:00
7cc305f7b4 [efi] Enable NET_PROTO_LLDP by default
Requested-by: Christian I. Nilsson <nikize@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-05 18:54:39 +00:00
dc16de3204 [lldp] Add support for the Link Layer Discovery Protocol
Add support for recording LLDP packets and exposing TLV values via the
settings mechanism.  LLDP settings are encoded as

  ${netX.lldp/<prefix>.<type>.<index>.<offset>.<length>}

where

  <type> is the TLV type

  <offset> is the starting offset within the TLV value

  <length> is the length (or zero to read the from <offset> to the end)

  <prefix>, if it has a non-zero value, is the subtype byte string of
  length <offset> to match at the start of the TLV value, up to a
  maximum matched length of 4 bytes

  <index> is the index of the entry matching <type> and <prefix> to be
  accessed, with zero indicating the first matching entry

The <prefix> is designed to accommodate both matching of the OUI
within an organization-specific TLV (e.g. 0x0080c2 for IEEE 802.1
TLVs) and of a subtype byte as found within many TLVs.

This encoding allows most LLDP values to be extracted easily.  For
example

  System name: ${netX.lldp/5.0.0.0:string}

  System description: ${netX.lldp/6.0.0.0:string}

  Port description: ${netX.lldp/4.0.0.0:string}

  Port interface name: ${netX.lldp/5.2.0.1.0:string}

  Chassis MAC address: ${netX.lldp/4.1.0.1.0:hex}

  Management IPv4 address: ${netX.lldp/5.1.8.0.2.4:ipv4}

  Port VLAN ID: ${netX.lldp/0x0080c2.1.127.0.4.2:int16}

  Port VLAN name: ${netX.lldp/0x0080c2.3.127.0.7.0:string}

  Maximum frame size: ${netX.lldp/0x00120f.4.127.0.4.2:uint16}

Originally-implemented-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-05 18:18:02 +00:00
6c0335adf6 [ci] Update to ubuntu-22.04 GitHub actions runner
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-03 20:08:16 +00:00
8450fa4a7b [dhcp] Ignore DHCPNAK unless originating from the selected DHCP server
RFC 2131 leaves undefined the behaviour of the client in response to a
DHCPNAK that comes from a server other than the selected DHCP server.

A substantial amount of online documentation suggests using multiple
independent DHCP servers with non-overlapping ranges in the same
subnet in order to provide some minimal redundancy.  Experimentation
shows that in this setup, at least ISC dhcpd will send a DHCPNAK in
response to the client's DHCPREQUEST for an address that is not within
the range defined on that server.  (Since the requested address does
lie within the subnet defined on that server, this will happen
regardless of the "authoritative" parameter.)  The client will
therefore receive a DHCPACK from the selected DHCP server along with
one or more DHCPNAKs from each of the non-selected DHCP servers.

Filter out responses from non-selected DHCP servers before checking
for a DHCPNAK, so that these arguably spurious DHCPNAKs will not cause
iPXE to return to the discovery state.

Continue to check for DHCPNAK before filtering out responses for
non-selected lease addresses, since experimentation shows that the
DHCPNAK will usually have an empty yiaddr field.

Reported-by: Anders Blomdell <anders.blomdell@control.lth.se>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-03 19:51:58 +00:00
4e456d9928 [efi] Do not attempt to drive PCI bridge devices
The "bridge" driver introduced in 3aa6b79 ("[pci] Add minimal PCI
bridge driver") is required only for BIOS builds using the ENA driver,
where experimentation shows that we cannot rely on the BIOS to fully
assign MMIO addresses.

Since the driver is a valid PCI driver, it will end up binding to all
PCI bridge devices even on a UEFI platform, where the firmware is
likely to have completed MMIO address assignment correctly.  This has
no impact on most systems since there is generally no UEFI driver for
PCI bridges: the enumeration of the whole PCI bus is handled by the
PciBusDxe driver bound to the root bridge.

Experimentation shows that at least one laptop will freeze at the
point that iPXE attempts to bind to the bridge device.  No deeper
investigation has been carried out to find the root cause.

Fix by causing efipci_supported() to return an error unless the
configuration space header type indicates a non-bridge device.

Reported-by: Marcel Petersen <mp@sbe.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-03 16:10:31 +00:00
d405a0bd84 [util] Add support for LoongArch64 binaries
Signed-off-by: Xiaotian Wu <wuxiaotian@loongson.cn>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-03 12:44:11 +00:00
49c13e81bc [ci] Update to actions/checkout@v3 to silence GitHub warnings
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-03 00:50:16 +00:00
8b645eea16 [xen] Update to current Xen headers
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-02 11:19:44 +00:00
6f250be279 [efi] Allow autoexec script to be located alongside iPXE binary
Try loading the autoexec.ipxe script first from the directory
containing the iPXE binary (based on the relative file path provided
to us via EFI_LOADED_IMAGE_PROTOCOL), then fall back to trying the
root directory.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-01 23:54:19 +00:00
b6304f2984 [realtek] Explicitly disable VLAN offload
Some cards seem to have the receive VLAN tag stripping feature enabled
by default, which causes received VLAN packets to be misinterpreted as
being received by the trunk device.

Fix by disabling VLAN tag stripping in the C+ Command Register.

Debugged-by: Xinming Lai <yiyihu@gmail.com>
Tested-by: Xinming Lai <yiyihu@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-01 19:09:30 +00:00
aa85c2918a [efi] Update to current EDK2 headers
Update to pick up the upstream commit bda715b ("MdePkg: Fix UINT64 and
INT64 word length for LoongArch64").

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-02-01 10:50:47 +00:00
66a2ff442d [tests] Verify ability to sleep the CPU
The self-test suite does not currently ever attempt to sleep the CPU.
This is an operation that may fail (e.g. by attempting to execute a
privileged instruction while running as a Linux userspace binary, or
by halting the CPU with all interrupts disabled).

Add a trivial self-test to exercise the ability to sleep the CPU
without crashing or halting forever.

Inspired-by: Xiaotian Wu <wuxiaotian@loongson.cn>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-31 10:17:57 +00:00
3bcd0d3271 [dhcp] Add IANA-defined values for all current EFI client architectures
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-31 02:00:12 +00:00
4bb521a8c4 [efi] Accept a command line passed to an iPXE image via LoadOptions
Treat a command line passed to iPXE via UEFI LoadOptions as an image
to be registered at startup, as is already done for the .lkrn, .pxe,
and .exe BIOS images.

Originally-implemented-by: Ladi Prosek <lprosek@redhat.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-29 18:56:11 +00:00
b9be454010 [la64] Import LoongArch64 ProcessorBind.h from EDK2 headers
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 19:14:00 +00:00
e3d543437e [efi] Update to current EDK2 headers
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 17:22:25 +00:00
137ca5d877 [efi] Mark ConsoleControl.h as a non-imported header
The obsolete ConsoleControl.h header is no longer present in the
current EDK2 codebase, but is still required for interoperability with
old iMacs.

Add an iPXE include guard to this file so that the EDK2 header import
script will no longer attempt to import it from the EDK2 tree.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 17:22:25 +00:00
900379594a [efi] Remove deleted directories from EDK2 header import script
The IntelFrameworkPkg and EdkCompatibilityPkg directories have been
removed from the EDK2 codebase.  Remove these directories from the
EDK2 header import script.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 17:22:25 +00:00
91944c6341 [efi] Allow for whitespace before #include in imported EDK2 header files
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 17:22:25 +00:00
dac41fc4ec [efi] Detect SPDX licence identifiers in imported EDK2 headers
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 17:22:25 +00:00
5220bdc524 [legal] Add missing FILE_LICENCE declaration to efi_path.c
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 17:15:16 +00:00
38f54fb413 [legal] Add support for the BSD-2-Clause-Patent licence
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2023-01-28 17:07:40 +00:00
183 changed files with 15600 additions and 2070 deletions

View File

@ -4,21 +4,53 @@ on: push
jobs:
cache:
name: Cache
runs-on: ubuntu-22.04
steps:
- name: Cache permissions
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache@v3
with:
path: /var/cache/apt/archives/*.deb
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
apt-cache-
- name: Download packages
run: |
sudo apt update
sudo apt install -y -d -o Acquire::Retries=50 \
mtools syslinux isolinux \
libc6-dev-i386 valgrind \
gcc-arm-none-eabi gcc-aarch64-linux-gnu
x86:
name: x86
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: cache
steps:
- name: Check out code
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache permissions
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache/restore@v3
with:
path: /var/cache/apt/archives/*.deb
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Install packages
run: |
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install -y -o Acquire::Retries=50 \
mtools syslinux isolinux \
libc6-dev-i386 libc6-dbg:i386 valgrind
libc6-dev-i386 valgrind \
libgcc-s1:i386 libc6-dbg:i386
- name: Build (BIOS)
run: |
make -j 4 -C src
@ -32,12 +64,21 @@ jobs:
arm32:
name: ARM32
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: cache
steps:
- name: Check out code
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache permissions
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache/restore@v3
with:
path: /var/cache/apt/archives/*.deb
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Install packages
run: |
sudo apt update
@ -52,12 +93,21 @@ jobs:
arm64:
name: ARM64
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: cache
steps:
- name: Check out code
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache permissions
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache/restore@v3
with:
path: /var/cache/apt/archives/*.deb
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Install packages
run: |
sudo apt update

View File

@ -8,10 +8,10 @@ on:
jobs:
submit:
name: Submit
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Download Coverity Scan
run: |
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \

View File

@ -1,12 +0,0 @@
#ifndef _BITS_ENTROPY_H
#define _BITS_ENTROPY_H
/** @file
*
* ARM-specific entropy API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_ENTROPY_H */

View File

@ -9,6 +9,9 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Page shift */
#define PAGE_SHIFT 12
#include <ipxe/arm_io.h>
#endif /* _BITS_IO_H */

View File

@ -20,9 +20,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** Page shift */
#define PAGE_SHIFT 12
/*
* Physical<->Bus address mappings
*

View File

@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef ASSEMBLY
/** Unprefixed constant operand modifier */
#define ASM_NO_PREFIX "c"
#define __asmcall
#define __libgcc

View File

@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef ASSEMBLY
/** Unprefixed constant operand modifier */
#define ASM_NO_PREFIX "c"
#define __asmcall
#define __libgcc

View File

@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef ASSEMBLY
/** Unprefixed constant operand modifier */
#define ASM_NO_PREFIX "c"
/** Declare a function with standard calling conventions */
#define __asmcall __attribute__ (( cdecl, regparm(0) ))

26
src/arch/loong64/Makefile Normal file
View File

@ -0,0 +1,26 @@
# Assembler section type character
#
ASM_TCHAR := @
ASM_TCHAR_OPS := @
# LoongArch64-specific flags
#
CFLAGS += -fstrength-reduce -fomit-frame-pointer
CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1
# Check if -mno-explicit-relocs is valid
ifeq ($(CCTYPE),gcc)
MNER_TEST = $(CC) -mno-explicit-relocs -x c -c /dev/null -o /dev/null >/dev/null 2>&1
MNER_FLAGS := $(shell $(MNER_TEST) && $(ECHO) '-mno-explicit-relocs')
WORKAROUND_CFLAGS += $(MNER_FLAGS)
endif
# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
CFLAGS += -fshort-wchar
# LoongArch64-specific directories containing source files
SRCDIRS += arch/loong64/core
# Include platform-specific Makefile
MAKEDEPS += arch/loong64/Makefile.$(PLATFORM)
include arch/loong64/Makefile.$(PLATFORM)

View File

@ -0,0 +1,10 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Starting virtual address
#
LDFLAGS += -Ttext=0x120000000
# Include generic Linux Makefile
#
MAKEDEPS += Makefile.linux
include Makefile.linux

View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
* Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
#include <ipxe/bigint.h>
/** @file
*
* Big integer support
*/
/**
* Multiply big integers
*
* @v multiplicand0 Element 0 of big integer to be multiplied
* @v multiplier0 Element 0 of big integer to be multiplied
* @v result0 Element 0 of big integer to hold result
* @v size Number of elements
*/
void bigint_multiply_raw ( const uint64_t *multiplicand0,
const uint64_t *multiplier0,
uint64_t *result0, unsigned int size ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
( ( const void * ) multiplicand0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
( ( const void * ) multiplier0 );
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
( ( void * ) result0 );
unsigned int i;
unsigned int j;
uint64_t multiplicand_element;
uint64_t multiplier_element;
uint64_t *result_elements;
uint64_t discard_low;
uint64_t discard_high;
uint64_t discard_temp_low;
uint64_t discard_temp_high;
/* Zero result */
memset ( result, 0, sizeof ( *result ) );
/* Multiply integers one element at a time */
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
* resulting double-element into the result,
* carrying as necessary. The carry can
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "mul.d %1, %6, %7\n\t"
"mulh.du %2, %6, %7\n\t"
"ld.d %3, %0, 0\n\t"
"ld.d %4, %0, 8\n\t"
"add.d %3, %3, %1\n\t"
"sltu $t0, %3, %1\n\t"
"add.d %4, %4, %2\n\t"
"sltu $t1, %4, %2\n\t"
"add.d %4, %4, $t0\n\t"
"sltu $t0, %4, $t0\n\t"
"or $t0, $t0, $t1\n\t"
"st.d %3, %0, 0\n\t"
"st.d %4, %0, 8\n\t"
"addi.d %0, %0, 16\n\t"
"beqz $t0, 2f\n"
"1:\n\t"
"ld.d %3, %0, 0\n\t"
"add.d %3, %3, $t0\n\t"
"sltu $t0, %3, $t0\n\t"
"st.d %3, %0, 0\n\t"
"addi.d %0, %0, 8\n\t"
"bnez $t0, 1b\n"
"2:"
: "+r" ( result_elements ),
"=&r" ( discard_low ),
"=&r" ( discard_high ),
"=r" ( discard_temp_low ),
"=r" ( discard_temp_high ),
"+m" ( *result )
: "r" ( multiplicand_element ),
"r" ( multiplier_element )
: "t0", "t1" );
}
}
}

View File

@ -0,0 +1,266 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
* Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
/** @file
*
* Optimised string operations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
/**
* Copy memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void loong64_memcpy ( void *dest, const void *src, size_t len ) {
void *discard_dest;
void *discard_end;
const void *discard_src;
size_t discard_offset;
unsigned long discard_data;
unsigned long discard_low;
unsigned long discard_high;
/* If length is too short, then just copy individual bytes.
*/
if ( len < 16 ) {
__asm__ __volatile__ ( "beqz %0, 2f\n\t"
"\n1:\n\t"
"addi.d %0, %0, -1\n\t"
"ldx.b %1, %3, %0\n\t"
"stx.b %1, %2, %0\n\t"
"bnez %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset ),
"=&r" ( discard_data )
: "r" ( dest ), "r" ( src ), "0" ( len )
: "memory", "t0" );
return;
}
/* Copy 16 bytes at a time: one initial
* potentially unaligned access, multiple destination-aligned
* accesses, one final potentially unaligned access.
*/
__asm__ __volatile__ ( "ld.d %3, %1, 0\n\t"
"ld.d %4, %1, 8\n\t"
"addi.d %1, %1, 16\n\t"
"st.d %3, %0, 0\n\t"
"st.d %4, %0, 8\n\t"
"addi.d %0, %0, 16\n\t"
"andi %3, %0, 15\n\t"
"sub.d %0, %0, %3\n\t"
"sub.d %1, %1, %3\n\t"
"addi.d $t0, $zero, 0xf\n\t"
"andn %2, %5, $t0\n\t"
"b 2f\n\t"
"\n1:\n\t"
"ld.d %3, %1, 0\n\t"
"ld.d %4, %1, 8\n\t"
"addi.d %1, %1, 16\n\t"
"st.d %3, %0, 0\n\t"
"st.d %4, %0, 8\n\t"
"addi.d %0, %0, 16\n\t"
"\n2:\n\t"
"bne %0, %2, 1b\n\t"
"ld.d %3, %6, -16\n\t"
"ld.d %4, %6, -8\n\t"
"st.d %3, %5, -16\n\t"
"st.d %4, %5, -8\n\t"
: "=&r" ( discard_dest ),
"=&r" ( discard_src ),
"=&r" ( discard_end ),
"=&r" ( discard_low ),
"=&r" ( discard_high )
: "r" ( dest + len ), "r" ( src + len ),
"0" ( dest ), "1" ( src )
: "memory", "t0" );
}
/**
* Zero memory region
*
* @v dest Destination region
* @v len Length
*/
void loong64_bzero ( void *dest, size_t len ) {
size_t discard_offset;
void *discard_dest;
void *discard_end;
/* If length is too short, then just zero individual bytes.
*/
if ( len < 16 ) {
__asm__ __volatile__ ( "beqz %0, 2f\n\t"
"\n1:\n\t"
"addi.d %0, %0, -1\n\t"
"stx.b $zero, %1, %0\n\t"
"bnez %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset )
: "r" ( dest ), "0" ( len )
: "memory" );
return;
}
/* To zero 16 bytes at a time: one initial
* potentially unaligned access, multiple aligned accesses,
* one final potentially unaligned access.
*/
__asm__ __volatile__ ( "st.d $zero, %0, 0\n\t"
"st.d $zero, %0, 8\n\t"
"addi.d %0, %0, 16\n\t"
"addi.w $t0, $zero, 15\n\t"
"andn %0, %0, $t0\n\t"
"addi.w $t0, $zero, 15\n\t"
"andn %1, %2, $t0\n\t"
"b 2f\n\t"
"\n1:\n\t"
"st.d $zero, %0, 0\n\t"
"st.d $zero, %0, 8\n\t"
"addi.d %0, %0, 16\n\t"
"\n2:\n\t"
"bne %0, %1, 1b\n\t"
"st.d $zero, %2, -16\n\t"
"st.d $zero, %2, -8\n\t"
: "=&r" ( discard_dest ),
"=&r" ( discard_end )
: "r" ( dest + len ), "0" ( dest )
: "memory", "t0" );
}
/**
* Fill memory region
*
* @v dest Destination region
* @v len Length
* @v character Fill character
*
* The unusual parameter order is to allow for more efficient
* tail-calling to loong64_memset() when zeroing a region.
*/
void loong64_memset ( void *dest, size_t len, int character ) {
size_t discard_offset;
/* Use optimised zeroing code if applicable */
if ( character == 0 ) {
loong64_bzero ( dest, len );
return;
}
/* Fill one byte at a time. Calling memset() with a non-zero
* value is relatively rare and unlikely to be
* performance-critical.
*/
__asm__ __volatile__ ( "beqz %0, 2f\n\t"
"\n1:\n\t"
"addi.d %0, %0, -1\n\t"
"stx.b %2, %1, %0\n\t"
"bnez %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset )
: "r" ( dest ), "r" ( character ), "0" ( len )
: "memory" );
}
/**
* Copy (possibly overlapping) memory region forwards
*
* @v dest Destination region
* @v src Source region
* @v len Length
*/
void loong64_memmove_forwards ( void *dest, const void *src, size_t len ) {
void *discard_dest;
const void *discard_src;
unsigned long discard_data;
/* Assume memmove() is not performance-critical, and perform a
* bytewise copy for simplicity.
*/
__asm__ __volatile__ ( "b 2f\n\t"
"\n1:\n\t"
"ld.b %2, %1, 0\n\t"
"addi.d %1, %1, 1\n\t"
"st.b %2, %0, 0\n\t"
"addi.d %0, %0, 1\n\t"
"\n2:\n\t"
"bne %0, %3, 1b\n\t"
: "=&r" ( discard_dest ),
"=&r" ( discard_src ),
"=&r" ( discard_data )
: "r" ( dest + len ), "0" ( dest ), "1" ( src )
: "memory" );
}
/**
* Copy (possibly overlapping) memory region backwards
*
* @v dest Destination region
* @v src Source region
* @v len Length
*/
void loong64_memmove_backwards ( void *dest, const void *src, size_t len ) {
size_t discard_offset;
unsigned long discard_data;
/* Assume memmove() is not performance-critical, and perform a
* bytewise copy for simplicity.
*/
__asm__ __volatile__ ( "beqz %0, 2f\n\t"
"\n1:\n\t"
"addi.d %0, %0, -1\n\t"
"ldx.b %1, %3, %0\n\t"
"stx.b %1, %2, %0\n\t"
"bnez %0, 1b\n\t"
"\n2:\n\t"
: "=&r" ( discard_offset ),
"=&r" ( discard_data )
: "r" ( dest ), "r" ( src ), "0" ( len )
: "memory" );
}
/**
* Copy (possibly overlapping) memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
*/
void loong64_memmove ( void *dest, const void *src, size_t len ) {
if ( dest <= src ) {
loong64_memmove_forwards ( dest, src, len );
} else {
loong64_memmove_backwards ( dest, src, len );
}
}

View File

@ -0,0 +1,53 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", %progbits
.text
/*
int setjmp(jmp_buf env);
*/
.globl setjmp
.type setjmp, %function
setjmp:
/* Store registers */
st.d $s0, $a0, 0x0
st.d $s1, $a0, 0x8
st.d $s2, $a0, 0x10
st.d $s3, $a0, 0x18
st.d $s4, $a0, 0x20
st.d $s5, $a0, 0x28
st.d $s6, $a0, 0x30
st.d $s7, $a0, 0x38
st.d $s8, $a0, 0x40
st.d $fp, $a0, 0x48
st.d $sp, $a0, 0x50
st.d $ra, $a0, 0x58
move $a0, $zero
jirl $zero, $ra, 0
.size setjmp, . - setjmp
/*
void longjmp(jmp_buf env, int val);
*/
.globl longjmp
.type longjmp, %function
longjmp:
/* Restore registers */
ld.d $s0, $a0, 0x0
ld.d $s1, $a0, 0x8
ld.d $s2, $a0, 0x10
ld.d $s3, $a0, 0x18
ld.d $s4, $a0, 0x20
ld.d $s5, $a0, 0x28
ld.d $s6, $a0, 0x30
ld.d $s7, $a0, 0x38
ld.d $s8, $a0, 0x40
ld.d $fp, $a0, 0x48
ld.d $sp, $a0, 0x50
ld.d $ra, $a0, 0x58
addi.d $a0, $zero, 1 # a0 = 1
beqz $a1, .exit # if (a1 == 0); goto L0
move $a0, $a1 # a0 = a1
.exit:
jirl $zero, $ra, 0
.size longjmp, . - longjmp

View File

@ -0,0 +1,12 @@
#ifndef _BITS_ACPI_H
#define _BITS_ACPI_H
/** @file
*
* LoongArch64-specific ACPI API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_ACPI_H */

View File

@ -0,0 +1,336 @@
#ifndef _BITS_BIGINT_H
#define _BITS_BIGINT_H
/** @file
*
* Big integer support
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
#include <strings.h>
/** Element of a big integer */
typedef uint64_t bigint_element_t;
/**
* Initialise big integer
*
* @v value0 Element 0 of big integer to initialise
* @v size Number of elements
* @v data Raw data
* @v len Length of raw data
*/
static inline __attribute__ (( always_inline )) void
bigint_init_raw ( uint64_t *value0, unsigned int size,
const void *data, size_t len ) {
size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
uint8_t *value_byte = ( ( void * ) value0 );
const uint8_t *data_byte = ( data + len );
/* Copy raw data in reverse order, padding with zeros */
while ( len-- )
*(value_byte++) = *(--data_byte);
while ( pad_len-- )
*(value_byte++) = 0;
}
/**
* Add big integers
*
* @v addend0 Element 0 of big integer to add
* @v value0 Element 0 of big integer to be added to
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
uint64_t *discard_addend;
uint64_t *discard_value;
uint64_t discard_addend_i;
uint64_t discard_value_i;
unsigned int discard_size;
__asm__ __volatile__ ( "move $t0, $zero\n"
"1:\n\t"
"ld.d %3, %0, 0\n\t"
"addi.d %0, %0, 8\n\t"
"ld.d %4, %1, 0\n\t"
"add.d %4, %4, $t0\n\t"
"sltu $t0, %4, $t0\n\t"
"add.d %4, %4, %3\n\t"
"sltu $t1, %4, %3\n\t"
"or $t0, $t0, $t1\n\t"
"st.d %4, %1, 0\n\t"
"addi.d %1, %1, 8\n\t"
"addi.w %2, %2, -1\n\t"
"bnez %2, 1b"
: "=r" ( discard_addend ),
"=r" ( discard_value ),
"=r" ( discard_size ),
"=r" ( discard_addend_i ),
"=r" ( discard_value_i ),
"+m" ( *value )
: "0" ( addend0 ),
"1" ( value0 ),
"2" ( size )
: "t0", "t1" );
}
/**
* Subtract big integers
*
* @v subtrahend0 Element 0 of big integer to subtract
* @v value0 Element 0 of big integer to be subtracted from
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
unsigned int size ) {
uint64_t *discard_subtrahend;
uint64_t *discard_value;
uint64_t discard_subtrahend_i;
uint64_t discard_value_i;
unsigned int discard_size;
unsigned int flag = 0;
discard_subtrahend = (uint64_t*) subtrahend0;
discard_value = value0;
discard_size = size;
do {
discard_subtrahend_i = *discard_subtrahend;
discard_subtrahend++;
discard_value_i = *discard_value;
discard_value_i = discard_value_i - discard_subtrahend_i - flag;
if ( *discard_value < (discard_subtrahend_i + flag)) {
flag = 1;
} else {
flag = 0;
}
*discard_value = discard_value_i;
discard_value++;
discard_size -= 1;
} while (discard_size != 0);
}
/**
* Rotate big integer left
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
uint64_t *discard_value;
uint64_t discard_value_i;
unsigned int discard_size;
uint64_t current_value_i;
unsigned int flag = 0;
discard_value = value0;
discard_size = size;
do {
discard_value_i = *discard_value;
current_value_i = discard_value_i;
discard_value_i += discard_value_i + flag;
if (discard_value_i < current_value_i) {
flag = 1;
} else {
flag = 0;
}
*discard_value = discard_value_i;
discard_value++;
discard_size -= 1;
} while ( discard_size != 0 );
}
/**
* Rotate big integer right
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_ror_raw ( uint64_t *value0, unsigned int size ) {
uint64_t *discard_value;
uint64_t discard_value_i;
uint64_t discard_value_j;
unsigned int discard_size;
discard_value = value0;
discard_size = size;
discard_value_j = 0;
do {
discard_size -= 1;
discard_value_i = *(discard_value + discard_size);
discard_value_j = (discard_value_j << 63) | (discard_value_i >> 1);
*(discard_value + discard_size) = discard_value_j;
discard_value_j = discard_value_i;
} while ( discard_size > 0 );
}
/**
* Test if big integer is equal to zero
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret is_zero Big integer is equal to zero
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_zero_raw ( const uint64_t *value0, unsigned int size ) {
const uint64_t *value = value0;
uint64_t value_i;
do {
value_i = *(value++);
if ( value_i )
break;
} while ( --size );
return ( value_i == 0 );
}
/**
* Compare big integers
*
* @v value0 Element 0 of big integer
* @v reference0 Element 0 of reference big integer
* @v size Number of elements
* @ret geq Big integer is greater than or equal to the reference
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_geq_raw ( const uint64_t *value0, const uint64_t *reference0,
unsigned int size ) {
const uint64_t *value = ( value0 + size );
const uint64_t *reference = ( reference0 + size );
uint64_t value_i;
uint64_t reference_i;
do {
value_i = *(--value);
reference_i = *(--reference);
if ( value_i != reference_i )
break;
} while ( --size );
return ( value_i >= reference_i );
}
/**
* Test if bit is set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @v bit Bit to test
* @ret is_set Bit is set
*/
static inline __attribute__ (( always_inline )) int
bigint_bit_is_set_raw ( const uint64_t *value0, unsigned int size,
unsigned int bit ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( const void * ) value0 );
unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
return ( !! ( value->element[index] & ( 1UL << subindex ) ) );
}
/**
* Find highest bit set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret max_bit Highest bit set + 1 (or 0 if no bits set)
*/
static inline __attribute__ (( always_inline )) int
bigint_max_set_bit_raw ( const uint64_t *value0, unsigned int size ) {
const uint64_t *value = ( value0 + size );
int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
uint64_t value_i;
do {
value_i = *(--value);
max_bit -= ( 64 - fls ( value_i ) );
if ( value_i )
break;
} while ( --size );
return max_bit;
}
/**
* Grow big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_grow_raw ( const uint64_t *source0, unsigned int source_size,
uint64_t *dest0, unsigned int dest_size ) {
unsigned int pad_size = ( dest_size - source_size );
memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) );
memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) );
}
/**
* Shrink big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_shrink_raw ( const uint64_t *source0, unsigned int source_size __unused,
uint64_t *dest0, unsigned int dest_size ) {
memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) );
}
/**
* Finalise big integer
*
* @v value0 Element 0 of big integer to finalise
* @v size Number of elements
* @v out Output buffer
* @v len Length of output buffer
*/
static inline __attribute__ (( always_inline )) void
bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
void *out, size_t len ) {
const uint8_t *value_byte = ( ( const void * ) value0 );
uint8_t *out_byte = ( out + len );
/* Copy raw data in reverse order */
while ( len-- )
*(--out_byte) = *(value_byte++);
}
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
const uint64_t *multiplier0,
uint64_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */

View File

@ -0,0 +1,102 @@
#ifndef _BITS_BITOPS_H
#define _BITS_BITOPS_H
/** @file
*
* loongArch bit operations
*
* We perform atomic bit set and bit clear operations using "ll"
* and "sc". We use the output constraint to inform the
* compiler that any memory from the start of the bit field up to and
* including the byte containing the bit may be modified. (This is
* overkill but shouldn't matter in practice since we're unlikely to
* subsequently read other bits from the same bit field.)
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/**
* Test and set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_set_bit ( unsigned int bit, volatile void *bits ) {
unsigned int index = ( bit / 64 );
unsigned int offset = ( bit % 64 );
volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
uint64_t mask = ( 1UL << offset );
uint64_t old;
uint64_t new;
__asm__ __volatile__ ( "1: \n\t"
"ll.d %[old], %[qword] \n\t"
"or %[new], %[old], %[mask] \n\t"
"sc.d %[new], %[qword] \n\t"
"beqz %[new], 1b \n\t"
: [old] "=&r" ( old ),
[new] "=&r" ( new ),
[qword] "+m" ( *qword )
: [mask] "r" ( mask )
: "cc", "memory");
return ( !! ( old & mask ) );
}
/**
* Test and clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
unsigned int index = ( bit / 64 );
unsigned int offset = ( bit % 64 );
volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
uint64_t mask = ( 1UL << offset );
uint64_t old;
uint64_t new;
__asm__ __volatile__ ( "1: \n\t"
"ll.d %[old], %[qword] \n\t"
"andn %[new], %[old], %[mask] \n\t"
"sc.d %[new], %[qword] \n\t"
"beqz %[new], 1b \n\t"
: [old] "=&r" ( old ),
[new] "=&r" ( new ),
[qword] "+m" ( *qword )
: [mask] "r" ( mask )
: "cc", "memory");
return ( !! ( old & mask ) );
}
/**
* Set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
set_bit ( unsigned int bit, volatile void *bits ) {
test_and_set_bit ( bit, bits );
}
/**
* Clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
clear_bit ( unsigned int bit, volatile void *bits ) {
test_and_clear_bit ( bit, bits );
}
#endif /* _BITS_BITOPS_H */

View File

@ -0,0 +1,47 @@
#ifndef _BITS_BYTESWAP_H
#define _BITS_BYTESWAP_H
/** @file
*
* Byte-order swapping functions
*
*/
#include <stdint.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static inline __attribute__ (( always_inline, const )) uint16_t
__bswap_variable_16 ( uint16_t x ) {
__asm__ ( "revb.2h %0, %1" : "=r" ( x ) : "r" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_16s ( uint16_t *x ) {
*x = __bswap_variable_16 ( *x );
}
static inline __attribute__ (( always_inline, const )) uint32_t
__bswap_variable_32 ( uint32_t x ) {
__asm__ ( "revb.2w %0, %1" : "=r" ( x ) : "r" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_32s ( uint32_t *x ) {
*x = __bswap_variable_32 ( *x );
}
static inline __attribute__ (( always_inline, const )) uint64_t
__bswap_variable_64 ( uint64_t x ) {
__asm__ ( "revb.d %0, %1" : "=r" ( x ) : "r" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_64s ( uint64_t *x ) {
*x = __bswap_variable_64 ( *x );
}
#endif

View File

@ -0,0 +1,19 @@
#ifndef _BITS_COMPILER_H
#define _BITS_COMPILER_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Dummy relocation type */
#define RELOC_TYPE_NONE R_LARCH_NONE
#ifndef ASSEMBLY
/** Unprefixed constant operand modifier */
#define ASM_NO_PREFIX "a"
#define __asmcall
#define __libgcc
#endif /* ASSEMBLY */
#endif /*_BITS_COMPILER_H */

View File

@ -0,0 +1,8 @@
#ifndef _BITS_ENDIAN_H
#define _BITS_ENDIAN_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif /* _BITS_ENDIAN_H */

View File

@ -0,0 +1,19 @@
#ifndef _BITS_ERRFILE_H
#define _BITS_ERRFILE_H
/** @file
*
* LoongArch64-specific error file identifiers
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @addtogroup errfile Error file identifiers
* @{
*/
/** @} */
#endif /* _BITS_ERRFILE_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_HYPERV_H
#define _BITS_HYPERV_H
/** @file
*
* Hyper-V interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_HYPERV_H */

View File

@ -0,0 +1,15 @@
#ifndef _BITS_IO_H
#define _BITS_IO_H
/** @file
*
* LoongArch64-specific I/O API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Page shift */
#define PAGE_SHIFT 12
#endif /* _BITS_IO_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_IOMAP_H
#define _BITS_IOMAP_H
/** @file
*
* LoongArch64-specific I/O mapping API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_IOMAP_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_NAP_H
#define _BITS_NAP_H
/** @file
*
* LoongArch64-specific CPU sleeping API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_MAP_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_PCI_IO_H
#define _BITS_PCI_IO_H
/** @file
*
* LoongArch64-specific PCI I/O API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_PCI_IO_H */

View File

@ -0,0 +1,28 @@
#ifndef _BITS_PROFILE_H
#define _BITS_PROFILE_H
/** @file
*
* Profiling
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/**
* Get profiling timestamp
*
* @ret timestamp Timestamp
*/
static inline __attribute__ (( always_inline )) uint64_t
profile_timestamp ( void ) {
uint64_t cycles;
/* Read cycle counter */
__asm__ __volatile__ ( "rdtime.d %0, $zero\n\t" : "=r" ( cycles ) );
return cycles;
}
#endif /* _BITS_PROFILE_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_REBOOT_H
#define _BITS_REBOOT_H
/** @file
*
* LoongArch64-specific reboot API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_REBOOT_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_SANBOOT_H
#define _BITS_SANBOOT_H
/** @file
*
* LoongArch64-specific sanboot API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_SANBOOT_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_SMBIOS_H
#define _BITS_SMBIOS_H
/** @file
*
* LoongArch64-specific SMBIOS API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_SMBIOS_H */

View File

@ -0,0 +1,23 @@
#ifndef _BITS_STDINT_H
#define _BITS_STDINT_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
typedef __SIZE_TYPE__ size_t;
typedef signed long ssize_t;
typedef signed long off_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
typedef unsigned long physaddr_t;
typedef unsigned long intptr_t;
#endif /* _BITS_STDINT_H */

View File

@ -0,0 +1,61 @@
#ifndef _BITS_STRING_H
#define _BITS_STRING_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* String functions
*
*/
extern void loong64_bzero ( void *dest, size_t len );
extern void loong64_memset ( void *dest, size_t len, int character );
extern void loong64_memcpy ( void *dest, const void *src, size_t len );
extern void loong64_memmove_forwards ( void *dest, const void *src, size_t len );
extern void loong64_memmove_backwards ( void *dest, const void *src, size_t len );
extern void loong64_memmove ( void *dest, const void *src, size_t len );
/**
* Fill memory region
*
* @v dest Destination region
* @v character Fill character
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memset ( void *dest, int character, size_t len ) {
loong64_memset ( dest, len, character );
return dest;
}
/**
* Copy memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memcpy ( void *dest, const void *src, size_t len ) {
loong64_memcpy ( dest, src, len );
return dest;
}
/**
* Copy (possibly overlapping) memory region
*
* @v dest Destination region
* @v src Source region
* @v len Length
* @ret dest Destination region
*/
static inline __attribute__ (( always_inline )) void *
memmove ( void *dest, const void *src, size_t len ) {
loong64_memmove ( dest, src, len );
return dest;
}
#endif /* _BITS_STRING_H */

View File

@ -0,0 +1,69 @@
#ifndef _BITS_STRINGS_H
#define _BITS_STRINGS_H
/** @file
*
* String functions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Find first (i.e. least significant) set bit
*
* @v value Value
* @ret lsb Least significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
unsigned long long bits = value;
unsigned long long lsb;
unsigned int lz;
/* Extract least significant set bit */
lsb = ( bits & -bits );
/* Count number of leading zeroes before LSB */
__asm__ ( "clz.d %0, %1" : "=r" ( lz ) : "r" ( lsb ) );
return ( 64 - lz );
}
/**
* Find first (i.e. least significant) set bit
*
* @v value Value
* @ret lsb Least significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
return __ffsll ( value );
}
/**
* Find last (i.e. most significant) set bit
*
* @v value Value
* @ret msb Most significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __flsll ( long long value ){
unsigned int lz;
/* Count number of leading zeroes */
__asm__ ( "clz.d %0, %1" : "=r" ( lz ) : "r" ( value ) );
return ( 64 - lz );
}
/**
* Find last (i.e. most significant) set bit
*
* @v value Value
* @ret msb Most significant bit set in value (LSB=1), or zero
*/
static inline __attribute__ (( always_inline )) int __flsl ( long value ) {
return __flsll ( value );
}
#endif /* _BITS_STRINGS_H */

View File

@ -0,0 +1,19 @@
#ifndef _BITS_TCPIP_H
#define _BITS_TCPIP_H
/** @file
*
* Transport-network layer interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static inline __attribute__ (( always_inline )) uint16_t
tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) {
/* Not yet optimised */
return generic_tcpip_continue_chksum ( partial, data, len );
}
#endif /* _BITS_TCPIP_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_TIME_H
#define _BITS_TIME_H
/** @file
*
* LoongArch64-specific time API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_TIME_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_UACCESS_H
#define _BITS_UACCESS_H
/** @file
*
* LoongArch64-specific user access API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_UACCESS_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_UART_H
#define _BITS_UART_H
/** @file
*
* 16550-compatible UART
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_UART_H */

View File

@ -0,0 +1,12 @@
#ifndef _BITS_UMALLOC_H
#define _BITS_UMALLOC_H
/** @file
*
* LoongArch64-specific user memory allocation API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_UMALLOC_H */

View File

@ -0,0 +1,13 @@
#ifndef _BITS_XEN_H
#define _BITS_XEN_H
/** @file
*
* Xen interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/nonxen.h>
#endif /* _BITS_XEN_H */

View File

@ -0,0 +1,45 @@
#ifndef GDBMACH_H
#define GDBMACH_H
/** @file
*
* GDB architecture specifics
*
* This file declares functions for manipulating the machine state and
* debugging context.
*
*/
#include <stdint.h>
typedef unsigned long gdbreg_t;
/* Register snapshot */
enum {
/* Not yet implemented */
GDBMACH_NREGS,
};
#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
/* Not yet implemented */
( void ) regs;
( void ) pc;
}
static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
/* Not yet implemented */
( void ) regs;
( void ) step;
}
static inline void gdbmach_breakpoint ( void ) {
/* Not yet implemented */
}
extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
int enable );
extern void gdbmach_init ( void );
#endif /* GDBMACH_H */

View File

@ -0,0 +1,20 @@
#ifndef _IPXE_EFI_DHCPARCH_H
#define _IPXE_EFI_DHCPARCH_H
/** @file
*
* DHCP client architecture definitions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
/** DHCP client architecture */
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_LOONG64
/** DHCP client network device interface */
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif /* _IPXE_EFI_DHCPARCH_H */

View File

@ -0,0 +1,53 @@
#ifndef LIMITS_H
#define LIMITS_H 1
/* Number of bits in a `char' */
#define CHAR_BIT 8
/* Minimum and maximum values a `signed char' can hold */
#define SCHAR_MIN (-128)
#define SCHAR_MAX 127
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
#define UCHAR_MAX 255
/* Minimum and maximum values a `char' can hold */
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
/* Minimum and maximum values a `signed short int' can hold */
#define SHRT_MIN (-32768)
#define SHRT_MAX 32767
/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
#define USHRT_MAX 65535
/* Minimum and maximum values a `signed int' can hold */
#define INT_MIN (-INT_MAX - 1)
#define INT_MAX 2147483647
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
#define UINT_MAX 4294967295U
/* Minimum and maximum values a `signed int' can hold */
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
#define UINT_MAX 4294967295U
/* Minimum and maximum values a `signed long' can hold */
#define LONG_MAX 9223372036854775807L
#define LONG_MIN (-LONG_MAX - 1L)
/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
#define ULONG_MAX 18446744073709551615UL
/* Minimum and maximum values a `signed long long' can hold */
#define LLONG_MAX 9223372036854775807LL
#define LLONG_MIN (-LONG_MAX - 1LL)
/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
#define ULLONG_MAX 18446744073709551615ULL
#endif /* LIMITS_H */

View File

@ -0,0 +1,31 @@
#ifndef _SETJMP_H
#define _SETJMP_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/** jump buffer env*/
typedef struct {
uint64_t s0;
uint64_t s1;
uint64_t s2;
uint64_t s3;
uint64_t s4;
uint64_t s5;
uint64_t s6;
uint64_t s7;
uint64_t s8;
uint64_t fp;
uint64_t sp;
uint64_t ra;
} jmp_buf[1];
extern int __asmcall __attribute__ (( returns_twice ))
setjmp ( jmp_buf env );
extern void __asmcall __attribute__ (( noreturn ))
longjmp ( jmp_buf env, int val );
#endif /* _SETJMP_H */

103
src/arch/x86/core/rdrand.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2023 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Hardware random number generator
*
*/
#include <errno.h>
#include <ipxe/cpuid.h>
#include <ipxe/entropy.h>
#include <ipxe/drbg.h>
struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED );
/** Number of times to retry RDRAND instruction */
#define RDRAND_RETRY_COUNT 16
/** Colour for debug messages */
#define colour &rdrand_entropy
/**
* Enable entropy gathering
*
* @ret rc Return status code
*/
static int rdrand_entropy_enable ( void ) {
struct x86_features features;
/* Check that RDRAND is supported */
x86_features ( &features );
if ( ! ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_RDRAND ) ) {
DBGC ( colour, "RDRAND not supported\n" );
return -ENOTSUP;
}
/* Data returned by RDRAND is theoretically full entropy, up
* to a security strength of 128 bits, so assume that each
* sample contains exactly 8 bits of entropy.
*/
if ( DRBG_SECURITY_STRENGTH > 128 )
return -ENOTSUP;
entropy_init ( &rdrand_entropy, MIN_ENTROPY ( 8.0 ) );
return 0;
}
/**
* Get noise sample
*
* @ret noise Noise sample
* @ret rc Return status code
*/
static int rdrand_get_noise ( noise_sample_t *noise ) {
unsigned int result;
unsigned int discard_c;
unsigned int ok;
/* Issue RDRAND, retrying until CF is set */
__asm__ ( "\n1:\n\t"
"rdrand %0\n\t"
"sbb %1, %1\n\t"
"loopz 1b\n\t"
: "=r" ( result ), "=r" ( ok ), "=c" ( discard_c )
: "2" ( RDRAND_RETRY_COUNT ) );
if ( ! ok ) {
DBGC ( colour, "RDRAND failed to become ready\n" );
return -EBUSY;
}
*noise = result;
return 0;
}
/** Hardware random number generator entropy source */
struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED ) = {
.name = "rdrand",
.enable = rdrand_entropy_enable,
.get_noise = rdrand_get_noise,
};

View File

@ -247,19 +247,17 @@ static void bzimage_update_header ( struct image *image,
*
* @v image bzImage file
* @v bzimg bzImage context
* @v cmdline Kernel command line
* @ret rc Return status code
*/
static int bzimage_parse_cmdline ( struct image *image,
struct bzimage_context *bzimg,
char *cmdline ) {
struct bzimage_context *bzimg ) {
const char *vga;
const char *mem;
char *sep;
char *vga;
char *mem;
char *end;
/* Look for "vga=" */
if ( ( vga = strstr ( cmdline, "vga=" ) ) ) {
vga += 4;
if ( ( vga = image_argument ( image, "vga=" ) ) ) {
sep = strchr ( vga, ' ' );
if ( sep )
*sep = '\0';
@ -270,10 +268,10 @@ static int bzimage_parse_cmdline ( struct image *image,
} else if ( strcmp ( vga, "ask" ) == 0 ) {
bzimg->vid_mode = BZI_VID_MODE_ASK;
} else {
bzimg->vid_mode = strtoul ( vga, &vga, 0 );
if ( *vga ) {
bzimg->vid_mode = strtoul ( vga, &end, 0 );
if ( *end ) {
DBGC ( image, "bzImage %p strange \"vga=\" "
"terminator '%c'\n", image, *vga );
"terminator '%c'\n", image, *end );
}
}
if ( sep )
@ -281,10 +279,9 @@ static int bzimage_parse_cmdline ( struct image *image,
}
/* Look for "mem=" */
if ( ( mem = strstr ( cmdline, "mem=" ) ) ) {
mem += 4;
bzimg->mem_limit = strtoul ( mem, &mem, 0 );
switch ( *mem ) {
if ( ( mem = image_argument ( image, "mem=" ) ) ) {
bzimg->mem_limit = strtoul ( mem, &end, 0 );
switch ( *end ) {
case 'G':
case 'g':
bzimg->mem_limit <<= 10;
@ -302,7 +299,7 @@ static int bzimage_parse_cmdline ( struct image *image,
break;
default:
DBGC ( image, "bzImage %p strange \"mem=\" "
"terminator '%c'\n", image, *mem );
"terminator '%c'\n", image, *end );
break;
}
bzimg->mem_limit -= 1;
@ -316,11 +313,10 @@ static int bzimage_parse_cmdline ( struct image *image,
*
* @v image bzImage image
* @v bzimg bzImage context
* @v cmdline Kernel command line
*/
static void bzimage_set_cmdline ( struct image *image,
struct bzimage_context *bzimg,
const char *cmdline ) {
struct bzimage_context *bzimg ) {
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
size_t cmdline_len;
/* Copy command line down to real-mode portion */
@ -359,8 +355,8 @@ static size_t bzimage_load_initrd ( struct image *image,
size_t offset;
size_t pad_len;
/* Do not include kernel image itself as an initrd */
if ( initrd == image )
/* Skip hidden images */
if ( initrd->flags & IMAGE_HIDDEN )
return 0;
/* Create cpio header for non-prebuilt images */
@ -410,10 +406,6 @@ static int bzimage_check_initrds ( struct image *image,
/* Calculate total loaded length of initrds */
for_each_image ( initrd ) {
/* Skip kernel */
if ( initrd == image )
continue;
/* Calculate length */
len += bzimage_load_initrd ( image, initrd, UNULL );
len = bzimage_align ( len );
@ -528,7 +520,6 @@ static void bzimage_load_initrds ( struct image *image,
*/
static int bzimage_exec ( struct image *image ) {
struct bzimage_context bzimg;
char *cmdline = ( image->cmdline ? image->cmdline : "" );
int rc;
/* Read and parse header from image */
@ -551,7 +542,7 @@ static int bzimage_exec ( struct image *image ) {
}
/* Parse command line for bootloader parameters */
if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
if ( ( rc = bzimage_parse_cmdline ( image, &bzimg ) ) != 0)
return rc;
/* Check that initrds can be loaded */
@ -568,7 +559,7 @@ static int bzimage_exec ( struct image *image ) {
bzimg.rm_filesz, bzimg.pm_sz );
/* Store command line */
bzimage_set_cmdline ( image, &bzimg, cmdline );
bzimage_set_cmdline ( image, &bzimg );
/* Prepare for exiting. Must do this before loading initrds,
* since loading the initrds will corrupt the external heap.

View File

@ -204,8 +204,8 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start,
break;
}
/* Do not include kernel image itself as a module */
if ( module_image == image )
/* Skip hidden images */
if ( module_image->flags & IMAGE_HIDDEN )
continue;
/* Page-align the module */

View File

@ -1,14 +0,0 @@
#ifndef _BITS_ENTROPY_H
#define _BITS_ENTROPY_H
/** @file
*
* x86-specific entropy API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/rtc_entropy.h>
#endif /* _BITS_ENTROPY_H */

View File

@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_cpuid ( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
#define ERRFILE_rdtsc_timer ( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
#define ERRFILE_acpi_timer ( ERRFILE_ARCH | ERRFILE_CORE | 0x00130000 )
#define ERRFILE_rdrand ( ERRFILE_ARCH | ERRFILE_CORE | 0x00140000 )
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

View File

@ -9,6 +9,9 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Page shift */
#define PAGE_SHIFT 12
#include <ipxe/x86_io.h>
#endif /* _BITS_IO_H */

View File

@ -39,6 +39,9 @@ struct x86_features {
/** Get standard features */
#define CPUID_FEATURES 0x00000001UL
/** RDRAND instruction is supported */
#define CPUID_FEATURES_INTEL_ECX_RDRAND 0x40000000UL
/** Hypervisor is present */
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL

View File

@ -1,62 +0,0 @@
#ifndef _IPXE_RTC_ENTROPY_H
#define _IPXE_RTC_ENTROPY_H
/** @file
*
* RTC-based entropy source
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#ifdef ENTROPY_RTC
#define ENTROPY_PREFIX_rtc
#else
#define ENTROPY_PREFIX_rtc __rtc_
#endif
/**
* min-entropy per sample
*
* @ret min_entropy min-entropy of each sample
*/
static inline __always_inline min_entropy_t
ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
/* The min-entropy has been measured on several platforms
* using the entropy_sample test code. Modelling the samples
* as independent, and using a confidence level of 99.99%, the
* measurements were as follows:
*
* qemu-kvm : 7.38 bits
* VMware : 7.46 bits
* Physical hardware : 2.67 bits
*
* We choose the lowest of these (2.67 bits) and apply a 50%
* safety margin to allow for some potential non-independence
* of samples.
*/
return MIN_ENTROPY ( 1.3 );
}
extern uint8_t rtc_sample ( void );
/**
* Get noise sample
*
* @ret noise Noise sample
* @ret rc Return status code
*/
static inline __always_inline int
ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
/* Get sample */
*noise = rtc_sample();
/* Always successful */
return 0;
}
#endif /* _IPXE_RTC_ENTROPY_H */

View File

@ -28,9 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** Page shift */
#define PAGE_SHIFT 12
/*
* Physical<->Bus address mappings
*

View File

@ -39,9 +39,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/cpuid.h>
#include <ipxe/entropy.h>
struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL );
/** Maximum time to wait for an RTC interrupt, in milliseconds */
#define RTC_MAX_WAIT_MS 100
/** Number of RTC interrupts to check for */
#define RTC_CHECK_COUNT 3
/** RTC interrupt handler */
extern void rtc_isr ( void );
@ -145,6 +150,7 @@ static void rtc_disable_int ( void ) {
* @ret rc Return status code
*/
static int rtc_entropy_check ( void ) {
unsigned int count = 0;
unsigned int i;
/* Check that RTC interrupts are working */
@ -158,14 +164,18 @@ static int rtc_entropy_check ( void ) {
"cli\n\t" );
/* Check for RTC interrupt flag */
if ( rtc_flag )
return 0;
if ( rtc_flag ) {
rtc_flag = 0;
if ( ++count >= RTC_CHECK_COUNT )
return 0;
}
/* Delay */
mdelay ( 1 );
}
DBGC ( &rtc_flag, "RTC timed out waiting for interrupt\n" );
DBGC ( &rtc_flag, "RTC timed out waiting for interrupt %d/%d\n",
( count + 1 ), RTC_CHECK_COUNT );
return -ETIMEDOUT;
}
@ -195,6 +205,21 @@ static int rtc_entropy_enable ( void ) {
if ( ( rc = rtc_entropy_check() ) != 0 )
goto err_check;
/* The min-entropy has been measured on several platforms
* using the entropy_sample test code. Modelling the samples
* as independent, and using a confidence level of 99.99%, the
* measurements were as follows:
*
* qemu-kvm : 7.38 bits
* VMware : 7.46 bits
* Physical hardware : 2.67 bits
*
* We choose the lowest of these (2.67 bits) and apply a 50%
* safety margin to allow for some potential non-independence
* of samples.
*/
entropy_init ( &rtc_entropy, MIN_ENTROPY ( 1.3 ) );
return 0;
err_check:
@ -218,11 +243,12 @@ static void rtc_entropy_disable ( void ) {
}
/**
* Measure a single RTC tick
* Get noise sample
*
* @ret delta Length of RTC tick (in TSC units)
* @ret noise Noise sample
* @ret rc Return status code
*/
uint8_t rtc_sample ( void ) {
static int rtc_get_noise ( noise_sample_t *noise ) {
uint32_t before;
uint32_t after;
uint32_t temp;
@ -257,10 +283,14 @@ uint8_t rtc_sample ( void ) {
: "=a" ( after ), "=d" ( before ), "=Q" ( temp )
: "2" ( 0 ) );
return ( after - before );
*noise = ( after - before );
return 0;
}
PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
PROVIDE_ENTROPY_INLINE ( rtc, get_noise );
/** RTC entropy source */
struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL ) = {
.name = "rtc",
.enable = rtc_entropy_enable,
.disable = rtc_entropy_disable,
.get_noise = rtc_get_noise,
};

View File

@ -8,6 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef ASSEMBLY
/** Unprefixed constant operand modifier */
#define ASM_NO_PREFIX "c"
/** Declare a function with standard calling conventions */
#define __asmcall __attribute__ (( regparm(0) ))

View File

@ -290,6 +290,9 @@ REQUIRE_OBJECT ( cert_cmd );
#ifdef IMAGE_MEM_CMD
REQUIRE_OBJECT ( image_mem_cmd );
#endif
#ifdef SHIM_CMD
REQUIRE_OBJECT ( shim_cmd );
#endif
/*
* Drag in miscellaneous objects
@ -352,6 +355,9 @@ REQUIRE_OBJECT ( vram_settings );
#ifdef ACPI_SETTINGS
REQUIRE_OBJECT ( acpi_settings );
#endif
#ifdef EFI_SETTINGS
REQUIRE_OBJECT ( efi_settings );
#endif
/*
* Drag in selected keyboard map

View File

@ -0,0 +1,51 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/entropy.h>
/** @file
*
* Entropy configuration options
*
*/
PROVIDE_REQUIRING_SYMBOL();
/*
* Drag in entropy sources
*/
#ifdef ENTROPY_RTC
REQUIRE_OBJECT ( rtc_entropy );
#endif
#ifdef ENTROPY_EFITICK
REQUIRE_OBJECT ( efi_entropy );
#endif
#ifdef ENTROPY_EFIRNG
REQUIRE_OBJECT ( efi_rng );
#endif
#ifdef ENTROPY_LINUX
REQUIRE_OBJECT ( linux_entropy );
#endif
#ifdef ENTROPY_RDRAND
REQUIRE_OBJECT ( rdrand );
#endif

View File

@ -49,3 +49,6 @@ REQUIRE_OBJECT ( eth_slow );
#ifdef NET_PROTO_EAPOL
REQUIRE_OBJECT ( eapol );
#endif
#ifdef NET_PROTO_LLDP
REQUIRE_OBJECT ( lldp );
#endif

View File

@ -19,13 +19,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define SMBIOS_EFI
#define SANBOOT_EFI
#define BOFM_EFI
#define ENTROPY_EFI
#define ENTROPY_EFITICK
#define ENTROPY_EFIRNG
#define TIME_EFI
#define REBOOT_EFI
#define ACPI_EFI
#define FDT_EFI
#define NET_PROTO_IPV6 /* IPv6 protocol */
#define NET_PROTO_LLDP /* Link Layer Discovery protocol */
#define DOWNLOAD_PROTO_FILE /* Local filesystem access */
@ -46,9 +48,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define REBOOT_CMD /* Reboot command */
#define EFI_SETTINGS /* EFI variable settings */
#if defined ( __i386__ ) || defined ( __x86_64__ )
#define IOAPI_X86
#define NAP_EFIX86
#define ENTROPY_RDRAND
#define CPUID_CMD /* x86 CPU feature detection command */
#define UNSAFE_STD /* Avoid setting direction flag */
#endif

View File

@ -33,4 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define SANBOOT_PROTO_FCP
#define SANBOOT_PROTO_HTTP
#if defined ( __i386__ ) || defined ( __x86_64__ )
#define ENTROPY_RDRAND
#endif
#endif /* CONFIG_DEFAULTS_LINUX_H */

View File

@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define SMBIOS_PCBIOS
#define SANBOOT_PCBIOS
#define ENTROPY_RTC
#define ENTROPY_RDRAND
#define TIME_RTC
#define REBOOT_PCBIOS
#define ACPI_RSDP

View File

@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define NET_PROTO_STP /* Spanning Tree protocol */
#define NET_PROTO_LACP /* Link Aggregation control protocol */
#define NET_PROTO_EAPOL /* EAP over LAN protocol */
//#define NET_PROTO_LLDP /* Link Layer Discovery protocol */
/*
* PXE support
@ -149,7 +150,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define POWEROFF_CMD /* Power off command */
//#define IMAGE_TRUST_CMD /* Image trust management commands */
//#define PCI_CMD /* PCI commands */
//#define PARAM_CMD /* Form parameter commands */
//#define PARAM_CMD /* Request parameter commands */
//#define NEIGHBOUR_CMD /* Neighbour management commands */
//#define PING_CMD /* Ping command */
//#define CONSOLE_CMD /* Console command */
@ -159,6 +160,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define CERT_CMD /* Certificate management commands */
//#define IMAGE_MEM_CMD /* Read memory command */
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
#define SHIM_CMD /* EFI shim command (or dummy command) */
/*
* ROM-specific options

View File

@ -9,6 +9,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
#define PCI_SETTINGS /* PCI device settings */
//#define CPUID_SETTINGS /* CPUID settings */
//#define MEMMAP_SETTINGS /* Memory map settings */

View File

@ -77,17 +77,12 @@ size_t cpio_name_len ( struct image *image ) {
*/
static void cpio_parse_cmdline ( struct image *image,
struct cpio_header *cpio ) {
const char *cmdline;
char *arg;
const char *arg;
char *end;
unsigned int mode;
/* Skip image filename */
cmdline = ( cpio_name ( image ) + cpio_name_len ( image ) );
/* Look for "mode=" */
if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
arg += 5;
if ( ( arg = image_argument ( image, "mode=" ) ) ) {
mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
if ( *end && ( *end != ' ' ) ) {
DBGC ( image, "CPIO %p strange \"mode=\" "

View File

@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <libgen.h>
@ -55,8 +56,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** List of registered images */
struct list_head images = LIST_HEAD_INIT ( images );
/** Image selected for execution */
struct image_tag selected_image __image_tag = {
.name = "SELECTED",
};
/** Currently-executing image */
struct image *current_image;
struct image_tag current_image __image_tag = {
.name = "CURRENT",
};
/** Current image trust requirement */
static int require_trusted_images = 0;
@ -71,8 +79,13 @@ static int require_trusted_images_permanent = 0;
*/
static void free_image ( struct refcnt *refcnt ) {
struct image *image = container_of ( refcnt, struct image, refcnt );
struct image_tag *tag;
DBGC ( image, "IMAGE %s freed\n", image->name );
for_each_table_entry ( tag, IMAGE_TAGS ) {
if ( tag->image == image )
tag->image = NULL;
}
free ( image->name );
free ( image->cmdline );
uri_put ( image->uri );
@ -260,12 +273,6 @@ int register_image ( struct image *image ) {
return rc;
}
/* Avoid ending up with multiple "selected" images on
* re-registration
*/
if ( image_find_selected() )
image->flags &= ~IMAGE_SELECTED;
/* Add to image list */
image_get ( image );
image->flags |= IMAGE_REGISTERED;
@ -311,7 +318,7 @@ void unregister_image ( struct image *image ) {
struct image * find_image ( const char *name ) {
struct image *image;
list_for_each_entry ( image, &images, list ) {
for_each_image ( image ) {
if ( strcmp ( image->name, name ) == 0 )
return image;
}
@ -319,6 +326,23 @@ struct image * find_image ( const char *name ) {
return NULL;
}
/**
* Find image by tag
*
* @v tag Image tag
* @ret image Executable image, or NULL
*/
struct image * find_image_tag ( struct image_tag *tag ) {
struct image *image;
for_each_image ( image ) {
if ( tag->image == image )
return image;
}
return NULL;
}
/**
* Execute image
*
@ -345,14 +369,13 @@ int image_exec ( struct image *image ) {
if ( image->uri )
churi ( image->uri );
/* Preserve record of any currently-running image */
saved_current_image = current_image;
/* Set as currently running image */
saved_current_image = image_tag ( image, &current_image );
/* Take out a temporary reference to the image. This allows
* the image to unregister itself if necessary, without
* automatically freeing itself.
/* Take out a temporary reference to the image, so that it
* does not get freed when temporarily unregistered.
*/
current_image = image_get ( image );
image_get ( image );
/* Check that this image can be executed */
if ( ! ( image->type && image->type->exec ) ) {
@ -370,6 +393,9 @@ int image_exec ( struct image *image ) {
/* Record boot attempt */
syslog ( LOG_NOTICE, "Executing \"%s\"\n", image->name );
/* Temporarily unregister the image during its execution */
unregister_image ( image );
/* Try executing the image */
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
DBGC ( image, "IMAGE %s could not execute: %s\n",
@ -386,6 +412,10 @@ int image_exec ( struct image *image ) {
image->name, strerror ( rc ) );
}
/* Re-register image (unless due to be replaced) */
if ( ! image->replacement )
register_image ( image );
/* Pick up replacement image before we drop the original
* image's temporary reference. The replacement image must
* already be registered, so we don't need to hold a temporary
@ -412,7 +442,7 @@ int image_exec ( struct image *image ) {
image_put ( image );
/* Restore previous currently-running image */
current_image = saved_current_image;
image_tag ( saved_current_image, &current_image );
/* Reset current working directory */
churi ( old_cwuri );
@ -435,7 +465,7 @@ int image_exec ( struct image *image ) {
* registered until the currently-executing image returns.
*/
int image_replace ( struct image *replacement ) {
struct image *image = current_image;
struct image *image = current_image.image;
int rc;
/* Sanity check */
@ -471,37 +501,17 @@ int image_replace ( struct image *replacement ) {
* @ret rc Return status code
*/
int image_select ( struct image *image ) {
struct image *tmp;
/* Unselect all other images */
for_each_image ( tmp )
tmp->flags &= ~IMAGE_SELECTED;
/* Check that this image can be executed */
if ( ! ( image->type && image->type->exec ) )
return -ENOEXEC;
/* Mark image as selected */
image->flags |= IMAGE_SELECTED;
image_tag ( image, &selected_image );
return 0;
}
/**
* Find selected image
*
* @ret image Executable image, or NULL
*/
struct image * image_find_selected ( void ) {
struct image *image;
for_each_image ( image ) {
if ( image->flags & IMAGE_SELECTED )
return image;
}
return NULL;
}
/**
* Change image trust requirement
*
@ -569,3 +579,33 @@ struct image * image_memory ( const char *name, userptr_t data, size_t len ) {
err_alloc_image:
return NULL;
}
/**
* Find argument within image command line
*
* @v image Image
* @v key Argument search key (including trailing delimiter)
* @ret value Argument value, or NULL if not found
*/
const char * image_argument ( struct image *image, const char *key ) {
const char *cmdline = image->cmdline;
const char *search;
const char *match;
const char *next;
/* Find argument */
for ( search = cmdline ; search ; search = next ) {
/* Find next occurrence, if any */
match = strstr ( search, key );
if ( ! match )
break;
next = ( match + strlen ( key ) );
/* Check preceding delimiter, if any */
if ( ( match == cmdline ) || isspace ( match[-1] ) )
return next;
}
return NULL;
}

View File

@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Form parameters
* Request parameters
*
*/
@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static LIST_HEAD ( parameters );
/**
* Free form parameter list
* Free request parameter list
*
* @v refcnt Reference count
*/
@ -60,7 +60,7 @@ static void free_parameters ( struct refcnt *refcnt ) {
}
/**
* Find form parameter list by name
* Find request parameter list by name
*
* @v name Parameter list name (may be NULL)
* @ret params Parameter list, or NULL if not found
@ -78,7 +78,7 @@ struct parameters * find_parameters ( const char *name ) {
}
/**
* Create form parameter list
* Create request parameter list
*
* @v name Parameter list name (may be NULL)
* @ret params Parameter list, or NULL on failure
@ -118,15 +118,17 @@ struct parameters * create_parameters ( const char *name ) {
}
/**
* Add form parameter
* Add request parameter
*
* @v params Parameter list
* @v key Parameter key
* @v value Parameter value
* @v flags Parameter flags
* @ret param Parameter, or NULL on failure
*/
struct parameter * add_parameter ( struct parameters *params,
const char *key, const char *value ) {
const char *key, const char *value,
unsigned int flags ) {
struct parameter *param;
size_t key_len;
size_t value_len;
@ -147,11 +149,14 @@ struct parameter * add_parameter ( struct parameters *params,
param->key = key_copy;
strcpy ( value_copy, value );
param->value = value_copy;
param->flags = flags;
/* Add to list of parameters */
list_add_tail ( &param->list, &params->entries );
DBGC ( params, "PARAMS \"%s\" added \"%s\"=\"%s\"\n",
params->name, param->key, param->value );
DBGC ( params, "PARAMS \"%s\" added \"%s\"=\"%s\"%s%s\n",
params->name, param->key, param->value,
( ( param->flags & PARAMETER_FORM ) ? " (form)" : "" ),
( ( param->flags & PARAMETER_HEADER ) ? " (header)" : "" ) );
return param;
}

View File

@ -302,7 +302,7 @@ int parse_autovivified_setting ( char *text, struct named_setting *setting ) {
}
/**
* Parse form parameter list name
* Parse request parameter list name
*
* @v text Text
* @ret params Parameter list

View File

@ -589,6 +589,32 @@ int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
return 0;
}
/**
* Check ASN.1 OID-identified algorithm
*
* @v cursor ASN.1 object cursor
* @v expected Expected algorithm
* @ret rc Return status code
*/
int asn1_check_algorithm ( const struct asn1_cursor *cursor,
struct asn1_algorithm *expected ) {
struct asn1_algorithm *actual;
int rc;
/* Parse algorithm */
if ( ( rc = asn1_algorithm ( cursor, &actual ) ) != 0 )
return rc;
/* Check algorithm matches */
if ( actual != expected ) {
DBGC ( cursor, "ASN1 %p algorithm %s does not match %s\n",
cursor, actual->name, expected->name );
return -ENOTTY_ALGORITHM;
}
return 0;
}
/**
* Parse ASN.1 GeneralizedTime
*

View File

@ -51,59 +51,33 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
__einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
/**
* Calculate cutoff value for the repetition count test
* Initialise repetition count test
*
* @ret cutoff Cutoff value
*
* This is the cutoff value for the Repetition Count Test defined in
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
* @v source Entropy source
*/
static inline __attribute__ (( always_inline )) unsigned int
repetition_count_cutoff ( void ) {
double max_repetitions;
unsigned int cutoff;
static void repetition_count_test_init ( struct entropy_source *source ) {
struct entropy_repetition_count_test *test =
&source->repetition_count_test;
/* The cutoff formula for the repetition test is:
*
* C = ( 1 + ( -log2(W) / H_min ) )
*
* where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
* 2011 Draft) Section 8.5.2.1.3.1).
*/
max_repetitions = ( 1 + ( MIN_ENTROPY ( 30 ) /
min_entropy_per_sample() ) );
/* Round up to a whole number of repetitions. We don't have
* the ceil() function available, so do the rounding by hand.
*/
cutoff = max_repetitions;
if ( cutoff < max_repetitions )
cutoff++;
linker_assert ( ( cutoff >= max_repetitions ), rounding_error );
/* Floating-point operations are not allowed in iPXE since we
* never set up a suitable environment. Abort the build
* unless the calculated number of repetitions is a
* compile-time constant.
*/
linker_assert ( __builtin_constant_p ( cutoff ),
repetition_count_cutoff_not_constant );
return cutoff;
/* Sanity checks */
assert ( test->repetition_count == 0 );
assert ( test->cutoff > 0 );
}
/**
* Perform repetition count test
*
* @v source Entropy source
* @v sample Noise sample
* @ret rc Return status code
*
* This is the Repetition Count Test defined in ANS X9.82 Part 2
* (October 2011 Draft) Section 8.5.2.1.2.
*/
static int repetition_count_test ( noise_sample_t sample ) {
static noise_sample_t most_recent_sample;
static unsigned int repetition_count = 0;
static int repetition_count_test ( struct entropy_source *source,
noise_sample_t sample ) {
struct entropy_repetition_count_test *test =
&source->repetition_count_test;
/* A = the most recently seen sample value
* B = the number of times that value A has been seen in a row
@ -116,158 +90,71 @@ static int repetition_count_test ( noise_sample_t sample ) {
* the initial value of most_recent_sample is treated as being
* undefined.)
*/
if ( ( sample == most_recent_sample ) && ( repetition_count > 0 ) ) {
if ( ( sample == test->most_recent_sample ) &&
( test->repetition_count > 0 ) ) {
/* a) If the new sample = A, then B is incremented by one. */
repetition_count++;
test->repetition_count++;
/* i. If B >= C, then an error condition is raised
* due to a failure of the test
*/
if ( repetition_count >= repetition_count_cutoff() )
if ( test->repetition_count >= test->cutoff ) {
DBGC ( source, "ENTROPY %s excessively repeated "
"value %d (%d/%d)\n", source->name, sample,
test->repetition_count, test->cutoff );
return -EPIPE_REPETITION_COUNT_TEST;
}
} else {
/* b) Else:
* i. A = new sample
*/
most_recent_sample = sample;
test->most_recent_sample = sample;
/* ii. B = 1 */
repetition_count = 1;
test->repetition_count = 1;
}
return 0;
}
/**
* Window size for the adaptive proportion test
* Initialise adaptive proportion test
*
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows
* five possible window sizes: 16, 64, 256, 4096 and 65536.
*
* We expect to generate relatively few (<256) entropy samples during
* a typical iPXE run; the use of a large window size would mean that
* the test would never complete a single cycle. We use a window size
* of 64, which is the smallest window size that permits values of
* H_min down to one bit per sample.
* @v source Entropy source
*/
#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64
static void adaptive_proportion_test_init ( struct entropy_source *source ) {
struct entropy_adaptive_proportion_test *test =
&source->adaptive_proportion_test;
/**
* Combine adaptive proportion test window size and min-entropy
*
* @v n N (window size)
* @v h H (min-entropy)
* @ret n_h (N,H) combined value
*/
#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) )
/* Sanity checks */
assert ( test->sample_count == 0 );
assert ( test->repetition_count == 0 );
assert ( test->cutoff > 0 );
/**
* Define a row of the adaptive proportion cutoff table
*
* @v h H (min-entropy)
* @v c16 Cutoff for N=16
* @v c64 Cutoff for N=64
* @v c256 Cutoff for N=256
* @v c4096 Cutoff for N=4096
* @v c65536 Cutoff for N=65536
*/
#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \
case APC_N_H ( 16, h ) : return c16; \
case APC_N_H ( 64, h ) : return c64; \
case APC_N_H ( 256, h ) : return c256; \
case APC_N_H ( 4096, h ) : return c4096; \
case APC_N_H ( 65536, h ) : return c65536;
/** Value used to represent "N/A" in adaptive proportion cutoff table */
#define APC_NA 0
/**
* Look up value in adaptive proportion test cutoff table
*
* @v n N (window size)
* @v h H (min-entropy)
* @ret cutoff Cutoff
*
* This is the table of cutoff values defined in ANS X9.82 Part 2
* (October 2011 Draft) Section 8.5.2.1.3.1.2.
*/
static inline __attribute__ (( always_inline )) unsigned int
adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) {
switch ( APC_N_H ( n, h ) ) {
APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 );
APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 );
APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 );
APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 );
APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 );
APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 );
APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 );
APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 );
APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 );
APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 );
APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 );
APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 );
APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 );
APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 );
APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 );
APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 );
APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 );
APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 );
APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 );
APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 );
default:
return APC_NA;
}
}
/**
* Calculate cutoff value for the adaptive proportion test
*
* @ret cutoff Cutoff value
*
* This is the cutoff value for the Adaptive Proportion Test defined
* in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2.
*/
static inline __attribute__ (( always_inline )) unsigned int
adaptive_proportion_cutoff ( void ) {
unsigned int h;
unsigned int n;
unsigned int cutoff;
/* Look up cutoff value in cutoff table */
n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
h = ( min_entropy_per_sample() / MIN_ENTROPY_SCALE );
cutoff = adaptive_proportion_cutoff_lookup ( n, h );
/* Fail unless cutoff value is a build-time constant */
linker_assert ( __builtin_constant_p ( cutoff ),
adaptive_proportion_cutoff_not_constant );
/* Fail if cutoff value is N/A */
linker_assert ( ( cutoff != APC_NA ),
adaptive_proportion_cutoff_not_applicable );
return cutoff;
/* Ensure that a new test run starts immediately */
test->sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
}
/**
* Perform adaptive proportion test
*
* @v source Entropy source
* @v sample Noise sample
* @ret rc Return status code
*
* This is the Adaptive Proportion Test for the Most Common Value
* defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.
*/
static int adaptive_proportion_test ( noise_sample_t sample ) {
static noise_sample_t current_counted_sample;
static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
static unsigned int repetition_count;
static int adaptive_proportion_test ( struct entropy_source *source,
noise_sample_t sample ) {
struct entropy_adaptive_proportion_test *test =
&source->adaptive_proportion_test;
/* A = the sample value currently being counted
* B = the number of samples examined in this run of the test so far
* S = the number of samples examined in this run of the test so far
* N = the total number of samples that must be observed in
* one run of the test, also known as the "window size" of
* the test
@ -284,37 +171,41 @@ static int adaptive_proportion_test ( noise_sample_t sample ) {
*/
/* 2. If S = N, then a new run of the test begins: */
if ( sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
if ( test->sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
/* a. A = the current sample */
current_counted_sample = sample;
test->current_counted_sample = sample;
/* b. S = 0 */
sample_count = 0;
test->sample_count = 0;
/* c. B = 0 */
repetition_count = 0;
test->repetition_count = 0;
} else {
/* Else: (the test is already running)
* a. S = S + 1
*/
sample_count++;
test->sample_count++;
/* b. If A = the current sample, then: */
if ( sample == current_counted_sample ) {
if ( sample == test->current_counted_sample ) {
/* i. B = B + 1 */
repetition_count++;
test->repetition_count++;
/* ii. If S (sic) > C then raise an error
* condition, because the test has
* detected a failure
*/
if ( repetition_count > adaptive_proportion_cutoff() )
if ( test->repetition_count > test->cutoff ) {
DBGC ( source, "ENTROPY %s excessively "
"repeated value %d (%d/%d)\n",
source->name, sample,
test->repetition_count, test->cutoff );
return -EPIPE_ADAPTIVE_PROPORTION_TEST;
}
}
}
@ -324,62 +215,180 @@ static int adaptive_proportion_test ( noise_sample_t sample ) {
/**
* Get entropy sample
*
* @v source Entropy source
* @ret entropy Entropy sample
* @ret rc Return status code
*
* This is the GetEntropy function defined in ANS X9.82 Part 2
* (October 2011 Draft) Section 6.5.1.
*/
static int get_entropy ( entropy_sample_t *entropy ) {
static int rc = 0;
static int get_entropy ( struct entropy_source *source,
entropy_sample_t *entropy ) {
noise_sample_t noise;
int rc;
/* Any failure is permanent */
if ( rc != 0 )
return rc;
if ( ( rc = source->rc ) != 0 )
goto err_broken;
/* Get noise sample */
if ( ( rc = get_noise ( &noise ) ) != 0 )
return rc;
if ( ( rc = get_noise ( source, &noise ) ) != 0 )
goto err_get_noise;
/* Perform Repetition Count Test and Adaptive Proportion Test
* as mandated by ANS X9.82 Part 2 (October 2011 Draft)
* Section 8.5.2.1.1.
*/
if ( ( rc = repetition_count_test ( noise ) ) != 0 )
return rc;
if ( ( rc = adaptive_proportion_test ( noise ) ) != 0 )
return rc;
if ( ( rc = repetition_count_test ( source, noise ) ) != 0 )
goto err_repetition_count_test;
if ( ( rc = adaptive_proportion_test ( source, noise ) ) != 0 )
goto err_adaptive_proportion_test;
/* We do not use any optional conditioning component */
*entropy = noise;
return 0;
err_adaptive_proportion_test:
err_repetition_count_test:
err_get_noise:
source->rc = rc;
err_broken:
return rc;
}
/**
* Calculate number of samples required for startup tests
* Initialise startup test
*
* @ret num_samples Number of samples required
*
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
* that at least one full cycle of the continuous tests must be
* performed at start-up.
* @v source Entropy source
*/
static inline __attribute__ (( always_inline )) unsigned int
startup_test_count ( void ) {
unsigned int num_samples;
static void startup_test_init ( struct entropy_source *source ) {
struct entropy_startup_test *test = &source->startup_test;
/* At least max(N,C) samples shall be generated by the noise
* source for start-up testing.
*/
num_samples = repetition_count_cutoff();
if ( num_samples < adaptive_proportion_cutoff() )
num_samples = adaptive_proportion_cutoff();
linker_assert ( __builtin_constant_p ( num_samples ),
startup_test_count_not_constant );
/* Sanity check */
assert ( test->tested == 0 );
assert ( test->count > 0 );
}
return num_samples;
/**
* Perform startup test
*
* @v source Entropy source
* @ret rc Return status code
*/
static int startup_test ( struct entropy_source *source ) {
struct entropy_startup_test *test = &source->startup_test;
entropy_sample_t sample;
int rc;
/* Perform mandatory number of startup tests */
for ( ; test->tested < test->count ; test->tested++ ) {
if ( ( rc = get_entropy ( source, &sample ) ) != 0 ) {
DBGC ( source, "ENTROPY %s failed: %s\n",
source->name, strerror ( rc ) );
return rc;
}
}
return 0;
}
/**
* Enable entropy gathering
*
* @v source Entropy source
* @ret rc Return status code
*/
int entropy_enable ( struct entropy_source *source ) {
int rc;
/* Refuse to enable a previously failed source */
if ( ( rc = source->rc ) != 0 )
return rc;
/* Enable entropy source */
if ( ( rc = source->enable() ) != 0 ) {
DBGC ( source, "ENTROPY %s could not enable: %s\n",
source->name, strerror ( rc ) );
source->rc = rc;
return rc;
}
/* Sanity check */
assert ( source->min_entropy_per_sample > 0 );
/* Initialise test state if this source has not previously been used */
if ( source->startup_test.tested == 0 ) {
repetition_count_test_init ( source );
adaptive_proportion_test_init ( source );
startup_test_init ( source );
}
DBGC ( source, "ENTROPY %s enabled\n", source->name );
return 0;
}
/**
* Enable and test entropy source
*
* @v source Entropy source
* @ret rc Return status code
*/
static int entropy_enable_and_test ( struct entropy_source *source ) {
int rc;
/* Enable source */
if ( ( rc = entropy_enable ( source ) ) != 0 )
goto err_enable;
/* Test source */
if ( ( rc = startup_test ( source ) ) != 0 )
goto err_test;
DBGC ( source, "ENTROPY %s passed %d startup tests\n",
source->name, source->startup_test.count );
return 0;
err_test:
entropy_disable ( source );
err_enable:
assert ( source->rc == rc );
return rc;
}
/**
* Enable first working entropy source
*
* @v source Entropy source to fill in
* @ret rc Return status code
*/
static int entropy_enable_working ( struct entropy_source **source ) {
int rc;
/* Find the first working source */
rc = -ENOENT;
for_each_table_entry ( *source, ENTROPY_SOURCES ) {
if ( ( rc = entropy_enable_and_test ( *source ) ) == 0 )
return 0;
}
DBGC ( *source, "ENTROPY has no working sources: %s\n",
strerror ( rc ) );
return rc;
}
/**
* Disable entropy gathering
*
* @v source Entropy source
*/
void entropy_disable ( struct entropy_source *source ) {
/* Disable entropy gathering, if applicable */
if ( source->disable )
source->disable();
DBGC ( source, "ENTROPY %s disabled\n", source->name );
}
/**
@ -402,7 +411,7 @@ static uint32_t make_next_nonce ( void ) {
/**
* Obtain entropy input temporary buffer
*
* @v num_samples Number of entropy samples
* @v min_entropy Min-entropy required
* @v tmp Temporary buffer
* @v tmp_len Length of temporary buffer
* @ret rc Return status code
@ -412,47 +421,41 @@ static uint32_t make_next_nonce ( void ) {
* and condensing each entropy source output after each GetEntropy
* call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section
* 13.3.4.2.
*
* To minimise code size, the number of samples required is calculated
* at compilation time.
*/
int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
int get_entropy_input_tmp ( min_entropy_t min_entropy, uint8_t *tmp,
size_t tmp_len ) {
static unsigned int startup_tested = 0;
struct entropy_source *source;
struct {
uint32_t nonce;
entropy_sample_t sample;
} __attribute__ (( packed )) data;;
uint8_t df_buf[tmp_len];
min_entropy_t entropy_total;
unsigned int num_samples;
unsigned int i;
int rc;
/* Enable entropy gathering */
if ( ( rc = entropy_enable() ) != 0 )
return rc;
if ( ( rc = entropy_enable_working ( &source ) ) != 0 )
goto err_enable_working;
/* Perform mandatory startup tests, if not yet performed */
for ( ; startup_tested < startup_test_count() ; startup_tested++ ) {
if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
goto err_get_entropy;
}
/* Sanity checks */
assert ( source->startup_test.count > 0 );
assert ( source->startup_test.tested >= source->startup_test.count );
/* 3. entropy_total = 0
*
* (Nothing to do; the number of entropy samples required has
* already been precalculated.)
*/
/* 3. entropy_total = 0 */
entropy_total = MIN_ENTROPY ( 0 );
/* 4. tmp = a fixed n-bit value, such as 0^n */
memset ( tmp, 0, tmp_len );
/* 5. While ( entropy_total < min_entropy ) */
while ( num_samples-- ) {
for ( num_samples = 0 ; entropy_total < min_entropy ; num_samples++ ) {
/* 5.1. ( status, entropy_bitstring, assessed_entropy )
* = GetEntropy()
* 5.2. If status indicates an error, return ( status, Null )
*/
if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
if ( ( rc = get_entropy ( source, &data.sample ) ) != 0 )
goto err_get_entropy;
/* 5.3. nonce = MakeNextNonce() */
@ -466,19 +469,26 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
for ( i = 0 ; i < tmp_len ; i++ )
tmp[i] ^= df_buf[i];
/* 5.5. entropy_total = entropy_total + assessed_entropy
*
* (Nothing to do; the number of entropy samples
* required has already been precalculated.)
*/
/* 5.5. entropy_total = entropy_total + assessed_entropy */
entropy_total += source->min_entropy_per_sample;
}
/* Disable entropy gathering */
entropy_disable();
entropy_disable ( source );
DBGC ( source, "ENTROPY %s gathered %d bits in %d samples\n",
source->name, ( min_entropy / MIN_ENTROPY_SCALE ), num_samples );
return 0;
err_get_entropy:
entropy_disable();
entropy_disable ( source );
assert ( source->rc == rc );
err_enable_working:
return rc;
}
/* Drag in objects via entropy_enable */
REQUIRING_SYMBOL ( entropy_enable );
/* Drag in entropy configuration */
REQUIRE_OBJECT ( config_entropy );

View File

@ -164,7 +164,7 @@ static int rsa_parse_mod_exp ( struct asn1_cursor *modulus,
int is_private;
int rc;
/* Enter subjectPublicKeyInfo/RSAPrivateKey */
/* Enter subjectPublicKeyInfo/privateKeyInfo/RSAPrivateKey */
memcpy ( &cursor, raw, sizeof ( cursor ) );
asn1_enter ( &cursor, ASN1_SEQUENCE );
@ -177,6 +177,23 @@ static int rsa_parse_mod_exp ( struct asn1_cursor *modulus,
/* Skip version */
asn1_skip_any ( &cursor );
/* Enter privateKey, if present */
if ( asn1_check_algorithm ( &cursor,
&rsa_encryption_algorithm ) == 0 ) {
/* Skip privateKeyAlgorithm */
asn1_skip_any ( &cursor );
/* Enter privateKey */
asn1_enter ( &cursor, ASN1_OCTET_STRING );
/* Enter RSAPrivateKey */
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Skip version */
asn1_skip ( &cursor, ASN1_INTEGER );
}
} else {
/* Public key */

View File

@ -609,6 +609,7 @@ static void scsicmd_read_capacity_cmd ( struct scsi_command *scsicmd,
*/
static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd,
int rc ) {
struct scsi_device *scsidev = scsicmd->scsidev;
struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
@ -645,6 +646,9 @@ static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd,
}
capacity.max_count = -1U;
/* Allow transport layer to update capacity */
block_capacity ( &scsidev->scsi, &capacity );
/* Return capacity to caller */
block_capacity ( &scsicmd->block, &capacity );

View File

@ -98,8 +98,16 @@ static void eisa_remove ( struct eisa_device *eisa ) {
static int eisabus_probe ( struct root_device *rootdev ) {
struct eisa_device *eisa = NULL;
unsigned int slot;
uint8_t system;
int rc;
/* Check for EISA system board */
system = inb ( EISA_VENDOR_ID );
if ( system & 0x80 ) {
DBG ( "No EISA system board (read %02x)\n", system );
return -ENODEV;
}
for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) {
/* Allocate struct eisa_device */
if ( ! eisa )

View File

@ -205,6 +205,7 @@ int pci_read_config ( struct pci_device *pci ) {
pci_read_config_dword ( pci, PCI_REVISION, &tmp );
pci->class = ( tmp >> 8 );
pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
pci_read_config_byte ( pci, PCI_HEADER_TYPE, &pci->hdrtype );
pci_read_bases ( pci );
/* Initialise generic device component */

View File

@ -1032,8 +1032,9 @@ static void nii_poll_tx ( struct net_device *netdev, unsigned int stat ) {
if ( stat & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN )
return;
/* Sanity check */
assert ( nii->txbuf != NULL );
/* Ignore spurious completions reported by some devices */
if ( ! nii->txbuf )
return;
/* Complete transmission */
iobuf = nii->txbuf;
@ -1131,7 +1132,7 @@ static void nii_poll ( struct net_device *netdev ) {
/* Get status */
op = NII_OP ( PXE_OPCODE_GET_STATUS,
( PXE_OPFLAGS_GET_INTERRUPT_STATUS |
( nii->txbuf ? PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS : 0)|
PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS |
( nii->media ? PXE_OPFLAGS_GET_MEDIA_STATUS : 0 ) ) );
if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
@ -1141,8 +1142,7 @@ static void nii_poll ( struct net_device *netdev ) {
}
/* Process any TX completions */
if ( nii->txbuf )
nii_poll_tx ( netdev, stat );
nii_poll_tx ( netdev, stat );
/* Process any RX completions */
nii_poll_rx ( netdev );

View File

@ -290,6 +290,18 @@ static int intel_reset ( struct intel_nic *intel ) {
pba, readl ( intel->regs + INTEL_PBA ) );
}
/* The Intel I210's packet buffer size registers reset only on
* power up. If an operating system changes these but then
* the computer recieves a reset signal without losing power,
* the registers will stay the same (but be incompatible with
* other register defaults), thus making the device unable to
* pass traffic.
*/
if ( intel->flags & INTEL_PBSIZE_RST ) {
writel ( INTEL_RXPBS_I210, intel->regs + INTEL_RXPBS );
writel ( INTEL_TXPBS_I210, intel->regs + INTEL_TXPBS );
}
/* Always reset MAC. Required to reset the TX and RX rings. */
writel ( ( ctrl | INTEL_CTRL_RST ), intel->regs + INTEL_CTRL );
mdelay ( INTEL_RESET_DELAY_MS );
@ -1139,7 +1151,7 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x1525, "82567v-4", "82567V-4", 0 ),
PCI_ROM ( 0x8086, 0x1526, "82576-5", "82576", 0 ),
PCI_ROM ( 0x8086, 0x1527, "82580-f2", "82580 Fiber", 0 ),
PCI_ROM ( 0x8086, 0x1533, "i210", "I210", 0 ),
PCI_ROM ( 0x8086, 0x1533, "i210", "I210", INTEL_PBSIZE_RST ),
PCI_ROM ( 0x8086, 0x1539, "i211", "I211", 0 ),
PCI_ROM ( 0x8086, 0x153a, "i217lm", "I217-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x153b, "i217v", "I217-V", 0 ),
@ -1147,7 +1159,7 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x155a, "i218lm", "I218-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x156f, "i219lm", "I219-LM", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1570, "i219v", "I219-V", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", 0 ),
PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", INTEL_PBSIZE_RST ),
PCI_ROM ( 0x8086, 0x15a0, "i218lm-2", "I218-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15a1, "i218v-2", "I218-V", 0 ),
PCI_ROM ( 0x8086, 0x15a2, "i218lm-3", "I218-LM", INTEL_NO_PHY_RST ),

View File

@ -138,6 +138,10 @@ struct intel_descriptor {
/** Packet Buffer Size */
#define INTEL_PBS 0x01008UL
/** Receive packet buffer size */
#define INTEL_RXPBS 0x02404UL
#define INTEL_RXPBS_I210 0x000000a2UL /**< I210 power-up default */
/** Receive Descriptor register block */
#define INTEL_RD 0x02800UL
@ -154,6 +158,10 @@ struct intel_descriptor {
/** Receive buffer length */
#define INTEL_RX_MAX_LEN 2048
/** Transmit packet buffer size */
#define INTEL_TXPBS 0x03404UL
#define INTEL_TXPBS_I210 0x04000014UL /**< I210 power-up default */
/** Transmit Descriptor register block */
#define INTEL_TD 0x03800UL
@ -319,6 +327,8 @@ enum intel_flags {
INTEL_NO_ASDE = 0x0008,
/** Reset may cause a complete device hang */
INTEL_RST_HANG = 0x0010,
/** PBSIZE registers must be explicitly reset */
INTEL_PBSIZE_RST = 0x0020,
};
/** The i219 has a seriously broken reset mechanism */

View File

@ -473,6 +473,7 @@ static struct pci_device_id intelx_nics[] = {
PCI_ROM ( 0x8086, 0x10f9, "82599-cx4", "82599 (CX4)", 0 ),
PCI_ROM ( 0x8086, 0x10fb, "82599-sfp", "82599 (SFI/SFP+)", 0 ),
PCI_ROM ( 0x8086, 0x10fc, "82599-xaui", "82599 (XAUI/BX4)", 0 ),
PCI_ROM ( 0x8086, 0x151c, "82599-tn", "82599 (TN)", 0 ),
PCI_ROM ( 0x8086, 0x1528, "x540t", "X540-AT2/X540-BT2", 0 ),
PCI_ROM ( 0x8086, 0x154d, "82599-sfp-sf2", "82599 (SFI/SFP+)", 0 ),
PCI_ROM ( 0x8086, 0x1557, "82599en-sfp", "82599 (Single Port SFI Only)", 0 ),

View File

@ -1067,11 +1067,15 @@ static void realtek_detect ( struct realtek_nic *rtl ) {
* Note that enabling DAC seems to cause bizarre behaviour
* (lockups, garbage data on the wire) on some systems, even
* if only 32-bit addresses are used.
*
* Disable VLAN offload, since some cards seem to have it
* enabled by default.
*/
cpcr = readw ( rtl->regs + RTL_CPCR );
cpcr |= ( RTL_CPCR_MULRW | RTL_CPCR_CPRX | RTL_CPCR_CPTX );
if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
cpcr |= RTL_CPCR_DAC;
cpcr &= ~RTL_CPCR_VLAN;
writew ( cpcr, rtl->regs + RTL_CPCR );
check_cpcr = readw ( rtl->regs + RTL_CPCR );

View File

@ -228,8 +228,9 @@ enum realtek_legacy_status {
/** C+ Command Register (word) */
#define RTL_CPCR 0xe0
#define RTL_CPCR_DAC 0x0010 /**< PCI Dual Address Cycle Enable */
#define RTL_CPCR_MULRW 0x0008 /**< PCI Multiple Read/Write Enable */
#define RTL_CPCR_VLAN 0x0040 /**< VLAN tag stripping enable */
#define RTL_CPCR_DAC 0x0010 /**< PCI Dual Address Cycle enable */
#define RTL_CPCR_MULRW 0x0008 /**< PCI Multiple Read/Write enable */
#define RTL_CPCR_CPRX 0x0002 /**< C+ receive enable */
#define RTL_CPCR_CPTX 0x0001 /**< C+ transmit enable */

View File

@ -129,7 +129,7 @@ static int imgsingle_exec ( int argc, char **argv,
&image ) ) != 0 )
goto err_acquire;
} else {
image = image_find_selected();
image = find_image_tag ( &selected_image );
if ( ! image ) {
printf ( "No image selected\n" );
goto err_acquire;

View File

@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Form parameter commands
* Request parameter commands
*
*/
@ -90,12 +90,16 @@ static int params_exec ( int argc, char **argv ) {
struct param_options {
/** Parameter list name */
char *params;
/** Parameter is a header */
int header;
};
/** "param" option list */
static struct option_descriptor param_opts[] = {
OPTION_DESC ( "params", 'p', required_argument,
struct param_options, params, parse_string ),
OPTION_DESC ( "header", 'H', no_argument,
struct param_options, header, parse_flag ),
};
/** "param" command descriptor */
@ -114,6 +118,7 @@ static int param_exec ( int argc, char **argv ) {
struct param_options opts;
char *key;
char *value;
unsigned int flags;
struct parameters *params;
struct parameter *param;
int rc;
@ -132,12 +137,15 @@ static int param_exec ( int argc, char **argv ) {
goto err_parse_value;
}
/* Construct flags */
flags = ( opts.header ? PARAMETER_HEADER : PARAMETER_FORM );
/* Identify parameter list */
if ( ( rc = parse_parameters ( opts.params, &params ) ) != 0 )
goto err_parse_parameters;
/* Add parameter */
param = add_parameter ( params, key, value );
param = add_parameter ( params, key, value, flags );
if ( ! param ) {
rc = -ENOMEM;
goto err_add_parameter;
@ -154,7 +162,7 @@ static int param_exec ( int argc, char **argv ) {
return rc;
}
/** Form parameter commands */
/** Request parameter commands */
struct command param_commands[] __command = {
{
.name = "params",

131
src/hci/commands/shim_cmd.c Normal file
View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2023 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/efi/efi_image.h>
#include <usr/imgmgmt.h>
#include <usr/shimmgmt.h>
/** @file
*
* EFI shim command
*
*/
/* Exist as a dummy command on non-EFI platforms */
#ifdef PLATFORM_efi
#define shim_dummy 0
#else
#define shim_dummy 1
#endif
/** "shim" options */
struct shim_options {
/** Download timeout */
unsigned long timeout;
/** Require third party loader */
int require_loader;
/** Allow PXE base code protocol */
int allow_pxe;
/** Allow SBAT variable access */
int allow_sbat;
};
/** "shim" option list */
static struct option_descriptor shim_opts[] = {
OPTION_DESC ( "timeout", 't', required_argument,
struct shim_options, timeout, parse_timeout ),
OPTION_DESC ( "require-loader", 'l', no_argument,
struct shim_options, require_loader, parse_flag ),
OPTION_DESC ( "allow-pxe", 'p', no_argument,
struct shim_options, allow_pxe, parse_flag ),
OPTION_DESC ( "allow-sbat", 's', no_argument,
struct shim_options, allow_sbat, parse_flag ),
};
/** "shim" command descriptor */
static struct command_descriptor shim_cmd =
COMMAND_DESC ( struct shim_options, shim_opts, 0, 1, NULL );
/**
* The "shim" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int shim_exec ( int argc, char **argv ) {
struct shim_options opts;
struct image *image = NULL;
struct image *kernel;
char *name_uri;
int download;
int rc;
/* Do absolutely nothing if this is a non-EFI platform */
if ( shim_dummy ) {
rc = 0;
goto err_dummy;
}
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &shim_cmd, &opts ) ) != 0 )
goto err_parse;
/* Decide whether or not to download images */
kernel = find_image_tag ( &selected_image );
download = ( ! ( kernel && efi_can_load ( kernel ) ) );
/* Parse name/URI string */
name_uri = argv[optind];
/* Acquire image, if applicable */
if ( download && name_uri &&
( ( rc = imgacquire ( name_uri, opts.timeout,
&image ) ) != 0 ) ) {
goto err_image;
}
/* (Un)register as shim */
if ( ( rc = shim ( image, opts.require_loader, opts.allow_pxe,
opts.allow_sbat ) ) != 0 )
goto err_shim;
err_shim:
err_image:
err_parse:
err_dummy:
return rc;
}
/** Shim commands */
struct command shim_commands[] __command = {
{
.name = "shim",
.exec = shim_exec,
},
};

View File

@ -31,6 +31,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/efi/efi_wrap.h>
#include <ipxe/efi/efi_pxe.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_image.h>
#include <ipxe/efi/efi_shim.h>
#include <ipxe/image.h>
#include <ipxe/init.h>
#include <ipxe/features.h>
@ -109,18 +111,14 @@ efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) {
*/
static wchar_t * efi_image_cmdline ( struct image *image ) {
wchar_t *cmdline;
size_t len;
len = ( strlen ( image->name ) +
( image->cmdline ?
( 1 /* " " */ + strlen ( image->cmdline ) ) : 0 ) );
cmdline = zalloc ( ( len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
if ( ! cmdline )
/* Allocate and construct command line */
if ( efi_asprintf ( &cmdline, "%s%s%s", image->name,
( image->cmdline ? " " : "" ),
( image->cmdline ? image->cmdline : "" ) ) < 0 ) {
return NULL;
efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s",
image->name,
( image->cmdline ? " " : "" ),
( image->cmdline ? image->cmdline : "" ) );
}
return cmdline;
}
@ -138,47 +136,65 @@ static int efi_image_exec ( struct image *image ) {
EFI_LOADED_IMAGE_PROTOCOL *image;
void *interface;
} loaded;
struct image *shim;
struct image *exec;
EFI_HANDLE handle;
EFI_MEMORY_TYPE type;
wchar_t *cmdline;
unsigned int toggle;
EFI_STATUS efirc;
int rc;
/* Find an appropriate device handle to use */
snpdev = last_opened_snpdev();
if ( ! snpdev ) {
DBGC ( image, "EFIIMAGE %p could not identify SNP device\n",
image );
DBGC ( image, "EFIIMAGE %s could not identify SNP device\n",
image->name );
rc = -ENODEV;
goto err_no_snpdev;
}
/* Use shim instead of directly executing image if applicable */
shim = ( efi_can_load ( image ) ?
NULL : find_image_tag ( &efi_shim ) );
exec = ( shim ? shim : image );
if ( shim ) {
DBGC ( image, "EFIIMAGE %s executing via %s\n",
image->name, shim->name );
}
/* Re-register as a hidden image to allow for access via file I/O */
toggle = ( ~image->flags & IMAGE_HIDDEN );
image->flags |= IMAGE_HIDDEN;
if ( ( rc = register_image ( image ) ) != 0 )
goto err_register_image;
/* Install file I/O protocols */
if ( ( rc = efi_file_install ( snpdev->handle ) ) != 0 ) {
DBGC ( image, "EFIIMAGE %p could not install file protocol: "
"%s\n", image, strerror ( rc ) );
DBGC ( image, "EFIIMAGE %s could not install file protocol: "
"%s\n", image->name, strerror ( rc ) );
goto err_file_install;
}
/* Install PXE base code protocol */
if ( ( rc = efi_pxe_install ( snpdev->handle, snpdev->netdev ) ) != 0 ){
DBGC ( image, "EFIIMAGE %p could not install PXE protocol: "
"%s\n", image, strerror ( rc ) );
DBGC ( image, "EFIIMAGE %s could not install PXE protocol: "
"%s\n", image->name, strerror ( rc ) );
goto err_pxe_install;
}
/* Install iPXE download protocol */
if ( ( rc = efi_download_install ( snpdev->handle ) ) != 0 ) {
DBGC ( image, "EFIIMAGE %p could not install iPXE download "
"protocol: %s\n", image, strerror ( rc ) );
DBGC ( image, "EFIIMAGE %s could not install iPXE download "
"protocol: %s\n", image->name, strerror ( rc ) );
goto err_download_install;
}
/* Create device path for image */
path = efi_image_path ( image, snpdev->path );
path = efi_image_path ( exec, snpdev->path );
if ( ! path ) {
DBGC ( image, "EFIIMAGE %p could not create device path\n",
image );
DBGC ( image, "EFIIMAGE %s could not create device path\n",
image->name );
rc = -ENOMEM;
goto err_image_path;
}
@ -186,21 +202,30 @@ static int efi_image_exec ( struct image *image ) {
/* Create command line for image */
cmdline = efi_image_cmdline ( image );
if ( ! cmdline ) {
DBGC ( image, "EFIIMAGE %p could not create command line\n",
image );
DBGC ( image, "EFIIMAGE %s could not create command line\n",
image->name );
rc = -ENOMEM;
goto err_cmdline;
}
/* Install shim special handling if applicable */
if ( shim &&
( ( rc = efi_shim_install ( shim, snpdev->handle,
&cmdline ) ) != 0 ) ){
DBGC ( image, "EFIIMAGE %s could not install shim handling: "
"%s\n", image->name, strerror ( rc ) );
goto err_shim_install;
}
/* Attempt loading image */
handle = NULL;
if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
user_to_virt ( image->data, 0 ),
image->len, &handle ) ) != 0 ) {
user_to_virt ( exec->data, 0 ),
exec->len, &handle ) ) != 0 ) {
/* Not an EFI image */
rc = -EEFI_LOAD ( efirc );
DBGC ( image, "EFIIMAGE %p could not load: %s\n",
image, strerror ( rc ) );
DBGC ( image, "EFIIMAGE %s could not load: %s\n",
image->name, strerror ( rc ) );
if ( efirc == EFI_SECURITY_VIOLATION ) {
goto err_load_image_security_violation;
} else {
@ -220,8 +245,8 @@ static int efi_image_exec ( struct image *image ) {
/* Some EFI 1.10 implementations seem not to fill in DeviceHandle */
if ( loaded.image->DeviceHandle == NULL ) {
DBGC ( image, "EFIIMAGE %p filling in missing DeviceHandle\n",
image );
DBGC ( image, "EFIIMAGE %s filling in missing DeviceHandle\n",
image->name );
loaded.image->DeviceHandle = snpdev->handle;
}
@ -251,14 +276,14 @@ static int efi_image_exec ( struct image *image ) {
/* Start the image */
if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) {
rc = -EEFI_START ( efirc );
DBGC ( image, "EFIIMAGE %p could not start (or returned with "
"error): %s\n", image, strerror ( rc ) );
DBGC ( image, "EFIIMAGE %s could not start (or returned with "
"error): %s\n", image->name, strerror ( rc ) );
goto err_start_image;
}
/* If image was a driver, connect it up to anything available */
if ( type == EfiBootServicesCode ) {
DBGC ( image, "EFIIMAGE %p connecting drivers\n", image );
DBGC ( image, "EFIIMAGE %s connecting drivers\n", image->name );
efi_driver_reconnect_all();
}
@ -286,6 +311,9 @@ static int efi_image_exec ( struct image *image ) {
if ( rc != 0 )
bs->UnloadImage ( handle );
err_load_image:
if ( shim )
efi_shim_uninstall();
err_shim_install:
free ( cmdline );
err_cmdline:
free ( path );
@ -296,6 +324,9 @@ static int efi_image_exec ( struct image *image ) {
err_pxe_install:
efi_file_uninstall ( snpdev->handle );
err_file_install:
unregister_image ( image );
err_register_image:
image->flags ^= toggle;
err_no_snpdev:
return rc;
}
@ -324,8 +355,8 @@ static int efi_image_probe ( struct image *image ) {
image->len, &handle ) ) != 0 ) {
/* Not an EFI image */
rc = -EEFI_LOAD ( efirc );
DBGC ( image, "EFIIMAGE %p could not load: %s\n",
image, strerror ( rc ) );
DBGC ( image, "EFIIMAGE %s could not load: %s\n",
image->name, strerror ( rc ) );
if ( efirc == EFI_SECURITY_VIOLATION ) {
goto err_load_image_security_violation;
} else {
@ -346,9 +377,75 @@ static int efi_image_probe ( struct image *image ) {
return rc;
}
/** EFI image type */
struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
.name = "EFI",
.probe = efi_image_probe,
.exec = efi_image_exec,
/**
* Probe EFI PE image
*
* @v image EFI file
* @ret rc Return status code
*
* The extremely broken UEFI Secure Boot model provides no way for us
* to unambiguously determine that a valid EFI executable image was
* rejected by LoadImage() because it failed signature verification.
* We must therefore use heuristics to guess whether not an image that
* was rejected by LoadImage() could still be loaded via a separate PE
* loader such as the UEFI shim.
*/
static int efi_pe_image_probe ( struct image *image ) {
const UINT16 magic = ( ( sizeof ( UINTN ) == sizeof ( uint32_t ) ) ?
EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC :
EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC );
union {
EFI_IMAGE_DOS_HEADER dos;
EFI_IMAGE_OPTIONAL_HEADER_UNION pe;
} u;
/* Check for existence of DOS header */
if ( image->len < sizeof ( u.dos ) ) {
DBGC ( image, "EFIIMAGE %s too short for DOS header\n",
image->name );
return -ENOEXEC;
}
copy_from_user ( &u.dos, image->data, 0, sizeof ( u.dos ) );
if ( u.dos.e_magic != EFI_IMAGE_DOS_SIGNATURE ) {
DBGC ( image, "EFIIMAGE %s missing MZ signature\n",
image->name );
return -ENOEXEC;
}
/* Check for existence of PE header */
if ( ( image->len < u.dos.e_lfanew ) ||
( ( image->len - u.dos.e_lfanew ) < sizeof ( u.pe ) ) ) {
DBGC ( image, "EFIIMAGE %s too short for PE header\n",
image->name );
return -ENOEXEC;
}
copy_from_user ( &u.pe, image->data, u.dos.e_lfanew, sizeof ( u.pe ) );
if ( u.pe.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE ) {
DBGC ( image, "EFIIMAGE %s missing PE signature\n",
image->name );
return -ENOEXEC;
}
/* Check PE header magic */
if ( u.pe.Pe32.OptionalHeader.Magic != magic ) {
DBGC ( image, "EFIIMAGE %s incorrect magic %04x\n",
image->name, u.pe.Pe32.OptionalHeader.Magic );
return -ENOEXEC;
}
return 0;
}
/** EFI image types */
struct image_type efi_image_type[] __image_type ( PROBE_NORMAL ) = {
{
.name = "EFI",
.probe = efi_image_probe,
.exec = efi_image_exec,
},
{
.name = "EFIPE",
.probe = efi_pe_image_probe,
.exec = efi_image_exec,
},
};

View File

@ -197,11 +197,6 @@ static int script_exec ( struct image *image ) {
size_t saved_offset;
int rc;
/* Temporarily de-register image, so that a "boot" command
* doesn't throw us into an execution loop.
*/
unregister_image ( image );
/* Preserve state of any currently-running script */
saved_offset = script_offset;
@ -212,10 +207,6 @@ static int script_exec ( struct image *image ) {
/* Restore saved state */
script_offset = saved_offset;
/* Re-register image (unless we have been replaced) */
if ( ! image->replacement )
register_image ( image );
return rc;
}
@ -320,6 +311,7 @@ static int terminate_on_label_found ( int rc ) {
* @ret rc Return status code
*/
static int goto_exec ( int argc, char **argv ) {
struct image *image = current_image.image;
struct goto_options opts;
size_t saved_offset;
int rc;
@ -329,7 +321,7 @@ static int goto_exec ( int argc, char **argv ) {
return rc;
/* Sanity check */
if ( ! current_image ) {
if ( ! image ) {
rc = -ENOTTY;
printf ( "Not in a script: %s\n", strerror ( rc ) );
return rc;
@ -340,10 +332,10 @@ static int goto_exec ( int argc, char **argv ) {
/* Find label */
saved_offset = script_offset;
if ( ( rc = process_script ( current_image, goto_find_label,
if ( ( rc = process_script ( image, goto_find_label,
terminate_on_label_found ) ) != 0 ) {
script_offset = saved_offset;
DBGC ( current_image, "[%04zx] No such label :%s\n",
DBGC ( image, "[%04zx] No such label :%s\n",
script_offset, goto_label );
return rc;
}

View File

@ -800,7 +800,7 @@ char __debug_disable(OBJECT) = ( DBGLVL_MAX & ~DBGLVL_DFLT );
* patent grant.
*/
#define FILE_LICENCE_BSD2_PATENT \
PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__bsd2__patent__ ) )
PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__bsd2_patent__ ) )
/** Declare a file as being under the one-clause MIT-style licence
*

View File

@ -262,10 +262,10 @@ static inline void eplatform_discard ( int dummy __unused, ... ) {}
".balign 8\n\t" \
"\n1:\n\t" \
".long ( 4f - 1b )\n\t" \
".long %c0\n\t" \
".long %" ASM_NO_PREFIX "0\n\t" \
".long ( 2f - 1b )\n\t" \
".long ( 3f - 1b )\n\t" \
".long %c1\n\t" \
".long %" ASM_NO_PREFIX "1\n\t" \
"\n2:\t.asciz \"" __einfo_desc ( einfo ) "\"\n\t" \
"\n3:\t.asciz \"" __FILE__ "\"\n\t" \
".balign 8\n\t" \

View File

@ -424,6 +424,8 @@ extern int asn1_digest_algorithm ( const struct asn1_cursor *cursor,
struct asn1_algorithm **algorithm );
extern int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
struct asn1_algorithm **algorithm );
extern int asn1_check_algorithm ( const struct asn1_cursor *cursor,
struct asn1_algorithm *expected );
extern int asn1_generalized_time ( const struct asn1_cursor *cursor,
time_t *time );
extern int asn1_grow ( struct asn1_builder *builder, size_t extra );

View File

@ -274,8 +274,9 @@ struct dhcp_client_architecture {
/** DHCP client architecture values
*
* These are defined by the PXE specification and redefined by
* RFC4578.
* These are originally defined by the PXE specification, redefined by
* RFC4578, redefined again by RFC5970, and now maintained in the IANA
* DHCPv6 parameters registry.
*/
enum dhcp_client_architecture_values {
/** Intel x86 PC */
@ -302,6 +303,24 @@ enum dhcp_client_architecture_values {
DHCP_CLIENT_ARCHITECTURE_ARM32 = 0x000a,
/** EFI 64-bit ARM */
DHCP_CLIENT_ARCHITECTURE_ARM64 = 0x000b,
/** EFI 32-bit RISC-V */
DHCP_CLIENT_ARCHITECTURE_RISCV32 = 0x0019,
/** EFI 64-bit RISC-V */
DHCP_CLIENT_ARCHITECTURE_RISCV64 = 0x001b,
/** EFI 128-bit RISC-V */
DHCP_CLIENT_ARCHITECTURE_RISCV128 = 0x001d,
/** EFI 32-bit MIPS */
DHCP_CLIENT_ARCHITECTURE_MIPS32 = 0x0021,
/** EFI 64-bit MIPS */
DHCP_CLIENT_ARCHITECTURE_MIPS64 = 0x0022,
/** EFI 32-bit Sunway */
DHCP_CLIENT_ARCHITECTURE_SUNWAY32 = 0x0023,
/** EFI 64-bit Sunway */
DHCP_CLIENT_ARCHITECTURE_SUNWAY64 = 0x0024,
/** EFI 32-bit LoongArch */
DHCP_CLIENT_ARCHITECTURE_LOONG32 = 0x0025,
/** EFI 64-bit LoongArch */
DHCP_CLIENT_ARCHITECTURE_LOONG64 = 0x0027,
};
/** Client network device interface */

View File

@ -188,6 +188,40 @@ typedef INT64 INTN;
#define GCC_ASM_IMPORT(func__) \
.extern _CONCATENATE (__USER_LABEL_PREFIX__, func__)
#if defined (__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
#define AARCH64_BTI_NOTE() \
.ifndef .Lgnu_bti_notesize ;\
.pushsection .note.gnu.property, "a" ;\
.set NT_GNU_PROPERTY_TYPE_0, 0x5 ;\
.set GNU_PROPERTY_AARCH64_FEATURE_1_AND, 0xc0000000 ;\
.set GNU_PROPERTY_AARCH64_FEATURE_1_BTI, 0x1 ;\
.align 3 ;\
.long .Lnamesize ;\
.long .Lgnu_bti_notesize ;\
.long NT_GNU_PROPERTY_TYPE_0 ;\
0: .asciz "GNU" ;\
.set .Lnamesize, . - 0b ;\
.align 3 ;\
1: .long GNU_PROPERTY_AARCH64_FEATURE_1_AND ;\
.long .Lvalsize ;\
2: .long GNU_PROPERTY_AARCH64_FEATURE_1_BTI ;\
.set .Lvalsize, . - 2b ;\
.align 3 ;\
.set .Lgnu_bti_notesize, . - 1b ;\
.popsection ;\
.endif
#define AARCH64_BTI(__type) \
AARCH64_BTI_NOTE() ;\
bti __type
#endif
#endif
#ifndef AARCH64_BTI
#define AARCH64_BTI_NOTE()
#define AARCH64_BTI(__type)
#endif
/**

View File

@ -760,6 +760,40 @@ typedef UINTN *BASE_LIST;
#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
#endif
/**
Returns the alignment requirement of a type.
@param TYPE The name of the type to retrieve the alignment requirement of.
@return Alignment requirement, in Bytes, of TYPE.
**/
#if defined (__cplusplus)
//
// Standard C++ operator.
//
#define ALIGNOF(TYPE) alignof (TYPE)
#elif defined (__GNUC__) || defined (__clang__) || (defined (_MSC_VER) && _MSC_VER >= 1900)
//
// All supported versions of GCC and Clang, as well as MSVC 2015 and later,
// support the standard operator _Alignof.
//
#define ALIGNOF(TYPE) _Alignof (TYPE)
#elif defined (_MSC_EXTENSIONS)
//
// Earlier versions of MSVC, at least MSVC 2008 and later, support the vendor
// extension __alignof.
//
#define ALIGNOF(TYPE) __alignof (TYPE)
#else
//
// For compilers that do not support inbuilt alignof operators, use OFFSET_OF.
// CHAR8 is known to have both a size and an alignment requirement of 1 Byte.
// As such, A must be located exactly at the offset equal to its alignment
// requirement.
//
#define ALIGNOF(TYPE) OFFSET_OF (struct { CHAR8 C; TYPE A; }, A)
#endif
/**
Portable definition for compile time assertions.
Equivalent to C11 static_assert macro from assert.h.
@ -795,12 +829,27 @@ STATIC_ASSERT (sizeof (CHAR16) == 2, "sizeof (CHAR16) does not meet UEFI Specif
STATIC_ASSERT (sizeof (L'A') == 2, "sizeof (L'A') does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (sizeof (L"A") == 4, "sizeof (L\"A\") does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (BOOLEAN) == sizeof (BOOLEAN), "Alignment of BOOLEAN does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (INT8) == sizeof (INT8), "Alignment of INT8 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (UINT8) == sizeof (UINT8), "Alignment of INT16 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (INT16) == sizeof (INT16), "Alignment of INT16 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (UINT16) == sizeof (UINT16), "Alignment of UINT16 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (INT32) == sizeof (INT32), "Alignment of INT32 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (UINT32) == sizeof (UINT32), "Alignment of UINT32 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (INT64) == sizeof (INT64), "Alignment of INT64 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (UINT64) == sizeof (UINT64), "Alignment of UINT64 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (CHAR8) == sizeof (CHAR8), "Alignment of CHAR8 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (CHAR16) == sizeof (CHAR16), "Alignment of CHAR16 does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (INTN) == sizeof (INTN), "Alignment of INTN does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (UINTN) == sizeof (UINTN), "Alignment of UINTN does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (VOID *) == sizeof (VOID *), "Alignment of VOID * does not meet UEFI Specification Data Type requirements");
//
// The following three enum types are used to verify that the compiler
// configuration for enum types is compliant with Section 2.3.1 of the
// UEFI 2.3 Specification. These enum types and enum values are not
// intended to be used. A prefix of '__' is used avoid conflicts with
// other types.
// UEFI 2.3.1 Errata C Specification. These enum types and enum values
// are not intended to be used. A prefix of '__' is used avoid
// conflicts with other types.
//
typedef enum {
__VerifyUint8EnumValue = 0xff
@ -811,12 +860,16 @@ typedef enum {
} __VERIFY_UINT16_ENUM_SIZE;
typedef enum {
__VerifyUint32EnumValue = 0xffffffff
} __VERIFY_UINT32_ENUM_SIZE;
__VerifyInt32EnumValue = 0x7fffffff
} __VERIFY_INT32_ENUM_SIZE;
STATIC_ASSERT (sizeof (__VERIFY_UINT8_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (sizeof (__VERIFY_UINT16_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (sizeof (__VERIFY_INT32_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (__VERIFY_UINT8_ENUM_SIZE) == sizeof (__VERIFY_UINT8_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (__VERIFY_UINT16_ENUM_SIZE) == sizeof (__VERIFY_UINT16_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (ALIGNOF (__VERIFY_INT32_ENUM_SIZE) == sizeof (__VERIFY_INT32_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements");
/**
Macro that returns a pointer to the data structure that contains a specified field of
@ -839,6 +892,49 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not m
**/
#define BASE_CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - OFFSET_OF (TYPE, Field)))
/**
Checks whether a value is a power of two.
@param Value The value to check.
@retval TRUE Value is a power of two.
@retval FALSE Value is not a power of two.
**/
#define IS_POW2(Value) ((Value) != 0U && ((Value) & ((Value) - 1U)) == 0U)
/**
Checks whether a value is aligned by a specified alignment.
@param Value The value to check.
@param Alignment The alignment boundary used to check against.
@retval TRUE Value is aligned by Alignment.
@retval FALSE Value is not aligned by Alignment.
**/
#define IS_ALIGNED(Value, Alignment) (((Value) & ((Alignment) - 1U)) == 0U)
/**
Checks whether a pointer or address is aligned by a specified alignment.
@param Address The pointer or address to check.
@param Alignment The alignment boundary used to check against.
@retval TRUE Address is aligned by Alignment.
@retval FALSE Address is not aligned by Alignment.
**/
#define ADDRESS_IS_ALIGNED(Address, Alignment) IS_ALIGNED ((UINTN) (Address), Alignment)
/**
Determines the addend to add to a value to round it up to the next boundary of
a specified alignment.
@param Value The value to round up.
@param Alignment The alignment boundary used to return the addend.
@return Addend to round Value up to alignment boundary Alignment.
**/
#define ALIGN_VALUE_ADDEND(Value, Alignment) (((Alignment) - (Value)) & ((Alignment) - 1U))
/**
Rounds a value up to the next boundary using a specified alignment.
@ -851,7 +947,7 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not m
@return A value up to the next boundary.
**/
#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
#define ALIGN_VALUE(Value, Alignment) ((Value) + ALIGN_VALUE_ADDEND (Value, Alignment))
/**
Adjust a pointer by adding the minimum offset required for it to be aligned on

View File

@ -90,19 +90,15 @@ FILE_LICENCE ( BSD2_PATENT );
#if defined (_MSC_VER) && _MSC_VER >= 1800
//
// Disable these warnings for VS2013.
//
//
// This warning is for potentially uninitialized local variable, and it may cause false
// positive issues in VS2013 and VS2015 build
// positive issues in VS2015 build
//
#pragma warning ( disable : 4701 )
//
// This warning is for potentially uninitialized local pointer variable, and it may cause
// false positive issues in VS2013 and VS2015 build
// false positive issues in VS2015 build
//
#pragma warning ( disable : 4703 )

View File

@ -103,6 +103,7 @@ typedef struct {
#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references).
#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line numbers stripped from file.
#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file.
#define EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE BIT5 ///< 0x0020 Supports addresses > 2-GB
#define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed.
#define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine.
#define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file.
@ -579,6 +580,13 @@ typedef struct {
UINT32 AddressOfNameOrdinals;
} EFI_IMAGE_EXPORT_DIRECTORY;
//
// Based export types.
//
#define EFI_IMAGE_EXPORT_ORDINAL_BASE 1
#define EFI_IMAGE_EXPORT_ADDR_SIZE 4
#define EFI_IMAGE_EXPORT_ORDINAL_SIZE 2
///
/// Hint/Name Table.
///
@ -627,7 +635,8 @@ typedef struct {
UINT32 FileOffset; ///< The file pointer to the debug data.
} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information.
#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information.
#define EFI_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS 20
///
/// Debug Data Structure defined in Microsoft C++.
@ -671,6 +680,39 @@ typedef struct {
//
} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
// avoid conflict with windows header files
#ifndef RUNTIME_FUNCTION_INDIRECT
//
// .pdata entries for X64
//
typedef struct {
UINT32 FunctionStartAddress;
UINT32 FunctionEndAddress;
UINT32 UnwindInfoAddress;
} RUNTIME_FUNCTION;
#endif
typedef struct {
UINT8 Version : 3;
UINT8 Flags : 5;
UINT8 SizeOfProlog;
UINT8 CountOfUnwindCodes;
UINT8 FrameRegister : 4;
UINT8 FrameRegisterOffset : 4;
} UNWIND_INFO;
///
/// Extended DLL Characteristics
///
#define EFI_IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT 0x0001
#define EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT 0x0040
typedef struct {
UINT32 DllCharacteristicsEx;
} EFI_IMAGE_DEBUG_EX_DLLCHARACTERISTICS_ENTRY;
///
/// Resource format.
///

View File

@ -153,6 +153,56 @@ typedef struct {
#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8
VOID
RiscVSetSupervisorScratch (
IN UINT64
);
UINT64
RiscVGetSupervisorScratch (
VOID
);
VOID
RiscVSetSupervisorStvec (
IN UINT64
);
UINT64
RiscVGetSupervisorStvec (
VOID
);
UINT64
RiscVGetSupervisorTrapCause (
VOID
);
VOID
RiscVSetSupervisorAddressTranslationRegister (
IN UINT64
);
UINT64
RiscVReadTimer (
VOID
);
VOID
RiscVEnableTimerInterrupt (
VOID
);
VOID
RiscVDisableTimerInterrupt (
VOID
);
VOID
RiscVClearPendingTimerInterrupt (
VOID
);
#endif // defined (MDE_CPU_RISCV64)
#if defined (MDE_CPU_LOONGARCH64)

View File

@ -0,0 +1,122 @@
/** @file
Processor or Compiler specific defines and types for LoongArch
Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef PROCESSOR_BIND_H_
#define PROCESSOR_BIND_H_
FILE_LICENCE ( BSD2_PATENT );
//
// Define the processor type so other code can make processor based choices
//
#define MDE_CPU_LOONGARCH64
#define EFIAPI
//
// Make sure we are using the correct packing rules per EFI specification
//
#ifndef __GNUC__
#pragma pack()
#endif
//
// Assume standard LoongArch 64-bit alignment.
// Need to check portability of long long
//
typedef unsigned long long UINT64;
typedef long long INT64;
typedef unsigned int UINT32;
typedef int INT32;
typedef unsigned short UINT16;
typedef unsigned short CHAR16;
typedef short INT16;
typedef unsigned char BOOLEAN;
typedef unsigned char UINT8;
typedef char CHAR8;
typedef char INT8;
//
// Unsigned value of native width. (4 bytes on supported 32-bit processor instructions,
// 8 bytes on supported 64-bit processor instructions)
//
typedef UINT64 UINTN;
//
// Signed value of native width. (4 bytes on supported 32-bit processor instructions,
// 8 bytes on supported 64-bit processor instructions)
//
typedef INT64 INTN;
//
// Processor specific defines
//
//
// A value of native width with the highest bit set.
//
#define MAX_BIT 0x8000000000000000ULL
//
// A value of native width with the two highest bits set.
//
#define MAX_2_BITS 0xC000000000000000ULL
//
// Maximum legal LoongArch 64-bit address
//
#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFFULL
//
// Maximum usable address at boot time (48 bits using 4KB pages)
//
#define MAX_ALLOC_ADDRESS 0xFFFFFFFFFFFFULL
//
// Maximum legal LoongArch 64-bit INTN and UINTN values.
//
#define MAX_INTN ((INTN)0x7FFFFFFFFFFFFFFFULL)
#define MAX_UINTN ((UINTN)0xFFFFFFFFFFFFFFFFULL)
//
// Page allocation granularity for LoongArch
//
#define DEFAULT_PAGE_ALLOCATION_GRANULARITY (0x1000)
#define RUNTIME_PAGE_ALLOCATION_GRANULARITY (0x10000)
#if defined (__GNUC__)
//
// For GNU assembly code, .global or .globl can declare global symbols.
// Define this macro to unify the usage.
//
#define ASM_GLOBAL .globl
#endif
//
// The stack alignment required for LoongArch
//
#define CPU_STACK_ALIGNMENT 16
/**
Return the pointer to the first instruction of a function given a function pointer.
On LOONGARCH CPU architectures, these two pointer values are the same,
so the implementation of this macro is very simple.
@param FunctionPointer A pointer to a function.
@return The pointer to the first instruction of a function given a function pointer.
**/
#define FUNCTION_ENTRY_POINT(FunctionPointer) (VOID *)(UINTN)(FunctionPointer)
#ifndef __USER_LABEL_PREFIX__
#define __USER_LABEL_PREFIX__
#endif
#endif

View File

@ -66,7 +66,7 @@ typedef enum {
// /// EfiGcdMemoryTypeUnaccepted is defined in PrePiDxeCis.h because it has not been
// /// defined in PI spec.
// EfiGcdMemoryTypeUnaccepted,
EfiGcdMemoryTypeMaximum = 8
EfiGcdMemoryTypeMaximum = 7
} EFI_GCD_MEMORY_TYPE;
///

View File

@ -61,6 +61,10 @@ typedef uint8_t BOOLEAN;
#include <ipxe/efi/AArch64/ProcessorBind.h>
#endif
#ifdef __loongarch__
#include <ipxe/efi/LoongArch64/ProcessorBind.h>
#endif
#endif /* EFI_HOSTONLY */
#endif /* _IPXE_EFI_PROCESSOR_BIND_H */

View File

@ -615,11 +615,34 @@ typedef struct {
#define EXCEPT_RISCV_STORE_AMO_ACCESS_FAULT 7
#define EXCEPT_RISCV_ENV_CALL_FROM_UMODE 8
#define EXCEPT_RISCV_ENV_CALL_FROM_SMODE 9
#define EXCEPT_RISCV_ENV_CALL_FROM_HMODE 10
#define EXCEPT_RISCV_ENV_CALL_FROM_VS_MODE 10
#define EXCEPT_RISCV_ENV_CALL_FROM_MMODE 11
#define EXCEPT_RISCV_INST_ACCESS_PAGE_FAULT 12
#define EXCEPT_RISCV_LOAD_ACCESS_PAGE_FAULT 13
#define EXCEPT_RISCV_14 14
#define EXCEPT_RISCV_STORE_ACCESS_PAGE_FAULT 15
#define EXCEPT_RISCV_16 16
#define EXCEPT_RISCV_17 17
#define EXCEPT_RISCV_18 18
#define EXCEPT_RISCV_19 19
#define EXCEPT_RISCV_INST_GUEST_PAGE_FAULT 20
#define EXCEPT_RISCV_LOAD_GUEST_PAGE_FAULT 21
#define EXCEPT_RISCV_VIRTUAL_INSTRUCTION 22
#define EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT 23
#define EXCEPT_RISCV_MAX_EXCEPTIONS (EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT)
#define EXCEPT_RISCV_SOFTWARE_INT 0x0
#define EXCEPT_RISCV_TIMER_INT 0x1
///
/// RISC-V processor exception types for interrupts.
///
#define EXCEPT_RISCV_IS_IRQ(x) ((x & 0x8000000000000000UL) != 0)
#define EXCEPT_RISCV_IRQ_INDEX(x) (x & 0x7FFFFFFFFFFFFFFFUL)
#define EXCEPT_RISCV_IRQ_0 0x8000000000000000UL
#define EXCEPT_RISCV_IRQ_SOFT_FROM_SMODE 0x8000000000000001UL
#define EXCEPT_RISCV_IRQ_SOFT_FROM_VSMODE 0x8000000000000002UL
#define EXCEPT_RISCV_IRQ_SOFT_FROM_MMODE 0x8000000000000003UL
#define EXCEPT_RISCV_IRQ_4 0x8000000000000004UL
#define EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE 0x8000000000000005UL
#define EXCEPT_RISCV_MAX_IRQS (EXCEPT_RISCV_IRQ_INDEX(EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE))
typedef struct {
UINT64 X0;
@ -654,6 +677,9 @@ typedef struct {
UINT64 X29;
UINT64 X30;
UINT64 X31;
UINT64 SEPC;
UINT32 SSTATUS;
UINT32 STVAL;
} EFI_SYSTEM_CONTEXT_RISCV64;
//

View File

@ -0,0 +1,782 @@
/** @file
UEFI Dynamic Host Configuration Protocol 6 Definition, which is used to get IPv6
addresses and other configuration parameters from DHCPv6 servers.
Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
This Protocol is introduced in UEFI Specification 2.2
**/
#ifndef __EFI_DHCP6_PROTOCOL_H__
#define __EFI_DHCP6_PROTOCOL_H__
FILE_LICENCE ( BSD2_PATENT );
#define EFI_DHCP6_PROTOCOL_GUID \
{ \
0x87c8bad7, 0x595, 0x4053, {0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \
}
#define EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \
{ \
0x9fb9a8a1, 0x2f4a, 0x43a6, {0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4, 0x7a, 0xd5 } \
}
typedef struct _EFI_DHCP6_PROTOCOL EFI_DHCP6_PROTOCOL;
typedef enum {
///
/// The EFI DHCPv6 Protocol instance is configured, and start() needs
/// to be called
///
Dhcp6Init = 0x0,
///
/// A Solicit packet is sent out to discover DHCPv6 server, and the EFI
/// DHCPv6 Protocol instance is collecting Advertise packets.
///
Dhcp6Selecting = 0x1,
///
/// A Request is sent out to the DHCPv6 server, and the EFI DHCPv6
/// Protocol instance is waiting for Reply packet.
///
Dhcp6Requesting = 0x2,
///
/// A Decline packet is sent out to indicate one or more addresses of the
/// configured IA are in use by another node, and the EFI DHCPv6.
/// Protocol instance is waiting for Reply packet.
///
Dhcp6Declining = 0x3,
///
/// A Confirm packet is sent out to confirm the IPv6 addresses of the
/// configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet.
///
Dhcp6Confirming = 0x4,
///
/// A Release packet is sent out to release one or more IPv6 addresses of
/// the configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet.
///
Dhcp6Releasing = 0x5,
///
/// The DHCPv6 S.A.R.R process is completed for the configured IA.
///
Dhcp6Bound = 0x6,
///
/// A Renew packet is sent out to extend lifetime for the IPv6 addresses of
/// the configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet.
///
Dhcp6Renewing = 0x7,
///
/// A Rebind packet is sent out to extend lifetime for the IPv6 addresses of
/// the configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet.
///
Dhcp6Rebinding = 0x8
} EFI_DHCP6_STATE;
typedef enum {
///
/// A Solicit packet is about to be sent. The packet is passed to Dhcp6Callback and
/// can be modified or replaced in Dhcp6Callback.
///
Dhcp6SendSolicit = 0x0,
///
/// An Advertise packet is received and will be passed to Dhcp6Callback.
///
Dhcp6RcvdAdvertise = 0x1,
///
/// It is time for Dhcp6Callback to determine whether select the default Advertise
/// packet by RFC 3315 policy, or overwrite it by specific user policy.
///
Dhcp6SelectAdvertise = 0x2,
///
/// A Request packet is about to be sent. The packet is passed to Dhcp6Callback and
/// can be modified or replaced in Dhcp6Callback.
///
Dhcp6SendRequest = 0x3,
///
/// A Reply packet is received and will be passed to Dhcp6Callback.
///
Dhcp6RcvdReply = 0x4,
///
/// A Reconfigure packet is received and will be passed to Dhcp6Callback.
///
Dhcp6RcvdReconfigure = 0x5,
///
/// A Decline packet is about to be sent. The packet is passed to Dhcp6Callback and
/// can be modified or replaced in Dhcp6Callback.
///
Dhcp6SendDecline = 0x6,
///
/// A Confirm packet is about to be sent. The packet is passed to Dhcp6Callback and
/// can be modified or replaced in Dhcp6Callback.
///
Dhcp6SendConfirm = 0x7,
///
/// A Release packet is about to be sent. The packet is passed to Dhcp6Callback and
/// can be modified or replaced in Dhcp6Callback.
///
Dhcp6SendRelease = 0x8,
///
/// A Renew packet is about to be sent. The packet is passed to Dhcp6Callback and
/// can be modified or replaced in Dhcp6Callback.
///
Dhcp6EnterRenewing = 0x9,
///
/// A Rebind packet is about to be sent. The packet is passed to Dhcp6Callback and
/// can be modified or replaced in Dhcp6Callback.
///
Dhcp6EnterRebinding = 0xa
} EFI_DHCP6_EVENT;
///
/// An IA which carries assigned not temporary address.
///
#define EFI_DHCP6_IA_TYPE_NA 3
///
/// An IA which carries assigned temporary address.
///
#define EFI_DHCP6_IA_TYPE_TA 4
#pragma pack(1)
///
/// EFI_DHCP6_PACKET_OPTION
/// defines the format of the DHCPv6 option, See RFC 3315 for more information.
/// This data structure is used to reference option data that is packed in the DHCPv6 packet.
///
typedef struct {
///
/// The DHCPv6 option code, stored in network order.
///
UINT16 OpCode;
///
/// Length of the DHCPv6 option data, stored in network order.
/// From the first byte to the last byte of the Data field.
///
UINT16 OpLen;
///
/// The data for the DHCPv6 option, stored in network order.
///
UINT8 Data[1];
} EFI_DHCP6_PACKET_OPTION;
///
/// EFI_DHCP6_HEADER
/// defines the format of the DHCPv6 header. See RFC 3315 for more information.
///
typedef struct {
///
/// The DHCPv6 transaction ID.
///
UINT32 MessageType : 8;
///
/// The DHCPv6 message type.
///
UINT32 TransactionId : 24;
} EFI_DHCP6_HEADER;
///
/// EFI_DHCP6_PACKET
/// defines the format of the DHCPv6 packet. See RFC 3315 for more information.
///
typedef struct {
///
/// Size of the EFI_DHCP6_PACKET buffer.
///
UINT32 Size;
///
/// Length of the EFI_DHCP6_PACKET from the first byte of the Header field to the last
/// byte of the Option[] field.
///
UINT32 Length;
struct {
///
/// The DHCPv6 packet header.
///
EFI_DHCP6_HEADER Header;
///
/// Start of the DHCPv6 packed option data.
///
UINT8 Option[1];
} Dhcp6;
} EFI_DHCP6_PACKET;
#pragma pack()
typedef struct {
///
/// Length of DUID in octects.
///
UINT16 Length;
///
/// Array of DUID octects.
///
UINT8 Duid[1];
} EFI_DHCP6_DUID;
typedef struct {
///
/// Initial retransmission timeout.
///
UINT32 Irt;
///
/// Maximum retransmission count for one packet. If Mrc is zero, there's no upper limit
/// for retransmission count.
///
UINT32 Mrc;
///
/// Maximum retransmission timeout for each retry. It's the upper bound of the number of
/// retransmission timeout. If Mrt is zero, there is no upper limit for retransmission
/// timeout.
///
UINT32 Mrt;
///
/// Maximum retransmission duration for one packet. It's the upper bound of the numbers
/// the client may retransmit a message. If Mrd is zero, there's no upper limit for
/// retransmission duration.
///
UINT32 Mrd;
} EFI_DHCP6_RETRANSMISSION;
typedef struct {
///
/// The IPv6 address.
///
EFI_IPv6_ADDRESS IpAddress;
///
/// The preferred lifetime in unit of seconds for the IPv6 address.
///
UINT32 PreferredLifetime;
///
/// The valid lifetime in unit of seconds for the IPv6 address.
///
UINT32 ValidLifetime;
} EFI_DHCP6_IA_ADDRESS;
typedef struct {
UINT16 Type; ///< Type for an IA.
UINT32 IaId; ///< The identifier for an IA.
} EFI_DHCP6_IA_DESCRIPTOR;
typedef struct {
///
/// The descriptor for IA.
///
EFI_DHCP6_IA_DESCRIPTOR Descriptor;
///
/// The state of the configured IA.
///
EFI_DHCP6_STATE State;
///
/// Pointer to the cached latest Reply packet. May be NULL if no packet is cached.
///
EFI_DHCP6_PACKET *ReplyPacket;
///
/// Number of IPv6 addresses of the configured IA.
///
UINT32 IaAddressCount;
///
/// List of the IPv6 addresses of the configured IA. When the state of the configured IA is
/// in Dhcp6Bound, Dhcp6Renewing and Dhcp6Rebinding, the IPv6 addresses are usable.
///
EFI_DHCP6_IA_ADDRESS IaAddress[1];
} EFI_DHCP6_IA;
typedef struct {
///
/// Pointer to the DHCPv6 unique identifier. The caller is responsible for freeing this buffer.
///
EFI_DHCP6_DUID *ClientId;
///
/// Pointer to the configured IA of current instance. The caller can free this buffer after
/// using it.
///
EFI_DHCP6_IA *Ia;
} EFI_DHCP6_MODE_DATA;
/**
EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol instance to
intercept events that occurs in the DHCPv6 S.A.R.R process.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance that is used to configure this
callback function.
@param[in] Context Pointer to the context that is initialized by EFI_DHCP6_PROTOCOL.Configure().
@param[in] CurrentState The current state of the configured IA.
@param[in] Dhcp6Event The event that occurs in the current state, which usually means a state transition.
@param[in] Packet Pointer to the DHCPv6 packet that is about to be sent or has been received.
The EFI DHCPv6 Protocol instance is responsible for freeing the buffer.
@param[out] NewPacket Pointer to the new DHCPv6 packet to overwrite the Packet. NewPacket can not
share the buffer with Packet. If *NewPacket is not NULL, the EFI DHCPv6
Protocol instance is responsible for freeing the buffer.
@retval EFI_SUCCESS Tell the EFI DHCPv6 Protocol instance to continue the DHCPv6 S.A.R.R process.
@retval EFI_ABORTED Tell the EFI DHCPv6 Protocol instance to abort the DHCPv6 S.A.R.R process,
and the state of the configured IA will be transferred to Dhcp6Init.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_CALLBACK)(
IN EFI_DHCP6_PROTOCOL *This,
IN VOID *Context,
IN EFI_DHCP6_STATE CurrentState,
IN EFI_DHCP6_EVENT Dhcp6Event,
IN EFI_DHCP6_PACKET *Packet,
OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL
);
typedef struct {
///
/// The callback function is to intercept various events that occur in the DHCPv6 S.A.R.R
/// process. Set to NULL to ignore all those events.
///
EFI_DHCP6_CALLBACK Dhcp6Callback;
///
/// Pointer to the context that will be passed to Dhcp6Callback.
///
VOID *CallbackContext;
///
/// Number of the DHCPv6 options in the OptionList.
///
UINT32 OptionCount;
///
/// List of the DHCPv6 options to be included in Solicit and Request packet. The buffer
/// can be freed after EFI_DHCP6_PROTOCOL.Configure() returns. Ignored if
/// OptionCount is zero. OptionList should not contain Client Identifier option
/// and any IA option, which will be appended by EFI DHCPv6 Protocol instance
/// automatically.
///
EFI_DHCP6_PACKET_OPTION **OptionList;
///
/// The descriptor for the IA of the EFI DHCPv6 Protocol instance.
///
EFI_DHCP6_IA_DESCRIPTOR IaDescriptor;
///
/// If not NULL, the event will be signaled when any IPv6 address information of the
/// configured IA is updated, including IPv6 address, preferred lifetime and valid
/// lifetime, or the DHCPv6 S.A.R.R process fails. Otherwise, Start(),
/// renewrebind(), decline(), release() and stop() will be blocking
/// operations, and they will wait for the exchange process completion or failure.
///
EFI_EVENT IaInfoEvent;
///
/// If TRUE, the EFI DHCPv6 Protocol instance is willing to accept Reconfigure packet.
/// Otherwise, it will ignore it. Reconfigure Accept option can not be specified through
/// OptionList parameter.
///
BOOLEAN ReconfigureAccept;
///
/// If TRUE, the EFI DHCPv6 Protocol instance will send Solicit packet with Rapid
/// Commit option. Otherwise, Rapid Commit option will not be included in Solicit
/// packet. Rapid Commit option can not be specified through OptionList parameter.
///
BOOLEAN RapidCommit;
///
/// Parameter to control Solicit packet retransmission behavior. The
/// buffer can be freed after EFI_DHCP6_PROTOCOL.Configure() returns.
///
EFI_DHCP6_RETRANSMISSION *SolicitRetransmission;
} EFI_DHCP6_CONFIG_DATA;
/**
EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
instance to intercept events that occurs in the DHCPv6 Information Request exchange process.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance that is used to configure this
callback function.
@param[in] Context Pointer to the context that is initialized in the EFI_DHCP6_PROTOCOL.InfoRequest().
@param[in] Packet Pointer to Reply packet that has been received. The EFI DHCPv6 Protocol instance is
responsible for freeing the buffer.
@retval EFI_SUCCESS Tell the EFI DHCPv6 Protocol instance to finish Information Request exchange process.
@retval EFI_NOT_READY Tell the EFI DHCPv6 Protocol instance to continue Information Request exchange process.
@retval EFI_ABORTED Tell the EFI DHCPv6 Protocol instance to abort the Information Request exchange process.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_INFO_CALLBACK)(
IN EFI_DHCP6_PROTOCOL *This,
IN VOID *Context,
IN EFI_DHCP6_PACKET *Packet
);
/**
Retrieve the current operating mode data and configuration data for the EFI DHCPv6 Protocol instance.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance.
@param[out] Dhcp6ModeData Pointer to the DHCPv6 mode data structure. The caller is responsible for freeing this
structure and each reference buffer.
@param[out] Dhcp6ConfigData Pointer to the DHCPv6 configuration data structure. The caller is responsible for
freeing this structure and each reference buffer.
@retval EFI_SUCCESS The mode data was returned.
@retval EFI_ACCESS_DENIED The EFI DHCPv6 Protocol instance has not been configured when Dhcp6ConfigData is not NULL.
@retval EFI_INVALID_PARAMETER One or more following conditions are TRUE:
- This is NULL.
- Both Dhcp6ConfigData and Dhcp6ModeData are NULL.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_GET_MODE_DATA)(
IN EFI_DHCP6_PROTOCOL *This,
OUT EFI_DHCP6_MODE_DATA *Dhcp6ModeData OPTIONAL,
OUT EFI_DHCP6_CONFIG_DATA *Dhcp6ConfigData OPTIONAL
);
/**
Initialize or clean up the configuration data for the EFI DHCPv6 Protocol instance.
The Configure() function is used to initialize or clean up the configuration data of the EFI
DHCPv6 Protocol instance.
- When Dhcp6CfgData is not NULL and Configure() is called successfully, the
configuration data will be initialized in the EFI DHCPv6 Protocol instance and the state of the
configured IA will be transferred into Dhcp6Init.
- When Dhcp6CfgData is NULL and Configure() is called successfully, the configuration
data will be cleaned up and no IA will be associated with the EFI DHCPv6 Protocol instance.
To update the configuration data for an EFI DCHPv6 Protocol instance, the original data must be
cleaned up before setting the new configuration data.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance.
@param[in] Dhcp6CfgData Pointer to the DHCPv6 configuration data structure.
@retval EFI_SUCCESS The mode data was returned.
@retval EFI_INVALID_PARAMETER One or more following conditions are TRUE
- This is NULL.
- OptionCount > 0 and OptionList is NULL.
- OptionList is not NULL, and Client Id option, Reconfigure Accept option,
Rapid Commit option or any IA option is specified in the OptionList.
- IaDescriptor.Type is neither EFI_DHCP6_IA_TYPE_NA nor EFI_DHCP6_IA_TYPE_NA.
- IaDescriptor is not unique.
- Both IaInfoEvent and SolicitRetransimssion are NULL.
- SolicitRetransmission is not NULL, and both SolicitRetransimssion->Mrc and
SolicitRetransmission->Mrd are zero.
@retval EFI_ACCESS_DENIED The EFI DHCPv6 Protocol instance has been already configured
when Dhcp6CfgData is not NULL.
The EFI DHCPv6 Protocol instance has already started the
DHCPv6 S.A.R.R when Dhcp6CfgData is NULL.
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_CONFIGURE)(
IN EFI_DHCP6_PROTOCOL *This,
IN EFI_DHCP6_CONFIG_DATA *Dhcp6CfgData OPTIONAL
);
/**
Start the DHCPv6 S.A.R.R process.
The Start() function starts the DHCPv6 S.A.R.R process. This function can be called only when
the state of the configured IA is in the Dhcp6Init state. If the DHCPv6 S.A.R.R process completes
successfully, the state of the configured IA will be transferred through Dhcp6Selecting and
Dhcp6Requesting to Dhcp6Bound state. The update of the IPv6 addresses will be notified through
EFI_DHCP6_CONFIG_DATA.IaInfoEvent. At the time when each event occurs in this process, the
callback function set by EFI_DHCP6_PROTOCOL.Configure() will be called and the user can take
this opportunity to control the process. If EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, the
Start() function call is a blocking operation. It will return after the DHCPv6 S.A.R.R process
completes or aborted by users. If the process is aborted by system or network error, the state of
the configured IA will be transferred to Dhcp6Init. The Start() function can be called again to
restart the process.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance.
@retval EFI_SUCCESS The DHCPv6 S.A.R.R process is completed and at least one IPv6
address has been bound to the configured IA when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.
The DHCPv6 S.A.R.R process is started when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.
@retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
@retval EFI_ALREADY_STARTED The DHCPv6 S.A.R.R process has already started.
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
@retval EFI_NO_RESPONSE The DHCPv6 S.A.R.R process failed because of no response.
@retval EFI_NO_MAPPING No IPv6 address has been bound to the configured IA after the
DHCPv6 S.A.R.R process.
@retval EFI_ABORTED The DHCPv6 S.A.R.R process aborted by user.
@retval EFI_NO_MEDIA There was a media error.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_START)(
IN EFI_DHCP6_PROTOCOL *This
);
/**
Request configuration information without the assignment of any IA addresses of the client.
The InfoRequest() function is used to request configuration information without the assignment
of any IPv6 address of the client. Client sends out Information Request packet to obtain
the required configuration information, and DHCPv6 server responds with Reply packet containing
the information for the client. The received Reply packet will be passed to the user by
ReplyCallback function. If user returns EFI_NOT_READY from ReplyCallback, the EFI DHCPv6
Protocol instance will continue to receive other Reply packets unless timeout according to
the Retransmission parameter. Otherwise, the Information Request exchange process will be
finished successfully if user returns EFI_SUCCESS from ReplyCallback.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance.
@param[in] SendClientId If TRUE, the EFI DHCPv6 Protocol instance will build Client
Identifier option and include it into Information Request
packet. If FALSE, Client Identifier option will not be included.
Client Identifier option can not be specified through OptionList
parameter.
@param[in] OptionRequest Pointer to the Option Request option in the Information Request
packet. Option Request option can not be specified through
OptionList parameter.
@param[in] OptionCount Number of options in OptionList.
@param[in] OptionList List of other DHCPv6 options. These options will be appended
to the Option Request option. The caller is responsible for
freeing this buffer. Type is defined in EFI_DHCP6_PROTOCOL.GetModeData().
@param[in] Retransmission Parameter to control Information Request packet retransmission
behavior. The buffer can be freed after EFI_DHCP6_PROTOCOL.InfoRequest()
returns.
@param[in] TimeoutEvent If not NULL, this event is signaled when the information request
exchange aborted because of no response. If NULL, the function
call is a blocking operation; and it will return after the
information-request exchange process finish or aborted by users.
@param[in] ReplyCallback The callback function is to intercept various events that occur
in the Information Request exchange process. It should not be
set to NULL.
@param[in] CallbackContext Pointer to the context that will be passed to ReplyCallback.
@retval EFI_SUCCESS The DHCPv6 S.A.R.R process is completed and at least one IPv6
@retval EFI_SUCCESS The DHCPv6 information request exchange process completed
when TimeoutEvent is NULL. Information Request packet has been
sent to DHCPv6 server when TimeoutEvent is not NULL.
@retval EFI_INVALID_PARAMETER One or more following conditions are TRUE:
- This is NULL.
- OptionRequest is NULL or OptionRequest->OpCode is invalid.
- OptionCount > 0 and OptionList is NULL.
- OptionList is not NULL, and Client Identify option or
Option Request option is specified in the OptionList.
- Retransimssion is NULL.
- Both Retransimssion->Mrc and Retransmission->Mrd are zero.
- ReplyCallback is NULL.
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
@retval EFI_NO_RESPONSE The DHCPv6 information request exchange process failed
because of no response, or not all requested-options are
responded by DHCPv6 servers when Timeout happened.
@retval EFI_ABORTED The DHCPv6 information request exchange process aborted by user.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_INFO_REQUEST)(
IN EFI_DHCP6_PROTOCOL *This,
IN BOOLEAN SendClientId,
IN EFI_DHCP6_PACKET_OPTION *OptionRequest,
IN UINT32 OptionCount,
IN EFI_DHCP6_PACKET_OPTION *OptionList[] OPTIONAL,
IN EFI_DHCP6_RETRANSMISSION *Retransmission,
IN EFI_EVENT TimeoutEvent OPTIONAL,
IN EFI_DHCP6_INFO_CALLBACK ReplyCallback,
IN VOID *CallbackContext OPTIONAL
);
/**
Manually extend the valid and preferred lifetimes for the IPv6 addresses of the configured
IA and update other configuration parameters by sending Renew or Rebind packet.
The RenewRebind() function is used to manually extend the valid and preferred lifetimes for the
IPv6 addresses of the configured IA and update other configuration parameters by sending Renew or
Rebind packet.
- When RebindRequest is FALSE and the state of the configured IA is Dhcp6Bound, it
will send Renew packet to the previously DHCPv6 server and transfer the state of the configured
IA to Dhcp6Renewing. If valid Reply packet received, the state transfers to Dhcp6Bound
and the valid and preferred timer restarts. If fails, the state transfers to Dhcp6Bound but the
timer continues.
- When RebindRequest is TRUE and the state of the configured IA is Dhcp6Bound, it will
send Rebind packet. If valid Reply packet received, the state transfers to Dhcp6Bound and the
valid and preferred timer restarts. If fails, the state transfers to Dhcp6Init and the IA can't
be used.
@param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.
@param[in] RebindRequest If TRUE, it will send Rebind packet and enter the Dhcp6Rebinding state.
Otherwise, it will send Renew packet and enter the Dhcp6Renewing state.
@retval EFI_SUCCESS The DHCPv6 renew/rebind exchange process has completed and at
least one IPv6 address of the configured IA has been bound again
when EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.
The EFI DHCPv6 Protocol instance has sent Renew or Rebind packet
when EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.
@retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured, or the state
of the configured IA is not in Dhcp6Bound.
@retval EFI_ALREADY_STARTED The state of the configured IA has already entered Dhcp6Renewing
when RebindRequest is FALSE.
The state of the configured IA has already entered Dhcp6Rebinding
when RebindRequest is TRUE.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_DEVICE_ERROR An unexpected system or system error occurred.
@retval EFI_NO_RESPONSE The DHCPv6 renew/rebind exchange process failed because of no response.
@retval EFI_NO_MAPPING No IPv6 address has been bound to the configured IA after the DHCPv6
renew/rebind exchange process.
@retval EFI_ABORTED The DHCPv6 renew/rebind exchange process aborted by user.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_RENEW_REBIND)(
IN EFI_DHCP6_PROTOCOL *This,
IN BOOLEAN RebindRequest
);
/**
Inform that one or more IPv6 addresses assigned by a server are already in use by
another node.
The Decline() function is used to manually decline the assignment of IPv6 addresses, which
have been already used by another node. If all IPv6 addresses of the configured IA are declined
through this function, the state of the IA will switch through Dhcp6Declining to Dhcp6Init,
otherwise, the state of the IA will restore to Dhcp6Bound after the declining process. The
Decline() can only be called when the IA is in Dhcp6Bound state. If the
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, this function is a blocking operation. It
will return after the declining process finishes, or aborted by user.
@param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.
@param[in] AddressCount Number of declining IPv6 addresses.
@param[in] Addresses Pointer to the buffer stored all the declining IPv6 addresses.
@retval EFI_SUCCESS The DHCPv6 decline exchange process has completed when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.
The EFI DHCPv6 Protocol instance has sent Decline packet when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.
@retval EFI_INVALID_PARAMETER One or more following conditions are TRUE
- This is NULL.
- AddressCount is zero or Addresses is NULL.
@retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with the configured IA
for this instance.
@retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured, or the
state of the configured IA is not in Dhcp6Bound.
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
@retval EFI_ABORTED The DHCPv6 decline exchange process aborted by user.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_DECLINE)(
IN EFI_DHCP6_PROTOCOL *This,
IN UINT32 AddressCount,
IN EFI_IPv6_ADDRESS *Addresses
);
/**
Release one or more IPv6 addresses associated with the configured IA for current instance.
The Release() function is used to manually release the one or more IPv6 address. If AddressCount
is zero, it will release all IPv6 addresses of the configured IA. If all IPv6 addresses of the IA
are released through this function, the state of the IA will switch through Dhcp6Releasing to
Dhcp6Init, otherwise, the state of the IA will restore to Dhcp6Bound after the releasing process.
The Release() can only be called when the IA is in Dhcp6Bound state. If the
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, the function is a blocking operation. It will return
after the releasing process finishes, or aborted by user.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance.
@param[in] AddressCount Number of releasing IPv6 addresses.
@param[in] Addresses Pointer to the buffer stored all the releasing IPv6 addresses.
Ignored if AddressCount is zero.
@retval EFI_SUCCESS The DHCPv6 release exchange process has completed when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.
The EFI DHCPv6 Protocol instance has sent Release packet when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.
@retval EFI_INVALID_PARAMETER One or more following conditions are TRUE
- This is NULL.
- AddressCount is not zero or Addresses is NULL.
@retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with the configured
IA for this instance.
@retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured, or the
state of the configured IA is not in Dhcp6Bound.
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
@retval EFI_ABORTED The DHCPv6 release exchange process aborted by user.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_RELEASE)(
IN EFI_DHCP6_PROTOCOL *This,
IN UINT32 AddressCount,
IN EFI_IPv6_ADDRESS *Addresses
);
/**
Stop the DHCPv6 S.A.R.R process.
The Stop() function is used to stop the DHCPv6 S.A.R.R process. If this function is called
successfully, all the IPv6 addresses of the configured IA will be released and the state of
the configured IA will be transferred to Dhcp6Init.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance.
@retval EFI_SUCCESS The DHCPv6 S.A.R.R process has been stopped when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.
The EFI DHCPv6 Protocol instance has sent Release packet if
need release or has been stopped if needn't, when
EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.
@retval EFI_INVALID_PARAMETER This is NULL.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_STOP)(
IN EFI_DHCP6_PROTOCOL *This
);
/**
Parse the option data in the DHCPv6 packet.
The Parse() function is used to retrieve the option list in the DHCPv6 packet.
@param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance.
@param[in] Packet Pointer to packet to be parsed.
@param[in] OptionCount On input, the number of entries in the PacketOptionList.
On output, the number of DHCPv6 options in the Packet.
@param[in] PacketOptionList List of pointers to the DHCPv6 options in the Packet.
The OpCode and OpLen in EFI_DHCP6_PACKET_OPTION are
both stored in network byte order.
@retval EFI_SUCCESS The packet was successfully parsed.
@retval EFI_INVALID_PARAMETER One or more following conditions are TRUE
- This is NULL.
- Packet is NULL.
- Packet is not a well-formed DHCPv6 packet.
- OptionCount is NULL.
- *OptionCount is not zero and PacketOptionList is NULL.
@retval EFI_BUFFER_TOO_SMALL *OptionCount is smaller than the number of options that were
found in the Packet.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DHCP6_PARSE)(
IN EFI_DHCP6_PROTOCOL *This,
IN EFI_DHCP6_PACKET *Packet,
IN OUT UINT32 *OptionCount,
OUT EFI_DHCP6_PACKET_OPTION *PacketOptionList[] OPTIONAL
);
///
/// The EFI DHCPv6 Protocol is used to get IPv6 addresses and other configuration parameters
/// from DHCPv6 servers.
///
struct _EFI_DHCP6_PROTOCOL {
EFI_DHCP6_GET_MODE_DATA GetModeData;
EFI_DHCP6_CONFIGURE Configure;
EFI_DHCP6_START Start;
EFI_DHCP6_INFO_REQUEST InfoRequest;
EFI_DHCP6_RENEW_REBIND RenewRebind;
EFI_DHCP6_DECLINE Decline;
EFI_DHCP6_RELEASE Release;
EFI_DHCP6_STOP Stop;
EFI_DHCP6_PARSE Parse;
};
extern EFI_GUID gEfiDhcp6ProtocolGuid;
extern EFI_GUID gEfiDhcp6ServiceBindingProtocolGuid;
#endif

View File

@ -0,0 +1,538 @@
/** @file
This file defines the EFI Domain Name Service Binding Protocol interface. It is split
into the following two main sections:
DNSv4 Service Binding Protocol (DNSv4SB)
DNSv4 Protocol (DNSv4)
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
This Protocol is introduced in UEFI Specification 2.5
**/
#ifndef __EFI_DNS4_PROTOCOL_H__
#define __EFI_DNS4_PROTOCOL_H__
FILE_LICENCE ( BSD2_PATENT );
#define EFI_DNS4_SERVICE_BINDING_PROTOCOL_GUID \
{ \
0xb625b186, 0xe063, 0x44f7, {0x89, 0x5, 0x6a, 0x74, 0xdc, 0x6f, 0x52, 0xb4 } \
}
#define EFI_DNS4_PROTOCOL_GUID \
{ \
0xae3d28cc, 0xe05b, 0x4fa1, {0xa0, 0x11, 0x7e, 0xb5, 0x5a, 0x3f, 0x14, 0x1 } \
}
typedef struct _EFI_DNS4_PROTOCOL EFI_DNS4_PROTOCOL;
///
/// EFI_DNS4_CONFIG_DATA
///
typedef struct {
///
/// Count of the DNS servers. When used with GetModeData(),
/// this field is the count of originally configured servers when
/// Configure() was called for this instance. When used with
/// Configure() this is the count of caller-supplied servers. If the
/// DnsServerListCount is zero, the DNS server configuration
/// will be retrieved from DHCP server automatically.
///
UINTN DnsServerListCount;
///
/// Pointer to DNS server list containing DnsServerListCount entries or NULL
/// if DnsServerListCountis 0. For Configure(), this will be NULL when there are
/// no caller supplied server addresses, and, the DNS instance will retrieve
/// DNS server from DHCP Server. The provided DNS server list is
/// recommended to be filled up in the sequence of preference. When
/// used with GetModeData(), the buffer containing the list will
/// be allocated by the driver implementing this protocol and must be
/// freed by the caller. When used with Configure(), the buffer
/// containing the list will be allocated and released by the caller.
///
EFI_IPv4_ADDRESS *DnsServerList;
///
/// Set to TRUE to use the default IP address/subnet mask and default routing table.
///
BOOLEAN UseDefaultSetting;
///
/// If TRUE, enable DNS cache function for this DNS instance. If FALSE, all DNS
/// query will not lookup local DNS cache.
///
BOOLEAN EnableDnsCache;
///
/// Use the protocol number defined in "Links to UEFI-Related
/// Documents"(http://uefi.org/uefi) under the heading "IANA
/// Protocol Numbers". Only TCP or UDP are supported, and other
/// protocol values are invalid. An implementation can choose to
/// support only UDP, or both TCP and UDP.
///
UINT8 Protocol;
///
/// If UseDefaultSetting is FALSE indicates the station address to use.
///
EFI_IPv4_ADDRESS StationIp;
///
/// If UseDefaultSetting is FALSE indicates the subnet mask to use.
///
EFI_IPv4_ADDRESS SubnetMask;
///
/// Local port number. Set to zero to use the automatically assigned port number.
///
UINT16 LocalPort;
///
/// Retry number if no response received after RetryInterval.
///
UINT32 RetryCount;
///
/// Minimum interval of retry is 2 second. If the retry interval is less than 2
/// seconds, then use the 2 seconds.
///
UINT32 RetryInterval;
} EFI_DNS4_CONFIG_DATA;
///
/// EFI_DNS4_CACHE_ENTRY
///
typedef struct {
///
/// Host name.
///
CHAR16 *HostName;
///
/// IP address of this host.
///
EFI_IPv4_ADDRESS *IpAddress;
///
/// Time in second unit that this entry will remain in DNS cache. A value of zero
/// means that this entry is permanent. A nonzero value will override the existing
/// one if this entry to be added is dynamic entry. Implementations may set its
/// default timeout value for the dynamically created DNS cache entry after one DNS
/// resolve succeeds.
///
UINT32 Timeout;
} EFI_DNS4_CACHE_ENTRY;
///
/// EFI_DNS4_MODE_DATA
///
typedef struct {
///
/// The configuration data of this instance.
///
EFI_DNS4_CONFIG_DATA DnsConfigData;
///
/// Number of configured DNS server. Each DNS instance has its own DNS server
/// configuration.
///
UINT32 DnsServerCount;
///
/// Pointer to common list of addresses of all configured DNS server
/// used by EFI_DNS4_PROTOCOL instances. List will include
/// DNS servers configured by this or any other EFI_DNS4_PROTOCOL instance.
/// The storage for this list is allocated by the driver publishing this
/// protocol, and must be freed by the caller.
///
EFI_IPv4_ADDRESS *DnsServerList;
///
/// Number of DNS Cache entries. The DNS Cache is shared among all DNS instances.
///
UINT32 DnsCacheCount;
///
/// Pointer to a buffer containing DnsCacheCount DNS Cache
/// entry structures. The storage for this list is allocated by the driver
/// publishing this protocol and must be freed by caller.
///
EFI_DNS4_CACHE_ENTRY *DnsCacheList;
} EFI_DNS4_MODE_DATA;
///
/// DNS_HOST_TO_ADDR_DATA
///
typedef struct {
///
/// Number of the returned IP addresses.
///
UINT32 IpCount;
///
/// Pointer to the all the returned IP addresses.
///
EFI_IPv4_ADDRESS *IpList;
} DNS_HOST_TO_ADDR_DATA;
///
/// DNS_ADDR_TO_HOST_DATA
///
typedef struct {
///
/// Pointer to the primary name for this host address. It's the caller's
/// responsibility to free the response memory.
///
CHAR16 *HostName;
} DNS_ADDR_TO_HOST_DATA;
///
/// DNS_RESOURCE_RECORD
///
typedef struct {
///
/// The Owner name.
///
CHAR8 *QName;
///
/// The Type Code of this RR.
///
UINT16 QType;
///
/// The CLASS code of this RR.
///
UINT16 QClass;
///
/// 32 bit integer which specify the time interval that the resource record may be
/// cached before the source of the information should again be consulted. Zero means
/// this RR can not be cached.
///
UINT32 TTL;
///
/// 16 big integer which specify the length of RData.
///
UINT16 DataLength;
///
/// A string of octets that describe the resource, the format of this information
/// varies according to QType and QClass difference.
///
CHAR8 *RData;
} DNS_RESOURCE_RECORD;
///
/// DNS_GENERAL_LOOKUP_DATA
///
typedef struct {
///
/// Number of returned matching RRs.
///
UINTN RRCount;
///
/// Pointer to the all the returned matching RRs. It's caller responsibility to free
/// the allocated memory to hold the returned RRs.
///
DNS_RESOURCE_RECORD *RRList;
} DNS_GENERAL_LOOKUP_DATA;
///
/// EFI_DNS4_COMPLETION_TOKEN
///
typedef struct {
///
/// This Event will be signaled after the Status field is updated by the EFI DNS
/// protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL.
///
EFI_EVENT Event;
///
/// Will be set to one of the following values:
/// EFI_SUCCESS: The host name to address translation completed successfully.
/// EFI_NOT_FOUND: No matching Resource Record (RR) is found.
/// EFI_TIMEOUT: No DNS server reachable, or RetryCount was exhausted without
/// response from all specified DNS servers.
/// EFI_DEVICE_ERROR: An unexpected system or network error occurred.
/// EFI_NO_MEDIA: There was a media error.
///
EFI_STATUS Status;
///
/// Retry number if no response received after RetryInterval. If zero, use the
/// parameter configured through Dns.Configure() interface.
///
UINT32 RetryCount;
///
/// Minimum interval of retry is 2 second. If the retry interval is less than 2
/// seconds, then use the 2 seconds. If zero, use the parameter configured through
/// Dns.Configure() interface.
UINT32 RetryInterval;
///
/// DNSv4 completion token data
///
union {
///
/// When the Token is used for host name to address translation, H2AData is a pointer
/// to the DNS_HOST_TO_ADDR_DATA.
///
DNS_HOST_TO_ADDR_DATA *H2AData;
///
/// When the Token is used for host address to host name translation, A2HData is a
/// pointer to the DNS_ADDR_TO_HOST_DATA.
///
DNS_ADDR_TO_HOST_DATA *A2HData;
///
/// When the Token is used for a general lookup function, GLookupDATA is a pointer to
/// the DNS_GENERAL_LOOKUP_DATA.
///
DNS_GENERAL_LOOKUP_DATA *GLookupData;
} RspData;
} EFI_DNS4_COMPLETION_TOKEN;
/**
Retrieve mode data of this DNS instance.
This function is used to retrieve DNS mode data for this DNS instance.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@param[out] DnsModeData Point to the mode data.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data
is available because this instance has not been
configured.
@retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_GET_MODE_DATA)(
IN EFI_DNS4_PROTOCOL *This,
OUT EFI_DNS4_MODE_DATA *DnsModeData
);
/**
Configure this DNS instance.
This function is used to configure DNS mode data for this DNS instance.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@param[in] DnsConfigData Point to the Configuration data.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_UNSUPPORTED The designated protocol is not supported.
@retval EFI_INVALID_PARAMETER This is NULL.
The StationIp address provided in DnsConfigData is not a
valid unicast.
DnsServerList is NULL while DnsServerListCount
is not ZERO.
DnsServerListCount is ZERO while DnsServerList
is not NULL
@retval EFI_OUT_OF_RESOURCES The DNS instance data or required space could not be
allocated.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The
EFI DNSv4 Protocol instance is not configured.
@retval EFI_ALREADY_STARTED Second call to Configure() with DnsConfigData. To
reconfigure the instance the caller must call Configure()
with NULL first to return driver to unconfigured state.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_CONFIGURE)(
IN EFI_DNS4_PROTOCOL *This,
IN EFI_DNS4_CONFIG_DATA *DnsConfigData
);
/**
Host name to host address translation.
The HostNameToIp () function is used to translate the host name to host IP address. A
type A query is used to get the one or more IP addresses for this host.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@param[in] HostName Host name.
@param[in] Token Point to the completion token to translate host name
to host address.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token.Event is NULL.
HostName is NULL. HostName string is unsupported format.
@retval EFI_NO_MAPPING There's no source address is available for use.
@retval EFI_NOT_STARTED This instance has not been started.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_HOST_NAME_TO_IP)(
IN EFI_DNS4_PROTOCOL *This,
IN CHAR16 *HostName,
IN EFI_DNS4_COMPLETION_TOKEN *Token
);
/**
IPv4 address to host name translation also known as Reverse DNS lookup.
The IpToHostName() function is used to translate the host address to host name. A type PTR
query is used to get the primary name of the host. Support of this function is optional.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@param[in] IpAddress Ip Address.
@param[in] Token Point to the completion token to translate host
address to host name.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_UNSUPPORTED This function is not supported.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token.Event is NULL.
IpAddress is not valid IP address .
@retval EFI_NO_MAPPING There's no source address is available for use.
@retval EFI_ALREADY_STARTED This Token is being used in another DNS session.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_IP_TO_HOST_NAME)(
IN EFI_DNS4_PROTOCOL *This,
IN EFI_IPv4_ADDRESS IpAddress,
IN EFI_DNS4_COMPLETION_TOKEN *Token
);
/**
Retrieve arbitrary information from the DNS server.
This GeneralLookup() function retrieves arbitrary information from the DNS. The caller
supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. All
RR content (e.g., TTL) was returned. The caller need parse the returned RR to get
required information. The function is optional.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@param[in] QName Pointer to Query Name.
@param[in] QType Query Type.
@param[in] QClass Query Name.
@param[in] Token Point to the completion token to retrieve arbitrary
information.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_UNSUPPORTED This function is not supported. Or the requested
QType is not supported
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token.Event is NULL.
QName is NULL.
@retval EFI_NO_MAPPING There's no source address is available for use.
@retval EFI_ALREADY_STARTED This Token is being used in another DNS session.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_GENERAL_LOOKUP)(
IN EFI_DNS4_PROTOCOL *This,
IN CHAR8 *QName,
IN UINT16 QType,
IN UINT16 QClass,
IN EFI_DNS4_COMPLETION_TOKEN *Token
);
/**
This function is to update the DNS Cache.
The UpdateDnsCache() function is used to add/delete/modify DNS cache entry. DNS cache
can be normally dynamically updated after the DNS resolve succeeds. This function
provided capability to manually add/delete/modify the DNS cache.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@param[in] DeleteFlag If FALSE, this function is to add one entry to the
DNS Cahce. If TRUE, this function will delete
matching DNS Cache entry.
@param[in] Override If TRUE, the maching DNS cache entry will be
overwritten with the supplied parameter. If FALSE,
EFI_ACCESS_DENIED will be returned if the entry to
be added is already existed.
@param[in] DnsCacheEntry Pointer to DNS Cache entry.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
DnsCacheEntry.HostName is NULL.
DnsCacheEntry.IpAddress is NULL.
DnsCacheEntry.Timeout is zero.
@retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is
not TRUE.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_UPDATE_DNS_CACHE)(
IN EFI_DNS4_PROTOCOL *This,
IN BOOLEAN DeleteFlag,
IN BOOLEAN Override,
IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry
);
/**
Polls for incoming data packets and processes outgoing data packets.
The Poll() function can be used by network drivers and applications to increase the
rate that data packets are moved between the communications device and the transmit
and receive queues.
In some systems, the periodic timer event in the managed network driver may not poll
the underlying communications device fast enough to transmit and/or receive all data
packets without missing incoming packets or dropping outgoing packets. Drivers and
applications that are experiencing packet loss should try calling the Poll()
function more often.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@retval EFI_SUCCESS Incoming or outgoing data was processed.
@retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive
queue. Consider increasing the polling rate.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_POLL)(
IN EFI_DNS4_PROTOCOL *This
);
/**
Abort an asynchronous DNS operation, including translation between IP and Host, and
general look up behavior.
The Cancel() function is used to abort a pending resolution request. After calling
this function, Token.Status will be set to EFI_ABORTED and then Token.Event will be
signaled. If the token is not in one of the queues, which usually means that the
asynchronous operation has completed, this function will not signal the token and
EFI_NOT_FOUND is returned.
@param[in] This Pointer to EFI_DNS4_PROTOCOL instance.
@param[in] Token Pointer to a token that has been issued by
EFI_DNS4_PROTOCOL.HostNameToIp (),
EFI_DNS4_PROTOCOL.IpToHostName() or
EFI_DNS4_PROTOCOL.GeneralLookup().
If NULL, all pending tokens are aborted.
@retval EFI_SUCCESS Incoming or outgoing data was processed.
@retval EFI_NOT_STARTED This EFI DNS4 Protocol instance has not been started.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS
operation was not found in the transmit queue. It
was either completed or was not issued by
HostNameToIp(), IpToHostName() or GeneralLookup().
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS4_CANCEL)(
IN EFI_DNS4_PROTOCOL *This,
IN EFI_DNS4_COMPLETION_TOKEN *Token
);
///
/// The EFI_DNS4_Protocol provides the function to get the host name and address
/// mapping, also provides pass through interface to retrieve arbitrary information
/// from DNS.
///
struct _EFI_DNS4_PROTOCOL {
EFI_DNS4_GET_MODE_DATA GetModeData;
EFI_DNS4_CONFIGURE Configure;
EFI_DNS4_HOST_NAME_TO_IP HostNameToIp;
EFI_DNS4_IP_TO_HOST_NAME IpToHostName;
EFI_DNS4_GENERAL_LOOKUP GeneralLookUp;
EFI_DNS4_UPDATE_DNS_CACHE UpdateDnsCache;
EFI_DNS4_POLL Poll;
EFI_DNS4_CANCEL Cancel;
};
extern EFI_GUID gEfiDns4ServiceBindingProtocolGuid;
extern EFI_GUID gEfiDns4ProtocolGuid;
#endif

View File

@ -0,0 +1,535 @@
/** @file
This file defines the EFI DNSv6 (Domain Name Service version 6) Protocol. It is split
into the following two main sections:
DNSv6 Service Binding Protocol (DNSv6SB)
DNSv6 Protocol (DNSv6)
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
This Protocol is introduced in UEFI Specification 2.5
**/
#ifndef __EFI_DNS6_PROTOCOL_H__
#define __EFI_DNS6_PROTOCOL_H__
FILE_LICENCE ( BSD2_PATENT );
#define EFI_DNS6_SERVICE_BINDING_PROTOCOL_GUID \
{ \
0x7f1647c8, 0xb76e, 0x44b2, {0xa5, 0x65, 0xf7, 0xf, 0xf1, 0x9c, 0xd1, 0x9e } \
}
#define EFI_DNS6_PROTOCOL_GUID \
{ \
0xca37bc1f, 0xa327, 0x4ae9, {0x82, 0x8a, 0x8c, 0x40, 0xd8, 0x50, 0x6a, 0x17 } \
}
typedef struct _EFI_DNS6_PROTOCOL EFI_DNS6_PROTOCOL;
///
/// EFI_DNS6_CONFIG_DATA
///
typedef struct {
///
/// If TRUE, enable DNS cache function for this DNS instance. If FALSE, all DNS query
/// will not lookup local DNS cache.
///
BOOLEAN EnableDnsCache;
///
/// Use the protocol number defined in
/// http://www.iana.org/assignments/protocol-numbers. Beside TCP/UDP, Other protocol
/// is invalid value. An implementation can choose to support UDP, or both TCP and UDP.
///
UINT8 Protocol;
///
/// The local IP address to use. Set to zero to let the underlying IPv6
/// driver choose a source address. If not zero it must be one of the
/// configured IP addresses in the underlying IPv6 driver.
///
EFI_IPv6_ADDRESS StationIp;
///
/// Local port number. Set to zero to use the automatically assigned port number.
///
UINT16 LocalPort;
///
/// Count of the DNS servers. When used with GetModeData(),
/// this field is the count of originally configured servers when
/// Configure() was called for this instance. When used with
/// Configure() this is the count of caller-supplied servers. If the
/// DnsServerListCount is zero, the DNS server configuration
/// will be retrieved from DHCP server automatically.
///
UINT32 DnsServerCount;
///
/// Pointer to DNS server list containing DnsServerListCount
/// entries or NULL if DnsServerListCount is 0. For Configure(),
/// this will be NULL when there are no caller supplied server addresses
/// and the DNS instance will retrieve DNS server from DHCP Server.
/// The provided DNS server list is recommended to be filled up in the sequence
/// of preference. When used with GetModeData(), the buffer containing the list
/// will be allocated by the driver implementing this protocol and must be
/// freed by the caller. When used with Configure(), the buffer
/// containing the list will be allocated and released by the caller.
///
EFI_IPv6_ADDRESS *DnsServerList;
///
/// Retry number if no response received after RetryInterval.
///
UINT32 RetryCount;
///
/// Minimum interval of retry is 2 second. If the retry interval is less than 2
/// seconds, then use the 2 seconds.
UINT32 RetryInterval;
} EFI_DNS6_CONFIG_DATA;
///
/// EFI_DNS6_CACHE_ENTRY
///
typedef struct {
///
/// Host name. This should be interpreted as Unicode characters.
///
CHAR16 *HostName;
///
/// IP address of this host.
///
EFI_IPv6_ADDRESS *IpAddress;
///
/// Time in second unit that this entry will remain in DNS cache. A value of zero means
/// that this entry is permanent. A nonzero value will override the existing one if
/// this entry to be added is dynamic entry. Implementations may set its default
/// timeout value for the dynamically created DNS cache entry after one DNS resolve
/// succeeds.
UINT32 Timeout;
} EFI_DNS6_CACHE_ENTRY;
///
/// EFI_DNS6_MODE_DATA
///
typedef struct {
///
/// The configuration data of this instance.
///
EFI_DNS6_CONFIG_DATA DnsConfigData;
///
/// Number of configured DNS6 servers.
///
UINT32 DnsServerCount;
///
/// Pointer to common list of addresses of all configured DNS server used by EFI_DNS6_PROTOCOL
/// instances. List will include DNS servers configured by this or any other EFI_DNS6_PROTOCOL
/// instance. The storage for this list is allocated by the driver publishing this protocol,
/// and must be freed by the caller.
///
EFI_IPv6_ADDRESS *DnsServerList;
///
/// Number of DNS Cache entries. The DNS Cache is shared among all DNS instances.
///
UINT32 DnsCacheCount;
///
/// Pointer to a buffer containing DnsCacheCount DNS Cache
/// entry structures. The storage for thislist is allocated by the driver
/// publishing this protocol and must be freed by caller.
///
EFI_DNS6_CACHE_ENTRY *DnsCacheList;
} EFI_DNS6_MODE_DATA;
///
/// DNS6_HOST_TO_ADDR_DATA
///
typedef struct {
///
/// Number of the returned IP address.
///
UINT32 IpCount;
///
/// Pointer to the all the returned IP address.
///
EFI_IPv6_ADDRESS *IpList;
} DNS6_HOST_TO_ADDR_DATA;
///
/// DNS6_ADDR_TO_HOST_DATA
///
typedef struct {
///
/// Pointer to the primary name for this host address. It's the caller's
/// responsibility to free the response memory.
///
CHAR16 *HostName;
} DNS6_ADDR_TO_HOST_DATA;
///
/// DNS6_RESOURCE_RECORD
///
typedef struct {
///
/// The Owner name.
///
CHAR8 *QName;
///
/// The Type Code of this RR.
///
UINT16 QType;
///
/// The CLASS code of this RR.
///
UINT16 QClass;
///
/// 32 bit integer which specify the time interval that the resource record may be
/// cached before the source of the information should again be consulted. Zero means
/// this RR cannot be cached.
///
UINT32 TTL;
///
/// 16 big integer which specify the length of RData.
///
UINT16 DataLength;
///
/// A string of octets that describe the resource, the format of this information
/// varies according to QType and QClass difference.
///
CHAR8 *RData;
} DNS6_RESOURCE_RECORD;
///
/// DNS6_GENERAL_LOOKUP_DATA
///
typedef struct {
///
/// Number of returned matching RRs.
///
UINTN RRCount;
///
/// Pointer to the all the returned matching RRs. It's caller responsibility to free
/// the allocated memory to hold the returned RRs.
///
DNS6_RESOURCE_RECORD *RRList;
} DNS6_GENERAL_LOOKUP_DATA;
///
/// EFI_DNS6_COMPLETION_TOKEN
///
typedef struct {
///
/// This Event will be signaled after the Status field is updated by the EFI DNSv6
/// protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL.
///
EFI_EVENT Event;
///
/// Will be set to one of the following values:
/// EFI_SUCCESS: The host name to address translation completed successfully.
/// EFI_NOT_FOUND: No matching Resource Record (RR) is found.
/// EFI_TIMEOUT: No DNS server reachable, or RetryCount was exhausted without
/// response from all specified DNS servers.
/// EFI_DEVICE_ERROR: An unexpected system or network error occurred.
/// EFI_NO_MEDIA: There was a media error.
///
EFI_STATUS Status;
///
/// The parameter configured through DNSv6.Configure() interface. Retry number if no
/// response received after RetryInterval.
///
UINT32 RetryCount;
///
/// The parameter configured through DNSv6.Configure() interface. Minimum interval of
/// retry is 2 seconds. If the retry interval is less than 2 seconds, then use the 2
/// seconds.
///
UINT32 RetryInterval;
///
/// DNSv6 completion token data
///
union {
///
/// When the Token is used for host name to address translation, H2AData is a pointer
/// to the DNS6_HOST_TO_ADDR_DATA.
///
DNS6_HOST_TO_ADDR_DATA *H2AData;
///
/// When the Token is used for host address to host name translation, A2HData is a
/// pointer to the DNS6_ADDR_TO_HOST_DATA.
///
DNS6_ADDR_TO_HOST_DATA *A2HData;
///
/// When the Token is used for a general lookup function, GLookupDATA is a pointer to
/// the DNS6_GENERAL_LOOKUP_DATA.
///
DNS6_GENERAL_LOOKUP_DATA *GLookupData;
} RspData;
} EFI_DNS6_COMPLETION_TOKEN;
/**
Retrieve mode data of this DNS instance.
This function is used to retrieve DNS mode data for this DNS instance.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@param[out] DnsModeData Pointer to the caller-allocated storage for the
EFI_DNS6_MODE_DATA data.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data
is available because this instance has not been
configured.
@retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL.
@retval EFI_OUT_OF_RESOURCE Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_GET_MODE_DATA)(
IN EFI_DNS6_PROTOCOL *This,
OUT EFI_DNS6_MODE_DATA *DnsModeData
);
/**
Configure this DNS instance.
The Configure() function is used to set and change the configuration data for this
EFI DNSv6 Protocol driver instance. Reset the DNS instance if DnsConfigData is NULL.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@param[in] DnsConfigData Pointer to the configuration data structure. All associated
storage to be allocated and released by caller.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER This is NULL.
The StationIp address provided in DnsConfigData is not zero and not a valid unicast.
DnsServerList is NULL while DnsServerList Count is not ZERO.
DnsServerList Count is ZERO while DnsServerList is not NULL.
@retval EFI_OUT_OF_RESOURCES The DNS instance data or required space could not be allocated.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The
EFI DNSv6 Protocol instance is not configured.
@retval EFI_UNSUPPORTED The designated protocol is not supported.
@retval EFI_ALREADY_STARTED Second call to Configure() with DnsConfigData. To
reconfigure the instance the caller must call Configure() with
NULL first to return driver to unconfigured state.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_CONFIGURE)(
IN EFI_DNS6_PROTOCOL *This,
IN EFI_DNS6_CONFIG_DATA *DnsConfigData
);
/**
Host name to host address translation.
The HostNameToIp () function is used to translate the host name to host IP address. A
type AAAA query is used to get the one or more IPv6 addresses for this host.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@param[in] HostName Host name.
@param[in] Token Point to the completion token to translate host name
to host address.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token.Event is NULL.
HostName is NULL or buffer contained unsupported characters.
@retval EFI_NO_MAPPING There's no source address is available for use.
@retval EFI_ALREADY_STARTED This Token is being used in another DNS session.
@retval EFI_NOT_STARTED This instance has not been started.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_HOST_NAME_TO_IP)(
IN EFI_DNS6_PROTOCOL *This,
IN CHAR16 *HostName,
IN EFI_DNS6_COMPLETION_TOKEN *Token
);
/**
Host address to host name translation.
The IpToHostName () function is used to translate the host address to host name. A
type PTR query is used to get the primary name of the host. Implementation can choose
to support this function or not.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@param[in] IpAddress Ip Address.
@param[in] Token Point to the completion token to translate host
address to host name.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_UNSUPPORTED This function is not supported.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token.Event is NULL.
IpAddress is not valid IP address.
@retval EFI_NO_MAPPING There's no source address is available for use.
@retval EFI_NOT_STARTED This instance has not been started.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_IP_TO_HOST_NAME)(
IN EFI_DNS6_PROTOCOL *This,
IN EFI_IPv6_ADDRESS IpAddress,
IN EFI_DNS6_COMPLETION_TOKEN *Token
);
/**
This function provides capability to retrieve arbitrary information from the DNS
server.
This GeneralLookup() function retrieves arbitrary information from the DNS. The caller
supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. All
RR content (e.g., TTL) was returned. The caller need parse the returned RR to get
required information. The function is optional. Implementation can choose to support
it or not.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@param[in] QName Pointer to Query Name.
@param[in] QType Query Type.
@param[in] QClass Query Name.
@param[in] Token Point to the completion token to retrieve arbitrary
information.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_UNSUPPORTED This function is not supported. Or the requested
QType is not supported
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token.Event is NULL.
QName is NULL.
@retval EFI_NO_MAPPING There's no source address is available for use.
@retval EFI_NOT_STARTED This instance has not been started.
@retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_GENERAL_LOOKUP)(
IN EFI_DNS6_PROTOCOL *This,
IN CHAR8 *QName,
IN UINT16 QType,
IN UINT16 QClass,
IN EFI_DNS6_COMPLETION_TOKEN *Token
);
/**
This function is to update the DNS Cache.
The UpdateDnsCache() function is used to add/delete/modify DNS cache entry. DNS cache
can be normally dynamically updated after the DNS resolve succeeds. This function
provided capability to manually add/delete/modify the DNS cache.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@param[in] DeleteFlag If FALSE, this function is to add one entry to the
DNS Cahce. If TRUE, this function will delete
matching DNS Cache entry.
@param[in] Override If TRUE, the maching DNS cache entry will be
overwritten with the supplied parameter. If FALSE,
EFI_ACCESS_DENIED will be returned if the entry to
be added is already existed.
@param[in] DnsCacheEntry Pointer to DNS Cache entry.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
DnsCacheEntry.HostName is NULL.
DnsCacheEntry.IpAddress is NULL.
DnsCacheEntry.Timeout is zero.
@retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is
not TRUE.
@retval EFI_OUT_OF_RESOURCE Failed to allocate needed resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_UPDATE_DNS_CACHE)(
IN EFI_DNS6_PROTOCOL *This,
IN BOOLEAN DeleteFlag,
IN BOOLEAN Override,
IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry
);
/**
Polls for incoming data packets and processes outgoing data packets.
The Poll() function can be used by network drivers and applications to increase the
rate that data packets are moved between the communications device and the transmit
and receive queues.
In some systems, the periodic timer event in the managed network driver may not poll
the underlying communications device fast enough to transmit and/or receive all data
packets without missing incoming packets or dropping outgoing packets. Drivers and
applications that are experiencing packet loss should try calling the Poll()
function more often.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@retval EFI_SUCCESS Incoming or outgoing data was processed.
@retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NO_MAPPING There is no source address is available for use.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive
queue. Consider increasing the polling rate.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_POLL)(
IN EFI_DNS6_PROTOCOL *This
);
/**
Abort an asynchronous DNS operation, including translation between IP and Host, and
general look up behavior.
The Cancel() function is used to abort a pending resolution request. After calling
this function, Token.Status will be set to EFI_ABORTED and then Token.Event will be
signaled. If the token is not in one of the queues, which usually means that the
asynchronous operation has completed, this function will not signal the token and
EFI_NOT_FOUND is returned.
@param[in] This Pointer to EFI_DNS6_PROTOCOL instance.
@param[in] Token Pointer to a token that has been issued by
EFI_DNS6_PROTOCOL.HostNameToIp (),
EFI_DNS6_PROTOCOL.IpToHostName() or
EFI_DNS6_PROTOCOL.GeneralLookup().
If NULL, all pending tokens are aborted.
@retval EFI_SUCCESS Incoming or outgoing data was processed.
@retval EFI_NOT_STARTED This EFI DNS6 Protocol instance has not been started.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NO_MAPPING There's no source address is available for use.
@retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS
operation was not found in the transmit queue. It
was either completed or was not issued by
HostNameToIp(), IpToHostName() or GeneralLookup().
**/
typedef
EFI_STATUS
(EFIAPI *EFI_DNS6_CANCEL)(
IN EFI_DNS6_PROTOCOL *This,
IN EFI_DNS6_COMPLETION_TOKEN *Token
);
///
/// The EFI_DNS6_PROTOCOL provides the function to get the host name and address
/// mapping, also provide pass through interface to retrieve arbitrary information from
/// DNSv6.
///
struct _EFI_DNS6_PROTOCOL {
EFI_DNS6_GET_MODE_DATA GetModeData;
EFI_DNS6_CONFIGURE Configure;
EFI_DNS6_HOST_NAME_TO_IP HostNameToIp;
EFI_DNS6_IP_TO_HOST_NAME IpToHostName;
EFI_DNS6_GENERAL_LOOKUP GeneralLookUp;
EFI_DNS6_UPDATE_DNS_CACHE UpdateDnsCache;
EFI_DNS6_POLL Poll;
EFI_DNS6_CANCEL Cancel;
};
extern EFI_GUID gEfiDns6ServiceBindingProtocolGuid;
extern EFI_GUID gEfiDns6ProtocolGuid;
#endif

View File

@ -0,0 +1,516 @@
/** @file
This file defines the EFI HTTP Protocol interface. It is split into
the following two main sections:
HTTP Service Binding Protocol (HTTPSB)
HTTP Protocol (HTTP)
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015-2017 Hewlett Packard Enterprise Development LP<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
This Protocol is introduced in UEFI Specification 2.5
**/
#ifndef __EFI_HTTP_PROTOCOL_H__
#define __EFI_HTTP_PROTOCOL_H__
FILE_LICENCE ( BSD2_PATENT );
#define EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \
{ \
0xbdc8e6af, 0xd9bc, 0x4379, {0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \
}
#define EFI_HTTP_PROTOCOL_GUID \
{ \
0x7a59b29b, 0x910b, 0x4171, {0x82, 0x42, 0xa8, 0x5a, 0x0d, 0xf2, 0x5b, 0x5b } \
}
typedef struct _EFI_HTTP_PROTOCOL EFI_HTTP_PROTOCOL;
///
/// EFI_HTTP_VERSION
///
typedef enum {
HttpVersion10,
HttpVersion11,
HttpVersionUnsupported
} EFI_HTTP_VERSION;
///
/// EFI_HTTP_METHOD
///
typedef enum {
HttpMethodGet,
HttpMethodPost,
HttpMethodPatch,
HttpMethodOptions,
HttpMethodConnect,
HttpMethodHead,
HttpMethodPut,
HttpMethodDelete,
HttpMethodTrace,
HttpMethodMax
} EFI_HTTP_METHOD;
///
/// EFI_HTTP_STATUS_CODE
///
typedef enum {
HTTP_STATUS_UNSUPPORTED_STATUS = 0,
HTTP_STATUS_100_CONTINUE,
HTTP_STATUS_101_SWITCHING_PROTOCOLS,
HTTP_STATUS_200_OK,
HTTP_STATUS_201_CREATED,
HTTP_STATUS_202_ACCEPTED,
HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION,
HTTP_STATUS_204_NO_CONTENT,
HTTP_STATUS_205_RESET_CONTENT,
HTTP_STATUS_206_PARTIAL_CONTENT,
HTTP_STATUS_300_MULTIPLE_CHOICES,
HTTP_STATUS_301_MOVED_PERMANENTLY,
HTTP_STATUS_302_FOUND,
HTTP_STATUS_303_SEE_OTHER,
HTTP_STATUS_304_NOT_MODIFIED,
HTTP_STATUS_305_USE_PROXY,
HTTP_STATUS_307_TEMPORARY_REDIRECT,
HTTP_STATUS_400_BAD_REQUEST,
HTTP_STATUS_401_UNAUTHORIZED,
HTTP_STATUS_402_PAYMENT_REQUIRED,
HTTP_STATUS_403_FORBIDDEN,
HTTP_STATUS_404_NOT_FOUND,
HTTP_STATUS_405_METHOD_NOT_ALLOWED,
HTTP_STATUS_406_NOT_ACCEPTABLE,
HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED,
HTTP_STATUS_408_REQUEST_TIME_OUT,
HTTP_STATUS_409_CONFLICT,
HTTP_STATUS_410_GONE,
HTTP_STATUS_411_LENGTH_REQUIRED,
HTTP_STATUS_412_PRECONDITION_FAILED,
HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE,
HTTP_STATUS_414_REQUEST_URI_TOO_LARGE,
HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE,
HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED,
HTTP_STATUS_417_EXPECTATION_FAILED,
HTTP_STATUS_500_INTERNAL_SERVER_ERROR,
HTTP_STATUS_501_NOT_IMPLEMENTED,
HTTP_STATUS_502_BAD_GATEWAY,
HTTP_STATUS_503_SERVICE_UNAVAILABLE,
HTTP_STATUS_504_GATEWAY_TIME_OUT,
HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED,
HTTP_STATUS_308_PERMANENT_REDIRECT
} EFI_HTTP_STATUS_CODE;
///
/// EFI_HTTPv4_ACCESS_POINT
///
typedef struct {
///
/// Set to TRUE to instruct the EFI HTTP instance to use the default address
/// information in every TCP connection made by this instance. In addition, when set
/// to TRUE, LocalAddress and LocalSubnet are ignored.
///
BOOLEAN UseDefaultAddress;
///
/// If UseDefaultAddress is set to FALSE, this defines the local IP address to be
/// used in every TCP connection opened by this instance.
///
EFI_IPv4_ADDRESS LocalAddress;
///
/// If UseDefaultAddress is set to FALSE, this defines the local subnet to be used
/// in every TCP connection opened by this instance.
///
EFI_IPv4_ADDRESS LocalSubnet;
///
/// This defines the local port to be used in
/// every TCP connection opened by this instance.
///
UINT16 LocalPort;
} EFI_HTTPv4_ACCESS_POINT;
///
/// EFI_HTTPv6_ACCESS_POINT
///
typedef struct {
///
/// Local IP address to be used in every TCP connection opened by this instance.
///
EFI_IPv6_ADDRESS LocalAddress;
///
/// Local port to be used in every TCP connection opened by this instance.
///
UINT16 LocalPort;
} EFI_HTTPv6_ACCESS_POINT;
///
/// EFI_HTTP_CONFIG_DATA_ACCESS_POINT
///
typedef struct {
///
/// HTTP version that this instance will support.
///
EFI_HTTP_VERSION HttpVersion;
///
/// Time out (in milliseconds) when blocking for requests.
///
UINT32 TimeOutMillisec;
///
/// Defines behavior of EFI DNS and TCP protocols consumed by this instance. If
/// FALSE, this instance will use EFI_DNS4_PROTOCOL and EFI_TCP4_PROTOCOL. If TRUE,
/// this instance will use EFI_DNS6_PROTOCOL and EFI_TCP6_PROTOCOL.
///
BOOLEAN LocalAddressIsIPv6;
union {
///
/// When LocalAddressIsIPv6 is FALSE, this points to the local address, subnet, and
/// port used by the underlying TCP protocol.
///
EFI_HTTPv4_ACCESS_POINT *IPv4Node;
///
/// When LocalAddressIsIPv6 is TRUE, this points to the local IPv6 address and port
/// used by the underlying TCP protocol.
///
EFI_HTTPv6_ACCESS_POINT *IPv6Node;
} AccessPoint;
} EFI_HTTP_CONFIG_DATA;
///
/// EFI_HTTP_REQUEST_DATA
///
typedef struct {
///
/// The HTTP method (e.g. GET, POST) for this HTTP Request.
///
EFI_HTTP_METHOD Method;
///
/// The URI of a remote host. From the information in this field, the HTTP instance
/// will be able to determine whether to use HTTP or HTTPS and will also be able to
/// determine the port number to use. If no port number is specified, port 80 (HTTP)
/// is assumed. See RFC 3986 for more details on URI syntax.
///
CHAR16 *Url;
} EFI_HTTP_REQUEST_DATA;
///
/// EFI_HTTP_RESPONSE_DATA
///
typedef struct {
///
/// Response status code returned by the remote host.
///
EFI_HTTP_STATUS_CODE StatusCode;
} EFI_HTTP_RESPONSE_DATA;
///
/// EFI_HTTP_HEADER
///
typedef struct {
///
/// Null terminated string which describes a field name. See RFC 2616 Section 14 for
/// detailed information about field names.
///
CHAR8 *FieldName;
///
/// Null terminated string which describes the corresponding field value. See RFC 2616
/// Section 14 for detailed information about field values.
///
CHAR8 *FieldValue;
} EFI_HTTP_HEADER;
///
/// EFI_HTTP_MESSAGE
///
typedef struct {
///
/// HTTP message data.
///
union {
///
/// When the token is used to send a HTTP request, Request is a pointer to storage that
/// contains such data as URL and HTTP method.
///
EFI_HTTP_REQUEST_DATA *Request;
///
/// When used to await a response, Response points to storage containing HTTP response
/// status code.
///
EFI_HTTP_RESPONSE_DATA *Response;
} Data;
///
/// Number of HTTP header structures in Headers list. On request, this count is
/// provided by the caller. On response, this count is provided by the HTTP driver.
///
UINTN HeaderCount;
///
/// Array containing list of HTTP headers. On request, this array is populated by the
/// caller. On response, this array is allocated and populated by the HTTP driver. It
/// is the responsibility of the caller to free this memory on both request and
/// response.
///
EFI_HTTP_HEADER *Headers;
///
/// Length in bytes of the HTTP body. This can be zero depending on the HttpMethod type.
///
UINTN BodyLength;
///
/// Body associated with the HTTP request or response. This can be NULL depending on
/// the HttpMethod type.
///
VOID *Body;
} EFI_HTTP_MESSAGE;
///
/// EFI_HTTP_TOKEN
///
typedef struct {
///
/// This Event will be signaled after the Status field is updated by the EFI HTTP
/// Protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. The Task Priority
/// Level (TPL) of Event must be lower than or equal to TPL_CALLBACK.
///
EFI_EVENT Event;
///
/// Status will be set to one of the following value if the HTTP request is
/// successfully sent or if an unexpected error occurs:
/// EFI_SUCCESS: The HTTP request was successfully sent to the remote host.
/// EFI_HTTP_ERROR: The response message was successfully received but contains a
/// HTTP error. The response status code is returned in token.
/// EFI_ABORTED: The HTTP request was cancelled by the caller and removed from
/// the transmit queue.
/// EFI_TIMEOUT: The HTTP request timed out before reaching the remote host.
/// EFI_DEVICE_ERROR: An unexpected system or network error occurred.
///
EFI_STATUS Status;
///
/// Pointer to storage containing HTTP message data.
///
EFI_HTTP_MESSAGE *Message;
} EFI_HTTP_TOKEN;
/**
Returns the operational parameters for the current HTTP child instance.
The GetModeData() function is used to read the current mode data (operational
parameters) for this HTTP protocol instance.
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
@param[out] HttpConfigData Point to buffer for operational parameters of this
HTTP instance. It is the responsibility of the caller
to allocate the memory for HttpConfigData and
HttpConfigData->AccessPoint.IPv6Node/IPv4Node. In fact,
it is recommended to allocate sufficient memory to record
IPv6Node since it is big enough for all possibilities.
@retval EFI_SUCCESS Operation succeeded.
@retval EFI_INVALID_PARAMETER This is NULL.
HttpConfigData is NULL.
HttpConfigData->AccessPoint.IPv4Node or
HttpConfigData->AccessPoint.IPv6Node is NULL.
@retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HTTP_GET_MODE_DATA)(
IN EFI_HTTP_PROTOCOL *This,
OUT EFI_HTTP_CONFIG_DATA *HttpConfigData
);
/**
Initialize or brutally reset the operational parameters for this EFI HTTP instance.
The Configure() function does the following:
When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring
timeout, local address, port, etc.
When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active
connections with remote hosts, canceling all asynchronous tokens, and flush request
and response buffers without informing the appropriate hosts.
No other EFI HTTP function can be executed by this instance until the Configure()
function is executed and returns successfully.
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
@param[in] HttpConfigData Pointer to the configure data to configure the instance.
@retval EFI_SUCCESS Operation succeeded.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
HttpConfigData->LocalAddressIsIPv6 is FALSE and
HttpConfigData->AccessPoint.IPv4Node is NULL.
HttpConfigData->LocalAddressIsIPv6 is TRUE and
HttpConfigData->AccessPoint.IPv6Node is NULL.
@retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling
Configure() with NULL to reset it.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when
executing Configure().
@retval EFI_UNSUPPORTED One or more options in ConfigData are not supported
in the implementation.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HTTP_CONFIGURE)(
IN EFI_HTTP_PROTOCOL *This,
IN EFI_HTTP_CONFIG_DATA *HttpConfigData OPTIONAL
);
/**
The Request() function queues an HTTP request to this HTTP instance,
similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent
successfully, or if there is an error, Status in token will be updated and Event will
be signaled.
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
@param[in] Token Pointer to storage containing HTTP request token.
@retval EFI_SUCCESS Outgoing data was processed.
@retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token->Message is NULL.
Token->Message->Body is not NULL,
Token->Message->BodyLength is non-zero, and
Token->Message->Data is NULL, but a previous call to
Request()has not been completed successfully.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.
@retval EFI_UNSUPPORTED The HTTP method is not supported in current implementation.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HTTP_REQUEST)(
IN EFI_HTTP_PROTOCOL *This,
IN EFI_HTTP_TOKEN *Token
);
/**
Abort an asynchronous HTTP request or response token.
The Cancel() function aborts a pending HTTP request or response transaction. If
Token is not NULL and the token is in transmit or receive queues when it is being
cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will
be signaled. If the token is not in one of the queues, which usually means that the
asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL,
all asynchronous tokens issued by Request() or Response() will be aborted.
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
@param[in] Token Point to storage containing HTTP request or response
token.
@retval EFI_SUCCESS Request and Response queues are successfully flushed.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NOT_STARTED This instance hasn't been configured.
@retval EFI_NOT_FOUND The asynchronous request or response token is not
found.
@retval EFI_UNSUPPORTED The implementation does not support this function.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HTTP_CANCEL)(
IN EFI_HTTP_PROTOCOL *This,
IN EFI_HTTP_TOKEN *Token
);
/**
The Response() function queues an HTTP response to this HTTP instance, similar to
Receive() function in the EFI TCP driver. When the HTTP Response is received successfully,
or if there is an error, Status in token will be updated and Event will be signaled.
The HTTP driver will queue a receive token to the underlying TCP instance. When data
is received in the underlying TCP instance, the data will be parsed and Token will
be populated with the response data. If the data received from the remote host
contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting
(asynchronously) for more data to be sent from the remote host before signaling
Event in Token.
It is the responsibility of the caller to allocate a buffer for Body and specify the
size in BodyLength. If the remote host provides a response that contains a content
body, up to BodyLength bytes will be copied from the receive buffer into Body and
BodyLength will be updated with the amount of bytes received and copied to Body. This
allows the client to download a large file in chunks instead of into one contiguous
block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is
non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive
token to underlying TCP instance. If data arrives in the receive buffer, up to
BodyLength bytes of data will be copied to Body. The HTTP driver will then update
BodyLength with the amount of bytes received and copied to Body.
If the HTTP driver does not have an open underlying TCP connection with the host
specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is
consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain
an open TCP connection between client and host.
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
@param[in] Token Pointer to storage containing HTTP response token.
@retval EFI_SUCCESS Allocation succeeded.
@retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been
initialized.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
Token is NULL.
Token->Message->Headers is NULL.
Token->Message is NULL.
Token->Message->Body is not NULL,
Token->Message->BodyLength is non-zero, and
Token->Message->Data is NULL, but a previous call to
Response() has not been completed successfully.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.
@retval EFI_ACCESS_DENIED An open TCP connection is not present with the host
specified by response URL.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HTTP_RESPONSE)(
IN EFI_HTTP_PROTOCOL *This,
IN EFI_HTTP_TOKEN *Token
);
/**
The Poll() function can be used by network drivers and applications to increase the
rate that data packets are moved between the communication devices and the transmit
and receive queues.
In some systems, the periodic timer event in the managed network driver may not poll
the underlying communications device fast enough to transmit and/or receive all data
packets without missing incoming packets or dropping outgoing packets. Drivers and
applications that are experiencing packet loss should try calling the Poll() function
more often.
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
@retval EFI_SUCCESS Incoming or outgoing data was processed..
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NOT_READY No incoming or outgoing data is processed.
@retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HTTP_POLL)(
IN EFI_HTTP_PROTOCOL *This
);
///
/// The EFI HTTP protocol is designed to be used by EFI drivers and applications to
/// create and transmit HTTP Requests, as well as handle HTTP responses that are
/// returned by a remote host. This EFI protocol uses and relies on an underlying EFI
/// TCP protocol.
///
struct _EFI_HTTP_PROTOCOL {
EFI_HTTP_GET_MODE_DATA GetModeData;
EFI_HTTP_CONFIGURE Configure;
EFI_HTTP_REQUEST Request;
EFI_HTTP_CANCEL Cancel;
EFI_HTTP_RESPONSE Response;
EFI_HTTP_POLL Poll;
};
extern EFI_GUID gEfiHttpServiceBindingProtocolGuid;
extern EFI_GUID gEfiHttpProtocolGuid;
#endif

View File

@ -0,0 +1,318 @@
/** @file
This file provides a definition of the EFI IPv4 Configuration II
Protocol.
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
This Protocol is introduced in UEFI Specification 2.5
**/
#ifndef __EFI_IP4CONFIG2_PROTOCOL_H__
#define __EFI_IP4CONFIG2_PROTOCOL_H__
FILE_LICENCE ( BSD2_PATENT );
#include <ipxe/efi/Protocol/Ip4.h>
#define EFI_IP4_CONFIG2_PROTOCOL_GUID \
{ \
0x5b446ed1, 0xe30b, 0x4faa, {0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \
}
typedef struct _EFI_IP4_CONFIG2_PROTOCOL EFI_IP4_CONFIG2_PROTOCOL;
///
/// EFI_IP4_CONFIG2_DATA_TYPE
///
typedef enum {
///
/// The interface information of the communication device this EFI
/// IPv4 Configuration II Protocol instance manages. This type of
/// data is read only. The corresponding Data is of type
/// EFI_IP4_CONFIG2_INTERFACE_INFO.
///
Ip4Config2DataTypeInterfaceInfo,
///
/// The general configuration policy for the EFI IPv4 network stack
/// running on the communication device this EFI IPv4
/// Configuration II Protocol instance manages. The policy will
/// affect other configuration settings. The corresponding Data is of
/// type EFI_IP4_CONFIG2_POLICY.
///
Ip4Config2DataTypePolicy,
///
/// The station addresses set manually for the EFI IPv4 network
/// stack. It is only configurable when the policy is
/// Ip4Config2PolicyStatic. The corresponding Data is of
/// type EFI_IP4_CONFIG2_MANUAL_ADDRESS. When DataSize
/// is 0 and Data is NULL, the existing configuration is cleared
/// from the EFI IPv4 Configuration II Protocol instance.
///
Ip4Config2DataTypeManualAddress,
///
/// The gateway addresses set manually for the EFI IPv4 network
/// stack running on the communication device this EFI IPv4
/// Configuration II Protocol manages. It is not configurable when
/// the policy is Ip4Config2PolicyDhcp. The gateway
/// addresses must be unicast IPv4 addresses. The corresponding
/// Data is a pointer to an array of EFI_IPv4_ADDRESS instances.
/// When DataSize is 0 and Data is NULL, the existing configuration
/// is cleared from the EFI IPv4 Configuration II Protocol instance.
///
Ip4Config2DataTypeGateway,
///
/// The DNS server list for the EFI IPv4 network stack running on
/// the communication device this EFI IPv4 Configuration II
/// Protocol manages. It is not configurable when the policy is
/// Ip4Config2PolicyDhcp. The DNS server addresses must be
/// unicast IPv4 addresses. The corresponding Data is a pointer to
/// an array of EFI_IPv4_ADDRESS instances. When DataSize
/// is 0 and Data is NULL, the existing configuration is cleared
/// from the EFI IPv4 Configuration II Protocol instance.
///
Ip4Config2DataTypeDnsServer,
Ip4Config2DataTypeMaximum
} EFI_IP4_CONFIG2_DATA_TYPE;
///
/// EFI_IP4_CONFIG2_INTERFACE_INFO related definitions
///
#define EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32
///
/// EFI_IP4_CONFIG2_INTERFACE_INFO
///
typedef struct {
///
/// The name of the interface. It is a NULL-terminated Unicode string.
///
CHAR16 Name[EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE];
///
/// The interface type of the network interface. See RFC 1700,
/// section "Number Hardware Type".
///
UINT8 IfType;
///
/// The size, in bytes, of the network interface's hardware address.
///
UINT32 HwAddressSize;
///
/// The hardware address for the network interface.
///
EFI_MAC_ADDRESS HwAddress;
///
/// The station IPv4 address of this EFI IPv4 network stack.
///
EFI_IPv4_ADDRESS StationAddress;
///
/// The subnet address mask that is associated with the station address.
///
EFI_IPv4_ADDRESS SubnetMask;
///
/// Size of the following RouteTable, in bytes. May be zero.
///
UINT32 RouteTableSize;
///
/// The route table of the IPv4 network stack runs on this interface.
/// Set to NULL if RouteTableSize is zero. Type EFI_IP4_ROUTE_TABLE is defined in
/// EFI_IP4_PROTOCOL.GetModeData().
///
EFI_IP4_ROUTE_TABLE *RouteTable OPTIONAL;
} EFI_IP4_CONFIG2_INTERFACE_INFO;
///
/// EFI_IP4_CONFIG2_POLICY
///
typedef enum {
///
/// Under this policy, the Ip4Config2DataTypeManualAddress,
/// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration
/// data are required to be set manually. The EFI IPv4 Protocol will get all
/// required configuration such as IPv4 address, subnet mask and
/// gateway settings from the EFI IPv4 Configuration II protocol.
///
Ip4Config2PolicyStatic,
///
/// Under this policy, the Ip4Config2DataTypeManualAddress,
/// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration data are
/// not allowed to set via SetData(). All of these configurations are retrieved from DHCP
/// server or other auto-configuration mechanism.
///
Ip4Config2PolicyDhcp,
Ip4Config2PolicyMax
} EFI_IP4_CONFIG2_POLICY;
///
/// EFI_IP4_CONFIG2_MANUAL_ADDRESS
///
typedef struct {
///
/// The IPv4 unicast address.
///
EFI_IPv4_ADDRESS Address;
///
/// The subnet mask.
///
EFI_IPv4_ADDRESS SubnetMask;
} EFI_IP4_CONFIG2_MANUAL_ADDRESS;
/**
Set the configuration for the EFI IPv4 network stack running on the communication device this EFI
IPv4 Configuration II Protocol instance manages.
This function is used to set the configuration data of type DataType for the EFI IPv4 network stack
running on the communication device this EFI IPv4 Configuration II Protocol instance manages.
The successfully configured data is valid after system reset or power-off.
The DataSize is used to calculate the count of structure instances in the Data for some
DataType that multiple structure instances are allowed.
This function is always non-blocking. When setting some typeof configuration data, an
asynchronous process is invoked to check the correctness of the data, such as doing address conflict
detection on the manually set local IPv4 address. EFI_NOT_READY is returned immediately to
indicate that such an asynchronous process is invoked and the process is not finished yet. The caller
willing to get the result of the asynchronous process is required to call RegisterDataNotify()
to register an event on the specified configuration data. Once the event is signaled, the caller can call
GetData()to get back the configuration data in order to know the result. For other types of
configuration data that do not require an asynchronous configuration process, the result of the
operation is immediately returned.
@param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
@param[in] DataType The type of data to set.
@param[in] DataSize Size of the buffer pointed to by Data in bytes.
@param[in] Data The data buffer to set. The type ofthe data buffer is associated
with the DataType.
@retval EFI_SUCCESS The specified configuration data for the EFI IPv4 network stack is set
successfully.
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
This is NULL.
One or more fields in Data and DataSize do not match the
requirement of the data type indicated by DataType.
@retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified configuration
data can not be set under the current policy.
@retval EFI_ACCESS_DENIED Another set operation on the specified configuration data is already in process.
@retval EFI_NOT_READY An asynchronous process is invoked to set the specified configuration data and
the process is not finished yet.
@retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type indicated by DataType.
@retval EFI_UNSUPPORTED This DataType is not supported.
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
@retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_IP4_CONFIG2_SET_DATA)(
IN EFI_IP4_CONFIG2_PROTOCOL *This,
IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
IN UINTN DataSize,
IN VOID *Data
);
/**
Get the configuration data for the EFI IPv4 network stack running on the communication device this
EFI IPv4 Configuration II Protocol instance manages.
This function returns the configuration data of type DataType for the EFI IPv4 network stack
running on the communication device this EFI IPv4 Configuration II Protocol instance manages.
The caller is responsible for allocating the buffer usedto return the specified configuration data and
the required size will be returned to the caller if the size of the buffer is too small.
EFI_NOT_READY is returned if the specified configuration data is not ready due to an already in
progress asynchronous configuration process. The caller can call RegisterDataNotify() to
register an event on the specified configuration data. Once the asynchronous configuration process is
finished, the event will be signaled and a subsequent GetData() call will return the specified
configuration data.
@param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
@param[in] DataType The type of data to get.
@param[out] DataSize On input, in bytes, the size of Data. On output, in bytes, the size
of buffer required to store the specified configuration data.
@param[in] Data The data buffer in which the configuration data is returned. The
type of the data buffer is associated with the DataType. Ignored
if DataSize is 0.
@retval EFI_SUCCESS The specified configuration data is got successfully.
@retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
This is NULL.
DataSize is NULL.
Data is NULL if *DataSizeis not zero.
@retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data
and the required size is returned in DataSize.
@retval EFI_NOT_READY The specified configuration data is not ready due to an already in
progress asynchronous configuration process.
@retval EFI_NOT_FOUND The specified configuration data is not found.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_IP4_CONFIG2_GET_DATA)(
IN EFI_IP4_CONFIG2_PROTOCOL *This,
IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
IN OUT UINTN *DataSize,
IN VOID *Data OPTIONAL
);
/**
Register an event that is to be signaled whenever a configuration process on the specified
configuration data is done.
This function registers an event that is to be signaled whenever a configuration process on the
specified configuration data is done. An event can be registered for different DataType
simultaneously and the caller is responsible for determining which type of configuration data causes
the signaling of the event in such case.
@param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
@param[in] DataType The type of data to unregister the event for.
@param[in] Event The event to register.
@retval EFI_SUCCESS The notification event for the specified configuration data is
registered.
@retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
@retval EFI_UNSUPPORTED The configuration data type specified by DataType is not supported.
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
@retval EFI_ACCESS_DENIED The Event is already registered for the DataType.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_IP4_CONFIG2_REGISTER_NOTIFY)(
IN EFI_IP4_CONFIG2_PROTOCOL *This,
IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
IN EFI_EVENT Event
);
/**
Remove a previously registered event for the specified configuration data.
This function removes a previously registeredevent for the specified configuration data.
@param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
@param[in] DataType The type of data to remove the previously registered event for.
@param[in] Event The event to unregister.
@retval EFI_SUCCESS The event registered for the specified configuration data is removed.
@retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
@retval EFI_NOT_FOUND The Eventhas not been registered for the specified DataType.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_IP4_CONFIG2_UNREGISTER_NOTIFY)(
IN EFI_IP4_CONFIG2_PROTOCOL *This,
IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
IN EFI_EVENT Event
);
///
/// The EFI_IP4_CONFIG2_PROTOCOL is designed to be the central repository for the common
/// configurations and the administrator configurable settings for the EFI IPv4 network stack.
/// An EFI IPv4 Configuration II Protocol instance will be installed on each communication device that
/// the EFI IPv4 network stack runs on.
///
struct _EFI_IP4_CONFIG2_PROTOCOL {
EFI_IP4_CONFIG2_SET_DATA SetData;
EFI_IP4_CONFIG2_GET_DATA GetData;
EFI_IP4_CONFIG2_REGISTER_NOTIFY RegisterDataNotify;
EFI_IP4_CONFIG2_UNREGISTER_NOTIFY UnregisterDataNotify;
};
extern EFI_GUID gEfiIp4Config2ProtocolGuid;
#endif

Some files were not shown because too many files have changed in this diff Show More