Merge ~paelzer/ubuntu/+source/ipxe:merge-20220113.fbbdc3926-jammy into ubuntu/+source/ipxe:ubuntu/jammy-devel

Proposed by Christian Ehrhardt 
Status: Merged
Merge reported by: Christian Ehrhardt 
Merged at revision: cf332c19e756abe964d0f3fbd108495f684de5c8
Proposed branch: ~paelzer/ubuntu/+source/ipxe:merge-20220113.fbbdc3926-jammy
Merge into: ubuntu/+source/ipxe:ubuntu/jammy-devel
Diff against target: 7130 lines (+3773/-672)
110 files modified
contrib/cloud/aws-import (+51/-12)
debian/changelog (+8/-0)
debian/control (+1/-0)
debian/grub-ipxe.install (+1/-0)
debian/rules (+13/-3)
src/Makefile (+1/-1)
src/Makefile.efi (+2/-1)
src/Makefile.housekeeping (+4/-3)
src/arch/x86/core/x86_bigint.c (+6/-5)
src/arch/x86/drivers/net/undinet.c (+9/-2)
src/arch/x86/image/bzimage.c (+3/-49)
src/arch/x86/image/initrd.c (+1/-0)
src/arch/x86/include/bits/bigint.h (+37/-17)
src/arch/x86/include/initrd.h (+0/-7)
src/arch/x86/include/ipxe/cpuid.h (+3/-0)
src/arch/x86/interface/pcbios/acpipwr.c (+66/-4)
src/arch/x86/interface/pcbios/bios_cachedhcp.c (+2/-1)
src/arch/x86/interface/pcbios/rtc_entropy.c (+11/-0)
src/arch/x86/interface/syslinux/comboot_call.c (+1/-1)
src/arch/x86/prefix/romprefix.S (+2/-2)
src/arch/x86/prefix/unlzma.S (+1/-1)
src/config/branding.h (+12/-12)
src/config/cloud/aws.ipxe (+18/-2)
src/config/cloud/gce.ipxe (+2/-1)
src/config/cloud/settings.h (+2/-0)
src/config/config.c (+6/-0)
src/config/config_archive.c (+36/-0)
src/config/general.h (+3/-0)
src/core/acpi.c (+30/-64)
src/core/acpimac.c (+154/-0)
src/core/archive.c (+138/-0)
src/core/base64.c (+1/-1)
src/core/cachedhcp.c (+130/-45)
src/core/console.c (+4/-1)
src/core/cpio.c (+85/-0)
src/core/image.c (+21/-4)
src/core/open.c (+2/-1)
src/core/settings.c (+18/-5)
src/core/string.c (+16/-1)
src/core/uri.c (+80/-51)
src/crypto/x509.c (+2/-1)
src/drivers/bus/virtio-pci.c (+30/-15)
src/drivers/bus/virtio-ring.c (+2/-2)
src/drivers/net/ath/ath5k/ath5k_eeprom.c (+3/-0)
src/drivers/net/bnxt/bnxt.c (+63/-5)
src/drivers/net/bnxt/bnxt.h (+1/-136)
src/drivers/net/ecm.c (+15/-5)
src/drivers/net/ecm.h (+1/-1)
src/drivers/net/efi/nii.c (+1/-1)
src/drivers/net/efi/snpnet.c (+14/-4)
src/drivers/net/intel.c (+12/-0)
src/drivers/net/intelx.c (+1/-0)
src/drivers/net/ncm.c (+1/-1)
src/drivers/net/rdc.c (+694/-0)
src/drivers/net/rdc.h (+194/-0)
src/drivers/net/realtek.c (+10/-0)
src/drivers/net/virtio-net.c (+25/-11)
src/drivers/usb/xhci.c (+71/-2)
src/drivers/usb/xhci.h (+2/-0)
src/hci/commands/image_archive_cmd.c (+105/-0)
src/hci/readline.c (+17/-7)
src/image/gzip.c (+167/-0)
src/image/zlib.c (+163/-0)
src/include/endian.h (+4/-0)
src/include/ipxe/acpi.h (+3/-1)
src/include/ipxe/acpimac.h (+14/-0)
src/include/ipxe/cachedhcp.h (+8/-1)
src/include/ipxe/cpio.h (+21/-0)
src/include/ipxe/dhcppkt.h (+1/-1)
src/include/ipxe/efi/efi.h (+1/-0)
src/include/ipxe/efi/efi_wrap.h (+1/-1)
src/include/ipxe/errfile.h (+5/-0)
src/include/ipxe/gzip.h (+71/-0)
src/include/ipxe/image.h (+12/-0)
src/include/ipxe/rndis.h (+2/-2)
src/include/ipxe/settings.h (+1/-0)
src/include/ipxe/srp.h (+1/-1)
src/include/ipxe/uri.h (+24/-7)
src/include/ipxe/virtio-pci.h (+6/-2)
src/include/ipxe/virtio-ring.h (+6/-1)
src/include/ipxe/zlib.h (+43/-0)
src/include/mii.h (+2/-0)
src/include/stdio.h (+1/-1)
src/include/strings.h (+2/-0)
src/include/usr/imgarchive.h (+16/-0)
src/interface/efi/efi_cachedhcp.c (+26/-3)
src/interface/efi/efi_entropy.c (+2/-2)
src/interface/efi/efi_file.c (+309/-69)
src/interface/efi/efi_init.c (+24/-3)
src/interface/efi/efi_timer.c (+1/-1)
src/interface/efi/efi_veto.c (+10/-8)
src/interface/efi/efi_watchdog.c (+34/-0)
src/interface/efi/efi_wrap.c (+62/-46)
src/interface/smbios/smbios_settings.c (+2/-1)
src/net/peerdisc.c (+23/-0)
src/net/tcp/httpconn.c (+2/-1)
src/net/tcp/httpcore.c (+2/-2)
src/tests/gzip_test.c (+160/-0)
src/tests/settings_test.c (+10/-0)
src/tests/string_test.c (+8/-0)
src/tests/tests.c (+2/-0)
src/tests/uri_test.c (+40/-13)
src/tests/x509_test.c (+1/-0)
src/tests/zlib_test.c (+133/-0)
src/usr/autoboot.c (+2/-2)
src/usr/imgarchive.c (+54/-0)
src/usr/imgmgmt.c (+2/-2)
src/util/elf2efi.c (+24/-10)
src/util/genfsimg (+19/-2)
src/util/niclist.pl (+1/-1)
Reviewer Review Type Date Requested Status
Andreas Hasenack Approve
Canonical Server Pending
git-ubuntu import Pending
Review via email: mp+414650@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

PPA: https://launchpad.net/~ci-train-ppa-service/+archive/ubuntu/4753/+packages

Regression tests are ongoing, but looking good enough by now to get the reviews started.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

FYI regression tests are mostly good (no ipxe issue left, just libvirt)

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Forgive my noobness with things ipxe, but why isn't this package just built again on arm64 (and armhf, and riscv, and ...)? Why keep it arch all?

Is this a case where the built files are on the server, and it can happily "serve" binaries from other architectures depending on the architecture of the booting client?

review: Needs Information
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Hi Andreas,
first of all it only needs/wants/supports arm64 + x86 - no other arch builds make sense.

Furthermore we'd want to keep it arch-all for a few reasons:
1. there are use cases of qemu emulating arm64 on any other arch, for that you'd want ipxe-arm64 there and being arch-all allows to use these roms just anywhere
2. Keeping a single build on just x86 is easier to debug and faster to build than having two builds (e.g. a common developer can fully run it on a laptop)
3. keeping both built by the same step allows us to keep the same package and dependencies.
   If we'd have two we#d either have:
   - two arch:all packages with new name/dependencies
   - one arch:any that for usage on non-primary architecture would need to be added via foreign-architecture

Overall the way as proposed is better for the developer, builds on LP and most importantly even the user without any drawback related to it.

Does that explain it enough Andreas?

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Yes, thanks
+1

review: Approve
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Uploading as tested

Uploading to ubuntu (via ftp to upload.ubuntu.com):
  Uploading ipxe_1.21.1+git-20220113.fbbdc3926-0ubuntu1.dsc: done.
  Uploading ipxe_1.21.1+git-20220113.fbbdc3926.orig.tar.gz: done.
  Uploading ipxe_1.21.1+git-20220113.fbbdc3926-0ubuntu1.debian.tar.xz: done.
  Uploading ipxe_1.21.1+git-20220113.fbbdc3926-0ubuntu1_source.buildinfo: done.
  Uploading ipxe_1.21.1+git-20220113.fbbdc3926-0ubuntu1_source.changes: done.
Successfully uploaded packages.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/contrib/cloud/aws-import b/contrib/cloud/aws-import
2index 9ee53e7..eef4302 100755
3--- a/contrib/cloud/aws-import
4+++ b/contrib/cloud/aws-import
5@@ -3,14 +3,25 @@
6 import argparse
7 from base64 import b64encode
8 from concurrent.futures import ThreadPoolExecutor, as_completed
9+from datetime import date
10 from hashlib import sha256
11 from itertools import count
12+import subprocess
13
14 import boto3
15
16 BLOCKSIZE = 512 * 1024
17
18
19+def detect_architecture(image):
20+ """Detect CPU architecture"""
21+ mdir = subprocess.run(['mdir', '-b', '-i', image, '::/EFI/BOOT'],
22+ capture_output=True)
23+ if any(b'BOOTAA64.EFI' in x for x in mdir.stdout.splitlines()):
24+ return 'arm64'
25+ return 'x86_64'
26+
27+
28 def create_snapshot(region, description, image):
29 """Create an EBS snapshot"""
30 client = boto3.client('ebs', region_name=region)
31@@ -65,36 +76,64 @@ def import_image(region, name, architecture, image, public):
32 return image_id
33
34
35+def launch_link(region, image_id):
36+ """Construct a web console launch link"""
37+ return ("https://console.aws.amazon.com/ec2/v2/home?"
38+ "region=%s#LaunchInstanceWizard:ami=%s" % (region, image_id))
39+
40+
41 # Parse command-line arguments
42 parser = argparse.ArgumentParser(description="Import AWS EC2 image (AMI)")
43-parser.add_argument('--architecture', '-a', default='x86_64',
44- help="CPU architecture")
45-parser.add_argument('--name', '-n', required=True,
46+parser.add_argument('--name', '-n',
47 help="Image name")
48 parser.add_argument('--public', '-p', action='store_true',
49 help="Make image public")
50 parser.add_argument('--region', '-r', action='append',
51 help="AWS region(s)")
52-parser.add_argument('image', help="iPXE disk image")
53+parser.add_argument('--wiki', '-w', metavar='FILE',
54+ help="Generate Dokuwiki table")
55+parser.add_argument('image', nargs='+', help="iPXE disk image")
56 args = parser.parse_args()
57
58+# Detect CPU architectures
59+architectures = {image: detect_architecture(image) for image in args.image}
60+
61+# Use default name if none specified
62+if not args.name:
63+ args.name = 'iPXE (%s)' % date.today().strftime('%Y-%m-%d')
64+
65 # Use all regions if none specified
66 if not args.region:
67 args.region = sorted(x['RegionName'] for x in
68 boto3.client('ec2').describe_regions()['Regions'])
69
70-# Use one thread per region to maximise parallelism
71-with ThreadPoolExecutor(max_workers=len(args.region)) as executor:
72+# Use one thread per import to maximise parallelism
73+imports = [(region, image) for region in args.region for image in args.image]
74+with ThreadPoolExecutor(max_workers=len(imports)) as executor:
75 futures = {executor.submit(import_image,
76 region=region,
77 name=args.name,
78- architecture=args.architecture,
79- image=args.image,
80- public=args.public): region
81- for region in args.region}
82+ architecture=architectures[image],
83+ image=image,
84+ public=args.public): (region, image)
85+ for region, image in imports}
86 results = {futures[future]: future.result()
87 for future in as_completed(futures)}
88
89+# Construct Dokuwiki table
90+wikitab = ["^ AWS region ^ CPU architecture ^ AMI ID ^\n"] + list(
91+ "| ''%s'' | ''%s'' | ''[[%s|%s]]'' |\n" % (
92+ region,
93+ architectures[image],
94+ launch_link(region, results[(region, image)]),
95+ results[(region, image)],
96+ ) for region, image in imports)
97+if args.wiki:
98+ with open(args.wiki, 'wt') as fh:
99+ fh.writelines(wikitab)
100+
101 # Show created images
102-for region in args.region:
103- print("%s: %s" % (region, results[region]))
104+for region, image in imports:
105+ print("%s %s %s %s" % (
106+ region, image, architectures[image], results[(region, image)]
107+ ))
108diff --git a/debian/changelog b/debian/changelog
109index e9fe661..1c1aed4 100644
110--- a/debian/changelog
111+++ b/debian/changelog
112@@ -1,3 +1,11 @@
113+ipxe (1.21.1+git-20220113.fbbdc3926-0ubuntu1) jammy; urgency=medium
114+
115+ * Bump code to 1.21.1+git-20220113.fbbdc3926
116+ * d/grub-ipxe.install, d/control, d/rules: Build ipxe-arm64.efi
117+ (LP: #1890230)
118+
119+ -- Christian Ehrhardt <christian.ehrhardt@canonical.com> Thu, 13 Jan 2022 14:53:40 +0100
120+
121 ipxe (1.21.1+git-20210429.323af9ee-0ubuntu1) impish; urgency=medium
122
123 * Bump code to 1.21.1+git-20210429.323af9ee
124diff --git a/debian/control b/debian/control
125index fea0238..1d324df 100644
126--- a/debian/control
127+++ b/debian/control
128@@ -9,6 +9,7 @@ Build-Depends:
129 dh-exec,
130 xorriso, isolinux, syslinux-common, syslinux-utils, dosfstools, mtools,
131 binutils-dev, liblzma-dev, zlib1g-dev,
132+ gcc-aarch64-linux-gnu,
133 Standards-Version: 3.9.6
134 Homepage: http://ipxe.org/
135 Vcs-Git: https://salsa.debian.org/waldi/ipxe.git
136diff --git a/debian/grub-ipxe.install b/debian/grub-ipxe.install
137index 7284a31..faac8e1 100644
138--- a/debian/grub-ipxe.install
139+++ b/debian/grub-ipxe.install
140@@ -1,3 +1,4 @@
141 debian/tree/ipxe/* .
142 src/bin-i386-pcbios/ipxe.lkrn boot
143 src/bin-x86_64-efi/ipxe.efi boot
144+src/bin-arm64-efi/ipxe-arm64.efi boot
145diff --git a/debian/rules b/debian/rules
146index d2885cf..d6108cf 100755
147--- a/debian/rules
148+++ b/debian/rules
149@@ -23,7 +23,10 @@ src/bin-i386-pcbios/%.rom src/bin-x86_64-efi/%.efirom: export CONFIG=qemu
150 # qemu EFI roms are built without HTTPS, EFI does that on its own (and better)
151 src/bin-x86_64-efi/%.efirom: export NOHTTPS=true
152
153-src/bin-i386-pcbios/% src/bin-x86_64-efi/%:
154+# Note: d/rules Makefile logic can't differentiate src/bin-arm64-efi/ipxe.efi
155+# from src/bin-x86_64-efi/ipxe.efi which makes these steps more complex and
156+# ugly than they should be.
157+src/bin-i386-pcbios/% src/bin-x86_64-efi/% src/bin-arm64-efi/%.efi:
158 # clean and reconfigure if either NOHTTPS or CONFIG=qemu switches
159 if [ "config:$(CONFIG)nohttps:$(NOHTTPS)" != "$(shell cat debian/last-used-config 2>/dev/null)" ]; then \
160 if [ "$(NOHTTPS)" = "true" ]; then \
161@@ -33,8 +36,15 @@ src/bin-i386-pcbios/% src/bin-x86_64-efi/%:
162 fi; \
163 echo -n "config:$(CONFIG)" > debian/last-used-config; \
164 echo -n "nohttps:$(NOHTTPS)" >> debian/last-used-config; \
165- fi;
166- dh_auto_build --sourcedirectory=src -- V=1 NO_WERROR=1 VERSION="$(VERSION)" $(subst src/,,$@)
167+ fi; \
168+ if [ "$@" = "src/bin-arm64-efi/ipxe-arm64.efi" ]; then \
169+ export CROSS=aarch64-linux-gnu-; \
170+ export CC=aarch64-linux-gnu-gcc; \
171+ dh_auto_build --sourcedirectory=src -- V=1 NO_WERROR=1 VERSION="$(VERSION)" bin-arm64-efi/ipxe.efi; \
172+ mv src/bin-arm64-efi/ipxe.efi src/bin-arm64-efi/ipxe-arm64.efi; \
173+ else \
174+ dh_auto_build --sourcedirectory=src -- V=1 NO_WERROR=1 VERSION="$(VERSION)" $(subst src/,,$@); \
175+ fi; \
176
177 src/bin-combined/%.efirom: src/bin-i386-pcbios/%.rom src/bin-x86_64-efi/%.efirom
178 @[ -d $(dir $@) ] || mkdir $(dir $@)
179diff --git a/src/Makefile b/src/Makefile
180index 69139dc..4c4abf1 100644
181--- a/src/Makefile
182+++ b/src/Makefile
183@@ -190,7 +190,7 @@ vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
184 @$(ECHO) ' bin/10222000.rom -- vlance/pcnet32'
185 @$(ECHO) ' bin/15ad07b0.rom -- vmxnet3'
186 @$(ECHO)
187- @$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
188+ @$(ECHO) 'For more information, see https://ipxe.org/howto/vmware'
189 @$(ECHO)
190 @$(ECHO) '==========================================================='
191
192diff --git a/src/Makefile.efi b/src/Makefile.efi
193index 11e29dd..bd479b3 100644
194--- a/src/Makefile.efi
195+++ b/src/Makefile.efi
196@@ -43,7 +43,8 @@ $(BIN)/%.drv.efi : $(BIN)/%.efidrv
197
198 $(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
199 $(QM)$(ECHO) " [FINISH] $@"
200- $(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) -c $< $@
201+ $(Q)$(EFIROM) -v $(firstword $(TGT_PCI_VENDOR) 0) \
202+ -d $(firstword $(TGT_PCI_DEVICE) 0) -c $< $@
203
204 $(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
205 $(QM)$(ECHO) " [CAB] $@"
206diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
207index e017c65..24ed5d1 100644
208--- a/src/Makefile.housekeeping
209+++ b/src/Makefile.housekeeping
210@@ -918,7 +918,7 @@ $(BIN)/deps/%.d : % $(MAKEDEPS)
211
212 # Calculate list of dependency files
213 #
214-AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
215+AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS) core/version.c)
216 autodeps :
217 @$(ECHO) $(AUTO_DEPS)
218 VERYCLEANUP += $(BIN)/deps
219@@ -1167,7 +1167,8 @@ $(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
220 $(Q)$(RM) $(BLIB)
221 $(QM)$(ECHO) " [AR] $@"
222 $(Q)$(AR) rD $@ $(sort $(BLIB_OBJS))
223- $(Q)$(OBJCOPY) --prefix-symbols=$(SYMBOL_PREFIX) $@
224+ $(Q)$(OBJCOPY) --enable-deterministic-archives \
225+ --prefix-symbols=$(SYMBOL_PREFIX) $@
226 $(Q)$(RANLIB) -D $@
227 blib : $(BLIB)
228
229@@ -1201,7 +1202,7 @@ endif
230 # Build version
231 #
232 GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
233-$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
234+$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(version_DEPS) $(GIT_INDEX)
235 $(QM)$(ECHO) " [VERSION] $@"
236 $(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
237 -DVERSION_MAJOR=$(VERSION_MAJOR) \
238diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c
239index 6413b2f..9a25bda 100644
240--- a/src/arch/x86/core/x86_bigint.c
241+++ b/src/arch/x86/core/x86_bigint.c
242@@ -75,17 +75,18 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
243 *
244 * a < 2^{n}, b < 2^{n} => ab < 2^{2n}
245 */
246- __asm__ __volatile__ ( "mull %4\n\t"
247- "addl %%eax, (%5,%2,4)\n\t"
248- "adcl %%edx, 4(%5,%2,4)\n\t"
249+ __asm__ __volatile__ ( "mull %5\n\t"
250+ "addl %%eax, (%6,%2,4)\n\t"
251+ "adcl %%edx, 4(%6,%2,4)\n\t"
252 "\n1:\n\t"
253- "adcl $0, 8(%5,%2,4)\n\t"
254+ "adcl $0, 8(%6,%2,4)\n\t"
255 "inc %2\n\t"
256 /* Does not affect CF */
257 "jc 1b\n\t"
258 : "=&a" ( discard_a ),
259 "=&d" ( discard_d ),
260- "=&r" ( index )
261+ "=&r" ( index ),
262+ "+m" ( *result )
263 : "0" ( multiplicand_element ),
264 "g" ( multiplier_element ),
265 "r" ( result_elements ),
266diff --git a/src/arch/x86/drivers/net/undinet.c b/src/arch/x86/drivers/net/undinet.c
267index 9b7d6d8..43cb18b 100644
268--- a/src/arch/x86/drivers/net/undinet.c
269+++ b/src/arch/x86/drivers/net/undinet.c
270@@ -104,6 +104,13 @@ static union u_PXENV_ANY __bss16 ( undinet_params );
271 SEGOFF16_t __bss16 ( undinet_entry_point );
272 #define undinet_entry_point __use_data16 ( undinet_entry_point )
273
274+/* Read TSC in real mode only when profiling */
275+#if PROFILING
276+#define RDTSC_IF_PROFILING "rdtsc\n\t"
277+#else
278+#define RDTSC_IF_PROFILING ""
279+#endif
280+
281 /** IRQ profiler */
282 static struct profiler undinet_irq_profiler __profiler =
283 { .name = "undinet.irq" };
284@@ -288,14 +295,14 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function,
285 */
286 profile_start ( &profiler->total );
287 __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
288- "rdtsc\n\t"
289+ RDTSC_IF_PROFILING
290 "pushl %%eax\n\t"
291 "pushw %%es\n\t"
292 "pushw %%di\n\t"
293 "pushw %%bx\n\t"
294 "lcall *undinet_entry_point\n\t"
295 "movw %%ax, %%bx\n\t"
296- "rdtsc\n\t"
297+ RDTSC_IF_PROFILING
298 "addw $6, %%sp\n\t"
299 "popl %%edx\n\t"
300 "popl %%ebp\n\t" /* gcc bug */ )
301diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c
302index 51498bf..a782127 100644
303--- a/src/arch/x86/image/bzimage.c
304+++ b/src/arch/x86/image/bzimage.c
305@@ -327,32 +327,6 @@ static void bzimage_set_cmdline ( struct image *image,
306 }
307
308 /**
309- * Parse standalone image command line for cpio parameters
310- *
311- * @v image bzImage file
312- * @v cpio CPIO header
313- * @v cmdline Command line
314- */
315-static void bzimage_parse_cpio_cmdline ( struct image *image,
316- struct cpio_header *cpio,
317- const char *cmdline ) {
318- char *arg;
319- char *end;
320- unsigned int mode;
321-
322- /* Look for "mode=" */
323- if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
324- arg += 5;
325- mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
326- if ( *end && ( *end != ' ' ) ) {
327- DBGC ( image, "bzImage %p strange \"mode=\""
328- "terminator '%c'\n", image, *end );
329- }
330- cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
331- }
332-}
333-
334-/**
335 * Align initrd length
336 *
337 * @v len Length
338@@ -374,11 +348,9 @@ static inline size_t bzimage_align ( size_t len ) {
339 static size_t bzimage_load_initrd ( struct image *image,
340 struct image *initrd,
341 userptr_t address ) {
342- char *filename = initrd->cmdline;
343- char *cmdline;
344+ const char *filename = cpio_name ( initrd );
345 struct cpio_header cpio;
346 size_t offset;
347- size_t name_len;
348 size_t pad_len;
349
350 /* Do not include kernel image itself as an initrd */
351@@ -386,25 +358,7 @@ static size_t bzimage_load_initrd ( struct image *image,
352 return 0;
353
354 /* Create cpio header for non-prebuilt images */
355- if ( filename && filename[0] ) {
356- cmdline = strchr ( filename, ' ' );
357- name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
358- : strlen ( filename ) ) + 1 /* NUL */ );
359- memset ( &cpio, '0', sizeof ( cpio ) );
360- memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
361- cpio_set_field ( cpio.c_mode, 0100644 );
362- cpio_set_field ( cpio.c_nlink, 1 );
363- cpio_set_field ( cpio.c_filesize, initrd->len );
364- cpio_set_field ( cpio.c_namesize, name_len );
365- if ( cmdline ) {
366- bzimage_parse_cpio_cmdline ( image, &cpio,
367- ( cmdline + 1 /* ' ' */ ));
368- }
369- offset = ( ( sizeof ( cpio ) + name_len + 0x03 ) & ~0x03 );
370- } else {
371- offset = 0;
372- name_len = 0;
373- }
374+ offset = cpio_header ( initrd, &cpio );
375
376 /* Copy in initrd image body (and cpio header if applicable) */
377 if ( address ) {
378@@ -413,7 +367,7 @@ static size_t bzimage_load_initrd ( struct image *image,
379 memset_user ( address, 0, 0, offset );
380 copy_to_user ( address, 0, &cpio, sizeof ( cpio ) );
381 copy_to_user ( address, sizeof ( cpio ), filename,
382- ( name_len - 1 /* NUL (or space) */ ) );
383+ cpio_name_len ( initrd ) );
384 }
385 DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
386 "%s%s\n", image, initrd, user_to_phys ( address, 0 ),
387diff --git a/src/arch/x86/image/initrd.c b/src/arch/x86/image/initrd.c
388index 49b959a..d7b1f57 100644
389--- a/src/arch/x86/image/initrd.c
390+++ b/src/arch/x86/image/initrd.c
391@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
392 #include <ipxe/uaccess.h>
393 #include <ipxe/init.h>
394 #include <ipxe/memblock.h>
395+#include <ipxe/cpio.h>
396
397 /** @file
398 *
399diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h
400index 4f1bc87..7443d6f 100644
401--- a/src/arch/x86/include/bits/bigint.h
402+++ b/src/arch/x86/include/bits/bigint.h
403@@ -25,19 +25,22 @@ typedef uint32_t bigint_element_t;
404 static inline __attribute__ (( always_inline )) void
405 bigint_init_raw ( uint32_t *value0, unsigned int size,
406 const void *data, size_t len ) {
407- long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
408+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
409+ ( ( void * ) value0 );
410+ long pad_len = ( sizeof ( *value ) - len );
411 void *discard_D;
412 long discard_c;
413
414 /* Copy raw data in reverse order, padding with zeros */
415 __asm__ __volatile__ ( "\n1:\n\t"
416- "movb -1(%2,%1), %%al\n\t"
417+ "movb -1(%3,%1), %%al\n\t"
418 "stosb\n\t"
419 "loop 1b\n\t"
420 "xorl %%eax, %%eax\n\t"
421- "mov %3, %1\n\t"
422+ "mov %4, %1\n\t"
423 "rep stosb\n\t"
424- : "=&D" ( discard_D ), "=&c" ( discard_c )
425+ : "=&D" ( discard_D ), "=&c" ( discard_c ),
426+ "+m" ( *value )
427 : "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
428 "1" ( len )
429 : "eax" );
430@@ -53,6 +56,8 @@ bigint_init_raw ( uint32_t *value0, unsigned int size,
431 static inline __attribute__ (( always_inline )) void
432 bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
433 unsigned int size ) {
434+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
435+ ( ( void * ) value0 );
436 long index;
437 void *discard_S;
438 long discard_c;
439@@ -60,11 +65,11 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
440 __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
441 "\n1:\n\t"
442 "lodsl\n\t"
443- "adcl %%eax, (%3,%0,4)\n\t"
444+ "adcl %%eax, (%4,%0,4)\n\t"
445 "inc %0\n\t" /* Does not affect CF */
446 "loop 1b\n\t"
447 : "=&r" ( index ), "=&S" ( discard_S ),
448- "=&c" ( discard_c )
449+ "=&c" ( discard_c ), "+m" ( *value )
450 : "r" ( value0 ), "1" ( addend0 ), "2" ( size )
451 : "eax" );
452 }
453@@ -79,6 +84,8 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
454 static inline __attribute__ (( always_inline )) void
455 bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
456 unsigned int size ) {
457+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
458+ ( ( void * ) value0 );
459 long index;
460 void *discard_S;
461 long discard_c;
462@@ -86,11 +93,11 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
463 __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
464 "\n1:\n\t"
465 "lodsl\n\t"
466- "sbbl %%eax, (%3,%0,4)\n\t"
467+ "sbbl %%eax, (%4,%0,4)\n\t"
468 "inc %0\n\t" /* Does not affect CF */
469 "loop 1b\n\t"
470 : "=&r" ( index ), "=&S" ( discard_S ),
471- "=&c" ( discard_c )
472+ "=&c" ( discard_c ), "+m" ( *value )
473 : "r" ( value0 ), "1" ( subtrahend0 ),
474 "2" ( size )
475 : "eax" );
476@@ -104,15 +111,18 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
477 */
478 static inline __attribute__ (( always_inline )) void
479 bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
480+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
481+ ( ( void * ) value0 );
482 long index;
483 long discard_c;
484
485 __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
486 "\n1:\n\t"
487- "rcll $1, (%2,%0,4)\n\t"
488+ "rcll $1, (%3,%0,4)\n\t"
489 "inc %0\n\t" /* Does not affect CF */
490 "loop 1b\n\t"
491- : "=&r" ( index ), "=&c" ( discard_c )
492+ : "=&r" ( index ), "=&c" ( discard_c ),
493+ "+m" ( *value )
494 : "r" ( value0 ), "1" ( size ) );
495 }
496
497@@ -124,13 +134,15 @@ bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
498 */
499 static inline __attribute__ (( always_inline )) void
500 bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
501+ bigint_t ( size ) __attribute__ (( may_alias )) *value =
502+ ( ( void * ) value0 );
503 long discard_c;
504
505 __asm__ __volatile__ ( "clc\n\t"
506 "\n1:\n\t"
507- "rcrl $1, -4(%1,%0,4)\n\t"
508+ "rcrl $1, -4(%2,%0,4)\n\t"
509 "loop 1b\n\t"
510- : "=&c" ( discard_c )
511+ : "=&c" ( discard_c ), "+m" ( *value )
512 : "r" ( value0 ), "0" ( size ) );
513 }
514
515@@ -239,6 +251,8 @@ bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
516 static inline __attribute__ (( always_inline )) void
517 bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
518 uint32_t *dest0, unsigned int dest_size ) {
519+ bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
520+ ( ( void * ) dest0 );
521 long pad_size = ( dest_size - source_size );
522 void *discard_D;
523 void *discard_S;
524@@ -246,10 +260,10 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
525
526 __asm__ __volatile__ ( "rep movsl\n\t"
527 "xorl %%eax, %%eax\n\t"
528- "mov %3, %2\n\t"
529+ "mov %4, %2\n\t"
530 "rep stosl\n\t"
531 : "=&D" ( discard_D ), "=&S" ( discard_S ),
532- "=&c" ( discard_c )
533+ "=&c" ( discard_c ), "+m" ( *dest )
534 : "g" ( pad_size ), "0" ( dest0 ),
535 "1" ( source0 ), "2" ( source_size )
536 : "eax" );
537@@ -266,13 +280,15 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
538 static inline __attribute__ (( always_inline )) void
539 bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
540 uint32_t *dest0, unsigned int dest_size ) {
541+ bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
542+ ( ( void * ) dest0 );
543 void *discard_D;
544 void *discard_S;
545 long discard_c;
546
547 __asm__ __volatile__ ( "rep movsl\n\t"
548 : "=&D" ( discard_D ), "=&S" ( discard_S ),
549- "=&c" ( discard_c )
550+ "=&c" ( discard_c ), "+m" ( *dest )
551 : "0" ( dest0 ), "1" ( source0 ),
552 "2" ( dest_size )
553 : "eax" );
554@@ -289,15 +305,19 @@ bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
555 static inline __attribute__ (( always_inline )) void
556 bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
557 void *out, size_t len ) {
558+ struct {
559+ uint8_t bytes[len];
560+ } __attribute__ (( may_alias )) *out_bytes = out;
561 void *discard_D;
562 long discard_c;
563
564 /* Copy raw data in reverse order */
565 __asm__ __volatile__ ( "\n1:\n\t"
566- "movb -1(%2,%1), %%al\n\t"
567+ "movb -1(%3,%1), %%al\n\t"
568 "stosb\n\t"
569 "loop 1b\n\t"
570- : "=&D" ( discard_D ), "=&c" ( discard_c )
571+ : "=&D" ( discard_D ), "=&c" ( discard_c ),
572+ "+m" ( *out_bytes )
573 : "r" ( value0 ), "0" ( out ), "1" ( len )
574 : "eax" );
575 }
576diff --git a/src/arch/x86/include/initrd.h b/src/arch/x86/include/initrd.h
577index ddb3e5a..2fb9d3d 100644
578--- a/src/arch/x86/include/initrd.h
579+++ b/src/arch/x86/include/initrd.h
580@@ -11,13 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
581
582 #include <ipxe/uaccess.h>
583
584-/** Minimum alignment for initrds
585- *
586- * Some versions of Linux complain about initrds that are not
587- * page-aligned.
588- */
589-#define INITRD_ALIGN 4096
590-
591 /** Minimum free space required to reshuffle initrds
592 *
593 * Chosen to avoid absurdly long reshuffling times
594diff --git a/src/arch/x86/include/ipxe/cpuid.h b/src/arch/x86/include/ipxe/cpuid.h
595index b5403bd..3983dfb 100644
596--- a/src/arch/x86/include/ipxe/cpuid.h
597+++ b/src/arch/x86/include/ipxe/cpuid.h
598@@ -42,6 +42,9 @@ struct x86_features {
599 /** Hypervisor is present */
600 #define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL
601
602+/** TSC is present */
603+#define CPUID_FEATURES_INTEL_EDX_TSC 0x00000010UL
604+
605 /** FXSAVE and FXRSTOR are supported */
606 #define CPUID_FEATURES_INTEL_EDX_FXSR 0x01000000UL
607
608diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c
609index dc164c7..3dac6b6 100644
610--- a/src/arch/x86/interface/pcbios/acpipwr.c
611+++ b/src/arch/x86/interface/pcbios/acpipwr.c
612@@ -43,6 +43,69 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
613 #define S5_SIGNATURE ACPI_SIGNATURE ( '_', 'S', '5', '_' )
614
615 /**
616+ * Extract \_Sx value from DSDT/SSDT
617+ *
618+ * @v zsdt DSDT or SSDT
619+ * @v len Length of DSDT/SSDT
620+ * @v offset Offset of signature within DSDT/SSDT
621+ * @v data Data buffer
622+ * @ret rc Return status code
623+ *
624+ * In theory, extracting the \_Sx value from the DSDT/SSDT requires a
625+ * full ACPI parser plus some heuristics to work around the various
626+ * broken encodings encountered in real ACPI implementations.
627+ *
628+ * In practice, we can get the same result by scanning through the
629+ * DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
630+ * four bytes, removing any bytes with bit 3 set, and treating
631+ * whatever is left as a little-endian value. This is one of the
632+ * uglier hacks I have ever implemented, but it's still prettier than
633+ * the ACPI specification itself.
634+ */
635+static int acpi_extract_sx ( userptr_t zsdt, size_t len, size_t offset,
636+ void *data ) {
637+ unsigned int *sx = data;
638+ uint8_t bytes[4];
639+ uint8_t *byte;
640+
641+ /* Skip signature and package header */
642+ offset += ( 4 /* signature */ + 3 /* package header */ );
643+
644+ /* Sanity check */
645+ if ( ( offset + sizeof ( bytes ) /* value */ ) > len ) {
646+ return -EINVAL;
647+ }
648+
649+ /* Read first four bytes of value */
650+ copy_from_user ( bytes, zsdt, offset, sizeof ( bytes ) );
651+ DBGC ( colour, "ACPI found \\_Sx containing %02x:%02x:%02x:%02x\n",
652+ bytes[0], bytes[1], bytes[2], bytes[3] );
653+
654+ /* Extract \Sx value. There are three potential encodings
655+ * that we might encounter:
656+ *
657+ * - SLP_TYPa, SLP_TYPb, rsvd, rsvd
658+ *
659+ * - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
660+ *
661+ * - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
662+ *
663+ * Since <byteprefix> and <dwordprefix> both have bit 3 set,
664+ * and valid SLP_TYPx must have bit 3 clear (since SLP_TYPx is
665+ * a 3-bit field), we can just skip any bytes with bit 3 set.
666+ */
667+ byte = bytes;
668+ if ( *byte & 0x08 )
669+ byte++;
670+ *sx = *(byte++);
671+ if ( *byte & 0x08 )
672+ byte++;
673+ *sx |= ( *byte << 8 );
674+
675+ return 0;
676+}
677+
678+/**
679 * Power off the computer using ACPI
680 *
681 * @ret rc Return status code
682@@ -56,7 +119,7 @@ int acpi_poweroff ( void ) {
683 unsigned int pm1b_cnt;
684 unsigned int slp_typa;
685 unsigned int slp_typb;
686- int s5;
687+ unsigned int s5;
688 int rc;
689
690 /* Locate FADT */
691@@ -74,9 +137,8 @@ int acpi_poweroff ( void ) {
692 pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT );
693
694 /* Extract \_S5 from DSDT or any SSDT */
695- s5 = acpi_sx ( S5_SIGNATURE );
696- if ( s5 < 0 ) {
697- rc = s5;
698+ if ( ( rc = acpi_extract ( S5_SIGNATURE, &s5,
699+ acpi_extract_sx ) ) != 0 ) {
700 DBGC ( colour, "ACPI could not extract \\_S5: %s\n",
701 strerror ( rc ) );
702 return rc;
703diff --git a/src/arch/x86/interface/pcbios/bios_cachedhcp.c b/src/arch/x86/interface/pcbios/bios_cachedhcp.c
704index 3d38699..277c40d 100644
705--- a/src/arch/x86/interface/pcbios/bios_cachedhcp.c
706+++ b/src/arch/x86/interface/pcbios/bios_cachedhcp.c
707@@ -59,7 +59,8 @@ static void cachedhcp_init ( void ) {
708 }
709
710 /* Record cached DHCPACK */
711- if ( ( rc = cachedhcp_record ( phys_to_user ( cached_dhcpack_phys ),
712+ if ( ( rc = cachedhcp_record ( &cached_dhcpack,
713+ phys_to_user ( cached_dhcpack_phys ),
714 sizeof ( BOOTPLAYER_t ) ) ) != 0 ) {
715 DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n",
716 strerror ( rc ) );
717diff --git a/src/arch/x86/interface/pcbios/rtc_entropy.c b/src/arch/x86/interface/pcbios/rtc_entropy.c
718index e9e6baa..e0c1756 100644
719--- a/src/arch/x86/interface/pcbios/rtc_entropy.c
720+++ b/src/arch/x86/interface/pcbios/rtc_entropy.c
721@@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
722 #include <biosint.h>
723 #include <pic8259.h>
724 #include <rtc.h>
725+#include <ipxe/cpuid.h>
726 #include <ipxe/entropy.h>
727
728 /** Maximum time to wait for an RTC interrupt, in milliseconds */
729@@ -174,8 +175,17 @@ static int rtc_entropy_check ( void ) {
730 * @ret rc Return status code
731 */
732 static int rtc_entropy_enable ( void ) {
733+ struct x86_features features;
734 int rc;
735
736+ /* Check that TSC is supported */
737+ x86_features ( &features );
738+ if ( ! ( features.intel.edx & CPUID_FEATURES_INTEL_EDX_TSC ) ) {
739+ DBGC ( &rtc_flag, "RTC has no TSC\n" );
740+ rc = -ENOTSUP;
741+ goto err_no_tsc;
742+ }
743+
744 /* Hook ISR and enable RTC interrupts */
745 rtc_hook_isr();
746 enable_irq ( RTC_IRQ );
747@@ -191,6 +201,7 @@ static int rtc_entropy_enable ( void ) {
748 rtc_disable_int();
749 disable_irq ( RTC_IRQ );
750 rtc_unhook_isr();
751+ err_no_tsc:
752 return rc;
753 }
754
755diff --git a/src/arch/x86/interface/syslinux/comboot_call.c b/src/arch/x86/interface/syslinux/comboot_call.c
756index dc308da..b75e8ef 100644
757--- a/src/arch/x86/interface/syslinux/comboot_call.c
758+++ b/src/arch/x86/interface/syslinux/comboot_call.c
759@@ -47,7 +47,7 @@ static char __bss16_array ( syslinux_version, [32] );
760 #define syslinux_version __use_data16 ( syslinux_version )
761
762 /** The "SYSLINUX" copyright string */
763-static char __data16_array ( syslinux_copyright, [] ) = " http://ipxe.org";
764+static char __data16_array ( syslinux_copyright, [] ) = " https://ipxe.org";
765 #define syslinux_copyright __use_data16 ( syslinux_copyright )
766
767 static char __data16_array ( syslinux_configuration_file, [] ) = "";
768diff --git a/src/arch/x86/prefix/romprefix.S b/src/arch/x86/prefix/romprefix.S
769index a9934a7..4e8793c 100644
770--- a/src/arch/x86/prefix/romprefix.S
771+++ b/src/arch/x86/prefix/romprefix.S
772@@ -161,7 +161,7 @@ pnpheader:
773
774 /* Manufacturer string */
775 mfgstr:
776- .asciz "http://ipxe.org"
777+ .asciz "https://ipxe.org"
778 .size mfgstr, . - mfgstr
779
780 /* Product string
781@@ -607,7 +607,7 @@ get_pmm_decompress_to:
782 * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/branding.h.
783 *
784 * While nothing in the GPL prevents you from removing all references
785- * to iPXE or http://ipxe.org, we prefer you not to do so.
786+ * to iPXE or https://ipxe.org, we prefer you not to do so.
787 *
788 * If you have an OEM-mandated branding requirement that cannot be
789 * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
790diff --git a/src/arch/x86/prefix/unlzma.S b/src/arch/x86/prefix/unlzma.S
791index 956eeb2..979f699 100644
792--- a/src/arch/x86/prefix/unlzma.S
793+++ b/src/arch/x86/prefix/unlzma.S
794@@ -44,7 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
795 */
796
797 .text
798- .arch i586
799+ .arch i486
800 .section ".prefix.lib", "ax", @progbits
801
802 #ifdef CODE16
803diff --git a/src/config/branding.h b/src/config/branding.h
804index 73f00af..e503dff 100644
805--- a/src/config/branding.h
806+++ b/src/config/branding.h
807@@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
808 */
809 #define PRODUCT_NAME ""
810 #define PRODUCT_SHORT_NAME "iPXE"
811-#define PRODUCT_URI "http://ipxe.org"
812+#define PRODUCT_URI "https://ipxe.org"
813
814 /*
815 * Tag line
816@@ -44,15 +44,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
817 * (e.g. "Permission denied") and a 32-bit error number. This number
818 * is incorporated into an error URI such as
819 *
820- * "No such file or directory (http://ipxe.org/2d0c613b)"
821+ * "No such file or directory (https://ipxe.org/2d0c613b)"
822 *
823 * or
824 *
825- * "Operation not supported (http://ipxe.org/3c092003)"
826+ * "Operation not supported (https://ipxe.org/3c092003)"
827 *
828 * Users may browse to the URI within the error message, which is
829 * provided by a database running on the iPXE web site
830- * (http://ipxe.org). This database provides details for all possible
831+ * (https://ipxe.org). This database provides details for all possible
832 * errors generated by iPXE, including:
833 *
834 * - the detailed error message (e.g. "Not an OCSP signing
835@@ -74,13 +74,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
836 *
837 * If you have a customer support team and would like your customers
838 * to contact your support team for all problems, instead of using the
839- * existing support infrastructure provided by http://ipxe.org, then
840+ * existing support infrastructure provided by https://ipxe.org, then
841 * you may define a custom URI to be included within error messages.
842 *
843 * Note that the custom URI is a printf() format string which must
844 * include a format specifier for the 32-bit error number.
845 */
846-#define PRODUCT_ERROR_URI "http://ipxe.org/%08x"
847+#define PRODUCT_ERROR_URI "https://ipxe.org/%08x"
848
849 /*
850 * Command help messages
851@@ -88,7 +88,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
852 * iPXE command help messages include a URI constructed from the
853 * command name, such as
854 *
855- * "See http://ipxe.org/cmd/vcreate for further information"
856+ * "See https://ipxe.org/cmd/vcreate for further information"
857 *
858 * The iPXE web site includes documentation for the commands provided
859 * by the iPXE shell, including:
860@@ -113,7 +113,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
861 *
862 * If you want to provide your own documentation for all of the
863 * commands provided by the iPXE shell, rather than using the existing
864- * support infrastructure provided by http://ipxe.org, then you may
865+ * support infrastructure provided by https://ipxe.org, then you may
866 * define a custom URI to be included within command help messages.
867 *
868 * Note that the custom URI is a printf() format string which must
869@@ -124,7 +124,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
870 * iPXE project and prohibit the alteration or removal of any
871 * references to "iPXE". ]
872 */
873-#define PRODUCT_COMMAND_URI "http://ipxe.org/cmd/%s"
874+#define PRODUCT_COMMAND_URI "https://ipxe.org/cmd/%s"
875
876 /*
877 * Setting help messages
878@@ -132,7 +132,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
879 * iPXE setting help messages include a URI constructed from the
880 * setting name, such as
881 *
882- * "http://ipxe.org/cfg/initiator-iqn"
883+ * "https://ipxe.org/cfg/initiator-iqn"
884 *
885 * The iPXE web site includes documentation for the settings used by
886 * iPXE, including:
887@@ -156,7 +156,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
888 *
889 * If you want to provide your own documentation for all of the
890 * settings used by iPXE, rather than using the existing support
891- * infrastructure provided by http://ipxe.org, then you may define a
892+ * infrastructure provided by https://ipxe.org, then you may define a
893 * custom URI to be included within setting help messages.
894 *
895 * Note that the custom URI is a printf() format string which must
896@@ -167,7 +167,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
897 * iPXE project and prohibit the alteration or removal of any
898 * references to "iPXE". ]
899 */
900-#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s"
901+#define PRODUCT_SETTING_URI "https://ipxe.org/cfg/%s"
902
903 #include <config/local/branding.h>
904
905diff --git a/src/config/cloud/aws.ipxe b/src/config/cloud/aws.ipxe
906index 2c96e38..6c00739 100644
907--- a/src/config/cloud/aws.ipxe
908+++ b/src/config/cloud/aws.ipxe
909@@ -3,6 +3,22 @@
910 echo Amazon EC2 - iPXE boot via user-data
911 echo CPU: ${cpuvendor} ${cpumodel}
912 ifstat ||
913-dhcp ||
914+
915+set attempt:int8 1
916+:dhcp_retry
917+echo DHCP attempt ${attempt}
918+dhcp --timeout 5000 && goto dhcp_ok ||
919+ifstat ||
920+inc attempt
921+iseq ${attempt} 10 || goto dhcp_retry
922+
923+:dhcp_fail
924+echo DHCP failed - rebooting
925+reboot ||
926+exit
927+
928+:dhcp_ok
929 route ||
930-chain -ar http://169.254.169.254/latest/user-data
931+chain -ar http://169.254.169.254/latest/user-data ||
932+ifstat ||
933+exit
934diff --git a/src/config/cloud/gce.ipxe b/src/config/cloud/gce.ipxe
935index 88e12b5..65e2e57 100644
936--- a/src/config/cloud/gce.ipxe
937+++ b/src/config/cloud/gce.ipxe
938@@ -5,4 +5,5 @@ echo CPU: ${cpuvendor} ${cpumodel}
939 ifstat ||
940 dhcp ||
941 route ||
942-chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot
943+chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot ||
944+ifstat ||
945diff --git a/src/config/cloud/settings.h b/src/config/cloud/settings.h
946index 34deeb0..c9d6bdc 100644
947--- a/src/config/cloud/settings.h
948+++ b/src/config/cloud/settings.h
949@@ -1,4 +1,6 @@
950 /* It can often be useful to know the CPU on which a cloud instance is
951 * running (e.g. to isolate problems with Azure AMD instances).
952 */
953+#if defined ( __i386__ ) || defined ( __x86_64__ )
954 #define CPUID_SETTINGS
955+#endif
956diff --git a/src/config/config.c b/src/config/config.c
957index 5e7a3ec..a818661 100644
958--- a/src/config/config.c
959+++ b/src/config/config.c
960@@ -182,6 +182,12 @@ REQUIRE_OBJECT ( efi_image );
961 #ifdef IMAGE_SDI
962 REQUIRE_OBJECT ( sdi );
963 #endif
964+#ifdef IMAGE_ZLIB
965+REQUIRE_OBJECT ( zlib );
966+#endif
967+#ifdef IMAGE_GZIP
968+REQUIRE_OBJECT ( gzip );
969+#endif
970
971 /*
972 * Drag in all requested commands
973diff --git a/src/config/config_archive.c b/src/config/config_archive.c
974new file mode 100644
975index 0000000..746fc7e
976--- /dev/null
977+++ b/src/config/config_archive.c
978@@ -0,0 +1,36 @@
979+/*
980+ * This program is free software; you can redistribute it and/or
981+ * modify it under the terms of the GNU General Public License as
982+ * published by the Free Software Foundation; either version 2 of the
983+ * License, or (at your option) any later version.
984+ *
985+ * This program is distributed in the hope that it will be useful, but
986+ * WITHOUT ANY WARRANTY; without even the implied warranty of
987+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
988+ * General Public License for more details.
989+ *
990+ * You should have received a copy of the GNU General Public License
991+ * along with this program; if not, write to the Free Software
992+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
993+ * 02110-1301, USA.
994+ *
995+ * You can also choose to distribute this program under the terms of
996+ * the Unmodified Binary Distribution Licence (as given in the file
997+ * COPYING.UBDL), provided that you have satisfied its requirements.
998+ */
999+
1000+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1001+
1002+#include <config/general.h>
1003+
1004+/** @file
1005+ *
1006+ * Archive image configuration
1007+ *
1008+ */
1009+
1010+PROVIDE_REQUIRING_SYMBOL();
1011+
1012+#ifdef IMAGE_ARCHIVE_CMD
1013+REQUIRE_OBJECT ( image_archive_cmd );
1014+#endif
1015diff --git a/src/config/general.h b/src/config/general.h
1016index 9b21f12..2d15f50 100644
1017--- a/src/config/general.h
1018+++ b/src/config/general.h
1019@@ -117,6 +117,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1020 #define IMAGE_PNG /* PNG image support */
1021 #define IMAGE_DER /* DER image support */
1022 #define IMAGE_PEM /* PEM image support */
1023+//#define IMAGE_ZLIB /* ZLIB image support */
1024+//#define IMAGE_GZIP /* GZIP image support */
1025
1026 /*
1027 * Command-line commands to include
1028@@ -156,6 +158,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1029 //#define NTP_CMD /* NTP commands */
1030 //#define CERT_CMD /* Certificate management commands */
1031 //#define IMAGE_MEM_CMD /* Read memory command */
1032+#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
1033
1034 /*
1035 * ROM-specific options
1036diff --git a/src/core/acpi.c b/src/core/acpi.c
1037index 52eb63a..aa486da 100644
1038--- a/src/core/acpi.c
1039+++ b/src/core/acpi.c
1040@@ -169,33 +169,22 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) {
1041 }
1042
1043 /**
1044- * Extract \_Sx value from DSDT/SSDT
1045+ * Extract value from DSDT/SSDT
1046 *
1047 * @v zsdt DSDT or SSDT
1048 * @v signature Signature (e.g. "_S5_")
1049- * @ret sx \_Sx value, or negative error
1050- *
1051- * In theory, extracting the \_Sx value from the DSDT/SSDT requires a
1052- * full ACPI parser plus some heuristics to work around the various
1053- * broken encodings encountered in real ACPI implementations.
1054- *
1055- * In practice, we can get the same result by scanning through the
1056- * DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
1057- * four bytes, removing any bytes with bit 3 set, and treating
1058- * whatever is left as a little-endian value. This is one of the
1059- * uglier hacks I have ever implemented, but it's still prettier than
1060- * the ACPI specification itself.
1061+ * @v data Data buffer
1062+ * @v extract Extraction method
1063+ * @ret rc Return status code
1064 */
1065-static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
1066+static int acpi_zsdt ( userptr_t zsdt, uint32_t signature, void *data,
1067+ int ( * extract ) ( userptr_t zsdt, size_t len,
1068+ size_t offset, void *data ) ) {
1069 struct acpi_header acpi;
1070- union {
1071- uint32_t dword;
1072- uint8_t byte[4];
1073- } buf;
1074+ uint32_t buf;
1075 size_t offset;
1076 size_t len;
1077- unsigned int sx;
1078- uint8_t *byte;
1079+ int rc;
1080
1081 /* Read table header */
1082 copy_from_user ( &acpi, zsdt, 0, sizeof ( acpi ) );
1083@@ -203,75 +192,51 @@ static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
1084
1085 /* Locate signature */
1086 for ( offset = sizeof ( acpi ) ;
1087- ( ( offset + sizeof ( buf ) /* signature */ + 3 /* pkg header */
1088- + sizeof ( buf ) /* value */ ) < len ) ;
1089+ ( ( offset + sizeof ( buf ) /* signature */ ) < len ) ;
1090 offset++ ) {
1091
1092 /* Check signature */
1093 copy_from_user ( &buf, zsdt, offset, sizeof ( buf ) );
1094- if ( buf.dword != cpu_to_le32 ( signature ) )
1095+ if ( buf != cpu_to_le32 ( signature ) )
1096 continue;
1097 DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n",
1098 user_to_phys ( zsdt, 0 ), acpi_name ( signature ),
1099 offset );
1100- offset += sizeof ( buf );
1101-
1102- /* Read first four bytes of value */
1103- copy_from_user ( &buf, zsdt, ( offset + 3 /* pkg header */ ),
1104- sizeof ( buf ) );
1105- DBGC ( zsdt, "DSDT/SSDT %#08lx found %s containing "
1106- "%02x:%02x:%02x:%02x\n", user_to_phys ( zsdt, 0 ),
1107- acpi_name ( signature ), buf.byte[0], buf.byte[1],
1108- buf.byte[2], buf.byte[3] );
1109-
1110- /* Extract \Sx value. There are three potential
1111- * encodings that we might encounter:
1112- *
1113- * - SLP_TYPa, SLP_TYPb, rsvd, rsvd
1114- *
1115- * - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
1116- *
1117- * - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
1118- *
1119- * Since <byteprefix> and <dwordprefix> both have bit
1120- * 3 set, and valid SLP_TYPx must have bit 3 clear
1121- * (since SLP_TYPx is a 3-bit field), we can just skip
1122- * any bytes with bit 3 set.
1123- */
1124- byte = &buf.byte[0];
1125- if ( *byte & 0x08 )
1126- byte++;
1127- sx = *(byte++);
1128- if ( *byte & 0x08 )
1129- byte++;
1130- sx |= ( *byte << 8 );
1131- return sx;
1132+
1133+ /* Attempt to extract data */
1134+ if ( ( rc = extract ( zsdt, len, offset, data ) ) == 0 )
1135+ return 0;
1136 }
1137
1138 return -ENOENT;
1139 }
1140
1141 /**
1142- * Extract \_Sx value from DSDT/SSDT
1143+ * Extract value from DSDT/SSDT
1144 *
1145 * @v signature Signature (e.g. "_S5_")
1146- * @ret sx \_Sx value, or negative error
1147+ * @v data Data buffer
1148+ * @v extract Extraction method
1149+ * @ret rc Return status code
1150 */
1151-int acpi_sx ( uint32_t signature ) {
1152+int acpi_extract ( uint32_t signature, void *data,
1153+ int ( * extract ) ( userptr_t zsdt, size_t len,
1154+ size_t offset, void *data ) ) {
1155 struct acpi_fadt fadtab;
1156 userptr_t fadt;
1157 userptr_t dsdt;
1158 userptr_t ssdt;
1159 unsigned int i;
1160- int sx;
1161+ int rc;
1162
1163 /* Try DSDT first */
1164 fadt = acpi_find ( FADT_SIGNATURE, 0 );
1165 if ( fadt ) {
1166 copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
1167 dsdt = phys_to_user ( fadtab.dsdt );
1168- if ( ( sx = acpi_sx_zsdt ( dsdt, signature ) ) >= 0 )
1169- return sx;
1170+ if ( ( rc = acpi_zsdt ( dsdt, signature, data,
1171+ extract ) ) == 0 )
1172+ return 0;
1173 }
1174
1175 /* Try all SSDTs */
1176@@ -279,11 +244,12 @@ int acpi_sx ( uint32_t signature ) {
1177 ssdt = acpi_find ( SSDT_SIGNATURE, i );
1178 if ( ! ssdt )
1179 break;
1180- if ( ( sx = acpi_sx_zsdt ( ssdt, signature ) ) >= 0 )
1181- return sx;
1182+ if ( ( rc = acpi_zsdt ( ssdt, signature, data,
1183+ extract ) ) == 0 )
1184+ return 0;
1185 }
1186
1187- DBGC ( colour, "ACPI could not find \\_Sx \"%s\"\n",
1188+ DBGC ( colour, "ACPI could not find \"%s\"\n",
1189 acpi_name ( signature ) );
1190 return -ENOENT;
1191 }
1192diff --git a/src/core/acpimac.c b/src/core/acpimac.c
1193new file mode 100644
1194index 0000000..1cc8220
1195--- /dev/null
1196+++ b/src/core/acpimac.c
1197@@ -0,0 +1,154 @@
1198+/*
1199+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
1200+ *
1201+ * This program is free software; you can redistribute it and/or
1202+ * modify it under the terms of the GNU General Public License as
1203+ * published by the Free Software Foundation; either version 2 of the
1204+ * License, or any later version.
1205+ *
1206+ * This program is distributed in the hope that it will be useful, but
1207+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1208+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1209+ * General Public License for more details.
1210+ *
1211+ * You should have received a copy of the GNU General Public License
1212+ * along with this program; if not, write to the Free Software
1213+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1214+ * 02110-1301, USA.
1215+ *
1216+ * You can also choose to distribute this program under the terms of
1217+ * the Unmodified Binary Distribution Licence (as given in the file
1218+ * COPYING.UBDL), provided that you have satisfied its requirements.
1219+ */
1220+
1221+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1222+
1223+#include <string.h>
1224+#include <errno.h>
1225+#include <ipxe/acpi.h>
1226+#include <ipxe/base16.h>
1227+#include <ipxe/ethernet.h>
1228+#include <ipxe/if_ether.h>
1229+#include <ipxe/acpimac.h>
1230+
1231+/** @file
1232+ *
1233+ * ACPI MAC address
1234+ *
1235+ */
1236+
1237+/** Colour for debug messages */
1238+#define colour FADT_SIGNATURE
1239+
1240+/** AMAC signature */
1241+#define AMAC_SIGNATURE ACPI_SIGNATURE ( 'A', 'M', 'A', 'C' )
1242+
1243+/** MACA signature */
1244+#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' )
1245+
1246+/** Maximum number of bytes to skip after AMAC/MACA signature
1247+ *
1248+ * This is entirely empirical.
1249+ */
1250+#define AUXMAC_MAX_SKIP 8
1251+
1252+/**
1253+ * Extract MAC address from DSDT/SSDT
1254+ *
1255+ * @v zsdt DSDT or SSDT
1256+ * @v len Length of DSDT/SSDT
1257+ * @v offset Offset of signature within DSDT/SSDT
1258+ * @v data Data buffer
1259+ * @ret rc Return status code
1260+ *
1261+ * Some vendors provide a "system MAC address" within the DSDT/SSDT,
1262+ * to be used to override the MAC address for a USB docking station.
1263+ *
1264+ * A full implementation would require an ACPI bytecode interpreter,
1265+ * since at least one OEM allows the MAC address to be constructed by
1266+ * executable ACPI bytecode (rather than a fixed data structure).
1267+ *
1268+ * We instead attempt to extract a plausible-looking "_AUXMAC_#.....#"
1269+ * string that appears shortly after an "AMAC" or "MACA" signature.
1270+ * This should work for most implementations encountered in practice.
1271+ */
1272+static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
1273+ void *data ) {
1274+ static const char prefix[9] = "_AUXMAC_#";
1275+ uint8_t *hw_addr = data;
1276+ size_t skip = 0;
1277+ char auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ +
1278+ ( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ];
1279+ char *mac = &auxmac[ sizeof ( prefix ) ];
1280+ int decoded_len;
1281+ int rc;
1282+
1283+ /* Skip signature and at least one tag byte */
1284+ offset += ( 4 /* signature */ + 1 /* tag byte */ );
1285+
1286+ /* Scan for "_AUXMAC_#.....#" close to signature */
1287+ for ( skip = 0 ;
1288+ ( ( skip < AUXMAC_MAX_SKIP ) &&
1289+ ( offset + skip + sizeof ( auxmac ) ) < len ) ;
1290+ skip++ ) {
1291+
1292+ /* Read value */
1293+ copy_from_user ( auxmac, zsdt, ( offset + skip ),
1294+ sizeof ( auxmac ) );
1295+
1296+ /* Check for expected format */
1297+ if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 )
1298+ continue;
1299+ if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' )
1300+ continue;
1301+ if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' )
1302+ continue;
1303+ DBGC ( colour, "ACPI found MAC string \"%s\"\n", auxmac );
1304+
1305+ /* Terminate MAC address string */
1306+ mac = &auxmac[ sizeof ( prefix ) ];
1307+ mac[ ETH_ALEN * 2 ] = '\0';
1308+
1309+ /* Decode MAC address */
1310+ decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN );
1311+ if ( decoded_len < 0 ) {
1312+ rc = decoded_len;
1313+ DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n",
1314+ mac, strerror ( rc ) );
1315+ return rc;
1316+ }
1317+
1318+ /* Check MAC address validity */
1319+ if ( ! is_valid_ether_addr ( hw_addr ) ) {
1320+ DBGC ( colour, "ACPI has invalid MAC %s\n",
1321+ eth_ntoa ( hw_addr ) );
1322+ return -EINVAL;
1323+ }
1324+
1325+ return 0;
1326+ }
1327+
1328+ return -ENOENT;
1329+}
1330+
1331+/**
1332+ * Extract MAC address from DSDT/SSDT
1333+ *
1334+ * @v hw_addr MAC address to fill in
1335+ * @ret rc Return status code
1336+ */
1337+int acpi_mac ( uint8_t *hw_addr ) {
1338+ int rc;
1339+
1340+ /* Look for an "AMAC" address */
1341+ if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
1342+ acpi_extract_mac ) ) == 0 )
1343+ return 0;
1344+
1345+ /* Look for a "MACA" address */
1346+ if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr,
1347+ acpi_extract_mac ) ) == 0 )
1348+ return 0;
1349+
1350+ return -ENOENT;
1351+}
1352diff --git a/src/core/archive.c b/src/core/archive.c
1353new file mode 100644
1354index 0000000..bb62c7e
1355--- /dev/null
1356+++ b/src/core/archive.c
1357@@ -0,0 +1,138 @@
1358+/*
1359+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
1360+ *
1361+ * This program is free software; you can redistribute it and/or
1362+ * modify it under the terms of the GNU General Public License as
1363+ * published by the Free Software Foundation; either version 2 of the
1364+ * License, or any later version.
1365+ *
1366+ * This program is distributed in the hope that it will be useful, but
1367+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1368+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1369+ * General Public License for more details.
1370+ *
1371+ * You should have received a copy of the GNU General Public License
1372+ * along with this program; if not, write to the Free Software
1373+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1374+ * 02110-1301, USA.
1375+ *
1376+ * You can also choose to distribute this program under the terms of
1377+ * the Unmodified Binary Distribution Licence (as given in the file
1378+ * COPYING.UBDL), provided that you have satisfied its requirements.
1379+ */
1380+
1381+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1382+
1383+#include <string.h>
1384+#include <errno.h>
1385+#include <ipxe/image.h>
1386+
1387+/** @file
1388+ *
1389+ * Archive images
1390+ *
1391+ */
1392+
1393+/**
1394+ * Extract archive image
1395+ *
1396+ * @v image Image
1397+ * @v name Extracted image name
1398+ * @v extracted Extracted image to fill in
1399+ * @ret rc Return status code
1400+ */
1401+int image_extract ( struct image *image, const char *name,
1402+ struct image **extracted ) {
1403+ char *dot;
1404+ int rc;
1405+
1406+ /* Check that this image can be used to extract an archive image */
1407+ if ( ! ( image->type && image->type->extract ) ) {
1408+ rc = -ENOTSUP;
1409+ goto err_unsupported;
1410+ }
1411+
1412+ /* Allocate new image */
1413+ *extracted = alloc_image ( image->uri );
1414+ if ( ! *extracted ) {
1415+ rc = -ENOMEM;
1416+ goto err_alloc;
1417+ }
1418+
1419+ /* Set image name */
1420+ if ( ( rc = image_set_name ( *extracted,
1421+ ( name ? name : image->name ) ) ) != 0 ) {
1422+ goto err_set_name;
1423+ }
1424+
1425+ /* Strip any archive or compression suffix from implicit name */
1426+ if ( ( ! name ) && ( (*extracted)->name ) &&
1427+ ( ( dot = strrchr ( (*extracted)->name, '.' ) ) != NULL ) ) {
1428+ *dot = '\0';
1429+ }
1430+
1431+ /* Try extracting archive image */
1432+ if ( ( rc = image->type->extract ( image, *extracted ) ) != 0 ) {
1433+ DBGC ( image, "IMAGE %s could not extract image: %s\n",
1434+ image->name, strerror ( rc ) );
1435+ goto err_extract;
1436+ }
1437+
1438+ /* Register image */
1439+ if ( ( rc = register_image ( *extracted ) ) != 0 )
1440+ goto err_register;
1441+
1442+ /* Propagate trust flag */
1443+ if ( image->flags & IMAGE_TRUSTED )
1444+ image_trust ( *extracted );
1445+
1446+ /* Drop local reference to image */
1447+ image_put ( *extracted );
1448+
1449+ return 0;
1450+
1451+ unregister_image ( *extracted );
1452+ err_register:
1453+ err_extract:
1454+ err_set_name:
1455+ image_put ( *extracted );
1456+ err_alloc:
1457+ err_unsupported:
1458+ return rc;
1459+}
1460+
1461+/**
1462+ * Extract and execute image
1463+ *
1464+ * @v image Image
1465+ * @ret rc Return status code
1466+ */
1467+int image_extract_exec ( struct image *image ) {
1468+ struct image *extracted;
1469+ int rc;
1470+
1471+ /* Extract image */
1472+ if ( ( rc = image_extract ( image, NULL, &extracted ) ) != 0 )
1473+ goto err_extract;
1474+
1475+ /* Set image command line */
1476+ if ( ( rc = image_set_cmdline ( extracted, image->cmdline ) ) != 0 )
1477+ goto err_set_cmdline;
1478+
1479+ /* Set auto-unregister flag */
1480+ extracted->flags |= IMAGE_AUTO_UNREGISTER;
1481+
1482+ /* Tail-recurse into extracted image */
1483+ return image_exec ( extracted );
1484+
1485+ err_set_cmdline:
1486+ unregister_image ( extracted );
1487+ err_extract:
1488+ return rc;
1489+}
1490+
1491+/* Drag in objects via image_extract() */
1492+REQUIRING_SYMBOL ( image_extract );
1493+
1494+/* Drag in archive image formats */
1495+REQUIRE_OBJECT ( config_archive );
1496diff --git a/src/core/base64.c b/src/core/base64.c
1497index e452f7d..ec11be2 100644
1498--- a/src/core/base64.c
1499+++ b/src/core/base64.c
1500@@ -36,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1501 *
1502 */
1503
1504-static const char base64[64] =
1505+static const char base64[ 64 + 1 /* NUL */ ] =
1506 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1507
1508 /**
1509diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c
1510index 0e7da4b..2fa9b0c 100644
1511--- a/src/core/cachedhcp.c
1512+++ b/src/core/cachedhcp.c
1513@@ -37,29 +37,121 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1514 *
1515 */
1516
1517+/** A cached DHCP packet */
1518+struct cached_dhcp_packet {
1519+ /** Settings block name */
1520+ const char *name;
1521+ /** DHCP packet (if any) */
1522+ struct dhcp_packet *dhcppkt;
1523+};
1524+
1525 /** Cached DHCPACK */
1526-static struct dhcp_packet *cached_dhcpack;
1527+struct cached_dhcp_packet cached_dhcpack = {
1528+ .name = DHCP_SETTINGS_NAME,
1529+};
1530+
1531+/** Cached ProxyDHCPOFFER */
1532+struct cached_dhcp_packet cached_proxydhcp = {
1533+ .name = PROXYDHCP_SETTINGS_NAME,
1534+};
1535+
1536+/** Cached PXEBSACK */
1537+struct cached_dhcp_packet cached_pxebs = {
1538+ .name = PXEBS_SETTINGS_NAME,
1539+};
1540+
1541+/** List of cached DHCP packets */
1542+static struct cached_dhcp_packet *cached_packets[] = {
1543+ &cached_dhcpack,
1544+ &cached_proxydhcp,
1545+ &cached_pxebs,
1546+};
1547
1548 /** Colour for debug messages */
1549 #define colour &cached_dhcpack
1550
1551 /**
1552- * Record cached DHCPACK
1553+ * Free cached DHCP packet
1554 *
1555+ * @v cache Cached DHCP packet
1556+ */
1557+static void cachedhcp_free ( struct cached_dhcp_packet *cache ) {
1558+
1559+ dhcppkt_put ( cache->dhcppkt );
1560+ cache->dhcppkt = NULL;
1561+}
1562+
1563+/**
1564+ * Apply cached DHCP packet settings
1565+ *
1566+ * @v cache Cached DHCP packet
1567+ * @v netdev Network device, or NULL
1568+ * @ret rc Return status code
1569+ */
1570+static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
1571+ struct net_device *netdev ) {
1572+ struct settings *settings;
1573+ int rc;
1574+
1575+ /* Do nothing if cache is empty */
1576+ if ( ! cache->dhcppkt )
1577+ return 0;
1578+
1579+ /* Do nothing unless cached packet's MAC address matches this
1580+ * network device, if specified.
1581+ */
1582+ if ( netdev ) {
1583+ if ( memcmp ( netdev->ll_addr, cache->dhcppkt->dhcphdr->chaddr,
1584+ netdev->ll_protocol->ll_addr_len ) != 0 ) {
1585+ DBGC ( colour, "CACHEDHCP %s does not match %s\n",
1586+ cache->name, netdev->name );
1587+ return 0;
1588+ }
1589+ DBGC ( colour, "CACHEDHCP %s is for %s\n",
1590+ cache->name, netdev->name );
1591+ }
1592+
1593+ /* Select appropriate parent settings block */
1594+ settings = ( netdev ? netdev_settings ( netdev ) : NULL );
1595+
1596+ /* Register settings */
1597+ if ( ( rc = register_settings ( &cache->dhcppkt->settings, settings,
1598+ cache->name ) ) != 0 ) {
1599+ DBGC ( colour, "CACHEDHCP %s could not register settings: %s\n",
1600+ cache->name, strerror ( rc ) );
1601+ return rc;
1602+ }
1603+
1604+ /* Free cached DHCP packet */
1605+ cachedhcp_free ( cache );
1606+
1607+ return 0;
1608+}
1609+
1610+/**
1611+ * Record cached DHCP packet
1612+ *
1613+ * @v cache Cached DHCP packet
1614 * @v data DHCPACK packet buffer
1615 * @v max_len Maximum possible length
1616 * @ret rc Return status code
1617 */
1618-int cachedhcp_record ( userptr_t data, size_t max_len ) {
1619+int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
1620+ size_t max_len ) {
1621 struct dhcp_packet *dhcppkt;
1622 struct dhcp_packet *tmp;
1623 struct dhcphdr *dhcphdr;
1624+ unsigned int i;
1625 size_t len;
1626
1627+ /* Free any existing cached packet */
1628+ cachedhcp_free ( cache );
1629+
1630 /* Allocate and populate DHCP packet */
1631 dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
1632 if ( ! dhcppkt ) {
1633- DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
1634+ DBGC ( colour, "CACHEDHCP %s could not allocate copy\n",
1635+ cache->name );
1636 return -ENOMEM;
1637 }
1638 dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
1639@@ -80,10 +172,26 @@ int cachedhcp_record ( userptr_t data, size_t max_len ) {
1640 dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
1641 dhcppkt_init ( dhcppkt, dhcphdr, len );
1642
1643- /* Store as cached DHCPACK, and mark original copy as consumed */
1644- DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n",
1645+ /* Discard duplicate packets, since some PXE stacks (including
1646+ * iPXE itself) will report the DHCPACK packet as the PXEBSACK
1647+ * if no separate PXEBSACK exists.
1648+ */
1649+ for ( i = 0 ; i < ( sizeof ( cached_packets ) /
1650+ sizeof ( cached_packets[0] ) ) ; i++ ) {
1651+ tmp = cached_packets[i]->dhcppkt;
1652+ if ( tmp && ( dhcppkt_len ( tmp ) == len ) &&
1653+ ( memcmp ( tmp->dhcphdr, dhcppkt->dhcphdr, len ) == 0 ) ) {
1654+ DBGC ( colour, "CACHEDHCP %s duplicates %s\n",
1655+ cache->name, cached_packets[i]->name );
1656+ dhcppkt_put ( dhcppkt );
1657+ return -EEXIST;
1658+ }
1659+ }
1660+
1661+ /* Store as cached packet */
1662+ DBGC ( colour, "CACHEDHCP %s at %#08lx+%#zx/%#zx\n", cache->name,
1663 user_to_phys ( data, 0 ), len, max_len );
1664- cached_dhcpack = dhcppkt;
1665+ cache->dhcppkt = dhcppkt;
1666
1667 return 0;
1668 }
1669@@ -94,14 +202,20 @@ int cachedhcp_record ( userptr_t data, size_t max_len ) {
1670 */
1671 static void cachedhcp_startup ( void ) {
1672
1673- /* If cached DHCP packet was not claimed by any network device
1674- * during startup, then free it.
1675- */
1676- if ( cached_dhcpack ) {
1677- DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
1678- dhcppkt_put ( cached_dhcpack );
1679- cached_dhcpack = NULL;
1680+ /* Apply cached ProxyDHCPOFFER, if any */
1681+ cachedhcp_apply ( &cached_proxydhcp, NULL );
1682+
1683+ /* Apply cached PXEBSACK, if any */
1684+ cachedhcp_apply ( &cached_pxebs, NULL );
1685+
1686+ /* Free any remaining cached packets */
1687+ if ( cached_dhcpack.dhcppkt ) {
1688+ DBGC ( colour, "CACHEDHCP %s unclaimed\n",
1689+ cached_dhcpack.name );
1690 }
1691+ cachedhcp_free ( &cached_dhcpack );
1692+ cachedhcp_free ( &cached_proxydhcp );
1693+ cachedhcp_free ( &cached_pxebs );
1694 }
1695
1696 /** Cached DHCPACK startup function */
1697@@ -117,38 +231,9 @@ struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
1698 * @ret rc Return status code
1699 */
1700 static int cachedhcp_probe ( struct net_device *netdev ) {
1701- struct ll_protocol *ll_protocol = netdev->ll_protocol;
1702- int rc;
1703
1704- /* Do nothing unless we have a cached DHCPACK */
1705- if ( ! cached_dhcpack )
1706- return 0;
1707-
1708- /* Do nothing unless cached DHCPACK's MAC address matches this
1709- * network device.
1710- */
1711- if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
1712- ll_protocol->ll_addr_len ) != 0 ) {
1713- DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
1714- netdev->name );
1715- return 0;
1716- }
1717- DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
1718-
1719- /* Register as DHCP settings for this network device */
1720- if ( ( rc = register_settings ( &cached_dhcpack->settings,
1721- netdev_settings ( netdev ),
1722- DHCP_SETTINGS_NAME ) ) != 0 ) {
1723- DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
1724- strerror ( rc ) );
1725- return rc;
1726- }
1727-
1728- /* Claim cached DHCPACK */
1729- dhcppkt_put ( cached_dhcpack );
1730- cached_dhcpack = NULL;
1731-
1732- return 0;
1733+ /* Apply cached DHCPACK to network device, if applicable */
1734+ return cachedhcp_apply ( &cached_dhcpack, netdev );
1735 }
1736
1737 /** Cached DHCP packet network device driver */
1738diff --git a/src/core/console.c b/src/core/console.c
1739index 7fd0003..2b90809 100644
1740--- a/src/core/console.c
1741+++ b/src/core/console.c
1742@@ -20,11 +20,12 @@ unsigned int console_height = CONSOLE_DEFAULT_HEIGHT;
1743 * Write a single character to each console device
1744 *
1745 * @v character Character to be written
1746+ * @ret character Character written
1747 *
1748 * The character is written out to all enabled console devices, using
1749 * each device's console_driver::putchar() method.
1750 */
1751-void putchar ( int character ) {
1752+int putchar ( int character ) {
1753 struct console_driver *console;
1754
1755 /* Automatic LF -> CR,LF translation */
1756@@ -37,6 +38,8 @@ void putchar ( int character ) {
1757 console->putchar )
1758 console->putchar ( character );
1759 }
1760+
1761+ return character;
1762 }
1763
1764 /**
1765diff --git a/src/core/cpio.c b/src/core/cpio.c
1766index 080c72d..27aee75 100644
1767--- a/src/core/cpio.c
1768+++ b/src/core/cpio.c
1769@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1770 */
1771
1772 #include <stdio.h>
1773+#include <stdlib.h>
1774 #include <string.h>
1775 #include <ipxe/cpio.h>
1776
1777@@ -45,3 +46,87 @@ void cpio_set_field ( char *field, unsigned long value ) {
1778 snprintf ( buf, sizeof ( buf ), "%08lx", value );
1779 memcpy ( field, buf, 8 );
1780 }
1781+
1782+/**
1783+ * Get CPIO image filename
1784+ *
1785+ * @v image Image
1786+ * @ret len CPIO filename length (0 for no filename)
1787+ */
1788+size_t cpio_name_len ( struct image *image ) {
1789+ const char *name = cpio_name ( image );
1790+ char *sep;
1791+ size_t len;
1792+
1793+ /* Check for existence of CPIO filename */
1794+ if ( ! name )
1795+ return 0;
1796+
1797+ /* Locate separator (if any) */
1798+ sep = strchr ( name, ' ' );
1799+ len = ( sep ? ( ( size_t ) ( sep - name ) ) : strlen ( name ) );
1800+
1801+ return len;
1802+}
1803+
1804+/**
1805+ * Parse CPIO image parameters
1806+ *
1807+ * @v image Image
1808+ * @v cpio CPIO header to fill in
1809+ */
1810+static void cpio_parse_cmdline ( struct image *image,
1811+ struct cpio_header *cpio ) {
1812+ const char *cmdline;
1813+ char *arg;
1814+ char *end;
1815+ unsigned int mode;
1816+
1817+ /* Skip image filename */
1818+ cmdline = ( cpio_name ( image ) + cpio_name_len ( image ) );
1819+
1820+ /* Look for "mode=" */
1821+ if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
1822+ arg += 5;
1823+ mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
1824+ if ( *end && ( *end != ' ' ) ) {
1825+ DBGC ( image, "CPIO %p strange \"mode=\" "
1826+ "terminator '%c'\n", image, *end );
1827+ }
1828+ cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
1829+ }
1830+}
1831+
1832+/**
1833+ * Construct CPIO header for image, if applicable
1834+ *
1835+ * @v image Image
1836+ * @v cpio CPIO header to fill in
1837+ * @ret len Length of magic CPIO header (including filename)
1838+ */
1839+size_t cpio_header ( struct image *image, struct cpio_header *cpio ) {
1840+ size_t name_len;
1841+ size_t len;
1842+
1843+ /* Get filename length */
1844+ name_len = cpio_name_len ( image );
1845+
1846+ /* Images with no filename are assumed to already be CPIO archives */
1847+ if ( ! name_len )
1848+ return 0;
1849+
1850+ /* Construct CPIO header */
1851+ memset ( cpio, '0', sizeof ( *cpio ) );
1852+ memcpy ( cpio->c_magic, CPIO_MAGIC, sizeof ( cpio->c_magic ) );
1853+ cpio_set_field ( cpio->c_mode, 0100644 );
1854+ cpio_set_field ( cpio->c_nlink, 1 );
1855+ cpio_set_field ( cpio->c_filesize, image->len );
1856+ cpio_set_field ( cpio->c_namesize, ( name_len + 1 /* NUL */ ) );
1857+ cpio_parse_cmdline ( image, cpio );
1858+
1859+ /* Calculate total length */
1860+ len = ( ( sizeof ( *cpio ) + name_len + 1 /* NUL */ + CPIO_ALIGN - 1 )
1861+ & ~( CPIO_ALIGN - 1 ) );
1862+
1863+ return len;
1864+}
1865diff --git a/src/core/image.c b/src/core/image.c
1866index 9fe77c5..ce8cf86 100644
1867--- a/src/core/image.c
1868+++ b/src/core/image.c
1869@@ -176,14 +176,13 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
1870 }
1871
1872 /**
1873- * Set image data
1874+ * Set image length
1875 *
1876 * @v image Image
1877- * @v data Image data
1878 * @v len Length of image data
1879 * @ret rc Return status code
1880 */
1881-int image_set_data ( struct image *image, userptr_t data, size_t len ) {
1882+int image_set_len ( struct image *image, size_t len ) {
1883 userptr_t new;
1884
1885 /* (Re)allocate image data */
1886@@ -191,10 +190,28 @@ int image_set_data ( struct image *image, userptr_t data, size_t len ) {
1887 if ( ! new )
1888 return -ENOMEM;
1889 image->data = new;
1890+ image->len = len;
1891+
1892+ return 0;
1893+}
1894+
1895+/**
1896+ * Set image data
1897+ *
1898+ * @v image Image
1899+ * @v data Image data
1900+ * @v len Length of image data
1901+ * @ret rc Return status code
1902+ */
1903+int image_set_data ( struct image *image, userptr_t data, size_t len ) {
1904+ int rc;
1905+
1906+ /* Set image length */
1907+ if ( ( rc = image_set_len ( image, len ) ) != 0 )
1908+ return rc;
1909
1910 /* Copy in new image data */
1911 memcpy_user ( image->data, 0, data, 0, len );
1912- image->len = len;
1913
1914 return 0;
1915 }
1916diff --git a/src/core/open.c b/src/core/open.c
1917index c27d8a0..f9198c9 100644
1918--- a/src/core/open.c
1919+++ b/src/core/open.c
1920@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1921
1922 #include <stdarg.h>
1923 #include <string.h>
1924+#include <strings.h>
1925 #include <errno.h>
1926 #include <ipxe/xfer.h>
1927 #include <ipxe/uri.h>
1928@@ -47,7 +48,7 @@ struct uri_opener * xfer_uri_opener ( const char *scheme ) {
1929 struct uri_opener *opener;
1930
1931 for_each_table_entry ( opener, URI_OPENERS ) {
1932- if ( strcmp ( scheme, opener->scheme ) == 0 )
1933+ if ( strcasecmp ( scheme, opener->scheme ) == 0 )
1934 return opener;
1935 }
1936 return NULL;
1937diff --git a/src/core/settings.c b/src/core/settings.c
1938index 430cdc8..fcdf98d 100644
1939--- a/src/core/settings.c
1940+++ b/src/core/settings.c
1941@@ -2199,7 +2199,7 @@ const struct setting_type setting_type_base64 __setting_type = {
1942 };
1943
1944 /**
1945- * Format UUID setting value
1946+ * Format UUID/GUID setting value
1947 *
1948 * @v type Setting type
1949 * @v raw Raw setting value
1950@@ -2208,17 +2208,24 @@ const struct setting_type setting_type_base64 __setting_type = {
1951 * @v len Length of buffer
1952 * @ret len Length of formatted value, or negative error
1953 */
1954-static int format_uuid_setting ( const struct setting_type *type __unused,
1955+static int format_uuid_setting ( const struct setting_type *type,
1956 const void *raw, size_t raw_len, char *buf,
1957 size_t len ) {
1958- const union uuid *uuid = raw;
1959+ union uuid uuid;
1960
1961 /* Range check */
1962- if ( raw_len != sizeof ( *uuid ) )
1963+ if ( raw_len != sizeof ( uuid ) )
1964 return -ERANGE;
1965
1966+ /* Copy value */
1967+ memcpy ( &uuid, raw, sizeof ( uuid ) );
1968+
1969+ /* Mangle GUID byte ordering */
1970+ if ( type == &setting_type_guid )
1971+ uuid_mangle ( &uuid );
1972+
1973 /* Format value */
1974- return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
1975+ return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
1976 }
1977
1978 /** UUID setting type */
1979@@ -2227,6 +2234,12 @@ const struct setting_type setting_type_uuid __setting_type = {
1980 .format = format_uuid_setting,
1981 };
1982
1983+/** GUID setting type */
1984+const struct setting_type setting_type_guid __setting_type = {
1985+ .name = "guid",
1986+ .format = format_uuid_setting,
1987+};
1988+
1989 /**
1990 * Format PCI bus:dev.fn setting value
1991 *
1992diff --git a/src/core/string.c b/src/core/string.c
1993index 188fe08..9a1b9b7 100644
1994--- a/src/core/string.c
1995+++ b/src/core/string.c
1996@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1997 #include <stdint.h>
1998 #include <stdlib.h>
1999 #include <string.h>
2000+#include <strings.h>
2001 #include <ctype.h>
2002
2003 /** @file
2004@@ -205,11 +206,24 @@ int strncmp ( const char *first, const char *second, size_t max ) {
2005 * @ret diff Difference
2006 */
2007 int strcasecmp ( const char *first, const char *second ) {
2008+
2009+ return strncasecmp ( first, second, ~( ( size_t ) 0 ) );
2010+}
2011+
2012+/**
2013+ * Compare case-insensitive strings
2014+ *
2015+ * @v first First string
2016+ * @v second Second string
2017+ * @v max Maximum length to compare
2018+ * @ret diff Difference
2019+ */
2020+int strncasecmp ( const char *first, const char *second, size_t max ) {
2021 const uint8_t *first_bytes = ( ( const uint8_t * ) first );
2022 const uint8_t *second_bytes = ( ( const uint8_t * ) second );
2023 int diff;
2024
2025- for ( ; ; first_bytes++, second_bytes++ ) {
2026+ for ( ; max-- ; first_bytes++, second_bytes++ ) {
2027 diff = ( toupper ( *first_bytes ) -
2028 toupper ( *second_bytes ) );
2029 if ( diff )
2030@@ -217,6 +231,7 @@ int strcasecmp ( const char *first, const char *second ) {
2031 if ( ! *first_bytes )
2032 return 0;
2033 }
2034+ return 0;
2035 }
2036
2037 /**
2038diff --git a/src/core/uri.c b/src/core/uri.c
2039index e9e512a..a0f79e9 100644
2040--- a/src/core/uri.c
2041+++ b/src/core/uri.c
2042@@ -79,12 +79,10 @@ size_t uri_decode ( const char *encoded, void *buf, size_t len ) {
2043 /**
2044 * Decode URI field in-place
2045 *
2046- * @v uri URI
2047- * @v field URI field index
2048+ * @v encoded Encoded field, or NULL
2049 */
2050-static void uri_decode_inplace ( struct uri *uri, unsigned int field ) {
2051- const char *encoded = uri_field ( uri, field );
2052- char *decoded = ( ( char * ) encoded );
2053+static void uri_decode_inplace ( char *encoded ) {
2054+ char *decoded = encoded;
2055 size_t len;
2056
2057 /* Do nothing if field is not present */
2058@@ -150,7 +148,7 @@ static int uri_character_escaped ( char c, unsigned int field ) {
2059 * parser but for any other URI parsers (e.g. HTTP query
2060 * string parsers, which care about '=' and '&').
2061 */
2062- static const char *escaped[URI_FIELDS] = {
2063+ static const char *escaped[URI_EPATH] = {
2064 /* Scheme or default: escape everything */
2065 [URI_SCHEME] = "/#:@?=&",
2066 /* Opaque part: escape characters which would affect
2067@@ -172,20 +170,21 @@ static int uri_character_escaped ( char c, unsigned int field ) {
2068 * appears within paths.
2069 */
2070 [URI_PATH] = "#:@?",
2071- /* Query: escape everything except '/', which
2072- * sometimes appears within queries.
2073- */
2074- [URI_QUERY] = "#:@?",
2075- /* Fragment: escape everything */
2076- [URI_FRAGMENT] = "/#:@?",
2077 };
2078
2079- return ( /* Always escape non-printing characters and whitespace */
2080- ( ! isprint ( c ) ) || ( c == ' ' ) ||
2081- /* Always escape '%' */
2082- ( c == '%' ) ||
2083- /* Escape field-specific characters */
2084- strchr ( escaped[field], c ) );
2085+ /* Always escape non-printing characters and whitespace */
2086+ if ( ( ! isprint ( c ) ) || ( c == ' ' ) )
2087+ return 1;
2088+
2089+ /* Escape nothing else in already-escaped fields */
2090+ if ( field >= URI_EPATH )
2091+ return 0;
2092+
2093+ /* Escape '%' and any field-specific characters */
2094+ if ( ( c == '%' ) || strchr ( escaped[field], c ) )
2095+ return 1;
2096+
2097+ return 0;
2098 }
2099
2100 /**
2101@@ -262,10 +261,12 @@ static void uri_dump ( const struct uri *uri ) {
2102 DBGC ( uri, " port \"%s\"", uri->port );
2103 if ( uri->path )
2104 DBGC ( uri, " path \"%s\"", uri->path );
2105- if ( uri->query )
2106- DBGC ( uri, " query \"%s\"", uri->query );
2107- if ( uri->fragment )
2108- DBGC ( uri, " fragment \"%s\"", uri->fragment );
2109+ if ( uri->epath )
2110+ DBGC ( uri, " epath \"%s\"", uri->epath );
2111+ if ( uri->equery )
2112+ DBGC ( uri, " equery \"%s\"", uri->equery );
2113+ if ( uri->efragment )
2114+ DBGC ( uri, " efragment \"%s\"", uri->efragment );
2115 if ( uri->params )
2116 DBGC ( uri, " params \"%s\"", uri->params->name );
2117 }
2118@@ -298,17 +299,19 @@ struct uri * parse_uri ( const char *uri_string ) {
2119 char *raw;
2120 char *tmp;
2121 char *path;
2122+ char *epath;
2123 char *authority;
2124 size_t raw_len;
2125 unsigned int field;
2126
2127- /* Allocate space for URI struct and a copy of the string */
2128+ /* Allocate space for URI struct and two copies of the string */
2129 raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
2130- uri = zalloc ( sizeof ( *uri ) + raw_len );
2131+ uri = zalloc ( sizeof ( *uri ) + ( 2 * raw_len ) );
2132 if ( ! uri )
2133 return NULL;
2134 ref_init ( &uri->refcnt, uri_free );
2135 raw = ( ( ( void * ) uri ) + sizeof ( *uri ) );
2136+ path = ( raw + raw_len );
2137
2138 /* Copy in the raw string */
2139 memcpy ( raw, uri_string, raw_len );
2140@@ -328,7 +331,7 @@ struct uri * parse_uri ( const char *uri_string ) {
2141 /* Chop off the fragment, if it exists */
2142 if ( ( tmp = strchr ( raw, '#' ) ) ) {
2143 *(tmp++) = '\0';
2144- uri->fragment = tmp;
2145+ uri->efragment = tmp;
2146 }
2147
2148 /* Identify absolute/relative URI */
2149@@ -338,47 +341,47 @@ struct uri * parse_uri ( const char *uri_string ) {
2150 *(tmp++) = '\0';
2151 if ( *tmp == '/' ) {
2152 /* Absolute URI with hierarchical part */
2153- path = tmp;
2154+ epath = tmp;
2155 } else {
2156 /* Absolute URI with opaque part */
2157 uri->opaque = tmp;
2158- path = NULL;
2159+ epath = NULL;
2160 }
2161 } else {
2162 /* Relative URI */
2163- path = raw;
2164+ epath = raw;
2165 }
2166
2167 /* If we don't have a path (i.e. we have an absolute URI with
2168 * an opaque portion, we're already finished processing
2169 */
2170- if ( ! path )
2171+ if ( ! epath )
2172 goto done;
2173
2174 /* Chop off the query, if it exists */
2175- if ( ( tmp = strchr ( path, '?' ) ) ) {
2176+ if ( ( tmp = strchr ( epath, '?' ) ) ) {
2177 *(tmp++) = '\0';
2178- uri->query = tmp;
2179+ uri->equery = tmp;
2180 }
2181
2182 /* If we have no path remaining, then we're already finished
2183 * processing.
2184 */
2185- if ( ! path[0] )
2186+ if ( ! epath[0] )
2187 goto done;
2188
2189 /* Identify net/absolute/relative path */
2190- if ( uri->scheme && ( strncmp ( path, "//", 2 ) == 0 ) ) {
2191+ if ( uri->scheme && ( strncmp ( epath, "//", 2 ) == 0 ) ) {
2192 /* Net path. If this is terminated by the first '/'
2193 * of an absolute path, then we have no space for a
2194 * terminator after the authority field, so shuffle
2195 * the authority down by one byte, overwriting one of
2196 * the two slashes.
2197 */
2198- authority = ( path + 2 );
2199+ authority = ( epath + 2 );
2200 if ( ( tmp = strchr ( authority, '/' ) ) ) {
2201 /* Shuffle down */
2202- uri->path = tmp;
2203+ uri->epath = tmp;
2204 memmove ( ( authority - 1 ), authority,
2205 ( tmp - authority ) );
2206 authority--;
2207@@ -386,10 +389,16 @@ struct uri * parse_uri ( const char *uri_string ) {
2208 }
2209 } else {
2210 /* Absolute/relative path */
2211- uri->path = path;
2212+ uri->epath = epath;
2213 authority = NULL;
2214 }
2215
2216+ /* Create copy of path for decoding */
2217+ if ( uri->epath ) {
2218+ strcpy ( path, uri->epath );
2219+ uri->path = path;
2220+ }
2221+
2222 /* If we don't have an authority (i.e. we have a non-net
2223 * path), we're already finished processing
2224 */
2225@@ -421,8 +430,8 @@ struct uri * parse_uri ( const char *uri_string ) {
2226
2227 done:
2228 /* Decode fields in-place */
2229- for ( field = 0 ; field < URI_FIELDS ; field++ )
2230- uri_decode_inplace ( uri, field );
2231+ for ( field = 0 ; field < URI_EPATH ; field++ )
2232+ uri_decode_inplace ( ( char * ) uri_field ( uri, field ) );
2233
2234 DBGC ( uri, "URI parsed \"%s\" to", uri_string );
2235 uri_dump ( uri );
2236@@ -458,8 +467,8 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
2237 static const char prefixes[URI_FIELDS] = {
2238 [URI_PASSWORD] = ':',
2239 [URI_PORT] = ':',
2240- [URI_QUERY] = '?',
2241- [URI_FRAGMENT] = '#',
2242+ [URI_EQUERY] = '?',
2243+ [URI_EFRAGMENT] = '#',
2244 };
2245 char prefix;
2246 size_t used = 0;
2247@@ -480,6 +489,10 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
2248 if ( ! uri_field ( uri, field ) )
2249 continue;
2250
2251+ /* Skip path field if encoded path is present */
2252+ if ( ( field == URI_PATH ) && uri->epath )
2253+ continue;
2254+
2255 /* Prefix this field, if applicable */
2256 prefix = prefixes[field];
2257 if ( ( field == URI_HOST ) && ( uri->user != NULL ) )
2258@@ -676,6 +689,7 @@ char * resolve_path ( const char *base_path,
2259 struct uri * resolve_uri ( const struct uri *base_uri,
2260 struct uri *relative_uri ) {
2261 struct uri tmp_uri;
2262+ char *tmp_epath = NULL;
2263 char *tmp_path = NULL;
2264 struct uri *new_uri;
2265
2266@@ -685,20 +699,27 @@ struct uri * resolve_uri ( const struct uri *base_uri,
2267
2268 /* Mangle URI */
2269 memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
2270- if ( relative_uri->path ) {
2271- tmp_path = resolve_path ( ( base_uri->path ?
2272- base_uri->path : "/" ),
2273- relative_uri->path );
2274+ if ( relative_uri->epath ) {
2275+ tmp_epath = resolve_path ( ( base_uri->epath ?
2276+ base_uri->epath : "/" ),
2277+ relative_uri->epath );
2278+ if ( ! tmp_epath )
2279+ goto err_epath;
2280+ tmp_path = strdup ( tmp_epath );
2281+ if ( ! tmp_path )
2282+ goto err_path;
2283+ uri_decode_inplace ( tmp_path );
2284+ tmp_uri.epath = tmp_epath;
2285 tmp_uri.path = tmp_path;
2286- tmp_uri.query = relative_uri->query;
2287- tmp_uri.fragment = relative_uri->fragment;
2288+ tmp_uri.equery = relative_uri->equery;
2289+ tmp_uri.efragment = relative_uri->efragment;
2290 tmp_uri.params = relative_uri->params;
2291- } else if ( relative_uri->query ) {
2292- tmp_uri.query = relative_uri->query;
2293- tmp_uri.fragment = relative_uri->fragment;
2294+ } else if ( relative_uri->equery ) {
2295+ tmp_uri.equery = relative_uri->equery;
2296+ tmp_uri.efragment = relative_uri->efragment;
2297 tmp_uri.params = relative_uri->params;
2298- } else if ( relative_uri->fragment ) {
2299- tmp_uri.fragment = relative_uri->fragment;
2300+ } else if ( relative_uri->efragment ) {
2301+ tmp_uri.efragment = relative_uri->efragment;
2302 tmp_uri.params = relative_uri->params;
2303 } else if ( relative_uri->params ) {
2304 tmp_uri.params = relative_uri->params;
2305@@ -707,7 +728,14 @@ struct uri * resolve_uri ( const struct uri *base_uri,
2306 /* Create demangled URI */
2307 new_uri = uri_dup ( &tmp_uri );
2308 free ( tmp_path );
2309+ free ( tmp_epath );
2310 return new_uri;
2311+
2312+ free ( tmp_path );
2313+ err_path:
2314+ free ( tmp_epath );
2315+ err_epath:
2316+ return NULL;
2317 }
2318
2319 /**
2320@@ -746,6 +774,7 @@ static struct uri * tftp_uri ( struct sockaddr *sa_server,
2321 if ( asprintf ( &path, "/%s", filename ) < 0 )
2322 goto err_path;
2323 tmp.path = path;
2324+ tmp.epath = path;
2325
2326 /* Demangle URI */
2327 uri = uri_dup ( &tmp );
2328diff --git a/src/crypto/x509.c b/src/crypto/x509.c
2329index 17d8c7a..1f017eb 100644
2330--- a/src/crypto/x509.c
2331+++ b/src/crypto/x509.c
2332@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
2333
2334 #include <stdlib.h>
2335 #include <string.h>
2336+#include <strings.h>
2337 #include <errno.h>
2338 #include <assert.h>
2339 #include <ipxe/list.h>
2340@@ -1464,7 +1465,7 @@ static int x509_check_dnsname ( struct x509_certificate *cert,
2341
2342 /* Compare names */
2343 if ( ! ( ( strlen ( name ) == len ) &&
2344- ( memcmp ( name, dnsname, len ) == 0 ) ) )
2345+ ( strncasecmp ( name, dnsname, len ) == 0 ) ) )
2346 return -ENOENT;
2347
2348 if ( name != fullname ) {
2349diff --git a/src/drivers/bus/virtio-pci.c b/src/drivers/bus/virtio-pci.c
2350index 5d2d627..8b34c72 100644
2351--- a/src/drivers/bus/virtio-pci.c
2352+++ b/src/drivers/bus/virtio-pci.c
2353@@ -17,37 +17,47 @@
2354 #include "ipxe/io.h"
2355 #include "ipxe/iomap.h"
2356 #include "ipxe/pci.h"
2357+#include "ipxe/dma.h"
2358 #include "ipxe/reboot.h"
2359 #include "ipxe/virtio-pci.h"
2360 #include "ipxe/virtio-ring.h"
2361
2362-static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num)
2363+static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num, size_t header_size)
2364 {
2365- size_t queue_size = PAGE_MASK + vring_size(num);
2366+ size_t ring_size = PAGE_MASK + vring_size(num);
2367 size_t vdata_size = num * sizeof(void *);
2368+ size_t queue_size = ring_size + vdata_size + header_size;
2369
2370- vq->queue = zalloc(queue_size + vdata_size);
2371+ vq->queue = dma_alloc(vq->dma, &vq->map, queue_size, queue_size);
2372 if (!vq->queue) {
2373 return -ENOMEM;
2374 }
2375
2376+ memset ( vq->queue, 0, queue_size );
2377+ vq->queue_size = queue_size;
2378+
2379 /* vdata immediately follows the ring */
2380- vq->vdata = (void **)(vq->queue + queue_size);
2381+ vq->vdata = (void **)(vq->queue + ring_size);
2382+
2383+ /* empty header immediately follows vdata */
2384+ vq->empty_header = (struct virtio_net_hdr_modern *)(vq->queue + ring_size + vdata_size);
2385
2386 return 0;
2387 }
2388
2389 void vp_free_vq(struct vring_virtqueue *vq)
2390 {
2391- if (vq->queue) {
2392- free(vq->queue);
2393+ if (vq->queue && vq->queue_size) {
2394+ dma_free(&vq->map, vq->queue, vq->queue_size);
2395 vq->queue = NULL;
2396 vq->vdata = NULL;
2397+ vq->queue_size = 0;
2398 }
2399 }
2400
2401 int vp_find_vq(unsigned int ioaddr, int queue_index,
2402- struct vring_virtqueue *vq)
2403+ struct vring_virtqueue *vq, struct dma_device *dma_dev,
2404+ size_t header_size)
2405 {
2406 struct vring * vr = &vq->vring;
2407 u16 num;
2408@@ -73,9 +83,10 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
2409 }
2410
2411 vq->queue_index = queue_index;
2412+ vq->dma = dma_dev;
2413
2414 /* initialize the queue */
2415- rc = vp_alloc_vq(vq, num);
2416+ rc = vp_alloc_vq(vq, num, header_size);
2417 if (rc) {
2418 DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n");
2419 return rc;
2420@@ -87,8 +98,7 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
2421 * NOTE: vr->desc is initialized by vring_init()
2422 */
2423
2424- outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
2425- ioaddr + VIRTIO_PCI_QUEUE_PFN);
2426+ outl(dma(&vq->map, vr->desc) >> PAGE_SHIFT, ioaddr + VIRTIO_PCI_QUEUE_PFN);
2427
2428 return num;
2429 }
2430@@ -348,7 +358,8 @@ void vpm_notify(struct virtio_pci_modern_device *vdev,
2431 }
2432
2433 int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
2434- unsigned nvqs, struct vring_virtqueue *vqs)
2435+ unsigned nvqs, struct vring_virtqueue *vqs,
2436+ struct dma_device *dma_dev, size_t header_size)
2437 {
2438 unsigned i;
2439 struct vring_virtqueue *vq;
2440@@ -392,11 +403,12 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
2441
2442 vq = &vqs[i];
2443 vq->queue_index = i;
2444+ vq->dma = dma_dev;
2445
2446 /* get offset of notification word for this vq */
2447 off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off));
2448
2449- err = vp_alloc_vq(vq, size);
2450+ err = vp_alloc_vq(vq, size, header_size);
2451 if (err) {
2452 DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev);
2453 return err;
2454@@ -406,13 +418,16 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
2455 /* activate the queue */
2456 vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size));
2457
2458- vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.desc),
2459+ vpm_iowrite64(vdev, &vdev->common,
2460+ dma(&vq->map, vq->vring.desc),
2461 COMMON_OFFSET(queue_desc_lo),
2462 COMMON_OFFSET(queue_desc_hi));
2463- vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.avail),
2464+ vpm_iowrite64(vdev, &vdev->common,
2465+ dma(&vq->map, vq->vring.avail),
2466 COMMON_OFFSET(queue_avail_lo),
2467 COMMON_OFFSET(queue_avail_hi));
2468- vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.used),
2469+ vpm_iowrite64(vdev, &vdev->common,
2470+ dma(&vq->map, vq->vring.used),
2471 COMMON_OFFSET(queue_used_lo),
2472 COMMON_OFFSET(queue_used_hi));
2473
2474diff --git a/src/drivers/bus/virtio-ring.c b/src/drivers/bus/virtio-ring.c
2475index 98e787e..e448c34 100644
2476--- a/src/drivers/bus/virtio-ring.c
2477+++ b/src/drivers/bus/virtio-ring.c
2478@@ -98,7 +98,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
2479 for (i = head; out; i = vr->desc[i].next, out--) {
2480
2481 vr->desc[i].flags = VRING_DESC_F_NEXT;
2482- vr->desc[i].addr = (u64)virt_to_phys(list->addr);
2483+ vr->desc[i].addr = list->addr;
2484 vr->desc[i].len = list->length;
2485 prev = i;
2486 list++;
2487@@ -106,7 +106,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
2488 for ( ; in; i = vr->desc[i].next, in--) {
2489
2490 vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
2491- vr->desc[i].addr = (u64)virt_to_phys(list->addr);
2492+ vr->desc[i].addr = list->addr;
2493 vr->desc[i].len = list->length;
2494 prev = i;
2495 list++;
2496diff --git a/src/drivers/net/ath/ath5k/ath5k_eeprom.c b/src/drivers/net/ath/ath5k/ath5k_eeprom.c
2497index 12519bc..46f33d1 100644
2498--- a/src/drivers/net/ath/ath5k/ath5k_eeprom.c
2499+++ b/src/drivers/net/ath/ath5k/ath5k_eeprom.c
2500@@ -39,6 +39,9 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
2501 {
2502 u32 status, timeout;
2503
2504+ /* Avoid returning uninitialised data on error */
2505+ *data = 0xffff;
2506+
2507 /*
2508 * Initialize EEPROM access
2509 */
2510diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c
2511index b8663c0..e387650 100644
2512--- a/src/drivers/net/bnxt/bnxt.c
2513+++ b/src/drivers/net/bnxt/bnxt.c
2514@@ -23,16 +23,74 @@ static void bnxt_adv_cq_index ( struct bnxt *bp, u16 cnt );
2515 static int bnxt_rx_complete ( struct net_device *dev, struct rx_pkt_cmpl *rx );
2516 void bnxt_link_evt ( struct bnxt *bp, struct hwrm_async_event_cmpl *evt );
2517
2518+static struct pci_device_id bnxt_nics[] = {
2519+ PCI_ROM( 0x14e4, 0x16c0, "14e4-16C0", "14e4-16C0", 0 ),
2520+ PCI_ROM( 0x14e4, 0x16c1, "14e4-16C1", "14e4-16C1", BNXT_FLAG_PCI_VF ),
2521+ PCI_ROM( 0x14e4, 0x16c8, "14e4-16C8", "14e4-16C8", 0 ),
2522+ PCI_ROM( 0x14e4, 0x16c9, "14e4-16C9", "14e4-16C9", 0 ),
2523+ PCI_ROM( 0x14e4, 0x16ca, "14e4-16CA", "14e4-16CA", 0 ),
2524+ PCI_ROM( 0x14e4, 0x16cc, "14e4-16CC", "14e4-16CC", 0 ),
2525+ PCI_ROM( 0x14e4, 0x16cd, "14e4-16CD", "14e4-16CD", 0 ),
2526+ PCI_ROM( 0x14e4, 0x16ce, "14e4-16CE", "14e4-16CE", 0 ),
2527+ PCI_ROM( 0x14e4, 0x16cf, "14e4-16CF", "14e4-16CF", 0 ),
2528+ PCI_ROM( 0x14e4, 0x16d0, "14e4-16D0", "14e4-16D0", 0 ),
2529+ PCI_ROM( 0x14e4, 0x16d1, "14e4-16D1", "14e4-16D1", 0 ),
2530+ PCI_ROM( 0x14e4, 0x16d2, "14e4-16D2", "14e4-16D2", 0 ),
2531+ PCI_ROM( 0x14e4, 0x16d4, "14e4-16D4", "14e4-16D4", 0 ),
2532+ PCI_ROM( 0x14e4, 0x16d5, "14e4-16D5", "14e4-16D5", 0 ),
2533+ PCI_ROM( 0x14e4, 0x16d6, "14e4-16D6", "14e4-16D6", 0 ),
2534+ PCI_ROM( 0x14e4, 0x16d7, "14e4-16D7", "14e4-16D7", 0 ),
2535+ PCI_ROM( 0x14e4, 0x16d8, "14e4-16D8", "14e4-16D8", 0 ),
2536+ PCI_ROM( 0x14e4, 0x16d9, "14e4-16D9", "14e4-16D9", 0 ),
2537+ PCI_ROM( 0x14e4, 0x16da, "14e4-16DA", "14e4-16DA", 0 ),
2538+ PCI_ROM( 0x14e4, 0x16db, "14e4-16DB", "14e4-16DB", 0 ),
2539+ PCI_ROM( 0x14e4, 0x16dc, "14e4-16DC", "14e4-16DC", BNXT_FLAG_PCI_VF ),
2540+ PCI_ROM( 0x14e4, 0x16de, "14e4-16DE", "14e4-16DE", 0 ),
2541+ PCI_ROM( 0x14e4, 0x16df, "14e4-16DF", "14e4-16DF", 0 ),
2542+ PCI_ROM( 0x14e4, 0x16e0, "14e4-16E0", "14e4-16E0", 0 ),
2543+ PCI_ROM( 0x14e4, 0x16e2, "14e4-16E2", "14e4-16E2", 0 ),
2544+ PCI_ROM( 0x14e4, 0x16e3, "14e4-16E3", "14e4-16E3", 0 ),
2545+ PCI_ROM( 0x14e4, 0x16e4, "14e4-16E4", "14e4-16E4", 0 ),
2546+ PCI_ROM( 0x14e4, 0x16e7, "14e4-16E7", "14e4-16E7", 0 ),
2547+ PCI_ROM( 0x14e4, 0x16e8, "14e4-16E8", "14e4-16E8", 0 ),
2548+ PCI_ROM( 0x14e4, 0x16e9, "14e4-16E9", "14e4-16E9", 0 ),
2549+ PCI_ROM( 0x14e4, 0x16ea, "14e4-16EA", "14e4-16EA", 0 ),
2550+ PCI_ROM( 0x14e4, 0x16eb, "14e4-16EB", "14e4-16EB", 0 ),
2551+ PCI_ROM( 0x14e4, 0x16ec, "14e4-16EC", "14e4-16EC", 0 ),
2552+ PCI_ROM( 0x14e4, 0x16ed, "14e4-16ED", "14e4-16ED", 0 ),
2553+ PCI_ROM( 0x14e4, 0x16ee, "14e4-16EE", "14e4-16EE", 0 ),
2554+ PCI_ROM( 0x14e4, 0x16ef, "14e4-16EF", "14e4-16EF", 0 ),
2555+ PCI_ROM( 0x14e4, 0x16f0, "14e4-16F0", "14e4-16F0", 0 ),
2556+ PCI_ROM( 0x14e4, 0x16f1, "14e4-16F1", "14e4-16F1", 0 ),
2557+ PCI_ROM( 0x14e4, 0x1604, "14e4-1604", "14e4-1604", 0 ),
2558+ PCI_ROM( 0x14e4, 0x1605, "14e4-1605", "14e4-1605", 0 ),
2559+ PCI_ROM( 0x14e4, 0x1606, "14e4-1606", "14e4-1606", 0 ),
2560+ PCI_ROM( 0x14e4, 0x1609, "14e4-1609", "14e4-1609", 0 ),
2561+ PCI_ROM( 0x14e4, 0x1614, "14e4-1614", "14e4-1614", 0 ),
2562+ PCI_ROM( 0x14e4, 0xd802, "14e4-D802", "14e4-D802", 0 ),
2563+ PCI_ROM( 0x14e4, 0xd804, "14e4-D804", "14e4-D804", 0 ),
2564+ PCI_ROM( 0x14e4, 0x1750, "14e4-1750", "14e4-1750", 0 ),
2565+ PCI_ROM( 0x14e4, 0x1802, "14e4-1802", "14e4-1802", 0 ),
2566+ PCI_ROM( 0x14e4, 0x1805, "14e4-1805", "14e4-1805", 0 ),
2567+ PCI_ROM( 0x14e4, 0x1751, "14e4-1751", "14e4-1751", 0 ),
2568+ PCI_ROM( 0x14e4, 0x1801, "14e4-1801", "14e4-1801", 0 ),
2569+ PCI_ROM( 0x14e4, 0x1804, "14e4-1804", "14e4-1804", 0 ),
2570+ PCI_ROM( 0x14e4, 0x1752, "14e4-1752", "14e4-1752", 0 ),
2571+ PCI_ROM( 0x14e4, 0x1800, "14e4-1800", "14e4-1800", 0 ),
2572+ PCI_ROM( 0x14e4, 0x1803, "14e4-1803", "14e4-1803", 0 ),
2573+ PCI_ROM( 0x14e4, 0x1806, "14e4-1806", "14e4-1806", BNXT_FLAG_PCI_VF ),
2574+ PCI_ROM( 0x14e4, 0x1807, "14e4-1807", "14e4-1807", BNXT_FLAG_PCI_VF ),
2575+ PCI_ROM( 0x14e4, 0x1808, "14e4-1808", "14e4-1808", BNXT_FLAG_PCI_VF ),
2576+ PCI_ROM( 0x14e4, 0x1809, "14e4-1809", "14e4-1809", BNXT_FLAG_PCI_VF ),
2577+};
2578+
2579 /**
2580 * Check if Virtual Function
2581 */
2582 u8 bnxt_is_pci_vf ( struct pci_device *pdev )
2583 {
2584- u16 i;
2585-
2586- for ( i = 0; i < ARRAY_SIZE ( bnxt_vf_nics ); i++ ) {
2587- if ( pdev->device == bnxt_vf_nics[i] )
2588- return 1;
2589+ if ( FLAG_TEST ( pdev->id->driver_data, BNXT_FLAG_PCI_VF ) ) {
2590+ return 1;
2591 }
2592 return 0;
2593 }
2594diff --git a/src/drivers/net/bnxt/bnxt.h b/src/drivers/net/bnxt/bnxt.h
2595index 4cca07b..2cbaec5 100644
2596--- a/src/drivers/net/bnxt/bnxt.h
2597+++ b/src/drivers/net/bnxt/bnxt.h
2598@@ -51,6 +51,7 @@ union dma_addr64_t {
2599 #define BNXT_FLAG_MULTI_HOST 0x0008
2600 #define BNXT_FLAG_NPAR_MODE 0x0010
2601 #define BNXT_FLAG_ATOMICS_ENABLE 0x0020
2602+#define BNXT_FLAG_PCI_VF 0x0040
2603 /*******************************************************************************
2604 * Status codes.
2605 ******************************************************************************/
2606@@ -867,140 +868,4 @@ struct bnxt {
2607 FUNC_VF_CFG_REQ_ENABLES_ASYNC_EVENT_CR | \
2608 FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR)
2609
2610-/* Device ID's */
2611-#define PCI_VID_BCOM 0x14e4
2612 #define CHIP_NUM_57500 0x1750
2613-
2614-#define DID_57508 0x1750
2615-#define DID_57508_MF 0x1802
2616-#define DID_57508_MF_RDMA 0x1805
2617-#define DID_57504 0x1751
2618-#define DID_57504_MF 0x1801
2619-#define DID_57504_MF_RDMA 0x1804
2620-#define DID_57502 0x1752
2621-#define DID_57502_MF 0x1800
2622-#define DID_57502_MF_RDMA 0x1803
2623-#define DID_57508_VF 0x1806
2624-#define DID_57508_VF_RDMA 0x1807
2625-#define DID_57508_VF_HV 0x1806
2626-#define DID_57508_VF_RDMA_HV 0x1807
2627-/* Stratus Device IDs */
2628-#define DID_57320_1 0x16F0
2629-#define DID_57320_2 0x16F1
2630-#define DID_57454_MHB 0x1604
2631-#define DID_57454_MHB_RDMA 0x1605
2632-#define DID_57454_VF_RDMA 0x1606
2633-#define DID_57454_VF 0x1609
2634-#define DID_57454 0x1614
2635-#define DID_58802 0xD802
2636-#define DID_58804 0xD804
2637-
2638-#define DID_57417_RDMA_MF 0x16C0
2639-#define DID_57417_VF_RDMA 0x16c1
2640-#define DID_57301 0x16C8
2641-#define DID_57302 0x16C9
2642-#define DID_57304 0x16CA
2643-#define DID_57417_MF 0x16CC
2644-#define DID_58700 0x16CD
2645-#define DID_57311 0x16CE
2646-#define DID_57312 0x16CF
2647-#define DID_57402 0x16D0
2648-#define DID_57404 0x16D1
2649-#define DID_57406 0x16D2
2650-#define DID_57402_MF 0x16D4
2651-#define DID_57407C 0x16D5
2652-#define DID_57412 0x16D6
2653-#define DID_57414 0x16D7
2654-#define DID_57416C 0x16D8
2655-#define DID_57417C 0x16D9
2656-#define DID_57402L 0x16DA
2657-#define DID_57404L 0x16DB
2658-#define DID_57417_VF 0x16dc
2659-#define DID_57412_MF 0x16DE
2660-#define DID_57314 0x16DF
2661-#define DID_57317C 0x16E0
2662-#define DID_57417F 0x16E2
2663-#define DID_57416F 0x16E3
2664-#define DID_57317F 0x16E4
2665-#define DID_57404_MF 0x16E7
2666-#define DID_57406_MF 0x16E8
2667-#define DID_57407F 0x16E9
2668-#define DID_57407_MF 0x16EA
2669-#define DID_57412_RDMA_MF 0x16EB
2670-#define DID_57414_MF 0x16EC
2671-#define DID_57414_RDMA_MF 0x16ED
2672-#define DID_57416_MF 0x16EE
2673-#define DID_57416_RDMA_MF 0x16EF
2674-
2675-static struct pci_device_id bnxt_nics[] = {
2676- PCI_ROM(PCI_VID_BCOM, DID_57417_RDMA_MF, "14e4-16C0", "14e4-16C0", 0),
2677- PCI_ROM(PCI_VID_BCOM, DID_57417_VF_RDMA, "14e4-16C1", "14e4-16C1", 0),
2678- PCI_ROM(PCI_VID_BCOM, DID_57301, "14e4-16C8", "14e4-16C8", 0),
2679- PCI_ROM(PCI_VID_BCOM, DID_57302, "14e4-16C9", "14e4-16C9", 0),
2680- PCI_ROM(PCI_VID_BCOM, DID_57304, "14e4-16CA", "14e4-16CA", 0),
2681- PCI_ROM(PCI_VID_BCOM, DID_57417_MF, "14e4-16CC", "14e4-16CC", 0),
2682- PCI_ROM(PCI_VID_BCOM, DID_58700, "14e4-16CD", "14e4-16CD", 0),
2683- PCI_ROM(PCI_VID_BCOM, DID_57311, "14e4-16CE", "14e4-16CE", 0),
2684- PCI_ROM(PCI_VID_BCOM, DID_57312, "14e4-16CF", "14e4-16CF", 0),
2685- PCI_ROM(PCI_VID_BCOM, DID_57402, "14e4-16D0", "14e4-16D0", 0),
2686- PCI_ROM(PCI_VID_BCOM, DID_57404, "14e4-16D1", "14e4-16D1", 0),
2687- PCI_ROM(PCI_VID_BCOM, DID_57406, "14e4-16D2", "14e4-16D2", 0),
2688- PCI_ROM(PCI_VID_BCOM, DID_57402_MF, "14e4-16D4", "14e4-16D4", 0),
2689- PCI_ROM(PCI_VID_BCOM, DID_57407C, "14e4-16D5", "14e4-16D5", 0),
2690- PCI_ROM(PCI_VID_BCOM, DID_57412, "14e4-16D6", "14e4-16D6", 0),
2691- PCI_ROM(PCI_VID_BCOM, DID_57414, "14e4-16D7", "14e4-16D7", 0),
2692- PCI_ROM(PCI_VID_BCOM, DID_57416C, "14e4-16D8", "14e4-16D8", 0),
2693- PCI_ROM(PCI_VID_BCOM, DID_57417C, "14e4-16D9", "14e4-16D9", 0),
2694- PCI_ROM(PCI_VID_BCOM, DID_57402L, "14e4-16DA", "14e4-16DA", 0),
2695- PCI_ROM(PCI_VID_BCOM, DID_57404L, "14e4-16DB", "14e4-16DB", 0),
2696- PCI_ROM(PCI_VID_BCOM, DID_57417_VF, "14e4-16DC", "14e4-16DC", 0),
2697- PCI_ROM(PCI_VID_BCOM, DID_57412_MF, "14e4-16DE", "14e4-16DE", 0),
2698- PCI_ROM(PCI_VID_BCOM, DID_57314, "14e4-16DF", "14e4-16DF", 0),
2699- PCI_ROM(PCI_VID_BCOM, DID_57317C, "14e4-16E0", "14e4-16E0", 0),
2700- PCI_ROM(PCI_VID_BCOM, DID_57417F, "14e4-16E2", "14e4-16E2", 0),
2701- PCI_ROM(PCI_VID_BCOM, DID_57416F, "14e4-16E3", "14e4-16E3", 0),
2702- PCI_ROM(PCI_VID_BCOM, DID_57317F, "14e4-16E4", "14e4-16E4", 0),
2703- PCI_ROM(PCI_VID_BCOM, DID_57404_MF, "14e4-16E7", "14e4-16E7", 0),
2704- PCI_ROM(PCI_VID_BCOM, DID_57406_MF, "14e4-16E8", "14e4-16E8", 0),
2705- PCI_ROM(PCI_VID_BCOM, DID_57407F, "14e4-16E9", "14e4-16E9", 0),
2706- PCI_ROM(PCI_VID_BCOM, DID_57407_MF, "14e4-16EA", "14e4-16EA", 0),
2707- PCI_ROM(PCI_VID_BCOM, DID_57412_RDMA_MF, "14e4-16EB", "14e4-16EB", 0),
2708- PCI_ROM(PCI_VID_BCOM, DID_57414_MF, "14e4-16EC", "14e4-16EC", 0),
2709- PCI_ROM(PCI_VID_BCOM, DID_57414_RDMA_MF, "14e4-16ED", "14e4-16ED", 0),
2710- PCI_ROM(PCI_VID_BCOM, DID_57416_MF, "14e4-16EE", "14e4-16EE", 0),
2711- PCI_ROM(PCI_VID_BCOM, DID_57416_RDMA_MF, "14e4-16EF", "14e4-16EF", 0),
2712-
2713- PCI_ROM(PCI_VID_BCOM, DID_57320_1, "14e4-16F0", "14e4-16F0", 0),
2714- PCI_ROM(PCI_VID_BCOM, DID_57320_2, "14e4-16F1", "14e4-16F1", 0),
2715- PCI_ROM(PCI_VID_BCOM, DID_57454_MHB, "14e4-1604", "14e4-1604", 0),
2716- PCI_ROM(PCI_VID_BCOM, DID_57454_MHB_RDMA, "14e4-1605", "14e4-1605", 0),
2717- PCI_ROM(PCI_VID_BCOM, DID_57454_VF_RDMA, "14e4-1606", "14e4-1606", 0),
2718- PCI_ROM(PCI_VID_BCOM, DID_57454_VF, "14e4-1609", "14e4-1609", 0),
2719- PCI_ROM(PCI_VID_BCOM, DID_57454, "14e4-1614", "14e4-1614", 0),
2720- PCI_ROM(PCI_VID_BCOM, DID_58802, "14e4-D802", "14e4-D802", 0),
2721- PCI_ROM(PCI_VID_BCOM, DID_58804, "14e4-D804", "14e4-D804", 0),
2722-
2723- PCI_ROM(PCI_VID_BCOM, DID_57508, "14e4-1750", "14e4-1750", 0),
2724- PCI_ROM(PCI_VID_BCOM, DID_57508_MF, "14e4-1802", "14e4-1802", 0),
2725- PCI_ROM(PCI_VID_BCOM, DID_57508_MF_RDMA, "14e4-1805", "14e4-1805", 0),
2726- PCI_ROM(PCI_VID_BCOM, DID_57504, "14e4-1751", "14e4-1751", 0),
2727- PCI_ROM(PCI_VID_BCOM, DID_57504_MF, "14e4-1801", "14e4-1801", 0),
2728- PCI_ROM(PCI_VID_BCOM, DID_57504_MF_RDMA, "14e4-1804", "14e4-1804", 0),
2729- PCI_ROM(PCI_VID_BCOM, DID_57502, "14e4-1752", "14e4-1752", 0),
2730- PCI_ROM(PCI_VID_BCOM, DID_57502_MF, "14e4-1800", "14e4-1800", 0),
2731- PCI_ROM(PCI_VID_BCOM, DID_57502_MF_RDMA, "14e4-1803", "14e4-1803", 0),
2732- PCI_ROM(PCI_VID_BCOM, DID_57508_VF, "14e4-1806", "14e4-1806", 0),
2733- PCI_ROM(PCI_VID_BCOM, DID_57508_VF_RDMA, "14e4-1807", "14e4-1807", 0),
2734- PCI_ROM(PCI_VID_BCOM, DID_57508_VF_HV, "14e4-1808", "14e4-1808", 0),
2735- PCI_ROM(PCI_VID_BCOM,
2736- DID_57508_VF_RDMA_HV, "14e4-1809", "14e4-1809", 0),
2737-};
2738-
2739-static u16 bnxt_vf_nics[] = {
2740- DID_57508_VF,
2741- DID_57508_VF_RDMA,
2742- DID_57508_VF_HV,
2743- DID_57508_VF_RDMA_HV,
2744- DID_57417_VF,
2745- DID_57417_VF_RDMA,
2746-};
2747diff --git a/src/drivers/net/ecm.c b/src/drivers/net/ecm.c
2748index 847a45b..826b3b1 100644
2749--- a/src/drivers/net/ecm.c
2750+++ b/src/drivers/net/ecm.c
2751@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
2752 #include <ipxe/if_ether.h>
2753 #include <ipxe/base16.h>
2754 #include <ipxe/profile.h>
2755+#include <ipxe/acpimac.h>
2756 #include <ipxe/usb.h>
2757 #include "ecm.h"
2758
2759@@ -81,17 +82,26 @@ ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
2760 /**
2761 * Get hardware MAC address
2762 *
2763- * @v usb USB device
2764+ * @v func USB function
2765 * @v desc Ethernet functional descriptor
2766 * @v hw_addr Hardware address to fill in
2767 * @ret rc Return status code
2768 */
2769-int ecm_fetch_mac ( struct usb_device *usb,
2770+int ecm_fetch_mac ( struct usb_function *func,
2771 struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
2772+ struct usb_device *usb = func->usb;
2773 char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
2774 int len;
2775 int rc;
2776
2777+ /* Use system-specific MAC address, if present and not already used */
2778+ if ( ( ( rc = acpi_mac ( hw_addr ) ) == 0 ) &&
2779+ ! find_netdev_by_ll_addr ( &ethernet_protocol, hw_addr ) ) {
2780+ DBGC ( usb, "USB %s using system-specific MAC %s\n",
2781+ func->name, eth_ntoa ( hw_addr ) );
2782+ return 0;
2783+ }
2784+
2785 /* Fetch MAC address string */
2786 len = usb_get_string_descriptor ( usb, desc->mac, 0, buf,
2787 sizeof ( buf ) );
2788@@ -103,7 +113,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
2789 /* Sanity check */
2790 if ( len != ( ( int ) ( sizeof ( buf ) - 1 /* NUL */ ) ) ) {
2791 DBGC ( usb, "USB %s has invalid ECM MAC \"%s\"\n",
2792- usb->name, buf );
2793+ func->name, buf );
2794 return -EINVAL;
2795 }
2796
2797@@ -112,7 +122,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
2798 if ( len < 0 ) {
2799 rc = len;
2800 DBGC ( usb, "USB %s could not decode ECM MAC \"%s\": %s\n",
2801- usb->name, buf, strerror ( rc ) );
2802+ func->name, buf, strerror ( rc ) );
2803 return rc;
2804 }
2805
2806@@ -464,7 +474,7 @@ static int ecm_probe ( struct usb_function *func,
2807 }
2808
2809 /* Fetch MAC address */
2810- if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
2811+ if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
2812 DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
2813 ecm, strerror ( rc ) );
2814 goto err_fetch_mac;
2815diff --git a/src/drivers/net/ecm.h b/src/drivers/net/ecm.h
2816index 83d324b..0ad3ddb 100644
2817--- a/src/drivers/net/ecm.h
2818+++ b/src/drivers/net/ecm.h
2819@@ -86,7 +86,7 @@ struct ecm_device {
2820 extern struct ecm_ethernet_descriptor *
2821 ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
2822 struct usb_interface_descriptor *interface );
2823-extern int ecm_fetch_mac ( struct usb_device *usb,
2824+extern int ecm_fetch_mac ( struct usb_function *func,
2825 struct ecm_ethernet_descriptor *desc,
2826 uint8_t *hw_addr );
2827
2828diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c
2829index b9f3465..833462e 100644
2830--- a/src/drivers/net/efi/nii.c
2831+++ b/src/drivers/net/efi/nii.c
2832@@ -576,7 +576,7 @@ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb,
2833 cdb.IFnum = nii->nii->IfNum;
2834
2835 /* Raise task priority level */
2836- tpl = bs->RaiseTPL ( TPL_CALLBACK );
2837+ tpl = bs->RaiseTPL ( efi_internal_tpl );
2838
2839 /* Issue command */
2840 DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n",
2841diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c
2842index fb52402..69ec6f5 100644
2843--- a/src/drivers/net/efi/snpnet.c
2844+++ b/src/drivers/net/efi/snpnet.c
2845@@ -164,6 +164,10 @@ static int snpnet_transmit ( struct net_device *netdev,
2846 EFI_STATUS efirc;
2847 int rc;
2848
2849+ /* Do nothing if shutdown is in progress */
2850+ if ( efi_shutdown_in_progress )
2851+ return -ECANCELED;
2852+
2853 /* Defer the packet if there is already a transmission in progress */
2854 if ( snp->txbuf ) {
2855 netdev_tx_defer ( netdev, iobuf );
2856@@ -283,6 +287,10 @@ static void snpnet_poll_rx ( struct net_device *netdev ) {
2857 */
2858 static void snpnet_poll ( struct net_device *netdev ) {
2859
2860+ /* Do nothing if shutdown is in progress */
2861+ if ( efi_shutdown_in_progress )
2862+ return;
2863+
2864 /* Process any TX completions */
2865 snpnet_poll_tx ( netdev );
2866
2867@@ -426,8 +434,9 @@ static void snpnet_close ( struct net_device *netdev ) {
2868 EFI_STATUS efirc;
2869 int rc;
2870
2871- /* Shut down NIC */
2872- if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) {
2873+ /* Shut down NIC (unless whole system shutdown is in progress) */
2874+ if ( ( ! efi_shutdown_in_progress ) &&
2875+ ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
2876 rc = -EEFI ( efirc );
2877 DBGC ( snp, "SNP %s could not shut down: %s\n",
2878 netdev->name, strerror ( rc ) );
2879@@ -589,8 +598,9 @@ void snpnet_stop ( struct efi_device *efidev ) {
2880 /* Unregister network device */
2881 unregister_netdev ( netdev );
2882
2883- /* Stop SNP protocol */
2884- if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) {
2885+ /* Stop SNP protocol (unless whole system shutdown is in progress) */
2886+ if ( ( ! efi_shutdown_in_progress ) &&
2887+ ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) {
2888 rc = -EEFI ( efirc );
2889 DBGC ( device, "SNP %s could not stop: %s\n",
2890 efi_handle_name ( device ), strerror ( rc ) );
2891diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c
2892index 8349296..ea3ebf6 100644
2893--- a/src/drivers/net/intel.c
2894+++ b/src/drivers/net/intel.c
2895@@ -1025,6 +1025,12 @@ static struct pci_device_id intel_nics[] = {
2896 PCI_ROM ( 0x8086, 0x043a, "dh8900cc-f", "DH8900CC Fiber", 0 ),
2897 PCI_ROM ( 0x8086, 0x043c, "dh8900cc-b", "DH8900CC Backplane", 0 ),
2898 PCI_ROM ( 0x8086, 0x0440, "dh8900cc-s", "DH8900CC SFP", 0 ),
2899+ PCI_ROM ( 0x8086, 0x0d4c, "i219lm-11", "I219-LM (11)", INTEL_I219 ),
2900+ PCI_ROM ( 0x8086, 0x0d4d, "i219v-11", "I219-V (11)", INTEL_I219 ),
2901+ PCI_ROM ( 0x8086, 0x0d4e, "i219lm-10", "I219-LM (10)", INTEL_I219 ),
2902+ PCI_ROM ( 0x8086, 0x0d4f, "i219v-10", "I219-V (10)", INTEL_I219 ),
2903+ PCI_ROM ( 0x8086, 0x0d53, "i219lm-12", "I219-LM (12)", INTEL_I219 ),
2904+ PCI_ROM ( 0x8086, 0x0d55, "i219v-12", "I219-V (12)", INTEL_I219 ),
2905 PCI_ROM ( 0x8086, 0x1000, "82542-f", "82542 (Fiber)", 0 ),
2906 PCI_ROM ( 0x8086, 0x1001, "82543gc-f", "82543GC (Fiber)", 0 ),
2907 PCI_ROM ( 0x8086, 0x1004, "82543gc", "82543GC (Copper)", 0 ),
2908@@ -1161,6 +1167,12 @@ static struct pci_device_id intel_nics[] = {
2909 PCI_ROM ( 0x8086, 0x15e1, "i219lm-9", "I219-LM (9)", INTEL_I219 ),
2910 PCI_ROM ( 0x8086, 0x15e2, "i219v-9", "I219-V (9)", INTEL_I219 ),
2911 PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_I219 ),
2912+ PCI_ROM ( 0x8086, 0x15f4, "i219lm-15", "I219-LM (15)", INTEL_I219 ),
2913+ PCI_ROM ( 0x8086, 0x15f5, "i219v-15", "I219-V (15)", INTEL_I219 ),
2914+ PCI_ROM ( 0x8086, 0x15f9, "i219lm-14", "I219-LM (14)", INTEL_I219 ),
2915+ PCI_ROM ( 0x8086, 0x15fa, "i219v-14", "I219-V (14)", INTEL_I219 ),
2916+ PCI_ROM ( 0x8086, 0x15fb, "i219lm-13", "I219-LM (13)", INTEL_I219 ),
2917+ PCI_ROM ( 0x8086, 0x15fc, "i219v-13", "I219-V (13)", INTEL_I219 ),
2918 PCI_ROM ( 0x8086, 0x1f41, "i354", "I354", INTEL_NO_ASDE ),
2919 PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
2920 PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
2921diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c
2922index ccf6b06..f4dad88 100644
2923--- a/src/drivers/net/intelx.c
2924+++ b/src/drivers/net/intelx.c
2925@@ -481,6 +481,7 @@ static struct pci_device_id intelx_nics[] = {
2926 PCI_ROM ( 0x8086, 0x15ab, "x552", "X552", 0 ),
2927 PCI_ROM ( 0x8086, 0x15c8, "x553t", "X553/X557-AT", 0 ),
2928 PCI_ROM ( 0x8086, 0x15ce, "x553-sfp", "X553 (SFP+)", 0 ),
2929+ PCI_ROM ( 0x8086, 0x15e4, "x553a", "X553", 0 ),
2930 PCI_ROM ( 0x8086, 0x15e5, "x553", "X553", 0 ),
2931 };
2932
2933diff --git a/src/drivers/net/ncm.c b/src/drivers/net/ncm.c
2934index cc07a43..1e8088d 100644
2935--- a/src/drivers/net/ncm.c
2936+++ b/src/drivers/net/ncm.c
2937@@ -598,7 +598,7 @@ static int ncm_probe ( struct usb_function *func,
2938 }
2939
2940 /* Fetch MAC address */
2941- if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
2942+ if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
2943 DBGC ( ncm, "NCM %p could not fetch MAC address: %s\n",
2944 ncm, strerror ( rc ) );
2945 goto err_fetch_mac;
2946diff --git a/src/drivers/net/rdc.c b/src/drivers/net/rdc.c
2947new file mode 100644
2948index 0000000..c3239c0
2949--- /dev/null
2950+++ b/src/drivers/net/rdc.c
2951@@ -0,0 +1,694 @@
2952+/*
2953+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
2954+ *
2955+ * This program is free software; you can redistribute it and/or
2956+ * modify it under the terms of the GNU General Public License as
2957+ * published by the Free Software Foundation; either version 2 of the
2958+ * License, or (at your option) any later version.
2959+ *
2960+ * This program is distributed in the hope that it will be useful, but
2961+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2962+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2963+ * General Public License for more details.
2964+ *
2965+ * You should have received a copy of the GNU General Public License
2966+ * along with this program; if not, write to the Free Software
2967+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2968+ * 02110-1301, USA.
2969+ *
2970+ * You can also choose to distribute this program under the terms of
2971+ * the Unmodified Binary Distribution Licence (as given in the file
2972+ * COPYING.UBDL), provided that you have satisfied its requirements.
2973+ */
2974+
2975+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
2976+
2977+#include <stdint.h>
2978+#include <string.h>
2979+#include <unistd.h>
2980+#include <errno.h>
2981+#include <byteswap.h>
2982+#include <ipxe/netdevice.h>
2983+#include <ipxe/ethernet.h>
2984+#include <ipxe/if_ether.h>
2985+#include <ipxe/iobuf.h>
2986+#include <ipxe/malloc.h>
2987+#include <ipxe/pci.h>
2988+#include "rdc.h"
2989+
2990+/** @file
2991+ *
2992+ * RDC R6040 network driver
2993+ *
2994+ */
2995+
2996+/******************************************************************************
2997+ *
2998+ * Device reset
2999+ *
3000+ ******************************************************************************
3001+ */
3002+
3003+/**
3004+ * Reset hardware
3005+ *
3006+ * @v rdc RDC device
3007+ * @ret rc Return status code
3008+ */
3009+static int rdc_reset ( struct rdc_nic *rdc ) {
3010+ unsigned int i;
3011+
3012+ /* Reset NIC */
3013+ writew ( RDC_MCR1_RST, rdc->regs + RDC_MCR1 );
3014+
3015+ /* Wait for reset to complete */
3016+ for ( i = 0 ; i < RDC_RESET_MAX_WAIT_MS ; i++ ) {
3017+
3018+ /* Check for reset completion */
3019+ if ( readw ( rdc->regs + RDC_MCR1 ) & RDC_MCR1_RST ) {
3020+ mdelay ( 1 );
3021+ continue;
3022+ }
3023+
3024+ /* Reset internal state machine */
3025+ writew ( RDC_MACSM_RST, rdc->regs + RDC_MACSM );
3026+ writew ( 0, rdc->regs + RDC_MACSM );
3027+ mdelay ( RDC_MACSM_RESET_DELAY_MS );
3028+
3029+ return 0;
3030+ }
3031+
3032+ DBGC ( rdc, "RDC %p timed out waiting for reset\n", rdc );
3033+ return -ETIMEDOUT;
3034+}
3035+
3036+/******************************************************************************
3037+ *
3038+ * MII interface
3039+ *
3040+ ******************************************************************************
3041+ */
3042+
3043+/**
3044+ * Read from MII register
3045+ *
3046+ * @v mdio MII interface
3047+ * @v phy PHY address
3048+ * @v reg Register address
3049+ * @ret value Data read, or negative error
3050+ */
3051+static int rdc_mii_read ( struct mii_interface *mdio, unsigned int phy,
3052+ unsigned int reg ) {
3053+ struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
3054+ uint16_t mmdio;
3055+ unsigned int i;
3056+
3057+ /* Initiate read */
3058+ mmdio = ( RDC_MMDIO_MIIRD | RDC_MMDIO_PHYAD ( phy ) |
3059+ RDC_MMDIO_REGAD ( reg ) );
3060+ writew ( mmdio, rdc->regs + RDC_MMDIO );
3061+
3062+ /* Wait for read to complete */
3063+ for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
3064+
3065+ /* Check for read completion */
3066+ if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIRD ) {
3067+ udelay ( 1 );
3068+ continue;
3069+ }
3070+
3071+ /* Return register value */
3072+ return ( readw ( rdc->regs + RDC_MMRD ) );
3073+ }
3074+
3075+ DBGC ( rdc, "RDC %p timed out waiting for MII read\n", rdc );
3076+ return -ETIMEDOUT;
3077+}
3078+
3079+/**
3080+ * Write to MII register
3081+ *
3082+ * @v mdio MII interface
3083+ * @v phy PHY address
3084+ * @v reg Register address
3085+ * @v data Data to write
3086+ * @ret rc Return status code
3087+ */
3088+static int rdc_mii_write ( struct mii_interface *mdio, unsigned int phy,
3089+ unsigned int reg, unsigned int data ) {
3090+ struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
3091+ uint16_t mmdio;
3092+ unsigned int i;
3093+
3094+ /* Initiate write */
3095+ mmdio = ( RDC_MMDIO_MIIWR | RDC_MMDIO_PHYAD ( phy ) |
3096+ RDC_MMDIO_REGAD ( reg ) );
3097+ writew ( data, rdc->regs + RDC_MMWD );
3098+ writew ( mmdio, rdc->regs + RDC_MMDIO );
3099+
3100+ /* Wait for write to complete */
3101+ for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
3102+
3103+ /* Check for write completion */
3104+ if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIWR ) {
3105+ udelay ( 1 );
3106+ continue;
3107+ }
3108+
3109+ return 0;
3110+ }
3111+
3112+ DBGC ( rdc, "RDC %p timed out waiting for MII write\n", rdc );
3113+ return -ETIMEDOUT;
3114+}
3115+
3116+/** RDC MII operations */
3117+static struct mii_operations rdc_mii_operations = {
3118+ .read = rdc_mii_read,
3119+ .write = rdc_mii_write,
3120+};
3121+
3122+/******************************************************************************
3123+ *
3124+ * Link state
3125+ *
3126+ ******************************************************************************
3127+ */
3128+
3129+/**
3130+ * Initialise PHY
3131+ *
3132+ * @v rdc RDC device
3133+ * @ret rc Return status code
3134+ */
3135+static int rdc_init_phy ( struct rdc_nic *rdc ) {
3136+ int rc;
3137+
3138+ /* Find PHY address */
3139+ if ( ( rc = mii_find ( &rdc->mii ) ) != 0 ) {
3140+ DBGC ( rdc, "RDC %p could not find PHY address: %s\n",
3141+ rdc, strerror ( rc ) );
3142+ return rc;
3143+ }
3144+
3145+ /* Reset PHY */
3146+ if ( ( rc = mii_reset ( &rdc->mii ) ) != 0 ) {
3147+ DBGC ( rdc, "RDC %p could not reset PHY: %s\n",
3148+ rdc, strerror ( rc ) );
3149+ return rc;
3150+ }
3151+
3152+ return 0;
3153+}
3154+
3155+/**
3156+ * Check link state
3157+ *
3158+ * @v netdev Network device
3159+ * @ret rc Return status code
3160+ */
3161+static int rdc_check_link ( struct net_device *netdev ) {
3162+ struct rdc_nic *rdc = netdev->priv;
3163+ int rc;
3164+
3165+ /* Check link state */
3166+ if ( ( rc = mii_check_link ( &rdc->mii, netdev ) ) != 0 ) {
3167+ DBGC ( rdc, "RDC %p could not check link: %s\n",
3168+ rdc, strerror ( rc ) );
3169+ return rc;
3170+ }
3171+
3172+ return 0;
3173+}
3174+
3175+/******************************************************************************
3176+ *
3177+ * Network device interface
3178+ *
3179+ ******************************************************************************
3180+ */
3181+
3182+/**
3183+ * Create descriptor ring
3184+ *
3185+ * @v rdc RDC device
3186+ * @v ring Descriptor ring
3187+ * @ret rc Return status code
3188+ */
3189+static int rdc_create_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
3190+ size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
3191+ struct rdc_descriptor *desc;
3192+ struct rdc_descriptor *next;
3193+ physaddr_t start;
3194+ unsigned int i;
3195+
3196+ /* Allocate descriptor ring */
3197+ ring->desc = dma_alloc ( rdc->dma, &ring->map, len, len );
3198+ if ( ! ring->desc )
3199+ return -ENOMEM;
3200+
3201+ /* Initialise descriptor ring */
3202+ memset ( ring->desc, 0, len );
3203+ for ( i = 0 ; i < ring->count ; i++ ) {
3204+ desc = &ring->desc[i];
3205+ next = &ring->desc[ ( i + 1 ) & ( ring->count - 1 ) ];
3206+ desc->next = cpu_to_le32 ( dma ( &ring->map, next ) );
3207+ }
3208+
3209+ /* Program ring address */
3210+ start = dma ( &ring->map, ring->desc );
3211+ writew ( ( start >> 0 ), ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
3212+ writew ( ( start >> 16 ), ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
3213+
3214+ DBGC ( rdc, "RDC %p ring %#02x is at [%08lx,%08lx)\n",
3215+ rdc, ring->reg, virt_to_phys ( ring->desc ),
3216+ ( virt_to_phys ( ring->desc ) + len ) );
3217+ return 0;
3218+}
3219+
3220+/**
3221+ * Destroy descriptor ring
3222+ *
3223+ * @v rdc RDC device
3224+ * @v ring Descriptor ring
3225+ */
3226+static void rdc_destroy_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
3227+ size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
3228+
3229+ /* Clear ring address */
3230+ writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
3231+ writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
3232+
3233+ /* Free descriptors */
3234+ dma_free ( &ring->map, ring->desc, len );
3235+ ring->desc = NULL;
3236+
3237+ /* Reset ring */
3238+ ring->prod = 0;
3239+ ring->cons = 0;
3240+}
3241+
3242+/**
3243+ * Refill receive descriptor ring
3244+ *
3245+ * @v rdc RDC device
3246+ */
3247+static void rdc_refill_rx ( struct rdc_nic *rdc ) {
3248+ struct rdc_descriptor *rx;
3249+ struct io_buffer *iobuf;
3250+ unsigned int rx_idx;
3251+
3252+ /* Refill ring */
3253+ while ( ( rdc->rx.prod - rdc->rx.cons ) < RDC_NUM_RX_DESC ) {
3254+
3255+ /* Allocate I/O buffer */
3256+ iobuf = alloc_rx_iob ( RDC_RX_MAX_LEN, rdc->dma );
3257+ if ( ! iobuf ) {
3258+ /* Wait for next refill */
3259+ break;
3260+ }
3261+
3262+ /* Get next receive descriptor */
3263+ rx_idx = ( rdc->rx.prod++ % RDC_NUM_RX_DESC );
3264+ rx = &rdc->rx.desc[rx_idx];
3265+
3266+ /* Populate receive descriptor */
3267+ rx->len = cpu_to_le16 ( RDC_RX_MAX_LEN );
3268+ rx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
3269+ wmb();
3270+ rx->flags = cpu_to_le16 ( RDC_FL_OWNED );
3271+
3272+ /* Record I/O buffer */
3273+ assert ( rdc->rx_iobuf[rx_idx] == NULL );
3274+ rdc->rx_iobuf[rx_idx] = iobuf;
3275+
3276+ DBGC2 ( rdc, "RDC %p RX %d is [%lx,%lx)\n",
3277+ rdc, rx_idx, virt_to_phys ( iobuf->data ),
3278+ ( virt_to_phys ( iobuf->data ) + RDC_RX_MAX_LEN ) );
3279+ }
3280+}
3281+
3282+/**
3283+ * Open network device
3284+ *
3285+ * @v netdev Network device
3286+ * @ret rc Return status code
3287+ */
3288+static int rdc_open ( struct net_device *netdev ) {
3289+ struct rdc_nic *rdc = netdev->priv;
3290+ int rc;
3291+
3292+ /* Create transmit descriptor ring */
3293+ if ( ( rc = rdc_create_ring ( rdc, &rdc->tx ) ) != 0 )
3294+ goto err_create_tx;
3295+
3296+ /* Create receive descriptor ring */
3297+ if ( ( rc = rdc_create_ring ( rdc, &rdc->rx ) ) != 0 )
3298+ goto err_create_rx;
3299+
3300+ /* Program receive buffer length */
3301+ writew ( RDC_RX_MAX_LEN, rdc->regs + RDC_MRBSR );
3302+
3303+ /* Enable transmit and receive */
3304+ writew ( ( RDC_MCR0_FD | RDC_MCR0_TXEN | RDC_MCR0_PROMISC |
3305+ RDC_MCR0_RXEN ),
3306+ rdc->regs + RDC_MCR0 );
3307+
3308+ /* Enable PHY status polling */
3309+ writew ( ( RDC_MPSCCR_EN | RDC_MPSCCR_PHYAD ( rdc->mii.address ) |
3310+ RDC_MPSCCR_SLOW ),
3311+ rdc->regs + RDC_MPSCCR );
3312+
3313+ /* Fill receive ring */
3314+ rdc_refill_rx ( rdc );
3315+
3316+ /* Update link state */
3317+ rdc_check_link ( netdev );
3318+
3319+ return 0;
3320+
3321+ rdc_destroy_ring ( rdc, &rdc->rx );
3322+ err_create_rx:
3323+ rdc_destroy_ring ( rdc, &rdc->tx );
3324+ err_create_tx:
3325+ return rc;
3326+}
3327+
3328+/**
3329+ * Close network device
3330+ *
3331+ * @v netdev Network device
3332+ */
3333+static void rdc_close ( struct net_device *netdev ) {
3334+ struct rdc_nic *rdc = netdev->priv;
3335+ unsigned int i;
3336+
3337+ /* Disable NIC */
3338+ writew ( 0, rdc->regs + RDC_MCR0 );
3339+
3340+ /* Destroy receive descriptor ring */
3341+ rdc_destroy_ring ( rdc, &rdc->rx );
3342+
3343+ /* Discard any unused receive buffers */
3344+ for ( i = 0 ; i < RDC_NUM_RX_DESC ; i++ ) {
3345+ if ( rdc->rx_iobuf[i] )
3346+ free_rx_iob ( rdc->rx_iobuf[i] );
3347+ rdc->rx_iobuf[i] = NULL;
3348+ }
3349+
3350+ /* Destroy transmit descriptor ring */
3351+ rdc_destroy_ring ( rdc, &rdc->tx );
3352+}
3353+
3354+/**
3355+ * Transmit packet
3356+ *
3357+ * @v netdev Network device
3358+ * @v iobuf I/O buffer
3359+ * @ret rc Return status code
3360+ */
3361+static int rdc_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
3362+ struct rdc_nic *rdc = netdev->priv;
3363+ struct rdc_descriptor *tx;
3364+ unsigned int tx_idx;
3365+ int rc;
3366+
3367+ /* Get next transmit descriptor */
3368+ if ( ( rdc->tx.prod - rdc->tx.cons ) >= RDC_NUM_TX_DESC ) {
3369+ DBGC ( rdc, "RDC %p out of transmit descriptors\n", rdc );
3370+ return -ENOBUFS;
3371+ }
3372+ tx_idx = ( rdc->tx.prod % RDC_NUM_TX_DESC );
3373+ tx = &rdc->tx.desc[tx_idx];
3374+
3375+ /* Pad to minimum length */
3376+ iob_pad ( iobuf, ETH_ZLEN );
3377+
3378+ /* Map I/O buffer */
3379+ if ( ( rc = iob_map_tx ( iobuf, rdc->dma ) ) != 0 )
3380+ return rc;
3381+
3382+ /* Update producer index */
3383+ rdc->tx.prod++;
3384+
3385+ /* Populate transmit descriptor */
3386+ tx->len = cpu_to_le16 ( iob_len ( iobuf ) );
3387+ tx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
3388+ wmb();
3389+ tx->flags = cpu_to_le16 ( RDC_FL_OWNED );
3390+ wmb();
3391+
3392+ /* Notify card that there are packets ready to transmit */
3393+ writew ( RDC_MTPR_TM2TX, rdc->regs + RDC_MTPR );
3394+
3395+ return 0;
3396+}
3397+
3398+/**
3399+ * Poll for completed packets
3400+ *
3401+ * @v netdev Network device
3402+ */
3403+static void rdc_poll_tx ( struct net_device *netdev ) {
3404+ struct rdc_nic *rdc = netdev->priv;
3405+ struct rdc_descriptor *tx;
3406+ unsigned int tx_idx;
3407+
3408+ /* Check for completed packets */
3409+ while ( rdc->tx.cons != rdc->tx.prod ) {
3410+
3411+ /* Get next transmit descriptor */
3412+ tx_idx = ( rdc->tx.cons % RDC_NUM_TX_DESC );
3413+ tx = &rdc->tx.desc[tx_idx];
3414+
3415+ /* Stop if descriptor is still in use */
3416+ if ( tx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
3417+ return;
3418+ DBGC2 ( rdc, "RDC %p TX %d complete\n", rdc, tx_idx );
3419+
3420+ /* Complete transmit descriptor */
3421+ rdc->tx.cons++;
3422+ netdev_tx_complete_next ( netdev );
3423+ }
3424+}
3425+
3426+/**
3427+ * Poll for received packets
3428+ *
3429+ * @v netdev Network device
3430+ */
3431+static void rdc_poll_rx ( struct net_device *netdev ) {
3432+ struct rdc_nic *rdc = netdev->priv;
3433+ struct rdc_descriptor *rx;
3434+ struct io_buffer *iobuf;
3435+ unsigned int rx_idx;
3436+ size_t len;
3437+
3438+ /* Check for received packets */
3439+ while ( rdc->rx.cons != rdc->rx.prod ) {
3440+
3441+ /* Get next receive descriptor */
3442+ rx_idx = ( rdc->rx.cons % RDC_NUM_RX_DESC );
3443+ rx = &rdc->rx.desc[rx_idx];
3444+
3445+ /* Stop if descriptor is still in use */
3446+ if ( rx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
3447+ return;
3448+
3449+ /* Populate I/O buffer */
3450+ iobuf = rdc->rx_iobuf[rx_idx];
3451+ rdc->rx_iobuf[rx_idx] = NULL;
3452+ len = le16_to_cpu ( rx->len );
3453+ iob_put ( iobuf, len );
3454+ iob_unput ( iobuf, 4 /* strip CRC */ );
3455+
3456+ /* Hand off to network stack */
3457+ if ( rx->flags & cpu_to_le16 ( RDC_FL_OK ) ) {
3458+ DBGC2 ( rdc, "RDC %p RX %d complete (length %zd)\n",
3459+ rdc, rx_idx, len );
3460+ netdev_rx ( netdev, iobuf );
3461+ } else {
3462+ DBGC2 ( rdc, "RDC %p RX %d error (length %zd, "
3463+ "flags %#04x)\n", rdc, rx_idx, len,
3464+ le16_to_cpu ( rx->flags ) );
3465+ netdev_rx_err ( netdev, iobuf, -EIO );
3466+ }
3467+ rdc->rx.cons++;
3468+ }
3469+}
3470+
3471+/**
3472+ * Poll for completed and received packets
3473+ *
3474+ * @v netdev Network device
3475+ */
3476+static void rdc_poll ( struct net_device *netdev ) {
3477+ struct rdc_nic *rdc = netdev->priv;
3478+ uint16_t misr;
3479+
3480+ /* Check for (and acknowledge) interrupts */
3481+ misr = readw ( rdc->regs + RDC_MISR );
3482+
3483+ /* Poll for TX completions, if applicable */
3484+ if ( misr & RDC_MIRQ_TX )
3485+ rdc_poll_tx ( netdev );
3486+
3487+ /* Poll for RX completions, if applicable */
3488+ if ( misr & RDC_MIRQ_RX )
3489+ rdc_poll_rx ( netdev );
3490+
3491+ /* Check link state, if applicable */
3492+ if ( misr & RDC_MIRQ_LINK )
3493+ rdc_check_link ( netdev );
3494+
3495+ /* Check for unexpected interrupts */
3496+ if ( misr & ~( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX_EARLY |
3497+ RDC_MIRQ_RX_EMPTY | RDC_MIRQ_RX ) ) {
3498+ DBGC ( rdc, "RDC %p unexpected MISR %#04x\n", rdc, misr );
3499+ /* Report as a TX error */
3500+ netdev_tx_err ( netdev, NULL, -ENOTSUP );
3501+ }
3502+
3503+ /* Refill receive ring */
3504+ rdc_refill_rx ( rdc );
3505+}
3506+
3507+/**
3508+ * Enable or disable interrupts
3509+ *
3510+ * @v netdev Network device
3511+ * @v enable Interrupts should be enabled
3512+ */
3513+static void rdc_irq ( struct net_device *netdev, int enable ) {
3514+ struct rdc_nic *rdc = netdev->priv;
3515+ uint16_t mier;
3516+
3517+ /* Enable/disable interrupts */
3518+ mier = ( enable ? ( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX ) : 0 );
3519+ writew ( mier, rdc->regs + RDC_MIER );
3520+}
3521+
3522+/** RDC network device operations */
3523+static struct net_device_operations rdc_operations = {
3524+ .open = rdc_open,
3525+ .close = rdc_close,
3526+ .transmit = rdc_transmit,
3527+ .poll = rdc_poll,
3528+ .irq = rdc_irq,
3529+};
3530+
3531+/******************************************************************************
3532+ *
3533+ * PCI interface
3534+ *
3535+ ******************************************************************************
3536+ */
3537+
3538+/**
3539+ * Probe PCI device
3540+ *
3541+ * @v pci PCI device
3542+ * @ret rc Return status code
3543+ */
3544+static int rdc_probe ( struct pci_device *pci ) {
3545+ struct net_device *netdev;
3546+ struct rdc_nic *rdc;
3547+ union rdc_mac mac;
3548+ int rc;
3549+
3550+ /* Allocate and initialise net device */
3551+ netdev = alloc_etherdev ( sizeof ( *rdc ) );
3552+ if ( ! netdev ) {
3553+ rc = -ENOMEM;
3554+ goto err_alloc;
3555+ }
3556+ netdev_init ( netdev, &rdc_operations );
3557+ rdc = netdev->priv;
3558+ pci_set_drvdata ( pci, netdev );
3559+ netdev->dev = &pci->dev;
3560+ memset ( rdc, 0, sizeof ( *rdc ) );
3561+ rdc->dma = &pci->dma;
3562+ mdio_init ( &rdc->mdio, &rdc_mii_operations );
3563+ mii_init ( &rdc->mii, &rdc->mdio, 0 );
3564+ rdc_init_ring ( &rdc->tx, RDC_NUM_TX_DESC, RDC_MTDSA );
3565+ rdc_init_ring ( &rdc->rx, RDC_NUM_RX_DESC, RDC_MRDSA );
3566+
3567+ /* Fix up PCI device */
3568+ adjust_pci_device ( pci );
3569+
3570+ /* Map registers */
3571+ rdc->regs = pci_ioremap ( pci, pci->membase, RDC_BAR_SIZE );
3572+ if ( ! rdc->regs ) {
3573+ rc = -ENODEV;
3574+ goto err_ioremap;
3575+ }
3576+
3577+ /* Fetch MAC address */
3578+ mac.mid[0] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID0 ) );
3579+ mac.mid[1] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID1 ) );
3580+ mac.mid[2] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID2 ) );
3581+ memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
3582+
3583+ /* Reset the NIC */
3584+ if ( ( rc = rdc_reset ( rdc ) ) != 0 )
3585+ goto err_reset;
3586+
3587+ /* Initialise PHY */
3588+ if ( ( rc = rdc_init_phy ( rdc ) ) != 0 )
3589+ goto err_init_phy;
3590+
3591+ /* Register network device */
3592+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
3593+ goto err_register_netdev;
3594+
3595+ /* Set initial link state */
3596+ rdc_check_link ( netdev );
3597+
3598+ return 0;
3599+
3600+ unregister_netdev ( netdev );
3601+ err_register_netdev:
3602+ err_init_phy:
3603+ rdc_reset ( rdc );
3604+ err_reset:
3605+ iounmap ( rdc->regs );
3606+ err_ioremap:
3607+ netdev_nullify ( netdev );
3608+ netdev_put ( netdev );
3609+ err_alloc:
3610+ return rc;
3611+}
3612+
3613+/**
3614+ * Remove PCI device
3615+ *
3616+ * @v pci PCI device
3617+ */
3618+static void rdc_remove ( struct pci_device *pci ) {
3619+ struct net_device *netdev = pci_get_drvdata ( pci );
3620+ struct rdc_nic *rdc = netdev->priv;
3621+
3622+ /* Unregister network device */
3623+ unregister_netdev ( netdev );
3624+
3625+ /* Reset card */
3626+ rdc_reset ( rdc );
3627+
3628+ /* Free network device */
3629+ iounmap ( rdc->regs );
3630+ netdev_nullify ( netdev );
3631+ netdev_put ( netdev );
3632+}
3633+
3634+/** RDC PCI device IDs */
3635+static struct pci_device_id rdc_nics[] = {
3636+ PCI_ROM ( 0x17f3, 0x6040, "r6040", "RDC R6040", 0 ),
3637+};
3638+
3639+/** RDC PCI driver */
3640+struct pci_driver rdc_driver __pci_driver = {
3641+ .ids = rdc_nics,
3642+ .id_count = ( sizeof ( rdc_nics ) / sizeof ( rdc_nics[0] ) ),
3643+ .probe = rdc_probe,
3644+ .remove = rdc_remove,
3645+};
3646diff --git a/src/drivers/net/rdc.h b/src/drivers/net/rdc.h
3647new file mode 100644
3648index 0000000..ee1671f
3649--- /dev/null
3650+++ b/src/drivers/net/rdc.h
3651@@ -0,0 +1,194 @@
3652+#ifndef _RDC_H
3653+#define _RDC_H
3654+
3655+/** @file
3656+ *
3657+ * RDC R6040 network driver
3658+ *
3659+ */
3660+
3661+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
3662+
3663+#include <stdint.h>
3664+#include <ipxe/if_ether.h>
3665+#include <ipxe/mii.h>
3666+
3667+/** RDC BAR size */
3668+#define RDC_BAR_SIZE 256
3669+
3670+/** An RDC descriptor */
3671+struct rdc_descriptor {
3672+ /** Flags */
3673+ uint16_t flags;
3674+ /** Length */
3675+ uint16_t len;
3676+ /** Address */
3677+ uint32_t addr;
3678+ /** Next descriptor */
3679+ uint32_t next;
3680+ /** Reserved */
3681+ uint32_t reserved;
3682+} __attribute__ (( packed ));
3683+
3684+/** Descriptor is owned by NIC */
3685+#define RDC_FL_OWNED 0x8000
3686+
3687+/** Packet OK */
3688+#define RDC_FL_OK 0x4000
3689+
3690+/** MAC control register 0 */
3691+#define RDC_MCR0 0x00
3692+#define RDC_MCR0_FD 0x8000 /**< Full duplex */
3693+#define RDC_MCR0_TXEN 0x1000 /**< Transmit enable */
3694+#define RDC_MCR0_PROMISC 0x0020 /**< Promiscuous mode */
3695+#define RDC_MCR0_RXEN 0x0002 /**< Receive enable */
3696+
3697+/** MAC control register 1 */
3698+#define RDC_MCR1 0x04
3699+#define RDC_MCR1_RST 0x0001 /**< MAC reset */
3700+
3701+/** Maximum time to wait for reset */
3702+#define RDC_RESET_MAX_WAIT_MS 10
3703+
3704+/** MAC transmit poll command register */
3705+#define RDC_MTPR 0x14
3706+#define RDC_MTPR_TM2TX 0x0001 /**< Trigger MAC to transmit */
3707+
3708+/** MAC receive buffer size register */
3709+#define RDC_MRBSR 0x18
3710+
3711+/** MAC MDIO control register */
3712+#define RDC_MMDIO 0x20
3713+#define RDC_MMDIO_MIIWR 0x4000 /**< MDIO write */
3714+#define RDC_MMDIO_MIIRD 0x2000 /**< MDIO read */
3715+#define RDC_MMDIO_PHYAD(x) ( (x) << 8 ) /**< PHY address */
3716+#define RDC_MMDIO_REGAD(x) ( (x) << 0 ) /**< Register address */
3717+
3718+/** Maximum time to wait for an MII read or write */
3719+#define RDC_MII_MAX_WAIT_US 2048
3720+
3721+/** MAC MDIO read data register */
3722+#define RDC_MMRD 0x24
3723+
3724+/** MAC MDIO write data register */
3725+#define RDC_MMWD 0x28
3726+
3727+/** MAC transmit descriptor start address */
3728+#define RDC_MTDSA 0x2c
3729+
3730+/** MAC receive descriptor start address */
3731+#define RDC_MRDSA 0x34
3732+
3733+/** MAC descriptor start address low half */
3734+#define RDC_MxDSA_LO 0x0
3735+
3736+/** MAC descriptor start address low half */
3737+#define RDC_MxDSA_HI 0x4
3738+
3739+/** MAC interrupt status register */
3740+#define RDC_MISR 0x3c
3741+#define RDC_MIRQ_LINK 0x0200 /**< Link status changed */
3742+#define RDC_MIRQ_TX 0x0010 /**< Transmit complete */
3743+#define RDC_MIRQ_RX_EARLY 0x0008 /**< Receive early interrupt */
3744+#define RDC_MIRQ_RX_EMPTY 0x0002 /**< Receive descriptor unavailable */
3745+#define RDC_MIRQ_RX 0x0001 /**< Receive complete */
3746+
3747+/** MAC interrupt enable register */
3748+#define RDC_MIER 0x40
3749+
3750+/** MAC address word 0 */
3751+#define RDC_MID0 0x68
3752+
3753+/** MAC address word 1 */
3754+#define RDC_MID1 0x6a
3755+
3756+/** MAC address word 2 */
3757+#define RDC_MID2 0x6c
3758+
3759+/** MAC PHY status change configuration register */
3760+#define RDC_MPSCCR 0x88
3761+#define RDC_MPSCCR_EN 0x8000 /**< PHY status change enable */
3762+#define RDC_MPSCCR_PHYAD(x) ( (x) << 8 ) /**< PHY address */
3763+#define RDC_MPSCCR_SLOW 0x0007 /**< Poll slowly */
3764+
3765+/** MAC state machine register */
3766+#define RDC_MACSM 0xac
3767+#define RDC_MACSM_RST 0x0002 /**< Reset state machine */
3768+
3769+/** Time to wait after resetting MAC state machine */
3770+#define RDC_MACSM_RESET_DELAY_MS 10
3771+
3772+/** A MAC address */
3773+union rdc_mac {
3774+ /** Raw bytes */
3775+ uint8_t raw[ETH_ALEN];
3776+ /** MIDx registers */
3777+ uint16_t mid[ ETH_ALEN / 2 ];
3778+};
3779+
3780+/** A descriptor ring */
3781+struct rdc_ring {
3782+ /** Descriptors */
3783+ struct rdc_descriptor *desc;
3784+ /** Descriptor ring DMA mapping */
3785+ struct dma_mapping map;
3786+ /** Producer index */
3787+ unsigned int prod;
3788+ /** Consumer index */
3789+ unsigned int cons;
3790+
3791+ /** Number of descriptors */
3792+ unsigned int count;
3793+ /** Start address register 0 */
3794+ unsigned int reg;
3795+};
3796+
3797+/**
3798+ * Initialise descriptor ring
3799+ *
3800+ * @v ring Descriptor ring
3801+ * @v count Number of descriptors
3802+ * @v reg Start address register 0
3803+ */
3804+static inline __attribute__ (( always_inline )) void
3805+rdc_init_ring ( struct rdc_ring *ring, unsigned int count, unsigned int reg ) {
3806+
3807+ ring->count = count;
3808+ ring->reg = reg;
3809+}
3810+
3811+/** Number of transmit descriptors
3812+ *
3813+ * This is a policy decision.
3814+ */
3815+#define RDC_NUM_TX_DESC 16
3816+
3817+/** Number of receive descriptors
3818+ *
3819+ * This is a policy decision.
3820+ */
3821+#define RDC_NUM_RX_DESC 8
3822+
3823+/** Receive buffer length */
3824+#define RDC_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
3825+
3826+/** An RDC network card */
3827+struct rdc_nic {
3828+ /** Registers */
3829+ void *regs;
3830+ /** DMA device */
3831+ struct dma_device *dma;
3832+ /** MII interface */
3833+ struct mii_interface mdio;
3834+ /** MII device */
3835+ struct mii_device mii;
3836+
3837+ /** Transmit descriptor ring */
3838+ struct rdc_ring tx;
3839+ /** Receive descriptor ring */
3840+ struct rdc_ring rx;
3841+ /** Receive I/O buffers */
3842+ struct io_buffer *rx_iobuf[RDC_NUM_RX_DESC];
3843+};
3844+
3845+#endif /* _RDC_H */
3846diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c
3847index 0af3416..a43efb6 100644
3848--- a/src/drivers/net/realtek.c
3849+++ b/src/drivers/net/realtek.c
3850@@ -420,6 +420,16 @@ static int realtek_phy_reset ( struct realtek_nic *rtl ) {
3851 */
3852 }
3853
3854+ /* Some cards (e.g. RTL8211B) have a hardware errata that
3855+ * requires the MII_MMD_DATA register to be cleared before the
3856+ * link will come up.
3857+ */
3858+ if ( ( rc = mii_write ( &rtl->mii, MII_MMD_DATA, 0 ) ) != 0 ) {
3859+ /* Ignore failures, since the register may not be
3860+ * present on all PHYs.
3861+ */
3862+ }
3863+
3864 /* Restart autonegotiation */
3865 if ( ( rc = mii_restart ( &rtl->mii ) ) != 0 ) {
3866 DBGC ( rtl, "REALTEK %p could not restart MII: %s\n",
3867diff --git a/src/drivers/net/virtio-net.c b/src/drivers/net/virtio-net.c
3868index 78ec9ac..0c45419 100644
3869--- a/src/drivers/net/virtio-net.c
3870+++ b/src/drivers/net/virtio-net.c
3871@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
3872 #include <ipxe/iobuf.h>
3873 #include <ipxe/netdevice.h>
3874 #include <ipxe/pci.h>
3875+#include <ipxe/dma.h>
3876 #include <ipxe/if_ether.h>
3877 #include <ipxe/ethernet.h>
3878 #include <ipxe/virtio-pci.h>
3879@@ -99,8 +100,9 @@ struct virtnet_nic {
3880 /** Pending rx packet count */
3881 unsigned int rx_num_iobufs;
3882
3883- /** Virtio net dummy packet headers */
3884- struct virtio_net_hdr_modern empty_header[QUEUE_NB];
3885+ /** DMA device */
3886+ struct dma_device *dma;
3887+
3888 };
3889
3890 /** Add an iobuf to a virtqueue
3891@@ -115,7 +117,7 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
3892 int vq_idx, struct io_buffer *iobuf ) {
3893 struct virtnet_nic *virtnet = netdev->priv;
3894 struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx];
3895- struct virtio_net_hdr_modern *header = &virtnet->empty_header[vq_idx];
3896+ struct virtio_net_hdr_modern *header = vq->empty_header;
3897 unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0;
3898 unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2;
3899 size_t header_len = ( virtnet->virtio_version ?
3900@@ -132,11 +134,11 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
3901 * to header->flags for received packets. Work around
3902 * this by using separate RX and TX headers.
3903 */
3904- .addr = ( char* ) header,
3905+ .addr = dma ( &vq->map, header ),
3906 .length = header_len,
3907 },
3908 {
3909- .addr = ( char* ) iobuf->data,
3910+ .addr = iob_dma ( iobuf ),
3911 .length = iob_len ( iobuf ),
3912 },
3913 };
3914@@ -161,7 +163,7 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) {
3915 struct io_buffer *iobuf;
3916
3917 /* Try to allocate a buffer, stop for now if out of memory */
3918- iobuf = alloc_iob ( len );
3919+ iobuf = alloc_rx_iob ( len, virtnet->dma );
3920 if ( ! iobuf )
3921 break;
3922
3923@@ -215,7 +217,8 @@ static int virtnet_open_legacy ( struct net_device *netdev ) {
3924
3925 /* Initialize rx/tx virtqueues */
3926 for ( i = 0; i < QUEUE_NB; i++ ) {
3927- if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) {
3928+ if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i], virtnet->dma,
3929+ sizeof ( struct virtio_net_hdr_modern ) ) == -1 ) {
3930 DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n",
3931 virtnet, i );
3932 virtnet_free_virtqueues ( netdev );
3933@@ -280,7 +283,8 @@ static int virtnet_open_modern ( struct net_device *netdev ) {
3934 }
3935
3936 /* Initialize rx/tx virtqueues */
3937- if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue ) ) {
3938+ if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue,
3939+ virtnet->dma, sizeof ( struct virtio_net_hdr_modern ) ) ) {
3940 DBGC ( virtnet, "VIRTIO-NET %p cannot register queues\n",
3941 virtnet );
3942 virtnet_free_virtqueues ( netdev );
3943@@ -335,7 +339,7 @@ static void virtnet_close ( struct net_device *netdev ) {
3944
3945 /* Free rx iobufs */
3946 list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) {
3947- free_iob ( iobuf );
3948+ free_rx_iob ( iobuf );
3949 }
3950 INIT_LIST_HEAD ( &virtnet->rx_iobufs );
3951 virtnet->rx_num_iobufs = 0;
3952@@ -478,6 +482,12 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
3953
3954 /* Enable PCI bus master and reset NIC */
3955 adjust_pci_device ( pci );
3956+
3957+ /* Configure DMA */
3958+ virtnet->dma = &pci->dma;
3959+ dma_set_mask_64bit ( virtnet->dma );
3960+ netdev->dma = virtnet->dma;
3961+
3962 vp_reset ( ioaddr );
3963
3964 /* Load MAC address and MTU */
3965@@ -506,7 +516,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
3966 return 0;
3967
3968 unregister_netdev ( netdev );
3969- err_register_netdev:
3970+err_register_netdev:
3971 vp_reset ( ioaddr );
3972 netdev_nullify ( netdev );
3973 netdev_put ( netdev );
3974@@ -586,6 +596,11 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) {
3975 /* Enable the PCI device */
3976 adjust_pci_device ( pci );
3977
3978+ /* Configure DMA */
3979+ virtnet->dma = &pci->dma;
3980+ dma_set_mask_64bit ( virtnet->dma );
3981+ netdev->dma = virtnet->dma;
3982+
3983 /* Reset the device and set initial status bits */
3984 vpm_reset ( &virtnet->vdev );
3985 vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE );
3986@@ -633,7 +648,6 @@ err_mac_address:
3987 vpm_reset ( &virtnet->vdev );
3988 netdev_nullify ( netdev );
3989 netdev_put ( netdev );
3990-
3991 virtio_pci_unmap_capability ( &virtnet->vdev.device );
3992 err_map_device:
3993 virtio_pci_unmap_capability ( &virtnet->vdev.isr );
3994diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c
3995index cc48af0..3247ee6 100644
3996--- a/src/drivers/usb/xhci.c
3997+++ b/src/drivers/usb/xhci.c
3998@@ -1165,6 +1165,31 @@ static int xhci_reset ( struct xhci_device *xhci ) {
3999 return -ETIMEDOUT;
4000 }
4001
4002+/**
4003+ * Mark xHCI device as permanently failed
4004+ *
4005+ * @v xhci xHCI device
4006+ * @ret rc Return status code
4007+ */
4008+static int xhci_fail ( struct xhci_device *xhci ) {
4009+ size_t len;
4010+ int rc;
4011+
4012+ /* Mark command mechanism as permanently failed */
4013+ xhci->failed = 1;
4014+
4015+ /* Reset device */
4016+ if ( ( rc = xhci_reset ( xhci ) ) != 0 )
4017+ return rc;
4018+
4019+ /* Discard DCBAA entries since DCBAAP has been cleared */
4020+ assert ( xhci->dcbaa.context != NULL );
4021+ len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) );
4022+ memset ( xhci->dcbaa.context, 0, len );
4023+
4024+ return 0;
4025+}
4026+
4027 /******************************************************************************
4028 *
4029 * Transfer request blocks
4030@@ -1720,6 +1745,10 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
4031 unsigned int consumed;
4032 unsigned int type;
4033
4034+ /* Do nothing if device has permanently failed */
4035+ if ( xhci->failed )
4036+ return;
4037+
4038 /* Poll for events */
4039 profile_start ( &xhci_event_profiler );
4040 for ( consumed = 0 ; ; consumed++ ) {
4041@@ -1778,6 +1807,7 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
4042 */
4043 static void xhci_abort ( struct xhci_device *xhci ) {
4044 physaddr_t crp;
4045+ uint32_t crcr;
4046
4047 /* Abort the command */
4048 DBGC2 ( xhci, "XHCI %s aborting command\n", xhci->name );
4049@@ -1786,8 +1816,18 @@ static void xhci_abort ( struct xhci_device *xhci ) {
4050 /* Allow time for command to abort */
4051 mdelay ( XHCI_COMMAND_ABORT_DELAY_MS );
4052
4053- /* Sanity check */
4054- assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );
4055+ /* Check for failure to abort */
4056+ crcr = readl ( xhci->op + XHCI_OP_CRCR );
4057+ if ( crcr & XHCI_CRCR_CRR ) {
4058+
4059+ /* Device has failed to abort a command and is almost
4060+ * certainly beyond repair. Reset device, abandoning
4061+ * all state, and mark device as failed to avoid
4062+ * delays on any future command attempts.
4063+ */
4064+ DBGC ( xhci, "XHCI %s failed to abort command\n", xhci->name );
4065+ xhci_fail ( xhci );
4066+ }
4067
4068 /* Consume (and ignore) any final command status */
4069 xhci_event_poll ( xhci );
4070@@ -1813,6 +1853,12 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) {
4071 unsigned int i;
4072 int rc;
4073
4074+ /* Immediately fail all commands if command mechanism has failed */
4075+ if ( xhci->failed ) {
4076+ rc = -EPIPE;
4077+ goto err_failed;
4078+ }
4079+
4080 /* Sanity check */
4081 if ( xhci->pending ) {
4082 DBGC ( xhci, "XHCI %s command ring busy\n", xhci->name );
4083@@ -1863,6 +1909,7 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) {
4084 err_enqueue:
4085 xhci->pending = NULL;
4086 err_pending:
4087+ err_failed:
4088 return rc;
4089 }
4090
4091@@ -3412,14 +3459,36 @@ static int xhci_probe ( struct pci_device *pci ) {
4092 static void xhci_remove ( struct pci_device *pci ) {
4093 struct xhci_device *xhci = pci_get_drvdata ( pci );
4094 struct usb_bus *bus = xhci->bus;
4095+ uint16_t command;
4096+
4097+ /* Some systems are observed to disable bus mastering on
4098+ * Thunderbolt controllers before we get a chance to shut
4099+ * down. Detect this and avoid attempting any DMA operations,
4100+ * which are guaranteed to fail and may end up spuriously
4101+ * completing after the operating system kernel starts up.
4102+ */
4103+ pci_read_config_word ( pci, PCI_COMMAND, &command );
4104+ if ( ! ( command & PCI_COMMAND_MASTER ) ) {
4105+ DBGC ( xhci, "XHCI %s DMA was disabled\n", xhci->name );
4106+ xhci_fail ( xhci );
4107+ }
4108
4109+ /* Unregister and free USB bus */
4110 unregister_usb_bus ( bus );
4111 free_usb_bus ( bus );
4112+
4113+ /* Reset device and undo any PCH-specific fixes */
4114 xhci_reset ( xhci );
4115 if ( xhci->quirks & XHCI_PCH )
4116 xhci_pch_undo ( xhci, pci );
4117+
4118+ /* Release ownership back to BIOS */
4119 xhci_legacy_release ( xhci );
4120+
4121+ /* Unmap registers */
4122 iounmap ( xhci->regs );
4123+
4124+ /* Free device */
4125 free ( xhci );
4126 }
4127
4128diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h
4129index 6e02d70..a3c8888 100644
4130--- a/src/drivers/usb/xhci.h
4131+++ b/src/drivers/usb/xhci.h
4132@@ -1115,6 +1115,8 @@ struct xhci_device {
4133 struct xhci_event_ring event;
4134 /** Current command (if any) */
4135 union xhci_trb *pending;
4136+ /** Command mechanism has permanently failed */
4137+ int failed;
4138
4139 /** Device slots, indexed by slot ID */
4140 struct xhci_slot **slot;
4141diff --git a/src/hci/commands/image_archive_cmd.c b/src/hci/commands/image_archive_cmd.c
4142new file mode 100644
4143index 0000000..a2212ae
4144--- /dev/null
4145+++ b/src/hci/commands/image_archive_cmd.c
4146@@ -0,0 +1,105 @@
4147+/*
4148+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
4149+ *
4150+ * This program is free software; you can redistribute it and/or
4151+ * modify it under the terms of the GNU General Public License as
4152+ * published by the Free Software Foundation; either version 2 of the
4153+ * License, or any later version.
4154+ *
4155+ * This program is distributed in the hope that it will be useful, but
4156+ * WITHOUT ANY WARRANTY; without even the implied warranty of
4157+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4158+ * General Public License for more details.
4159+ *
4160+ * You should have received a copy of the GNU General Public License
4161+ * along with this program; if not, write to the Free Software
4162+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
4163+ * 02110-1301, USA.
4164+ *
4165+ * You can also choose to distribute this program under the terms of
4166+ * the Unmodified Binary Distribution Licence (as given in the file
4167+ * COPYING.UBDL), provided that you have satisfied its requirements.
4168+ */
4169+
4170+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4171+
4172+#include <getopt.h>
4173+#include <ipxe/command.h>
4174+#include <ipxe/parseopt.h>
4175+#include <usr/imgmgmt.h>
4176+#include <usr/imgarchive.h>
4177+
4178+/** @file
4179+ *
4180+ * Archive image commands
4181+ *
4182+ */
4183+
4184+/** "imgextract" options */
4185+struct imgextract_options {
4186+ /** Image name */
4187+ char *name;
4188+ /** Keep original image */
4189+ int keep;
4190+ /** Download timeout */
4191+ unsigned long timeout;
4192+};
4193+
4194+/** "imgextract" option list */
4195+static struct option_descriptor imgextract_opts[] = {
4196+ OPTION_DESC ( "name", 'n', required_argument,
4197+ struct imgextract_options, name, parse_string ),
4198+ OPTION_DESC ( "keep", 'k', no_argument,
4199+ struct imgextract_options, keep, parse_flag ),
4200+ OPTION_DESC ( "timeout", 't', required_argument,
4201+ struct imgextract_options, timeout, parse_timeout ),
4202+};
4203+
4204+/** "imgextract" command descriptor */
4205+static struct command_descriptor imgextract_cmd =
4206+ COMMAND_DESC ( struct imgextract_options, imgextract_opts, 1, 1, NULL );
4207+
4208+/**
4209+ * The "imgextract" command
4210+ *
4211+ * @v argc Argument count
4212+ * @v argv Argument list
4213+ * @ret rc Return status code
4214+ */
4215+static int imgextract_exec ( int argc, char **argv ) {
4216+ struct imgextract_options opts;
4217+ struct image *image;
4218+ int rc;
4219+
4220+ /* Parse options */
4221+ if ( ( rc = parse_options ( argc, argv, &imgextract_cmd,
4222+ &opts ) ) != 0 )
4223+ goto err_parse;
4224+
4225+ /* Acquire image */
4226+ if ( ( rc = imgacquire ( argv[optind], opts.timeout, &image ) ) != 0 )
4227+ goto err_acquire;
4228+
4229+ /* Extract archive image */
4230+ if ( ( rc = imgextract ( image, opts.name ) ) != 0 )
4231+ goto err_extract;
4232+
4233+ /* Success */
4234+ rc = 0;
4235+
4236+ err_extract:
4237+ /* Discard original image unless --keep was specified */
4238+ if ( ! opts.keep )
4239+ unregister_image ( image );
4240+ err_acquire:
4241+ err_parse:
4242+ return rc;
4243+}
4244+
4245+/** Archive image commands */
4246+struct command image_archive_commands[] __command = {
4247+ {
4248+ .name = "imgextract",
4249+ .exec = imgextract_exec,
4250+ },
4251+};
4252diff --git a/src/hci/readline.c b/src/hci/readline.c
4253index 852c450..ecc72d4 100644
4254--- a/src/hci/readline.c
4255+++ b/src/hci/readline.c
4256@@ -38,7 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4257 *
4258 */
4259
4260-#define READLINE_MAX 256
4261+#define READLINE_MAX 1024
4262
4263 /**
4264 * Synchronise console with edited string
4265@@ -258,8 +258,8 @@ void history_free ( struct readline_history *history ) {
4266 int readline_history ( const char *prompt, const char *prefill,
4267 struct readline_history *history, unsigned long timeout,
4268 char **line ) {
4269- char buf[READLINE_MAX];
4270 struct edit_string string;
4271+ char *buf;
4272 int key;
4273 int move_by;
4274 const char *new_string;
4275@@ -275,10 +275,14 @@ int readline_history ( const char *prompt, const char *prefill,
4276 /* Ensure cursor is visible */
4277 printf ( "\033[?25h" );
4278
4279- /* Initialise editable string */
4280+ /* Allocate buffer and initialise editable string */
4281+ buf = zalloc ( READLINE_MAX );
4282+ if ( ! buf ) {
4283+ rc = -ENOMEM;
4284+ goto done;
4285+ }
4286 memset ( &string, 0, sizeof ( string ) );
4287- init_editstring ( &string, buf, sizeof ( buf ) );
4288- buf[0] = '\0';
4289+ init_editstring ( &string, buf, READLINE_MAX );
4290
4291 /* Prefill string, if applicable */
4292 if ( prefill ) {
4293@@ -303,8 +307,13 @@ int readline_history ( const char *prompt, const char *prefill,
4294 switch ( key ) {
4295 case CR:
4296 case LF:
4297- *line = strdup ( buf );
4298- rc = ( ( *line ) ? 0 : -ENOMEM );
4299+ /* Shrink string (ignoring failures) */
4300+ *line = realloc ( buf,
4301+ ( strlen ( buf ) + 1 /* NUL */ ) );
4302+ if ( ! *line )
4303+ *line = buf;
4304+ buf = NULL;
4305+ rc = 0;
4306 goto done;
4307 case CTRL_C:
4308 rc = -ECANCELED;
4309@@ -332,6 +341,7 @@ int readline_history ( const char *prompt, const char *prefill,
4310
4311 done:
4312 putchar ( '\n' );
4313+ free ( buf );
4314 if ( history ) {
4315 if ( *line && (*line)[0] )
4316 history_append ( history, *line );
4317diff --git a/src/image/gzip.c b/src/image/gzip.c
4318new file mode 100644
4319index 0000000..98376e1
4320--- /dev/null
4321+++ b/src/image/gzip.c
4322@@ -0,0 +1,167 @@
4323+/*
4324+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
4325+ *
4326+ * This program is free software; you can redistribute it and/or
4327+ * modify it under the terms of the GNU General Public License as
4328+ * published by the Free Software Foundation; either version 2 of the
4329+ * License, or any later version.
4330+ *
4331+ * This program is distributed in the hope that it will be useful, but
4332+ * WITHOUT ANY WARRANTY; without even the implied warranty of
4333+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4334+ * General Public License for more details.
4335+ *
4336+ * You should have received a copy of the GNU General Public License
4337+ * along with this program; if not, write to the Free Software
4338+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
4339+ * 02110-1301, USA.
4340+ *
4341+ * You can also choose to distribute this program under the terms of
4342+ * the Unmodified Binary Distribution Licence (as given in the file
4343+ * COPYING.UBDL), provided that you have satisfied its requirements.
4344+ */
4345+
4346+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4347+
4348+#include <stdlib.h>
4349+#include <errno.h>
4350+#include <assert.h>
4351+#include <ipxe/deflate.h>
4352+#include <ipxe/uaccess.h>
4353+#include <ipxe/image.h>
4354+#include <ipxe/zlib.h>
4355+#include <ipxe/gzip.h>
4356+
4357+/** @file
4358+ *
4359+ * gzip compressed images
4360+ *
4361+ */
4362+
4363+/**
4364+ * Extract gzip image
4365+ *
4366+ * @v image Image
4367+ * @v extracted Extracted image
4368+ * @ret rc Return status code
4369+ */
4370+static int gzip_extract ( struct image *image, struct image *extracted ) {
4371+ struct gzip_header header;
4372+ struct gzip_extra_header extra;
4373+ struct gzip_crc_header crc;
4374+ struct gzip_footer footer;
4375+ struct deflate_chunk in;
4376+ unsigned int strings;
4377+ size_t offset;
4378+ size_t len;
4379+ off_t nul;
4380+ int rc;
4381+
4382+ /* Sanity check */
4383+ assert ( image->len >= ( sizeof ( header ) + sizeof ( footer ) ) );
4384+
4385+ /* Extract footer */
4386+ len = ( image->len - sizeof ( footer ) );
4387+ copy_from_user ( &footer, image->data, len, sizeof ( footer ) );
4388+
4389+ /* Extract fixed header */
4390+ copy_from_user ( &header, image->data, 0, sizeof ( header ) );
4391+ offset = sizeof ( header );
4392+ assert ( offset <= ( image->len - sizeof ( footer ) ) );
4393+
4394+ /* Skip extra header, if present */
4395+ if ( header.flags & GZIP_FL_EXTRA ) {
4396+ copy_from_user ( &extra, image->data, offset,
4397+ sizeof ( extra ) );
4398+ offset += sizeof ( extra );
4399+ offset += le16_to_cpu ( extra.len );
4400+ if ( offset > len ) {
4401+ DBGC ( image, "GZIP %p overlength extra header\n",
4402+ image );
4403+ return -EINVAL;
4404+ }
4405+ }
4406+ assert ( offset <= ( image->len - sizeof ( footer ) ) );
4407+
4408+ /* Skip name and/or comment, if present */
4409+ strings = 0;
4410+ if ( header.flags & GZIP_FL_NAME )
4411+ strings++;
4412+ if ( header.flags & GZIP_FL_COMMENT )
4413+ strings++;
4414+ while ( strings-- ) {
4415+ nul = memchr_user ( image->data, offset, 0, ( len - offset ) );
4416+ if ( nul < 0 ) {
4417+ DBGC ( image, "GZIP %p overlength name/comment\n",
4418+ image );
4419+ return -EINVAL;
4420+ }
4421+ offset = ( nul + 1 /* NUL */ );
4422+ }
4423+ assert ( offset <= ( image->len - sizeof ( footer ) ) );
4424+
4425+ /* Skip CRC, if present */
4426+ if ( header.flags & GZIP_FL_HCRC ) {
4427+ offset += sizeof ( crc );
4428+ if ( offset > len ) {
4429+ DBGC ( image, "GZIP %p overlength CRC header\n",
4430+ image );
4431+ return -EINVAL;
4432+ }
4433+ }
4434+
4435+ /* Initialise input chunk */
4436+ deflate_chunk_init ( &in, userptr_add ( image->data, offset ), 0, len );
4437+
4438+ /* Presize extracted image */
4439+ if ( ( rc = image_set_len ( extracted,
4440+ le32_to_cpu ( footer.len ) ) ) != 0 ) {
4441+ DBGC ( image, "GZIP %p could not presize: %s\n",
4442+ image, strerror ( rc ) );
4443+ return rc;
4444+ }
4445+
4446+ /* Decompress image (expanding if necessary) */
4447+ if ( ( rc = zlib_deflate ( DEFLATE_RAW, &in, extracted ) ) != 0 ) {
4448+ DBGC ( image, "GZIP %p could not decompress: %s\n",
4449+ image, strerror ( rc ) );
4450+ return rc;
4451+ }
4452+
4453+ return 0;
4454+}
4455+
4456+/**
4457+ * Probe gzip image
4458+ *
4459+ * @v image gzip image
4460+ * @ret rc Return status code
4461+ */
4462+static int gzip_probe ( struct image *image ) {
4463+ struct gzip_header header;
4464+ struct gzip_footer footer;
4465+
4466+ /* Sanity check */
4467+ if ( image->len < ( sizeof ( header ) + sizeof ( footer ) ) ) {
4468+ DBGC ( image, "GZIP %p image too short\n", image );
4469+ return -ENOEXEC;
4470+ }
4471+
4472+ /* Check magic header */
4473+ copy_from_user ( &header.magic, image->data, 0,
4474+ sizeof ( header.magic ) );
4475+ if ( header.magic != cpu_to_be16 ( GZIP_MAGIC ) ) {
4476+ DBGC ( image, "GZIP %p invalid magic\n", image );
4477+ return -ENOEXEC;
4478+ }
4479+
4480+ return 0;
4481+}
4482+
4483+/** gzip image type */
4484+struct image_type gzip_image_type __image_type ( PROBE_NORMAL ) = {
4485+ .name = "gzip",
4486+ .probe = gzip_probe,
4487+ .extract = gzip_extract,
4488+ .exec = image_extract_exec,
4489+};
4490diff --git a/src/image/zlib.c b/src/image/zlib.c
4491new file mode 100644
4492index 0000000..a42c47e
4493--- /dev/null
4494+++ b/src/image/zlib.c
4495@@ -0,0 +1,163 @@
4496+/*
4497+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
4498+ *
4499+ * This program is free software; you can redistribute it and/or
4500+ * modify it under the terms of the GNU General Public License as
4501+ * published by the Free Software Foundation; either version 2 of the
4502+ * License, or any later version.
4503+ *
4504+ * This program is distributed in the hope that it will be useful, but
4505+ * WITHOUT ANY WARRANTY; without even the implied warranty of
4506+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4507+ * General Public License for more details.
4508+ *
4509+ * You should have received a copy of the GNU General Public License
4510+ * along with this program; if not, write to the Free Software
4511+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
4512+ * 02110-1301, USA.
4513+ *
4514+ * You can also choose to distribute this program under the terms of
4515+ * the Unmodified Binary Distribution Licence (as given in the file
4516+ * COPYING.UBDL), provided that you have satisfied its requirements.
4517+ */
4518+
4519+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4520+
4521+#include <stdlib.h>
4522+#include <errno.h>
4523+#include <assert.h>
4524+#include <ipxe/deflate.h>
4525+#include <ipxe/uaccess.h>
4526+#include <ipxe/image.h>
4527+#include <ipxe/zlib.h>
4528+
4529+/** @file
4530+ *
4531+ * zlib compressed images
4532+ *
4533+ */
4534+
4535+/**
4536+ * Extract compressed data to image
4537+ *
4538+ * @v format Compression format code
4539+ * @v in Compressed input chunk
4540+ * @v extracted Extracted image
4541+ * @ret rc Return status code
4542+ */
4543+int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in,
4544+ struct image *extracted ) {
4545+ struct deflate *deflate;
4546+ struct deflate_chunk out;
4547+ int rc;
4548+
4549+ /* Allocate and initialise decompressor */
4550+ deflate = zalloc ( sizeof ( *deflate ) );
4551+ if ( ! deflate ) {
4552+ rc = -ENOMEM;
4553+ goto err_alloc;
4554+ }
4555+
4556+ /* Decompress data, (re)allocating if necessary */
4557+ while ( 1 ) {
4558+
4559+ /* (Re)initialise decompressor */
4560+ deflate_init ( deflate, format );
4561+
4562+ /* (Re)initialise input chunk */
4563+ in->offset = 0;
4564+
4565+ /* Initialise output chunk */
4566+ deflate_chunk_init ( &out, extracted->data, 0, extracted->len );
4567+
4568+ /* Decompress data */
4569+ if ( ( rc = deflate_inflate ( deflate, in, &out ) ) != 0 ) {
4570+ DBGC ( extracted, "ZLIB %p could not decompress: %s\n",
4571+ extracted, strerror ( rc ) );
4572+ goto err_inflate;
4573+ }
4574+
4575+ /* Check that decompression is valid */
4576+ if ( ! deflate_finished ( deflate ) ) {
4577+ DBGC ( extracted, "ZLIB %p decompression incomplete\n",
4578+ extracted );
4579+ rc = -EINVAL;
4580+ goto err_unfinished;
4581+ }
4582+
4583+ /* Finish if output image size was correct */
4584+ if ( out.offset == extracted->len )
4585+ break;
4586+
4587+ /* Otherwise, resize output image and retry */
4588+ if ( ( rc = image_set_len ( extracted, out.offset ) ) != 0 ) {
4589+ DBGC ( extracted, "ZLIB %p could not resize: %s\n",
4590+ extracted, strerror ( rc ) );
4591+ goto err_set_size;
4592+ }
4593+ }
4594+
4595+ /* Success */
4596+ rc = 0;
4597+
4598+ err_set_size:
4599+ err_unfinished:
4600+ err_inflate:
4601+ free ( deflate );
4602+ err_alloc:
4603+ return rc;
4604+}
4605+
4606+/**
4607+ * Extract zlib image
4608+ *
4609+ * @v image Image
4610+ * @v extracted Extracted image
4611+ * @ret rc Return status code
4612+ */
4613+static int zlib_extract ( struct image *image, struct image *extracted ) {
4614+ struct deflate_chunk in;
4615+ int rc;
4616+
4617+ /* Initialise input chunk */
4618+ deflate_chunk_init ( &in, image->data, 0, image->len );
4619+
4620+ /* Decompress image */
4621+ if ( ( rc = zlib_deflate ( DEFLATE_ZLIB, &in, extracted ) ) != 0 )
4622+ return rc;
4623+
4624+ return 0;
4625+}
4626+
4627+/**
4628+ * Probe zlib image
4629+ *
4630+ * @v image zlib image
4631+ * @ret rc Return status code
4632+ */
4633+static int zlib_probe ( struct image *image ) {
4634+ union zlib_magic magic;
4635+
4636+ /* Sanity check */
4637+ if ( image->len < sizeof ( magic ) ) {
4638+ DBGC ( image, "ZLIB %p image too short\n", image );
4639+ return -ENOEXEC;
4640+ }
4641+
4642+ /* Check magic header */
4643+ copy_from_user ( &magic, image->data, 0, sizeof ( magic ) );
4644+ if ( ! zlib_magic_is_valid ( &magic ) ) {
4645+ DBGC ( image, "ZLIB %p invalid magic data\n", image );
4646+ return -ENOEXEC;
4647+ }
4648+
4649+ return 0;
4650+}
4651+
4652+/** zlib image type */
4653+struct image_type zlib_image_type __image_type ( PROBE_NORMAL ) = {
4654+ .name = "zlib",
4655+ .probe = zlib_probe,
4656+ .extract = zlib_extract,
4657+ .exec = image_extract_exec,
4658+};
4659diff --git a/src/include/endian.h b/src/include/endian.h
4660index 79c3163..bdae9de 100644
4661--- a/src/include/endian.h
4662+++ b/src/include/endian.h
4663@@ -8,14 +8,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4664 * Little-endian systems should define BYTE_ORDER as LITTLE_ENDIAN.
4665 * This constant is intended to be used only at compile time.
4666 */
4667+#ifndef __LITTLE_ENDIAN
4668 #define __LITTLE_ENDIAN 0x44332211UL
4669+#endif
4670
4671 /** Constant representing big-endian byte order
4672 *
4673 * Big-endian systems should define BYTE_ORDER as BIG_ENDIAN.
4674 * This constant is intended to be used only at compile time.
4675 */
4676+#ifndef __BIG_ENDIAN
4677 #define __BIG_ENDIAN 0x11223344UL
4678+#endif
4679
4680 #include "bits/endian.h"
4681
4682diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h
4683index 81ef7ff..7df3ec2 100644
4684--- a/src/include/ipxe/acpi.h
4685+++ b/src/include/ipxe/acpi.h
4686@@ -387,7 +387,9 @@ acpi_describe ( struct interface *interface );
4687 typeof ( struct acpi_descriptor * ( object_type ) )
4688
4689 extern void acpi_fix_checksum ( struct acpi_header *acpi );
4690-extern int acpi_sx ( uint32_t signature );
4691+extern int acpi_extract ( uint32_t signature, void *data,
4692+ int ( * extract ) ( userptr_t zsdt, size_t len,
4693+ size_t offset, void *data ) );
4694 extern void acpi_add ( struct acpi_descriptor *desc );
4695 extern void acpi_del ( struct acpi_descriptor *desc );
4696 extern int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) );
4697diff --git a/src/include/ipxe/acpimac.h b/src/include/ipxe/acpimac.h
4698new file mode 100644
4699index 0000000..de673eb
4700--- /dev/null
4701+++ b/src/include/ipxe/acpimac.h
4702@@ -0,0 +1,14 @@
4703+#ifndef _IPXE_ACPIMAC_H
4704+#define _IPXE_ACPIMAC_H
4705+
4706+/** @file
4707+ *
4708+ * ACPI MAC address
4709+ *
4710+ */
4711+
4712+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4713+
4714+extern int acpi_mac ( uint8_t *hw_addr );
4715+
4716+#endif /* _IPXE_ACPIMAC_H */
4717diff --git a/src/include/ipxe/cachedhcp.h b/src/include/ipxe/cachedhcp.h
4718index 7765c64..39ce745 100644
4719--- a/src/include/ipxe/cachedhcp.h
4720+++ b/src/include/ipxe/cachedhcp.h
4721@@ -12,6 +12,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4722 #include <stddef.h>
4723 #include <ipxe/uaccess.h>
4724
4725-extern int cachedhcp_record ( userptr_t data, size_t max_len );
4726+struct cached_dhcp_packet;
4727+
4728+extern struct cached_dhcp_packet cached_dhcpack;
4729+extern struct cached_dhcp_packet cached_proxydhcp;
4730+extern struct cached_dhcp_packet cached_pxebs;
4731+
4732+extern int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
4733+ size_t max_len );
4734
4735 #endif /* _IPXE_CACHEDHCP_H */
4736diff --git a/src/include/ipxe/cpio.h b/src/include/ipxe/cpio.h
4737index 0637c53..9c5e22d 100644
4738--- a/src/include/ipxe/cpio.h
4739+++ b/src/include/ipxe/cpio.h
4740@@ -9,6 +9,8 @@
4741
4742 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4743
4744+#include <ipxe/image.h>
4745+
4746 /** A CPIO archive header
4747 *
4748 * All field are hexadecimal ASCII numbers padded with '0' on the
4749@@ -48,6 +50,25 @@ struct cpio_header {
4750 /** CPIO magic */
4751 #define CPIO_MAGIC "070701"
4752
4753+/** CPIO header length alignment */
4754+#define CPIO_ALIGN 4
4755+
4756+/** Alignment for CPIO archives within an initrd */
4757+#define INITRD_ALIGN 4096
4758+
4759+/**
4760+ * Get CPIO image name
4761+ *
4762+ * @v image Image
4763+ * @ret name Image name (not NUL terminated)
4764+ */
4765+static inline __attribute__ (( always_inline )) const char *
4766+cpio_name ( struct image *image ) {
4767+ return image->cmdline;
4768+}
4769+
4770 extern void cpio_set_field ( char *field, unsigned long value );
4771+extern size_t cpio_name_len ( struct image *image );
4772+extern size_t cpio_header ( struct image *image, struct cpio_header *cpio );
4773
4774 #endif /* _IPXE_CPIO_H */
4775diff --git a/src/include/ipxe/dhcppkt.h b/src/include/ipxe/dhcppkt.h
4776index f13dfc9..8607596 100644
4777--- a/src/include/ipxe/dhcppkt.h
4778+++ b/src/include/ipxe/dhcppkt.h
4779@@ -56,7 +56,7 @@ dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
4780 * @v dhcppkt DHCP packet
4781 * @ret len Used length
4782 */
4783-static inline int dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
4784+static inline size_t dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
4785 return ( offsetof ( struct dhcphdr, options ) +
4786 dhcppkt->options.used_len );
4787 }
4788diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h
4789index a83fa0f..1dd0d44 100644
4790--- a/src/include/ipxe/efi/efi.h
4791+++ b/src/include/ipxe/efi/efi.h
4792@@ -223,6 +223,7 @@ extern EFI_HANDLE efi_image_handle;
4793 extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
4794 extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
4795 extern EFI_SYSTEM_TABLE *efi_systab;
4796+extern EFI_TPL efi_internal_tpl;
4797 extern EFI_TPL efi_external_tpl;
4798 extern int efi_shutdown_in_progress;
4799
4800diff --git a/src/include/ipxe/efi/efi_wrap.h b/src/include/ipxe/efi/efi_wrap.h
4801index 6c7ccf2..2747a9e 100644
4802--- a/src/include/ipxe/efi/efi_wrap.h
4803+++ b/src/include/ipxe/efi/efi_wrap.h
4804@@ -10,7 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4805
4806 #include <ipxe/efi/efi.h>
4807
4808-extern EFI_SYSTEM_TABLE * efi_wrap_systab ( void );
4809+extern EFI_BOOT_SERVICES * efi_wrap_bs ( void );
4810 extern void efi_wrap ( EFI_HANDLE handle );
4811
4812 #endif /* _IPXE_EFI_WRAP_H */
4813diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
4814index e3bf9f5..23e406b 100644
4815--- a/src/include/ipxe/errfile.h
4816+++ b/src/include/ipxe/errfile.h
4817@@ -77,6 +77,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4818 #define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 )
4819 #define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 )
4820 #define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 )
4821+#define ERRFILE_acpimac ( ERRFILE_CORE | 0x00280000 )
4822
4823 #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
4824 #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
4825@@ -213,6 +214,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4826 #define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 )
4827 #define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 )
4828 #define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 )
4829+#define ERRFILE_rdc ( ERRFILE_DRIVER | 0x00d10000 )
4830
4831 #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
4832 #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
4833@@ -301,6 +303,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4834 #define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 )
4835 #define ERRFILE_der ( ERRFILE_IMAGE | 0x00080000 )
4836 #define ERRFILE_pem ( ERRFILE_IMAGE | 0x00090000 )
4837+#define ERRFILE_archive ( ERRFILE_IMAGE | 0x000a0000 )
4838+#define ERRFILE_zlib ( ERRFILE_IMAGE | 0x000b0000 )
4839+#define ERRFILE_gzip ( ERRFILE_IMAGE | 0x000c0000 )
4840
4841 #define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
4842 #define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )
4843diff --git a/src/include/ipxe/gzip.h b/src/include/ipxe/gzip.h
4844new file mode 100644
4845index 0000000..c8cf641
4846--- /dev/null
4847+++ b/src/include/ipxe/gzip.h
4848@@ -0,0 +1,71 @@
4849+#ifndef _IPXE_GZIP_H
4850+#define _IPXE_GZIP_H
4851+
4852+/** @file
4853+ *
4854+ * gzip compressed images
4855+ *
4856+ */
4857+
4858+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4859+
4860+#include <stdint.h>
4861+#include <ipxe/image.h>
4862+
4863+/** gzip header */
4864+struct gzip_header {
4865+ /** Magic ID */
4866+ uint16_t magic;
4867+ /** Compression method */
4868+ uint8_t method;
4869+ /** Flags */
4870+ uint8_t flags;
4871+ /** Modification time */
4872+ uint32_t mtime;
4873+ /** Extra flags */
4874+ uint8_t extra;
4875+ /** Operating system */
4876+ uint8_t os;
4877+} __attribute__ (( packed ));
4878+
4879+/** Magic ID */
4880+#define GZIP_MAGIC 0x1f8b
4881+
4882+/** Compression method */
4883+#define GZIP_METHOD_DEFLATE 0x08
4884+
4885+/** CRC header is present */
4886+#define GZIP_FL_HCRC 0x02
4887+
4888+/** Extra header is present */
4889+#define GZIP_FL_EXTRA 0x04
4890+
4891+/** File name is present */
4892+#define GZIP_FL_NAME 0x08
4893+
4894+/** File comment is present */
4895+#define GZIP_FL_COMMENT 0x10
4896+
4897+/** gzip extra header */
4898+struct gzip_extra_header {
4899+ /** Extra header length (excluding this field) */
4900+ uint16_t len;
4901+} __attribute__ (( packed ));
4902+
4903+/** gzip CRC header */
4904+struct gzip_crc_header {
4905+ /** CRC-16 */
4906+ uint16_t crc;
4907+} __attribute__ (( packed ));
4908+
4909+/** gzip footer */
4910+struct gzip_footer {
4911+ /** CRC-32 */
4912+ uint32_t crc;
4913+ /** Uncompressed size (modulo 2^32) */
4914+ uint32_t len;
4915+} __attribute__ (( packed ));
4916+
4917+extern struct image_type gzip_image_type __image_type ( PROBE_NORMAL );
4918+
4919+#endif /* _IPXE_GZIP_H */
4920diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h
4921index 4fd2700..0a5a260 100644
4922--- a/src/include/ipxe/image.h
4923+++ b/src/include/ipxe/image.h
4924@@ -113,6 +113,14 @@ struct image_type {
4925 */
4926 int ( * asn1 ) ( struct image *image, size_t offset,
4927 struct asn1_cursor **cursor );
4928+ /**
4929+ * Extract archive image
4930+ *
4931+ * @v image Image
4932+ * @v extracted Extracted image
4933+ * @ret rc Return status code
4934+ */
4935+ int ( * extract ) ( struct image *image, struct image *extracted );
4936 };
4937
4938 /**
4939@@ -175,6 +183,7 @@ extern struct image * alloc_image ( struct uri *uri );
4940 extern int image_set_uri ( struct image *image, struct uri *uri );
4941 extern int image_set_name ( struct image *image, const char *name );
4942 extern int image_set_cmdline ( struct image *image, const char *cmdline );
4943+extern int image_set_len ( struct image *image, size_t len );
4944 extern int image_set_data ( struct image *image, userptr_t data, size_t len );
4945 extern int register_image ( struct image *image );
4946 extern void unregister_image ( struct image *image );
4947@@ -189,6 +198,9 @@ extern struct image * image_memory ( const char *name, userptr_t data,
4948 extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf );
4949 extern int image_asn1 ( struct image *image, size_t offset,
4950 struct asn1_cursor **cursor );
4951+extern int image_extract ( struct image *image, const char *name,
4952+ struct image **extracted );
4953+extern int image_extract_exec ( struct image *image );
4954
4955 /**
4956 * Increment reference count on an image
4957diff --git a/src/include/ipxe/rndis.h b/src/include/ipxe/rndis.h
4958index bcb6d8e..e8ece1e 100644
4959--- a/src/include/ipxe/rndis.h
4960+++ b/src/include/ipxe/rndis.h
4961@@ -84,7 +84,7 @@ struct rndis_initialise_completion {
4962 /** Packet alignment factor */
4963 uint32_t align;
4964 /** Reserved */
4965- uint32_t reserved;
4966+ uint32_t reserved[2];
4967 } __attribute__ (( packed ));
4968
4969 /** RNDIS halt message */
4970@@ -237,7 +237,7 @@ struct rndis_packet_message {
4971 /** Per-packet information record */
4972 struct rndis_packet_field ppi;
4973 /** Reserved */
4974- uint32_t reserved;
4975+ uint32_t reserved[2];
4976 } __attribute__ (( packed ));
4977
4978 /** RNDIS packet record */
4979diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h
4980index f463e66..e042b97 100644
4981--- a/src/include/ipxe/settings.h
4982+++ b/src/include/ipxe/settings.h
4983@@ -426,6 +426,7 @@ extern const struct setting_type setting_type_hexhyp __setting_type;
4984 extern const struct setting_type setting_type_hexraw __setting_type;
4985 extern const struct setting_type setting_type_base64 __setting_type;
4986 extern const struct setting_type setting_type_uuid __setting_type;
4987+extern const struct setting_type setting_type_guid __setting_type;
4988 extern const struct setting_type setting_type_busdevfn __setting_type;
4989 extern const struct setting_type setting_type_dnssl __setting_type;
4990
4991diff --git a/src/include/ipxe/srp.h b/src/include/ipxe/srp.h
4992index 3abb099..1f66a22 100644
4993--- a/src/include/ipxe/srp.h
4994+++ b/src/include/ipxe/srp.h
4995@@ -774,7 +774,7 @@ struct srp_aer_rsp {
4996 * The working draft specification for the SRP boot firmware table can
4997 * be found at
4998 *
4999- * http://ipxe.org/wiki/srp/sbft
5000+ * https://ipxe.org/wiki/srp/sbft
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches