Compare commits

...

71 Commits

Author SHA1 Message Date
e814d33900 [uri] Allow for relative URIs that include colons within the path
RFC3986 allows for colons to appear within the path component of a
relative URI, but iPXE will currently parse such URIs incorrectly by
interpreting the text before the colon as the URI scheme.

Fix by checking for valid characters when identifying the URI scheme.
Deliberately deviate from the RFC3986 definition of valid characters
by accepting "_" (which was incorrectly used in the iPXE-specific
"ib_srp" URI scheme and so must be accepted for compatibility with
existing deployments), and by omitting the code to check for
characters that are not used in any URI scheme supported by iPXE.

Reported-by: Ignat Korchagin <ignat@cloudflare.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2022-01-13 15:03:22 +00:00
f4f9adf618 [efi] Include Secure Boot Advanced Targeting (SBAT) metadata
SBAT defines an encoding for security generation numbers stored as a
CSV file within a special ".sbat" section in the signed binary.  If a
Secure Boot exploit is discovered then the generation number will be
incremented alongside the corresponding fix.

Platforms may then record the minimum generation number required for
any given product.  This allows for an efficient revocation mechanism
that consumes minimal flash storage space (in contrast to the DBX
mechanism, which allows for only a single-digit number of revocation
events to ever take place across all possible signed binaries).

Add SBAT metadata to iPXE EFI binaries to support this mechanism.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2022-01-13 14:12:44 +00:00
fbbdc39260 [build] Ensure version.%.o is always rebuilt as expected
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2022-01-13 13:43:08 +00:00
53a5de3641 [doc] Update user-visible ipxe.org URIs to use HTTPS
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2022-01-13 12:48:38 +00:00
91c77e2592 [efi] Do not align VirtualSize for .reloc and .debug sections
As of commit f1e9e2b ("[efi] Align EFI image sections by page size"),
the VirtualSize fields for the .reloc and .debug sections have been
rounded up to the (4kB) image alignment.  This breaks the PE
relocation logic in the UEFI shim, which requires the VirtualSize
field to exactly match the size as recorded in the data directory.

Fix by setting the VirtualSize field to the unaligned size of the
section, as is already done for normal PE sections (i.e. those other
than .reloc and .debug).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2022-01-11 15:27:14 +00:00
f43c2fd697 [settings] Support formatting UUIDs as little-endian GUIDs
The RFC4122 specification defines UUIDs as being in network byte
order, but an unfortunately significant amount of (mostly Microsoft)
software treats them as having the first three fields in little-endian
byte order.

In an ideal world, any server-side software that compares UUIDs for
equality would perform an endian-insensitive comparison (analogous to
comparing strings for equality using a case-insensitive comparison),
and would therefore not care about byte order differences.

Define a setting type name ":guid" to allow a UUID setting to be
formatted in little-endian order, to simplify interoperability with
server-side software that expects such a formatting.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2022-01-04 14:03:12 +00:00
9062544f6a [efi] Disable EFI watchdog timer when shutting down to boot an OS
The UEFI specification mandates that the EFI watchdog timer should be
disabled by the platform firmware as part of the ExitBootServices()
call, but some platforms (e.g. Hyper-V) are observed to occasionally
forget to do so, resulting in a reboot approximately five minutes
after starting the operating system.

Work around these firmware bugs by disabling the watchdog timer
ourselves.

Requested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-25 09:30:59 +00:00
562c74e1ea [efi] Run ExitBootServices shutdown hook at TPL_NOTIFY
On some systems (observed with the Thunderbolt ports on a ThinkPad X1
Extreme Gen3 and a ThinkPad P53), if the IOMMU is enabled then the
system firmware will install an ExitBootServices notification event
that disables bus mastering on the Thunderbolt xHCI controller and all
PCI bridges, and destroys any extant IOMMU mappings.  This leaves the
xHCI controller unable to perform any DMA operations.

As described in commit 236299b ("[xhci] Avoid DMA during shutdown if
firmware has disabled bus mastering"), any subsequent DMA operation
attempted by the xHCI controller will end up completing after the
operating system kernel has reenabled bus mastering, resulting in a
DMA operation to an area of memory that the hardware is no longer
permitted to access and, on Windows with the Driver Verifier enabled,
a STOP 0xE6 (DRIVER_VERIFIER_DMA_VIOLATION).

That commit avoids triggering any DMA attempts during the shutdown of
the xHCI controller itself.  However, this is not a complete solution
since any attached and opened USB device (e.g. a USB NIC) may
asynchronously trigger DMA attempts that happen to occur after bus
mastering has been disabled but before we reset the xHCI controller.

Avoid this problem by installing our own ExitBootServices notification
event at TPL_NOTIFY, thereby causing it to be invoked before the
firmware's own ExitBootServices notification event that disables bus
mastering.

This unsurprisingly causes the shutdown hook itself to be invoked at
TPL_NOTIFY, which causes a fatal error when later code attempts to
raise the TPL to TPL_CALLBACK (which is a lower TPL).  Work around
this problem by redefining the "internal" iPXE TPL to be variable, and
set this internal TPL to TPL_NOTIFY when the shutdown hook is invoked.

Avoid calling into an underlying SNP protocol instance from within our
shutdown hook at TPL_NOTIFY, since the underlying SNP driver may
attempt to raise the TPL to TPL_CALLBACK (which would cause a fatal
error).  Failing to shut down the underlying SNP device is safe to do
since the underlying device must, in any case, have installed its own
ExitBootServices hook if any shutdown actions are required.

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-23 15:55:01 +00:00
0f4cc4b5a7 [build] Include EFI system partition table entry in isohybrid images
Add the "--uefi" option when invoking isohybrid on an EFI-bootable
image, to create a partition mapping to the EFI system partition
embedded within the ISO image.

This allows the resulting isohybrid image to be booted on UEFI systems
that will not recognise an El Torito boot catalog on a non-CDROM
device.

Originally-fixed-by: Christian Hesse <mail@eworm.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-23 15:26:55 +00:00
a046da21a4 [efi] Raise TPL during driver unload entry point
The efi_unload() function is currently missing the calls to raise and
restore the TPL.  This has the side effect of causing iPXE to return
from the driver unload entry point at TPL_CALLBACK, which will cause
unexpected behaviour (typically a system lockup) shortly afterwards.

Fix by adding the missing calls to raise and restore the TPL.

Debugged-by: Petr Borsodi <petr.borsodi@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-22 12:50:38 +00:00
3ad27fbe78 [intel] Add PCI ID for Intel X553 0x15e4
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-22 12:42:18 +00:00
b6045a8cbb [efi] Modify global system table when wrapping a loaded image
The EFI loaded image protocol allows an image to be provided with a
custom system table, and we currently use this mechanism to wrap any
boot services calls made by the loaded image in order to provide
strace-like debugging via DEBUG=efi_wrap.

The ExitBootServices() call will modify the global system table,
leaving the loaded image using a system table that is no longer
current.  When DEBUG=efi_wrap is used, this generally results in the
machine locking up at the point that the loaded operating system calls
ExitBootServices().

Fix by modifying the global EFI system table to point to our wrapper
functions, instead of providing a custom system table via the loaded
image protocol.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-21 13:34:10 +00:00
51612b6e69 [efi] Do not attempt to use console output after ExitBootServices()
A successful call to ExitBootServices() will result in the EFI console
becoming unusable.  Ensure that the EFI wrapper produces a complete
line of debug output before calling the wrapped ExitBootServices()
method, and attempt subsequent debug output only if the call fails.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-21 13:24:24 +00:00
236299baa3 [xhci] Avoid DMA during shutdown if firmware has disabled bus mastering
On some systems (observed with the Thunderbolt ports on a ThinkPad X1
Extreme Gen3 and a ThinkPad P53), the system firmware will disable bus
mastering on the xHCI controller and all PCI bridges at the point that
ExitBootServices() is called if the IOMMU is enabled.  This leaves the
xHCI controller unable to shut down cleanly since all commands will
fail with a timeout.

Commit 85eb961 ("[xhci] Allow for permanent failure of the command
mechanism") allows us to detect that this has happened and respond
cleanly.  However, some unidentified hardware component (either the
xHCI controller or one of the PCI bridges) seems to manage to enqueue
the attempted DMA operation and eventually complete it after the
operating system kernel has reenabled bus mastering.  This results in
a DMA operation to an area of memory that the hardware is no longer
permitted to access.  On Windows with the Driver Verifier enabled,
this will result in a STOP 0xE6 (DRIVER_VERIFIER_DMA_VIOLATION).

Work around this problem by detecting when bus mastering has been
disabled, and immediately failing the device to avoid initiating any
further DMA attempts.

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-12 22:27:25 +00:00
1844aacc83 [uri] Retain original encodings for path, query, and fragment fields
iPXE decodes any percent-encoded characters during the URI parsing
stage, thereby allowing protocol implementations to consume the raw
field values directly without further decoding.

When reconstructing a URI string for use in an HTTP request line, the
percent-encoding is currently reapplied in a reversible way: we
guarantee that our reconstructed URI string could be decoded to give
the same raw field values.

This technically violates RFC3986, which states that "URIs that differ
in the replacement of a reserved character with its corresponding
percent-encoded octet are not equivalent".  Experiments show that
several HTTP server applications will attach meaning to the choice of
whether or not a particular character was percent-encoded, even when
the percent-encoding is unnecessary from the perspective of parsing
the URI into its component fields.

Fix by storing the originally encoded substrings for the path, query,
and fragment fields and using these original encoded versions when
reconstructing a URI string.  The path field is also stored as a
decoded string, for use by protocols such as TFTP that communicate
using raw strings rather than URI-encoded strings.  All other fields
(such as the username and password) continue to be stored only in
their decoded versions since nothing ever needs to know the originally
encoded versions of these fields.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-11-12 09:58:29 +00:00
85eb961bf9 [xhci] Allow for permanent failure of the command mechanism
Some xHCI controllers (observed with the Thunderbolt ports on a
ThinkPad X1 Extreme Gen3 and a ThinkPad P53) seem to suffer a
catastrophic failure at the point that ExitBootServices() is called if
the IOMMU is enabled.  The symptoms appear to be consistent with
another UEFI driver (e.g. the IOMMU driver, or the Thunderbolt driver)
having torn down the DMA mappings, leaving the xHCI controller unable
to write to host memory.  The observable effect is that all commands
fail with a timeout, and attempts to abort command execution similarly
fail since the xHCI controller is unable to report the abort
completion.

Check for failure to abort a command, and respond by performing a full
device reset (as recommended by the xHCI specification) and by marking
the device as permanently failed.

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-10-28 23:18:07 +01:00
f24a2794e1 [virtio] Update driver to use DMA API
Signed-off-by: Aaron Young <aaron.young@oracle.com>
2021-10-28 13:19:30 +01:00
2265a65191 [readline] Extend maximum read line length to 1024 characters
Realistic Linux kernel command lines may exceed our current 256
character limit for interactively edited commands or settings.

Switch from stack allocation to heap allocation, and increase the
limit to 1024 characters.

Requested-by: Matteo Guglielmi <Matteo.Guglielmi@dalco.ch>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-09-10 15:51:14 +01:00
05a76acc6d [ecm] Use ACPI-provided system-specific MAC address if present
Use the "system MAC address" provided within the DSDT/SSDT if such an
address is available and has not already been assigned to a network
device.

Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-09-09 12:56:02 +01:00
91e147213c [ecm] Expose USB vendor/device information to ecm_fetch_mac()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-09-09 12:52:12 +01:00
0cc4c42f0a [acpi] Allow for extraction of a MAC address from the DSDT/SSDT
Some vendors provide a "system MAC address" within the DSDT/SSDT, to
be used to override the MAC address for a USB docking station.

A full implementation would require an ACPI bytecode interpreter,
since at least one OEM allows the MAC address to be constructed by
executable ACPI bytecode (rather than a fixed data structure).

We instead attempt to extract a plausible-looking "_AUXMAC_#.....#"
string that appears shortly after an "AMAC" or "MACA" signature.  This
should work for most implementations encountered in practice.

Debugged-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-09-09 12:18:00 +01:00
02ec659b73 [acpi] Generalise DSDT/SSDT data extraction logic
Allow for the DSDT/SSDT signature-scanning and value extraction code
to be reused for extracting a pass-through MAC address.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-09-08 14:46:30 +01:00
e09e1142a3 [efi] Record cached ProxyDHCPOFFER and PXEBSACK, if present
Commit cd3de55 ("[efi] Record cached DHCPACK from loaded image's
device handle, if present") added the ability for a chainloaded UEFI
iPXE to reuse an IPv4 address and DHCP options previously obtained by
a built-in PXE stack, without needing to perform a second DHCP
request.

Extend this to also record the cached ProxyDHCPOFFER and PXEBSACK
obtained from the EFI_PXE_BASE_CODE_PROTOCOL instance installed on the
loaded image's device handle, if present.

This allows a chainloaded UEFI iPXE to reuse a boot filename or other
options that were provided via a ProxyDHCP or PXE boot server
mechanism, rather than by standard DHCP.

Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-27 13:50:36 +01:00
db6310c3e5 [efi] Use zero for PCI vendor/device IDs when no applicable ID exists
When building an EFI ROM image for which no PCI vendor/device ID is
applicable (e.g. bin-x86_64-efi/ipxe.efirom), the build process will
currently construct a command such as

  ./util/efirom -v -d -c bin-x86_64-efi/ipxe.efidrv \
                         bin-x86_64-efi/ipxe.efirom

which gets interpreted as a vendor ID of "-0xd" (i.e. 0xfff3, after
truncation to 16 bits).

Fix by using an explicit zero ID when no applicable ID exists, as is
already done when constructing BIOS ROM images.

Reported-by: Konstantin Aladyshev <aladyshev22@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-26 15:47:47 +01:00
b33cc1efe3 [build] Fix genfsimg to work with FATDIR with space
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-26 15:34:33 +01:00
4d180be517 [cloud] Retry DHCP aggressively in AWS EC2
The DHCP service in EC2 has been observed to occasionally stop
responding for bursts of several seconds.  This can easily result in a
failed boot, since the current cloud boot script will attempt DHCP
only once.

Work around this problem by retrying DHCP in a fairly tight cycle
within the cloud boot script, and falling back to a reboot after
several failed DHCP attempts.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-20 13:19:15 +01:00
c64dfff0a9 [efi] Match signtool expectations for file alignment
As of commit f1e9e2b ("[efi] Align EFI image sections by page size"),
our SectionAlignment has been increased to 4kB in order to allow for
page-level memory protection to be applied by the UEFI firmware, with
FileAlignment left at 32 bytes.

The PE specification states that the value for FileAlignment "should
be a power of 2 between 512 and 64k, inclusive", and that "if the
SectionAlignment is less than the architecture's page size, then
FileAlignment must match SectionAlignment".

Testing shows that signtool.exe will reject binaries where
FileAlignment is less than 512, unless FileAlignment is equal to
SectionAlignment.  This indicates a somewhat zealous interpretation of
the word "should" in the PE specification.

Work around this interpretation by increasing FileAlignment from 32
bytes to 512 bytes, and add explanatory comments for both
FileAlignment and SectionAlignment.

Debugged-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-15 15:45:24 +01:00
8d08300ad9 [libc] Allow for externally-defined LITTLE_ENDIAN and BIG_ENDIAN constants
When building the Linux userspace binaries, the external system
headers may have already defined values for the __LITTLE_ENDIAN and
__BIG_ENDIAN constants.

Fix by retaining the existing values if already defined, since the
actual values of these constants do not matter.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-15 14:16:17 +01:00
2690f73096 [uri] Make URI schemes case-insensitive
RFC 3986 section 3.1 defines URI schemes as case-insensitive (though
the canonical form is always lowercase).

Use strcasecmp() rather than strcmp() to allow for case insensitivity
in URI schemes.

Requested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-01 16:32:46 +01:00
4aa0375821 [rdc] Add driver for RDC R6040 embedded NIC
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-28 12:32:19 +01:00
5622575c5e [realtek] Work around hardware bug on RTL8211B
The RTL8211B seems to have a bug that prevents the link from coming up
unless the MII_MMD_DATA register is cleared.

The Linux kernel driver applies this workaround (in rtl8211b_resume())
only to the specific RTL8211B PHY model, along with a matching
workaround to set bit 9 of MII_MMD_DATA when suspending the PHY.
Since we have no need to ever suspend the PHY, and since writing a
zero ought to be harmless, we just clear the register unconditionally.

Debugged-by: Nikolay Pertsev <nikolay.p@cos.flag.org>
Tested-by: Nikolay Pertsev <nikolay.p@cos.flag.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-24 12:36:46 +01:00
0688114ea6 [cloud] Show ifstat output after a failed boot attempt
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-23 10:22:38 +01:00
9b6ad2d888 [peerdist] Assume that most recently discovered peer can be reused
The peer discovery time has a significant impact on the overall
PeerDist download speed, since each block requires an individual
discovery attempt.  In most cases, a peer that responds for block N
will turn out to also respond for block N+1.

Assume that the most recently discovered peer (for any block) probably
has a copy of the next block to be discovered, thereby allowing the
peer download attempt to begin immediately.

In the case that this assumption is incorrect, the existing error
recovery path will allow for fallback to newly discovered peers (or to
the origin server).

Suggested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-22 09:45:21 +01:00
51c88a4a62 [build] Fix building on broken versions of GNU binutils
Some versions of GNU objcopy (observed with binutils 2.23.52.0.1 on
CentOS 7.0.1406) document the -D/--enable-deterministic-archives
option but fail to recognise the short form of the option.

Work around this problem by using the long form of the option.

Reported-by: Olaf Hering <olaf@aepfle.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-17 14:37:39 +01:00
bf4ccd4265 [build] Ensure build ID is deterministic
Commit 040cdd0 ("[linux] Add a prefix to all symbols to avoid future
name collisions") unintentionally reintroduced an element of
non-determinism into the build ID, by omitting the -D option when
manipulating the blib.a archive.

Fix by adding the -D option to restore determinism.

Reworded-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-14 14:36:51 +01:00
3c040ad387 [efi] Veto the Itautec Ip4ConfigDxe driver
The Ip4ConfigDxe driver bug that was observed on Dell systems in
commit 64b4452 ("[efi] Blacklist the Dell Ip4ConfigDxe driver") has
also been observed on systems with a manufacturer name of "Itautec
S.A.".  The symptoms of the bug are identical: an attempt to call
DisconnectController() on the LOM device handle will lock up the
system.

Fix by extending the veto to cover the Ip4ConfigDxe driver for this
manufacturer.

Debugged-by: Celso Viana <celso.vianna@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-11 15:14:21 +01:00
3dd1989ac0 [libc] Match standard prototype for putchar()
Reported-by: Bernhard M. Wiedemann <bwiedemann@suse.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-07 13:26:01 +01:00
52300ccf98 [base64] Include terminating NUL within base64 character array
Reported-by: Bernhard M. Wiedemann <bwiedemann@suse.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-07 13:20:02 +01:00
92807f5759 [rndis] Fix size of reserved fields
Most RNDIS data structures include a trailing 4-byte reserved field.
For the REMOTE_NDIS_PACKET_MSG and REMOTE_NDIS_INITIALIZE_CMPLT
structures, this is an 8-byte field instead.

iPXE currently uses incorrect structure definitions with a 4-byte
reserved field in all data structures, resulting in data payloads that
overlap the last 4 bytes of the 8-byte reserved field.

RNDIS uses explicit offsets to locate any data payloads beyond the
message header, and so liberal RNDIS parsers (such as those used in
Hyper-V and in the Linux USB Ethernet gadget driver) are still able to
parse the malformed structures.

A stricter RNDIS parser (such as that found in some older Android
builds that seem to use an out-of-tree USB Ethernet gadget driver) may
reject the malformed structures since the data payload offset is less
than the header length, causing iPXE to be unable to transmit packets.

Fix by correcting the length of the reserved fields.

Debugged-by: Martin Nield <pmn1492@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-07 12:01:10 +01:00
065dce8d59 [ath5k] Avoid returning uninitialised data on EEPROM read errors
Originally-implemented-by: Bernhard M. Wiedemann <bwiedemann@suse.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-04 14:16:44 +01:00
f3f568e382 [crypto] Add memory output constraints for big-integer inline assembly
The ARM versions of the big-integer inline assembly functions include
constraints to indicate that the output value is modified by the
assembly code.  These constraints are not present in the equivalent
code for the x86 versions.

As of GCC 11, this results in the compiler reporting that the output
values may be uninitialized.

Fix by including the relevant memory output constraints.

Reported-by: Christian Hesse <mail@eworm.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-06-03 13:34:14 +01:00
74c54461cb [build] Use SOURCE_DATE_EPOCH for isohybrid MBR ID if it exists
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-24 15:38:54 +01:00
0d68d71519 [build] Use SOURCE_DATE_EPOCH for .iso timestamps if it exists
Originally-implemented-by: Bernhard M. Wiedemann <bwiedemann@suse.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-24 15:30:08 +01:00
e5f0255173 [efi] Provide an "initrd.magic" file for use by UEFI kernels
Provide a file "initrd.magic" via the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
that contains the initrd file as constructed for BIOS bzImage kernels
(including injected files with CPIO headers constructed by iPXE).

This allows BIOS and UEFI kernels to obtain the exact same initramfs
image, by adding "initrd=initrd.magic" to the kernel command line.
For example:

  #!ipxe
  kernel boot/vmlinuz initrd=initrd.magic
  initrd boot/initrd.img
  initrd boot/modules/e1000.ko      /lib/modules/e1000.ko
  initrd boot/modules/af_packet.ko  /lib/modules/af_packet.ko
  boot

Do not include the "initrd.magic" file within the root directory
listing, since doing so would break software such as wimboot that
processes all files within the root directory.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-21 20:18:50 +01:00
ef9953b712 [efi] Allow for non-image-backed virtual files
Restructure the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL implementation to
allow for the existence of virtual files that are not simply backed by
a single underlying image.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-21 16:32:36 +01:00
bfca3db41e [cpio] Split out bzImage initrd CPIO header construction
iPXE will construct CPIO headers for images that have a non-empty
command line, thereby allowing raw images (without CPIO headers) to be
injected into a dynamically constructed initrd.  This feature is
currently implemented within the BIOS-only bzImage format support.

Split out the CPIO header construction logic to allow for reuse in
other contexts such as in a UEFI build.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-21 15:19:38 +01:00
fc8bd4ba1a [x509] Use case-insensitive comparison for certificate names
DNS names are case-insensitive, and RFC 5280 (unlike RFC 3280)
mandates support for case-insensitive name comparison in X.509
certificates.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-18 11:46:28 +01:00
661093054b [libc] Add strncasecmp()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-18 11:45:24 +01:00
059c4dc688 [bnxt] Use hexadecimal values in PCI_ROM entries
Use hexadecimal values instead of macros in PCI_ROM entries so Perl
script can parse them correctly.  Move PCI_ROM entries from header
file to C file.  Integrate bnxt_vf_nics array into PCI_ROM entries by
introducing BNXT_FLAG_PCI_VF flag into driver_data field.  Add
whitespaces in PCI_ROM entries for style consistency.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-17 22:35:53 +01:00
adb2ed907e [intel] Add PCI ID for I219-V and -LM 10 to 15
Signed-off-by: Christian Nilsson <nikize@gmail.com>
2021-05-17 22:29:07 +01:00
d7bc9e9d67 [image] Support archive image formats independently of "imgextract" command
Support for the zlib and gzip archive image formats is currently
included only if the IMAGE_ARCHIVE_CMD is used to enable the
"imgextract" command.

The ability to transparently execute a single-member archive image
without using the "imgextract" command renders this unintuitive: a
user wanting to gain the ability to boot a gzip-compressed kernel
image would expect to have to enable IMAGE_GZIP rather than
IMAGE_ARCHIVE_CMD.

Reverse the inclusion logic, so that archive image formats must now be
enabled explicitly (via IMAGE_GZIP and/or IMAGE_ZLIB), with the
archive image management commands dragged in as needed if any archive
image formats are enabled.  The archive image management commands may
be explicitly disabled via IMAGE_ARCHIVE_CMD if necessary.

This matches the behaviour of IBMGMT_CMD and similar options, where
the relevant commands are included only when something else already
drags in the underlying feature.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-12 14:50:34 +01:00
62f732207e [image] Propagate trust flag to extracted archive images
An extracted image is wholly derived from the original archive image.
If the original archive image has been verified and marked as trusted,
then this trust logically extends to any image extracted from it.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-12 14:14:52 +01:00
191f8825cb [image] Allow single-member archive images to be executed transparently
Provide image_extract_exec() as a helper method to allow single-member
archive images (such as gzip compressed images) to be executed without
an explicit "imgextract" step.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-12 13:57:35 +01:00
a6a8bb1a9a [undi] Read TSC only when profiling
Avoid using the "rdtsc" instruction unless profiling is enabled.  This
allows the non-debug build of the UNDI driver to be used on a CPU such
as a 486 that does not support the TSC.

Reported-by: Nikolai Zhubr <n-a-zhubr@yandex.ru>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-12 11:03:01 +01:00
05fcf1a2f0 [rng] Check for TSC support before using RTC entropy source
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-12 10:24:00 +01:00
13c1abe10a [prefix] Specify i486 architecture for LZMA decompressor
The decompressor uses the i486 "bswap" instruction, but does not
require any instructions that exist only on i586 or above.  Update the
".arch" directive to reflect the requirements of the code as
implemented.

Reported-by: Martin Habets <habetsm.xilinx@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-12 10:09:33 +01:00
866fa1ce76 [gzip] Add support for gzip archive images
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-08 15:34:19 +01:00
d093683d93 [zlib] Add support for zlib archive images
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-08 15:34:19 +01:00
5c9c8d2b9b [image] Add "imgextract" command for extracting archive images
Add the concept of extracting an image from an archive (which could be
a single-file archive such as a gzip-compressed file), along with an
"imgextract" command to expose this functionality to scripts.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-08 15:34:19 +01:00
de4f31cdca [image] Provide image_set_len() utility function
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-08 15:34:19 +01:00
106f4c5391 [cloud] Allow multiple images to be imported simultaneously
Allow both x86_64 and arm64 images to be imported in a single import
command, thereby allowing for e.g.

  make CONFIG=cloud EMBED=config/cloud/aws.ipxe bin/ipxe.usb

  make CONFIG=cloud EMBED=config/cloud/aws.ipxe \
       CROSS=aarch64-linux-gnu- bin-arm64-efi/ipxe.usb

  ../contrib/cloud/aws-import -w amilist.txt -p \
       bin/ipxe.usb bin-arm64-efi/ipxe.usb

This simplifies the process of generating a single amilist.txt file
for inclusion in the documentation at https://ipxe.org/howto/ec2

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-02 12:38:03 +01:00
1dfc05622d [cloud] Attempt to include CPUID_SETTINGS only for x86 builds
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-02 12:38:03 +01:00
438513f6f6 [cloud] Autodetect CPU architecture from AMI disk image
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-02 09:39:10 +01:00
6dad316e66 [cloud] Use a sortable default AMI name
The AWS console user interface provides no convenient way to sort AMIs
by creation date.

Provide a default AMI name constructed from the current date and CPU
architecture, to simplify the task of finding the most recent iPXE AMI
in a given AWS region.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-01 22:08:17 +01:00
e994237c0b [cloud] Add ability to generate Dokuwiki table of AMI images
Add an option to generate the amilist.txt list of current AMI images
as included in the EC2 documentation at https://ipxe.org/howto/ec2

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-05-01 21:36:19 +01:00
323af9ee84 [settings] Add --timeout option to "read" command
Requested-by: Matteo Guglielmi <Matteo.Guglielmi@dalco.ch>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-04-23 12:30:30 +01:00
b2501dd122 [readline] Add an optional timeout to readline_history()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-04-23 12:27:57 +01:00
56f7d44fde [efi] Show ACPI address space descriptor ranges in debug messages
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-04-21 16:13:02 +01:00
3efdbef2f0 [efi] Always map full length of coherent DMA buffer allocation
The EFI PCI API takes a page count as the input to AllocateBuffer()
but a byte count as the input to Map().  There is nothing in the UEFI
specification that requires us to map exactly the allocated length,
and no systems have yet been observed that will fail if the map length
does not exactly match the allocated length.  However, it is plausible
that some implementations may fail if asked to map a length that does
not match the length of the corresponding allocation.

Avoid potential future problems by always mapping the full allocated
length.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-04-20 14:37:08 +01:00
e4afaa2246 [build] Fix genfsimg to build ISO with long filenames
Commit 79c0173 ("[build] Create util/genfsimg for building
filesystem-based images") introduced the new genfsimg, which lacks the
-l option when building ISO files.  This option is required to build
level 2 (long plain) ISO9660 filenames, which are required when using
the .lkrn extensions on older versions of ISOLINUX.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-04-20 13:39:39 +01:00
614d99eba1 [xen] Avoid infinite loop on allocation failure in xenstore_response()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-04-20 13:28:57 +01:00
119 changed files with 3981 additions and 701 deletions

View File

@ -3,14 +3,25 @@
import argparse
from base64 import b64encode
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import date
from hashlib import sha256
from itertools import count
import subprocess
import boto3
BLOCKSIZE = 512 * 1024
def detect_architecture(image):
"""Detect CPU architecture"""
mdir = subprocess.run(['mdir', '-b', '-i', image, '::/EFI/BOOT'],
capture_output=True)
if any(b'BOOTAA64.EFI' in x for x in mdir.stdout.splitlines()):
return 'arm64'
return 'x86_64'
def create_snapshot(region, description, image):
"""Create an EBS snapshot"""
client = boto3.client('ebs', region_name=region)
@ -65,36 +76,64 @@ def import_image(region, name, architecture, image, public):
return image_id
def launch_link(region, image_id):
"""Construct a web console launch link"""
return ("https://console.aws.amazon.com/ec2/v2/home?"
"region=%s#LaunchInstanceWizard:ami=%s" % (region, image_id))
# Parse command-line arguments
parser = argparse.ArgumentParser(description="Import AWS EC2 image (AMI)")
parser.add_argument('--architecture', '-a', default='x86_64',
help="CPU architecture")
parser.add_argument('--name', '-n', required=True,
parser.add_argument('--name', '-n',
help="Image name")
parser.add_argument('--public', '-p', action='store_true',
help="Make image public")
parser.add_argument('--region', '-r', action='append',
help="AWS region(s)")
parser.add_argument('image', help="iPXE disk image")
parser.add_argument('--wiki', '-w', metavar='FILE',
help="Generate Dokuwiki table")
parser.add_argument('image', nargs='+', help="iPXE disk image")
args = parser.parse_args()
# Detect CPU architectures
architectures = {image: detect_architecture(image) for image in args.image}
# Use default name if none specified
if not args.name:
args.name = 'iPXE (%s)' % date.today().strftime('%Y-%m-%d')
# Use all regions if none specified
if not args.region:
args.region = sorted(x['RegionName'] for x in
boto3.client('ec2').describe_regions()['Regions'])
# Use one thread per region to maximise parallelism
with ThreadPoolExecutor(max_workers=len(args.region)) as executor:
# Use one thread per import to maximise parallelism
imports = [(region, image) for region in args.region for image in args.image]
with ThreadPoolExecutor(max_workers=len(imports)) as executor:
futures = {executor.submit(import_image,
region=region,
name=args.name,
architecture=args.architecture,
image=args.image,
public=args.public): region
for region in args.region}
architecture=architectures[image],
image=image,
public=args.public): (region, image)
for region, image in imports}
results = {futures[future]: future.result()
for future in as_completed(futures)}
# Construct Dokuwiki table
wikitab = ["^ AWS region ^ CPU architecture ^ AMI ID ^\n"] + list(
"| ''%s'' | ''%s'' | ''[[%s|%s]]'' |\n" % (
region,
architectures[image],
launch_link(region, results[(region, image)]),
results[(region, image)],
) for region, image in imports)
if args.wiki:
with open(args.wiki, 'wt') as fh:
fh.writelines(wikitab)
# Show created images
for region in args.region:
print("%s: %s" % (region, results[region]))
for region, image in imports:
print("%s %s %s %s" % (
region, image, architectures[image], results[(region, image)]
))

View File

@ -190,7 +190,7 @@ vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
@$(ECHO) ' bin/10222000.rom -- vlance/pcnet32'
@$(ECHO) ' bin/15ad07b0.rom -- vmxnet3'
@$(ECHO)
@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
@$(ECHO) 'For more information, see https://ipxe.org/howto/vmware'
@$(ECHO)
@$(ECHO) '==========================================================='

View File

@ -43,7 +43,8 @@ $(BIN)/%.drv.efi : $(BIN)/%.efidrv
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) -c $< $@
$(Q)$(EFIROM) -v $(firstword $(TGT_PCI_VENDOR) 0) \
-d $(firstword $(TGT_PCI_DEVICE) 0) -c $< $@
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
$(QM)$(ECHO) " [CAB] $@"

View File

@ -918,7 +918,7 @@ $(BIN)/deps/%.d : % $(MAKEDEPS)
# Calculate list of dependency files
#
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS) core/version.c)
autodeps :
@$(ECHO) $(AUTO_DEPS)
VERYCLEANUP += $(BIN)/deps
@ -1167,7 +1167,8 @@ $(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
$(Q)$(RM) $(BLIB)
$(QM)$(ECHO) " [AR] $@"
$(Q)$(AR) rD $@ $(sort $(BLIB_OBJS))
$(Q)$(OBJCOPY) --prefix-symbols=$(SYMBOL_PREFIX) $@
$(Q)$(OBJCOPY) --enable-deterministic-archives \
--prefix-symbols=$(SYMBOL_PREFIX) $@
$(Q)$(RANLIB) -D $@
blib : $(BLIB)
@ -1201,7 +1202,7 @@ endif
# Build version
#
GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(version_DEPS) $(GIT_INDEX)
$(QM)$(ECHO) " [VERSION] $@"
$(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
-DVERSION_MAJOR=$(VERSION_MAJOR) \

View File

@ -136,6 +136,8 @@ SECTIONS {
*(.note.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
/*

View File

@ -100,5 +100,7 @@ SECTIONS {
*(.rel.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
}

View File

@ -75,17 +75,18 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
*
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "mull %4\n\t"
"addl %%eax, (%5,%2,4)\n\t"
"adcl %%edx, 4(%5,%2,4)\n\t"
__asm__ __volatile__ ( "mull %5\n\t"
"addl %%eax, (%6,%2,4)\n\t"
"adcl %%edx, 4(%6,%2,4)\n\t"
"\n1:\n\t"
"adcl $0, 8(%5,%2,4)\n\t"
"adcl $0, 8(%6,%2,4)\n\t"
"inc %2\n\t"
/* Does not affect CF */
"jc 1b\n\t"
: "=&a" ( discard_a ),
"=&d" ( discard_d ),
"=&r" ( index )
"=&r" ( index ),
"+m" ( *result )
: "0" ( multiplicand_element ),
"g" ( multiplier_element ),
"r" ( result_elements ),

View File

@ -104,6 +104,13 @@ static union u_PXENV_ANY __bss16 ( undinet_params );
SEGOFF16_t __bss16 ( undinet_entry_point );
#define undinet_entry_point __use_data16 ( undinet_entry_point )
/* Read TSC in real mode only when profiling */
#if PROFILING
#define RDTSC_IF_PROFILING "rdtsc\n\t"
#else
#define RDTSC_IF_PROFILING ""
#endif
/** IRQ profiler */
static struct profiler undinet_irq_profiler __profiler =
{ .name = "undinet.irq" };
@ -288,14 +295,14 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function,
*/
profile_start ( &profiler->total );
__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
"rdtsc\n\t"
RDTSC_IF_PROFILING
"pushl %%eax\n\t"
"pushw %%es\n\t"
"pushw %%di\n\t"
"pushw %%bx\n\t"
"lcall *undinet_entry_point\n\t"
"movw %%ax, %%bx\n\t"
"rdtsc\n\t"
RDTSC_IF_PROFILING
"addw $6, %%sp\n\t"
"popl %%edx\n\t"
"popl %%ebp\n\t" /* gcc bug */ )

View File

@ -326,32 +326,6 @@ static void bzimage_set_cmdline ( struct image *image,
DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
}
/**
* Parse standalone image command line for cpio parameters
*
* @v image bzImage file
* @v cpio CPIO header
* @v cmdline Command line
*/
static void bzimage_parse_cpio_cmdline ( struct image *image,
struct cpio_header *cpio,
const char *cmdline ) {
char *arg;
char *end;
unsigned int mode;
/* Look for "mode=" */
if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
arg += 5;
mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
if ( *end && ( *end != ' ' ) ) {
DBGC ( image, "bzImage %p strange \"mode=\""
"terminator '%c'\n", image, *end );
}
cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
}
}
/**
* Align initrd length
*
@ -374,11 +348,9 @@ static inline size_t bzimage_align ( size_t len ) {
static size_t bzimage_load_initrd ( struct image *image,
struct image *initrd,
userptr_t address ) {
char *filename = initrd->cmdline;
char *cmdline;
const char *filename = cpio_name ( initrd );
struct cpio_header cpio;
size_t offset;
size_t name_len;
size_t pad_len;
/* Do not include kernel image itself as an initrd */
@ -386,25 +358,7 @@ static size_t bzimage_load_initrd ( struct image *image,
return 0;
/* Create cpio header for non-prebuilt images */
if ( filename && filename[0] ) {
cmdline = strchr ( filename, ' ' );
name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
: strlen ( filename ) ) + 1 /* NUL */ );
memset ( &cpio, '0', sizeof ( cpio ) );
memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
cpio_set_field ( cpio.c_mode, 0100644 );
cpio_set_field ( cpio.c_nlink, 1 );
cpio_set_field ( cpio.c_filesize, initrd->len );
cpio_set_field ( cpio.c_namesize, name_len );
if ( cmdline ) {
bzimage_parse_cpio_cmdline ( image, &cpio,
( cmdline + 1 /* ' ' */ ));
}
offset = ( ( sizeof ( cpio ) + name_len + 0x03 ) & ~0x03 );
} else {
offset = 0;
name_len = 0;
}
offset = cpio_header ( initrd, &cpio );
/* Copy in initrd image body (and cpio header if applicable) */
if ( address ) {
@ -413,7 +367,7 @@ static size_t bzimage_load_initrd ( struct image *image,
memset_user ( address, 0, 0, offset );
copy_to_user ( address, 0, &cpio, sizeof ( cpio ) );
copy_to_user ( address, sizeof ( cpio ), filename,
( name_len - 1 /* NUL (or space) */ ) );
cpio_name_len ( initrd ) );
}
DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
"%s%s\n", image, initrd, user_to_phys ( address, 0 ),

View File

@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
#include <ipxe/init.h>
#include <ipxe/memblock.h>
#include <ipxe/cpio.h>
/** @file
*

View File

@ -25,19 +25,22 @@ typedef uint32_t bigint_element_t;
static inline __attribute__ (( always_inline )) void
bigint_init_raw ( uint32_t *value0, unsigned int size,
const void *data, size_t len ) {
long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
long pad_len = ( sizeof ( *value ) - len );
void *discard_D;
long discard_c;
/* Copy raw data in reverse order, padding with zeros */
__asm__ __volatile__ ( "\n1:\n\t"
"movb -1(%2,%1), %%al\n\t"
"movb -1(%3,%1), %%al\n\t"
"stosb\n\t"
"loop 1b\n\t"
"xorl %%eax, %%eax\n\t"
"mov %3, %1\n\t"
"mov %4, %1\n\t"
"rep stosb\n\t"
: "=&D" ( discard_D ), "=&c" ( discard_c )
: "=&D" ( discard_D ), "=&c" ( discard_c ),
"+m" ( *value )
: "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
"1" ( len )
: "eax" );
@ -53,6 +56,8 @@ bigint_init_raw ( uint32_t *value0, unsigned int size,
static inline __attribute__ (( always_inline )) void
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
long index;
void *discard_S;
long discard_c;
@ -60,11 +65,11 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"lodsl\n\t"
"adcl %%eax, (%3,%0,4)\n\t"
"adcl %%eax, (%4,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&S" ( discard_S ),
"=&c" ( discard_c )
"=&c" ( discard_c ), "+m" ( *value )
: "r" ( value0 ), "1" ( addend0 ), "2" ( size )
: "eax" );
}
@ -79,6 +84,8 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
static inline __attribute__ (( always_inline )) void
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
long index;
void *discard_S;
long discard_c;
@ -86,11 +93,11 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"lodsl\n\t"
"sbbl %%eax, (%3,%0,4)\n\t"
"sbbl %%eax, (%4,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&S" ( discard_S ),
"=&c" ( discard_c )
"=&c" ( discard_c ), "+m" ( *value )
: "r" ( value0 ), "1" ( subtrahend0 ),
"2" ( size )
: "eax" );
@ -104,15 +111,18 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
*/
static inline __attribute__ (( always_inline )) void
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
long index;
long discard_c;
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"rcll $1, (%2,%0,4)\n\t"
"rcll $1, (%3,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&c" ( discard_c )
: "=&r" ( index ), "=&c" ( discard_c ),
"+m" ( *value )
: "r" ( value0 ), "1" ( size ) );
}
@ -124,13 +134,15 @@ bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
*/
static inline __attribute__ (( always_inline )) void
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( void * ) value0 );
long discard_c;
__asm__ __volatile__ ( "clc\n\t"
"\n1:\n\t"
"rcrl $1, -4(%1,%0,4)\n\t"
"rcrl $1, -4(%2,%0,4)\n\t"
"loop 1b\n\t"
: "=&c" ( discard_c )
: "=&c" ( discard_c ), "+m" ( *value )
: "r" ( value0 ), "0" ( size ) );
}
@ -239,6 +251,8 @@ bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
static inline __attribute__ (( always_inline )) void
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
uint32_t *dest0, unsigned int dest_size ) {
bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
( ( void * ) dest0 );
long pad_size = ( dest_size - source_size );
void *discard_D;
void *discard_S;
@ -246,10 +260,10 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
__asm__ __volatile__ ( "rep movsl\n\t"
"xorl %%eax, %%eax\n\t"
"mov %3, %2\n\t"
"mov %4, %2\n\t"
"rep stosl\n\t"
: "=&D" ( discard_D ), "=&S" ( discard_S ),
"=&c" ( discard_c )
"=&c" ( discard_c ), "+m" ( *dest )
: "g" ( pad_size ), "0" ( dest0 ),
"1" ( source0 ), "2" ( source_size )
: "eax" );
@ -266,13 +280,15 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
static inline __attribute__ (( always_inline )) void
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
uint32_t *dest0, unsigned int dest_size ) {
bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
( ( void * ) dest0 );
void *discard_D;
void *discard_S;
long discard_c;
__asm__ __volatile__ ( "rep movsl\n\t"
: "=&D" ( discard_D ), "=&S" ( discard_S ),
"=&c" ( discard_c )
"=&c" ( discard_c ), "+m" ( *dest )
: "0" ( dest0 ), "1" ( source0 ),
"2" ( dest_size )
: "eax" );
@ -289,15 +305,19 @@ bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
static inline __attribute__ (( always_inline )) void
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
void *out, size_t len ) {
struct {
uint8_t bytes[len];
} __attribute__ (( may_alias )) *out_bytes = out;
void *discard_D;
long discard_c;
/* Copy raw data in reverse order */
__asm__ __volatile__ ( "\n1:\n\t"
"movb -1(%2,%1), %%al\n\t"
"movb -1(%3,%1), %%al\n\t"
"stosb\n\t"
"loop 1b\n\t"
: "=&D" ( discard_D ), "=&c" ( discard_c )
: "=&D" ( discard_D ), "=&c" ( discard_c ),
"+m" ( *out_bytes )
: "r" ( value0 ), "0" ( out ), "1" ( len )
: "eax" );
}

View File

@ -11,13 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
/** Minimum alignment for initrds
*
* Some versions of Linux complain about initrds that are not
* page-aligned.
*/
#define INITRD_ALIGN 4096
/** Minimum free space required to reshuffle initrds
*
* Chosen to avoid absurdly long reshuffling times

View File

@ -42,6 +42,9 @@ struct x86_features {
/** Hypervisor is present */
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL
/** TSC is present */
#define CPUID_FEATURES_INTEL_EDX_TSC 0x00000010UL
/** FXSAVE and FXRSTOR are supported */
#define CPUID_FEATURES_INTEL_EDX_FXSR 0x01000000UL

View File

@ -42,6 +42,69 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** _S5_ signature */
#define S5_SIGNATURE ACPI_SIGNATURE ( '_', 'S', '5', '_' )
/**
* Extract \_Sx value from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer
* @ret rc Return status code
*
* In theory, extracting the \_Sx value from the DSDT/SSDT requires a
* full ACPI parser plus some heuristics to work around the various
* broken encodings encountered in real ACPI implementations.
*
* In practice, we can get the same result by scanning through the
* DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
* four bytes, removing any bytes with bit 3 set, and treating
* whatever is left as a little-endian value. This is one of the
* uglier hacks I have ever implemented, but it's still prettier than
* the ACPI specification itself.
*/
static int acpi_extract_sx ( userptr_t zsdt, size_t len, size_t offset,
void *data ) {
unsigned int *sx = data;
uint8_t bytes[4];
uint8_t *byte;
/* Skip signature and package header */
offset += ( 4 /* signature */ + 3 /* package header */ );
/* Sanity check */
if ( ( offset + sizeof ( bytes ) /* value */ ) > len ) {
return -EINVAL;
}
/* Read first four bytes of value */
copy_from_user ( bytes, zsdt, offset, sizeof ( bytes ) );
DBGC ( colour, "ACPI found \\_Sx containing %02x:%02x:%02x:%02x\n",
bytes[0], bytes[1], bytes[2], bytes[3] );
/* Extract \Sx value. There are three potential encodings
* that we might encounter:
*
* - SLP_TYPa, SLP_TYPb, rsvd, rsvd
*
* - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
*
* - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
*
* Since <byteprefix> and <dwordprefix> both have bit 3 set,
* and valid SLP_TYPx must have bit 3 clear (since SLP_TYPx is
* a 3-bit field), we can just skip any bytes with bit 3 set.
*/
byte = bytes;
if ( *byte & 0x08 )
byte++;
*sx = *(byte++);
if ( *byte & 0x08 )
byte++;
*sx |= ( *byte << 8 );
return 0;
}
/**
* Power off the computer using ACPI
*
@ -56,7 +119,7 @@ int acpi_poweroff ( void ) {
unsigned int pm1b_cnt;
unsigned int slp_typa;
unsigned int slp_typb;
int s5;
unsigned int s5;
int rc;
/* Locate FADT */
@ -74,9 +137,8 @@ int acpi_poweroff ( void ) {
pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT );
/* Extract \_S5 from DSDT or any SSDT */
s5 = acpi_sx ( S5_SIGNATURE );
if ( s5 < 0 ) {
rc = s5;
if ( ( rc = acpi_extract ( S5_SIGNATURE, &s5,
acpi_extract_sx ) ) != 0 ) {
DBGC ( colour, "ACPI could not extract \\_S5: %s\n",
strerror ( rc ) );
return rc;

View File

@ -59,7 +59,8 @@ static void cachedhcp_init ( void ) {
}
/* Record cached DHCPACK */
if ( ( rc = cachedhcp_record ( phys_to_user ( cached_dhcpack_phys ),
if ( ( rc = cachedhcp_record ( &cached_dhcpack,
phys_to_user ( cached_dhcpack_phys ),
sizeof ( BOOTPLAYER_t ) ) ) != 0 ) {
DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n",
strerror ( rc ) );

View File

@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <biosint.h>
#include <pic8259.h>
#include <rtc.h>
#include <ipxe/cpuid.h>
#include <ipxe/entropy.h>
/** Maximum time to wait for an RTC interrupt, in milliseconds */
@ -174,8 +175,17 @@ static int rtc_entropy_check ( void ) {
* @ret rc Return status code
*/
static int rtc_entropy_enable ( void ) {
struct x86_features features;
int rc;
/* Check that TSC is supported */
x86_features ( &features );
if ( ! ( features.intel.edx & CPUID_FEATURES_INTEL_EDX_TSC ) ) {
DBGC ( &rtc_flag, "RTC has no TSC\n" );
rc = -ENOTSUP;
goto err_no_tsc;
}
/* Hook ISR and enable RTC interrupts */
rtc_hook_isr();
enable_irq ( RTC_IRQ );
@ -191,6 +201,7 @@ static int rtc_entropy_enable ( void ) {
rtc_disable_int();
disable_irq ( RTC_IRQ );
rtc_unhook_isr();
err_no_tsc:
return rc;
}

View File

@ -47,7 +47,7 @@ static char __bss16_array ( syslinux_version, [32] );
#define syslinux_version __use_data16 ( syslinux_version )
/** The "SYSLINUX" copyright string */
static char __data16_array ( syslinux_copyright, [] ) = " http://ipxe.org";
static char __data16_array ( syslinux_copyright, [] ) = " https://ipxe.org";
#define syslinux_copyright __use_data16 ( syslinux_copyright )
static char __data16_array ( syslinux_configuration_file, [] ) = "";

View File

@ -161,7 +161,7 @@ pnpheader:
/* Manufacturer string */
mfgstr:
.asciz "http://ipxe.org"
.asciz "https://ipxe.org"
.size mfgstr, . - mfgstr
/* Product string
@ -607,7 +607,7 @@ get_pmm_decompress_to:
* strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/branding.h.
*
* While nothing in the GPL prevents you from removing all references
* to iPXE or http://ipxe.org, we prefer you not to do so.
* to iPXE or https://ipxe.org, we prefer you not to do so.
*
* If you have an OEM-mandated branding requirement that cannot be
* satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,

View File

@ -44,7 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
.text
.arch i586
.arch i486
.section ".prefix.lib", "ax", @progbits
#ifdef CODE16

View File

@ -229,6 +229,8 @@ SECTIONS {
*(.einfo.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
/*

View File

@ -24,6 +24,8 @@ SECTIONS {
*(.einfo.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
}

View File

@ -100,5 +100,7 @@ SECTIONS {
*(.rel.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
}

View File

@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#define PRODUCT_NAME ""
#define PRODUCT_SHORT_NAME "iPXE"
#define PRODUCT_URI "http://ipxe.org"
#define PRODUCT_URI "https://ipxe.org"
/*
* Tag line
@ -44,15 +44,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* (e.g. "Permission denied") and a 32-bit error number. This number
* is incorporated into an error URI such as
*
* "No such file or directory (http://ipxe.org/2d0c613b)"
* "No such file or directory (https://ipxe.org/2d0c613b)"
*
* or
*
* "Operation not supported (http://ipxe.org/3c092003)"
* "Operation not supported (https://ipxe.org/3c092003)"
*
* Users may browse to the URI within the error message, which is
* provided by a database running on the iPXE web site
* (http://ipxe.org). This database provides details for all possible
* (https://ipxe.org). This database provides details for all possible
* errors generated by iPXE, including:
*
* - the detailed error message (e.g. "Not an OCSP signing
@ -74,13 +74,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* If you have a customer support team and would like your customers
* to contact your support team for all problems, instead of using the
* existing support infrastructure provided by http://ipxe.org, then
* existing support infrastructure provided by https://ipxe.org, then
* you may define a custom URI to be included within error messages.
*
* Note that the custom URI is a printf() format string which must
* include a format specifier for the 32-bit error number.
*/
#define PRODUCT_ERROR_URI "http://ipxe.org/%08x"
#define PRODUCT_ERROR_URI "https://ipxe.org/%08x"
/*
* Command help messages
@ -88,7 +88,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE command help messages include a URI constructed from the
* command name, such as
*
* "See http://ipxe.org/cmd/vcreate for further information"
* "See https://ipxe.org/cmd/vcreate for further information"
*
* The iPXE web site includes documentation for the commands provided
* by the iPXE shell, including:
@ -113,7 +113,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* If you want to provide your own documentation for all of the
* commands provided by the iPXE shell, rather than using the existing
* support infrastructure provided by http://ipxe.org, then you may
* support infrastructure provided by https://ipxe.org, then you may
* define a custom URI to be included within command help messages.
*
* Note that the custom URI is a printf() format string which must
@ -124,7 +124,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE project and prohibit the alteration or removal of any
* references to "iPXE". ]
*/
#define PRODUCT_COMMAND_URI "http://ipxe.org/cmd/%s"
#define PRODUCT_COMMAND_URI "https://ipxe.org/cmd/%s"
/*
* Setting help messages
@ -132,7 +132,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE setting help messages include a URI constructed from the
* setting name, such as
*
* "http://ipxe.org/cfg/initiator-iqn"
* "https://ipxe.org/cfg/initiator-iqn"
*
* The iPXE web site includes documentation for the settings used by
* iPXE, including:
@ -156,7 +156,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* If you want to provide your own documentation for all of the
* settings used by iPXE, rather than using the existing support
* infrastructure provided by http://ipxe.org, then you may define a
* infrastructure provided by https://ipxe.org, then you may define a
* custom URI to be included within setting help messages.
*
* Note that the custom URI is a printf() format string which must
@ -167,7 +167,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE project and prohibit the alteration or removal of any
* references to "iPXE". ]
*/
#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s"
#define PRODUCT_SETTING_URI "https://ipxe.org/cfg/%s"
/*
* Product security name suffix
*
* Vendors creating signed iPXE binaries must set this to a non-empty
* value (e.g. "2pint").
*/
#define PRODUCT_SBAT_NAME ""
/*
* Product security generation
*
* Vendors creating signed iPXE binaries must set this to a non-zero
* value, and must increment the value whenever a Secure Boot exploit
* is fixed (unless the upstream IPXE_SBAT_GENERATION has already been
* incremented as part of that fix).
*/
#define PRODUCT_SBAT_GENERATION 0
#include <config/local/branding.h>

View File

@ -3,6 +3,22 @@
echo Amazon EC2 - iPXE boot via user-data
echo CPU: ${cpuvendor} ${cpumodel}
ifstat ||
dhcp ||
set attempt:int8 1
:dhcp_retry
echo DHCP attempt ${attempt}
dhcp --timeout 5000 && goto dhcp_ok ||
ifstat ||
inc attempt
iseq ${attempt} 10 || goto dhcp_retry
:dhcp_fail
echo DHCP failed - rebooting
reboot ||
exit
:dhcp_ok
route ||
chain -ar http://169.254.169.254/latest/user-data
chain -ar http://169.254.169.254/latest/user-data ||
ifstat ||
exit

View File

@ -5,4 +5,5 @@ echo CPU: ${cpuvendor} ${cpumodel}
ifstat ||
dhcp ||
route ||
chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot
chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot ||
ifstat ||

View File

@ -1,4 +1,6 @@
/* It can often be useful to know the CPU on which a cloud instance is
* running (e.g. to isolate problems with Azure AMD instances).
*/
#if defined ( __i386__ ) || defined ( __x86_64__ )
#define CPUID_SETTINGS
#endif

View File

@ -182,6 +182,12 @@ REQUIRE_OBJECT ( efi_image );
#ifdef IMAGE_SDI
REQUIRE_OBJECT ( sdi );
#endif
#ifdef IMAGE_ZLIB
REQUIRE_OBJECT ( zlib );
#endif
#ifdef IMAGE_GZIP
REQUIRE_OBJECT ( gzip );
#endif
/*
* Drag in all requested commands

View File

@ -0,0 +1,36 @@
/*
* 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/general.h>
/** @file
*
* Archive image configuration
*
*/
PROVIDE_REQUIRING_SYMBOL();
#ifdef IMAGE_ARCHIVE_CMD
REQUIRE_OBJECT ( image_archive_cmd );
#endif

View File

@ -117,6 +117,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define IMAGE_PNG /* PNG image support */
#define IMAGE_DER /* DER image support */
#define IMAGE_PEM /* PEM image support */
//#define IMAGE_ZLIB /* ZLIB image support */
//#define IMAGE_GZIP /* GZIP image support */
/*
* Command-line commands to include
@ -156,6 +158,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define NTP_CMD /* NTP commands */
//#define CERT_CMD /* Certificate management commands */
//#define IMAGE_MEM_CMD /* Read memory command */
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
/*
* ROM-specific options

View File

@ -169,33 +169,22 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) {
}
/**
* Extract \_Sx value from DSDT/SSDT
* Extract value from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v signature Signature (e.g. "_S5_")
* @ret sx \_Sx value, or negative error
*
* In theory, extracting the \_Sx value from the DSDT/SSDT requires a
* full ACPI parser plus some heuristics to work around the various
* broken encodings encountered in real ACPI implementations.
*
* In practice, we can get the same result by scanning through the
* DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
* four bytes, removing any bytes with bit 3 set, and treating
* whatever is left as a little-endian value. This is one of the
* uglier hacks I have ever implemented, but it's still prettier than
* the ACPI specification itself.
* @v data Data buffer
* @v extract Extraction method
* @ret rc Return status code
*/
static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
static int acpi_zsdt ( userptr_t zsdt, uint32_t signature, void *data,
int ( * extract ) ( userptr_t zsdt, size_t len,
size_t offset, void *data ) ) {
struct acpi_header acpi;
union {
uint32_t dword;
uint8_t byte[4];
} buf;
uint32_t buf;
size_t offset;
size_t len;
unsigned int sx;
uint8_t *byte;
int rc;
/* Read table header */
copy_from_user ( &acpi, zsdt, 0, sizeof ( acpi ) );
@ -203,75 +192,51 @@ static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
/* Locate signature */
for ( offset = sizeof ( acpi ) ;
( ( offset + sizeof ( buf ) /* signature */ + 3 /* pkg header */
+ sizeof ( buf ) /* value */ ) < len ) ;
( ( offset + sizeof ( buf ) /* signature */ ) < len ) ;
offset++ ) {
/* Check signature */
copy_from_user ( &buf, zsdt, offset, sizeof ( buf ) );
if ( buf.dword != cpu_to_le32 ( signature ) )
if ( buf != cpu_to_le32 ( signature ) )
continue;
DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n",
user_to_phys ( zsdt, 0 ), acpi_name ( signature ),
offset );
offset += sizeof ( buf );
/* Read first four bytes of value */
copy_from_user ( &buf, zsdt, ( offset + 3 /* pkg header */ ),
sizeof ( buf ) );
DBGC ( zsdt, "DSDT/SSDT %#08lx found %s containing "
"%02x:%02x:%02x:%02x\n", user_to_phys ( zsdt, 0 ),
acpi_name ( signature ), buf.byte[0], buf.byte[1],
buf.byte[2], buf.byte[3] );
/* Extract \Sx value. There are three potential
* encodings that we might encounter:
*
* - SLP_TYPa, SLP_TYPb, rsvd, rsvd
*
* - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
*
* - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
*
* Since <byteprefix> and <dwordprefix> both have bit
* 3 set, and valid SLP_TYPx must have bit 3 clear
* (since SLP_TYPx is a 3-bit field), we can just skip
* any bytes with bit 3 set.
*/
byte = &buf.byte[0];
if ( *byte & 0x08 )
byte++;
sx = *(byte++);
if ( *byte & 0x08 )
byte++;
sx |= ( *byte << 8 );
return sx;
/* Attempt to extract data */
if ( ( rc = extract ( zsdt, len, offset, data ) ) == 0 )
return 0;
}
return -ENOENT;
}
/**
* Extract \_Sx value from DSDT/SSDT
* Extract value from DSDT/SSDT
*
* @v signature Signature (e.g. "_S5_")
* @ret sx \_Sx value, or negative error
* @v data Data buffer
* @v extract Extraction method
* @ret rc Return status code
*/
int acpi_sx ( uint32_t signature ) {
int acpi_extract ( uint32_t signature, void *data,
int ( * extract ) ( userptr_t zsdt, size_t len,
size_t offset, void *data ) ) {
struct acpi_fadt fadtab;
userptr_t fadt;
userptr_t dsdt;
userptr_t ssdt;
unsigned int i;
int sx;
int rc;
/* Try DSDT first */
fadt = acpi_find ( FADT_SIGNATURE, 0 );
if ( fadt ) {
copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
dsdt = phys_to_user ( fadtab.dsdt );
if ( ( sx = acpi_sx_zsdt ( dsdt, signature ) ) >= 0 )
return sx;
if ( ( rc = acpi_zsdt ( dsdt, signature, data,
extract ) ) == 0 )
return 0;
}
/* Try all SSDTs */
@ -279,11 +244,12 @@ int acpi_sx ( uint32_t signature ) {
ssdt = acpi_find ( SSDT_SIGNATURE, i );
if ( ! ssdt )
break;
if ( ( sx = acpi_sx_zsdt ( ssdt, signature ) ) >= 0 )
return sx;
if ( ( rc = acpi_zsdt ( ssdt, signature, data,
extract ) ) == 0 )
return 0;
}
DBGC ( colour, "ACPI could not find \\_Sx \"%s\"\n",
DBGC ( colour, "ACPI could not find \"%s\"\n",
acpi_name ( signature ) );
return -ENOENT;
}

154
src/core/acpimac.c Normal file
View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2021 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 <string.h>
#include <errno.h>
#include <ipxe/acpi.h>
#include <ipxe/base16.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/acpimac.h>
/** @file
*
* ACPI MAC address
*
*/
/** Colour for debug messages */
#define colour FADT_SIGNATURE
/** AMAC signature */
#define AMAC_SIGNATURE ACPI_SIGNATURE ( 'A', 'M', 'A', 'C' )
/** MACA signature */
#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' )
/** Maximum number of bytes to skip after AMAC/MACA signature
*
* This is entirely empirical.
*/
#define AUXMAC_MAX_SKIP 8
/**
* Extract MAC address from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer
* @ret rc Return status code
*
* Some vendors provide a "system MAC address" within the DSDT/SSDT,
* to be used to override the MAC address for a USB docking station.
*
* A full implementation would require an ACPI bytecode interpreter,
* since at least one OEM allows the MAC address to be constructed by
* executable ACPI bytecode (rather than a fixed data structure).
*
* We instead attempt to extract a plausible-looking "_AUXMAC_#.....#"
* string that appears shortly after an "AMAC" or "MACA" signature.
* This should work for most implementations encountered in practice.
*/
static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
void *data ) {
static const char prefix[9] = "_AUXMAC_#";
uint8_t *hw_addr = data;
size_t skip = 0;
char auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ +
( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ];
char *mac = &auxmac[ sizeof ( prefix ) ];
int decoded_len;
int rc;
/* Skip signature and at least one tag byte */
offset += ( 4 /* signature */ + 1 /* tag byte */ );
/* Scan for "_AUXMAC_#.....#" close to signature */
for ( skip = 0 ;
( ( skip < AUXMAC_MAX_SKIP ) &&
( offset + skip + sizeof ( auxmac ) ) < len ) ;
skip++ ) {
/* Read value */
copy_from_user ( auxmac, zsdt, ( offset + skip ),
sizeof ( auxmac ) );
/* Check for expected format */
if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 )
continue;
if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' )
continue;
if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' )
continue;
DBGC ( colour, "ACPI found MAC string \"%s\"\n", auxmac );
/* Terminate MAC address string */
mac = &auxmac[ sizeof ( prefix ) ];
mac[ ETH_ALEN * 2 ] = '\0';
/* Decode MAC address */
decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN );
if ( decoded_len < 0 ) {
rc = decoded_len;
DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n",
mac, strerror ( rc ) );
return rc;
}
/* Check MAC address validity */
if ( ! is_valid_ether_addr ( hw_addr ) ) {
DBGC ( colour, "ACPI has invalid MAC %s\n",
eth_ntoa ( hw_addr ) );
return -EINVAL;
}
return 0;
}
return -ENOENT;
}
/**
* Extract MAC address from DSDT/SSDT
*
* @v hw_addr MAC address to fill in
* @ret rc Return status code
*/
int acpi_mac ( uint8_t *hw_addr ) {
int rc;
/* Look for an "AMAC" address */
if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
acpi_extract_mac ) ) == 0 )
return 0;
/* Look for a "MACA" address */
if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr,
acpi_extract_mac ) ) == 0 )
return 0;
return -ENOENT;
}

138
src/core/archive.c Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2021 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 <string.h>
#include <errno.h>
#include <ipxe/image.h>
/** @file
*
* Archive images
*
*/
/**
* Extract archive image
*
* @v image Image
* @v name Extracted image name
* @v extracted Extracted image to fill in
* @ret rc Return status code
*/
int image_extract ( struct image *image, const char *name,
struct image **extracted ) {
char *dot;
int rc;
/* Check that this image can be used to extract an archive image */
if ( ! ( image->type && image->type->extract ) ) {
rc = -ENOTSUP;
goto err_unsupported;
}
/* Allocate new image */
*extracted = alloc_image ( image->uri );
if ( ! *extracted ) {
rc = -ENOMEM;
goto err_alloc;
}
/* Set image name */
if ( ( rc = image_set_name ( *extracted,
( name ? name : image->name ) ) ) != 0 ) {
goto err_set_name;
}
/* Strip any archive or compression suffix from implicit name */
if ( ( ! name ) && ( (*extracted)->name ) &&
( ( dot = strrchr ( (*extracted)->name, '.' ) ) != NULL ) ) {
*dot = '\0';
}
/* Try extracting archive image */
if ( ( rc = image->type->extract ( image, *extracted ) ) != 0 ) {
DBGC ( image, "IMAGE %s could not extract image: %s\n",
image->name, strerror ( rc ) );
goto err_extract;
}
/* Register image */
if ( ( rc = register_image ( *extracted ) ) != 0 )
goto err_register;
/* Propagate trust flag */
if ( image->flags & IMAGE_TRUSTED )
image_trust ( *extracted );
/* Drop local reference to image */
image_put ( *extracted );
return 0;
unregister_image ( *extracted );
err_register:
err_extract:
err_set_name:
image_put ( *extracted );
err_alloc:
err_unsupported:
return rc;
}
/**
* Extract and execute image
*
* @v image Image
* @ret rc Return status code
*/
int image_extract_exec ( struct image *image ) {
struct image *extracted;
int rc;
/* Extract image */
if ( ( rc = image_extract ( image, NULL, &extracted ) ) != 0 )
goto err_extract;
/* Set image command line */
if ( ( rc = image_set_cmdline ( extracted, image->cmdline ) ) != 0 )
goto err_set_cmdline;
/* Set auto-unregister flag */
extracted->flags |= IMAGE_AUTO_UNREGISTER;
/* Tail-recurse into extracted image */
return image_exec ( extracted );
err_set_cmdline:
unregister_image ( extracted );
err_extract:
return rc;
}
/* Drag in objects via image_extract() */
REQUIRING_SYMBOL ( image_extract );
/* Drag in archive image formats */
REQUIRE_OBJECT ( config_archive );

View File

@ -36,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
static const char base64[64] =
static const char base64[ 64 + 1 /* NUL */ ] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**

View File

@ -37,29 +37,121 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** A cached DHCP packet */
struct cached_dhcp_packet {
/** Settings block name */
const char *name;
/** DHCP packet (if any) */
struct dhcp_packet *dhcppkt;
};
/** Cached DHCPACK */
static struct dhcp_packet *cached_dhcpack;
struct cached_dhcp_packet cached_dhcpack = {
.name = DHCP_SETTINGS_NAME,
};
/** Cached ProxyDHCPOFFER */
struct cached_dhcp_packet cached_proxydhcp = {
.name = PROXYDHCP_SETTINGS_NAME,
};
/** Cached PXEBSACK */
struct cached_dhcp_packet cached_pxebs = {
.name = PXEBS_SETTINGS_NAME,
};
/** List of cached DHCP packets */
static struct cached_dhcp_packet *cached_packets[] = {
&cached_dhcpack,
&cached_proxydhcp,
&cached_pxebs,
};
/** Colour for debug messages */
#define colour &cached_dhcpack
/**
* Record cached DHCPACK
* Free cached DHCP packet
*
* @v cache Cached DHCP packet
*/
static void cachedhcp_free ( struct cached_dhcp_packet *cache ) {
dhcppkt_put ( cache->dhcppkt );
cache->dhcppkt = NULL;
}
/**
* Apply cached DHCP packet settings
*
* @v cache Cached DHCP packet
* @v netdev Network device, or NULL
* @ret rc Return status code
*/
static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
struct net_device *netdev ) {
struct settings *settings;
int rc;
/* Do nothing if cache is empty */
if ( ! cache->dhcppkt )
return 0;
/* Do nothing unless cached packet's MAC address matches this
* network device, if specified.
*/
if ( netdev ) {
if ( memcmp ( netdev->ll_addr, cache->dhcppkt->dhcphdr->chaddr,
netdev->ll_protocol->ll_addr_len ) != 0 ) {
DBGC ( colour, "CACHEDHCP %s does not match %s\n",
cache->name, netdev->name );
return 0;
}
DBGC ( colour, "CACHEDHCP %s is for %s\n",
cache->name, netdev->name );
}
/* Select appropriate parent settings block */
settings = ( netdev ? netdev_settings ( netdev ) : NULL );
/* Register settings */
if ( ( rc = register_settings ( &cache->dhcppkt->settings, settings,
cache->name ) ) != 0 ) {
DBGC ( colour, "CACHEDHCP %s could not register settings: %s\n",
cache->name, strerror ( rc ) );
return rc;
}
/* Free cached DHCP packet */
cachedhcp_free ( cache );
return 0;
}
/**
* Record cached DHCP packet
*
* @v cache Cached DHCP packet
* @v data DHCPACK packet buffer
* @v max_len Maximum possible length
* @ret rc Return status code
*/
int cachedhcp_record ( userptr_t data, size_t max_len ) {
int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
size_t max_len ) {
struct dhcp_packet *dhcppkt;
struct dhcp_packet *tmp;
struct dhcphdr *dhcphdr;
unsigned int i;
size_t len;
/* Free any existing cached packet */
cachedhcp_free ( cache );
/* Allocate and populate DHCP packet */
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
if ( ! dhcppkt ) {
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
DBGC ( colour, "CACHEDHCP %s could not allocate copy\n",
cache->name );
return -ENOMEM;
}
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
@ -80,10 +172,26 @@ int cachedhcp_record ( userptr_t data, size_t max_len ) {
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
dhcppkt_init ( dhcppkt, dhcphdr, len );
/* Store as cached DHCPACK, and mark original copy as consumed */
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n",
/* Discard duplicate packets, since some PXE stacks (including
* iPXE itself) will report the DHCPACK packet as the PXEBSACK
* if no separate PXEBSACK exists.
*/
for ( i = 0 ; i < ( sizeof ( cached_packets ) /
sizeof ( cached_packets[0] ) ) ; i++ ) {
tmp = cached_packets[i]->dhcppkt;
if ( tmp && ( dhcppkt_len ( tmp ) == len ) &&
( memcmp ( tmp->dhcphdr, dhcppkt->dhcphdr, len ) == 0 ) ) {
DBGC ( colour, "CACHEDHCP %s duplicates %s\n",
cache->name, cached_packets[i]->name );
dhcppkt_put ( dhcppkt );
return -EEXIST;
}
}
/* Store as cached packet */
DBGC ( colour, "CACHEDHCP %s at %#08lx+%#zx/%#zx\n", cache->name,
user_to_phys ( data, 0 ), len, max_len );
cached_dhcpack = dhcppkt;
cache->dhcppkt = dhcppkt;
return 0;
}
@ -94,14 +202,20 @@ int cachedhcp_record ( userptr_t data, size_t max_len ) {
*/
static void cachedhcp_startup ( void ) {
/* If cached DHCP packet was not claimed by any network device
* during startup, then free it.
*/
if ( cached_dhcpack ) {
DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
dhcppkt_put ( cached_dhcpack );
cached_dhcpack = NULL;
/* Apply cached ProxyDHCPOFFER, if any */
cachedhcp_apply ( &cached_proxydhcp, NULL );
/* Apply cached PXEBSACK, if any */
cachedhcp_apply ( &cached_pxebs, NULL );
/* Free any remaining cached packets */
if ( cached_dhcpack.dhcppkt ) {
DBGC ( colour, "CACHEDHCP %s unclaimed\n",
cached_dhcpack.name );
}
cachedhcp_free ( &cached_dhcpack );
cachedhcp_free ( &cached_proxydhcp );
cachedhcp_free ( &cached_pxebs );
}
/** Cached DHCPACK startup function */
@ -117,38 +231,9 @@ struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
* @ret rc Return status code
*/
static int cachedhcp_probe ( struct net_device *netdev ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
int rc;
/* Do nothing unless we have a cached DHCPACK */
if ( ! cached_dhcpack )
return 0;
/* Do nothing unless cached DHCPACK's MAC address matches this
* network device.
*/
if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
ll_protocol->ll_addr_len ) != 0 ) {
DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
netdev->name );
return 0;
}
DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
/* Register as DHCP settings for this network device */
if ( ( rc = register_settings ( &cached_dhcpack->settings,
netdev_settings ( netdev ),
DHCP_SETTINGS_NAME ) ) != 0 ) {
DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
strerror ( rc ) );
return rc;
}
/* Claim cached DHCPACK */
dhcppkt_put ( cached_dhcpack );
cached_dhcpack = NULL;
return 0;
/* Apply cached DHCPACK to network device, if applicable */
return cachedhcp_apply ( &cached_dhcpack, netdev );
}
/** Cached DHCP packet network device driver */

View File

@ -20,11 +20,12 @@ unsigned int console_height = CONSOLE_DEFAULT_HEIGHT;
* Write a single character to each console device
*
* @v character Character to be written
* @ret character Character written
*
* The character is written out to all enabled console devices, using
* each device's console_driver::putchar() method.
*/
void putchar ( int character ) {
int putchar ( int character ) {
struct console_driver *console;
/* Automatic LF -> CR,LF translation */
@ -37,6 +38,8 @@ void putchar ( int character ) {
console->putchar )
console->putchar ( character );
}
return character;
}
/**

View File

@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ipxe/cpio.h>
@ -45,3 +46,87 @@ void cpio_set_field ( char *field, unsigned long value ) {
snprintf ( buf, sizeof ( buf ), "%08lx", value );
memcpy ( field, buf, 8 );
}
/**
* Get CPIO image filename
*
* @v image Image
* @ret len CPIO filename length (0 for no filename)
*/
size_t cpio_name_len ( struct image *image ) {
const char *name = cpio_name ( image );
char *sep;
size_t len;
/* Check for existence of CPIO filename */
if ( ! name )
return 0;
/* Locate separator (if any) */
sep = strchr ( name, ' ' );
len = ( sep ? ( ( size_t ) ( sep - name ) ) : strlen ( name ) );
return len;
}
/**
* Parse CPIO image parameters
*
* @v image Image
* @v cpio CPIO header to fill in
*/
static void cpio_parse_cmdline ( struct image *image,
struct cpio_header *cpio ) {
const char *cmdline;
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;
mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
if ( *end && ( *end != ' ' ) ) {
DBGC ( image, "CPIO %p strange \"mode=\" "
"terminator '%c'\n", image, *end );
}
cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
}
}
/**
* Construct CPIO header for image, if applicable
*
* @v image Image
* @v cpio CPIO header to fill in
* @ret len Length of magic CPIO header (including filename)
*/
size_t cpio_header ( struct image *image, struct cpio_header *cpio ) {
size_t name_len;
size_t len;
/* Get filename length */
name_len = cpio_name_len ( image );
/* Images with no filename are assumed to already be CPIO archives */
if ( ! name_len )
return 0;
/* Construct CPIO header */
memset ( cpio, '0', sizeof ( *cpio ) );
memcpy ( cpio->c_magic, CPIO_MAGIC, sizeof ( cpio->c_magic ) );
cpio_set_field ( cpio->c_mode, 0100644 );
cpio_set_field ( cpio->c_nlink, 1 );
cpio_set_field ( cpio->c_filesize, image->len );
cpio_set_field ( cpio->c_namesize, ( name_len + 1 /* NUL */ ) );
cpio_parse_cmdline ( image, cpio );
/* Calculate total length */
len = ( ( sizeof ( *cpio ) + name_len + 1 /* NUL */ + CPIO_ALIGN - 1 )
& ~( CPIO_ALIGN - 1 ) );
return len;
}

View File

@ -175,6 +175,26 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
return 0;
}
/**
* Set image length
*
* @v image Image
* @v len Length of image data
* @ret rc Return status code
*/
int image_set_len ( struct image *image, size_t len ) {
userptr_t new;
/* (Re)allocate image data */
new = urealloc ( image->data, len );
if ( ! new )
return -ENOMEM;
image->data = new;
image->len = len;
return 0;
}
/**
* Set image data
*
@ -184,17 +204,14 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
* @ret rc Return status code
*/
int image_set_data ( struct image *image, userptr_t data, size_t len ) {
userptr_t new;
int rc;
/* (Re)allocate image data */
new = urealloc ( image->data, len );
if ( ! new )
return -ENOMEM;
image->data = new;
/* Set image length */
if ( ( rc = image_set_len ( image, len ) ) != 0 )
return rc;
/* Copy in new image data */
memcpy_user ( image->data, 0, data, 0, len );
image->len = len;
return 0;
}

View File

@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <ipxe/xfer.h>
#include <ipxe/uri.h>
@ -47,7 +48,7 @@ struct uri_opener * xfer_uri_opener ( const char *scheme ) {
struct uri_opener *opener;
for_each_table_entry ( opener, URI_OPENERS ) {
if ( strcmp ( scheme, opener->scheme ) == 0 )
if ( strcasecmp ( scheme, opener->scheme ) == 0 )
return opener;
}
return NULL;

View File

@ -2199,7 +2199,7 @@ const struct setting_type setting_type_base64 __setting_type = {
};
/**
* Format UUID setting value
* Format UUID/GUID setting value
*
* @v type Setting type
* @v raw Raw setting value
@ -2208,17 +2208,24 @@ const struct setting_type setting_type_base64 __setting_type = {
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int format_uuid_setting ( const struct setting_type *type __unused,
static int format_uuid_setting ( const struct setting_type *type,
const void *raw, size_t raw_len, char *buf,
size_t len ) {
const union uuid *uuid = raw;
union uuid uuid;
/* Range check */
if ( raw_len != sizeof ( *uuid ) )
if ( raw_len != sizeof ( uuid ) )
return -ERANGE;
/* Copy value */
memcpy ( &uuid, raw, sizeof ( uuid ) );
/* Mangle GUID byte ordering */
if ( type == &setting_type_guid )
uuid_mangle ( &uuid );
/* Format value */
return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
}
/** UUID setting type */
@ -2227,6 +2234,12 @@ const struct setting_type setting_type_uuid __setting_type = {
.format = format_uuid_setting,
};
/** GUID setting type */
const struct setting_type setting_type_guid __setting_type = {
.name = "guid",
.format = format_uuid_setting,
};
/**
* Format PCI bus:dev.fn setting value
*

View File

@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
/** @file
@ -205,11 +206,24 @@ int strncmp ( const char *first, const char *second, size_t max ) {
* @ret diff Difference
*/
int strcasecmp ( const char *first, const char *second ) {
return strncasecmp ( first, second, ~( ( size_t ) 0 ) );
}
/**
* Compare case-insensitive strings
*
* @v first First string
* @v second Second string
* @v max Maximum length to compare
* @ret diff Difference
*/
int strncasecmp ( const char *first, const char *second, size_t max ) {
const uint8_t *first_bytes = ( ( const uint8_t * ) first );
const uint8_t *second_bytes = ( ( const uint8_t * ) second );
int diff;
for ( ; ; first_bytes++, second_bytes++ ) {
for ( ; max-- ; first_bytes++, second_bytes++ ) {
diff = ( toupper ( *first_bytes ) -
toupper ( *second_bytes ) );
if ( diff )
@ -217,6 +231,7 @@ int strcasecmp ( const char *first, const char *second ) {
if ( ! *first_bytes )
return 0;
}
return 0;
}
/**

View File

@ -79,12 +79,10 @@ size_t uri_decode ( const char *encoded, void *buf, size_t len ) {
/**
* Decode URI field in-place
*
* @v uri URI
* @v field URI field index
* @v encoded Encoded field, or NULL
*/
static void uri_decode_inplace ( struct uri *uri, unsigned int field ) {
const char *encoded = uri_field ( uri, field );
char *decoded = ( ( char * ) encoded );
static void uri_decode_inplace ( char *encoded ) {
char *decoded = encoded;
size_t len;
/* Do nothing if field is not present */
@ -150,7 +148,7 @@ static int uri_character_escaped ( char c, unsigned int field ) {
* parser but for any other URI parsers (e.g. HTTP query
* string parsers, which care about '=' and '&').
*/
static const char *escaped[URI_FIELDS] = {
static const char *escaped[URI_EPATH] = {
/* Scheme or default: escape everything */
[URI_SCHEME] = "/#:@?=&",
/* Opaque part: escape characters which would affect
@ -172,20 +170,21 @@ static int uri_character_escaped ( char c, unsigned int field ) {
* appears within paths.
*/
[URI_PATH] = "#:@?",
/* Query: escape everything except '/', which
* sometimes appears within queries.
*/
[URI_QUERY] = "#:@?",
/* Fragment: escape everything */
[URI_FRAGMENT] = "/#:@?",
};
return ( /* Always escape non-printing characters and whitespace */
( ! isprint ( c ) ) || ( c == ' ' ) ||
/* Always escape '%' */
( c == '%' ) ||
/* Escape field-specific characters */
strchr ( escaped[field], c ) );
/* Always escape non-printing characters and whitespace */
if ( ( ! isprint ( c ) ) || ( c == ' ' ) )
return 1;
/* Escape nothing else in already-escaped fields */
if ( field >= URI_EPATH )
return 0;
/* Escape '%' and any field-specific characters */
if ( ( c == '%' ) || strchr ( escaped[field], c ) )
return 1;
return 0;
}
/**
@ -262,10 +261,12 @@ static void uri_dump ( const struct uri *uri ) {
DBGC ( uri, " port \"%s\"", uri->port );
if ( uri->path )
DBGC ( uri, " path \"%s\"", uri->path );
if ( uri->query )
DBGC ( uri, " query \"%s\"", uri->query );
if ( uri->fragment )
DBGC ( uri, " fragment \"%s\"", uri->fragment );
if ( uri->epath )
DBGC ( uri, " epath \"%s\"", uri->epath );
if ( uri->equery )
DBGC ( uri, " equery \"%s\"", uri->equery );
if ( uri->efragment )
DBGC ( uri, " efragment \"%s\"", uri->efragment );
if ( uri->params )
DBGC ( uri, " params \"%s\"", uri->params->name );
}
@ -298,17 +299,19 @@ struct uri * parse_uri ( const char *uri_string ) {
char *raw;
char *tmp;
char *path;
char *epath;
char *authority;
size_t raw_len;
unsigned int field;
/* Allocate space for URI struct and a copy of the string */
/* Allocate space for URI struct and two copies of the string */
raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
uri = zalloc ( sizeof ( *uri ) + raw_len );
uri = zalloc ( sizeof ( *uri ) + ( 2 * raw_len ) );
if ( ! uri )
return NULL;
ref_init ( &uri->refcnt, uri_free );
raw = ( ( ( void * ) uri ) + sizeof ( *uri ) );
path = ( raw + raw_len );
/* Copy in the raw string */
memcpy ( raw, uri_string, raw_len );
@ -328,57 +331,62 @@ struct uri * parse_uri ( const char *uri_string ) {
/* Chop off the fragment, if it exists */
if ( ( tmp = strchr ( raw, '#' ) ) ) {
*(tmp++) = '\0';
uri->fragment = tmp;
uri->efragment = tmp;
}
/* Identify absolute/relative URI */
if ( ( tmp = strchr ( raw, ':' ) ) ) {
/* Identify absolute URIs */
epath = raw;
for ( tmp = raw ; ; tmp++ ) {
/* Possible scheme character (for our URI schemes) */
if ( isalpha ( *tmp ) || ( *tmp == '-' ) || ( *tmp == '_' ) )
continue;
/* Invalid scheme character or NUL: is a relative URI */
if ( *tmp != ':' )
break;
/* Absolute URI: identify hierarchical/opaque */
uri->scheme = raw;
*(tmp++) = '\0';
if ( *tmp == '/' ) {
/* Absolute URI with hierarchical part */
path = tmp;
epath = tmp;
} else {
/* Absolute URI with opaque part */
uri->opaque = tmp;
path = NULL;
epath = NULL;
}
} else {
/* Relative URI */
path = raw;
break;
}
/* If we don't have a path (i.e. we have an absolute URI with
* an opaque portion, we're already finished processing
*/
if ( ! path )
if ( ! epath )
goto done;
/* Chop off the query, if it exists */
if ( ( tmp = strchr ( path, '?' ) ) ) {
if ( ( tmp = strchr ( epath, '?' ) ) ) {
*(tmp++) = '\0';
uri->query = tmp;
uri->equery = tmp;
}
/* If we have no path remaining, then we're already finished
* processing.
*/
if ( ! path[0] )
if ( ! epath[0] )
goto done;
/* Identify net/absolute/relative path */
if ( uri->scheme && ( strncmp ( path, "//", 2 ) == 0 ) ) {
if ( uri->scheme && ( strncmp ( epath, "//", 2 ) == 0 ) ) {
/* Net path. If this is terminated by the first '/'
* of an absolute path, then we have no space for a
* terminator after the authority field, so shuffle
* the authority down by one byte, overwriting one of
* the two slashes.
*/
authority = ( path + 2 );
authority = ( epath + 2 );
if ( ( tmp = strchr ( authority, '/' ) ) ) {
/* Shuffle down */
uri->path = tmp;
uri->epath = tmp;
memmove ( ( authority - 1 ), authority,
( tmp - authority ) );
authority--;
@ -386,10 +394,16 @@ struct uri * parse_uri ( const char *uri_string ) {
}
} else {
/* Absolute/relative path */
uri->path = path;
uri->epath = epath;
authority = NULL;
}
/* Create copy of path for decoding */
if ( uri->epath ) {
strcpy ( path, uri->epath );
uri->path = path;
}
/* If we don't have an authority (i.e. we have a non-net
* path), we're already finished processing
*/
@ -421,8 +435,8 @@ struct uri * parse_uri ( const char *uri_string ) {
done:
/* Decode fields in-place */
for ( field = 0 ; field < URI_FIELDS ; field++ )
uri_decode_inplace ( uri, field );
for ( field = 0 ; field < URI_EPATH ; field++ )
uri_decode_inplace ( ( char * ) uri_field ( uri, field ) );
DBGC ( uri, "URI parsed \"%s\" to", uri_string );
uri_dump ( uri );
@ -458,8 +472,8 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
static const char prefixes[URI_FIELDS] = {
[URI_PASSWORD] = ':',
[URI_PORT] = ':',
[URI_QUERY] = '?',
[URI_FRAGMENT] = '#',
[URI_EQUERY] = '?',
[URI_EFRAGMENT] = '#',
};
char prefix;
size_t used = 0;
@ -480,6 +494,10 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
if ( ! uri_field ( uri, field ) )
continue;
/* Skip path field if encoded path is present */
if ( ( field == URI_PATH ) && uri->epath )
continue;
/* Prefix this field, if applicable */
prefix = prefixes[field];
if ( ( field == URI_HOST ) && ( uri->user != NULL ) )
@ -676,6 +694,7 @@ char * resolve_path ( const char *base_path,
struct uri * resolve_uri ( const struct uri *base_uri,
struct uri *relative_uri ) {
struct uri tmp_uri;
char *tmp_epath = NULL;
char *tmp_path = NULL;
struct uri *new_uri;
@ -685,20 +704,27 @@ struct uri * resolve_uri ( const struct uri *base_uri,
/* Mangle URI */
memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
if ( relative_uri->path ) {
tmp_path = resolve_path ( ( base_uri->path ?
base_uri->path : "/" ),
relative_uri->path );
if ( relative_uri->epath ) {
tmp_epath = resolve_path ( ( base_uri->epath ?
base_uri->epath : "/" ),
relative_uri->epath );
if ( ! tmp_epath )
goto err_epath;
tmp_path = strdup ( tmp_epath );
if ( ! tmp_path )
goto err_path;
uri_decode_inplace ( tmp_path );
tmp_uri.epath = tmp_epath;
tmp_uri.path = tmp_path;
tmp_uri.query = relative_uri->query;
tmp_uri.fragment = relative_uri->fragment;
tmp_uri.equery = relative_uri->equery;
tmp_uri.efragment = relative_uri->efragment;
tmp_uri.params = relative_uri->params;
} else if ( relative_uri->query ) {
tmp_uri.query = relative_uri->query;
tmp_uri.fragment = relative_uri->fragment;
} else if ( relative_uri->equery ) {
tmp_uri.equery = relative_uri->equery;
tmp_uri.efragment = relative_uri->efragment;
tmp_uri.params = relative_uri->params;
} else if ( relative_uri->fragment ) {
tmp_uri.fragment = relative_uri->fragment;
} else if ( relative_uri->efragment ) {
tmp_uri.efragment = relative_uri->efragment;
tmp_uri.params = relative_uri->params;
} else if ( relative_uri->params ) {
tmp_uri.params = relative_uri->params;
@ -707,7 +733,14 @@ struct uri * resolve_uri ( const struct uri *base_uri,
/* Create demangled URI */
new_uri = uri_dup ( &tmp_uri );
free ( tmp_path );
free ( tmp_epath );
return new_uri;
free ( tmp_path );
err_path:
free ( tmp_epath );
err_epath:
return NULL;
}
/**
@ -746,6 +779,7 @@ static struct uri * tftp_uri ( struct sockaddr *sa_server,
if ( asprintf ( &path, "/%s", filename ) < 0 )
goto err_path;
tmp.path = path;
tmp.epath = path;
/* Demangle URI */
uri = uri_dup ( &tmp );

View File

@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <wchar.h>
#include <ipxe/features.h>
#include <ipxe/version.h>
#include <ipxe/sbat.h>
#include <config/general.h>
#include <config/branding.h>
@ -92,3 +93,32 @@ const wchar_t build_wname[] = WSTRING ( BUILD_NAME );
/** Copy of build name string within ".prefix" */
const char build_name_prefix[] __attribute__ (( section ( ".prefix.name" ) ))
= BUILD_NAME;
/** SBAT upstream iPXE line
*
* This line represents the security generation of the upstream
* codebase from which this build is derived.
*/
#define SBAT_IPXE \
SBAT_LINE ( "ipxe", IPXE_SBAT_GENERATION, \
"iPXE", BUILD_NAME, VERSION, "https://ipxe.org" )
/** SBAT local build line
*
* This line states the security generation of the local build, which
* may include non-default features or non-upstreamed modifications.
*/
#if PRODUCT_SBAT_GENERATION
#define SBAT_PRODUCT \
SBAT_LINE ( "ipxe." PRODUCT_SBAT_NAME, PRODUCT_SBAT_GENERATION, \
PRODUCT_SHORT_NAME, BUILD_NAME, VERSION, \
PRODUCT_URI )
#else
#define SBAT_PRODUCT ""
#endif
/** SBAT data */
#define SBAT_DATA SBAT_HEADER "" SBAT_IPXE "" SBAT_PRODUCT
/** SBAT data (without any NUL terminator) */
const char sbat[ sizeof ( SBAT_DATA ) - 1 ] __sbat = SBAT_DATA;

View File

@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/list.h>
@ -1464,7 +1465,7 @@ static int x509_check_dnsname ( struct x509_certificate *cert,
/* Compare names */
if ( ! ( ( strlen ( name ) == len ) &&
( memcmp ( name, dnsname, len ) == 0 ) ) )
( strncasecmp ( name, dnsname, len ) == 0 ) ) )
return -ENOENT;
if ( name != fullname ) {

View File

@ -17,37 +17,47 @@
#include "ipxe/io.h"
#include "ipxe/iomap.h"
#include "ipxe/pci.h"
#include "ipxe/dma.h"
#include "ipxe/reboot.h"
#include "ipxe/virtio-pci.h"
#include "ipxe/virtio-ring.h"
static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num)
static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num, size_t header_size)
{
size_t queue_size = PAGE_MASK + vring_size(num);
size_t ring_size = PAGE_MASK + vring_size(num);
size_t vdata_size = num * sizeof(void *);
size_t queue_size = ring_size + vdata_size + header_size;
vq->queue = zalloc(queue_size + vdata_size);
vq->queue = dma_alloc(vq->dma, &vq->map, queue_size, queue_size);
if (!vq->queue) {
return -ENOMEM;
}
memset ( vq->queue, 0, queue_size );
vq->queue_size = queue_size;
/* vdata immediately follows the ring */
vq->vdata = (void **)(vq->queue + queue_size);
vq->vdata = (void **)(vq->queue + ring_size);
/* empty header immediately follows vdata */
vq->empty_header = (struct virtio_net_hdr_modern *)(vq->queue + ring_size + vdata_size);
return 0;
}
void vp_free_vq(struct vring_virtqueue *vq)
{
if (vq->queue) {
free(vq->queue);
if (vq->queue && vq->queue_size) {
dma_free(&vq->map, vq->queue, vq->queue_size);
vq->queue = NULL;
vq->vdata = NULL;
vq->queue_size = 0;
}
}
int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq)
struct vring_virtqueue *vq, struct dma_device *dma_dev,
size_t header_size)
{
struct vring * vr = &vq->vring;
u16 num;
@ -73,9 +83,10 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
}
vq->queue_index = queue_index;
vq->dma = dma_dev;
/* initialize the queue */
rc = vp_alloc_vq(vq, num);
rc = vp_alloc_vq(vq, num, header_size);
if (rc) {
DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n");
return rc;
@ -87,8 +98,7 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
* NOTE: vr->desc is initialized by vring_init()
*/
outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
ioaddr + VIRTIO_PCI_QUEUE_PFN);
outl(dma(&vq->map, vr->desc) >> PAGE_SHIFT, ioaddr + VIRTIO_PCI_QUEUE_PFN);
return num;
}
@ -348,7 +358,8 @@ void vpm_notify(struct virtio_pci_modern_device *vdev,
}
int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
unsigned nvqs, struct vring_virtqueue *vqs)
unsigned nvqs, struct vring_virtqueue *vqs,
struct dma_device *dma_dev, size_t header_size)
{
unsigned i;
struct vring_virtqueue *vq;
@ -392,11 +403,12 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
vq = &vqs[i];
vq->queue_index = i;
vq->dma = dma_dev;
/* get offset of notification word for this vq */
off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off));
err = vp_alloc_vq(vq, size);
err = vp_alloc_vq(vq, size, header_size);
if (err) {
DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev);
return err;
@ -406,13 +418,16 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
/* activate the queue */
vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size));
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.desc),
vpm_iowrite64(vdev, &vdev->common,
dma(&vq->map, vq->vring.desc),
COMMON_OFFSET(queue_desc_lo),
COMMON_OFFSET(queue_desc_hi));
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.avail),
vpm_iowrite64(vdev, &vdev->common,
dma(&vq->map, vq->vring.avail),
COMMON_OFFSET(queue_avail_lo),
COMMON_OFFSET(queue_avail_hi));
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.used),
vpm_iowrite64(vdev, &vdev->common,
dma(&vq->map, vq->vring.used),
COMMON_OFFSET(queue_used_lo),
COMMON_OFFSET(queue_used_hi));

View File

@ -98,7 +98,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
for (i = head; out; i = vr->desc[i].next, out--) {
vr->desc[i].flags = VRING_DESC_F_NEXT;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].addr = list->addr;
vr->desc[i].len = list->length;
prev = i;
list++;
@ -106,7 +106,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
for ( ; in; i = vr->desc[i].next, in--) {
vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].addr = list->addr;
vr->desc[i].len = list->length;
prev = i;
list++;

View File

@ -39,6 +39,9 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
{
u32 status, timeout;
/* Avoid returning uninitialised data on error */
*data = 0xffff;
/*
* Initialize EEPROM access
*/

View File

@ -23,16 +23,74 @@ static void bnxt_adv_cq_index ( struct bnxt *bp, u16 cnt );
static int bnxt_rx_complete ( struct net_device *dev, struct rx_pkt_cmpl *rx );
void bnxt_link_evt ( struct bnxt *bp, struct hwrm_async_event_cmpl *evt );
static struct pci_device_id bnxt_nics[] = {
PCI_ROM( 0x14e4, 0x16c0, "14e4-16C0", "14e4-16C0", 0 ),
PCI_ROM( 0x14e4, 0x16c1, "14e4-16C1", "14e4-16C1", BNXT_FLAG_PCI_VF ),
PCI_ROM( 0x14e4, 0x16c8, "14e4-16C8", "14e4-16C8", 0 ),
PCI_ROM( 0x14e4, 0x16c9, "14e4-16C9", "14e4-16C9", 0 ),
PCI_ROM( 0x14e4, 0x16ca, "14e4-16CA", "14e4-16CA", 0 ),
PCI_ROM( 0x14e4, 0x16cc, "14e4-16CC", "14e4-16CC", 0 ),
PCI_ROM( 0x14e4, 0x16cd, "14e4-16CD", "14e4-16CD", 0 ),
PCI_ROM( 0x14e4, 0x16ce, "14e4-16CE", "14e4-16CE", 0 ),
PCI_ROM( 0x14e4, 0x16cf, "14e4-16CF", "14e4-16CF", 0 ),
PCI_ROM( 0x14e4, 0x16d0, "14e4-16D0", "14e4-16D0", 0 ),
PCI_ROM( 0x14e4, 0x16d1, "14e4-16D1", "14e4-16D1", 0 ),
PCI_ROM( 0x14e4, 0x16d2, "14e4-16D2", "14e4-16D2", 0 ),
PCI_ROM( 0x14e4, 0x16d4, "14e4-16D4", "14e4-16D4", 0 ),
PCI_ROM( 0x14e4, 0x16d5, "14e4-16D5", "14e4-16D5", 0 ),
PCI_ROM( 0x14e4, 0x16d6, "14e4-16D6", "14e4-16D6", 0 ),
PCI_ROM( 0x14e4, 0x16d7, "14e4-16D7", "14e4-16D7", 0 ),
PCI_ROM( 0x14e4, 0x16d8, "14e4-16D8", "14e4-16D8", 0 ),
PCI_ROM( 0x14e4, 0x16d9, "14e4-16D9", "14e4-16D9", 0 ),
PCI_ROM( 0x14e4, 0x16da, "14e4-16DA", "14e4-16DA", 0 ),
PCI_ROM( 0x14e4, 0x16db, "14e4-16DB", "14e4-16DB", 0 ),
PCI_ROM( 0x14e4, 0x16dc, "14e4-16DC", "14e4-16DC", BNXT_FLAG_PCI_VF ),
PCI_ROM( 0x14e4, 0x16de, "14e4-16DE", "14e4-16DE", 0 ),
PCI_ROM( 0x14e4, 0x16df, "14e4-16DF", "14e4-16DF", 0 ),
PCI_ROM( 0x14e4, 0x16e0, "14e4-16E0", "14e4-16E0", 0 ),
PCI_ROM( 0x14e4, 0x16e2, "14e4-16E2", "14e4-16E2", 0 ),
PCI_ROM( 0x14e4, 0x16e3, "14e4-16E3", "14e4-16E3", 0 ),
PCI_ROM( 0x14e4, 0x16e4, "14e4-16E4", "14e4-16E4", 0 ),
PCI_ROM( 0x14e4, 0x16e7, "14e4-16E7", "14e4-16E7", 0 ),
PCI_ROM( 0x14e4, 0x16e8, "14e4-16E8", "14e4-16E8", 0 ),
PCI_ROM( 0x14e4, 0x16e9, "14e4-16E9", "14e4-16E9", 0 ),
PCI_ROM( 0x14e4, 0x16ea, "14e4-16EA", "14e4-16EA", 0 ),
PCI_ROM( 0x14e4, 0x16eb, "14e4-16EB", "14e4-16EB", 0 ),
PCI_ROM( 0x14e4, 0x16ec, "14e4-16EC", "14e4-16EC", 0 ),
PCI_ROM( 0x14e4, 0x16ed, "14e4-16ED", "14e4-16ED", 0 ),
PCI_ROM( 0x14e4, 0x16ee, "14e4-16EE", "14e4-16EE", 0 ),
PCI_ROM( 0x14e4, 0x16ef, "14e4-16EF", "14e4-16EF", 0 ),
PCI_ROM( 0x14e4, 0x16f0, "14e4-16F0", "14e4-16F0", 0 ),
PCI_ROM( 0x14e4, 0x16f1, "14e4-16F1", "14e4-16F1", 0 ),
PCI_ROM( 0x14e4, 0x1604, "14e4-1604", "14e4-1604", 0 ),
PCI_ROM( 0x14e4, 0x1605, "14e4-1605", "14e4-1605", 0 ),
PCI_ROM( 0x14e4, 0x1606, "14e4-1606", "14e4-1606", 0 ),
PCI_ROM( 0x14e4, 0x1609, "14e4-1609", "14e4-1609", 0 ),
PCI_ROM( 0x14e4, 0x1614, "14e4-1614", "14e4-1614", 0 ),
PCI_ROM( 0x14e4, 0xd802, "14e4-D802", "14e4-D802", 0 ),
PCI_ROM( 0x14e4, 0xd804, "14e4-D804", "14e4-D804", 0 ),
PCI_ROM( 0x14e4, 0x1750, "14e4-1750", "14e4-1750", 0 ),
PCI_ROM( 0x14e4, 0x1802, "14e4-1802", "14e4-1802", 0 ),
PCI_ROM( 0x14e4, 0x1805, "14e4-1805", "14e4-1805", 0 ),
PCI_ROM( 0x14e4, 0x1751, "14e4-1751", "14e4-1751", 0 ),
PCI_ROM( 0x14e4, 0x1801, "14e4-1801", "14e4-1801", 0 ),
PCI_ROM( 0x14e4, 0x1804, "14e4-1804", "14e4-1804", 0 ),
PCI_ROM( 0x14e4, 0x1752, "14e4-1752", "14e4-1752", 0 ),
PCI_ROM( 0x14e4, 0x1800, "14e4-1800", "14e4-1800", 0 ),
PCI_ROM( 0x14e4, 0x1803, "14e4-1803", "14e4-1803", 0 ),
PCI_ROM( 0x14e4, 0x1806, "14e4-1806", "14e4-1806", BNXT_FLAG_PCI_VF ),
PCI_ROM( 0x14e4, 0x1807, "14e4-1807", "14e4-1807", BNXT_FLAG_PCI_VF ),
PCI_ROM( 0x14e4, 0x1808, "14e4-1808", "14e4-1808", BNXT_FLAG_PCI_VF ),
PCI_ROM( 0x14e4, 0x1809, "14e4-1809", "14e4-1809", BNXT_FLAG_PCI_VF ),
};
/**
* Check if Virtual Function
*/
u8 bnxt_is_pci_vf ( struct pci_device *pdev )
{
u16 i;
for ( i = 0; i < ARRAY_SIZE ( bnxt_vf_nics ); i++ ) {
if ( pdev->device == bnxt_vf_nics[i] )
return 1;
if ( FLAG_TEST ( pdev->id->driver_data, BNXT_FLAG_PCI_VF ) ) {
return 1;
}
return 0;
}

View File

@ -51,6 +51,7 @@ union dma_addr64_t {
#define BNXT_FLAG_MULTI_HOST 0x0008
#define BNXT_FLAG_NPAR_MODE 0x0010
#define BNXT_FLAG_ATOMICS_ENABLE 0x0020
#define BNXT_FLAG_PCI_VF 0x0040
/*******************************************************************************
* Status codes.
******************************************************************************/
@ -867,140 +868,4 @@ struct bnxt {
FUNC_VF_CFG_REQ_ENABLES_ASYNC_EVENT_CR | \
FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR)
/* Device ID's */
#define PCI_VID_BCOM 0x14e4
#define CHIP_NUM_57500 0x1750
#define DID_57508 0x1750
#define DID_57508_MF 0x1802
#define DID_57508_MF_RDMA 0x1805
#define DID_57504 0x1751
#define DID_57504_MF 0x1801
#define DID_57504_MF_RDMA 0x1804
#define DID_57502 0x1752
#define DID_57502_MF 0x1800
#define DID_57502_MF_RDMA 0x1803
#define DID_57508_VF 0x1806
#define DID_57508_VF_RDMA 0x1807
#define DID_57508_VF_HV 0x1806
#define DID_57508_VF_RDMA_HV 0x1807
/* Stratus Device IDs */
#define DID_57320_1 0x16F0
#define DID_57320_2 0x16F1
#define DID_57454_MHB 0x1604
#define DID_57454_MHB_RDMA 0x1605
#define DID_57454_VF_RDMA 0x1606
#define DID_57454_VF 0x1609
#define DID_57454 0x1614
#define DID_58802 0xD802
#define DID_58804 0xD804
#define DID_57417_RDMA_MF 0x16C0
#define DID_57417_VF_RDMA 0x16c1
#define DID_57301 0x16C8
#define DID_57302 0x16C9
#define DID_57304 0x16CA
#define DID_57417_MF 0x16CC
#define DID_58700 0x16CD
#define DID_57311 0x16CE
#define DID_57312 0x16CF
#define DID_57402 0x16D0
#define DID_57404 0x16D1
#define DID_57406 0x16D2
#define DID_57402_MF 0x16D4
#define DID_57407C 0x16D5
#define DID_57412 0x16D6
#define DID_57414 0x16D7
#define DID_57416C 0x16D8
#define DID_57417C 0x16D9
#define DID_57402L 0x16DA
#define DID_57404L 0x16DB
#define DID_57417_VF 0x16dc
#define DID_57412_MF 0x16DE
#define DID_57314 0x16DF
#define DID_57317C 0x16E0
#define DID_57417F 0x16E2
#define DID_57416F 0x16E3
#define DID_57317F 0x16E4
#define DID_57404_MF 0x16E7
#define DID_57406_MF 0x16E8
#define DID_57407F 0x16E9
#define DID_57407_MF 0x16EA
#define DID_57412_RDMA_MF 0x16EB
#define DID_57414_MF 0x16EC
#define DID_57414_RDMA_MF 0x16ED
#define DID_57416_MF 0x16EE
#define DID_57416_RDMA_MF 0x16EF
static struct pci_device_id bnxt_nics[] = {
PCI_ROM(PCI_VID_BCOM, DID_57417_RDMA_MF, "14e4-16C0", "14e4-16C0", 0),
PCI_ROM(PCI_VID_BCOM, DID_57417_VF_RDMA, "14e4-16C1", "14e4-16C1", 0),
PCI_ROM(PCI_VID_BCOM, DID_57301, "14e4-16C8", "14e4-16C8", 0),
PCI_ROM(PCI_VID_BCOM, DID_57302, "14e4-16C9", "14e4-16C9", 0),
PCI_ROM(PCI_VID_BCOM, DID_57304, "14e4-16CA", "14e4-16CA", 0),
PCI_ROM(PCI_VID_BCOM, DID_57417_MF, "14e4-16CC", "14e4-16CC", 0),
PCI_ROM(PCI_VID_BCOM, DID_58700, "14e4-16CD", "14e4-16CD", 0),
PCI_ROM(PCI_VID_BCOM, DID_57311, "14e4-16CE", "14e4-16CE", 0),
PCI_ROM(PCI_VID_BCOM, DID_57312, "14e4-16CF", "14e4-16CF", 0),
PCI_ROM(PCI_VID_BCOM, DID_57402, "14e4-16D0", "14e4-16D0", 0),
PCI_ROM(PCI_VID_BCOM, DID_57404, "14e4-16D1", "14e4-16D1", 0),
PCI_ROM(PCI_VID_BCOM, DID_57406, "14e4-16D2", "14e4-16D2", 0),
PCI_ROM(PCI_VID_BCOM, DID_57402_MF, "14e4-16D4", "14e4-16D4", 0),
PCI_ROM(PCI_VID_BCOM, DID_57407C, "14e4-16D5", "14e4-16D5", 0),
PCI_ROM(PCI_VID_BCOM, DID_57412, "14e4-16D6", "14e4-16D6", 0),
PCI_ROM(PCI_VID_BCOM, DID_57414, "14e4-16D7", "14e4-16D7", 0),
PCI_ROM(PCI_VID_BCOM, DID_57416C, "14e4-16D8", "14e4-16D8", 0),
PCI_ROM(PCI_VID_BCOM, DID_57417C, "14e4-16D9", "14e4-16D9", 0),
PCI_ROM(PCI_VID_BCOM, DID_57402L, "14e4-16DA", "14e4-16DA", 0),
PCI_ROM(PCI_VID_BCOM, DID_57404L, "14e4-16DB", "14e4-16DB", 0),
PCI_ROM(PCI_VID_BCOM, DID_57417_VF, "14e4-16DC", "14e4-16DC", 0),
PCI_ROM(PCI_VID_BCOM, DID_57412_MF, "14e4-16DE", "14e4-16DE", 0),
PCI_ROM(PCI_VID_BCOM, DID_57314, "14e4-16DF", "14e4-16DF", 0),
PCI_ROM(PCI_VID_BCOM, DID_57317C, "14e4-16E0", "14e4-16E0", 0),
PCI_ROM(PCI_VID_BCOM, DID_57417F, "14e4-16E2", "14e4-16E2", 0),
PCI_ROM(PCI_VID_BCOM, DID_57416F, "14e4-16E3", "14e4-16E3", 0),
PCI_ROM(PCI_VID_BCOM, DID_57317F, "14e4-16E4", "14e4-16E4", 0),
PCI_ROM(PCI_VID_BCOM, DID_57404_MF, "14e4-16E7", "14e4-16E7", 0),
PCI_ROM(PCI_VID_BCOM, DID_57406_MF, "14e4-16E8", "14e4-16E8", 0),
PCI_ROM(PCI_VID_BCOM, DID_57407F, "14e4-16E9", "14e4-16E9", 0),
PCI_ROM(PCI_VID_BCOM, DID_57407_MF, "14e4-16EA", "14e4-16EA", 0),
PCI_ROM(PCI_VID_BCOM, DID_57412_RDMA_MF, "14e4-16EB", "14e4-16EB", 0),
PCI_ROM(PCI_VID_BCOM, DID_57414_MF, "14e4-16EC", "14e4-16EC", 0),
PCI_ROM(PCI_VID_BCOM, DID_57414_RDMA_MF, "14e4-16ED", "14e4-16ED", 0),
PCI_ROM(PCI_VID_BCOM, DID_57416_MF, "14e4-16EE", "14e4-16EE", 0),
PCI_ROM(PCI_VID_BCOM, DID_57416_RDMA_MF, "14e4-16EF", "14e4-16EF", 0),
PCI_ROM(PCI_VID_BCOM, DID_57320_1, "14e4-16F0", "14e4-16F0", 0),
PCI_ROM(PCI_VID_BCOM, DID_57320_2, "14e4-16F1", "14e4-16F1", 0),
PCI_ROM(PCI_VID_BCOM, DID_57454_MHB, "14e4-1604", "14e4-1604", 0),
PCI_ROM(PCI_VID_BCOM, DID_57454_MHB_RDMA, "14e4-1605", "14e4-1605", 0),
PCI_ROM(PCI_VID_BCOM, DID_57454_VF_RDMA, "14e4-1606", "14e4-1606", 0),
PCI_ROM(PCI_VID_BCOM, DID_57454_VF, "14e4-1609", "14e4-1609", 0),
PCI_ROM(PCI_VID_BCOM, DID_57454, "14e4-1614", "14e4-1614", 0),
PCI_ROM(PCI_VID_BCOM, DID_58802, "14e4-D802", "14e4-D802", 0),
PCI_ROM(PCI_VID_BCOM, DID_58804, "14e4-D804", "14e4-D804", 0),
PCI_ROM(PCI_VID_BCOM, DID_57508, "14e4-1750", "14e4-1750", 0),
PCI_ROM(PCI_VID_BCOM, DID_57508_MF, "14e4-1802", "14e4-1802", 0),
PCI_ROM(PCI_VID_BCOM, DID_57508_MF_RDMA, "14e4-1805", "14e4-1805", 0),
PCI_ROM(PCI_VID_BCOM, DID_57504, "14e4-1751", "14e4-1751", 0),
PCI_ROM(PCI_VID_BCOM, DID_57504_MF, "14e4-1801", "14e4-1801", 0),
PCI_ROM(PCI_VID_BCOM, DID_57504_MF_RDMA, "14e4-1804", "14e4-1804", 0),
PCI_ROM(PCI_VID_BCOM, DID_57502, "14e4-1752", "14e4-1752", 0),
PCI_ROM(PCI_VID_BCOM, DID_57502_MF, "14e4-1800", "14e4-1800", 0),
PCI_ROM(PCI_VID_BCOM, DID_57502_MF_RDMA, "14e4-1803", "14e4-1803", 0),
PCI_ROM(PCI_VID_BCOM, DID_57508_VF, "14e4-1806", "14e4-1806", 0),
PCI_ROM(PCI_VID_BCOM, DID_57508_VF_RDMA, "14e4-1807", "14e4-1807", 0),
PCI_ROM(PCI_VID_BCOM, DID_57508_VF_HV, "14e4-1808", "14e4-1808", 0),
PCI_ROM(PCI_VID_BCOM,
DID_57508_VF_RDMA_HV, "14e4-1809", "14e4-1809", 0),
};
static u16 bnxt_vf_nics[] = {
DID_57508_VF,
DID_57508_VF_RDMA,
DID_57508_VF_HV,
DID_57508_VF_RDMA_HV,
DID_57417_VF,
DID_57417_VF_RDMA,
};

View File

@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/if_ether.h>
#include <ipxe/base16.h>
#include <ipxe/profile.h>
#include <ipxe/acpimac.h>
#include <ipxe/usb.h>
#include "ecm.h"
@ -81,17 +82,26 @@ ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
/**
* Get hardware MAC address
*
* @v usb USB device
* @v func USB function
* @v desc Ethernet functional descriptor
* @v hw_addr Hardware address to fill in
* @ret rc Return status code
*/
int ecm_fetch_mac ( struct usb_device *usb,
int ecm_fetch_mac ( struct usb_function *func,
struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
struct usb_device *usb = func->usb;
char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
int len;
int rc;
/* Use system-specific MAC address, if present and not already used */
if ( ( ( rc = acpi_mac ( hw_addr ) ) == 0 ) &&
! find_netdev_by_ll_addr ( &ethernet_protocol, hw_addr ) ) {
DBGC ( usb, "USB %s using system-specific MAC %s\n",
func->name, eth_ntoa ( hw_addr ) );
return 0;
}
/* Fetch MAC address string */
len = usb_get_string_descriptor ( usb, desc->mac, 0, buf,
sizeof ( buf ) );
@ -103,7 +113,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
/* Sanity check */
if ( len != ( ( int ) ( sizeof ( buf ) - 1 /* NUL */ ) ) ) {
DBGC ( usb, "USB %s has invalid ECM MAC \"%s\"\n",
usb->name, buf );
func->name, buf );
return -EINVAL;
}
@ -112,7 +122,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
if ( len < 0 ) {
rc = len;
DBGC ( usb, "USB %s could not decode ECM MAC \"%s\": %s\n",
usb->name, buf, strerror ( rc ) );
func->name, buf, strerror ( rc ) );
return rc;
}
@ -464,7 +474,7 @@ static int ecm_probe ( struct usb_function *func,
}
/* Fetch MAC address */
if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
ecm, strerror ( rc ) );
goto err_fetch_mac;

View File

@ -86,7 +86,7 @@ struct ecm_device {
extern struct ecm_ethernet_descriptor *
ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
struct usb_interface_descriptor *interface );
extern int ecm_fetch_mac ( struct usb_device *usb,
extern int ecm_fetch_mac ( struct usb_function *func,
struct ecm_ethernet_descriptor *desc,
uint8_t *hw_addr );

View File

@ -576,7 +576,7 @@ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb,
cdb.IFnum = nii->nii->IfNum;
/* Raise task priority level */
tpl = bs->RaiseTPL ( TPL_CALLBACK );
tpl = bs->RaiseTPL ( efi_internal_tpl );
/* Issue command */
DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n",

View File

@ -164,6 +164,10 @@ static int snpnet_transmit ( struct net_device *netdev,
EFI_STATUS efirc;
int rc;
/* Do nothing if shutdown is in progress */
if ( efi_shutdown_in_progress )
return -ECANCELED;
/* Defer the packet if there is already a transmission in progress */
if ( snp->txbuf ) {
netdev_tx_defer ( netdev, iobuf );
@ -283,6 +287,10 @@ static void snpnet_poll_rx ( struct net_device *netdev ) {
*/
static void snpnet_poll ( struct net_device *netdev ) {
/* Do nothing if shutdown is in progress */
if ( efi_shutdown_in_progress )
return;
/* Process any TX completions */
snpnet_poll_tx ( netdev );
@ -426,8 +434,9 @@ static void snpnet_close ( struct net_device *netdev ) {
EFI_STATUS efirc;
int rc;
/* Shut down NIC */
if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) {
/* Shut down NIC (unless whole system shutdown is in progress) */
if ( ( ! efi_shutdown_in_progress ) &&
( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
rc = -EEFI ( efirc );
DBGC ( snp, "SNP %s could not shut down: %s\n",
netdev->name, strerror ( rc ) );
@ -589,8 +598,9 @@ void snpnet_stop ( struct efi_device *efidev ) {
/* Unregister network device */
unregister_netdev ( netdev );
/* Stop SNP protocol */
if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) {
/* Stop SNP protocol (unless whole system shutdown is in progress) */
if ( ( ! efi_shutdown_in_progress ) &&
( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) {
rc = -EEFI ( efirc );
DBGC ( device, "SNP %s could not stop: %s\n",
efi_handle_name ( device ), strerror ( rc ) );

View File

@ -1025,6 +1025,12 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x043a, "dh8900cc-f", "DH8900CC Fiber", 0 ),
PCI_ROM ( 0x8086, 0x043c, "dh8900cc-b", "DH8900CC Backplane", 0 ),
PCI_ROM ( 0x8086, 0x0440, "dh8900cc-s", "DH8900CC SFP", 0 ),
PCI_ROM ( 0x8086, 0x0d4c, "i219lm-11", "I219-LM (11)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x0d4d, "i219v-11", "I219-V (11)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x0d4e, "i219lm-10", "I219-LM (10)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x0d4f, "i219v-10", "I219-V (10)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x0d53, "i219lm-12", "I219-LM (12)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x0d55, "i219v-12", "I219-V (12)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1000, "82542-f", "82542 (Fiber)", 0 ),
PCI_ROM ( 0x8086, 0x1001, "82543gc-f", "82543GC (Fiber)", 0 ),
PCI_ROM ( 0x8086, 0x1004, "82543gc", "82543GC (Copper)", 0 ),
@ -1161,6 +1167,12 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x15e1, "i219lm-9", "I219-LM (9)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15e2, "i219v-9", "I219-V (9)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15f4, "i219lm-15", "I219-LM (15)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15f5, "i219v-15", "I219-V (15)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15f9, "i219lm-14", "I219-LM (14)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15fa, "i219v-14", "I219-V (14)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15fb, "i219lm-13", "I219-LM (13)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15fc, "i219v-13", "I219-V (13)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1f41, "i354", "I354", INTEL_NO_ASDE ),
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),

View File

@ -481,6 +481,7 @@ static struct pci_device_id intelx_nics[] = {
PCI_ROM ( 0x8086, 0x15ab, "x552", "X552", 0 ),
PCI_ROM ( 0x8086, 0x15c8, "x553t", "X553/X557-AT", 0 ),
PCI_ROM ( 0x8086, 0x15ce, "x553-sfp", "X553 (SFP+)", 0 ),
PCI_ROM ( 0x8086, 0x15e4, "x553a", "X553", 0 ),
PCI_ROM ( 0x8086, 0x15e5, "x553", "X553", 0 ),
};

View File

@ -598,7 +598,7 @@ static int ncm_probe ( struct usb_function *func,
}
/* Fetch MAC address */
if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
DBGC ( ncm, "NCM %p could not fetch MAC address: %s\n",
ncm, strerror ( rc ) );
goto err_fetch_mac;

694
src/drivers/net/rdc.c Normal file
View File

@ -0,0 +1,694 @@
/*
* Copyright (C) 2021 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 (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 <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/iobuf.h>
#include <ipxe/malloc.h>
#include <ipxe/pci.h>
#include "rdc.h"
/** @file
*
* RDC R6040 network driver
*
*/
/******************************************************************************
*
* Device reset
*
******************************************************************************
*/
/**
* Reset hardware
*
* @v rdc RDC device
* @ret rc Return status code
*/
static int rdc_reset ( struct rdc_nic *rdc ) {
unsigned int i;
/* Reset NIC */
writew ( RDC_MCR1_RST, rdc->regs + RDC_MCR1 );
/* Wait for reset to complete */
for ( i = 0 ; i < RDC_RESET_MAX_WAIT_MS ; i++ ) {
/* Check for reset completion */
if ( readw ( rdc->regs + RDC_MCR1 ) & RDC_MCR1_RST ) {
mdelay ( 1 );
continue;
}
/* Reset internal state machine */
writew ( RDC_MACSM_RST, rdc->regs + RDC_MACSM );
writew ( 0, rdc->regs + RDC_MACSM );
mdelay ( RDC_MACSM_RESET_DELAY_MS );
return 0;
}
DBGC ( rdc, "RDC %p timed out waiting for reset\n", rdc );
return -ETIMEDOUT;
}
/******************************************************************************
*
* MII interface
*
******************************************************************************
*/
/**
* Read from MII register
*
* @v mdio MII interface
* @v phy PHY address
* @v reg Register address
* @ret value Data read, or negative error
*/
static int rdc_mii_read ( struct mii_interface *mdio, unsigned int phy,
unsigned int reg ) {
struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
uint16_t mmdio;
unsigned int i;
/* Initiate read */
mmdio = ( RDC_MMDIO_MIIRD | RDC_MMDIO_PHYAD ( phy ) |
RDC_MMDIO_REGAD ( reg ) );
writew ( mmdio, rdc->regs + RDC_MMDIO );
/* Wait for read to complete */
for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
/* Check for read completion */
if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIRD ) {
udelay ( 1 );
continue;
}
/* Return register value */
return ( readw ( rdc->regs + RDC_MMRD ) );
}
DBGC ( rdc, "RDC %p timed out waiting for MII read\n", rdc );
return -ETIMEDOUT;
}
/**
* Write to MII register
*
* @v mdio MII interface
* @v phy PHY address
* @v reg Register address
* @v data Data to write
* @ret rc Return status code
*/
static int rdc_mii_write ( struct mii_interface *mdio, unsigned int phy,
unsigned int reg, unsigned int data ) {
struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
uint16_t mmdio;
unsigned int i;
/* Initiate write */
mmdio = ( RDC_MMDIO_MIIWR | RDC_MMDIO_PHYAD ( phy ) |
RDC_MMDIO_REGAD ( reg ) );
writew ( data, rdc->regs + RDC_MMWD );
writew ( mmdio, rdc->regs + RDC_MMDIO );
/* Wait for write to complete */
for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
/* Check for write completion */
if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIWR ) {
udelay ( 1 );
continue;
}
return 0;
}
DBGC ( rdc, "RDC %p timed out waiting for MII write\n", rdc );
return -ETIMEDOUT;
}
/** RDC MII operations */
static struct mii_operations rdc_mii_operations = {
.read = rdc_mii_read,
.write = rdc_mii_write,
};
/******************************************************************************
*
* Link state
*
******************************************************************************
*/
/**
* Initialise PHY
*
* @v rdc RDC device
* @ret rc Return status code
*/
static int rdc_init_phy ( struct rdc_nic *rdc ) {
int rc;
/* Find PHY address */
if ( ( rc = mii_find ( &rdc->mii ) ) != 0 ) {
DBGC ( rdc, "RDC %p could not find PHY address: %s\n",
rdc, strerror ( rc ) );
return rc;
}
/* Reset PHY */
if ( ( rc = mii_reset ( &rdc->mii ) ) != 0 ) {
DBGC ( rdc, "RDC %p could not reset PHY: %s\n",
rdc, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Check link state
*
* @v netdev Network device
* @ret rc Return status code
*/
static int rdc_check_link ( struct net_device *netdev ) {
struct rdc_nic *rdc = netdev->priv;
int rc;
/* Check link state */
if ( ( rc = mii_check_link ( &rdc->mii, netdev ) ) != 0 ) {
DBGC ( rdc, "RDC %p could not check link: %s\n",
rdc, strerror ( rc ) );
return rc;
}
return 0;
}
/******************************************************************************
*
* Network device interface
*
******************************************************************************
*/
/**
* Create descriptor ring
*
* @v rdc RDC device
* @v ring Descriptor ring
* @ret rc Return status code
*/
static int rdc_create_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
struct rdc_descriptor *desc;
struct rdc_descriptor *next;
physaddr_t start;
unsigned int i;
/* Allocate descriptor ring */
ring->desc = dma_alloc ( rdc->dma, &ring->map, len, len );
if ( ! ring->desc )
return -ENOMEM;
/* Initialise descriptor ring */
memset ( ring->desc, 0, len );
for ( i = 0 ; i < ring->count ; i++ ) {
desc = &ring->desc[i];
next = &ring->desc[ ( i + 1 ) & ( ring->count - 1 ) ];
desc->next = cpu_to_le32 ( dma ( &ring->map, next ) );
}
/* Program ring address */
start = dma ( &ring->map, ring->desc );
writew ( ( start >> 0 ), ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
writew ( ( start >> 16 ), ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
DBGC ( rdc, "RDC %p ring %#02x is at [%08lx,%08lx)\n",
rdc, ring->reg, virt_to_phys ( ring->desc ),
( virt_to_phys ( ring->desc ) + len ) );
return 0;
}
/**
* Destroy descriptor ring
*
* @v rdc RDC device
* @v ring Descriptor ring
*/
static void rdc_destroy_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
/* Clear ring address */
writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
/* Free descriptors */
dma_free ( &ring->map, ring->desc, len );
ring->desc = NULL;
/* Reset ring */
ring->prod = 0;
ring->cons = 0;
}
/**
* Refill receive descriptor ring
*
* @v rdc RDC device
*/
static void rdc_refill_rx ( struct rdc_nic *rdc ) {
struct rdc_descriptor *rx;
struct io_buffer *iobuf;
unsigned int rx_idx;
/* Refill ring */
while ( ( rdc->rx.prod - rdc->rx.cons ) < RDC_NUM_RX_DESC ) {
/* Allocate I/O buffer */
iobuf = alloc_rx_iob ( RDC_RX_MAX_LEN, rdc->dma );
if ( ! iobuf ) {
/* Wait for next refill */
break;
}
/* Get next receive descriptor */
rx_idx = ( rdc->rx.prod++ % RDC_NUM_RX_DESC );
rx = &rdc->rx.desc[rx_idx];
/* Populate receive descriptor */
rx->len = cpu_to_le16 ( RDC_RX_MAX_LEN );
rx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
wmb();
rx->flags = cpu_to_le16 ( RDC_FL_OWNED );
/* Record I/O buffer */
assert ( rdc->rx_iobuf[rx_idx] == NULL );
rdc->rx_iobuf[rx_idx] = iobuf;
DBGC2 ( rdc, "RDC %p RX %d is [%lx,%lx)\n",
rdc, rx_idx, virt_to_phys ( iobuf->data ),
( virt_to_phys ( iobuf->data ) + RDC_RX_MAX_LEN ) );
}
}
/**
* Open network device
*
* @v netdev Network device
* @ret rc Return status code
*/
static int rdc_open ( struct net_device *netdev ) {
struct rdc_nic *rdc = netdev->priv;
int rc;
/* Create transmit descriptor ring */
if ( ( rc = rdc_create_ring ( rdc, &rdc->tx ) ) != 0 )
goto err_create_tx;
/* Create receive descriptor ring */
if ( ( rc = rdc_create_ring ( rdc, &rdc->rx ) ) != 0 )
goto err_create_rx;
/* Program receive buffer length */
writew ( RDC_RX_MAX_LEN, rdc->regs + RDC_MRBSR );
/* Enable transmit and receive */
writew ( ( RDC_MCR0_FD | RDC_MCR0_TXEN | RDC_MCR0_PROMISC |
RDC_MCR0_RXEN ),
rdc->regs + RDC_MCR0 );
/* Enable PHY status polling */
writew ( ( RDC_MPSCCR_EN | RDC_MPSCCR_PHYAD ( rdc->mii.address ) |
RDC_MPSCCR_SLOW ),
rdc->regs + RDC_MPSCCR );
/* Fill receive ring */
rdc_refill_rx ( rdc );
/* Update link state */
rdc_check_link ( netdev );
return 0;
rdc_destroy_ring ( rdc, &rdc->rx );
err_create_rx:
rdc_destroy_ring ( rdc, &rdc->tx );
err_create_tx:
return rc;
}
/**
* Close network device
*
* @v netdev Network device
*/
static void rdc_close ( struct net_device *netdev ) {
struct rdc_nic *rdc = netdev->priv;
unsigned int i;
/* Disable NIC */
writew ( 0, rdc->regs + RDC_MCR0 );
/* Destroy receive descriptor ring */
rdc_destroy_ring ( rdc, &rdc->rx );
/* Discard any unused receive buffers */
for ( i = 0 ; i < RDC_NUM_RX_DESC ; i++ ) {
if ( rdc->rx_iobuf[i] )
free_rx_iob ( rdc->rx_iobuf[i] );
rdc->rx_iobuf[i] = NULL;
}
/* Destroy transmit descriptor ring */
rdc_destroy_ring ( rdc, &rdc->tx );
}
/**
* Transmit packet
*
* @v netdev Network device
* @v iobuf I/O buffer
* @ret rc Return status code
*/
static int rdc_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
struct rdc_nic *rdc = netdev->priv;
struct rdc_descriptor *tx;
unsigned int tx_idx;
int rc;
/* Get next transmit descriptor */
if ( ( rdc->tx.prod - rdc->tx.cons ) >= RDC_NUM_TX_DESC ) {
DBGC ( rdc, "RDC %p out of transmit descriptors\n", rdc );
return -ENOBUFS;
}
tx_idx = ( rdc->tx.prod % RDC_NUM_TX_DESC );
tx = &rdc->tx.desc[tx_idx];
/* Pad to minimum length */
iob_pad ( iobuf, ETH_ZLEN );
/* Map I/O buffer */
if ( ( rc = iob_map_tx ( iobuf, rdc->dma ) ) != 0 )
return rc;
/* Update producer index */
rdc->tx.prod++;
/* Populate transmit descriptor */
tx->len = cpu_to_le16 ( iob_len ( iobuf ) );
tx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
wmb();
tx->flags = cpu_to_le16 ( RDC_FL_OWNED );
wmb();
/* Notify card that there are packets ready to transmit */
writew ( RDC_MTPR_TM2TX, rdc->regs + RDC_MTPR );
return 0;
}
/**
* Poll for completed packets
*
* @v netdev Network device
*/
static void rdc_poll_tx ( struct net_device *netdev ) {
struct rdc_nic *rdc = netdev->priv;
struct rdc_descriptor *tx;
unsigned int tx_idx;
/* Check for completed packets */
while ( rdc->tx.cons != rdc->tx.prod ) {
/* Get next transmit descriptor */
tx_idx = ( rdc->tx.cons % RDC_NUM_TX_DESC );
tx = &rdc->tx.desc[tx_idx];
/* Stop if descriptor is still in use */
if ( tx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
return;
DBGC2 ( rdc, "RDC %p TX %d complete\n", rdc, tx_idx );
/* Complete transmit descriptor */
rdc->tx.cons++;
netdev_tx_complete_next ( netdev );
}
}
/**
* Poll for received packets
*
* @v netdev Network device
*/
static void rdc_poll_rx ( struct net_device *netdev ) {
struct rdc_nic *rdc = netdev->priv;
struct rdc_descriptor *rx;
struct io_buffer *iobuf;
unsigned int rx_idx;
size_t len;
/* Check for received packets */
while ( rdc->rx.cons != rdc->rx.prod ) {
/* Get next receive descriptor */
rx_idx = ( rdc->rx.cons % RDC_NUM_RX_DESC );
rx = &rdc->rx.desc[rx_idx];
/* Stop if descriptor is still in use */
if ( rx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
return;
/* Populate I/O buffer */
iobuf = rdc->rx_iobuf[rx_idx];
rdc->rx_iobuf[rx_idx] = NULL;
len = le16_to_cpu ( rx->len );
iob_put ( iobuf, len );
iob_unput ( iobuf, 4 /* strip CRC */ );
/* Hand off to network stack */
if ( rx->flags & cpu_to_le16 ( RDC_FL_OK ) ) {
DBGC2 ( rdc, "RDC %p RX %d complete (length %zd)\n",
rdc, rx_idx, len );
netdev_rx ( netdev, iobuf );
} else {
DBGC2 ( rdc, "RDC %p RX %d error (length %zd, "
"flags %#04x)\n", rdc, rx_idx, len,
le16_to_cpu ( rx->flags ) );
netdev_rx_err ( netdev, iobuf, -EIO );
}
rdc->rx.cons++;
}
}
/**
* Poll for completed and received packets
*
* @v netdev Network device
*/
static void rdc_poll ( struct net_device *netdev ) {
struct rdc_nic *rdc = netdev->priv;
uint16_t misr;
/* Check for (and acknowledge) interrupts */
misr = readw ( rdc->regs + RDC_MISR );
/* Poll for TX completions, if applicable */
if ( misr & RDC_MIRQ_TX )
rdc_poll_tx ( netdev );
/* Poll for RX completions, if applicable */
if ( misr & RDC_MIRQ_RX )
rdc_poll_rx ( netdev );
/* Check link state, if applicable */
if ( misr & RDC_MIRQ_LINK )
rdc_check_link ( netdev );
/* Check for unexpected interrupts */
if ( misr & ~( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX_EARLY |
RDC_MIRQ_RX_EMPTY | RDC_MIRQ_RX ) ) {
DBGC ( rdc, "RDC %p unexpected MISR %#04x\n", rdc, misr );
/* Report as a TX error */
netdev_tx_err ( netdev, NULL, -ENOTSUP );
}
/* Refill receive ring */
rdc_refill_rx ( rdc );
}
/**
* Enable or disable interrupts
*
* @v netdev Network device
* @v enable Interrupts should be enabled
*/
static void rdc_irq ( struct net_device *netdev, int enable ) {
struct rdc_nic *rdc = netdev->priv;
uint16_t mier;
/* Enable/disable interrupts */
mier = ( enable ? ( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX ) : 0 );
writew ( mier, rdc->regs + RDC_MIER );
}
/** RDC network device operations */
static struct net_device_operations rdc_operations = {
.open = rdc_open,
.close = rdc_close,
.transmit = rdc_transmit,
.poll = rdc_poll,
.irq = rdc_irq,
};
/******************************************************************************
*
* PCI interface
*
******************************************************************************
*/
/**
* Probe PCI device
*
* @v pci PCI device
* @ret rc Return status code
*/
static int rdc_probe ( struct pci_device *pci ) {
struct net_device *netdev;
struct rdc_nic *rdc;
union rdc_mac mac;
int rc;
/* Allocate and initialise net device */
netdev = alloc_etherdev ( sizeof ( *rdc ) );
if ( ! netdev ) {
rc = -ENOMEM;
goto err_alloc;
}
netdev_init ( netdev, &rdc_operations );
rdc = netdev->priv;
pci_set_drvdata ( pci, netdev );
netdev->dev = &pci->dev;
memset ( rdc, 0, sizeof ( *rdc ) );
rdc->dma = &pci->dma;
mdio_init ( &rdc->mdio, &rdc_mii_operations );
mii_init ( &rdc->mii, &rdc->mdio, 0 );
rdc_init_ring ( &rdc->tx, RDC_NUM_TX_DESC, RDC_MTDSA );
rdc_init_ring ( &rdc->rx, RDC_NUM_RX_DESC, RDC_MRDSA );
/* Fix up PCI device */
adjust_pci_device ( pci );
/* Map registers */
rdc->regs = pci_ioremap ( pci, pci->membase, RDC_BAR_SIZE );
if ( ! rdc->regs ) {
rc = -ENODEV;
goto err_ioremap;
}
/* Fetch MAC address */
mac.mid[0] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID0 ) );
mac.mid[1] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID1 ) );
mac.mid[2] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID2 ) );
memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
/* Reset the NIC */
if ( ( rc = rdc_reset ( rdc ) ) != 0 )
goto err_reset;
/* Initialise PHY */
if ( ( rc = rdc_init_phy ( rdc ) ) != 0 )
goto err_init_phy;
/* Register network device */
if ( ( rc = register_netdev ( netdev ) ) != 0 )
goto err_register_netdev;
/* Set initial link state */
rdc_check_link ( netdev );
return 0;
unregister_netdev ( netdev );
err_register_netdev:
err_init_phy:
rdc_reset ( rdc );
err_reset:
iounmap ( rdc->regs );
err_ioremap:
netdev_nullify ( netdev );
netdev_put ( netdev );
err_alloc:
return rc;
}
/**
* Remove PCI device
*
* @v pci PCI device
*/
static void rdc_remove ( struct pci_device *pci ) {
struct net_device *netdev = pci_get_drvdata ( pci );
struct rdc_nic *rdc = netdev->priv;
/* Unregister network device */
unregister_netdev ( netdev );
/* Reset card */
rdc_reset ( rdc );
/* Free network device */
iounmap ( rdc->regs );
netdev_nullify ( netdev );
netdev_put ( netdev );
}
/** RDC PCI device IDs */
static struct pci_device_id rdc_nics[] = {
PCI_ROM ( 0x17f3, 0x6040, "r6040", "RDC R6040", 0 ),
};
/** RDC PCI driver */
struct pci_driver rdc_driver __pci_driver = {
.ids = rdc_nics,
.id_count = ( sizeof ( rdc_nics ) / sizeof ( rdc_nics[0] ) ),
.probe = rdc_probe,
.remove = rdc_remove,
};

194
src/drivers/net/rdc.h Normal file
View File

@ -0,0 +1,194 @@
#ifndef _RDC_H
#define _RDC_H
/** @file
*
* RDC R6040 network driver
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/if_ether.h>
#include <ipxe/mii.h>
/** RDC BAR size */
#define RDC_BAR_SIZE 256
/** An RDC descriptor */
struct rdc_descriptor {
/** Flags */
uint16_t flags;
/** Length */
uint16_t len;
/** Address */
uint32_t addr;
/** Next descriptor */
uint32_t next;
/** Reserved */
uint32_t reserved;
} __attribute__ (( packed ));
/** Descriptor is owned by NIC */
#define RDC_FL_OWNED 0x8000
/** Packet OK */
#define RDC_FL_OK 0x4000
/** MAC control register 0 */
#define RDC_MCR0 0x00
#define RDC_MCR0_FD 0x8000 /**< Full duplex */
#define RDC_MCR0_TXEN 0x1000 /**< Transmit enable */
#define RDC_MCR0_PROMISC 0x0020 /**< Promiscuous mode */
#define RDC_MCR0_RXEN 0x0002 /**< Receive enable */
/** MAC control register 1 */
#define RDC_MCR1 0x04
#define RDC_MCR1_RST 0x0001 /**< MAC reset */
/** Maximum time to wait for reset */
#define RDC_RESET_MAX_WAIT_MS 10
/** MAC transmit poll command register */
#define RDC_MTPR 0x14
#define RDC_MTPR_TM2TX 0x0001 /**< Trigger MAC to transmit */
/** MAC receive buffer size register */
#define RDC_MRBSR 0x18
/** MAC MDIO control register */
#define RDC_MMDIO 0x20
#define RDC_MMDIO_MIIWR 0x4000 /**< MDIO write */
#define RDC_MMDIO_MIIRD 0x2000 /**< MDIO read */
#define RDC_MMDIO_PHYAD(x) ( (x) << 8 ) /**< PHY address */
#define RDC_MMDIO_REGAD(x) ( (x) << 0 ) /**< Register address */
/** Maximum time to wait for an MII read or write */
#define RDC_MII_MAX_WAIT_US 2048
/** MAC MDIO read data register */
#define RDC_MMRD 0x24
/** MAC MDIO write data register */
#define RDC_MMWD 0x28
/** MAC transmit descriptor start address */
#define RDC_MTDSA 0x2c
/** MAC receive descriptor start address */
#define RDC_MRDSA 0x34
/** MAC descriptor start address low half */
#define RDC_MxDSA_LO 0x0
/** MAC descriptor start address low half */
#define RDC_MxDSA_HI 0x4
/** MAC interrupt status register */
#define RDC_MISR 0x3c
#define RDC_MIRQ_LINK 0x0200 /**< Link status changed */
#define RDC_MIRQ_TX 0x0010 /**< Transmit complete */
#define RDC_MIRQ_RX_EARLY 0x0008 /**< Receive early interrupt */
#define RDC_MIRQ_RX_EMPTY 0x0002 /**< Receive descriptor unavailable */
#define RDC_MIRQ_RX 0x0001 /**< Receive complete */
/** MAC interrupt enable register */
#define RDC_MIER 0x40
/** MAC address word 0 */
#define RDC_MID0 0x68
/** MAC address word 1 */
#define RDC_MID1 0x6a
/** MAC address word 2 */
#define RDC_MID2 0x6c
/** MAC PHY status change configuration register */
#define RDC_MPSCCR 0x88
#define RDC_MPSCCR_EN 0x8000 /**< PHY status change enable */
#define RDC_MPSCCR_PHYAD(x) ( (x) << 8 ) /**< PHY address */
#define RDC_MPSCCR_SLOW 0x0007 /**< Poll slowly */
/** MAC state machine register */
#define RDC_MACSM 0xac
#define RDC_MACSM_RST 0x0002 /**< Reset state machine */
/** Time to wait after resetting MAC state machine */
#define RDC_MACSM_RESET_DELAY_MS 10
/** A MAC address */
union rdc_mac {
/** Raw bytes */
uint8_t raw[ETH_ALEN];
/** MIDx registers */
uint16_t mid[ ETH_ALEN / 2 ];
};
/** A descriptor ring */
struct rdc_ring {
/** Descriptors */
struct rdc_descriptor *desc;
/** Descriptor ring DMA mapping */
struct dma_mapping map;
/** Producer index */
unsigned int prod;
/** Consumer index */
unsigned int cons;
/** Number of descriptors */
unsigned int count;
/** Start address register 0 */
unsigned int reg;
};
/**
* Initialise descriptor ring
*
* @v ring Descriptor ring
* @v count Number of descriptors
* @v reg Start address register 0
*/
static inline __attribute__ (( always_inline )) void
rdc_init_ring ( struct rdc_ring *ring, unsigned int count, unsigned int reg ) {
ring->count = count;
ring->reg = reg;
}
/** Number of transmit descriptors
*
* This is a policy decision.
*/
#define RDC_NUM_TX_DESC 16
/** Number of receive descriptors
*
* This is a policy decision.
*/
#define RDC_NUM_RX_DESC 8
/** Receive buffer length */
#define RDC_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
/** An RDC network card */
struct rdc_nic {
/** Registers */
void *regs;
/** DMA device */
struct dma_device *dma;
/** MII interface */
struct mii_interface mdio;
/** MII device */
struct mii_device mii;
/** Transmit descriptor ring */
struct rdc_ring tx;
/** Receive descriptor ring */
struct rdc_ring rx;
/** Receive I/O buffers */
struct io_buffer *rx_iobuf[RDC_NUM_RX_DESC];
};
#endif /* _RDC_H */

View File

@ -420,6 +420,16 @@ static int realtek_phy_reset ( struct realtek_nic *rtl ) {
*/
}
/* Some cards (e.g. RTL8211B) have a hardware errata that
* requires the MII_MMD_DATA register to be cleared before the
* link will come up.
*/
if ( ( rc = mii_write ( &rtl->mii, MII_MMD_DATA, 0 ) ) != 0 ) {
/* Ignore failures, since the register may not be
* present on all PHYs.
*/
}
/* Restart autonegotiation */
if ( ( rc = mii_restart ( &rtl->mii ) ) != 0 ) {
DBGC ( rtl, "REALTEK %p could not restart MII: %s\n",

View File

@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include <ipxe/pci.h>
#include <ipxe/dma.h>
#include <ipxe/if_ether.h>
#include <ipxe/ethernet.h>
#include <ipxe/virtio-pci.h>
@ -99,8 +100,9 @@ struct virtnet_nic {
/** Pending rx packet count */
unsigned int rx_num_iobufs;
/** Virtio net dummy packet headers */
struct virtio_net_hdr_modern empty_header[QUEUE_NB];
/** DMA device */
struct dma_device *dma;
};
/** Add an iobuf to a virtqueue
@ -115,7 +117,7 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
int vq_idx, struct io_buffer *iobuf ) {
struct virtnet_nic *virtnet = netdev->priv;
struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx];
struct virtio_net_hdr_modern *header = &virtnet->empty_header[vq_idx];
struct virtio_net_hdr_modern *header = vq->empty_header;
unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0;
unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2;
size_t header_len = ( virtnet->virtio_version ?
@ -132,11 +134,11 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
* to header->flags for received packets. Work around
* this by using separate RX and TX headers.
*/
.addr = ( char* ) header,
.addr = dma ( &vq->map, header ),
.length = header_len,
},
{
.addr = ( char* ) iobuf->data,
.addr = iob_dma ( iobuf ),
.length = iob_len ( iobuf ),
},
};
@ -161,7 +163,7 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) {
struct io_buffer *iobuf;
/* Try to allocate a buffer, stop for now if out of memory */
iobuf = alloc_iob ( len );
iobuf = alloc_rx_iob ( len, virtnet->dma );
if ( ! iobuf )
break;
@ -215,7 +217,8 @@ static int virtnet_open_legacy ( struct net_device *netdev ) {
/* Initialize rx/tx virtqueues */
for ( i = 0; i < QUEUE_NB; i++ ) {
if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) {
if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i], virtnet->dma,
sizeof ( struct virtio_net_hdr_modern ) ) == -1 ) {
DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n",
virtnet, i );
virtnet_free_virtqueues ( netdev );
@ -280,7 +283,8 @@ static int virtnet_open_modern ( struct net_device *netdev ) {
}
/* Initialize rx/tx virtqueues */
if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue ) ) {
if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue,
virtnet->dma, sizeof ( struct virtio_net_hdr_modern ) ) ) {
DBGC ( virtnet, "VIRTIO-NET %p cannot register queues\n",
virtnet );
virtnet_free_virtqueues ( netdev );
@ -335,7 +339,7 @@ static void virtnet_close ( struct net_device *netdev ) {
/* Free rx iobufs */
list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) {
free_iob ( iobuf );
free_rx_iob ( iobuf );
}
INIT_LIST_HEAD ( &virtnet->rx_iobufs );
virtnet->rx_num_iobufs = 0;
@ -478,6 +482,12 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
/* Enable PCI bus master and reset NIC */
adjust_pci_device ( pci );
/* Configure DMA */
virtnet->dma = &pci->dma;
dma_set_mask_64bit ( virtnet->dma );
netdev->dma = virtnet->dma;
vp_reset ( ioaddr );
/* Load MAC address and MTU */
@ -506,7 +516,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
return 0;
unregister_netdev ( netdev );
err_register_netdev:
err_register_netdev:
vp_reset ( ioaddr );
netdev_nullify ( netdev );
netdev_put ( netdev );
@ -586,6 +596,11 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) {
/* Enable the PCI device */
adjust_pci_device ( pci );
/* Configure DMA */
virtnet->dma = &pci->dma;
dma_set_mask_64bit ( virtnet->dma );
netdev->dma = virtnet->dma;
/* Reset the device and set initial status bits */
vpm_reset ( &virtnet->vdev );
vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE );
@ -633,7 +648,6 @@ err_mac_address:
vpm_reset ( &virtnet->vdev );
netdev_nullify ( netdev );
netdev_put ( netdev );
virtio_pci_unmap_capability ( &virtnet->vdev.device );
err_map_device:
virtio_pci_unmap_capability ( &virtnet->vdev.isr );

View File

@ -1165,6 +1165,31 @@ static int xhci_reset ( struct xhci_device *xhci ) {
return -ETIMEDOUT;
}
/**
* Mark xHCI device as permanently failed
*
* @v xhci xHCI device
* @ret rc Return status code
*/
static int xhci_fail ( struct xhci_device *xhci ) {
size_t len;
int rc;
/* Mark command mechanism as permanently failed */
xhci->failed = 1;
/* Reset device */
if ( ( rc = xhci_reset ( xhci ) ) != 0 )
return rc;
/* Discard DCBAA entries since DCBAAP has been cleared */
assert ( xhci->dcbaa.context != NULL );
len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) );
memset ( xhci->dcbaa.context, 0, len );
return 0;
}
/******************************************************************************
*
* Transfer request blocks
@ -1720,6 +1745,10 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
unsigned int consumed;
unsigned int type;
/* Do nothing if device has permanently failed */
if ( xhci->failed )
return;
/* Poll for events */
profile_start ( &xhci_event_profiler );
for ( consumed = 0 ; ; consumed++ ) {
@ -1778,6 +1807,7 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
*/
static void xhci_abort ( struct xhci_device *xhci ) {
physaddr_t crp;
uint32_t crcr;
/* Abort the command */
DBGC2 ( xhci, "XHCI %s aborting command\n", xhci->name );
@ -1786,8 +1816,18 @@ static void xhci_abort ( struct xhci_device *xhci ) {
/* Allow time for command to abort */
mdelay ( XHCI_COMMAND_ABORT_DELAY_MS );
/* Sanity check */
assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );
/* Check for failure to abort */
crcr = readl ( xhci->op + XHCI_OP_CRCR );
if ( crcr & XHCI_CRCR_CRR ) {
/* Device has failed to abort a command and is almost
* certainly beyond repair. Reset device, abandoning
* all state, and mark device as failed to avoid
* delays on any future command attempts.
*/
DBGC ( xhci, "XHCI %s failed to abort command\n", xhci->name );
xhci_fail ( xhci );
}
/* Consume (and ignore) any final command status */
xhci_event_poll ( xhci );
@ -1813,6 +1853,12 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) {
unsigned int i;
int rc;
/* Immediately fail all commands if command mechanism has failed */
if ( xhci->failed ) {
rc = -EPIPE;
goto err_failed;
}
/* Sanity check */
if ( xhci->pending ) {
DBGC ( xhci, "XHCI %s command ring busy\n", xhci->name );
@ -1863,6 +1909,7 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) {
err_enqueue:
xhci->pending = NULL;
err_pending:
err_failed:
return rc;
}
@ -3412,14 +3459,36 @@ static int xhci_probe ( struct pci_device *pci ) {
static void xhci_remove ( struct pci_device *pci ) {
struct xhci_device *xhci = pci_get_drvdata ( pci );
struct usb_bus *bus = xhci->bus;
uint16_t command;
/* Some systems are observed to disable bus mastering on
* Thunderbolt controllers before we get a chance to shut
* down. Detect this and avoid attempting any DMA operations,
* which are guaranteed to fail and may end up spuriously
* completing after the operating system kernel starts up.
*/
pci_read_config_word ( pci, PCI_COMMAND, &command );
if ( ! ( command & PCI_COMMAND_MASTER ) ) {
DBGC ( xhci, "XHCI %s DMA was disabled\n", xhci->name );
xhci_fail ( xhci );
}
/* Unregister and free USB bus */
unregister_usb_bus ( bus );
free_usb_bus ( bus );
/* Reset device and undo any PCH-specific fixes */
xhci_reset ( xhci );
if ( xhci->quirks & XHCI_PCH )
xhci_pch_undo ( xhci, pci );
/* Release ownership back to BIOS */
xhci_legacy_release ( xhci );
/* Unmap registers */
iounmap ( xhci->regs );
/* Free device */
free ( xhci );
}

View File

@ -1115,6 +1115,8 @@ struct xhci_device {
struct xhci_event_ring event;
/** Current command (if any) */
union xhci_trb *pending;
/** Command mechanism has permanently failed */
int failed;
/** Device slots, indexed by slot ID */
struct xhci_slot **slot;

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2021 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 <usr/imgmgmt.h>
#include <usr/imgarchive.h>
/** @file
*
* Archive image commands
*
*/
/** "imgextract" options */
struct imgextract_options {
/** Image name */
char *name;
/** Keep original image */
int keep;
/** Download timeout */
unsigned long timeout;
};
/** "imgextract" option list */
static struct option_descriptor imgextract_opts[] = {
OPTION_DESC ( "name", 'n', required_argument,
struct imgextract_options, name, parse_string ),
OPTION_DESC ( "keep", 'k', no_argument,
struct imgextract_options, keep, parse_flag ),
OPTION_DESC ( "timeout", 't', required_argument,
struct imgextract_options, timeout, parse_timeout ),
};
/** "imgextract" command descriptor */
static struct command_descriptor imgextract_cmd =
COMMAND_DESC ( struct imgextract_options, imgextract_opts, 1, 1, NULL );
/**
* The "imgextract" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int imgextract_exec ( int argc, char **argv ) {
struct imgextract_options opts;
struct image *image;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &imgextract_cmd,
&opts ) ) != 0 )
goto err_parse;
/* Acquire image */
if ( ( rc = imgacquire ( argv[optind], opts.timeout, &image ) ) != 0 )
goto err_acquire;
/* Extract archive image */
if ( ( rc = imgextract ( image, opts.name ) ) != 0 )
goto err_extract;
/* Success */
rc = 0;
err_extract:
/* Discard original image unless --keep was specified */
if ( ! opts.keep )
unregister_image ( image );
err_acquire:
err_parse:
return rc;
}
/** Archive image commands */
struct command image_archive_commands[] __command = {
{
.name = "imgextract",
.exec = imgextract_exec,
},
};

View File

@ -100,20 +100,40 @@ static int show_exec ( int argc, char **argv ) {
}
/** "set", "clear", and "read" options */
struct set_core_options {};
struct set_core_options {
/** Timeout */
unsigned long timeout;
};
/** "set", "clear", and "read" option list */
static struct option_descriptor set_core_opts[] = {};
static union {
/* "set" takes no options */
struct option_descriptor set[0];
/* "clear" takes no options */
struct option_descriptor clear[0];
/* "read" takes --timeout option */
struct option_descriptor read[1];
} set_core_opts = {
.read = {
OPTION_DESC ( "timeout", 't', required_argument,
struct set_core_options, timeout, parse_timeout ),
},
};
/** "set" command descriptor */
static struct command_descriptor set_cmd =
COMMAND_DESC ( struct set_core_options, set_core_opts, 1, MAX_ARGUMENTS,
"<setting> <value>" );
COMMAND_DESC ( struct set_core_options, set_core_opts.set,
1, MAX_ARGUMENTS, "<setting> <value>" );
/** "clear" and "read" command descriptor */
static struct command_descriptor clear_read_cmd =
COMMAND_DESC ( struct set_core_options, set_core_opts, 1, 1,
"<setting>" );
/** "clear" command descriptor */
static struct command_descriptor clear_cmd =
COMMAND_DESC ( struct set_core_options, set_core_opts.clear,
1, 1, "<setting>" );
/** "read" command descriptor */
static struct command_descriptor read_cmd =
COMMAND_DESC ( struct set_core_options, set_core_opts.read,
1, 1, "<setting>" );
/**
* "set", "clear", and "read" command
@ -127,6 +147,7 @@ static struct command_descriptor clear_read_cmd =
static int set_core_exec ( int argc, char **argv,
struct command_descriptor *cmd,
int ( * get_value ) ( struct named_setting *setting,
struct set_core_options *opts,
char **args, char **value ) ) {
struct set_core_options opts;
struct named_setting setting;
@ -143,7 +164,8 @@ static int set_core_exec ( int argc, char **argv,
goto err_parse_setting;
/* Parse setting value */
if ( ( rc = get_value ( &setting, &argv[ optind + 1 ], &value ) ) != 0 )
if ( ( rc = get_value ( &setting, &opts, &argv[ optind + 1 ],
&value ) ) != 0 )
goto err_get_value;
/* Apply default type if necessary */
@ -170,11 +192,13 @@ static int set_core_exec ( int argc, char **argv,
* Get setting value for "set" command
*
* @v setting Named setting
* @v opts Options list
* @v args Remaining arguments
* @ret value Setting value
* @ret rc Return status code
*/
static int set_value ( struct named_setting *setting __unused,
struct set_core_options *opts __unused,
char **args, char **value ) {
*value = concat_args ( args );
@ -200,10 +224,12 @@ static int set_exec ( int argc, char **argv ) {
*
* @v setting Named setting
* @v args Remaining arguments
* @v opts Options list
* @ret value Setting value
* @ret rc Return status code
*/
static int clear_value ( struct named_setting *setting __unused,
struct set_core_options *opts __unused,
char **args __unused, char **value ) {
*value = NULL;
@ -218,7 +244,7 @@ static int clear_value ( struct named_setting *setting __unused,
* @ret rc Return status code
*/
static int clear_exec ( int argc, char **argv ) {
return set_core_exec ( argc, argv, &clear_read_cmd, clear_value );
return set_core_exec ( argc, argv, &clear_cmd, clear_value );
}
/**
@ -226,11 +252,13 @@ static int clear_exec ( int argc, char **argv ) {
*
* @v setting Named setting
* @v args Remaining arguments
* @v opts Options list
* @ret value Setting value
* @ret rc Return status code
*/
static int read_value ( struct named_setting *setting, char **args __unused,
char **value ) {
static int read_value ( struct named_setting *setting,
struct set_core_options *opts,
char **args __unused, char **value ) {
char *existing;
int rc;
@ -241,7 +269,8 @@ static int read_value ( struct named_setting *setting, char **args __unused,
NULL, &setting->setting, &existing );
/* Read new value */
if ( ( rc = readline_history ( NULL, existing, NULL, value ) ) != 0 )
if ( ( rc = readline_history ( NULL, existing, NULL, opts->timeout,
value ) ) != 0 )
goto err_readline;
err_readline:
@ -257,7 +286,7 @@ static int read_value ( struct named_setting *setting, char **args __unused,
* @ret rc Return status code
*/
static int read_exec ( int argc, char **argv ) {
return set_core_exec ( argc, argv, &clear_read_cmd, read_value );
return set_core_exec ( argc, argv, &read_cmd, read_value );
}
/** "inc" options */

View File

@ -38,7 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
#define READLINE_MAX 256
#define READLINE_MAX 1024
/**
* Synchronise console with edited string
@ -248,6 +248,7 @@ void history_free ( struct readline_history *history ) {
* @v prompt Prompt string
* @v prefill Prefill string, or NULL for no prefill
* @v history History buffer, or NULL for no history
* @v timeout Timeout period, in ticks (0=indefinite)
* @ret line Line read from console (excluding terminating newline)
* @ret rc Return status code
*
@ -255,9 +256,10 @@ void history_free ( struct readline_history *history ) {
* eventually call free() to release the storage.
*/
int readline_history ( const char *prompt, const char *prefill,
struct readline_history *history, char **line ) {
char buf[READLINE_MAX];
struct readline_history *history, unsigned long timeout,
char **line ) {
struct edit_string string;
char *buf;
int key;
int move_by;
const char *new_string;
@ -273,10 +275,14 @@ int readline_history ( const char *prompt, const char *prefill,
/* Ensure cursor is visible */
printf ( "\033[?25h" );
/* Initialise editable string */
/* Allocate buffer and initialise editable string */
buf = zalloc ( READLINE_MAX );
if ( ! buf ) {
rc = -ENOMEM;
goto done;
}
memset ( &string, 0, sizeof ( string ) );
init_editstring ( &string, buf, sizeof ( buf ) );
buf[0] = '\0';
init_editstring ( &string, buf, READLINE_MAX );
/* Prefill string, if applicable */
if ( prefill ) {
@ -285,15 +291,29 @@ int readline_history ( const char *prompt, const char *prefill,
}
while ( 1 ) {
/* Get keypress */
key = getkey ( timeout );
if ( key < 0 ) {
rc = -ETIMEDOUT;
goto done;
}
timeout = 0;
/* Handle keypress */
key = edit_string ( &string, getkey ( 0 ) );
key = edit_string ( &string, key );
sync_console ( &string );
move_by = 0;
switch ( key ) {
case CR:
case LF:
*line = strdup ( buf );
rc = ( ( *line ) ? 0 : -ENOMEM );
/* Shrink string (ignoring failures) */
*line = realloc ( buf,
( strlen ( buf ) + 1 /* NUL */ ) );
if ( ! *line )
*line = buf;
buf = NULL;
rc = 0;
goto done;
case CTRL_C:
rc = -ECANCELED;
@ -321,6 +341,7 @@ int readline_history ( const char *prompt, const char *prefill,
done:
putchar ( '\n' );
free ( buf );
if ( history ) {
if ( *line && (*line)[0] )
history_append ( history, *line );
@ -342,6 +363,6 @@ int readline_history ( const char *prompt, const char *prefill,
char * readline ( const char *prompt ) {
char *line;
readline_history ( prompt, NULL, NULL, &line );
readline_history ( prompt, NULL, NULL, 0, &line );
return line;
}

View File

@ -91,7 +91,7 @@ int shell ( void ) {
/* Read and execute commands */
do {
readline_history ( shell_prompt, NULL, &history, &line );
readline_history ( shell_prompt, NULL, &history, 0, &line );
if ( line ) {
rc = system ( line );
free ( line );

167
src/image/gzip.c Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright (C) 2021 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 <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/deflate.h>
#include <ipxe/uaccess.h>
#include <ipxe/image.h>
#include <ipxe/zlib.h>
#include <ipxe/gzip.h>
/** @file
*
* gzip compressed images
*
*/
/**
* Extract gzip image
*
* @v image Image
* @v extracted Extracted image
* @ret rc Return status code
*/
static int gzip_extract ( struct image *image, struct image *extracted ) {
struct gzip_header header;
struct gzip_extra_header extra;
struct gzip_crc_header crc;
struct gzip_footer footer;
struct deflate_chunk in;
unsigned int strings;
size_t offset;
size_t len;
off_t nul;
int rc;
/* Sanity check */
assert ( image->len >= ( sizeof ( header ) + sizeof ( footer ) ) );
/* Extract footer */
len = ( image->len - sizeof ( footer ) );
copy_from_user ( &footer, image->data, len, sizeof ( footer ) );
/* Extract fixed header */
copy_from_user ( &header, image->data, 0, sizeof ( header ) );
offset = sizeof ( header );
assert ( offset <= ( image->len - sizeof ( footer ) ) );
/* Skip extra header, if present */
if ( header.flags & GZIP_FL_EXTRA ) {
copy_from_user ( &extra, image->data, offset,
sizeof ( extra ) );
offset += sizeof ( extra );
offset += le16_to_cpu ( extra.len );
if ( offset > len ) {
DBGC ( image, "GZIP %p overlength extra header\n",
image );
return -EINVAL;
}
}
assert ( offset <= ( image->len - sizeof ( footer ) ) );
/* Skip name and/or comment, if present */
strings = 0;
if ( header.flags & GZIP_FL_NAME )
strings++;
if ( header.flags & GZIP_FL_COMMENT )
strings++;
while ( strings-- ) {
nul = memchr_user ( image->data, offset, 0, ( len - offset ) );
if ( nul < 0 ) {
DBGC ( image, "GZIP %p overlength name/comment\n",
image );
return -EINVAL;
}
offset = ( nul + 1 /* NUL */ );
}
assert ( offset <= ( image->len - sizeof ( footer ) ) );
/* Skip CRC, if present */
if ( header.flags & GZIP_FL_HCRC ) {
offset += sizeof ( crc );
if ( offset > len ) {
DBGC ( image, "GZIP %p overlength CRC header\n",
image );
return -EINVAL;
}
}
/* Initialise input chunk */
deflate_chunk_init ( &in, userptr_add ( image->data, offset ), 0, len );
/* Presize extracted image */
if ( ( rc = image_set_len ( extracted,
le32_to_cpu ( footer.len ) ) ) != 0 ) {
DBGC ( image, "GZIP %p could not presize: %s\n",
image, strerror ( rc ) );
return rc;
}
/* Decompress image (expanding if necessary) */
if ( ( rc = zlib_deflate ( DEFLATE_RAW, &in, extracted ) ) != 0 ) {
DBGC ( image, "GZIP %p could not decompress: %s\n",
image, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Probe gzip image
*
* @v image gzip image
* @ret rc Return status code
*/
static int gzip_probe ( struct image *image ) {
struct gzip_header header;
struct gzip_footer footer;
/* Sanity check */
if ( image->len < ( sizeof ( header ) + sizeof ( footer ) ) ) {
DBGC ( image, "GZIP %p image too short\n", image );
return -ENOEXEC;
}
/* Check magic header */
copy_from_user ( &header.magic, image->data, 0,
sizeof ( header.magic ) );
if ( header.magic != cpu_to_be16 ( GZIP_MAGIC ) ) {
DBGC ( image, "GZIP %p invalid magic\n", image );
return -ENOEXEC;
}
return 0;
}
/** gzip image type */
struct image_type gzip_image_type __image_type ( PROBE_NORMAL ) = {
.name = "gzip",
.probe = gzip_probe,
.extract = gzip_extract,
.exec = image_extract_exec,
};

163
src/image/zlib.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2021 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 <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/deflate.h>
#include <ipxe/uaccess.h>
#include <ipxe/image.h>
#include <ipxe/zlib.h>
/** @file
*
* zlib compressed images
*
*/
/**
* Extract compressed data to image
*
* @v format Compression format code
* @v in Compressed input chunk
* @v extracted Extracted image
* @ret rc Return status code
*/
int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in,
struct image *extracted ) {
struct deflate *deflate;
struct deflate_chunk out;
int rc;
/* Allocate and initialise decompressor */
deflate = zalloc ( sizeof ( *deflate ) );
if ( ! deflate ) {
rc = -ENOMEM;
goto err_alloc;
}
/* Decompress data, (re)allocating if necessary */
while ( 1 ) {
/* (Re)initialise decompressor */
deflate_init ( deflate, format );
/* (Re)initialise input chunk */
in->offset = 0;
/* Initialise output chunk */
deflate_chunk_init ( &out, extracted->data, 0, extracted->len );
/* Decompress data */
if ( ( rc = deflate_inflate ( deflate, in, &out ) ) != 0 ) {
DBGC ( extracted, "ZLIB %p could not decompress: %s\n",
extracted, strerror ( rc ) );
goto err_inflate;
}
/* Check that decompression is valid */
if ( ! deflate_finished ( deflate ) ) {
DBGC ( extracted, "ZLIB %p decompression incomplete\n",
extracted );
rc = -EINVAL;
goto err_unfinished;
}
/* Finish if output image size was correct */
if ( out.offset == extracted->len )
break;
/* Otherwise, resize output image and retry */
if ( ( rc = image_set_len ( extracted, out.offset ) ) != 0 ) {
DBGC ( extracted, "ZLIB %p could not resize: %s\n",
extracted, strerror ( rc ) );
goto err_set_size;
}
}
/* Success */
rc = 0;
err_set_size:
err_unfinished:
err_inflate:
free ( deflate );
err_alloc:
return rc;
}
/**
* Extract zlib image
*
* @v image Image
* @v extracted Extracted image
* @ret rc Return status code
*/
static int zlib_extract ( struct image *image, struct image *extracted ) {
struct deflate_chunk in;
int rc;
/* Initialise input chunk */
deflate_chunk_init ( &in, image->data, 0, image->len );
/* Decompress image */
if ( ( rc = zlib_deflate ( DEFLATE_ZLIB, &in, extracted ) ) != 0 )
return rc;
return 0;
}
/**
* Probe zlib image
*
* @v image zlib image
* @ret rc Return status code
*/
static int zlib_probe ( struct image *image ) {
union zlib_magic magic;
/* Sanity check */
if ( image->len < sizeof ( magic ) ) {
DBGC ( image, "ZLIB %p image too short\n", image );
return -ENOEXEC;
}
/* Check magic header */
copy_from_user ( &magic, image->data, 0, sizeof ( magic ) );
if ( ! zlib_magic_is_valid ( &magic ) ) {
DBGC ( image, "ZLIB %p invalid magic data\n", image );
return -ENOEXEC;
}
return 0;
}
/** zlib image type */
struct image_type zlib_image_type __image_type ( PROBE_NORMAL ) = {
.name = "zlib",
.probe = zlib_probe,
.extract = zlib_extract,
.exec = image_extract_exec,
};

View File

@ -8,14 +8,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* Little-endian systems should define BYTE_ORDER as LITTLE_ENDIAN.
* This constant is intended to be used only at compile time.
*/
#ifndef __LITTLE_ENDIAN
#define __LITTLE_ENDIAN 0x44332211UL
#endif
/** Constant representing big-endian byte order
*
* Big-endian systems should define BYTE_ORDER as BIG_ENDIAN.
* This constant is intended to be used only at compile time.
*/
#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN 0x11223344UL
#endif
#include "bits/endian.h"

View File

@ -387,7 +387,9 @@ acpi_describe ( struct interface *interface );
typeof ( struct acpi_descriptor * ( object_type ) )
extern void acpi_fix_checksum ( struct acpi_header *acpi );
extern int acpi_sx ( uint32_t signature );
extern int acpi_extract ( uint32_t signature, void *data,
int ( * extract ) ( userptr_t zsdt, size_t len,
size_t offset, void *data ) );
extern void acpi_add ( struct acpi_descriptor *desc );
extern void acpi_del ( struct acpi_descriptor *desc );
extern int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) );

View File

@ -0,0 +1,14 @@
#ifndef _IPXE_ACPIMAC_H
#define _IPXE_ACPIMAC_H
/** @file
*
* ACPI MAC address
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern int acpi_mac ( uint8_t *hw_addr );
#endif /* _IPXE_ACPIMAC_H */

View File

@ -12,6 +12,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/uaccess.h>
extern int cachedhcp_record ( userptr_t data, size_t max_len );
struct cached_dhcp_packet;
extern struct cached_dhcp_packet cached_dhcpack;
extern struct cached_dhcp_packet cached_proxydhcp;
extern struct cached_dhcp_packet cached_pxebs;
extern int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
size_t max_len );
#endif /* _IPXE_CACHEDHCP_H */

View File

@ -9,6 +9,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/image.h>
/** A CPIO archive header
*
* All field are hexadecimal ASCII numbers padded with '0' on the
@ -48,6 +50,25 @@ struct cpio_header {
/** CPIO magic */
#define CPIO_MAGIC "070701"
/** CPIO header length alignment */
#define CPIO_ALIGN 4
/** Alignment for CPIO archives within an initrd */
#define INITRD_ALIGN 4096
/**
* Get CPIO image name
*
* @v image Image
* @ret name Image name (not NUL terminated)
*/
static inline __attribute__ (( always_inline )) const char *
cpio_name ( struct image *image ) {
return image->cmdline;
}
extern void cpio_set_field ( char *field, unsigned long value );
extern size_t cpio_name_len ( struct image *image );
extern size_t cpio_header ( struct image *image, struct cpio_header *cpio );
#endif /* _IPXE_CPIO_H */

View File

@ -56,7 +56,7 @@ dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
* @v dhcppkt DHCP packet
* @ret len Used length
*/
static inline int dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
static inline size_t dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
return ( offsetof ( struct dhcphdr, options ) +
dhcppkt->options.used_len );
}

View File

@ -223,6 +223,7 @@ extern EFI_HANDLE efi_image_handle;
extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
extern EFI_SYSTEM_TABLE *efi_systab;
extern EFI_TPL efi_internal_tpl;
extern EFI_TPL efi_external_tpl;
extern int efi_shutdown_in_progress;

View File

@ -10,7 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
extern EFI_SYSTEM_TABLE * efi_wrap_systab ( void );
extern EFI_BOOT_SERVICES * efi_wrap_bs ( void );
extern void efi_wrap ( EFI_HANDLE handle );
#endif /* _IPXE_EFI_WRAP_H */

View File

@ -77,6 +77,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 )
#define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 )
#define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 )
#define ERRFILE_acpimac ( ERRFILE_CORE | 0x00280000 )
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
@ -213,6 +214,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 )
#define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 )
#define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 )
#define ERRFILE_rdc ( ERRFILE_DRIVER | 0x00d10000 )
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
@ -301,6 +303,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 )
#define ERRFILE_der ( ERRFILE_IMAGE | 0x00080000 )
#define ERRFILE_pem ( ERRFILE_IMAGE | 0x00090000 )
#define ERRFILE_archive ( ERRFILE_IMAGE | 0x000a0000 )
#define ERRFILE_zlib ( ERRFILE_IMAGE | 0x000b0000 )
#define ERRFILE_gzip ( ERRFILE_IMAGE | 0x000c0000 )
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )

71
src/include/ipxe/gzip.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef _IPXE_GZIP_H
#define _IPXE_GZIP_H
/** @file
*
* gzip compressed images
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/image.h>
/** gzip header */
struct gzip_header {
/** Magic ID */
uint16_t magic;
/** Compression method */
uint8_t method;
/** Flags */
uint8_t flags;
/** Modification time */
uint32_t mtime;
/** Extra flags */
uint8_t extra;
/** Operating system */
uint8_t os;
} __attribute__ (( packed ));
/** Magic ID */
#define GZIP_MAGIC 0x1f8b
/** Compression method */
#define GZIP_METHOD_DEFLATE 0x08
/** CRC header is present */
#define GZIP_FL_HCRC 0x02
/** Extra header is present */
#define GZIP_FL_EXTRA 0x04
/** File name is present */
#define GZIP_FL_NAME 0x08
/** File comment is present */
#define GZIP_FL_COMMENT 0x10
/** gzip extra header */
struct gzip_extra_header {
/** Extra header length (excluding this field) */
uint16_t len;
} __attribute__ (( packed ));
/** gzip CRC header */
struct gzip_crc_header {
/** CRC-16 */
uint16_t crc;
} __attribute__ (( packed ));
/** gzip footer */
struct gzip_footer {
/** CRC-32 */
uint32_t crc;
/** Uncompressed size (modulo 2^32) */
uint32_t len;
} __attribute__ (( packed ));
extern struct image_type gzip_image_type __image_type ( PROBE_NORMAL );
#endif /* _IPXE_GZIP_H */

View File

@ -113,6 +113,14 @@ struct image_type {
*/
int ( * asn1 ) ( struct image *image, size_t offset,
struct asn1_cursor **cursor );
/**
* Extract archive image
*
* @v image Image
* @v extracted Extracted image
* @ret rc Return status code
*/
int ( * extract ) ( struct image *image, struct image *extracted );
};
/**
@ -175,6 +183,7 @@ extern struct image * alloc_image ( struct uri *uri );
extern int image_set_uri ( struct image *image, struct uri *uri );
extern int image_set_name ( struct image *image, const char *name );
extern int image_set_cmdline ( struct image *image, const char *cmdline );
extern int image_set_len ( struct image *image, size_t len );
extern int image_set_data ( struct image *image, userptr_t data, size_t len );
extern int register_image ( struct image *image );
extern void unregister_image ( struct image *image );
@ -189,6 +198,9 @@ extern struct image * image_memory ( const char *name, userptr_t data,
extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf );
extern int image_asn1 ( struct image *image, size_t offset,
struct asn1_cursor **cursor );
extern int image_extract ( struct image *image, const char *name,
struct image **extracted );
extern int image_extract_exec ( struct image *image );
/**
* Increment reference count on an image

View File

@ -84,7 +84,7 @@ struct rndis_initialise_completion {
/** Packet alignment factor */
uint32_t align;
/** Reserved */
uint32_t reserved;
uint32_t reserved[2];
} __attribute__ (( packed ));
/** RNDIS halt message */
@ -237,7 +237,7 @@ struct rndis_packet_message {
/** Per-packet information record */
struct rndis_packet_field ppi;
/** Reserved */
uint32_t reserved;
uint32_t reserved[2];
} __attribute__ (( packed ));
/** RNDIS packet record */

68
src/include/ipxe/sbat.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef _IPXE_SBAT_H
#define _IPXE_SBAT_H
/** @file
*
* Secure Boot Advanced Targeting (SBAT)
*
* SBAT defines an encoding for security generation numbers stored as
* a CSV file within a special ".sbat" section in the signed binary.
* If a Secure Boot exploit is discovered then the generation number
* will be incremented alongside the corresponding fix.
*
* Platforms may then record the minimum generation number required
* for any given product. This allows for an efficient revocation
* mechanism that consumes minimal flash storage space (in contrast to
* the DBX mechanism, which allows for only a single-digit number of
* revocation events to ever take place across all possible signed
* binaries).
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* A single line within an SBAT CSV file
*
* @v name Machine-readable component name
* @v generation Security generation number
* @v vendor Human-readable vendor name
* @v package Human-readable package name
* @v version Human-readable package version
* @v uri Contact URI
* @ret line CSV line
*/
#define SBAT_LINE( name, generation, vendor, package, version, uri ) \
name "," _S2 ( generation ) "," vendor "," package "," \
version "," uri "\n"
/** SBAT format generation */
#define SBAT_GENERATION 1
/** Upstream security generation
*
* This represents the security generation of the upstream codebase.
* It will be incremented whenever a Secure Boot exploit is fixed in
* the upstream codebase.
*
* If you do not have commit access to the upstream iPXE repository,
* then you may not modify this value under any circumstances.
*/
#define IPXE_SBAT_GENERATION 1
/* Seriously, do not modify this value */
#if IPXE_SBAT_GENERATION != 1
#error "You may not modify IPXE_SBAT_GENERATION"
#endif
/** SBAT header line */
#define SBAT_HEADER \
SBAT_LINE ( "sbat", SBAT_GENERATION, "SBAT Version", "sbat", \
_S2 ( SBAT_GENERATION ), \
"https://github.com/rhboot/shim/blob/main/SBAT.md" )
/** Mark variable as being in the ".sbat" section */
#define __sbat __attribute__ (( section ( ".sbat" ), aligned ( 512 ) ))
extern const char sbat[] __sbat;
#endif /* _IPXE_SBAT_H */

View File

@ -426,6 +426,7 @@ extern const struct setting_type setting_type_hexhyp __setting_type;
extern const struct setting_type setting_type_hexraw __setting_type;
extern const struct setting_type setting_type_base64 __setting_type;
extern const struct setting_type setting_type_uuid __setting_type;
extern const struct setting_type setting_type_guid __setting_type;
extern const struct setting_type setting_type_busdevfn __setting_type;
extern const struct setting_type setting_type_dnssl __setting_type;

View File

@ -774,7 +774,7 @@ struct srp_aer_rsp {
* The working draft specification for the SRP boot firmware table can
* be found at
*
* http://ipxe.org/wiki/srp/sbft
* https://ipxe.org/wiki/srp/sbft
*
*****************************************************************************
*/

View File

@ -46,6 +46,20 @@ struct parameters;
* scheme = "ftp", user = "joe", password = "secret",
* host = "insecure.org", port = "8081", path = "/hidden/path/to",
* query = "what=is", fragment = "this"
*
* The URI syntax includes a percent-encoding mechanism that can be
* used to represent characters that would otherwise not be possible,
* such as a '/' character within the password field. These encodings
* are decoded during the URI parsing stage, thereby allowing protocol
* implementations to consume the raw field values directly without
* further decoding.
*
* Some protocols (such as HTTP) communicate using URI-encoded values.
* For these protocols, the original encoded substring must be
* retained verbatim since the choice of whether or not to encode a
* particular character may have significance to the receiving
* application. We therefore retain the originally-encoded substrings
* for the path, query, and fragment fields.
*/
struct uri {
/** Reference count */
@ -62,12 +76,14 @@ struct uri {
const char *host;
/** Port number */
const char *port;
/** Path */
/** Path (after URI decoding) */
const char *path;
/** Query */
const char *query;
/** Fragment */
const char *fragment;
/** Path (with original URI encoding) */
const char *epath;
/** Query (with original URI encoding) */
const char *equery;
/** Fragment (with original URI encoding) */
const char *efragment;
/** Form parameters */
struct parameters *params;
} __attribute__ (( packed ));
@ -100,8 +116,9 @@ enum uri_fields {
URI_HOST = URI_FIELD ( host ),
URI_PORT = URI_FIELD ( port ),
URI_PATH = URI_FIELD ( path ),
URI_QUERY = URI_FIELD ( query ),
URI_FRAGMENT = URI_FIELD ( fragment ),
URI_EPATH = URI_FIELD ( epath ),
URI_EQUERY = URI_FIELD ( equery ),
URI_EFRAGMENT = URI_FIELD ( efragment ),
URI_FIELDS
};

View File

@ -1,6 +1,8 @@
#ifndef _VIRTIO_PCI_H_
# define _VIRTIO_PCI_H_
#include <ipxe/dma.h>
/* A 32-bit r/o bitmask of the features supported by the host */
#define VIRTIO_PCI_HOST_FEATURES 0
@ -198,7 +200,8 @@ struct vring_virtqueue;
void vp_free_vq(struct vring_virtqueue *vq);
int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq);
struct vring_virtqueue *vq, struct dma_device *dma_dev,
size_t header_size);
/* Virtio 1.0 I/O routines abstract away the three possible HW access
@ -298,7 +301,8 @@ void vpm_notify(struct virtio_pci_modern_device *vdev,
struct vring_virtqueue *vq);
int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
unsigned nvqs, struct vring_virtqueue *vqs);
unsigned nvqs, struct vring_virtqueue *vqs,
struct dma_device *dma_dev, size_t header_size);
int virtio_pci_find_capability(struct pci_device *pci, uint8_t cfg_type);

View File

@ -2,6 +2,7 @@
# define _VIRTIO_RING_H_
#include <ipxe/virtio-pci.h>
#include <ipxe/dma.h>
/* Status byte for guest to report progress, and synchronize features. */
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
@ -74,17 +75,21 @@ struct vring {
struct vring_virtqueue {
unsigned char *queue;
size_t queue_size;
struct dma_mapping map;
struct dma_device *dma;
struct vring vring;
u16 free_head;
u16 last_used_idx;
void **vdata;
struct virtio_net_hdr_modern *empty_header;
/* PCI */
int queue_index;
struct virtio_pci_region notification;
};
struct vring_list {
char *addr;
physaddr_t addr;
unsigned int length;
};

43
src/include/ipxe/zlib.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef _IPXE_ZLIB_H
#define _IPXE_ZLIB_H
/** @file
*
* zlib compressed images
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <byteswap.h>
#include <ipxe/image.h>
#include <ipxe/deflate.h>
/** zlib magic header */
union zlib_magic {
/** Compression method and flags */
uint8_t cmf;
/** Check value */
uint16_t check;
} __attribute__ (( packed ));
/**
* Check that zlib magic header is valid
*
* @v magic Magic header
* @ret is_valid Magic header is valid
*/
static inline int zlib_magic_is_valid ( union zlib_magic *magic ) {
/* Check magic value as per RFC 6713 */
return ( ( ( magic->cmf & 0x8f ) == 0x08 ) &&
( ( be16_to_cpu ( magic->check ) % 31 ) == 0 ) );
}
extern int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in,
struct image *extracted );
extern struct image_type zlib_image_type __image_type ( PROBE_NORMAL );
#endif /* _IPXE_ZLIB_H */

View File

@ -23,6 +23,8 @@ FILE_LICENCE ( GPL2_ONLY );
#define MII_EXPANSION 0x06 /* Expansion register */
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
#define MII_STAT1000 0x0a /* 1000BASE-T status */
#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
#define MII_ESTATUS 0x0f /* Extended Status */
#define MII_DCOUNTER 0x12 /* Disconnect counter */
#define MII_FCSCOUNTER 0x13 /* False carrier counter */

View File

@ -51,7 +51,8 @@ struct readline_history {
extern void history_free ( struct readline_history *history );
extern int readline_history ( const char *prompt, const char *prefill,
struct readline_history *history, char **line );
struct readline_history *history,
unsigned long timeout, char **line );
extern char * __malloc readline ( const char *prompt );
#endif /* _READLINE_H */

View File

@ -6,7 +6,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdarg.h>
extern void putchar ( int character );
extern int putchar ( int character );
extern int getchar ( void );

View File

@ -189,5 +189,7 @@ bzero ( void *dest, size_t len ) {
}
int __pure strcasecmp ( const char *first, const char *second ) __nonnull;
int __pure strncasecmp ( const char *first, const char *second,
size_t max ) __nonnull;
#endif /* _STRINGS_H */

View File

@ -0,0 +1,16 @@
#ifndef _USR_IMGARCHIVE_H
#define _USR_IMGARCHIVE_H
/** @file
*
* Archive image management
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/image.h>
extern int imgextract ( struct image *image, const char *name );
#endif /* _USR_IMGARCHIVE_H */

View File

@ -75,17 +75,40 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) {
/* Record DHCPACK, if present */
if ( mode->DhcpAckReceived &&
( ( rc = cachedhcp_record ( virt_to_user ( &mode->DhcpAck ),
( ( rc = cachedhcp_record ( &cached_dhcpack,
virt_to_user ( &mode->DhcpAck ),
sizeof ( mode->DhcpAck ) ) ) != 0 ) ) {
DBGC ( device, "EFI %s could not record DHCPACK: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_record;
goto err_dhcpack;
}
/* Record ProxyDHCPOFFER, if present */
if ( mode->ProxyOfferReceived &&
( ( rc = cachedhcp_record ( &cached_proxydhcp,
virt_to_user ( &mode->ProxyOffer ),
sizeof ( mode->ProxyOffer ) ) ) != 0)){
DBGC ( device, "EFI %s could not record ProxyDHCPOFFER: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_proxydhcp;
}
/* Record PxeBSACK, if present */
if ( mode->PxeReplyReceived &&
( ( rc = cachedhcp_record ( &cached_pxebs,
virt_to_user ( &mode->PxeReply ),
sizeof ( mode->PxeReply ) ) ) != 0)){
DBGC ( device, "EFI %s could not record PXEBSACK: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_pxebs;
}
/* Success */
rc = 0;
err_record:
err_pxebs:
err_proxydhcp:
err_dhcpack:
err_ipv6:
bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid,
efi_image_handle, NULL );

View File

@ -104,8 +104,8 @@ static void efi_entropy_disable ( void ) {
/* Close timer tick event */
bs->CloseEvent ( tick );
/* Return to TPL_CALLBACK */
bs->RaiseTPL ( TPL_CALLBACK );
/* Return to internal TPL */
bs->RaiseTPL ( efi_internal_tpl );
}
/**

View File

@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <wchar.h>
#include <ipxe/image.h>
#include <ipxe/cpio.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
#include <ipxe/efi/Protocol/BlockIo.h>
@ -50,17 +51,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** EFI media ID */
#define EFI_MEDIA_ID_MAGIC 0x69505845
/** An image exposed as an EFI file */
/** An EFI virtual file reader */
struct efi_file_reader {
/** EFI file */
struct efi_file *file;
/** Position within virtual file */
size_t pos;
/** Output data buffer */
void *data;
/** Length of output data buffer */
size_t len;
};
/** An EFI file */
struct efi_file {
/** Reference count */
struct refcnt refcnt;
/** EFI file protocol */
EFI_FILE_PROTOCOL file;
/** Image */
/** Image (if any) */
struct image *image;
/** Filename */
const char *name;
/** Current file position */
size_t pos;
/**
* Read from file
*
* @v reader File reader
* @ret len Length read
*/
size_t ( * read ) ( struct efi_file_reader *reader );
};
static struct efi_file efi_file_root;
static struct efi_file efi_file_initrd;
/**
* Free EFI file
*
* @v refcnt Reference count
*/
static void efi_file_free ( struct refcnt *refcnt ) {
struct efi_file *file =
container_of ( refcnt, struct efi_file, refcnt );
image_put ( file->image );
free ( file );
}
/**
* Get EFI file name (for debugging)
@ -70,28 +108,201 @@ static struct efi_file efi_file_root;
*/
static const char * efi_file_name ( struct efi_file *file ) {
return ( file->image ? file->image->name : "<root>" );
return ( file == &efi_file_root ? "<root>" : file->name );
}
/**
* Find EFI file image
*
* @v wname Filename
* @v name Filename
* @ret image Image, or NULL
*/
static struct image * efi_file_find ( const CHAR16 *wname ) {
char name[ wcslen ( wname ) + 1 /* NUL */ ];
static struct image * efi_file_find ( const char *name ) {
struct image *image;
/* Find image */
snprintf ( name, sizeof ( name ), "%ls", wname );
list_for_each_entry ( image, &images, list ) {
if ( strcasecmp ( image->name, name ) == 0 )
return image;
}
return NULL;
}
/**
* Get length of EFI file
*
* @v file EFI file
* @ret len Length of file
*/
static size_t efi_file_len ( struct efi_file *file ) {
struct efi_file_reader reader;
/* If this is the root directory, then treat as length zero */
if ( ! file->read )
return 0;
/* Initialise reader */
reader.file = file;
reader.pos = 0;
reader.data = NULL;
reader.len = 0;
/* Perform dummy read to determine file length */
file->read ( &reader );
return reader.pos;
}
/**
* Read chunk of EFI file
*
* @v reader EFI file reader
* @v data Input data, or UNULL to zero-fill
* @v len Length of input data
* @ret len Length of output data
*/
static size_t efi_file_read_chunk ( struct efi_file_reader *reader,
userptr_t data, size_t len ) {
struct efi_file *file = reader->file;
size_t offset;
/* Calculate offset into input data */
offset = ( file->pos - reader->pos );
/* Consume input data range */
reader->pos += len;
/* Calculate output length */
if ( offset < len ) {
len -= offset;
} else {
len = 0;
}
if ( len > reader->len )
len = reader->len;
/* Copy or zero output data */
if ( data ) {
copy_from_user ( reader->data, data, offset, len );
} else {
memset ( reader->data, 0, len );
}
/* Consume output buffer */
file->pos += len;
reader->data += len;
reader->len -= len;
return len;
}
/**
* Read from image-backed file
*
* @v reader EFI file reader
* @ret len Length read
*/
static size_t efi_file_read_image ( struct efi_file_reader *reader ) {
struct efi_file *file = reader->file;
struct image *image = file->image;
/* Read from file */
return efi_file_read_chunk ( reader, image->data, image->len );
}
/**
* Read from magic initrd file
*
* @v reader EFI file reader
* @ret len Length read
*/
static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
struct efi_file *file = reader->file;
struct cpio_header cpio;
struct image *image;
const char *name;
size_t pad_len;
size_t cpio_len;
size_t name_len;
size_t len;
/* Read from file */
len = 0;
for_each_image ( image ) {
/* Ignore currently executing image */
if ( image == current_image )
continue;
/* Pad to alignment boundary */
pad_len = ( ( -reader->pos ) & ( INITRD_ALIGN - 1 ) );
if ( pad_len ) {
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) pad\n",
efi_file_name ( file ), reader->pos,
( reader->pos + pad_len ) );
}
len += efi_file_read_chunk ( reader, UNULL, pad_len );
/* Read CPIO header, if applicable */
cpio_len = cpio_header ( image, &cpio );
if ( cpio_len ) {
name = cpio_name ( image );
name_len = cpio_name_len ( image );
pad_len = ( cpio_len - sizeof ( cpio ) - name_len );
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s header\n",
efi_file_name ( file ), reader->pos,
( reader->pos + cpio_len ), image->name );
len += efi_file_read_chunk ( reader,
virt_to_user ( &cpio ),
sizeof ( cpio ) );
len += efi_file_read_chunk ( reader,
virt_to_user ( name ),
name_len );
len += efi_file_read_chunk ( reader, UNULL, pad_len );
}
/* Read file data */
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s\n",
efi_file_name ( file ), reader->pos,
( reader->pos + image->len ), image->name );
len += efi_file_read_chunk ( reader, image->data, image->len );
}
return len;
}
/**
* Open fixed file
*
* @v file EFI file
* @v new New EFI file
* @ret efirc EFI status code
*/
static EFI_STATUS efi_file_open_fixed ( struct efi_file *file,
EFI_FILE_PROTOCOL **new ) {
/* Increment reference count */
ref_get ( &file->refcnt );
/* Return opened file */
*new = &file->file;
DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) );
return 0;
}
/**
* Associate file with image
*
* @v file EFI file
* @v image Image
*/
static void efi_file_image ( struct efi_file *file, struct image *image ) {
file->image = image;
file->name = image->name;
file->read = efi_file_read_image;
}
/**
@ -106,50 +317,60 @@ static struct image * efi_file_find ( const CHAR16 *wname ) {
*/
static EFI_STATUS EFIAPI
efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
CHAR16 *wname, UINT64 mode __unused,
UINT64 attributes __unused ) {
CHAR16 *wname, UINT64 mode, UINT64 attributes __unused ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
char buf[ wcslen ( wname ) + 1 /* NUL */ ];
struct efi_file *new_file;
struct image *image;
char *name;
/* Convert name to ASCII */
snprintf ( buf, sizeof ( buf ), "%ls", wname );
name = buf;
/* Initial '\' indicates opening from the root directory */
while ( *wname == L'\\' ) {
while ( *name == '\\' ) {
file = &efi_file_root;
wname++;
name++;
}
/* Allow root directory itself to be opened */
if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
*new = &efi_file_root.file;
return 0;
}
if ( ( name[0] == '\0' ) || ( name[0] == '.' ) )
return efi_file_open_fixed ( &efi_file_root, new );
/* Fail unless opening from the root */
if ( file->image ) {
if ( file != &efi_file_root ) {
DBGC ( file, "EFIFILE %s is not a directory\n",
efi_file_name ( file ) );
return EFI_NOT_FOUND;
}
/* Identify image */
image = efi_file_find ( wname );
if ( ! image ) {
DBGC ( file, "EFIFILE \"%ls\" does not exist\n", wname );
return EFI_NOT_FOUND;
}
/* Fail unless opening read-only */
if ( mode != EFI_FILE_MODE_READ ) {
DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
image->name, mode );
name, mode );
return EFI_WRITE_PROTECTED;
}
/* Allow magic initrd to be opened */
if ( strcasecmp ( name, efi_file_initrd.name ) == 0 )
return efi_file_open_fixed ( &efi_file_initrd, new );
/* Identify image */
image = efi_file_find ( name );
if ( ! image ) {
DBGC ( file, "EFIFILE %s does not exist\n", name );
return EFI_NOT_FOUND;
}
/* Allocate and initialise file */
new_file = zalloc ( sizeof ( *new_file ) );
if ( ! new_file )
return EFI_OUT_OF_RESOURCES;
ref_init ( &file->refcnt, efi_file_free );
memcpy ( &new_file->file, &efi_file_root.file,
sizeof ( new_file->file ) );
new_file->image = image_get ( image );
efi_file_image ( new_file, image_get ( image ) );
*new = &new_file->file;
DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
@ -165,14 +386,9 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
/* Do nothing if this is the root */
if ( ! file->image )
return 0;
/* Close file */
DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
image_put ( file->image );
free ( file );
ref_put ( &file->refcnt );
return 0;
}
@ -229,30 +445,29 @@ static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
/**
* Return file information structure
*
* @v image Image, or NULL for the root directory
* @v file EFI file
* @v len Length of data buffer
* @v data Data buffer
* @ret efirc EFI status code
*/
static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
static EFI_STATUS efi_file_info ( struct efi_file *file, UINTN *len,
VOID *data ) {
EFI_FILE_INFO info;
const char *name;
size_t file_len;
/* Get file length */
file_len = efi_file_len ( file );
/* Populate file information */
memset ( &info, 0, sizeof ( info ) );
if ( image ) {
info.FileSize = image->len;
info.PhysicalSize = image->len;
info.Attribute = EFI_FILE_READ_ONLY;
name = image->name;
} else {
info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
name = "";
}
info.FileSize = file_len;
info.PhysicalSize = file_len;
info.Attribute = EFI_FILE_READ_ONLY;
if ( file == &efi_file_root )
info.Attribute |= EFI_FILE_DIRECTORY;
return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
len, data );
return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO,
file->name, len, data );
}
/**
@ -266,14 +481,16 @@ static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
VOID *data ) {
EFI_STATUS efirc;
struct efi_file entry;
struct image *image;
unsigned int index;
/* Construct directory entry at current position */
/* Construct directory entries for image-backed files */
index = file->pos;
for_each_image ( image ) {
if ( index-- == 0 ) {
efirc = efi_file_info ( image, len, data );
efi_file_image ( &entry, image );
efirc = efi_file_info ( &entry, len, data );
if ( efirc == 0 )
file->pos++;
return efirc;
@ -296,21 +513,25 @@ static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
UINTN *len, VOID *data ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
size_t remaining;
struct efi_file_reader reader;
size_t pos = file->pos;
/* If this is the root directory, then construct a directory entry */
if ( ! file->image )
if ( ! file->read )
return efi_file_read_dir ( file, len, data );
/* Initialise reader */
reader.file = file;
reader.pos = 0;
reader.data = data;
reader.len = *len;
/* Read from the file */
remaining = ( file->image->len - file->pos );
if ( *len > remaining )
*len = remaining;
DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
efi_file_name ( file ), file->pos,
( ( size_t ) ( file->pos + *len ) ) );
copy_from_user ( data, file->image->data, file->pos, *len );
file->pos += *len;
efi_file_name ( file ), pos, file->pos );
*len = file->read ( &reader );
assert ( ( pos + *len ) == file->pos );
return 0;
}
@ -342,24 +563,21 @@ static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
UINT64 position ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
size_t len;
/* If this is the root directory, reset to the start */
if ( ! file->image ) {
DBGC ( file, "EFIFILE root directory rewound\n" );
file->pos = 0;
return 0;
}
/* Get file length */
len = efi_file_len ( file );
/* Check for the magic end-of-file value */
if ( position == 0xffffffffffffffffULL )
position = file->image->len;
position = len;
/* Fail if we attempt to seek past the end of the file (since
* we do not support writes).
*/
if ( position > file->image->len ) {
if ( position > len ) {
DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
efi_file_name ( file ), position, file->image->len );
efi_file_name ( file ), position, len );
return EFI_UNSUPPORTED;
}
@ -408,7 +626,7 @@ static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
/* Get file information */
DBGC ( file, "EFIFILE %s get file information\n",
efi_file_name ( file ) );
return efi_file_info ( file->image, len, data );
return efi_file_info ( file, len, data );
} else if ( memcmp ( type, &efi_file_system_info_id,
sizeof ( *type ) ) == 0 ) {
@ -468,6 +686,7 @@ static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
/** Root directory */
static struct efi_file efi_file_root = {
.refcnt = REF_INIT ( ref_no_free ),
.file = {
.Revision = EFI_FILE_PROTOCOL_REVISION,
.Open = efi_file_open,
@ -482,6 +701,28 @@ static struct efi_file efi_file_root = {
.Flush = efi_file_flush,
},
.image = NULL,
.name = "",
};
/** Magic initrd file */
static struct efi_file efi_file_initrd = {
.refcnt = REF_INIT ( ref_no_free ),
.file = {
.Revision = EFI_FILE_PROTOCOL_REVISION,
.Open = efi_file_open,
.Close = efi_file_close,
.Delete = efi_file_delete,
.Read = efi_file_read,
.Write = efi_file_write,
.GetPosition = efi_file_get_position,
.SetPosition = efi_file_set_position,
.GetInfo = efi_file_get_info,
.SetInfo = efi_file_set_info,
.Flush = efi_file_flush,
},
.image = NULL,
.name = "initrd.magic",
.read = efi_file_read_initrd,
};
/**
@ -496,8 +737,7 @@ efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
EFI_FILE_PROTOCOL **file ) {
DBGC ( &efi_file_root, "EFIFILE open volume\n" );
*file = &efi_file_root.file;
return 0;
return efi_file_open_fixed ( &efi_file_root, file );
}
/** EFI simple file system protocol */

View File

@ -47,6 +47,9 @@ EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
*/
EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab );
/** Internal task priority level */
EFI_TPL efi_internal_tpl = TPL_CALLBACK;
/** External task priority level */
EFI_TPL efi_external_tpl = TPL_APPLICATION;
@ -79,6 +82,17 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
void *context __unused ) {
/* This callback is invoked at TPL_NOTIFY in order to ensure
* that we have an opportunity to shut down cleanly before
* other shutdown hooks perform destructive operations such as
* disabling the IOMMU.
*
* Modify the internal task priority level so that no code
* attempts to raise from TPL_NOTIFY to TPL_CALLBACK (which
* would trigger a fatal exception).
*/
efi_internal_tpl = TPL_NOTIFY;
/* Mark shutdown as being in progress, to indicate that large
* parts of the system (e.g. timers) are no longer functional.
*/
@ -273,7 +287,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
* bother doing so when ExitBootServices() is called.
*/
if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
TPL_CALLBACK, efi_shutdown_hook,
TPL_NOTIFY, efi_shutdown_hook,
NULL, &efi_shutdown_event ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( systab, "EFI could not create ExitBootServices event: "
@ -316,9 +330,13 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_SYSTEM_TABLE *systab = efi_systab;
struct efi_saved_tpl tpl;
DBGC ( systab, "EFI image unloading\n" );
/* Raise TPL */
efi_raise_tpl ( &tpl );
/* Shut down */
shutdown_exit();
@ -336,6 +354,9 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
DBGC ( systab, "EFI image unloaded\n" );
/* Restore TPL */
efi_restore_tpl ( &tpl );
return 0;
}
@ -366,7 +387,7 @@ __attribute__ (( noreturn )) void __stack_chk_fail ( void ) {
}
/**
* Raise task priority level to TPL_CALLBACK
* Raise task priority level to internal level
*
* @v tpl Saved TPL
*/
@ -377,7 +398,7 @@ void efi_raise_tpl ( struct efi_saved_tpl *tpl ) {
tpl->previous = efi_external_tpl;
/* Raise TPL and record previous TPL as new external TPL */
tpl->current = bs->RaiseTPL ( TPL_CALLBACK );
tpl->current = bs->RaiseTPL ( efi_internal_tpl );
efi_external_tpl = tpl->current;
}

View File

@ -337,6 +337,9 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
offset = le64_to_cpu ( u.res->qword.offset );
start = ( offset + le64_to_cpu ( u.res->qword.min ) );
end = ( start + le64_to_cpu ( u.res->qword.len ) );
DBGC2 ( pci, "EFIPCI " PCI_FMT " found range [%08llx,%08llx) "
"-> [%08llx,%08llx)\n", PCI_ARGS ( pci ), start, end,
( start - offset ), ( end - offset ) );
if ( ( bus_addr < start ) || ( ( bus_addr + len ) > end ) )
continue;
@ -523,7 +526,8 @@ static void * efipci_dma_alloc ( struct dma_device *dma,
/* Map buffer */
if ( ( rc = efipci_dma_map ( dma, map, virt_to_phys ( addr ),
len, DMA_BI ) ) != 0 )
( pages * EFI_PAGE_SIZE ),
DMA_BI ) ) != 0 )
goto err_map;
/* Increment allocation count (for debugging) */

View File

@ -137,7 +137,7 @@ static unsigned long efi_currticks ( void ) {
efi_jiffies++;
} else {
bs->RestoreTPL ( efi_external_tpl );
bs->RaiseTPL ( TPL_CALLBACK );
bs->RaiseTPL ( efi_internal_tpl );
}
return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );

View File

@ -362,7 +362,7 @@ static int efi_veto_driver ( EFI_HANDLE driver ) {
}
/**
* Veto Dell Ip4ConfigDxe driver
* Veto Ip4ConfigDxe driver on some platforms
*
* @v binding Driver binding protocol
* @v loaded Loaded image protocol
@ -372,19 +372,21 @@ static int efi_veto_driver ( EFI_HANDLE driver ) {
* @ret vetoed Driver is to be vetoed
*/
static int
efi_veto_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
const char *manufacturer, const CHAR16 *name ) {
efi_veto_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
const char *manufacturer, const CHAR16 *name ) {
static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
static const char *dell = "Dell Inc.";
static const char *itautec = "Itautec S.A.";
/* Check manufacturer and driver name */
if ( ! manufacturer )
return 0;
if ( ! name )
return 0;
if ( strcmp ( manufacturer, dell ) != 0 )
if ( ( strcmp ( manufacturer, dell ) != 0 ) &&
( strcmp ( manufacturer, itautec ) != 0 ) )
return 0;
if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 )
return 0;
@ -436,8 +438,8 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
/** Driver vetoes */
static struct efi_veto efi_vetoes[] = {
{
.name = "Dell Ip4Config",
.veto = efi_veto_dell_ip4config,
.name = "Ip4Config",
.veto = efi_veto_ip4config,
},
{
.name = "HP Xhci",

View File

@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/retry.h>
#include <ipxe/timer.h>
#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_watchdog.h>
@ -80,3 +81,36 @@ static void efi_watchdog_expired ( struct retry_timer *timer,
/** Watchdog holdoff timer */
struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired );
/**
* Disable watching when shutting down to boot an operating system
*
* @v booting System is shutting down for OS boot
*/
static void efi_watchdog_shutdown ( int booting ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_STATUS efirc;
int rc;
/* If we are shutting down to boot an operating system, then
* disable the boot services watchdog timer. The UEFI
* specification mandates that the platform firmware does this
* as part of the ExitBootServices() call, but some platforms
* (e.g. Hyper-V) are observed to occasionally forget to do
* so, resulting in a reboot approximately five minutes after
* starting the operating system.
*/
if ( booting &&
( ( efirc = bs->SetWatchdogTimer ( 0, 0, 0, NULL ) ) != 0 ) ) {
rc = -EEFI ( efirc );
DBGC ( &efi_watchdog, "EFI could not disable watchdog timer: "
"%s\n", strerror ( rc ) );
/* Nothing we can do */
}
}
/** Watchdog startup/shutdown function */
struct startup_fn efi_watchdog_startup_fn __startup_fn ( STARTUP_EARLY ) = {
.name = "efi_watchdog",
.shutdown = efi_watchdog_shutdown,
};

View File

@ -195,6 +195,47 @@ static const char * efi_timer_delay ( EFI_TIMER_DELAY type ) {
}
}
/**
* Dump information about a loaded image
*
* @v handle Image handle
*/
static void efi_dump_image ( EFI_HANDLE handle ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
EFI_LOADED_IMAGE_PROTOCOL *image;
void *intf;
} loaded;
EFI_STATUS efirc;
int rc;
/* Open loaded image protocol */
if ( ( efirc = bs->OpenProtocol ( handle,
&efi_loaded_image_protocol_guid,
&loaded.intf, efi_image_handle, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
rc = -EEFI ( efirc );
DBGC ( colour, "WRAP %s could not get loaded image protocol: "
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
return;
}
/* Dump image information */
DBGC ( colour, "WRAP %s at base %p has protocols:\n",
efi_handle_name ( handle ), loaded.image->ImageBase );
DBGC_EFI_PROTOCOLS ( colour, handle );
DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) );
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle ));
DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) );
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle ));
DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) );
DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) );
/* Close loaded image protocol */
bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid,
efi_image_handle, NULL );
}
/**
* Wrap RaiseTPL()
*
@ -655,9 +696,9 @@ efi_load_image_wrapper ( BOOLEAN boot_policy, EFI_HANDLE parent_image_handle,
DBGC ( colour, "%s ", efi_handle_name ( *image_handle ) );
DBGC ( colour, ") -> %p\n", retaddr );
/* Wrap the new image */
/* Dump information about loaded image */
if ( efirc == 0 )
efi_wrap ( *image_handle );
efi_dump_image ( *image_handle );
return efirc;
}
@ -735,11 +776,14 @@ efi_exit_boot_services_wrapper ( EFI_HANDLE image_handle, UINTN map_key ) {
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGC ( colour, "ExitBootServices ( %s, %#llx ) ",
DBGC ( colour, "ExitBootServices ( %s, %#llx ) -> %p\n",
efi_handle_name ( image_handle ),
( ( unsigned long long ) map_key ) );
( ( unsigned long long ) map_key ), retaddr );
efirc = bs->ExitBootServices ( image_handle, map_key );
DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
if ( efirc != 0 ) {
DBGC ( colour, "ExitBootServices ( ... ) = %s -> %p\n",
efi_status ( efirc ), retaddr );
}
return efirc;
}
@ -1129,12 +1173,11 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl,
}
/**
* Build table wrappers
* Build boot services table wrapper
*
* @ret systab Wrapped system table
* @ret bs Wrapped boot services table
*/
EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
static EFI_SYSTEM_TABLE efi_systab_wrapper;
EFI_BOOT_SERVICES * efi_wrap_bs ( void ) {
static EFI_BOOT_SERVICES efi_bs_wrapper;
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
@ -1194,12 +1237,7 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
= efi_uninstall_multiple_protocol_interfaces_wrapper;
efi_bs_wrapper.CreateEventEx = efi_create_event_ex_wrapper;
/* Build system table wrapper */
memcpy ( &efi_systab_wrapper, efi_systab,
sizeof ( efi_systab_wrapper ) );
efi_systab_wrapper.BootServices = &efi_bs_wrapper;
return &efi_systab_wrapper;
return &efi_bs_wrapper;
}
/**
@ -1208,42 +1246,20 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
* @v handle Image handle
*/
void efi_wrap ( EFI_HANDLE handle ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
EFI_LOADED_IMAGE_PROTOCOL *image;
void *intf;
} loaded;
EFI_STATUS efirc;
int rc;
static EFI_SYSTEM_TABLE efi_systab_copy;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return;
/* Open loaded image protocol */
if ( ( efirc = bs->OpenProtocol ( handle,
&efi_loaded_image_protocol_guid,
&loaded.intf, efi_image_handle, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
rc = -EEFI ( efirc );
DBGC ( colour, "WRAP %s could not get loaded image protocol: "
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
return;
/* Construct modified system table */
if ( efi_systab != &efi_systab_copy ) {
memcpy ( &efi_systab_copy, efi_systab,
sizeof ( efi_systab_copy ) );
efi_systab->BootServices = efi_wrap_bs();
efi_systab = &efi_systab_copy;
}
/* Provide system table wrapper to image */
loaded.image->SystemTable = efi_wrap_systab();
DBGC ( colour, "WRAP %s at base %p has protocols:\n",
efi_handle_name ( handle ), loaded.image->ImageBase );
DBGC_EFI_PROTOCOLS ( colour, handle );
DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) );
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle ));
DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) );
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle ));
DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) );
DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) );
/* Close loaded image protocol */
bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid,
efi_image_handle, NULL );
/* Dump image information */
efi_dump_image ( handle );
}

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