EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c

Go to the documentation of this file.
00001 
00016 #include "PxeBcImpl.h"
00017 
00018 
00028 VOID
00029 PxeBcDisplayBootItem (
00030   IN UINT8                 *Str,
00031   IN UINT8                 Len
00032   )
00033 {
00034   UINT8                    Tmp;
00035 
00036   //
00037   // Cut off the chars behind 70th.
00038   //
00039   Len       = (UINT8) MIN (PXEBC_DISPLAY_MAX_LINE, Len);
00040   Tmp       = Str[Len];
00041   Str[Len]  = 0;
00042   AsciiPrint ("%a \n", Str);
00043 
00044   //
00045   // Restore the original 70th char.
00046   //
00047   Str[Len]  = Tmp;
00048 }
00049 
00050 
00063 EFI_STATUS
00064 PxeBcSelectBootPrompt (
00065   IN PXEBC_PRIVATE_DATA      *Private
00066   )
00067 {
00068   PXEBC_DHCP_PACKET_CACHE    *Cache;
00069   PXEBC_VENDOR_OPTION        *VendorOpt;
00070   EFI_PXE_BASE_CODE_MODE     *Mode;
00071   EFI_EVENT                  TimeoutEvent;
00072   EFI_EVENT                  DescendEvent;
00073   EFI_INPUT_KEY              InputKey;
00074   EFI_STATUS                 Status;
00075   UINT32                     OfferType;
00076   UINT8                      Timeout;
00077   UINT8                      *Prompt;
00078   UINT8                      PromptLen;
00079   INT32                      SecCol;
00080   INT32                      SecRow;
00081 
00082   TimeoutEvent = NULL;
00083   DescendEvent = NULL;
00084   Mode         = Private->PxeBc.Mode;
00085   Cache        = Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Private->DhcpAck;
00086   OfferType    = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;
00087 
00088   //
00089   // Only ProxyPxe10 offer needs boot prompt.
00090   //
00091   if (OfferType != PxeOfferTypeProxyPxe10) {
00092     return EFI_NOT_FOUND;
00093   }
00094 
00095   //
00096   // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.
00097   //
00098   ASSERT (!Mode->UsingIpv6);
00099 
00100   VendorOpt = &Cache->Dhcp4.VendorOpt;
00101   if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {
00102     return EFI_SUCCESS;
00103   }
00104 
00105   Timeout   = VendorOpt->MenuPrompt->Timeout;
00106   Prompt    = VendorOpt->MenuPrompt->Prompt;
00107   PromptLen = (UINT8) (VendorOpt->MenuPromptLen - 1);
00108 
00109   //
00110   // The valid scope of Timeout refers to PXE2.1 spec.
00111   //
00112   if (Timeout == 0) {
00113     return EFI_SUCCESS;
00114   }
00115   if (Timeout == 255) {
00116     return EFI_TIMEOUT;
00117   }
00118 
00119   //
00120   // Create and start a timer as timeout event.
00121   //
00122   Status = gBS->CreateEvent (
00123                   EVT_TIMER,
00124                   TPL_CALLBACK,
00125                   NULL,
00126                   NULL,
00127                   &TimeoutEvent
00128                   );
00129   if (EFI_ERROR (Status)) {
00130     return Status;
00131   }
00132 
00133   Status = gBS->SetTimer (
00134                   TimeoutEvent,
00135                   TimerRelative,
00136                   Timeout * TICKS_PER_SECOND
00137                   );
00138   if (EFI_ERROR (Status)) {
00139     goto ON_EXIT;
00140   }
00141 
00142   //
00143   // Create and start a periodic timer as descend event by second.
00144   //
00145   Status = gBS->CreateEvent (
00146                   EVT_TIMER,
00147                   TPL_CALLBACK,
00148                   NULL,
00149                   NULL,
00150                   &DescendEvent
00151                   );
00152   if (EFI_ERROR (Status)) {
00153     goto ON_EXIT;
00154   }
00155 
00156   Status = gBS->SetTimer (
00157                   DescendEvent,
00158                   TimerPeriodic,
00159                   TICKS_PER_SECOND
00160                   );
00161   if (EFI_ERROR (Status)) {
00162     goto ON_EXIT;
00163   }
00164 
00165   //
00166   // Display the boot item and cursor on the screen.
00167   //
00168   SecCol = gST->ConOut->Mode->CursorColumn;
00169   SecRow = gST->ConOut->Mode->CursorRow;
00170 
00171   PxeBcDisplayBootItem (Prompt, PromptLen);
00172 
00173   gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);
00174   AsciiPrint ("(%d) ", Timeout--);
00175 
00176   while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
00177     if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {
00178       gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);
00179       AsciiPrint ("(%d) ", Timeout--);
00180     }
00181     if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {
00182       gBS->Stall (10 * TICKS_PER_MS);
00183       continue;
00184     }
00185     //
00186     // Parse the input key by user.
00187     //
00188     if (InputKey.ScanCode == 0) {
00189 
00190       switch (InputKey.UnicodeChar) {
00191 
00192       case CTRL ('c'):
00193         Status = EFI_ABORTED;
00194         break;
00195 
00196       case CTRL ('m'):
00197       case 'm':
00198       case 'M':
00199         Status = EFI_TIMEOUT;
00200         break;
00201 
00202       default:
00203         continue;
00204       }
00205 
00206     } else {
00207 
00208       switch (InputKey.ScanCode) {
00209 
00210       case SCAN_F8:
00211         Status = EFI_TIMEOUT;
00212         break;
00213 
00214       case SCAN_ESC:
00215         Status = EFI_ABORTED;
00216         break;
00217 
00218       default:
00219         continue;
00220       }
00221     }
00222 
00223     break;
00224   }
00225 
00226   //
00227   // Reset the cursor on the screen.
00228   //
00229   gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1);
00230 
00231 ON_EXIT:
00232   if (DescendEvent != NULL) {
00233     gBS->CloseEvent (DescendEvent);
00234   }
00235   if (TimeoutEvent != NULL) {
00236     gBS->CloseEvent (TimeoutEvent);
00237   }
00238 
00239   return Status;
00240 }
00241 
00242 
00255 EFI_STATUS
00256 PxeBcSelectBootMenu (
00257   IN  PXEBC_PRIVATE_DATA              *Private,
00258   OUT UINT16                          *Type,
00259   IN  BOOLEAN                         UseDefaultItem
00260   )
00261 {
00262   EFI_PXE_BASE_CODE_MODE     *Mode;
00263   PXEBC_DHCP_PACKET_CACHE    *Cache;
00264   PXEBC_VENDOR_OPTION        *VendorOpt;
00265   EFI_INPUT_KEY              InputKey;
00266   UINT32                     OfferType;
00267   UINT8                      MenuSize;
00268   UINT8                      MenuNum;
00269   INT32                      TopRow;
00270   UINT16                     Select;
00271   UINT16                     LastSelect;
00272   UINT8                      Index;
00273   BOOLEAN                    Finish;
00274   CHAR8                      Blank[PXEBC_DISPLAY_MAX_LINE];
00275   PXEBC_BOOT_MENU_ENTRY      *MenuItem;
00276   PXEBC_BOOT_MENU_ENTRY      *MenuArray[PXEBC_MENU_MAX_NUM];
00277 
00278   Finish    = FALSE;
00279   Select    = 1;
00280   Index     = 0;
00281   *Type     = 0;
00282   Mode      = Private->PxeBc.Mode;
00283   Cache     = Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Private->DhcpAck;
00284   OfferType = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;
00285 
00286   //
00287   // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.
00288   //
00289   ASSERT (!Mode->UsingIpv6);
00290   ASSERT (OfferType == PxeOfferTypeProxyPxe10);
00291 
00292   VendorOpt = &Cache->Dhcp4.VendorOpt;
00293   if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {
00294     return EFI_SUCCESS;
00295   }
00296 
00297   //
00298   // Display the boot menu on the screen.
00299   //
00300   SetMem (Blank, sizeof(Blank), ' ');
00301 
00302   MenuSize  = VendorOpt->BootMenuLen;
00303   MenuItem  = VendorOpt->BootMenu;
00304 
00305   if (MenuSize == 0) {
00306     return EFI_DEVICE_ERROR;
00307   }
00308 
00309   while (MenuSize > 0 && Index < PXEBC_MENU_MAX_NUM) {
00310     ASSERT (MenuItem != NULL);
00311     MenuArray[Index]  = MenuItem;
00312     MenuSize          = (UINT8) (MenuSize - (MenuItem->DescLen + 3));
00313     MenuItem          = (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + MenuItem->DescLen + 3);
00314     Index++;
00315   }
00316 
00317   if (UseDefaultItem) {
00318     ASSERT (MenuArray[0] != NULL);
00319     CopyMem (Type, &MenuArray[0]->Type, sizeof (UINT16));
00320     *Type = NTOHS (*Type);
00321     return EFI_SUCCESS;
00322   }
00323 
00324   MenuNum = Index;
00325 
00326   for (Index = 0; Index < MenuNum; Index++) {
00327     ASSERT (MenuArray[Index] != NULL);
00328     PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);
00329   }
00330 
00331   TopRow = gST->ConOut->Mode->CursorRow - MenuNum;
00332 
00333   //
00334   // Select the boot item by user in the boot menu.
00335   //
00336   do {
00337     //
00338     // Highlight selected row.
00339     //
00340     gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
00341     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);
00342     ASSERT (Select < PXEBC_MENU_MAX_NUM);
00343     ASSERT (MenuArray[Select] != NULL);
00344     Blank[MenuArray[Select]->DescLen] = 0;
00345     AsciiPrint ("%a\r", Blank);
00346     PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);
00347     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);
00348     LastSelect = Select;
00349 
00350     while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {
00351       gBS->Stall (10 * TICKS_PER_MS);
00352     }
00353 
00354     if (InputKey.ScanCode != 0) {
00355       switch (InputKey.UnicodeChar) {
00356       case CTRL ('c'):
00357         InputKey.ScanCode = SCAN_ESC;
00358         break;
00359 
00360       case CTRL ('j'):  /* linefeed */
00361       case CTRL ('m'):  /* return */
00362         Finish = TRUE;
00363         break;
00364 
00365       case CTRL ('i'):  /* tab */
00366       case ' ':
00367       case 'd':
00368       case 'D':
00369         InputKey.ScanCode = SCAN_DOWN;
00370         break;
00371 
00372       case CTRL ('h'):  /* backspace */
00373       case 'u':
00374       case 'U':
00375         InputKey.ScanCode = SCAN_UP;
00376         break;
00377 
00378       default:
00379         InputKey.ScanCode = 0;
00380       }
00381     }
00382 
00383     switch (InputKey.ScanCode) {
00384     case SCAN_LEFT:
00385     case SCAN_UP:
00386       if (Select != 0) {
00387         Select--;
00388       }
00389       break;
00390 
00391     case SCAN_DOWN:
00392     case SCAN_RIGHT:
00393       if (++Select == MenuNum) {
00394         Select--;
00395       }
00396       break;
00397 
00398     case SCAN_PAGE_UP:
00399     case SCAN_HOME:
00400       Select = 0;
00401       break;
00402 
00403     case SCAN_PAGE_DOWN:
00404     case SCAN_END:
00405       Select = (UINT16) (MenuNum - 1);
00406       break;
00407 
00408     case SCAN_ESC:
00409       return EFI_ABORTED;
00410     }
00411 
00412     //
00413     // Unhighlight the last selected row.
00414     //
00415     gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
00416     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);
00417     ASSERT (LastSelect < PXEBC_MENU_MAX_NUM);
00418     ASSERT (MenuArray[LastSelect] != NULL);
00419     Blank[MenuArray[LastSelect]->DescLen] = 0;
00420     AsciiPrint ("%a\r", Blank);
00421     PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);
00422     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);
00423   } while (!Finish);
00424 
00425   //
00426   // Swap the byte order.
00427   //
00428   ASSERT (Select < PXEBC_MENU_MAX_NUM);
00429   ASSERT (MenuArray[Select] != NULL);
00430   CopyMem (Type, &MenuArray[Select]->Type, sizeof (UINT16));
00431   *Type = NTOHS (*Type);
00432 
00433   return EFI_SUCCESS;
00434 }
00435 
00436 
00447 EFI_STATUS
00448 PxeBcDhcp4BootInfo (
00449   IN OUT PXEBC_PRIVATE_DATA   *Private,
00450      OUT UINT64               *BufferSize
00451   )
00452 {
00453   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
00454   EFI_PXE_BASE_CODE_MODE      *Mode;
00455   EFI_STATUS                  Status;
00456   PXEBC_DHCP4_PACKET_CACHE    *Cache4;
00457   UINT16                      Value;
00458 
00459   PxeBc       = &Private->PxeBc;
00460   Mode        = PxeBc->Mode;
00461   Status      = EFI_SUCCESS;
00462   *BufferSize = 0;
00463 
00464   //
00465   // Get the last received Dhcp4 reply packet.
00466   //
00467   if (Mode->PxeReplyReceived) {
00468     Cache4 = &Private->PxeReply.Dhcp4;
00469   } else if (Mode->ProxyOfferReceived) {
00470     Cache4 = &Private->ProxyOffer.Dhcp4;
00471   } else {
00472     Cache4 = &Private->DhcpAck.Dhcp4;
00473   }
00474 
00475   //
00476   // Parse the boot server Ipv4 address by next server address.
00477   // If this field isn't available, use option 54 instead.
00478   //
00479   CopyMem (
00480     &Private->ServerIp,
00481     &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,
00482     sizeof (EFI_IPv4_ADDRESS)
00483     );
00484 
00485   if (Private->ServerIp.Addr[0] == 0) {
00486     CopyMem (
00487       &Private->ServerIp,
00488       Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
00489       sizeof (EFI_IPv4_ADDRESS)
00490       );
00491   }
00492 
00493   //
00494   // Parse the boot file name by option.
00495   //
00496   ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
00497   Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data;
00498 
00499   if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
00500     //
00501     // Parse the boot file size by option.
00502     //
00503     CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
00504     Value       = NTOHS (Value);
00505     //
00506     // The field of boot file size is 512 bytes in unit.
00507     //
00508     *BufferSize = 512 * Value;
00509   } else {
00510     //
00511     // Get the bootfile size by tftp command if no option available.
00512     //
00513     Status = PxeBc->Mtftp (
00514                       PxeBc,
00515                       EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
00516                       NULL,
00517                       FALSE,
00518                       BufferSize,
00519                       &Private->BlockSize,
00520                       &Private->ServerIp,
00521                       Private->BootFileName,
00522                       NULL,
00523                       FALSE
00524                       );
00525   }
00526 
00527   //
00528   // Save the value of boot file size.
00529   //
00530   Private->BootFileSize = (UINTN) *BufferSize;
00531 
00532   //
00533   // Display all the information: boot server address, boot file name and boot file size.
00534   //
00535   AsciiPrint ("\n  Server IP address is ");
00536   PxeBcShowIp4Addr (&Private->ServerIp.v4);
00537   AsciiPrint ("\n  NBP filename is %a", Private->BootFileName);
00538   AsciiPrint ("\n  NBP filesize is %d Bytes", Private->BootFileSize);
00539 
00540   return Status;
00541 }
00542 
00543 
00555 EFI_STATUS
00556 PxeBcDhcp6BootInfo (
00557   IN OUT PXEBC_PRIVATE_DATA   *Private,
00558      OUT UINT64               *BufferSize
00559   )
00560 {
00561   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
00562   EFI_PXE_BASE_CODE_MODE      *Mode;
00563   EFI_STATUS                  Status;
00564   PXEBC_DHCP6_PACKET_CACHE    *Cache6;
00565   UINT16                      Value;
00566 
00567   PxeBc       = &Private->PxeBc;
00568   Mode        = PxeBc->Mode;
00569   Status      = EFI_SUCCESS;
00570   *BufferSize = 0;
00571 
00572   //
00573   // Get the last received Dhcp6 reply packet.
00574   //
00575   if (Mode->PxeReplyReceived) {
00576     Cache6 = &Private->PxeReply.Dhcp6;
00577   } else if (Mode->ProxyOfferReceived) {
00578     Cache6 = &Private->ProxyOffer.Dhcp6;
00579   } else {
00580     Cache6 = &Private->DhcpAck.Dhcp6;
00581   }
00582 
00583   ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
00584 
00585   //
00586   // Parse (m)tftp server ip address and bootfile name.
00587   //
00588   Status = PxeBcExtractBootFileUrl (
00589              &Private->BootFileName,
00590              &Private->ServerIp.v6,
00591              (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
00592              NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
00593              );
00594   if (EFI_ERROR (Status)) {
00595     return Status;
00596   }
00597 
00598   //
00599   // Parse the value of boot file size.
00600   //
00601   if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] != NULL) {
00602     //
00603     // Parse it out if have the boot file parameter option.
00604     //
00605     Status = PxeBcExtractBootFileParam ((CHAR8 *) Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM]->Data, &Value);
00606     if (EFI_ERROR (Status)) {
00607       return Status;
00608     }
00609     //
00610     // The field of boot file size is 512 bytes in unit.
00611     //
00612     *BufferSize = 512 * Value;
00613   } else {
00614     //
00615     // Send get file size command by tftp if option unavailable.
00616     //
00617     Status = PxeBc->Mtftp (
00618                       PxeBc,
00619                       EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
00620                       NULL,
00621                       FALSE,
00622                       BufferSize,
00623                       &Private->BlockSize,
00624                       &Private->ServerIp,
00625                       Private->BootFileName,
00626                       NULL,
00627                       FALSE
00628                       );
00629   }
00630 
00631   //
00632   // Save the value of boot file size.
00633   //
00634   Private->BootFileSize = (UINTN) *BufferSize;
00635 
00636   //
00637   // Display all the information: boot server address, boot file name and boot file size.
00638   //
00639   AsciiPrint ("\n  Server IP address is ");
00640   PxeBcShowIp6Addr (&Private->ServerIp.v6);
00641   AsciiPrint ("\n  NBP filename is %a", Private->BootFileName);
00642   AsciiPrint ("\n  NBP filesize is %d Bytes", Private->BootFileSize);
00643 
00644   return Status;
00645 }
00646 
00647 
00662 EFI_STATUS
00663 PxeBcExtractDiscoverInfo (
00664   IN     PXEBC_PRIVATE_DATA               *Private,
00665   IN     UINT16                           Type,
00666   IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO  *Info,
00667      OUT PXEBC_BOOT_SVR_ENTRY             **BootEntry,
00668      OUT EFI_PXE_BASE_CODE_SRVLIST        **SrvList
00669   )
00670 {
00671   EFI_PXE_BASE_CODE_MODE          *Mode;
00672   PXEBC_DHCP4_PACKET_CACHE        *Cache4;
00673   PXEBC_VENDOR_OPTION             *VendorOpt;
00674   PXEBC_BOOT_SVR_ENTRY            *Entry;
00675   BOOLEAN                         IsFound;
00676 
00677   Mode = Private->PxeBc.Mode;
00678 
00679   if (Mode->UsingIpv6) {
00680     Info->IpCnt    = 1;
00681     Info->UseUCast = TRUE;
00682 
00683     Info->SrvList[0].Type              = Type;
00684     Info->SrvList[0].AcceptAnyResponse = FALSE;
00685 
00686     //
00687     // There is no vendor options specified in DHCPv6, so take BootFileUrl in the last cached packet.
00688     //
00689     CopyMem (&Info->SrvList[0].IpAddr, &Private->ServerIp, sizeof (EFI_IP_ADDRESS));
00690 
00691     *SrvList  = Info->SrvList;
00692   } else {
00693     Entry     = NULL;
00694     IsFound   = FALSE;
00695     Cache4    = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer.Dhcp4 : &Private->DhcpAck.Dhcp4;
00696     VendorOpt = &Cache4->VendorOpt;
00697 
00698     if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {
00699       //
00700       // Address is not acquired or no discovery options.
00701       //
00702       return EFI_INVALID_PARAMETER;
00703     }
00704 
00705     //
00706     // Parse the boot server entry from the vendor option in the last cached packet.
00707     //
00708     Info->UseMCast    = (BOOLEAN) !IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);
00709     Info->UseBCast    = (BOOLEAN) !IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);
00710     Info->MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);
00711     Info->UseUCast    = Info->MustUseList;
00712 
00713     if (Info->UseMCast) {
00714       //
00715       // Get the multicast discover ip address from vendor option if has.
00716       //
00717       CopyMem (&Info->ServerMCastIp.v4, &VendorOpt->DiscoverMcastIp, sizeof (EFI_IPv4_ADDRESS));
00718     }
00719 
00720     Info->IpCnt = 0;
00721 
00722     if (Info->MustUseList) {
00723       Entry = VendorOpt->BootSvr;
00724 
00725       while (((UINT8) (Entry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {
00726         if (Entry->Type == HTONS (Type)) {
00727           IsFound = TRUE;
00728           break;
00729         }
00730         Entry = GET_NEXT_BOOT_SVR_ENTRY (Entry);
00731       }
00732 
00733       if (!IsFound) {
00734         return EFI_DEVICE_ERROR;
00735       }
00736 
00737       Info->IpCnt = Entry->IpCnt;
00738     }
00739 
00740     *BootEntry = Entry;
00741   }
00742 
00743   return EFI_SUCCESS;
00744 }
00745 
00746 
00764 EFI_STATUS
00765 PxeBcDiscoverBootServer (
00766   IN  PXEBC_PRIVATE_DATA                *Private,
00767   IN  UINT16                            Type,
00768   IN  UINT16                            *Layer,
00769   IN  BOOLEAN                           UseBis,
00770   IN  EFI_IP_ADDRESS                    *DestIp,
00771   IN  UINT16                            IpCount,
00772   IN  EFI_PXE_BASE_CODE_SRVLIST         *SrvList
00773   )
00774 {
00775   if (Private->PxeBc.Mode->UsingIpv6) {
00776     return PxeBcDhcp6Discover (
00777              Private,
00778              Type,
00779              Layer,
00780              UseBis,
00781              DestIp
00782              );
00783   } else {
00784     return PxeBcDhcp4Discover (
00785              Private,
00786              Type,
00787              Layer,
00788              UseBis,
00789              DestIp,
00790              IpCount,
00791              SrvList
00792              );
00793   }
00794 }
00795 
00796 
00809 EFI_STATUS
00810 PxeBcDiscoverBootFile (
00811   IN OUT PXEBC_PRIVATE_DATA   *Private,
00812      OUT UINT64               *BufferSize
00813   )
00814 {
00815   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
00816   EFI_PXE_BASE_CODE_MODE      *Mode;
00817   EFI_STATUS                  Status;
00818   UINT16                      Type;
00819   UINT16                      Layer;
00820   BOOLEAN                     UseBis;
00821 
00822   PxeBc = &Private->PxeBc;
00823   Mode  = PxeBc->Mode;
00824   Type  = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;
00825   Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;
00826 
00827   //
00828   // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
00829   // other pxe boot information.
00830   //
00831   Status = PxeBc->Dhcp (PxeBc, TRUE);
00832   if (EFI_ERROR (Status)) {
00833     return Status;
00834   }
00835 
00836   //
00837   // Select a boot server from boot server list.
00838   //
00839   Status = PxeBcSelectBootPrompt (Private);
00840 
00841   if (Status == EFI_SUCCESS) {
00842     //
00843     // Choose by user's input.
00844     //
00845     Status = PxeBcSelectBootMenu (Private, &Type, TRUE);
00846   } else if (Status == EFI_TIMEOUT) {
00847     //
00848     // Choose by default item.
00849     //
00850     Status = PxeBcSelectBootMenu (Private, &Type, FALSE);
00851   }
00852 
00853   if (!EFI_ERROR (Status)) {
00854 
00855     if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {
00856       //
00857       // Local boot(PXE bootstrap server) need abort
00858       //
00859       return EFI_ABORTED;
00860     }
00861 
00862     //
00863     // Start to discover the boot server to get (m)tftp server ip address, bootfile
00864     // name and bootfile size.
00865     //
00866     UseBis = (BOOLEAN) (Mode->BisSupported && Mode->BisDetected);
00867     Status = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);
00868     if (EFI_ERROR (Status)) {
00869       return Status;
00870     }
00871   }
00872 
00873   //
00874   // Parse the boot information.
00875   //
00876   if (Mode->UsingIpv6) {
00877     Status = PxeBcDhcp6BootInfo (Private, BufferSize);
00878   } else {
00879     Status = PxeBcDhcp4BootInfo (Private, BufferSize);
00880   }
00881 
00882   return Status;
00883 }
00884 
00885 
00896 EFI_STATUS
00897 PxeBcInstallCallback (
00898   IN OUT PXEBC_PRIVATE_DATA   *Private,
00899      OUT BOOLEAN              *NewMakeCallback
00900   )
00901 {
00902   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
00903   EFI_STATUS                  Status;
00904 
00905   //
00906   // Check whether PxeBaseCodeCallbackProtocol already installed.
00907   //
00908   PxeBc  = &Private->PxeBc;
00909   Status = gBS->HandleProtocol (
00910                   Private->Controller,
00911                   &gEfiPxeBaseCodeCallbackProtocolGuid,
00912                   (VOID **) &Private->PxeBcCallback
00913                   );
00914   if (Status == EFI_UNSUPPORTED) {
00915 
00916     CopyMem (
00917       &Private->LoadFileCallback,
00918       &gPxeBcCallBackTemplate,
00919       sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL)
00920       );
00921 
00922     //
00923     // Install a default callback if user didn't offer one.
00924     //
00925     Status = gBS->InstallProtocolInterface (
00926                     &Private->Controller,
00927                     &gEfiPxeBaseCodeCallbackProtocolGuid,
00928                     EFI_NATIVE_INTERFACE,
00929                     &Private->LoadFileCallback
00930                     );
00931 
00932     (*NewMakeCallback) = (BOOLEAN) (Status == EFI_SUCCESS);
00933 
00934     Status = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, NewMakeCallback);
00935     if (EFI_ERROR (Status)) {
00936       PxeBc->Stop (PxeBc);
00937       return Status;
00938     }
00939   }
00940 
00941   return EFI_SUCCESS;
00942 }
00943 
00944 
00953 VOID
00954 PxeBcUninstallCallback (
00955   IN PXEBC_PRIVATE_DATA        *Private,
00956   IN BOOLEAN                   NewMakeCallback
00957   )
00958 {
00959   EFI_PXE_BASE_CODE_PROTOCOL   *PxeBc;
00960 
00961   PxeBc = &Private->PxeBc;
00962 
00963   if (NewMakeCallback) {
00964 
00965     NewMakeCallback = FALSE;
00966 
00967     PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
00968 
00969     gBS->UninstallProtocolInterface (
00970           Private->Controller,
00971           &gEfiPxeBaseCodeCallbackProtocolGuid,
00972           &Private->LoadFileCallback
00973           );
00974   }
00975 }
00976 
00977 
00992 EFI_STATUS
00993 PxeBcReadBootFileList (
00994   IN     PXEBC_PRIVATE_DATA           *Private,
00995   IN OUT UINT64                       *BufferSize,
00996   IN     VOID                         *Buffer           OPTIONAL
00997   )
00998 {
00999   EFI_STATUS                          Status;
01000   EFI_PXE_BASE_CODE_PROTOCOL          *PxeBc;
01001 
01002   PxeBc        = &Private->PxeBc;
01003 
01004   //
01005   // Try to download the boot file if everything is ready.
01006   //
01007   if (Buffer != NULL) {
01008     Status = PxeBc->Mtftp (
01009                       PxeBc,
01010                       EFI_PXE_BASE_CODE_TFTP_READ_FILE,
01011                       Buffer,
01012                       FALSE,
01013                       BufferSize,
01014                       &Private->BlockSize,
01015                       &Private->ServerIp,
01016                       Private->BootFileName,
01017                       NULL,
01018                       FALSE
01019                       );
01020 
01021 
01022   } else {
01023     Status      = EFI_BUFFER_TOO_SMALL;
01024   }
01025 
01026   return Status;
01027 }
01028 
01029 
01044 EFI_STATUS
01045 PxeBcLoadBootFile (
01046   IN     PXEBC_PRIVATE_DATA           *Private,
01047   IN OUT UINTN                        *BufferSize,
01048   IN     VOID                         *Buffer         OPTIONAL
01049   )
01050 {
01051   BOOLEAN                             NewMakeCallback;
01052   UINT64                              RequiredSize;
01053   UINT64                              CurrentSize;
01054   EFI_STATUS                          Status;
01055   EFI_PXE_BASE_CODE_PROTOCOL          *PxeBc;
01056   EFI_PXE_BASE_CODE_MODE              *PxeBcMode;
01057 
01058   NewMakeCallback = FALSE;
01059   PxeBc           = &Private->PxeBc;
01060   PxeBcMode       = &Private->Mode;
01061   CurrentSize     = *BufferSize;
01062   RequiredSize    = 0;
01063 
01064   //
01065   // Install pxebc callback protocol if hasn't been installed yet.
01066   //
01067   Status = PxeBcInstallCallback (Private, &NewMakeCallback);
01068   if (EFI_ERROR(Status)) {
01069     return Status;
01070   }
01071 
01072   if (Private->BootFileSize == 0) {
01073     //
01074     // Discover the boot information about the bootfile if hasn't.
01075     //
01076     Status = PxeBcDiscoverBootFile (Private, &RequiredSize);
01077     if (EFI_ERROR (Status)) {
01078       goto ON_EXIT;
01079     }
01080 
01081     if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize)) {
01082       //
01083       // It's error if the required buffer size is beyond the system scope.
01084       //
01085       Status = EFI_DEVICE_ERROR;
01086       goto ON_EXIT;
01087     } else if (RequiredSize > 0) {
01088       //
01089       // Get the right buffer size of the bootfile required.
01090       //
01091       if (CurrentSize < RequiredSize || Buffer == NULL) {
01092         //
01093         // It's buffer too small if the size of user buffer is smaller than the required.
01094         //
01095         CurrentSize = RequiredSize;
01096         Status      = EFI_BUFFER_TOO_SMALL;
01097         goto ON_EXIT;
01098       }
01099       CurrentSize = RequiredSize;
01100     } else if (RequiredSize == 0 && PxeBcMode->UsingIpv6) {
01101       //
01102       // Try to download another bootfile in list if failed to get the filesize of the last one.
01103       // It's special for the case of IPv6.
01104       //
01105       Status = PxeBcReadBootFileList (Private, &CurrentSize, Buffer);
01106       goto ON_EXIT;
01107     }
01108   } else if (CurrentSize < Private->BootFileSize || Buffer == NULL ) {
01109     //
01110     // It's buffer too small if the size of user buffer is smaller than the required.
01111     //
01112     CurrentSize = Private->BootFileSize;
01113     Status      = EFI_BUFFER_TOO_SMALL;
01114     goto ON_EXIT;
01115   }
01116 
01117   //
01118   // Begin to download the bootfile if everything is ready.
01119   //
01120   AsciiPrint ("\n Downloading NBP file...\n");
01121   if (PxeBcMode->UsingIpv6) {
01122     Status = PxeBcReadBootFileList (
01123                Private,
01124                &CurrentSize,
01125                Buffer
01126                );
01127   } else {
01128     Status = PxeBc->Mtftp (
01129                       PxeBc,
01130                       EFI_PXE_BASE_CODE_TFTP_READ_FILE,
01131                       Buffer,
01132                       FALSE,
01133                       &CurrentSize,
01134                       &Private->BlockSize,
01135                       &Private->ServerIp,
01136                       Private->BootFileName,
01137                       NULL,
01138                       FALSE
01139                       );
01140   }
01141 
01142 ON_EXIT:
01143   *BufferSize = (UINTN) CurrentSize;
01144   PxeBcUninstallCallback(Private, NewMakeCallback);
01145 
01146   if (Status == EFI_SUCCESS) {
01147     AsciiPrint ("\n  Succeed to download NBP file.\n");
01148     return EFI_SUCCESS;
01149   } else if (Status == EFI_BUFFER_TOO_SMALL && Buffer != NULL) {
01150     AsciiPrint ("\n  PXE-E05: Buffer size is smaller than the requested file.\n");
01151   } else if (Status == EFI_DEVICE_ERROR) {
01152     AsciiPrint ("\n  PXE-E07: Network device error.\n");
01153   } else if (Status == EFI_OUT_OF_RESOURCES) {
01154     AsciiPrint ("\n  PXE-E09: Could not allocate I/O buffers.\n");
01155   } else if (Status == EFI_NO_MEDIA) {
01156     AsciiPrint ("\n  PXE-E12: Could not detect network connection.\n");
01157   } else if (Status == EFI_NO_RESPONSE) {
01158     AsciiPrint ("\n  PXE-E16: No offer received.\n");
01159   } else if (Status == EFI_TIMEOUT) {
01160     AsciiPrint ("\n  PXE-E18: Server response timeout.\n");
01161   } else if (Status == EFI_ABORTED) {
01162     AsciiPrint ("\n  PXE-E21: Remote boot cancelled.\n");
01163   } else if (Status == EFI_ICMP_ERROR) {
01164     AsciiPrint ("\n  PXE-E22: Client received ICMP error from server.\n");
01165   } else if (Status == EFI_TFTP_ERROR) {
01166     AsciiPrint ("\n  PXE-E23: Client received TFTP error from server.\n");
01167   } else if (Status == EFI_NOT_FOUND) {
01168     AsciiPrint ("\n  PXE-E53: No boot filename received.\n");
01169   } else if (Status != EFI_BUFFER_TOO_SMALL) {
01170     AsciiPrint ("\n  PXE-E99: Unexpected network error.\n");
01171   }
01172 
01173   return Status;
01174 }
01175 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines