diff options
author | H. Peter Anvin <hpa@zytor.com> | 2014-06-16 20:25:02 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2014-06-16 20:25:02 -0700 |
commit | 44e01ff5852eae227e84b7ac3b4d7a7bf8574c3c (patch) | |
tree | 9bbfb71f6cefcfc58bf822b25c406275a267201b /utils | |
parent | 191e622cdd85271783682ff38f4c307b89cfe040 (diff) | |
download | syslinux-44e01ff5852eae227e84b7ac3b4d7a7bf8574c3c.tar.gz syslinux-44e01ff5852eae227e84b7ac3b4d7a7bf8574c3c.tar.xz syslinux-44e01ff5852eae227e84b7ac3b4d7a7bf8574c3c.zip |
pxe: Add support for embedded options in EFIsyslinux-6.03-pre16
For EFI, rather than mucking with the PECOFF or ELF headers (we have
both!) just use a fixed-size buffer embedded in the image with a large
magic number that can be scanned for safely.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'utils')
-rwxr-xr-x | utils/pxelinux-options | 101 |
1 files changed, 78 insertions, 23 deletions
diff --git a/utils/pxelinux-options b/utils/pxelinux-options index ab7075b5..dfd98cf1 100755 --- a/utils/pxelinux-options +++ b/utils/pxelinux-options @@ -199,21 +199,56 @@ sub read_optsets($) my($file) = @_; my $data, $bdata, $adata; my $patch_start = (stat($file))[7]; + my $hdroffset = 0; # 0 means non-deep-embedded + my $bufsize = 0; + my $junk; + my %hdr; - return undef unless (seek($file, 8, SEEK_SET)); - return undef unless (read($file, $data, 7*4) == 7*4); + return undef unless (seek($file, 0, SEEK_SET)); + return undef unless (read($file, $data, 48) == 48); - my($magic, $len, $flags, $boff, $blen, $aoff, $alen) - = unpack("VVVVVVV", $data); - return undef if ($magic != 0x2983c8ac); - return undef if ($len < 7*4); + my($mzmagic, $junk, $magic, $len, $flags, $boff, $blen, $aoff, $alen) + = unpack("va[6]VVVVVVV", $data); + + if ($mzmagic == 0x5a4d) { + # It is an EFI file... search for the magic number + $hdroffset = 48; + my $magic = pack("VVVV", 0x2a171ead, 0x0600e65e, + 0x4025a4e4, 0x42388fc8); + + while (1) { + return undef unless (read($file, $data, 16) == 16); + last if ($data eq $magic); + + $hdroffset += 16; + } + + return undef unless (read($file, $data, 16) == 16); + ($blen, $alen, $bufsize, $junk) = unpack("VVVV", $data); + + printf STDERR "EFI: offset = 0x%x, blen = %d, alen = %d, bufsize = %d\n", $hdroffset, $blen, $alen, $bufsize; + + $patch_start = $boff = $hdroffset + 32; + $aoff = $boff + $blen; + + $hdr{'deep'} = 1; + $hdr{'bufsize'} = $bufsize; + $hdr{'hdroffset'} = $hdroffset; + } else { + # It is a BIOS PXE file + + return undef if ($magic != 0x2983c8ac); + return undef if ($len < 7*4); + + $hdr{'deep'} = 0; + } if ($blen == 0) { $bdata = ''; } else { return undef unless (seek($file, $boff, SEEK_SET)); return undef unless (read($file, $bdata, $blen) == $blen); - $patch_start = $boff if ($boff < $patch_start); + $patch_start = $boff if ($boff < patch_start); } if ($alen == 0) { @@ -224,37 +259,57 @@ sub read_optsets($) $patch_start = $aoff if ($aoff < $patch_start); } - return ($patch_start, $bdata, $adata); + $hdr{'patch_start'} = $patch_start; + + return (\%hdr, $bdata, $adata); } -sub write_optsets($$@) +sub write_optsets($$$@) { - my($file, $patch_start, $bdata, $adata) = @_; + my($file, $hdr, $bdata, $adata) = @_; my $boff = 0; my $aoff = 0; + my $bufsize = 0; + my $patch_start = $hdr->{'patch_start'}; + my $len; + + $bdata .= "\xff" unless ($bdata eq ''); + $adata .= "\xff" unless ($adata eq ''); + + $len = length($bdata) + length($adata); + + if (defined($hdr->{'bufsize'})) { + return undef unless ($len <= $hdr->{'bufsize'}); + } + + return undef unless (seek($file, $patch_start, SEEK_SET)); - if (length($bdata) > 0) { - $bdata .= "\xff"; + if (length($bdata)) { $boff = $patch_start; - return undef unless (seek($file, $boff, SEEK_SET)); return undef unless (print $file $bdata); $patch_start += length($bdata); } - if (length($adata) > 0) { - $adata .= "\xff"; + if (length($adata)) { $aoff = $patch_start; - return undef unless (seek($file, $aoff, SEEK_SET)); return undef unless (print $file $adata); $patch_start += length($adata); } - my $hdr = pack("VVVV", $boff, length($bdata), $aoff, length($adata)); + if ($hdr->{'deep'}) { + return undef unless (print $file "\0" x ($hdr->{'bufsize'} - $len)); + return undef unless (seek($file, $hdr->{'hdroffset'} + 16, SEEK_SET)); + my $hdr = pack("VV", length($bdata), length($adata)); + return undef unless (print $file $hdr); + } else { + my $hdr = pack("VVVV", $boff, length($bdata), $aoff, length($adata)); - return undef unless (seek($file, 8+3*4, SEEK_SET)); - return undef unless (print $file $hdr); + return undef unless (seek($file, 8+3*4, SEEK_SET)); + return undef unless (print $file $hdr); + + truncate($file, $patch_start); + } - truncate($file, $patch_start); return 1; } @@ -468,8 +523,8 @@ $mode = $no_write ? '<' : '+<'; open(FILE, $mode, $file) or die "$0: cannot open: $file: $!\n"; -($patch_start, @data) = read_optsets(\*FILE); -if (!defined($patch_start)) { +($hdrinfo, @data) = read_optsets(\*FILE); +if (!defined($hdrinfo)) { die "$0: $file: patch block not found or file corrupt\n"; } @@ -490,7 +545,7 @@ if ($list) { } if (!$no_write) { - if (!write_optsets(\*FILE, $patch_start, @data)) { + if (!write_optsets(\*FILE, $hdrinfo, @data)) { die "$0: $file: failed to write options: $!\n"; } } |