pxe_loadfile.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,697 行 · 第 1/3 页

C
1,697
字号
        UINT16  n;

        EfiCopyMem (&n, &op[2], 2);
        CredentialLen = HTONS (n) * 512;
      }
    }

    if (CredentialLen == 0) {
      BlockSize = 8192;

      Status = Private->EfiBc.Mtftp (
                                &Private->EfiBc,
                                EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
                                NULL,
                                FALSE,
                                &CredentialLen,
                                &BlockSize,
                                &Private->ServerIp,
                                CredentialFilename,
                                NULL,
                                FALSE
                                );

      if (EFI_ERROR (Status)) {
        return Status;
      }

      if (CredentialLen == 0) {
        //
        // %%TBD -- EFI error for invalid credential
        // file.
        //
        return EFI_PROTOCOL_ERROR;
      }
    }
    //
    // Allocate credential file buffer.
    //
    Status = gBS->AllocatePool (
                    EfiBootServicesData,
                    (UINTN) CredentialLen,
                    &CredentialBuffer
                    );

    if (EFI_ERROR (Status)) {
      return Status;
    }
    //
    // Download credential file.
    //
    BlockSize = 8192;

    Status = Private->EfiBc.Mtftp (
                              &Private->EfiBc,
                              EFI_PXE_BASE_CODE_TFTP_READ_FILE,
                              CredentialBuffer,
                              FALSE,
                              &CredentialLen,
                              &BlockSize,
                              &Private->ServerIp,
                              CredentialFilename,
                              NULL,
                              FALSE
                              );

    if (EFI_ERROR (Status)) {
      gBS->FreePool (CredentialBuffer);
      return Status;
    }
    //
    // Verify credentials.
    //
    if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {
      Status = EFI_SUCCESS;
    } else {
      //
      // %%TBD -- An EFI error code for failing credential verification.
      //
      Status = EFI_PROTOCOL_ERROR;
    }

    gBS->FreePool (CredentialBuffer);
  }

  return Status;
}

STATIC
EFI_STATUS
LoadfileStart (
  IN PXE_BASECODE_DEVICE  *Private,
  IN OUT UINT64           *BufferSize,
  IN VOID                 *Buffer
  )
/*++

Routine Description:

  Start PXE DHCP.  Get DHCP and proxyDHCP information.
  Display remote boot menu and prompt.  Select item from menu.

Arguments:

  Private - Pointer to PxeBc interface
  BufferSize - Pointer to download buffer size
  Buffer - Pointer to download buffer

Returns:

  EFI_SUCCESS - 
  EFI_NOT_READY - 
  
--*/
{
  EFI_PXE_BASE_CODE_MODE      *PxeBcMode;
  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
  EFI_SIMPLE_NETWORK_MODE     *SnpMode;
  EFI_STATUS                  Status;
  VOID                        *RxBuf;

  DEBUG ((EFI_D_WARN, "\nLoadfileStart()  Enter."));

  //
  // Try to start BaseCode, for now only IPv4 is supported
  // so don't try to start using IPv6.
  //
  Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);

  if (EFI_ERROR (Status)) {
    if (Status != EFI_ALREADY_STARTED) {
      DEBUG ((EFI_D_NET, "\nLoadfileStart()  Exit  BC.Start() == %xh", Status));
      return Status;
    }
  }
  //
  // Get pointers to PXE mode structure, SNP protocol structure
  // and SNP mode structure.
  //
  PxeBcMode = Private->EfiBc.Mode;
  Snp       = Private->SimpleNetwork;
  SnpMode   = Snp->Mode;

  //
  // Display client MAC address, like 16-bit PXE ROMs
  //
  Aprint ("\nCLIENT MAC ADDR: ");

  {
    UINTN Index;
    UINTN hlen;

    hlen = SnpMode->HwAddressSize;

    for (Index = 0; Index < hlen; ++Index) {
      Aprint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);
    }
  }

  Aprint ("\nDHCP");

  Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);

  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_WARN, "\nLoadfileStart()  Exit  BC.Dhcp() == %Xh", Status));
    Aprint ("\r               \r");
    return Status;
  }

  ShowMyInfo (Private);

  RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)

  Status = DoMenu (Private, RxBufferPtr);

  if (Status == EFI_SUCCESS) {
    //
    // did a discovery - take info from discovery packet
    //
    RxBuf = &PXE_ACK_BUFFER;
  } else if (Status == NO_MENU) {
    //
    // did not do a discovery - take info from rxbuf
    //
    Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;

    if (!(Private->ServerIp.Addr[0])) {
      *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;
    }
  } else {
    DEBUG ((EFI_D_WARN, "\nLoadfileStart()  Exit  DoMenu() == %Xh", Status));
    return Status;
  }

  if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
    DEBUG ((EFI_D_WARN, "\nLoadfileStart()  Exit  Not ready?"));
    return EFI_NOT_READY;
  }
  //
  // check for file size option sent
  //
  if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {
    Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);
  }

  Private->BootServerReceiveBuffer  = RxBufferPtr;

  Status = DownloadFile (Private, BufferSize, Buffer);

  DEBUG (
    (EFI_D_WARN,
    "\nLoadfileStart()  Exit.  DownloadFile() = %Xh",
    Status)
    );

  return Status;
}

EFI_STATUS
EFIAPI
LoadFile (
  IN EFI_LOAD_FILE_PROTOCOL           *This,
  IN EFI_DEVICE_PATH_PROTOCOL         *FilePath,
  IN BOOLEAN                          BootPolicy,
  IN OUT UINTN                        *BufferSize,
  IN OUT VOID                         *Buffer
  )
/*++

Routine Description:

  Loadfile interface for PxeBc interface

Arguments:

  This -  Pointer to Loadfile interface
  FilePath - Not used and not checked
  BootPolicy - Must be TRUE
  BufferSize - Pointer to buffer size 
  Buffer - Pointer to download buffer or NULL

Returns:

  EFI_INVALID_PARAMETER -
  EFI_UNSUPPORTED -
  EFI_SUCCESS -
  EFI_BUFFER_TOO_SMALL -

--*/
{
  LOADFILE_DEVICE *LoadfilePtr;
  UINT64          TmpBufSz;
  INT32           OrigMode;
  INT32           OrigAttribute;
  BOOLEAN         RemoveCallback;
  BOOLEAN         NewMakeCallback;
  EFI_STATUS      Status;
  EFI_STATUS      TempStatus;
  //
  //
  //
  OrigMode        = gST->ConOut->Mode->Mode;
  OrigAttribute   = gST->ConOut->Mode->Attribute;
  RemoveCallback  = FALSE;

  Aprint ("Running LoadFile()\n");

  //
  // Resolve Warning 4 unreferenced parameter problem
  //
  FilePath = NULL;

  //
  // If either if these parameters are NULL, we cannot continue.
  //
  if (This == NULL || BufferSize == NULL) {
    DEBUG ((EFI_D_WARN, "\nLoadFile()  This or BufferSize == NULL"));
    return EFI_INVALID_PARAMETER;
  }
  //
  // We only support BootPolicy == TRUE
  //
  if (!BootPolicy) {
    DEBUG ((EFI_D_WARN, "\nLoadFile()  BootPolicy == FALSE"));
    return EFI_UNSUPPORTED;
  }
  //
  // Get pointer to LoadFile protocol structure.
  //
  LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);

  if (LoadfilePtr == NULL) {
    DEBUG (
      (EFI_D_NET,
      "\nLoadFile()  Could not get pointer to LoadFile structure")
      );
    return EFI_INVALID_PARAMETER;
  }
  //
  // Lock interface
  //
  EfiAcquireLock (&LoadfilePtr->Lock);

  //
  // Set console output mode and display attribute
  //
  if (OrigMode != 0) {
    gST->ConOut->SetMode (gST->ConOut, 0);
  }

  gST->ConOut->SetAttribute (
                gST->ConOut,
                EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)
                );

  //
  // See if BaseCode already has a Callback protocol attached.
  // If there is none, attach our own Callback protocol.
  //
  Status = gBS->HandleProtocol (
                  LoadfilePtr->Private->Handle,
                  &gEfiPxeBaseCodeCallbackProtocolGuid,
                  (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr
                  );

  switch (Status) {
  case EFI_SUCCESS:
    //
    // There is already a callback routine.  Do nothing.
    //
    DEBUG ((EFI_D_WARN, "\nLoadFile()  BC callback exists."));
    break;

  case EFI_UNSUPPORTED:
    //
    // No BaseCode Callback protocol found.  Add our own.
    //
    Status = gBS->InstallProtocolInterface (
                    &LoadfilePtr->Private->Handle,
                    &gEfiPxeBaseCodeCallbackProtocolGuid,
                    EFI_NATIVE_INTERFACE,
                    &_bc_callback
                    );

    DEBUG ((EFI_D_WARN, "\nLoadFile()  Callback install status == %xh", Status));

    RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);

    if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {
      NewMakeCallback = TRUE;
      LoadfilePtr->Private->EfiBc.SetParameters (
                                    &LoadfilePtr->Private->EfiBc,
                                    NULL,
                                    NULL,
                                    NULL,
                                    NULL,
                                    &NewMakeCallback
                                    );
    }

    break;

  default:
    DEBUG ((EFI_D_WARN, "\nLoadFile()  Callback check status == %xh", Status));
  }
  //
  // Check for starting or for continuing after already getting
  // the file size.
  //
  if (LoadfilePtr->Private->FileSize == 0) {
    TmpBufSz  = 0;
    Status    = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);

    if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {
      *BufferSize = 0xFFFFFFFF;
    } else {
      *BufferSize = (UINTN) TmpBufSz;
    }

    if (Status == EFI_BUFFER_TOO_SMALL) {
      //
      // This is done so loadfile will work even if the boot manager
      // did not make the first call with Buffer == NULL.
      //
      Buffer = NULL;
    }
  } else if (Buffer == NULL) {
    DEBUG ((EFI_D_WARN, "\nLoadfile()  Get buffer size"));

    //
    // Continuing from previous LoadFile request.  Make sure there
    // is a buffer and that it is big enough.
    //
    *BufferSize = LoadfilePtr->Private->FileSize;
    Status      = EFI_BUFFER_TOO_SMALL;
  } else {
    DEBUG ((EFI_D_WARN, "\nLoadFile()  Download file"));

    //
    // Everything looks good, try to download the file.
    //
    TmpBufSz  = *BufferSize;
    Status    = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);

    //
    // Next call to loadfile will start DHCP process again.
    //
    LoadfilePtr->Private->FileSize = 0;
  }
  //
  // If we added a callback protocol, now is the time to remove it.
  //
  if (RemoveCallback) {
    NewMakeCallback = FALSE;
    TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (
                                          &LoadfilePtr->Private->EfiBc,
                                          NULL,
                                          NULL,
                                          NULL,
                                          NULL,
                                          &NewMakeCallback
                                          );

    if (TempStatus == EFI_SUCCESS) {
      gBS->UninstallProtocolInterface (
            LoadfilePtr->Private->Handle,
            &gEfiPxeBaseCodeCallbackProtocolGuid,
            &_bc_callback
            );
    }
  }
  //
  // Restore display mode and attribute
  //
  if (OrigMode != 0) {
    gST->ConOut->SetMode (gST->ConOut, OrigMode);
  }

  gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);

  //
  // Unlock interface
  //
  EfiReleaseLock (&LoadfilePtr->Lock);

  DEBUG ((EFI_D_WARN, "\nBC.Loadfile()  Status == %xh\n", Status));

  switch (Status) {
  case EFI_SUCCESS:           /* 0 */
    return EFI_SUCCESS;

  case EFI_BUFFER_TOO_SMALL:  /* 5 */
    //
    // Error is only displayed when we are actually trying to
    // download the boot image.
    //
    if (Buffer == NULL) {
      return EFI_BUFFER_TOO_SMALL;
    }

    Aprint ("\nPXE-E05: Download buffer is smaller than requested file.\n");
    break;

  case EFI_DEVICE_ERROR:      /* 7 */
    Aprint ("\nPXE-E07: Network device error.  Check network connection.\n");
    break;

  case EFI_OUT_OF_RESOURCES:  /* 9 */
    Aprint ("\nPXE-E09: Could not allocate I/O buffers.\n");
    break;

  case EFI_NO_MEDIA:          /* 12 */
    Aprint ("\nPXE-E12: Could not detect network connection.  Check cable.\n");
    break;

  case EFI_NO_RESPONSE:       /* 16 */
    Aprint ("\nPXE-E16: Valid PXE offer not received.\n");
    break;

  case EFI_TIMEOUT:           /* 18 */
    Aprint ("\nPXE-E18: Timeout.  Server did not respond.\n");
    break;

  case EFI_ABORTED:           /* 21 */
    Aprint ("\nPXE-E21: Remote boot cancelled.\n");
    break;

  case EFI_ICMP_ERROR:        /* 22 */
    Aprint ("\nPXE-E22: Client received ICMP error from server.\n");

    if (LoadfilePtr->Private->EfiBc.Mode == NULL) {
      break;
    }

    if (!LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {
      break;
    }

    Aprint (
      "PXE-E98: Type: %xh  Code: %xh  ",
      LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,
      LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code
      );

    switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {
    case 0x03:
      switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {
      case 0x00:              /* net unreachable */
        Aprint ("Net unreachable");
        break;

      case 0x01:              /* host unreachable */
        Aprint ("Host unreachable");
        break;

      case 0x02:              /* protocol unreachable */
        Aprint ("Protocol unreachable");
        break;

      case 0x03:              /* port unreachable */
        Aprint ("Port unreachable");
        break;

      case 0x04:              /* Fragmentation needed */
        Aprint ("Fragmentation needed");
        break;

      case 0x05:              /* Source route failed */
        Aprint ("Source route failed");
        break;
      }

      break;
    }

    Aprint ("\n");

    break;

  case EFI_TFTP_ERROR:        /* 23 */
    Aprint ("\nPXE-E23: Client received TFTP error from server.\n");

    if (LoadfilePtr->Private->EfiBc.Mode == NULL) {
      break;
    }

    if (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived) {
      Aprint (
        "PXE-E98: Code: %xh  %a\n",
        LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,
        LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString
        );
    }

    break;

  default:
    Aprint ("\nPXE-E99: Unexpected network error: %xh\n", Status);
  }

  LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);

  return Status;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?