/** List out help information on all the commands or print extended information about a specific passed in command. Argv[0] - "help" Argv[1] - Command to display help about @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EFIAPI EblHelpCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Index; CHAR8 *Ptr; UINTN CurrentRow = 0; if (Argc == 1) { // Print all the commands AsciiPrint ("Embedded Boot Loader (EBL) commands (help command for more info):\n"); CurrentRow++; for (Index = 0; Index < mCmdTableNextFreeIndex; Index++) { EblSetTextColor (EFI_YELLOW); AsciiPrint (" %a", mCmdTable[Index]->Name); EblSetTextColor (0); AsciiPrint ("%a\n", mCmdTable[Index]->HelpSummary); // Handle multi line help summaries CurrentRow += CountNewLines (mCmdTable[Index]->HelpSummary); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } } else if (Argv[1] != NULL) { // Print specific help for (Index = 0, CurrentRow = 0; Index < mCmdTableNextFreeIndex; Index++) { if (AsciiStriCmp (Argv[1], mCmdTable[Index]->Name) == 0) { Ptr = (mCmdTable[Index]->Help == NULL) ? mCmdTable[Index]->HelpSummary : mCmdTable[Index]->Help; AsciiPrint ("%a%a\n", Argv[1], Ptr); // Handle multi line help summaries CurrentRow += CountNewLines (Ptr); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } } } return EFI_SUCCESS; }
/** Perform a dir on a device. The device must support Simple File System Protocol or the FV protocol. Argv[0] - "dir" Argv[1] - Device Name:path. Path is optional Argv[2] - Optional filename to match on. A leading * means match substring Argv[3] - Optional FV file type dir fs1:\efi ; perform a dir on fs1: device in the efi directory dir fs1:\efi *.efi; perform a dir on fs1: device in the efi directory but only print out files that contain the string *.efi dir fv1:\ ; perform a dir on fv1: device in the efi directory NOTE: fv devices do not contain subdirs dir fv1:\ * PEIM ; will match all files of type PEIM @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblDirCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_OPEN_FILE *File; EFI_FILE_INFO *DirInfo; UINTN ReadSize; UINTN CurrentRow; CHAR16 *MatchSubString; EFI_STATUS GetNextFileStatus; UINTN Key; EFI_FV_FILETYPE SearchType; EFI_FV_FILETYPE Type; EFI_FV_FILE_ATTRIBUTES Attributes; UINTN Size; EFI_GUID NameGuid; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; UINT32 AuthenticationStatus; VOID *Section; UINTN SectionSize; EFI_FV_FILETYPE Index; UINTN Length; UINTN BestMatchCount; CHAR16 UnicodeFileName[MAX_CMD_LINE]; CHAR8 *Path; CHAR8 *TypeStr; UINTN TotalSize; if (Argc <= 1) { Path = EfiGetCwd (); if (Path == NULL) { return EFI_SUCCESS; } } else { Path = Argv[1]; } File = EfiOpen (Path, EFI_FILE_MODE_READ, 0); if (File == NULL) { return EFI_SUCCESS; } if (File->Type == EfiOpenFirmwareVolume) { // FV Dir SearchType = EFI_FV_FILETYPE_ALL; UnicodeFileName[0] = '\0'; MatchSubString = &UnicodeFileName[0]; if (Argc > 2) { AsciiStrToUnicodeStr (Argv[2], UnicodeFileName); if (UnicodeFileName[0] == '*') { // Handle *Name substring matching MatchSubString = &UnicodeFileName[1]; } // Handle file type matchs if (Argc > 3) { // match a specific file type, always last argument Length = AsciiStrLen (Argv[3]); for (Index = 1, BestMatchCount = 0; Index < sizeof (gFvFileType)/sizeof (CHAR8 *); Index++) { if (AsciiStriCmp (gFvFileType[Index], Argv[3]) == 0) { // exact match SearchType = Index; break; } if (AsciiStrniCmp (Argv[3], gFvFileType[Index], Length) == 0) { // partial match, so keep looking to make sure there is only one partial match BestMatchCount++; SearchType = Index; } } if (BestMatchCount > 1) { SearchType = EFI_FV_FILETYPE_ALL; } } } TotalSize = 0; Fv = File->Fv; Key = 0; CurrentRow = 0; do { Type = SearchType; GetNextFileStatus = Fv->GetNextFile ( Fv, &Key, &Type, &NameGuid, &Attributes, &Size ); if (!EFI_ERROR (GetNextFileStatus)) { TotalSize += Size; // Calculate size of entire file Section = NULL; Size = 0; Status = Fv->ReadFile ( Fv, &NameGuid, Section, &Size, &Type, &Attributes, &AuthenticationStatus ); if (!((Status == EFI_BUFFER_TOO_SMALL) || !EFI_ERROR (Status))) { // EFI_SUCCESS or EFI_BUFFER_TOO_SMALL mean size is valid Size = 0; } TypeStr = (Type <= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) ? gFvFileType[Type] : "UNKNOWN"; // read the UI seciton to do a name match. Section = NULL; Status = Fv->ReadSection ( Fv, &NameGuid, EFI_SECTION_USER_INTERFACE, 0, &Section, &SectionSize, &AuthenticationStatus ); if (!EFI_ERROR (Status)) { if (StrStr (Section, MatchSubString) != NULL) { AsciiPrint ("%,9d %7a %g %s\n", Size, TypeStr, &NameGuid, Section); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } FreePool (Section); } else { if (*MatchSubString == '\0') { AsciiPrint ("%,9d %7a %g\n", Size, TypeStr, &NameGuid); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } } } } while (!EFI_ERROR (GetNextFileStatus)); if (SearchType == EFI_FV_FILETYPE_ALL) { AsciiPrint ("%,20d bytes in files %,d bytes free\n", TotalSize, File->FvSize - File->FvHeaderSize - TotalSize); } } else if ((File->Type == EfiOpenFileSystem) || (File->Type == EfiOpenBlockIo)) { // Simple File System DIR if (File->FsFileInfo == NULL) { return EFI_SUCCESS; } if (!(File->FsFileInfo->Attribute & EFI_FILE_DIRECTORY)) { return EFI_SUCCESS; } // Handle *Name substring matching MatchSubString = NULL; UnicodeFileName[0] = '\0'; if (Argc > 2) { AsciiStrToUnicodeStr (Argv[2], UnicodeFileName); if (UnicodeFileName[0] == '*') { MatchSubString = &UnicodeFileName[1]; } } File->FsFileHandle->SetPosition (File->FsFileHandle, 0); for (CurrentRow = 0;;) { // First read gets the size DirInfo = NULL; ReadSize = 0; Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo); if (Status == EFI_BUFFER_TOO_SMALL) { // Allocate the buffer for the real read DirInfo = AllocatePool (ReadSize); if (DirInfo == NULL) { goto Done; } // Read the data Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo); if ((EFI_ERROR (Status)) || (ReadSize == 0)) { break; } } else { break; } if (MatchSubString != NULL) { if (StrStr (&DirInfo->FileName[0], MatchSubString) == NULL) { // does not match *name argument, so skip continue; } } else if (UnicodeFileName[0] != '\0') { // is not an exact match for name argument, so skip if (StrCmp (&DirInfo->FileName[0], UnicodeFileName) != 0) { continue; } } if (DirInfo->Attribute & EFI_FILE_DIRECTORY) { AsciiPrint (" <DIR> %s\n", &DirInfo->FileName[0]); } else { AsciiPrint ("%,14ld %s\n", DirInfo->FileSize, &DirInfo->FileName[0]); } if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } FreePool (DirInfo); } Done: if (DirInfo != NULL) { FreePool (DirInfo); } } EfiClose (File); return EFI_SUCCESS; }
EFI_STATUS OutputData ( IN UINT8 *Address, IN UINTN Length, IN UINTN Width, IN UINTN Offset ) { UINT8 *EndAddress; UINTN Line; CHAR8 TextLine[0x11]; UINTN CurrentRow = 0; UINTN Bytes; UINTN Spaces = 0; CHAR8 Blanks[80]; AsciiStrCpyS (Blanks, sizeof Blanks, mBlanks); for (EndAddress = Address + Length; Address < EndAddress; Offset += Line) { AsciiPrint ("%08x: ", Offset); for (Line = 0; (Line < 0x10) && (Address < EndAddress);) { Bytes = EndAddress - Address; switch (Width) { case 4: if (Bytes >= 4) { AsciiPrint ("%08x ", *((UINT32 *)Address)); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); } else { AsciiPrint ("%08x ", GetBytes(Address, Bytes)); Address += Bytes; Line += Bytes; } break; case 2: if (Bytes >= 2) { AsciiPrint ("%04x ", *((UINT16 *)Address)); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); } else { AsciiPrint ("%04x ", GetBytes(Address, Bytes)); Address += Bytes; Line += Bytes; } break; case 1: AsciiPrint ("%02x ", *((UINT8 *)Address)); TextLine[Line++] = ConvertToTextLine(*Address++); break; default: AsciiPrint ("Width must be 1, 2, or 4!\n"); return EFI_INVALID_PARAMETER; } } // Pad spaces if (Line < 0x10) { switch (Width) { case 4: Spaces = 9 * ((0x10 - Line)/4); break; case 2: Spaces = 5 * ((0x10 - Line)/2); break; case 1: Spaces = 3 * (0x10 - Line); break; } Blanks[Spaces] = '\0'; AsciiPrint(Blanks); Blanks[Spaces] = ' '; } TextLine[Line] = 0; AsciiPrint ("|%a|\n", TextLine); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { return EFI_END_OF_FILE; } } if (Length % Width != 0) { AsciiPrint ("%08x\n", Offset); } return EFI_SUCCESS; }
/** Dump out the EFI memory map Argv[0] - "memmap" @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblMemMapCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_MEMORY_DESCRIPTOR *MemMap; EFI_MEMORY_DESCRIPTOR *OrigMemMap; UINTN MemMapSize; UINTN MapKey; UINTN DescriptorSize; UINT32 DescriptorVersion; UINT64 PageCount[EfiMaxMemoryType]; UINTN Index; UINT64 EntrySize; UINTN CurrentRow; UINT64 TotalMemory; ZeroMem (PageCount, sizeof (PageCount)); AsciiPrint ("EFI Memory Map\n"); // First call is to figure out how big the buffer needs to be MemMapSize = 0; MemMap = NULL; Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); if (Status == EFI_BUFFER_TOO_SMALL) { // In case the AllocatPool changes the memory map we added in some extra descriptors MemMapSize += (DescriptorSize * 0x100); OrigMemMap = MemMap = AllocatePool (MemMapSize); if (OrigMemMap != NULL) { // 2nd time we get the data Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); if (!EFI_ERROR (Status)) { for (Index = 0, CurrentRow = 0; Index < MemMapSize/DescriptorSize; Index++) { EntrySize = LShiftU64 (MemMap->NumberOfPages, 12); AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType[MemMap->Type % EfiMaxMemoryType], MemMap->PhysicalStart, MemMap->PhysicalStart + EntrySize -1, MemMap->NumberOfPages, MemMap->Attribute); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { break; } PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages; MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize); } } for (Index = 0, TotalMemory = 0; Index < EfiMaxMemoryType; Index++) { if (PageCount[Index] != 0) { AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType[Index], PageCount[Index], LShiftU64 (PageCount[Index], 12)); if (Index == EfiLoaderCode || Index == EfiLoaderData || Index == EfiBootServicesCode || Index == EfiBootServicesData || Index == EfiRuntimeServicesCode || Index == EfiRuntimeServicesData || Index == EfiConventionalMemory || Index == EfiACPIReclaimMemory || Index == EfiACPIMemoryNVS || Index == EfiPalCode ) { // Count total memory TotalMemory += PageCount[Index]; } } } AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12)); FreePool (OrigMemMap); } } return EFI_SUCCESS; }
/** Dump information about devices in the system. fv: PI Firmware Volume fs: EFI Simple File System blk: EFI Block IO LoadFile: EFI Load File Protocol (commonly PXE network boot) Argv[0] - "device" @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblDeviceCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Index; UINTN CurrentRow; UINTN Max; CurrentRow = 0; // Need to call here to make sure Device Counts are valid EblUpdateDeviceLists (); // Now we can print out the info... Max = EfiGetDeviceCounts (EfiOpenFirmwareVolume); if (Max != 0) { AsciiPrint ("Firmware Volume Devices:\n"); for (Index = 0; Index < Max; Index++) { EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume, Index)); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { break; } } } Max = EfiGetDeviceCounts (EfiOpenFileSystem); if (Max != 0) { AsciiPrint ("File System Devices:\n"); for (Index = 0; Index < Max; Index++) { EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem, Index)); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { break; } } } Max = EfiGetDeviceCounts (EfiOpenBlockIo); if (Max != 0) { AsciiPrint ("Block IO Devices:\n"); for (Index = 0; Index < Max; Index++) { EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo, Index)); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { break; } } } Max = EfiGetDeviceCounts (EfiOpenLoadFile); if (Max != 0) { AsciiPrint ("LoadFile Devices: (usually network)\n"); for (Index = 0; Index < Max; Index++) { EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile, Index)); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { break; } } } return EFI_SUCCESS; }