ref: 16e08adb32778864035cc582c3a9163d3032ca4b
parent: e81e1a4aeddad2bc612c9c5243573250b6ff33a4
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Oct 23 19:11:49 EDT 2014
efi: add initial pxe support (v4 only)
--- a/sys/src/boot/efi/efi.c
+++ b/sys/src/boot/efi/efi.c
@@ -2,15 +2,14 @@
#include "fns.h"
#include "efi.h"
-enum {
- MAXPATH = 128,
-};
-
-UINTN MK;
+UINTN MK;
EFI_HANDLE IH;
EFI_SYSTEM_TABLE *ST;
-EFI_FILE_PROTOCOL *root;
+void* (*open)(char *name);
+int (*read)(void *f, void *data, int len);
+void (*close)(void *f);
+
void
putc(int c)
{
@@ -18,7 +17,7 @@
w[0] = c;
w[1] = 0;
- eficall(2, ST->ConOut->OutputString, ST->ConOut, w);
+ eficall(ST->ConOut->OutputString, ST->ConOut, w);
}
int
@@ -26,7 +25,7 @@
{
EFI_INPUT_KEY k;
- if(eficall(2, ST->ConIn->ReadKeyStroke, ST->ConIn, &k))
+ if(eficall(ST->ConIn->ReadKeyStroke, ST->ConIn, &k))
return 0;
return k.UnicodeChar;
}
@@ -34,79 +33,16 @@
void
usleep(int us)
{
- eficall(1, ST->BootServices->Stall, (UINTN)us);
+ eficall(ST->BootServices->Stall, (UINTN)us);
}
void
unload(void)
{
- eficall(2, ST->BootServices->ExitBootServices, IH, MK);
+ eficall(ST->BootServices->ExitBootServices, IH, MK);
}
-void
-fsinit(void)
-{
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
-
- fs = nil;
- root = nil;
- if(eficall(3, ST->BootServices->LocateProtocol,
- &EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, nil, &fs))
- return;
- if(eficall(2, fs->OpenVolume, fs, &root)){
- root = nil;
- return;
- }
-}
-
static void
-towpath(CHAR16 *w, int nw, char *s)
-{
- int i;
-
- for(i=0; *s && i<nw-1; i++){
- *w = *s++;
- if(*w == '/')
- *w = '\\';
- w++;
- }
- *w = 0;
-}
-
-EFI_FILE_PROTOCOL*
-fswalk(EFI_FILE_PROTOCOL *dir, char *name)
-{
- CHAR16 wname[MAXPATH];
- EFI_FILE_PROTOCOL *fp;
-
- towpath(wname, MAXPATH, name);
-
- fp = nil;
- if(eficall(5, dir->Open, dir, &fp, wname, (UINT64)1, (UINT64)1))
- return nil;
- return fp;
-}
-
-
-int
-read(void *f, void *data, int len)
-{
- UINTN size;
-
- size = len;
- if(eficall(3, ((EFI_FILE_PROTOCOL*)f)->Read, f, &size, data))
- return 0;
- return (int)size;
-}
-
-void
-close(void *f)
-{
- eficall(1, ((EFI_FILE_PROTOCOL*)f)->Close, f);
-}
-
-
-static void
memconf(char **cfg)
{
static uchar memtype[EfiMaxMemoryType] = {
@@ -134,7 +70,7 @@
mapsize = sizeof(mapbuf);
entsize = sizeof(EFI_MEMORY_DESCRIPTOR);
entvers = 1;
- if(eficall(5, ST->BootServices->GetMemoryMap, &mapsize, mapbuf, &MK, &entsize, &entvers))
+ if(eficall(ST->BootServices->GetMemoryMap, &mapsize, mapbuf, &MK, &entsize, &entvers))
return;
s = *cfg;
@@ -165,6 +101,16 @@
static void
acpiconf(char **cfg)
{
+ static EFI_GUID ACPI_20_TABLE_GUID = {
+ 0x8868e871, 0xe4f1, 0x11d3,
+ 0xbc, 0x22, 0x00, 0x80,
+ 0xc7, 0x3c, 0x88, 0x81,
+ };
+ static EFI_GUID ACPI_10_TABLE_GUID = {
+ 0xeb9d2d30, 0x2d88, 0x11d3,
+ 0x9a, 0x16, 0x00, 0x90,
+ 0x27, 0x3f, 0xc1, 0x4d,
+ };
EFI_CONFIGURATION_TABLE *t;
uintptr pa;
char *s;
@@ -220,6 +166,11 @@
static void
screenconf(char **cfg)
{
+ static EFI_GUID EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID = {
+ 0x9042a9de, 0x23dc, 0x4a38,
+ 0x96, 0xfb, 0x7a, 0xde,
+ 0xd0, 0x80, 0x51, 0x6a,
+ };
EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
EFI_HANDLE *Handles;
UINTN Count;
@@ -231,13 +182,13 @@
Count = 0;
Handles = nil;
- if(eficall(5, ST->BootServices->LocateHandleBuffer,
+ if(eficall(ST->BootServices->LocateHandleBuffer,
ByProtocol, &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, nil, &Count, &Handles))
return;
for(i=0; i<Count; i++){
gop = nil;
- if(eficall(3, ST->BootServices->HandleProtocol,
+ if(eficall(ST->BootServices->HandleProtocol,
Handles[i], &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, &gop))
continue;
@@ -331,7 +282,7 @@
}
EFI_STATUS
-main(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st)
+efimain(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st)
{
char path[MAXPATH], *kern;
void *f;
@@ -339,12 +290,13 @@
IH = ih;
ST = st;
- fsinit();
+ f = pxeinit();
+ if(f == nil)
+ f = fsinit();
- f = fswalk(root, "/plan9.ini");
for(;;){
kern = configure(f, path);
- f = fswalk(root, kern);
+ f = open(kern);
if(f == nil){
print("not found\n");
continue;
--- a/sys/src/boot/efi/efi.h
+++ b/sys/src/boot/efi/efi.h
@@ -4,6 +4,7 @@
typedef ushort UINT16;
typedef ulong UINT32;
typedef uvlong UINT64;
+typedef UINT8 BOOLEAN;
typedef uintptr UINTN;
@@ -87,41 +88,6 @@
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
} EFI_GRAPHICS_OUTPUT_PROTOCOL;
-EFI_GUID EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID = {
- 0x9042a9de, 0x23dc, 0x4a38,
- 0x96, 0xfb, 0x7a, 0xde,
- 0xd0, 0x80, 0x51, 0x6a,
-};
-
-typedef struct {
- UINT64 Revision;
- void *Open;
- void *Close;
- void *Delete;
- void *Read;
- void *Write;
- void *GetPosition;
- void *SetPosition;
- void *GetInfo;
- void *SetInfo;
- void *Flush;
- void *OpenEx;
- void *ReadEx;
- void *WriteEx;
- void *FlushEx;
-} EFI_FILE_PROTOCOL;
-
-typedef struct {
- UINT64 Revision;
- void *OpenVolume;
-} EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
-
-EFI_GUID EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID = {
- 0x0964e5b22, 0x6459, 0x11d2,
- 0x8e, 0x39, 0x00, 0xa0,
- 0xc9, 0x69, 0x72, 0x3b,
-};
-
enum {
EfiReservedMemoryType,
EfiLoaderCode,
@@ -243,19 +209,6 @@
void *QueryVariableInfo;
} EFI_RUNTIME_SERVICES;
-
-EFI_GUID ACPI_20_TABLE_GUID = {
- 0x8868e871, 0xe4f1, 0x11d3,
- 0xbc, 0x22, 0x00, 0x80,
- 0xc7, 0x3c, 0x88, 0x81,
-};
-
-EFI_GUID ACPI_10_TABLE_GUID = {
- 0xeb9d2d30, 0x2d88, 0x11d3,
- 0x9a, 0x16, 0x00, 0x90,
- 0x27, 0x3f, 0xc1, 0x4d,
-};
-
typedef struct {
EFI_GUID VendorGuid;
void *VendorTable;
@@ -282,3 +235,6 @@
UINTN NumberOfTableEntries;
EFI_CONFIGURATION_TABLE *ConfigurationTable;
} EFI_SYSTEM_TABLE;
+
+extern EFI_SYSTEM_TABLE *ST;
+extern EFI_HANDLE IH;
--- a/sys/src/boot/efi/fns.h
+++ b/sys/src/boot/efi/fns.h
@@ -1,11 +1,20 @@
+enum {
+ MAXPATH = 128,
+};
+
extern char hex[];
void usleep(int t);
void jump(void *pc);
-int read(void *f, void *data, int len);
+void* pxeinit(void);
+void* fsinit(void);
+
+void* (*open)(char *name);
+int (*read)(void *f, void *data, int len);
+void (*close)(void *f);
+
int readn(void *f, void *data, int len);
-void close(void *f);
void unload(void);
int getc(void);
@@ -25,5 +34,5 @@
char *hexfmt(char *s, int i, uvlong a);
char *decfmt(char *s, int i, ulong a);
-long eficall(long narg, void *proc, ...);
+uintptr eficall(void *proc, ...);
void eficonfig(char **cfg);
--- /dev/null
+++ b/sys/src/boot/efi/fs.c
@@ -1,0 +1,106 @@
+#include <u.h>
+#include "fns.h"
+#include "efi.h"
+
+typedef struct {
+ UINT64 Revision;
+ void *Open;
+ void *Close;
+ void *Delete;
+ void *Read;
+ void *Write;
+ void *GetPosition;
+ void *SetPosition;
+ void *GetInfo;
+ void *SetInfo;
+ void *Flush;
+ void *OpenEx;
+ void *ReadEx;
+ void *WriteEx;
+ void *FlushEx;
+} EFI_FILE_PROTOCOL;
+
+typedef struct {
+ UINT64 Revision;
+ void *OpenVolume;
+} EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
+
+static
+EFI_GUID EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID = {
+ 0x0964e5b22, 0x6459, 0x11d2,
+ 0x8e, 0x39, 0x00, 0xa0,
+ 0xc9, 0x69, 0x72, 0x3b,
+};
+
+static
+EFI_FILE_PROTOCOL *fsroot;
+
+static void
+towpath(CHAR16 *w, int nw, char *s)
+{
+ int i;
+
+ for(i=0; *s && i<nw-1; i++){
+ *w = *s++;
+ if(*w == '/')
+ *w = '\\';
+ w++;
+ }
+ *w = 0;
+}
+
+static void*
+fsopen(char *name)
+{
+ CHAR16 wname[MAXPATH];
+ EFI_FILE_PROTOCOL *fp;
+
+ if(fsroot == nil)
+ return nil;
+
+ towpath(wname, MAXPATH, name);
+
+ fp = nil;
+ if(eficall(fsroot->Open, fsroot, &fp, wname, (UINT64)1, (UINT64)1))
+ return nil;
+ return fp;
+}
+
+static int
+fsread(void *f, void *data, int len)
+{
+ UINTN size;
+
+ size = len;
+ if(eficall(((EFI_FILE_PROTOCOL*)f)->Read, f, &size, data))
+ return 0;
+ return (int)size;
+}
+
+static void
+fsclose(void *f)
+{
+ eficall(((EFI_FILE_PROTOCOL*)f)->Close, f);
+}
+
+void*
+fsinit(void)
+{
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
+
+ fs = nil;
+ fsroot = nil;
+ if(eficall(ST->BootServices->LocateProtocol,
+ &EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, nil, &fs))
+ return nil;
+ if(eficall(fs->OpenVolume, fs, &fsroot)){
+ fsroot = nil;
+ return nil;
+ }
+
+ read = fsread;
+ close = fsclose;
+ open = fsopen;
+
+ return fsopen("/plan9.ini");
+}
--- a/sys/src/boot/efi/mkfile
+++ b/sys/src/boot/efi/mkfile
@@ -13,7 +13,7 @@
clean:V:
rm -f *.[68] *.out $TARG
-bootia32.efi: pe32.8 efi.8 sub.8
+bootia32.efi: pe32.8 efi.8 fs.8 pxe.8 sub.8
8l -l -H3 -T$IMAGEBASE -o $target $prereq
pe32.8: pe32.s
@@ -22,6 +22,12 @@
efi.8: efi.c efi.h
8c $CFLAGS efi.c
+fs.8: fs.c efi.h
+ 8c $CFLAGS fs.c
+
+pxe.8: pxe.c efi.h
+ 8c $CFLAGS pxe.c
+
sub.8: sub.c
8c $CFLAGS sub.c
@@ -28,7 +34,7 @@
%.8: $HFILES
-bootx64.efi: pe64.6 efi.6 sub.6
+bootx64.efi: pe64.6 efi.6 fs.6 pxe.6 sub.6
6l -l -s -R1 -T$IMAGEBASE -o bootx64.out $prereq
dd -if bootx64.out -bs 1 -iseek 40 >$target
@@ -37,6 +43,12 @@
efi.6: efi.c efi.h
6c $CFLAGS efi.c
+
+fs.6: fs.c efi.h
+ 6c $CFLAGS fs.c
+
+pxe.6: pxe.c efi.h
+ 6c $CFLAGS pxe.c
sub.6: sub.c
6c $CFLAGS sub.c
--- a/sys/src/boot/efi/pe32.s
+++ b/sys/src/boot/efi/pe32.s
@@ -129,7 +129,7 @@
MOVL $edata-IMAGEBASE(SB), CX
CLD
REP; MOVSB
- MOVL $main(SB), DI
+ MOVL $efimain(SB), DI
MOVL DI, (SP)
RET
@@ -138,12 +138,22 @@
MOVL 4(SP), AX
JMP *AX
-
TEXT eficall(SB), 1, $0
- MOVL 0(SP), DI /* saved by callee */
- MOVL 8(SP), AX
- ADDL $12, SP
+ MOVL SP, SI
+ MOVL SP, DI
+ MOVL $(4*16), CX
+ SUBL CX, DI
+ ANDL $~15ULL, DI
+ SUBL $8, DI
+
+ MOVL 4(SI), AX
+ LEAL 8(DI), SP
+
+ CLD
+ REP; MOVSB
+ SUBL $(4*16), SI
+
CALL AX
- SUBL $12, SP
- MOVL DI, 0(SP)
+
+ MOVL SI, SP
RET
--- a/sys/src/boot/efi/pe64.s
+++ b/sys/src/boot/efi/pe64.s
@@ -136,25 +136,28 @@
REP; MOVSB
MOVQ 16(SP), BP
- MOVQ $main(SB), DI
+ MOVQ $efimain(SB), DI
MOVQ DI, (SP)
RET
TEXT eficall(SB), 1, $-4
- MOVQ 0(SP), DI /* saved by callee */
- MOVQ 16(SP), AX
- ADDQ $24, SP
+ MOVQ SP, SI
+ MOVQ SP, DI
+ MOVL $(8*16), CX
+ SUBQ CX, DI
+ ANDQ $~15ULL, DI
+ LEAQ 16(DI), SP
+ CLD
+ REP; MOVSB
+ SUBQ $(8*16), SI
- /* arguments in regisyers */
MOVQ 0(SP), CX
MOVQ 8(SP), DX
MOVQ 16(SP), R8
MOVQ 24(SP), R9
+ CALL BP
- CALL AX
-
- SUBQ $24, SP
- MOVQ DI, 0(SP)
+ MOVQ SI, SP
RET
#include "mem.h"
--- /dev/null
+++ b/sys/src/boot/efi/pxe.c
@@ -1,0 +1,359 @@
+#include <u.h>
+#include "fns.h"
+#include "efi.h"
+
+typedef UINT16 EFI_PXE_BASE_CODE_UDP_PORT;
+
+typedef struct {
+ UINT8 Addr[4];
+} EFI_IPv4_ADDRESS;
+
+typedef struct {
+ UINT8 Addr[16];
+} EFI_IPv6_ADDRESS;
+
+typedef union {
+ UINT32 Addr[4];
+ EFI_IPv4_ADDRESS v4;
+ EFI_IPv6_ADDRESS v6;
+} EFI_IP_ADDRESS;
+
+typedef struct {
+ UINT8 Addr[32];
+} EFI_MAC_ADDRESS;
+
+typedef struct {
+ UINT8 BootpOpcode;
+ UINT8 BootpHwType;
+ UINT8 BootpHwAddrLen;
+ UINT8 BootpGateHops;
+ UINT32 BootpIdent;
+ UINT16 BootpSeconds;
+ UINT16 BootpFlags;
+ UINT8 BootpCiAddr[4];
+ UINT8 BootpYiAddr[4];
+ UINT8 BootpSiAddr[4];
+ UINT8 BootpGiAddr[4];
+ UINT8 BootpHwAddr[16];
+ UINT8 BootpSrvName[64];
+ UINT8 BootpBootFile[128];
+ UINT32 DhcpMagik;
+ UINT8 DhcpOptions[56];
+} EFI_PXE_BASE_CODE_DHCPV4_PACKET;
+
+typedef struct {
+ BOOLEAN Started;
+ BOOLEAN Ipv6Available;
+ BOOLEAN Ipv6Supported;
+ BOOLEAN UsingIpv6;
+ BOOLEAN BisSupported;
+ BOOLEAN BisDetected;
+ BOOLEAN AutoArp;
+ BOOLEAN SendGUID;
+ BOOLEAN DhcpDiscoverValid;
+ BOOLEAN DhcpAckReceived;
+ BOOLEAN ProxyOfferReceived;
+ BOOLEAN PxeDiscoverValid;
+ BOOLEAN PxeReplyReceived;
+ BOOLEAN PxeBisReplyReceived;
+ BOOLEAN IcmpErrorReceived;
+ BOOLEAN TftpErrorReceived;
+ BOOLEAN MakeCallbacks;
+
+ UINT8 TTL;
+ UINT8 ToS;
+
+ UINT8 Reserved;
+
+ UINT8 StationIp[16];
+ UINT8 SubnetMask[16];
+
+ UINT8 DhcpDiscover[1472];
+ UINT8 DhcpAck[1472];
+} EFI_PXE_BASE_CODE_MODE;
+
+typedef struct {
+ UINT64 Revision;
+ void *Start;
+ void *Stop;
+ void *Dhcp;
+ void *Discover;
+ void *Mtftp;
+ void *UdpWrite;
+ void *UdpRead;
+ void *SetIpFilter;
+ void *Arp;
+ void *SetParameters;
+ void *SetStationIp;
+ void *SetPackets;
+ EFI_PXE_BASE_CODE_MODE *Mode;
+} EFI_PXE_BASE_CODE_PROTOCOL;
+
+
+enum {
+ Tftp_READ = 1,
+ Tftp_WRITE = 2,
+ Tftp_DATA = 3,
+ Tftp_ACK = 4,
+ Tftp_ERROR = 5,
+ Tftp_OACK = 6,
+
+ TftpPort = 69,
+
+ Segsize = 512,
+};
+
+static
+EFI_GUID EFI_PXE_BASE_CODE_PROTOCOL_GUID = {
+ 0x03C4E603, 0xAC28, 0x11D3,
+ 0x9A, 0x2D, 0x00, 0x90,
+ 0x27, 0x3F, 0xC1, 0x4D,
+};
+
+static
+EFI_PXE_BASE_CODE_PROTOCOL *pxe;
+
+static
+EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp;
+
+typedef struct Tftp Tftp;
+struct Tftp
+{
+ EFI_IP_ADDRESS sip;
+ EFI_IP_ADDRESS dip;
+
+ EFI_PXE_BASE_CODE_UDP_PORT sport;
+ EFI_PXE_BASE_CODE_UDP_PORT dport;
+
+ char *rp;
+ char *ep;
+
+ int seq;
+ int eof;
+
+ char pkt[2+2+Segsize];
+ char nul;
+};
+
+static void
+puts(void *x, ushort v)
+{
+ uchar *p = x;
+
+ p[1] = (v>>8) & 0xFF;
+ p[0] = v & 0xFF;
+}
+
+static ushort
+gets(void *x)
+{
+ uchar *p = x;
+
+ return p[1]<<8 | p[0];
+}
+
+static void
+hnputs(void *x, ushort v)
+{
+ uchar *p = x;
+
+ p[0] = (v>>8) & 0xFF;
+ p[1] = v & 0xFF;
+}
+
+static ushort
+nhgets(void *x)
+{
+ uchar *p = x;
+
+ return p[0]<<8 | p[1];
+}
+
+enum {
+ ANY_SRC_IP = 0x0001,
+ ANY_SRC_PORT = 0x0002,
+ ANY_DEST_IP = 0x0004,
+ ANY_DEST_PORT = 0x0008,
+ USE_FILTER = 0x0010,
+ MAY_FRAGMENT = 0x0020,
+};
+
+static int
+udpread(EFI_IP_ADDRESS *sip, EFI_IP_ADDRESS *dip,
+ EFI_PXE_BASE_CODE_UDP_PORT *sport,
+ EFI_PXE_BASE_CODE_UDP_PORT dport,
+ int *len, void *data)
+{
+ UINTN size;
+
+ size = *len;
+ if(eficall(pxe->UdpRead, pxe, (UINTN)ANY_SRC_PORT, dip, &dport, sip, sport, nil, nil, &size, data))
+ return -1;
+
+ *len = size;
+ return 0;
+}
+
+static int
+udpwrite(EFI_IP_ADDRESS *dip,
+ EFI_PXE_BASE_CODE_UDP_PORT sport,
+ EFI_PXE_BASE_CODE_UDP_PORT dport,
+ int len, void *data)
+{
+ UINTN size;
+
+ size = len;
+ if(eficall(pxe->UdpWrite, pxe, (UINTN)MAY_FRAGMENT, dip, &dport, nil, nil, &sport, nil, nil, &size, data))
+ return -1;
+
+ return 0;
+}
+
+static int
+pxeread(void *f, void *data, int len)
+{
+ Tftp *t = f;
+ int seq, n;
+
+ while(!t->eof && t->rp >= t->ep){
+ for(;;){
+ n = sizeof(t->pkt);
+ if(udpread(&t->dip, &t->sip, &t->dport, t->sport, &n, t->pkt))
+ continue;
+ if(n >= 4)
+ break;
+ }
+ switch(nhgets(t->pkt)){
+ case Tftp_DATA:
+ seq = nhgets(t->pkt+2);
+ if(seq > t->seq){
+ putc('?');
+ continue;
+ }
+ hnputs(t->pkt, Tftp_ACK);
+ while(udpwrite(&t->dip, t->sport, t->dport, 4, t->pkt))
+ putc('!');
+ if(seq < t->seq){
+ putc('@');
+ continue;
+ }
+ t->seq = seq+1;
+ n -= 4;
+ t->rp = t->pkt + 4;
+ t->ep = t->rp + n;
+ t->eof = n < Segsize;
+ break;
+ case Tftp_ERROR:
+ print(t->pkt+4);
+ print("\n");
+ default:
+ t->eof = 1;
+ return -1;
+ }
+ break;
+ }
+ n = t->ep - t->rp;
+ if(len > n)
+ len = n;
+ memmove(data, t->rp, len);
+ t->rp += len;
+ return len;
+}
+
+static void
+pxeclose(void *f)
+{
+ Tftp *t = f;
+ t->eof = 1;
+}
+
+
+static int
+tftpopen(Tftp *t, char *path)
+{
+ static EFI_PXE_BASE_CODE_UDP_PORT xport = 6666;
+ int r, n;
+ char *p;
+
+ t->sport = xport++;
+ t->dport = 0;
+ t->rp = t->ep = 0;
+ t->seq = 1;
+ t->eof = 0;
+ t->nul = 0;
+ p = t->pkt;
+ hnputs(p, Tftp_READ); p += 2;
+ n = strlen(path)+1;
+ memmove(p, path, n); p += n;
+ memmove(p, "octet", 6); p += 6;
+ n = p - t->pkt;
+ for(;;){
+ if(r = udpwrite(&t->dip, t->sport, TftpPort, n, t->pkt))
+ break;
+ if(r = pxeread(t, 0, 0))
+ break;
+ return 0;
+ }
+ pxeclose(t);
+ return r;
+}
+
+static void*
+pxeopen(char *name)
+{
+ static Tftp t[1];
+
+ memset(t, 0, sizeof(Tftp));
+
+ memmove(&t->dip, dhcp->BootpSiAddr, 4);
+ memmove(&t->sip, pxe->Mode->StationIp, 4);
+
+ if(tftpopen(t, name) == 0)
+ return t;
+ return nil;
+}
+
+void*
+pxeinit(void)
+{
+ EFI_HANDLE *Handles;
+ UINTN Count;
+ char ini[24];
+ uchar *mac;
+ void *f;
+ int i;
+
+ pxe = nil;
+ dhcp = nil;
+ Count = 0;
+ Handles = nil;
+ if(eficall(ST->BootServices->LocateHandleBuffer,
+ ByProtocol, &EFI_PXE_BASE_CODE_PROTOCOL_GUID, nil, &Count, &Handles))
+ return nil;
+
+ for(i=0; i<Count; i++){
+ pxe = nil;
+ if(eficall(ST->BootServices->HandleProtocol,
+ Handles[i], &EFI_PXE_BASE_CODE_PROTOCOL_GUID, &pxe))
+ continue;
+ if(pxe->Mode != nil && pxe->Mode->Started)
+ break;
+ }
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET*)pxe->Mode->DhcpAck;
+
+ mac = dhcp->BootpHwAddr;
+ memmove(ini, "/cfg/pxe/", 9);
+ for(i=0; i<6; i++){
+ ini[9+i*2+0] = hex[mac[i] >> 4];
+ ini[9+i*2+1] = hex[mac[i] & 0xF];
+ }
+ ini[9+12] = '\0';
+
+ open = pxeopen;
+ read = pxeread;
+ close = pxeclose;
+
+ if((f = pxeopen(ini)) != nil)
+ return f;
+ return pxeopen("/cfg/pxe/default");
+}