pxe_loadfile.c

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

C
1,697
字号

  MenuLth                 = Ptr.MenuPtr->Header.Length;
  Ptr.CurrentMenuItemPtr  = Ptr.MenuPtr->MenuItem;

  //
  // build menu items array
  //
  for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems <= MAX_MENULIST;) {
    UINTN lth;

    lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);

    MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;

    if (lth > Longest) {
      //
      // check if too long
      //
      if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {
        Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));
      }
    }

    Index += lth;
    Ptr.BytePtr += lth;
  }

  if (Status != AUTO_SELECT) {
    UINT8 BlankBuf[75];

    EfiSetMem (BlankBuf, sizeof BlankBuf, ' ');
    BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;
    Aprint ("\n");

    //
    // now put up menu
    //
    for (Index = 0; Index < NumMenuItems; ++Index) {
      PrintMenuItem (MenuItemPtrs[Index]);
    }

    TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;

    //
    // now wait for a selection
    //
    Done = FALSE;
    do {
      //
      // highlight selection
      //
      EFI_INPUT_KEY Key;
      UINTN         NewSelected;

      NewSelected = Selected;

      //
      // highlight selected row
      //
      gST->ConOut->SetAttribute (
                    gST->ConOut,
                    EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)
                    );
      gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);

      Aprint (" --->%a\r", BlankBuf);

      PrintMenuItem (MenuItemPtrs[Selected]);
      gST->ConOut->SetAttribute (
                    gST->ConOut,
                    EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
                    );
      gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);

      //
      // wait for a keystroke
      //
      while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
        UINT8 TmpBuf[512];
        UINTN TmpBufLen;

        TmpBufLen = sizeof TmpBuf;

        Private->EfiBc.UdpRead (
                        &Private->EfiBc,
                        EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
                        EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
                        EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
                        NULL, /* dest ip */
                        NULL, /* dest port */
                        NULL, /* src ip */
                        NULL, /* src port */
                        NULL, /* hdr size */
                        NULL, /* hdr ptr */
                        &TmpBufLen,
                        TmpBuf
                        );
      }

      if (!Key.ScanCode) {
        switch (Key.UnicodeChar) {
        case Ctl ('c'):
          Key.ScanCode = SCAN_ESC;
          break;

        case Ctl ('j'): /* linefeed */
        case Ctl ('m'): /* return */
          Done = TRUE;
          break;

        case Ctl ('i'): /* tab */
        case ' ':
        case 'd':
        case 'D':
          Key.ScanCode = SCAN_DOWN;
          break;

        case Ctl ('h'): /* backspace */
        case 'u':
        case 'U':
          Key.ScanCode = SCAN_UP;
          break;

        default:
          Key.ScanCode = 0;
        }
      }

      switch (Key.ScanCode) {
      case SCAN_LEFT:
      case SCAN_UP:
        if (NewSelected) {
          --NewSelected;
        }

        break;

      case SCAN_DOWN:
      case SCAN_RIGHT:
        if (++NewSelected == NumMenuItems) {
          --NewSelected;
        }

        break;

      case SCAN_PAGE_UP:
      case SCAN_HOME:
        NewSelected = 0;
        break;

      case SCAN_PAGE_DOWN:
      case SCAN_END:
        NewSelected = NumMenuItems - 1;
        break;

      case SCAN_ESC:
        return LOCAL_BOOT;
      }

      /* unhighlight last selected row */
      gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);

      Aprint ("%a\r", BlankBuf);

      PrintMenuItem (MenuItemPtrs[Selected]);

      Selected = NewSelected;
    } while (!Done);
  }

  SaveNumRte  = Private->EfiBc.Mode->RouteTableEntries;

  Type        = NTOHS (MenuItemPtrs[Selected]->Type);

  if (Type == 0) {
    DEBUG ((EFI_D_WARN, "\nDoMenu()  Local boot selected.  "));
    return LOCAL_BOOT;
  }

  Aprint ("Discover");

  Status = Private->EfiBc.Discover (
                            &Private->EfiBc,
                            Type,
                            &Layer,
                            (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),
                            0
                            );

  if (EFI_ERROR (Status)) {
    Aprint ("\r                    \r");

    DEBUG (
      (EFI_D_WARN,
      "\nDoMenu()  Return w/ %xh (%r).",
      Status,
      Status)
      );

    return Status;
  }

  Aprint ("\rBOOT_SERVER_IP: ");
  PrintIpv4 ((UINT8 *) &Private->ServerIp);

  for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {
    if ((Index % 3) == 0) {
      Aprint ("\r\nGATEWAY IP:");
    }

    Aprint (" ");
    PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);
    Aprint (" ");
  }

  Aprint ("\n");

  DEBUG ((EFI_D_WARN, "\nDoMenu()  Return w/ EFI_SUCCESS.  "));

  return EFI_SUCCESS;
}

STATIC
UINT16
GetValue (
  DHCPV4_OP_STRUCT *OpPtr
  )
/*++

Routine Description:

  Get value 8- or 16-bit value from DHCP option.

Arguments:

  OpPtr - Pointer to DHCP option

Returns:

  Value from DHCP option
  
--*/
{
  if (OpPtr->Header.Length == 1) {
    return OpPtr->Data[0];
  } else {
    return NTOHS (OpPtr->Data);
  }
}

STATIC
UINT8 *
_PxeBcFindOpt (
  UINT8 *BufferPtr,
  UINTN BufferLen,
  UINT8 OpCode
  )
/*++

Routine Description:

  Locate opcode in buffer.

Arguments:

  BufferPtr - Pointer to buffer
  BufferLen - Length of buffer
  OpCode - Option number

Returns:

  Pointer to opcode, may be NULL
  
--*/
{
  if (BufferPtr == NULL) {
    return NULL;
  }

  while (BufferLen != 0) {
    if (*BufferPtr == OpCode) {
      return BufferPtr;
    }

    switch (*BufferPtr) {
    case OP_END:
      return NULL;

    case OP_PAD:
      ++BufferPtr;
      --BufferLen;
      continue;
    }

    if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {
      return NULL;
    }

    BufferLen -= 2 + BufferPtr[1];
    BufferPtr += 2 + BufferPtr[1];
  }

  return NULL;
}

UINT8 *
PxeBcFindDhcpOpt (
  EFI_PXE_BASE_CODE_PACKET  *PacketPtr,
  UINT8                     OpCode
  )
/*++

Routine Description:

  Find option in packet

Arguments:

  PacketPtr - Pointer to packet
  OpCode - option number

Returns:

  Pointer to option in packet
  
--*/
{
  UINTN PacketLen;
  UINT8 Overload;
  UINT8 *OptionBufferPtr;

  //
  //
  //
  PacketLen = 380;
  Overload  = 0;

  //
  // Figure size of DHCP option space.
  //
  OptionBufferPtr = _PxeBcFindOpt (
                      PacketPtr->Dhcpv4.DhcpOptions,
                      380,
                      OP_DHCP_MAX_MESSAGE_SZ
                      );

  if (OptionBufferPtr != NULL) {
    if (OptionBufferPtr[1] == 2) {
      UINT16  n;

      EfiCopyMem (&n, &OptionBufferPtr[2], 2);
      PacketLen = HTONS (n);

      if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {
        PacketLen = 380;
      } else {
        PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;
      }
    }
  }
  //
  // Look for option overloading.
  //
  OptionBufferPtr = _PxeBcFindOpt (
                      PacketPtr->Dhcpv4.DhcpOptions,
                      PacketLen,
                      OP_DHCP_OPTION_OVERLOAD
                      );

  if (OptionBufferPtr != NULL) {
    if (OptionBufferPtr[1] == 1) {
      Overload = OptionBufferPtr[2];
    }
  }
  //
  // Look for caller's option.
  //
  OptionBufferPtr = _PxeBcFindOpt (
                      PacketPtr->Dhcpv4.DhcpOptions,
                      PacketLen,
                      OpCode
                      );

  if (OptionBufferPtr != NULL) {
    return OptionBufferPtr;
  }

  if (Overload & OVLD_FILE) {
    OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);

    if (OptionBufferPtr != NULL) {
      return OptionBufferPtr;
    }
  }

  if (Overload & OVLD_SRVR_NAME) {
    OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);

    if (OptionBufferPtr != NULL) {
      return OptionBufferPtr;
    }
  }

  return NULL;
}

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

Routine Description:

  Download file into buffer

Arguments:

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

Returns:

  EFI_BUFFER_TOO_SMALL -
  EFI_NOT_FOUND -
  EFI_PROTOCOL_ERROR -

--*/
{
  EFI_PXE_BASE_CODE_MTFTP_INFO  MtftpInfo;
  EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;
  DHCP_RECEIVE_BUFFER           *RxBuf;
  EFI_STATUS                    Status;
  UINTN                         BlockSize;

  RxBuf     = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;
  BlockSize = 0x8000;

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

  if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {
    if (Private->FileSize != 0) {
      *BufferSize = Private->FileSize;
      return EFI_BUFFER_TOO_SMALL;
    }

    Aprint ("\nTSize");

    OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;
  } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {
    OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;

    EfiZeroMem (&MtftpInfo, sizeof MtftpInfo);

    *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;

    EfiCopyMem (
      &MtftpInfo.CPort,
      RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,
      sizeof MtftpInfo.CPort
      );

    EfiCopyMem (
      &MtftpInfo.SPort,
      RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,
      sizeof MtftpInfo.SPort
      );

    MtftpInfo.ListenTimeout   = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);

    MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);

    Aprint ("\nMTFTP");
  } else {
    Aprint ("\nTFTP");

    OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
  }

  Private->FileSize = 0;

  RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;

  Status = Private->EfiBc.Mtftp (
                            &Private->EfiBc,
                            OpCode,
                            Buffer,
                            FALSE,
                            BufferSize,
                            &BlockSize,
                            &Private->ServerIp,
                            (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,
                            &MtftpInfo,
                            FALSE
                            );

  if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {
    DEBUG ((EFI_D_WARN, "\nDownloadFile()  Exit #1 %Xh", Status));
    return Status;
  }

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

  if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
    DEBUG ((EFI_D_WARN, "\nDownloadFile()  Exit #2"));
    return EFI_BUFFER_TOO_SMALL;
  }

  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_WARN, "\nDownloadFile()  Exit #3 %Xh", Status));
    return Status;
  }

  if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {
    UINT64  CredentialLen;
    UINTN   BlockSize;
    UINT8   CredentialFilename[256];
    UINT8   *op;
    VOID    *CredentialBuffer;

    //
    // Get name of credential file.  It may be in the BOOTP
    // bootfile field or a DHCP option.
    //
    EfiZeroMem (CredentialFilename, sizeof CredentialFilename);

    op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);

    if (op != NULL) {
      if (op[1] == 0) {
        /* No credential filename */
        return EFI_NOT_FOUND;
      }

      EfiCopyMem (CredentialFilename, &op[2], op[1]);
    } else {
      if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {
        /* No credential filename */
        return EFI_NOT_FOUND;
      }

      EfiCopyMem (CredentialFilename, &op[2], 128);
    }
    //
    // Get size of credential file.  It may be available as a
    // DHCP option.  If not, use the TFTP get file size.
    //
    CredentialLen = 0;

    op            = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);

    if (op != NULL) {
      /*
       * This is actually the size of the credential file
       * buffer.  The actual credential file size will be
       * returned when we download the file.
       */
      if (op[1] == 2) {

⌨️ 快捷键说明

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