efi: add initial pxe support (v4 only)

This commit is contained in:
cinap_lenrek 2014-10-23 23:11:49 +02:00
parent e81e1a4aed
commit 16e08adb32
8 changed files with 555 additions and 148 deletions

View file

@ -2,14 +2,13 @@
#include "fns.h" #include "fns.h"
#include "efi.h" #include "efi.h"
enum {
MAXPATH = 128,
};
UINTN MK; UINTN MK;
EFI_HANDLE IH; EFI_HANDLE IH;
EFI_SYSTEM_TABLE *ST; 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 void
putc(int c) putc(int c)
@ -18,7 +17,7 @@ putc(int c)
w[0] = c; w[0] = c;
w[1] = 0; w[1] = 0;
eficall(2, ST->ConOut->OutputString, ST->ConOut, w); eficall(ST->ConOut->OutputString, ST->ConOut, w);
} }
int int
@ -26,7 +25,7 @@ getc(void)
{ {
EFI_INPUT_KEY k; EFI_INPUT_KEY k;
if(eficall(2, ST->ConIn->ReadKeyStroke, ST->ConIn, &k)) if(eficall(ST->ConIn->ReadKeyStroke, ST->ConIn, &k))
return 0; return 0;
return k.UnicodeChar; return k.UnicodeChar;
} }
@ -34,78 +33,15 @@ getc(void)
void void
usleep(int us) usleep(int us)
{ {
eficall(1, ST->BootServices->Stall, (UINTN)us); eficall(ST->BootServices->Stall, (UINTN)us);
} }
void void
unload(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 static void
memconf(char **cfg) memconf(char **cfg)
{ {
@ -134,7 +70,7 @@ memconf(char **cfg)
mapsize = sizeof(mapbuf); mapsize = sizeof(mapbuf);
entsize = sizeof(EFI_MEMORY_DESCRIPTOR); entsize = sizeof(EFI_MEMORY_DESCRIPTOR);
entvers = 1; entvers = 1;
if(eficall(5, ST->BootServices->GetMemoryMap, &mapsize, mapbuf, &MK, &entsize, &entvers)) if(eficall(ST->BootServices->GetMemoryMap, &mapsize, mapbuf, &MK, &entsize, &entvers))
return; return;
s = *cfg; s = *cfg;
@ -165,6 +101,16 @@ memconf(char **cfg)
static void static void
acpiconf(char **cfg) 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; EFI_CONFIGURATION_TABLE *t;
uintptr pa; uintptr pa;
char *s; char *s;
@ -220,6 +166,11 @@ lowbit(ulong mask)
static void static void
screenconf(char **cfg) 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_GRAPHICS_OUTPUT_PROTOCOL *gop;
EFI_HANDLE *Handles; EFI_HANDLE *Handles;
UINTN Count; UINTN Count;
@ -231,13 +182,13 @@ screenconf(char **cfg)
Count = 0; Count = 0;
Handles = nil; Handles = nil;
if(eficall(5, ST->BootServices->LocateHandleBuffer, if(eficall(ST->BootServices->LocateHandleBuffer,
ByProtocol, &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, nil, &Count, &Handles)) ByProtocol, &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, nil, &Count, &Handles))
return; return;
for(i=0; i<Count; i++){ for(i=0; i<Count; i++){
gop = nil; gop = nil;
if(eficall(3, ST->BootServices->HandleProtocol, if(eficall(ST->BootServices->HandleProtocol,
Handles[i], &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, &gop)) Handles[i], &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, &gop))
continue; continue;
@ -331,7 +282,7 @@ eficonfig(char **cfg)
} }
EFI_STATUS EFI_STATUS
main(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st) efimain(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st)
{ {
char path[MAXPATH], *kern; char path[MAXPATH], *kern;
void *f; void *f;
@ -339,12 +290,13 @@ main(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st)
IH = ih; IH = ih;
ST = st; ST = st;
fsinit(); f = pxeinit();
if(f == nil)
f = fsinit();
f = fswalk(root, "/plan9.ini");
for(;;){ for(;;){
kern = configure(f, path); kern = configure(f, path);
f = fswalk(root, kern); f = open(kern);
if(f == nil){ if(f == nil){
print("not found\n"); print("not found\n");
continue; continue;

View file

@ -4,6 +4,7 @@ typedef uchar UINT8;
typedef ushort UINT16; typedef ushort UINT16;
typedef ulong UINT32; typedef ulong UINT32;
typedef uvlong UINT64; typedef uvlong UINT64;
typedef UINT8 BOOLEAN;
typedef uintptr UINTN; typedef uintptr UINTN;
@ -87,41 +88,6 @@ typedef struct {
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
} EFI_GRAPHICS_OUTPUT_PROTOCOL; } 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 { enum {
EfiReservedMemoryType, EfiReservedMemoryType,
EfiLoaderCode, EfiLoaderCode,
@ -243,19 +209,6 @@ typedef struct {
void *QueryVariableInfo; void *QueryVariableInfo;
} EFI_RUNTIME_SERVICES; } 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 { typedef struct {
EFI_GUID VendorGuid; EFI_GUID VendorGuid;
void *VendorTable; void *VendorTable;
@ -282,3 +235,6 @@ typedef struct {
UINTN NumberOfTableEntries; UINTN NumberOfTableEntries;
EFI_CONFIGURATION_TABLE *ConfigurationTable; EFI_CONFIGURATION_TABLE *ConfigurationTable;
} EFI_SYSTEM_TABLE; } EFI_SYSTEM_TABLE;
extern EFI_SYSTEM_TABLE *ST;
extern EFI_HANDLE IH;

View file

@ -1,11 +1,20 @@
enum {
MAXPATH = 128,
};
extern char hex[]; extern char hex[];
void usleep(int t); void usleep(int t);
void jump(void *pc); 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); int readn(void *f, void *data, int len);
void close(void *f);
void unload(void); void unload(void);
int getc(void); int getc(void);
@ -25,5 +34,5 @@ char *bootkern(void *f);
char *hexfmt(char *s, int i, uvlong a); char *hexfmt(char *s, int i, uvlong a);
char *decfmt(char *s, int i, ulong a); char *decfmt(char *s, int i, ulong a);
long eficall(long narg, void *proc, ...); uintptr eficall(void *proc, ...);
void eficonfig(char **cfg); void eficonfig(char **cfg);

106
sys/src/boot/efi/fs.c Normal file
View file

@ -0,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");
}

View file

@ -13,7 +13,7 @@ install:V: $TARG
clean:V: clean:V:
rm -f *.[68] *.out $TARG 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 8l -l -H3 -T$IMAGEBASE -o $target $prereq
pe32.8: pe32.s pe32.8: pe32.s
@ -22,13 +22,19 @@ pe32.8: pe32.s
efi.8: efi.c efi.h efi.8: efi.c efi.h
8c $CFLAGS efi.c 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 sub.8: sub.c
8c $CFLAGS sub.c 8c $CFLAGS sub.c
%.8: $HFILES %.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 6l -l -s -R1 -T$IMAGEBASE -o bootx64.out $prereq
dd -if bootx64.out -bs 1 -iseek 40 >$target dd -if bootx64.out -bs 1 -iseek 40 >$target
@ -38,6 +44,12 @@ pe64.6: pe64.s
efi.6: efi.c efi.h efi.6: efi.c efi.h
6c $CFLAGS efi.c 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 sub.6: sub.c
6c $CFLAGS sub.c 6c $CFLAGS sub.c

View file

@ -129,7 +129,7 @@ TEXT reloc(SB), 1, $0
MOVL $edata-IMAGEBASE(SB), CX MOVL $edata-IMAGEBASE(SB), CX
CLD CLD
REP; MOVSB REP; MOVSB
MOVL $main(SB), DI MOVL $efimain(SB), DI
MOVL DI, (SP) MOVL DI, (SP)
RET RET
@ -138,12 +138,22 @@ TEXT jump(SB), $0
MOVL 4(SP), AX MOVL 4(SP), AX
JMP *AX JMP *AX
TEXT eficall(SB), 1, $0 TEXT eficall(SB), 1, $0
MOVL 0(SP), DI /* saved by callee */ MOVL SP, SI
MOVL 8(SP), AX MOVL SP, DI
ADDL $12, SP 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 CALL AX
SUBL $12, SP
MOVL DI, 0(SP) MOVL SI, SP
RET RET

View file

@ -136,25 +136,28 @@ TEXT reloc(SB), 1, $-4
REP; MOVSB REP; MOVSB
MOVQ 16(SP), BP MOVQ 16(SP), BP
MOVQ $main(SB), DI MOVQ $efimain(SB), DI
MOVQ DI, (SP) MOVQ DI, (SP)
RET RET
TEXT eficall(SB), 1, $-4 TEXT eficall(SB), 1, $-4
MOVQ 0(SP), DI /* saved by callee */ MOVQ SP, SI
MOVQ 16(SP), AX MOVQ SP, DI
ADDQ $24, SP 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 0(SP), CX
MOVQ 8(SP), DX MOVQ 8(SP), DX
MOVQ 16(SP), R8 MOVQ 16(SP), R8
MOVQ 24(SP), R9 MOVQ 24(SP), R9
CALL BP
CALL AX MOVQ SI, SP
SUBQ $24, SP
MOVQ DI, 0(SP)
RET RET
#include "mem.h" #include "mem.h"

359
sys/src/boot/efi/pxe.c Normal file
View file

@ -0,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");
}