2 * Copyright (C) 2001-2009 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
4 * Contributed by Jason Fleischli <jason.fleischli@hp.com>
5 * Copyright (C) 2006-2009 Intel Corporation
6 * Contributed by Fenghua Yu <fenghua.yu@intel.com>
7 * Contributed by Bibo Mao <bibo.mao@intel.com>
8 * Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
10 * This file is part of the ELILO, the EFI Linux boot loader.
12 * ELILO is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2, or (at your option)
17 * ELILO is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with ELILO; see the file COPYING. If not, write to the Free
24 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
27 * Please check out the elilo.txt for complete documentation on how
28 * to use this program.
38 #define FS_NAME L"netfs"
40 #define NETFS_DEFAULT_BUFSIZE 16*MB
41 #define NETFS_DEFAULT_BUFSIZE_INC 8*MB
42 #define NETFS_DEFAULT_BLOCKSIZE 1024 /* setting to zero is supposed to default the underlying */
43 /* pxe implementation to largest blocksize supported,... */
44 /* in reality on original older efi implementations its */
45 /* never set causing the pxe transfer to timeout. */
46 /* the spec defines the minimum supported blocksize default */
47 /* to be 512 bytes... a bit extreme, 1024 should work for */
50 #define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
51 #define NETFS_FD_MAX 2
53 typedef struct _netfs_fd {
54 struct _netfs_fd *next;
57 UINT64 netbuf_maxsize; /* currently allocated buffer */
58 UINTN netbuf_size; /* number of bytes currently used in the buffer */
59 UINT64 netbuf_pos; /* current position in the buffer */
60 BOOLEAN is_valid; /* avoid conflicting opens */
63 CHAR16 last_file[FILENAME_MAXLEN];
68 EFI_PXE_BASE_CODE *pxe;
69 EFI_HANDLE dev; /* handle to device we're attached to */
70 BOOLEAN using_pxe; /* true if downloaded using the PXE protocol vs. regular DHCP */
72 EFI_IP_ADDRESS srv_ip;
73 EFI_IP_ADDRESS cln_ip;
75 EFI_IP_ADDRESS netmask;
78 netfs_fd_t fd_tab[NETFS_FD_MAX];
84 #define NETFS_F2FD(l,f) (UINTN)((f)-(l)->fd_tab)
85 #define NETFS_FD2F(l,fd) ((l)->fd_tab+fd)
86 #define NETFS_F_INVALID(f) ((f)->is_valid == FALSE)
90 netfs_interface_t pub_intf;
92 netfs_interface_t pub_intf;
93 netfs_priv_state_t priv_data;
97 #define FS_PRIVATE(n) (&(((netfs_t *)n)->netfs_priv.priv_data))
104 static dev_tab_t *dev_tab; /* holds all devices we found */
105 static UINTN ndev; /* how many entries in dev_tab */
107 static EFI_GUID NetFsProtocol = NETFS_PROTOCOL;
111 static EFI_PXE_BASE_CODE_CALLBACK_STATUS
113 IN EFI_PXE_BASE_CODE_CALLBACK *this,
114 IN EFI_PXE_BASE_CODE_FUNCTION function,
116 IN UINT32 packet_len,
117 IN EFI_PXE_BASE_CODE_PACKET *packet OPTIONAL
120 Print(L"netfs_callback called received=%d packet_len=%d\n", received, packet_len);
124 static EFI_PXE_BASE_CODE_CALLBACK netfs_callback = {
125 EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION,
131 netfs_fd_alloc(netfs_priv_state_t *nfs, CHAR16 *name)
133 netfs_fd_t *tmp = NULL, *prev = NULL, *match;
134 UINT8 netbuf_reuse = 0;
136 if (nfs->free_fd == NULL) {
137 ERR_PRT((L"out of file descriptor"));
140 match = nfs->free_fd;
141 for (tmp = nfs->free_fd; tmp; tmp = tmp->next) {
142 if (!StrCmp(name, tmp->last_file)) {
143 DBG_PRT((L"Using cached file %s netbuf_size=%d", tmp->last_file, tmp->netbuf_size));
150 /* indicate whether or not we got a match in caching */
151 match->netbuf_reuse = netbuf_reuse;
153 if (match == nfs->free_fd)
154 nfs->free_fd = match->next;
156 prev->next = match->next;
158 nfs->free_fd_count--;
164 netfs_fd_free(netfs_priv_state_t *nfs, netfs_fd_t *f)
167 ERR_PRT((L"invalid fd"));
170 f->next = nfs->free_fd;
172 /* we keep the netbuf, in case we can reuse it */
176 nfs->free_fd_count++;
178 if (nfs->free_fd_count > NETFS_FD_MAX) {
179 ERR_PRT((L"too many free descriptors %d", nfs->free_fd_count));
185 netbuf_alloc(netfs_fd_t *f)
187 /* we will try to reuse the existing buffer first */
188 if (f->netbuf != 0) return 0;
192 f->netbuf = (CHAR8 *)alloc_pages(EFI_SIZE_TO_PAGES(f->netbuf_maxsize), EfiLoaderData, AllocateAnyPages, 0);
194 return f->netbuf == 0 ? -1 : 0;
198 netfs_name(netfs_interface_t *this, CHAR16 *name, UINTN maxlen)
200 if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
202 StrnCpy(name, FS_NAME, maxlen-1);
204 name[maxlen-1] = CHAR_NULL;
210 netfs_extract_ip(netfs_priv_state_t *nfs)
212 EFI_PXE_BASE_CODE *pxe = nfs->pxe;
214 if (pxe->Mode->PxeDiscoverValid) {
215 nfs->using_pxe = TRUE;
216 Memcpy(&nfs->srv_ip, pxe->Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS));
217 Memcpy(&nfs->hw_addr, pxe->Mode->PxeReply.Dhcpv4.BootpHwAddr, 16*sizeof(UINT8));
219 Memcpy(&nfs->srv_ip, pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS));
220 Memcpy(&nfs->hw_addr, pxe->Mode->DhcpAck.Dhcpv4.BootpHwAddr, sizeof(nfs->hw_addr));
223 Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS));
224 Memcpy(&nfs->netmask, &pxe->Mode->SubnetMask, sizeof(EFI_IP_ADDRESS));
227 * the fact that we use index 0, is just a guess
229 if (pxe->Mode->RouteTableEntries>0)
230 Memcpy(&nfs->gw_ip, &pxe->Mode->RouteTable[0].GwAddr, sizeof(EFI_IP_ADDRESS));
232 VERB_PRT(1, Print(L"PXE PxeDiscoverValid: %s\n", pxe->Mode->PxeDiscoverValid? L"Yes (PXE-aware DHCPD)\n" : L"No (Regular DHCPD)\n"));
234 status = BS->HandleProtocol(dev, &PxeCallbackProtocol, (VOID **)&netfs_callback);
235 status = LibInstallProtocolInterfaces(&dev, &PxeCallbackProtocol, &netfs_callback, NULL);
236 Print(L"PXE Callback support : %r\n", status);
237 if (status == EFI_SUCCESS) {
239 status = pxe->SetParameters(pxe, NULL, NULL, NULL, NULL, &doit);
240 Print(L"PXE Callback SetParameters: %r\n", status);
244 * XXX: TFTPD server not quite right when using PXE, need to extract bootservers...
246 VERB_PRT(1, Print(L"Local IP: %d.%d.%d.%d\n",
247 pxe->Mode->StationIp.v4.Addr[0] & 0xff,
248 pxe->Mode->StationIp.v4.Addr[1] & 0xff,
249 pxe->Mode->StationIp.v4.Addr[2] & 0xff,
250 pxe->Mode->StationIp.v4.Addr[3] & 0xff));
252 VERB_PRT(1, Print(L"SM: %d.%d.%d.%d\n",
253 pxe->Mode->SubnetMask.v4.Addr[0] & 0xff,
254 pxe->Mode->SubnetMask.v4.Addr[1] & 0xff,
255 pxe->Mode->SubnetMask.v4.Addr[2] & 0xff,
256 pxe->Mode->SubnetMask.v4.Addr[3] & 0xff));
258 VERB_PRT(1, Print(L"TFTPD IP: %d.%d.%d.%d\n",
259 nfs->srv_ip.v4.Addr[0] & 0xff,
260 nfs->srv_ip.v4.Addr[1] & 0xff,
261 nfs->srv_ip.v4.Addr[2] & 0xff,
262 nfs->srv_ip.v4.Addr[3] & 0xff));
264 VERB_PRT(1, Print(L"Gateway IP: %d.%d.%d.%d\n",
265 nfs->gw_ip.v4.Addr[0] & 0xff,
266 nfs->gw_ip.v4.Addr[1] & 0xff,
267 nfs->gw_ip.v4.Addr[2] & 0xff,
268 nfs->gw_ip.v4.Addr[3] & 0xff));
273 netfs_start(EFI_PXE_BASE_CODE *pxe)
277 status = uefi_call_wrapper(pxe->Start, 2, pxe, FALSE);
278 if (EFI_ERROR(status)) return status;
280 return pxe->Dhcp(pxe, FALSE);
284 netfs_open(netfs_interface_t *this, CHAR16 *name, UINTN *fd)
286 netfs_priv_state_t *nfs;
289 CHAR8 ascii_name[FILENAME_MAXLEN];
290 UINTN blocksize = NETFS_DEFAULT_BLOCKSIZE;
291 UINTN prev_netbufsize, retries = 0;
292 BOOLEAN server_provided_filesize = FALSE;
294 if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
296 nfs = FS_PRIVATE(this);
298 if (nfs->pxe == NULL) return EFI_INVALID_PARAMETER;
301 * Try to start protocol if not already active
303 if (nfs->pxe->Mode->Started == FALSE) {
304 status = netfs_start(nfs->pxe);
305 if (EFI_ERROR(status)) return status;
306 netfs_extract_ip(nfs);
309 if ((f=netfs_fd_alloc(nfs, name)) == NULL) return EFI_OUT_OF_RESOURCES;
311 if (f->netbuf_reuse) {
314 *fd = NETFS_F2FD(nfs, f);
317 f->netbuf_maxsize = NETFS_DEFAULT_BUFSIZE;
320 if (f->netbuf == NULL && netbuf_alloc(f) == -1) {
321 netfs_fd_free(nfs, f);
322 return EFI_OUT_OF_RESOURCES;
325 /* well, we need to download ! */
327 U2ascii(name, ascii_name, FILENAME_MAXLEN);
329 VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...\n", ascii_name,
330 nfs->srv_ip.v4.Addr[0],
331 nfs->srv_ip.v4.Addr[1],
332 nfs->srv_ip.v4.Addr[2],
333 nfs->srv_ip.v4.Addr[3]));
336 netfs_fd_free(nfs, f);
337 VERB_PRT(2, Print(L"Failed: %r\n", status));
342 * netboot bugfix SF tracker 2874380
344 * For read operations, the return data will be placed in the buffer specified by BufferPtr. If
345 * BufferSize is too small to contain the entire downloaded file, then
346 * EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero or the size of
347 * the requested file (the size of the requested file is only returned if the TFTP server supports TFTP
348 * options). If BufferSize is large enough for the read operation, then BufferSize will be set to
349 * the size of the downloaded file, and EFI_SUCCESS will be returned. Applications using the
350 * PxeBc.Mtftp() services should use the get-file-size operations to determine the size of the
351 * downloaded file prior to using the read-file operations—especially when downloading large
352 * (greater than 64 MB) files—instead of making two calls to the read-file operation. Following this
353 * recommendation will save time if the file is larger than expected and the TFTP server does not
354 * support TFTP option extensions. Without TFTP option extension support, the client has to
355 * download the entire file, counting and discarding the received packets, to determine the file size.
357 * For TFTP “get file size” operations, the size of the requested file or directory is returned in
358 * BufferSize, and EFI_SUCCESS will be returned. If the TFTP server does not support options,
359 * the file will be downloaded into a bit bucket and the length of the downloaded file will be returned.
361 status = uefi_call_wrapper(nfs->pxe->Mtftp, 10,
363 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
366 &(f->netbuf_size), // PXE writes size of file from server here
373 * If options are not supported by this tftp server, according to the spec the file will be
374 * downloaded into a bit bucket, the size calculated by efi fw and returned in the status
375 * field of this call. YUK!!... in this case we will default to currently allocated max
376 * if thats still not big enough it will be caught and increased following the read file attempt
378 * XXX need to research how this is handled or changed in the latest UEFI spec.
380 if (status != EFI_SUCCESS) {
381 f->netbuf_size = f->netbuf_maxsize;
382 VERB_PRT(2, Print(L"setting default buffer size of %d for %a, no filesize recd from tftp server\n",
383 f->netbuf_size, ascii_name));
386 if (status == EFI_SUCCESS) {
387 server_provided_filesize = TRUE;
388 VERB_PRT(2, Print(L"received file size of %d for %a from tftp server.\n",
389 f->netbuf_size, ascii_name));
392 if (f->netbuf_size > f->netbuf_maxsize) { // we need a bigger buffer
393 VERB_PRT(2, Print(L"allocated buffer too small, attempting to increase\n"));
394 f->netbuf_maxsize += f->netbuf_size;
397 if (netbuf_alloc(f) == -1) return EFI_OUT_OF_RESOURCES;
400 /* paranoid catch any corner case missed */
401 if (f->netbuf_size == 0) f->netbuf_size = f->netbuf_maxsize;
403 DBG_PRT((L"\nbefore read: netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n",
408 prev_netbufsize = f->netbuf_size;
410 /* now try and download this file from the tftp server */
411 status = uefi_call_wrapper(nfs->pxe->Mtftp, 10,
413 EFI_PXE_BASE_CODE_TFTP_READ_FILE,
423 DBG_PRT((L"after: status=%r netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n",
429 if ((status == EFI_TIMEOUT || status == EFI_BUFFER_TOO_SMALL) && !server_provided_filesize) {
430 Print(L"buffer too small, need netbuf_size=%d\n", f->netbuf_size);
432 * if the TFTP server supports TFTP options, then we should
433 * get the required size. So we test to see if the size
434 * we set has changed. If so, we got the required size.
435 * If not, we increase the buffer size and retry.
437 if (f->netbuf_size == prev_netbufsize) {
438 f->netbuf_maxsize += NETFS_DEFAULT_BUFSIZE_INC;
440 /* we got an answer from the TFTP server, let's try it */
441 f->netbuf_maxsize = f->netbuf_size;
442 server_provided_filesize = TRUE;
446 f->netbuf = NULL; /* will force reallocation */
448 if (netbuf_alloc(f) == 0) {
453 } else if (status == EFI_TIMEOUT) { //if just a simple timeout, buffers are good just retry
454 VERB_PRT(2, Print(L"TFTP returned EFI_TIMEOUT ERROR... %d retries left.\n", (2 - retries)));
458 if (status == EFI_SUCCESS) {
459 /* start at the beginning of the file */
462 /* cache file name */
463 StrCpy(f->last_file, name);
467 *fd = NETFS_F2FD(nfs, f);
468 VERB_PRT(2, Print(L"Done\n"));
470 netfs_fd_free(nfs, f);
471 VERB_PRT(2, Print(L"Failed: %r\n", status));
473 DBG_PRT((L"File %s netbuf_size=%d: %r", name, f->netbuf_size, status));
477 for(i=0; i < netbuf_size; i++) {
478 Print(L"%c", (CHAR16)netbuf[i]);
488 netfs_read(netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
490 netfs_priv_state_t *nfs;
494 if (this == NULL || fd >= NETFS_FD_MAX || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER;
496 nfs = FS_PRIVATE(this);
497 f = NETFS_FD2F(nfs, fd);
499 if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
501 count = MIN(*size, f->netbuf_size - f->netbuf_pos);
503 if (count) Memcpy(buf, f->netbuf+f->netbuf_pos, count);
506 f->netbuf_pos += count;
512 netfs_close(netfs_interface_t *this, UINTN fd)
514 netfs_priv_state_t *nfs;
517 if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;
519 nfs = FS_PRIVATE(this);
520 f = NETFS_FD2F(nfs, fd);
522 if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
524 netfs_fd_free(nfs, f);
530 netfs_seek(netfs_interface_t *this, UINTN fd, UINT64 newpos)
532 netfs_priv_state_t *nfs;
535 if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;
537 nfs = FS_PRIVATE(this);
538 f = NETFS_FD2F(nfs, fd);
540 if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
542 if (newpos > f->netbuf_size) return EFI_INVALID_PARAMETER;
544 f->netbuf_pos = newpos;
550 netfs_infosize(netfs_interface_t *this, UINTN fd, UINT64 *sz)
552 netfs_priv_state_t *nfs;
555 if (this == NULL || fd >= NETFS_FD_MAX || sz == NULL) return EFI_INVALID_PARAMETER;
557 nfs = FS_PRIVATE(this);
558 f = NETFS_FD2F(nfs, fd);
560 if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
562 *sz = f->netbuf_size;
568 find_dhcp_option(EFI_PXE_BASE_CODE_PACKET *packet, UINT8 use_ipv6, UINT8 option, CHAR8 *str, INTN *len)
572 UINT8 *opts = packet->Dhcpv4.DhcpOptions;
578 DBG_PRT((L"reach end of options (no marker)\n"));
583 if (tag == 0) continue;
584 if (tag == 255) break;
589 { UINT8 l = length, k = 0;
590 Print(L"found option %d len=%d: ", tag, length);
591 while (l--) { Print(L"%c(%d)\n", (CHAR16)opts[k], opts[k]); k++; }
597 while (length--) { *str++ = opts[i++]; }
606 netfs_getinfo(netfs_interface_t *this, netfs_info_t *info)
608 netfs_priv_state_t *nfs;
612 if (this == NULL || info == NULL) return EFI_INVALID_PARAMETER;
614 nfs = FS_PRIVATE(this);
616 Memcpy(&info->cln_ipaddr, &nfs->cln_ip, sizeof(EFI_IP_ADDRESS));
617 Memcpy(&info->srv_ipaddr, &nfs->srv_ip, sizeof(EFI_IP_ADDRESS));
618 Memcpy(&info->netmask, &nfs->netmask, sizeof(EFI_IP_ADDRESS));
619 Memcpy(&info->gw_ipaddr, &nfs->gw_ip, sizeof(EFI_IP_ADDRESS));
620 Memcpy(&info->hw_addr, &nfs->hw_addr, sizeof(info->hw_addr));
622 info->using_pxe = nfs->using_pxe;
623 info->started = nfs->pxe->Mode->Started;
624 info->using_ipv6 = nfs->pxe->Mode->UsingIpv6;
626 if (nfs->pxe->Mode->UsingIpv6) goto skip_options;
628 r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 15, str, &len);
630 ascii2U(str, info->domainame, 255);
632 VERB_PRT(3, Print(L"domain(15): %a\n", str));
634 r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 12, str, &len);
636 ascii2U(str, info->hostname, 255);
638 VERB_PRT(3, Print(L"hostname(12): %a\n", str));
641 * extract bootfile name from DHCP exchanges
643 if (nfs->using_pxe == 0) {
644 ascii2U(nfs->pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, info->bootfile, NETFS_BOOTFILE_MAXLEN);
645 VERB_PRT(3, Print(L"bootfile: %s\n", info->bootfile));
653 find_pxe_server_type(EFI_PXE_BASE_CODE *pxe)
657 UINT8 *opts = pxe->Mode->PxeReply.Dhcpv4.DhcpOptions;
664 DBG_PRT((L"Tag #%d Length %d\n",tag, length));
666 if (tag == 43) goto found;
670 return NETFS_DEFAULT_SERVER_TYPE;
678 server_type =(opts[i+2]<<8) | opts[i+3];
679 DBG_PRT((L"ServerType: %d\n", server_type));
684 return NETFS_DEFAULT_SERVER_TYPE;
688 netfs_query_layer(netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str)
690 netfs_priv_state_t *nfs;
693 if (this == NULL || str == NULL) return EFI_INVALID_PARAMETER;
695 nfs = FS_PRIVATE(this);
697 if (nfs->using_pxe == FALSE) return EFI_UNSUPPORTED;
699 if (server_type == 0) server_type = find_pxe_server_type(nfs->pxe);
701 status = uefi_call_wrapper(nfs->pxe->Discover, 5, nfs->pxe, server_type, &layer, FALSE, 0);
702 if(status == EFI_SUCCESS) {
703 ascii2U(nfs->pxe->Mode->PxeReply.Dhcpv4.BootpBootFile, str, maxlen);
709 netfs_init_state(netfs_t *netfs, EFI_HANDLE dev, EFI_PXE_BASE_CODE *pxe)
711 netfs_priv_state_t *nfs = FS_PRIVATE(netfs);
714 /* need to do some init here on netfs_intf */
715 Memset(netfs, 0, sizeof(*netfs));
718 netfs->pub_intf.netfs_name = netfs_name;
719 netfs->pub_intf.netfs_open = netfs_open;
720 netfs->pub_intf.netfs_read = netfs_read;
721 netfs->pub_intf.netfs_close = netfs_close;
722 netfs->pub_intf.netfs_infosize = netfs_infosize;
723 netfs->pub_intf.netfs_seek = netfs_seek;
724 netfs->pub_intf.netfs_query_layer = netfs_query_layer;
725 netfs->pub_intf.netfs_getinfo = netfs_getinfo;
731 * we defer DHCP request until it is really necessary (netfs_open)
733 if (pxe->Mode->Started == TRUE) netfs_extract_ip(nfs);
735 Memset(nfs->fd_tab, 0, sizeof(nfs->fd_tab));
737 for (i=0; i < NETFS_FD_MAX-1; i++) {
738 nfs->fd_tab[i].next = &nfs->fd_tab[i+1];
740 /* null on last element is done by memset */
742 nfs->free_fd = nfs->fd_tab;
743 nfs->free_fd_count = NETFS_FD_MAX;
747 netfs_install_one(EFI_HANDLE dev, VOID **intf)
752 EFI_PXE_BASE_CODE *pxe;
754 status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &NetFsProtocol, (VOID **)&netfs);
755 if (status == EFI_SUCCESS) {
756 ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
760 status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &PxeBaseCodeProtocol, (VOID **)&pxe);
761 if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
764 netfs = (netfs_t *)alloc(sizeof(*netfs), EfiLoaderData);
766 ERR_PRT((L"failed to allocate %s", FS_NAME));
767 return EFI_OUT_OF_RESOURCES;
770 netfs_init_state(netfs, dev, pxe);
772 status = LibInstallProtocolInterfaces(&dev, &NetFsProtocol, netfs, NULL);
773 if (EFI_ERROR(status)) {
774 ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
780 if (intf) *intf = (VOID *)netfs;
783 { EFI_DEVICE_PATH *dp; CHAR16 *str;
784 dp = DevicePathFromHandle(dev);
785 str = DevicePathToStr(dp);
786 Print(L"attached %s to %s\n", FS_NAME, str);
801 uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &PxeBaseCodeProtocol, NULL, &size, NULL);
802 if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
804 DBG_PRT((L"size=%d", size));
806 dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
807 if (dev_tab == NULL) {
808 ERR_PRT((L"failed to allocate handle table"));
809 return EFI_OUT_OF_RESOURCES;
812 status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &PxeBaseCodeProtocol, NULL, &size, (VOID **)dev_tab);
813 if (status != EFI_SUCCESS) {
814 ERR_PRT((L"failed to get handles: %r", status));
818 ndev = size / sizeof(EFI_HANDLE);
820 for(i=0; i < ndev; i++) {
822 netfs_install_one(dev_tab[i].dev, &intf);
823 /* override device handle with interface pointer */
824 dev_tab[i].intf = intf;
831 netfs_uninstall(VOID)
834 netfs_priv_state_t *nfs;
838 for(i=0; i < ndev; i++) {
839 if (dev_tab[i].intf == NULL) continue;
840 nfs = FS_PRIVATE(dev_tab[i].intf);
841 status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, nfs->dev, &NetFsProtocol, dev_tab[i].intf);
842 if (EFI_ERROR(status)) {
843 ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
847 { EFI_DEVICE_PATH *dp; CHAR16 *str;
848 dp = DevicePathFromHandle(nfs->dev);
849 str = DevicePathToStr(dp);
850 Print(L"uninstalled %s on %s\n", FS_NAME, str);
854 if (nfs->pxe->Mode->Started == TRUE)
855 uefi_call_wrapper(nfs->pxe->Stop, 1, nfs->pxe);
857 free(dev_tab[i].intf);
859 if (dev_tab) free(dev_tab);