Merge ~paelzer/ubuntu/+source/ipxe:merge-20220113.fbbdc3926-jammy into ubuntu/+source/ipxe:ubuntu/jammy-devel
- Git
- lp:~paelzer/ubuntu/+source/ipxe
- merge-20220113.fbbdc3926-jammy
- Merge into ubuntu/jammy-devel
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) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andreas Hasenack | Approve | ||
Canonical Server | Pending | ||
git-ubuntu import | Pending | ||
Review via email: mp+414650@code.launchpad.net |
Commit message
Description of the change
Christian Ehrhardt (paelzer) wrote : | # |
Christian Ehrhardt (paelzer) wrote : | # |
FYI regression tests are mostly good (no ipxe issue left, just libvirt)
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?
Christian Ehrhardt (paelzer) wrote : | # |
Hi Andreas,
first of all it only needs/wants/
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-
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?
Andreas Hasenack (ahasenack) wrote : | # |
Yes, thanks
+1
Christian Ehrhardt (paelzer) wrote : | # |
Uploading as tested
Uploading to ubuntu (via ftp to upload.ubuntu.com):
Uploading ipxe_1.
Uploading ipxe_1.
Uploading ipxe_1.
Uploading ipxe_1.
Uploading ipxe_1.
Successfully uploaded packages.
Christian Ehrhardt (paelzer) wrote : | # |
Preview Diff
1 | diff --git a/contrib/cloud/aws-import b/contrib/cloud/aws-import |
2 | index 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 | + )) |
108 | diff --git a/debian/changelog b/debian/changelog |
109 | index 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 |
124 | diff --git a/debian/control b/debian/control |
125 | index 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 |
136 | diff --git a/debian/grub-ipxe.install b/debian/grub-ipxe.install |
137 | index 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 |
145 | diff --git a/debian/rules b/debian/rules |
146 | index 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 $@) |
179 | diff --git a/src/Makefile b/src/Makefile |
180 | index 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 | |
192 | diff --git a/src/Makefile.efi b/src/Makefile.efi |
193 | index 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] $@" |
206 | diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping |
207 | index 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) \ |
238 | diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c |
239 | index 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 ), |
266 | diff --git a/src/arch/x86/drivers/net/undinet.c b/src/arch/x86/drivers/net/undinet.c |
267 | index 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 */ ) |
301 | diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c |
302 | index 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 ), |
387 | diff --git a/src/arch/x86/image/initrd.c b/src/arch/x86/image/initrd.c |
388 | index 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 | * |
399 | diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h |
400 | index 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 | } |
576 | diff --git a/src/arch/x86/include/initrd.h b/src/arch/x86/include/initrd.h |
577 | index 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 |
594 | diff --git a/src/arch/x86/include/ipxe/cpuid.h b/src/arch/x86/include/ipxe/cpuid.h |
595 | index 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 | |
608 | diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c |
609 | index 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; |
703 | diff --git a/src/arch/x86/interface/pcbios/bios_cachedhcp.c b/src/arch/x86/interface/pcbios/bios_cachedhcp.c |
704 | index 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 ) ); |
717 | diff --git a/src/arch/x86/interface/pcbios/rtc_entropy.c b/src/arch/x86/interface/pcbios/rtc_entropy.c |
718 | index 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 | |
755 | diff --git a/src/arch/x86/interface/syslinux/comboot_call.c b/src/arch/x86/interface/syslinux/comboot_call.c |
756 | index 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, [] ) = ""; |
768 | diff --git a/src/arch/x86/prefix/romprefix.S b/src/arch/x86/prefix/romprefix.S |
769 | index 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, |
790 | diff --git a/src/arch/x86/prefix/unlzma.S b/src/arch/x86/prefix/unlzma.S |
791 | index 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 |
803 | diff --git a/src/config/branding.h b/src/config/branding.h |
804 | index 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 | |
905 | diff --git a/src/config/cloud/aws.ipxe b/src/config/cloud/aws.ipxe |
906 | index 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 |
934 | diff --git a/src/config/cloud/gce.ipxe b/src/config/cloud/gce.ipxe |
935 | index 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 || |
945 | diff --git a/src/config/cloud/settings.h b/src/config/cloud/settings.h |
946 | index 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 |
956 | diff --git a/src/config/config.c b/src/config/config.c |
957 | index 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 |
973 | diff --git a/src/config/config_archive.c b/src/config/config_archive.c |
974 | new file mode 100644 |
975 | index 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 |
1015 | diff --git a/src/config/general.h b/src/config/general.h |
1016 | index 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 |
1036 | diff --git a/src/core/acpi.c b/src/core/acpi.c |
1037 | index 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 | } |
1192 | diff --git a/src/core/acpimac.c b/src/core/acpimac.c |
1193 | new file mode 100644 |
1194 | index 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 | +} |
1352 | diff --git a/src/core/archive.c b/src/core/archive.c |
1353 | new file mode 100644 |
1354 | index 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 ); |
1496 | diff --git a/src/core/base64.c b/src/core/base64.c |
1497 | index 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 | /** |
1509 | diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c |
1510 | index 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 */ |
1738 | diff --git a/src/core/console.c b/src/core/console.c |
1739 | index 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 | /** |
1765 | diff --git a/src/core/cpio.c b/src/core/cpio.c |
1766 | index 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 | +} |
1865 | diff --git a/src/core/image.c b/src/core/image.c |
1866 | index 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 | } |
1916 | diff --git a/src/core/open.c b/src/core/open.c |
1917 | index 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; |
1937 | diff --git a/src/core/settings.c b/src/core/settings.c |
1938 | index 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 | * |
1992 | diff --git a/src/core/string.c b/src/core/string.c |
1993 | index 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 | /** |
2038 | diff --git a/src/core/uri.c b/src/core/uri.c |
2039 | index 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 ); |
2328 | diff --git a/src/crypto/x509.c b/src/crypto/x509.c |
2329 | index 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 ) { |
2349 | diff --git a/src/drivers/bus/virtio-pci.c b/src/drivers/bus/virtio-pci.c |
2350 | index 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 | |
2474 | diff --git a/src/drivers/bus/virtio-ring.c b/src/drivers/bus/virtio-ring.c |
2475 | index 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++; |
2496 | diff --git a/src/drivers/net/ath/ath5k/ath5k_eeprom.c b/src/drivers/net/ath/ath5k/ath5k_eeprom.c |
2497 | index 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 | */ |
2510 | diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c |
2511 | index 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 | } |
2594 | diff --git a/src/drivers/net/bnxt/bnxt.h b/src/drivers/net/bnxt/bnxt.h |
2595 | index 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 | -}; |
2747 | diff --git a/src/drivers/net/ecm.c b/src/drivers/net/ecm.c |
2748 | index 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 ( ðernet_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; |
2815 | diff --git a/src/drivers/net/ecm.h b/src/drivers/net/ecm.h |
2816 | index 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 | |
2828 | diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c |
2829 | index 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", |
2841 | diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c |
2842 | index 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 ) ); |
2891 | diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c |
2892 | index 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 ), |
2921 | diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c |
2922 | index 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 | |
2933 | diff --git a/src/drivers/net/ncm.c b/src/drivers/net/ncm.c |
2934 | index 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; |
2946 | diff --git a/src/drivers/net/rdc.c b/src/drivers/net/rdc.c |
2947 | new file mode 100644 |
2948 | index 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 | +}; |
3646 | diff --git a/src/drivers/net/rdc.h b/src/drivers/net/rdc.h |
3647 | new file mode 100644 |
3648 | index 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 */ |
3846 | diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c |
3847 | index 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", |
3867 | diff --git a/src/drivers/net/virtio-net.c b/src/drivers/net/virtio-net.c |
3868 | index 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 ); |
3994 | diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c |
3995 | index 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 | |
4128 | diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h |
4129 | index 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; |
4141 | diff --git a/src/hci/commands/image_archive_cmd.c b/src/hci/commands/image_archive_cmd.c |
4142 | new file mode 100644 |
4143 | index 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 | +}; |
4252 | diff --git a/src/hci/readline.c b/src/hci/readline.c |
4253 | index 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 ); |
4317 | diff --git a/src/image/gzip.c b/src/image/gzip.c |
4318 | new file mode 100644 |
4319 | index 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 | +}; |
4490 | diff --git a/src/image/zlib.c b/src/image/zlib.c |
4491 | new file mode 100644 |
4492 | index 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 | +}; |
4659 | diff --git a/src/include/endian.h b/src/include/endian.h |
4660 | index 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 | |
4682 | diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h |
4683 | index 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 ) ); |
4697 | diff --git a/src/include/ipxe/acpimac.h b/src/include/ipxe/acpimac.h |
4698 | new file mode 100644 |
4699 | index 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 */ |
4717 | diff --git a/src/include/ipxe/cachedhcp.h b/src/include/ipxe/cachedhcp.h |
4718 | index 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 */ |
4736 | diff --git a/src/include/ipxe/cpio.h b/src/include/ipxe/cpio.h |
4737 | index 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 */ |
4775 | diff --git a/src/include/ipxe/dhcppkt.h b/src/include/ipxe/dhcppkt.h |
4776 | index 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 | } |
4788 | diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h |
4789 | index 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 | |
4800 | diff --git a/src/include/ipxe/efi/efi_wrap.h b/src/include/ipxe/efi/efi_wrap.h |
4801 | index 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 */ |
4813 | diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h |
4814 | index 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 ) |
4843 | diff --git a/src/include/ipxe/gzip.h b/src/include/ipxe/gzip.h |
4844 | new file mode 100644 |
4845 | index 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 */ |
4920 | diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h |
4921 | index 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 |
4957 | diff --git a/src/include/ipxe/rndis.h b/src/include/ipxe/rndis.h |
4958 | index 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 */ |
4979 | diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h |
4980 | index 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 | |
4991 | diff --git a/src/include/ipxe/srp.h b/src/include/ipxe/srp.h |
4992 | index 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 |
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.