Пример #1
0
EFI_STATUS
BdsTftpLoadImage (
    IN     EFI_DEVICE_PATH*       DevicePath,
    IN     EFI_HANDLE             Handle,
    IN     EFI_DEVICE_PATH*       RemainingDevicePath,
    IN     EFI_ALLOCATE_TYPE      Type,
    IN OUT EFI_PHYSICAL_ADDRESS   *Image,
    OUT    UINTN                  *ImageSize
)
{
    EFI_STATUS                  Status;
    EFI_PXE_BASE_CODE_PROTOCOL  *Pxe;
    UINT64                      TftpBufferSize;
    VOID*                       TftpBuffer;
    EFI_IP_ADDRESS              ServerIp;
    IPv4_DEVICE_PATH*           IPv4DevicePathNode;
    FILEPATH_DEVICE_PATH*       FilePathDevicePath;
    EFI_IP_ADDRESS              LocalIp;

    ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP));

    IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
    FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);

    Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
    if (EFI_ERROR(Status)) {
        return Status;
    }

    Status = Pxe->Start (Pxe, FALSE);
    if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
        return Status;
    }

    if (!IPv4DevicePathNode->StaticIpAddress) {
        Status = Pxe->Dhcp(Pxe, TRUE);
    } else {
        CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
        Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);
    }
    if (EFI_ERROR(Status)) {
        return Status;
    }

    CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));

    Status = Pxe->Mtftp (
                 Pxe,
                 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
                 NULL,
                 FALSE,
                 &TftpBufferSize,
                 NULL,
                 &ServerIp,
                 (UINT8 *)FilePathDevicePath->PathName,
                 NULL,
                 TRUE
             );
    if (EFI_ERROR(Status)) {
        return Status;
    }

    // Allocate a buffer to hold the whole file.
    TftpBuffer = AllocatePool(TftpBufferSize);
    if (TftpBuffer == NULL) {
        return EFI_OUT_OF_RESOURCES;
    }

    Status = Pxe->Mtftp (
                 Pxe,
                 EFI_PXE_BASE_CODE_TFTP_READ_FILE,
                 TftpBuffer,
                 FALSE,
                 &TftpBufferSize,
                 NULL,
                 &ServerIp,
                 (UINT8 *)FilePathDevicePath->PathName,
                 NULL,
                 FALSE
             );
    if (EFI_ERROR(Status)) {
        FreePool(TftpBuffer);
    } else if (ImageSize != NULL) {
        *ImageSize = (UINTN)TftpBufferSize;
    }

    return Status;
}
Пример #2
0
/**
  Parse out the boot information from the last Dhcp4 reply packet.

  @param[in, out] Private      Pointer to PxeBc private data.
  @param[out]     BufferSize   Size of the boot file to be downloaded.

  @retval EFI_SUCCESS          Successfully parsed out all the boot information.
  @retval Others               Failed to parse out the boot information.

**/
EFI_STATUS
PxeBcDhcp4BootInfo (
  IN OUT PXEBC_PRIVATE_DATA   *Private,
     OUT UINT64               *BufferSize
  )
{
  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
  EFI_PXE_BASE_CODE_MODE      *Mode;
  EFI_STATUS                  Status;
  PXEBC_DHCP4_PACKET_CACHE    *Cache4;
  UINT16                      Value;
  PXEBC_VENDOR_OPTION         *VendorOpt;
  PXEBC_BOOT_SVR_ENTRY        *Entry;
  
  PxeBc       = &Private->PxeBc;
  Mode        = PxeBc->Mode;
  Status      = EFI_SUCCESS;
  *BufferSize = 0;

  //
  // Get the last received Dhcp4 reply packet.
  //
  if (Mode->PxeReplyReceived) {
    Cache4 = &Private->PxeReply.Dhcp4;
  } else if (Mode->ProxyOfferReceived) {
    Cache4 = &Private->ProxyOffer.Dhcp4;
  } else {
    Cache4 = &Private->DhcpAck.Dhcp4;
  }

  ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);

  //
  // Parse the boot server address.
  // If prompt/discover is disabled, get the first boot server from the boot servers list.
  // Otherwise, parse the boot server Ipv4 address from next server address field in DHCP header.
  // If all these fields are not available, use option 54 instead.
  //
  VendorOpt = &Cache4->VendorOpt;
  if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && IS_VALID_BOOT_SERVERS (VendorOpt->BitMap)) {
    Entry = VendorOpt->BootSvr;
    if (VendorOpt->BootSvrLen >= sizeof (PXEBC_BOOT_SVR_ENTRY) && Entry->IpCnt > 0) {
      CopyMem (
        &Private->ServerIp,
        &Entry->IpAddr[0],
        sizeof (EFI_IPv4_ADDRESS)
        );
    }
  }
  if (Private->ServerIp.Addr[0] == 0) {
    //
    // ServerIp.Addr[0] equals zero means we failed to get IP address from boot server list.
    // Try to use next server address field.
    //
    CopyMem (
      &Private->ServerIp,
      &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,
      sizeof (EFI_IPv4_ADDRESS)
      );
  }
  if (Private->ServerIp.Addr[0] == 0) {
    //
    // Still failed , use the IP address from option 54.
    //
    CopyMem (
      &Private->ServerIp,
      Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
      sizeof (EFI_IPv4_ADDRESS)
      );
  }

  //
  // Parse the boot file name by option.
  //
  Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data;

  if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
    //
    // Parse the boot file size by option.
    //
    CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
    Value       = NTOHS (Value);
    //
    // The field of boot file size is 512 bytes in unit.
    //
    *BufferSize = 512 * Value;
  } else {
    //
    // Get the bootfile size by tftp command if no option available.
    //
    Status = PxeBc->Mtftp (
                      PxeBc,
                      EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
                      NULL,
                      FALSE,
                      BufferSize,
                      &Private->BlockSize,
                      &Private->ServerIp,
                      Private->BootFileName,
                      NULL,
                      FALSE
                      );
  }

  //
  // Save the value of boot file size.
  //
  Private->BootFileSize = (UINTN) *BufferSize;

  //
  // Display all the information: boot server address, boot file name and boot file size.
  //
  AsciiPrint ("\n  Server IP address is ");
  PxeBcShowIp4Addr (&Private->ServerIp.v4);
  AsciiPrint ("\n  NBP filename is %a", Private->BootFileName);
  AsciiPrint ("\n  NBP filesize is %d Bytes", Private->BootFileSize);

  return Status;
}
Пример #3
0
/**
  Parse out the boot information from the last Dhcp6 reply packet.

  @param[in, out] Private      Pointer to PxeBc private data.
  @param[out]     BufferSize   Size of the boot file to be downloaded.

  @retval EFI_SUCCESS          Successfully parsed out all the boot information.
  @retval EFI_BUFFER_TOO_SMALL
  @retval Others               Failed to parse out the boot information.

**/
EFI_STATUS
PxeBcDhcp6BootInfo (
  IN OUT PXEBC_PRIVATE_DATA   *Private,
     OUT UINT64               *BufferSize
  )
{
  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
  EFI_PXE_BASE_CODE_MODE      *Mode;
  EFI_STATUS                  Status;
  PXEBC_DHCP6_PACKET_CACHE    *Cache6;
  UINT16                      Value;

  PxeBc       = &Private->PxeBc;
  Mode        = PxeBc->Mode;
  Status      = EFI_SUCCESS;
  *BufferSize = 0;

  //
  // Get the last received Dhcp6 reply packet.
  //
  if (Mode->PxeReplyReceived) {
    Cache6 = &Private->PxeReply.Dhcp6;
  } else if (Mode->ProxyOfferReceived) {
    Cache6 = &Private->ProxyOffer.Dhcp6;
  } else {
    Cache6 = &Private->DhcpAck.Dhcp6;
  }

  ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);

  //
  // Set the station address to IP layer.
  //
  Status = PxeBcSetIp6Address (Private);
  if (EFI_ERROR (Status)) {
    return Status;
  }


  //
  // Parse (m)tftp server ip address and bootfile name.
  //
  Status = PxeBcExtractBootFileUrl (
             Private,
             &Private->BootFileName,
             &Private->ServerIp.v6,
             (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
             NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Parse the value of boot file size.
  //
  if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] != NULL) {
    //
    // Parse it out if have the boot file parameter option.
    //
    Status = PxeBcExtractBootFileParam ((CHAR8 *) Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM]->Data, &Value);
    if (EFI_ERROR (Status)) {
      return Status;
    }
    //
    // The field of boot file size is 512 bytes in unit.
    //
    *BufferSize = 512 * Value;
  } else {
    //
    // Send get file size command by tftp if option unavailable.
    //
    Status = PxeBc->Mtftp (
                      PxeBc,
                      EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
                      NULL,
                      FALSE,
                      BufferSize,
                      &Private->BlockSize,
                      &Private->ServerIp,
                      Private->BootFileName,
                      NULL,
                      FALSE
                      );
  }

  //
  // Save the value of boot file size.
  //
  Private->BootFileSize = (UINTN) *BufferSize;

  //
  // Display all the information: boot server address, boot file name and boot file size.
  //
  AsciiPrint ("\n  Server IP address is ");
  PxeBcShowIp6Addr (&Private->ServerIp.v6);
  AsciiPrint ("\n  NBP filename is %a", Private->BootFileName);
  AsciiPrint ("\n  NBP filesize is %d Bytes", Private->BootFileSize);

  return Status;
}
Пример #4
0
/**
  Parse out the boot information from the last Dhcp4 reply packet.

  @param[in, out] Private      Pointer to PxeBc private data.
  @param[out]     BufferSize   Size of the boot file to be downloaded.

  @retval EFI_SUCCESS          Successfully parsed out all the boot information.
  @retval Others               Failed to parse out the boot information.

**/
EFI_STATUS
PxeBcDhcp4BootInfo (
  IN OUT PXEBC_PRIVATE_DATA   *Private,
     OUT UINT64               *BufferSize
  )
{
  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
  EFI_PXE_BASE_CODE_MODE      *Mode;
  EFI_STATUS                  Status;
  PXEBC_DHCP4_PACKET_CACHE    *Cache4;
  UINT16                      Value;

  PxeBc       = &Private->PxeBc;
  Mode        = PxeBc->Mode;
  Status      = EFI_SUCCESS;
  *BufferSize = 0;

  //
  // Get the last received Dhcp4 reply packet.
  //
  if (Mode->PxeReplyReceived) {
    Cache4 = &Private->PxeReply.Dhcp4;
  } else if (Mode->ProxyOfferReceived) {
    Cache4 = &Private->ProxyOffer.Dhcp4;
  } else {
    Cache4 = &Private->DhcpAck.Dhcp4;
  }

  //
  // Parse the boot server Ipv4 address by next server address.
  // If this field isn't available, use option 54 instead.
  //
  CopyMem (
    &Private->ServerIp,
    &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,
    sizeof (EFI_IPv4_ADDRESS)
    );

  if (Private->ServerIp.Addr[0] == 0) {
    CopyMem (
      &Private->ServerIp,
      Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
      sizeof (EFI_IPv4_ADDRESS)
      );
  }

  //
  // Parse the boot file name by option.
  //
  ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
  Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data;

  if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
    //
    // Parse the boot file size by option.
    //
    CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
    Value       = NTOHS (Value);
    //
    // The field of boot file size is 512 bytes in unit.
    //
    *BufferSize = 512 * Value;
  } else {
    //
    // Get the bootfile size by tftp command if no option available.
    //
    Status = PxeBc->Mtftp (
                      PxeBc,
                      EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
                      NULL,
                      FALSE,
                      BufferSize,
                      &Private->BlockSize,
                      &Private->ServerIp,
                      Private->BootFileName,
                      NULL,
                      FALSE
                      );
  }

  //
  // Save the value of boot file size.
  //
  Private->BootFileSize = (UINTN) *BufferSize;

  //
  // Display all the information: boot server address, boot file name and boot file size.
  //
  AsciiPrint ("\n  Server IP address is ");
  PxeBcShowIp4Addr (&Private->ServerIp.v4);
  AsciiPrint ("\n  NBP filename is %a", Private->BootFileName);
  AsciiPrint ("\n  NBP filesize is %d Bytes", Private->BootFileSize);

  return Status;
}