aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2014-06-16 20:25:02 -0700
committerH. Peter Anvin <hpa@zytor.com>2014-06-16 20:25:02 -0700
commit44e01ff5852eae227e84b7ac3b4d7a7bf8574c3c (patch)
tree9bbfb71f6cefcfc58bf822b25c406275a267201b
parent191e622cdd85271783682ff38f4c307b89cfe040 (diff)
downloadsyslinux-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>
-rw-r--r--efi/pxe.c35
-rwxr-xr-xutils/pxelinux-options101
2 files changed, 113 insertions, 23 deletions
diff --git a/efi/pxe.c b/efi/pxe.c
index 62fddb08..0c9fb06a 100644
--- a/efi/pxe.c
+++ b/efi/pxe.c
@@ -65,6 +65,28 @@ int pxe_init(bool quiet)
return 0;
}
+#define EDHCP_BUF_LEN 8192
+
+struct embedded_dhcp_options {
+ uint32_t magic[4];
+ uint32_t bdhcp_len;
+ uint32_t adhcp_len;
+ uint32_t buffer_size;
+ uint32_t reserved;
+ uint8_t dhcp_data[EDHCP_BUF_LEN];
+} __attribute__((aligned(16)));
+
+struct embedded_dhcp_options embedded_dhcp_options =
+{
+ .magic[0] = 0x2a171ead,
+ .magic[1] = 0x0600e65e,
+ .magic[2] = 0x4025a4e4,
+ .magic[3] = 0x42388fc8,
+ .bdhcp_len = 0,
+ .adhcp_len = 0,
+ .buffer_size = EDHCP_BUF_LEN,
+};
+
void net_parse_dhcp(void)
{
EFI_PXE_BASE_CODE_MODE *mode;
@@ -92,6 +114,12 @@ void net_parse_dhcp(void)
mode = bc->Mode;
/*
+ * Parse any "before" hardcoded options
+ */
+ parse_dhcp_options(embedded_dhcp_options.dhcp_data,
+ embedded_dhcp_options.bdhcp_len, 0);
+
+ /*
* Get the DHCP client identifiers (query info 1)
*/
Print(L"Getting cached packet ");
@@ -129,6 +157,13 @@ void net_parse_dhcp(void)
parse_dhcp(&mode->PxeReply.Dhcpv4, pkt_len);
Print(L"\n");
+ /*
+ * Parse any "after" hardcoded options
+ */
+ parse_dhcp_options(embedded_dhcp_options.dhcp_data +
+ embedded_dhcp_options.bdhcp_len,
+ embedded_dhcp_options.adhcp_len, 0);
+
ip = IPInfo.myip;
sprintf(dst, "%u.%u.%u.%u",
((const uint8_t *)&ip)[0],
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";
}
}