diff options
author | peter <peter@FreeBSD.org> | 2002-07-20 03:51:53 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2002-07-20 03:51:53 +0000 |
commit | 3c805ef8bd61a3ab8eca8e44853ab0eb69df2192 (patch) | |
tree | da8ba722ee4dac361fb771e61064a3098ba09461 /sys | |
parent | 4af604d0520417bba59538b8ce875dec93a5e6fb (diff) | |
download | FreeBSD-src-3c805ef8bd61a3ab8eca8e44853ab0eb69df2192.zip FreeBSD-src-3c805ef8bd61a3ab8eca8e44853ab0eb69df2192.tar.gz |
Work around some nasty bugs on the [beta] Itanium2's E1000 UNDI driver.
Bug#1: The GetStatus() function returns radically different pointers that
do not match any packets we transmitted. I think it might be pointing to
a copy of the packet or something. Since we do not transmit more than
one packet at a time, just wait for "anything".
Bug#2: The Receive() function takes a pointer and a length. However, it
either ignores the length or otherwise does bad things and writes outside
of ptr[0] through ptr[len-1]. This is bad and causes massive stack
corruption for us since we are receiving packets into small buffers on
the stack. Instead, Receive() into a large enough buffer and bcopy the
data to the requested area.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/boot/efi/libefi/efinet.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/sys/boot/efi/libefi/efinet.c b/sys/boot/efi/libefi/efinet.c index 10b1721..f2a6ac4 100644 --- a/sys/boot/efi/libefi/efinet.c +++ b/sys/boot/efi/libefi/efinet.c @@ -102,10 +102,14 @@ efinet_put(struct iodesc *desc, void *pkt, size_t len) return -1; /* Wait for the buffer to be transmitted */ - buf = 0; /* XXX Is this needed? */ do { + buf = 0; /* XXX Is this needed? */ status = net->GetStatus(net, 0, &buf); - } while (status == EFI_SUCCESS && buf != pkt); + /* + * XXX EFI1.1 and the E1000 card returns a different + * address than we gave. Sigh. + */ + } while (status == EFI_SUCCESS && buf == 0); /* XXX How do we deal with status != EFI_SUCCESS now? */ return (status == EFI_SUCCESS) ? len : -1; @@ -120,15 +124,26 @@ efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) EFI_STATUS status; UINTN bufsz; time_t t; + char buf[2048]; net = nif->nif_devdata; t = time(0); while ((time(0) - t) < timeout) { - bufsz = len; - status = net->Receive(net, 0, &bufsz, pkt, 0, 0, 0); - if (status == EFI_SUCCESS) + bufsz = sizeof(buf); + status = net->Receive(net, 0, &bufsz, buf, 0, 0, 0); + if (status == EFI_SUCCESS) { + /* + * XXX EFI1.1 and the E1000 card trash our + * workspace if we do not do this silly copy. + * Either they are not respecting the len + * value or do not like the alignment. + */ + if (bufsz > len) + bufsz = len; + bcopy(buf, pkt, bufsz); return bufsz; + } if (status != EFI_NOT_READY) return 0; } |