Example #1
0
/**
  Write to IO space

  Argv[0] - "iowrite"[.#] # is optional width 1, 2, or 4. Default 1
  Argv[1] - Hex IO address
  Argv[2] - Hex data to write

  iow.4 0x3f8 af  ;Do a 32-bit IO write of af to 0x3f8
  iow   0x3f8 af  ;Do an 8-bit IO write of af to 0x3f8

  @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
EblIoWriteCmd (
  IN UINTN  Argc,
  IN CHAR8  **Argv
  )
{
  UINTN   Width;
  UINTN   Port;
  UINTN   Data;

  if (Argc < 3) {
    return EFI_INVALID_PARAMETER;
  }

  Port = AsciiStrHexToUintn (Argv[1]);
  Data = AsciiStrHexToUintn (Argv[2]);
  Width = WidthFromCommandName (Argv[0], 1);

  if (Width == 1) {
    IoWrite8 (Port, (UINT8)Data);
  } else if (Width == 2) {
    IoWrite16 (Port, (UINT16)Data);
  } else if (Width == 4) {
    IoWrite32 (Port, (UINT32)Data);
  } else {
    return EFI_INVALID_PARAMETER;
  }
  return EFI_SUCCESS;
}
Example #2
0
/**
  Simple arm disassembler via a library

  Argv[0] - disasm
  Argv[1] - Address to start disassembling from
  ARgv[2] - Number of instructions to disassembly (optional)

  @param  Argc   Number of command arguments in Argv
  @param  Argv   Array of strings that represent the parsed command line. 
                 Argv[0] is the comamnd name

  @return EFI_SUCCESS

**/
EFI_STATUS
EblDisassembler (
  IN UINTN  Argc,
  IN CHAR8  **Argv
  )
{
  UINT8   *Ptr, *CurrentAddress;
  UINT32  Address;
  UINT32  Count;
  CHAR8   Buffer[80];
  UINT32  ItBlock;
  
  if (Argc < 2) {
    return EFI_INVALID_PARAMETER;
  }
  
  Address = AsciiStrHexToUintn (Argv[1]);
  Count   = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 20;

  Ptr = (UINT8 *)(UINTN)Address;  
  ItBlock = 0;
  do {
    CurrentAddress = Ptr;
    DisassembleInstruction (&Ptr, TRUE, TRUE, &ItBlock, Buffer, sizeof (Buffer));
    AsciiPrint ("0x%08x: %a\n", CurrentAddress, Buffer);
  } while (Count-- > 0);
 

  return EFI_SUCCESS;
}
Example #3
0
/** ‘P n...=r...’
 Writes the new value of n-th register received into the input buffer to the n-th register

 @param   SystemContext   Register content at time of the exception
 @param   InBuffer      Ponter to the input buffer received from gdb server
 **/
VOID
EFIAPI
WriteNthRegister (
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
  IN  CHAR8           *InBuffer
  )
{
  UINTN RegNumber;
  CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE];  // put the 'n..' part of the message into this array
  CHAR8 *RegNumBufPtr;
  CHAR8 *InBufPtr; // pointer to the input buffer
  
  // find the register number to write
  InBufPtr = &InBuffer[1];
  RegNumBufPtr = RegNumBuffer;
  while (*InBufPtr != '=') {
    *RegNumBufPtr++ = *InBufPtr++;
  } 
  *RegNumBufPtr = '\0';
  RegNumber = AsciiStrHexToUintn (RegNumBuffer); 

  // check if this is a valid Register Number
  if ((RegNumber < 0) || (RegNumber >= sizeof (gRegisterOffsets)/sizeof (UINTN))) {
	SendError (GDB_EINVALIDREGNUM); 
    return;
  }
  InBufPtr++;  // skips the '=' character
  BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
  SendSuccess();
}
Example #4
0
/**
  Read from IO space

  Argv[0] - "ioread"[.#] # is optional width 1, 2, or 4. Default 1
  Argv[1] - Hex IO address

  ior.4 0x3f8  ;Do a 32-bit IO Read from 0x3f8
  ior   0x3f8  ;Do a  8-bit IO Read from 0x3f8

  @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
EblIoReadCmd (
  IN UINTN  Argc,
  IN CHAR8  **Argv
  )
{
  UINTN   Width;
  UINTN   Port;
  UINTN   Data;

  if (Argc < 2) {
    return EFI_INVALID_PARAMETER;
  }

  Port = AsciiStrHexToUintn (Argv[1]);
  Width = WidthFromCommandName (Argv[0], 1);

  if (Width == 1) {
    Data = IoRead8 (Port);
  } else if (Width == 2) {
    Data = IoRead16 (Port);
  } else if (Width == 4) {
    Data = IoRead32 (Port);
  } else {
    return EFI_INVALID_PARAMETER;
  }

  AsciiPrint ("0x%04x = 0x%x", Port, Data);

  return EFI_SUCCESS;
}
Example #5
0
/**
  Get section entry heximal UINTN value.

  @param[in]  Context         INI Config file context.
  @param[in]  SectionName     Section name.
  @param[in]  EntryName       Section entry name.
  @param[out] Data            Point to the got heximal UINTN value.

  @retval EFI_SUCCESS    Section entry heximal UINTN value is got.
  @retval EFI_NOT_FOUND  Section is not found.
**/
EFI_STATUS
EFIAPI
GetHexUintnFromDataFile (
  IN      VOID                          *Context,
  IN      CHAR8                         *SectionName,
  IN      CHAR8                         *EntryName,
  OUT     UINTN                         *Data
  )
{
  CHAR8                                 *Value;
  EFI_STATUS                            Status;

  if (Context == NULL || SectionName == NULL || EntryName == NULL || Data == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Status = GetStringFromDataFile(
             Context,
             SectionName,
             EntryName,
             &Value
             );
  if (EFI_ERROR(Status)) {
    return EFI_NOT_FOUND;
  }
  ASSERT (Value != NULL);
  if (!IsValidHexString(Value, AsciiStrLen(Value))) {
    return EFI_NOT_FOUND;
  }
  *Data = AsciiStrHexToUintn(Value);
  return EFI_SUCCESS;
}
Example #6
0
/**
  Receive a GDB Remote Serial Protocol Packet

  $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
  the packet teminating character '#' and the two digit checksum.

  If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed.
  (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)

  If an ack '+' is not sent resend the packet

  @param PacketData   Payload data for the packet

  @retval             Number of bytes of packet data received.

**/
UINTN
ReceivePacket (
  OUT  CHAR8 *PacketData,
  IN   UINTN PacketDataSize
 )
{
  UINT8 CheckSum;
  UINTN Index;
  CHAR8 Char;
  CHAR8 SumString[3];
  CHAR8 TestChar;

  ZeroMem (PacketData, PacketDataSize);

  for (;;) {
      // wait for the start of a packet
    TestChar = GdbGetChar ();
    while (TestChar != '$') {
      TestChar = GdbGetChar ();
    };

  retry:
    for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) {
      Char = GdbGetChar ();
      if (Char == '$') {
        goto retry;
      }
      if (Char == '#') {
        break;
      }

      PacketData[Index] = Char;
      CheckSum = CheckSum + Char;
    }
    PacketData[Index] = '\0';

    if (Index == PacketDataSize) {
      continue;
    }

    SumString[0] = GdbGetChar ();
    SumString[1] = GdbGetChar ();
    SumString[2] = '\0';

    if (AsciiStrHexToUintn (SumString) == CheckSum) {
      // Ack: Success
      GdbPutChar ('+');

      // Null terminate the callers string
      PacketData[Index] = '\0';
      return Index;
    } else {
      // Ack: Failure
      GdbPutChar ('-');
    }
  }

  //return 0;
}
Example #7
0
/** ‘c [addr ]’ 
 Continue. addr is Address to resume. If addr is omitted, resume at current 
 Address.
 
 @param   SystemContext     Register content at time of the exception  
 **/
VOID
EFIAPI
ContinueAtAddress (
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
  IN    CHAR8                 *PacketData
  )
{
  if (PacketData[1] != '\0') {
    SystemContext.SystemContextIa32->Eip = AsciiStrHexToUintn (&PacketData[1]);
  } 
}
Example #8
0
/** ‘s [addr ]’
 Single step. addr is the Address at which to resume. If addr is omitted, resume 
 at same Address.
 
 @param   SystemContext     Register content at time of the exception  
 **/
VOID
EFIAPI
SingleStep (
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
  IN    CHAR8                 *PacketData
  )
{
  if (PacketData[1] != '\0') {
    SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]);
  }
  
  AddSingleStep (SystemContext);
}
Example #9
0
/**
  Parse the F reply packet and extract the return value and an ErrNo if it exists.

  @param  Packet  Packet to parse like an F reply packet
  @param  ErrNo   Buffer to hold Count bytes that were read

  @retval -1      Error, not a valid F reply packet
  @retval other   Return the return code from the F reply packet

**/
INTN
GdbParseFReplyPacket (
  IN  CHAR8   *Packet,
  OUT UINTN   *ErrNo
  )
{
  INTN   RetCode;

  if (Packet[0] != 'F') {
    // A valid responce would be an F packet
    return -1;
  }

  RetCode = AsciiStrHexToUintn (&Packet[1]);

  // Find 1st comma
  for (;*Packet != '\0' && *Packet != ',';  Packet++);
  if (*Packet == '\0') {
    *ErrNo = 0;
    return RetCode;
  }

  *ErrNo = AsciiStrHexToUintn (++Packet);

  // Find 2nd comma
  for (;*Packet != '\0' && *Packet != ',';  Packet++);
  if (*Packet == '\0') {
    return RetCode;
  }

  if (*(++Packet) == 'C') {
    GdbCtrlCBreakMessage (*ErrNo);
  }

  return RetCode;
}
/**
  Convert the dec or hex ascii string to value.

  @param Str             ascii string to be converted.

  @return the converted value.

**/
UINTN
UpdateAtoi (
  IN      UINT8                         *Str
  )
{
  UINTN Number;

  Number = 0;

  //
  // Skip preceeding while spaces
  //
  while (*Str != '\0') {
    if (*Str != 0x20) {
      break;
    }
    Str++;
  }

  if (*Str == '\0') {
    return Number;
  }

  //
  // Find whether the string is prefixed by 0x.
  // That is, it should be xtoi or atoi.
  //
  if (*Str == '0') {
    if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) {
      return AsciiStrHexToUintn ((CONST CHAR8 *) Str);
    }
  }

  while (*Str != '\0') {
    if ((*Str >= '0') && (*Str <= '9')) {
      Number  = Number * 10 + *Str - '0';
    } else {
      break;
    }
    Str++;
  }

  return Number;
}
Example #11
0
/**
  Decode a percent-encoded URI component to the ASCII character.
  
  Decode the input component in Buffer according to RFC 3986. The caller is responsible to make 
  sure ResultBuffer points to a buffer with size equal or greater than ((AsciiStrSize (Buffer))
  in bytes. 

  @param[in]    Buffer           The pointer to a percent-encoded URI component.
  @param[in]    BufferLength     Length of Buffer in bytes.
  @param[out]   ResultBuffer     Point to the buffer to store the decode result.
  @param[out]   ResultLength     Length of decoded string in ResultBuffer in bytes.

  @retval EFI_SUCCESS            Successfully decoded the URI.
  @retval EFI_INVALID_PARAMETER  Buffer is not a valid percent-encoded string.
  
**/
EFI_STATUS
EFIAPI
UriPercentDecode (
  IN      CHAR8            *Buffer,
  IN      UINT32            BufferLength,
     OUT  CHAR8            *ResultBuffer,
     OUT  UINT32           *ResultLength
  )
{
  UINTN           Index;
  UINTN           Offset;
  CHAR8           HexStr[3];

  if (Buffer == NULL || BufferLength == 0 || ResultBuffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  
  Index = 0;
  Offset = 0;
  HexStr[2] = '\0';
  while (Index < BufferLength) {
    if (Buffer[Index] == '%') {
      if (!NET_IS_HEX_CHAR (Buffer[Index+1]) || !NET_IS_HEX_CHAR (Buffer[Index+2])) {
        return EFI_INVALID_PARAMETER;
      }
      HexStr[0] = Buffer[Index+1];
      HexStr[1] = Buffer[Index+2];
      ResultBuffer[Offset] = (CHAR8) AsciiStrHexToUintn (HexStr);
      Index += 3;
    } else {
      ResultBuffer[Offset] = Buffer[Index];
      Index++;
    }
    Offset++;
  }

  *ResultLength = (UINT32) Offset;
    
  return EFI_SUCCESS;
}
Example #12
0
/** ‘p n’ 
 Reads the n-th register's value into an output buffer and sends it as a packet 
 @param   SystemContext   Register content at time of the exception
 @param   InBuffer      Pointer to the input buffer received from gdb server
 **/
VOID
ReadNthRegister (
  IN  EFI_SYSTEM_CONTEXT   SystemContext,
  IN  CHAR8                *InBuffer
  )
{
  UINTN RegNumber;
  CHAR8 OutBuffer[17];  // 1 reg=16 hex chars, and the end '\0' (escape seq)
  CHAR8 *OutBufPtr;   // pointer to the output buffer
  
  RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
  
  if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) {
    SendError (GDB_EINVALIDREGNUM); 
    return;
  }
  
  OutBufPtr = OutBuffer;
  OutBufPtr = BasicReadRegister(SystemContext, RegNumber, OutBufPtr);
  
  *OutBufPtr = '\0';  // the end of the buffer
  SendPacket (OutBuffer);
}
Example #13
0
/**
  Load a file into memory and optionally jump to it. A load address can be
  specified or automatically allocated. A quoted command line can optionally
  be passed into the image.

  Argv[0] - "go"
  Argv[1] - Device Name:path for the file to load
  Argv[2] - Address to load to or '*' if the load address will be allocated
  Argv[3] - Optional Entry point to the image. Image will be called if present
  Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs
            to include the command name

  go fv1:\EblCmdX  0x10000  0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX
    from FV1 to location 0x10000 and call the entry point at 0x10010 passing
    in "EblCmdX Arg2 Arg3 Arg4" as the arguments.

  go fv0:\EblCmdX  *  0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0
    to location allocated by this command and call the entry point at offset 0x10
    passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments.

  go fv1:\EblCmdX  0x10000; Load EblCmdX to address 0x10000 and return

  @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
EblGoCmd (
  IN UINTN  Argc,
  IN CHAR8  **Argv
  )
{
  EFI_STATUS                    Status;
  EFI_OPEN_FILE                 *File;
  VOID                          *Address;
  UINTN                         Size;
  EBL_COMMMAND                  EntryPoint;
  UINTN                         EntryPointArgc;
  CHAR8                         *EntryPointArgv[MAX_ARGS];


  if (Argc <= 2) {
    // device name and laod address are required
    return EFI_SUCCESS;
  }

  File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
  if (File == NULL) {
    AsciiPrint ("  %a is not a valid path\n", Argv[1]);
    return EFI_SUCCESS;
  }

  EntryPoint  = (EBL_COMMMAND)((Argc > 3) ? (UINTN)AsciiStrHexToUintn (Argv[3]) : (UINTN)NULL);
  if (Argv[2][0] == '*') {
    // * Means allocate the buffer
    Status = EfiReadAllocatePool (File, &Address, &Size);

    // EntryPoint is relative to the start of the image
    EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address);

  } else {
    Address = (VOID *)AsciiStrHexToUintn (Argv[2]);
    Size = File->Size;

    // File->Size for LoadFile is lazy so we need to use the tell to figure it out
    EfiTell (File, NULL);
    Status = EfiRead (File, Address, &Size);
  }

  if (!EFI_ERROR (Status)) {
    AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address);

    if (Argc > 3) {
      if (Argc > 4) {
        ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv);
      } else {
        EntryPointArgc = 1;
        EntryPointArgv[0] = File->FileName;
      }

      Status = EntryPoint (EntryPointArgc, EntryPointArgv);
    }
  }

  EfiClose (File);
  return Status;
}
/**
  Convert the input ascii string into GUID value.

  @param Str             Ascii GUID string to be converted.
  @param Guid            Pointer to the converted GUID value.

  @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
  @retval EFI_NOT_FOUND         The input ascii string is not a valid GUID format string.
  @retval EFI_SUCCESS           GUID value is got.

**/
EFI_STATUS
UpdateStringToGuid (
  IN      UINT8                         *Str,
  IN OUT  EFI_GUID                      *Guid
  )
{
  UINT8                                 *PtrBuffer;
  UINT8                                 *PtrPosition;
  UINT8                                 *Buffer;
  UINTN                                 Data;
  UINTN                                 StrLen;
  UINTN                                 Index;
  UINT8                                 Digits[3];

  StrLen          = AsciiStrLen  ((CONST CHAR8 *) Str);
  Buffer          = AllocateCopyPool (StrLen + 1, Str);
  if (Buffer == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Data1
  //
  PtrBuffer       = Buffer;
  PtrPosition     = PtrBuffer;
  while (*PtrBuffer != '\0') {
    if (*PtrBuffer == '-') {
      break;
    }
    PtrBuffer++;
  }
  if (*PtrBuffer == '\0') {
    FreePool (Buffer);
    return EFI_NOT_FOUND;
  }

  *PtrBuffer      = '\0';
  Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
  Guid->Data1     = (UINT32)Data;

  //
  // Data2
  //
  PtrBuffer++;
  PtrPosition     = PtrBuffer;
  while (*PtrBuffer != '\0') {
    if (*PtrBuffer == '-') {
      break;
    }
    PtrBuffer++;
  }
  if (*PtrBuffer == '\0') {
    FreePool (Buffer);
    return EFI_NOT_FOUND;
  }
  *PtrBuffer      = '\0';
  Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
  Guid->Data2     = (UINT16)Data;

  //
  // Data3
  //
  PtrBuffer++;
  PtrPosition     = PtrBuffer;
  while (*PtrBuffer != '\0') {
    if (*PtrBuffer == '-') {
      break;
    }
    PtrBuffer++;
  }
  if (*PtrBuffer == '\0') {
    FreePool (Buffer);
    return EFI_NOT_FOUND;
  }
  *PtrBuffer      = '\0';
  Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
  Guid->Data3     = (UINT16)Data;

  //
  // Data4[0..1]
  //
  for ( Index = 0 ; Index < 2 ; Index++) {
    PtrBuffer++;
    if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
      FreePool (Buffer);
      return EFI_NOT_FOUND;
    }
    Digits[0]     = *PtrBuffer;
    PtrBuffer++;
    Digits[1]     = *PtrBuffer;
    Digits[2]     = '\0';
    Data          = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
    Guid->Data4[Index] = (UINT8)Data;
  }

  //
  // skip the '-'
  //
  PtrBuffer++;
  if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) {
    return EFI_NOT_FOUND;
  }

  //
  // Data4[2..7]
  //
  for ( ; Index < 8; Index++) {
    PtrBuffer++;
    if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
      FreePool (Buffer);
      return EFI_NOT_FOUND;
    }
    Digits[0]     = *PtrBuffer;
    PtrBuffer++;
    Digits[1]     = *PtrBuffer;
    Digits[2]     = '\0';
    Data          = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
    Guid->Data4[Index] = (UINT8)Data;
  }

  FreePool (Buffer);

  return EFI_SUCCESS;
}
/**
  Parse Config data file to get the updated data array.

  @param DataBuffer      Config raw file buffer.
  @param BufferSize      Size of raw buffer.
  @param NumOfUpdates    Pointer to the number of update data.
  @param UpdateArray     Pointer to the config of update data.

  @retval EFI_NOT_FOUND         No config data is found.
  @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
  @retval EFI_SUCCESS           Parse the config file successfully.

**/
EFI_STATUS
ParseUpdateDataFile (
  IN      UINT8                         *DataBuffer,
  IN      UINTN                         BufferSize,
  IN OUT  UINTN                         *NumOfUpdates,
  IN OUT  UPDATE_CONFIG_DATA            **UpdateArray
  )
{
  EFI_STATUS                            Status;
  CHAR8                                 *Value;
  CHAR8                                 *SectionName;
  CHAR8                                 Entry[MAX_LINE_LENGTH];
  SECTION_ITEM                          *SectionHead;
  COMMENT_LINE                          *CommentHead;
  UINTN                                 Num;
  UINTN                                 Index;
  EFI_GUID                              FileGuid;

  SectionHead           = NULL;
  CommentHead           = NULL;

  //
  // First process the data buffer and get all sections and entries
  //
  Status                = PreProcessDataFile (
                            DataBuffer,
                            BufferSize,
                            &SectionHead,
                            &CommentHead
                            );
  if (EFI_ERROR (Status)) {
    FreeAllList (SectionHead, CommentHead);
    return Status;
  }

  //
  // Now get NumOfUpdate
  //
  Value                 = NULL;
  Status                = UpdateGetProfileString (
                            SectionHead,
                            (UINT8 *) "Head",
                            (UINT8 *) "NumOfUpdate",
                            (UINT8 **) &Value
                            );
  if (Value == NULL) {
    FreeAllList (SectionHead, CommentHead);
    return EFI_NOT_FOUND;
  }
  Num                   = UpdateAtoi((UINT8 *) Value);
  if (Num <= 0) {
    FreeAllList (SectionHead, CommentHead);
    return EFI_NOT_FOUND;
  }

  *NumOfUpdates         = Num;
  *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num));
  if (*UpdateArray == NULL) {
    FreeAllList (SectionHead, CommentHead);
    return EFI_OUT_OF_RESOURCES;
  }

  for ( Index = 0 ; Index < *NumOfUpdates ; Index++) {
    //
    // Get the section name of each update
    //
    AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Update");
    UpdateStrCatNumber ((UINT8 *) Entry, Index);
    Value               = NULL;
    Status              = UpdateGetProfileString (
                            SectionHead,
                            (UINT8 *) "Head",
                            (UINT8 *) Entry,
                            (UINT8 **) &Value
                            );
    if (Value == NULL) {
      FreeAllList (SectionHead, CommentHead);
      return EFI_NOT_FOUND;
    }

    //
    // The section name of this update has been found.
    // Now looks for all the config data of this update
    //
    SectionName         = Value;

    //
    // UpdateType
    //
    Value               = NULL;
    Status              = UpdateGetProfileString (
                            SectionHead,
                            (UINT8 *) SectionName,
                            (UINT8 *) "UpdateType",
                            (UINT8 **) &Value
                            );
    if (Value == NULL) {
      FreeAllList (SectionHead, CommentHead);
      return EFI_NOT_FOUND;
    }

    Num                 = UpdateAtoi((UINT8 *) Value);
    if (( Num >= (UINTN) UpdateOperationMaximum)) {
      FreeAllList (SectionHead, CommentHead);
      return Status;
    }
    (*UpdateArray)[Index].Index       = Index;
    (*UpdateArray)[Index].UpdateType  = (UPDATE_OPERATION_TYPE) Num;

    //
    // FvBaseAddress
    //
    Value               = NULL;
    Status              = UpdateGetProfileString (
                            SectionHead,
                            (UINT8 *) SectionName,
                            (UINT8 *) "FvBaseAddress",
                            (UINT8 **) &Value
                            );
    if (Value == NULL) {
      FreeAllList (SectionHead, CommentHead);
      return EFI_NOT_FOUND;
    }

    Num                 = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
    (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num;

    //
    // FileBuid
    //
    Value               = NULL;
    Status              = UpdateGetProfileString (
                            SectionHead,
                            (UINT8 *) SectionName,
                            (UINT8 *) "FileGuid",
                            (UINT8 **) &Value
                            );
    if (Value == NULL) {
      FreeAllList (SectionHead, CommentHead);
      return EFI_NOT_FOUND;
    }

    Status              = UpdateStringToGuid ((UINT8 *) Value, &FileGuid);
    if (EFI_ERROR (Status)) {
      FreeAllList (SectionHead, CommentHead);
      return Status;
    }
    CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID));

    //
    // FaultTolerant
    // Default value is FALSE
    //
    Value               = NULL;
    (*UpdateArray)[Index].FaultTolerant = FALSE;
    Status              = UpdateGetProfileString (
                            SectionHead,
                            (UINT8 *) SectionName,
                            (UINT8 *) "FaultTolerant",
                            (UINT8 **) &Value
                           );
    if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
      FreeAllList (SectionHead, CommentHead);
      return Status;
    } else if (Value != NULL) {
      if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) {
        (*UpdateArray)[Index].FaultTolerant = TRUE;
      } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) {
        (*UpdateArray)[Index].FaultTolerant = FALSE;
      }
    }

    if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) {
      //
      // Length
      //
      Value             = NULL;
      Status            = UpdateGetProfileString (
                            SectionHead,
                            (UINT8 *) SectionName,
                            (UINT8 *) "Length",
                            (UINT8 **) &Value
                            );
      if (Value == NULL) {
        FreeAllList (SectionHead, CommentHead);
        return EFI_NOT_FOUND;
      }

      Num               = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
      (*UpdateArray)[Index].Length = (UINTN) Num;
    }
  }

  //
  // Now all configuration data got. Free those temporary buffers
  //
  FreeAllList (SectionHead, CommentHead);

  return EFI_SUCCESS;
}
Example #16
0
/**
Open a device named by PathName. The PathName includes a device name and
path separated by a :. See file header for more details on the PathName
syntax. There is no checking to prevent a file from being opened more than
one type.

SectionType is only used to open an FV. Each file in an FV contains multiple
sections and only the SectionType section is opened.

For any file that is opened with EfiOpen() must be closed with EfiClose().

@param  PathName    Path to parse to open
@param  OpenMode    Same as EFI_FILE.Open()
@param  SectionType Section in FV to open.

@return NULL  Open failed
@return Valid EFI_OPEN_FILE handle

**/
EFI_OPEN_FILE *
EfiOpen (
  IN        CHAR8               *PathName,
  IN  CONST UINT64              OpenMode,
  IN  CONST EFI_SECTION_TYPE    SectionType
  )
{
  EFI_STATUS                Status;
  EFI_OPEN_FILE             *File;
  EFI_OPEN_FILE             FileData;
  UINTN                     StrLen;
  UINTN                     FileStart;
  UINTN                     DevNumber = 0;
  EFI_OPEN_FILE_GUARD       *GuardFile;
  BOOLEAN                   VolumeNameMatch;
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
  UINTN                     Size;
  EFI_IP_ADDRESS            Ip;
  CHAR8                     *CwdPlusPathName;
  UINTN                     Index;
  EFI_SECTION_TYPE          ModifiedSectionType;

  EblUpdateDeviceLists ();

  File = &FileData;
  ZeroMem (File, sizeof (EFI_OPEN_FILE));

  StrLen = AsciiStrSize (PathName);
  if (StrLen <= 1) {
    // Smallest valid path is 1 char and a null
    return NULL;
  }

  for (FileStart = 0; FileStart < StrLen; FileStart++) {
    if (PathName[FileStart] == ':') {
      FileStart++;
      break;
    }
  }

  //
  // Matching volume name has precedence over handle based names
  //
  VolumeNameMatch = EblMatchVolumeName (PathName, FileStart, &DevNumber);
  if (!VolumeNameMatch) {
    if (FileStart == StrLen) {
      // No Volume name or device name, so try Current Working Directory
      if (gCwd == NULL) {
        // No CWD
        return NULL;
      }

      // We could add a current working directory concept
      CwdPlusPathName = AllocatePool (AsciiStrSize (gCwd) + AsciiStrSize (PathName));
      if (CwdPlusPathName == NULL) {
        return NULL;
      }

      if ((PathName[0] == '/') || (PathName[0] == '\\')) {
        // PathName starts in / so this means we go to the root of the device in the CWD.
        CwdPlusPathName[0] = '\0';
        for (FileStart = 0; gCwd[FileStart] != '\0'; FileStart++) {
          CwdPlusPathName[FileStart] = gCwd[FileStart];
          if (gCwd[FileStart] == ':') {
            FileStart++;
            CwdPlusPathName[FileStart] = '\0';
            break;
          }
        }
      } else {
        AsciiStrCpy (CwdPlusPathName, gCwd);
        StrLen = AsciiStrLen (gCwd);
        if ((*PathName != '/') && (*PathName != '\\') && (gCwd[StrLen-1] != '/') && (gCwd[StrLen-1] != '\\')) {
          AsciiStrCat (CwdPlusPathName, "\\");
        }
      }

      AsciiStrCat (CwdPlusPathName, PathName);
      if (AsciiStrStr (CwdPlusPathName, ":") == NULL) {
        // Extra error check to make sure we don't recurse and blow stack
        return NULL;
      }

      File = EfiOpen (CwdPlusPathName, OpenMode, SectionType);
      FreePool (CwdPlusPathName);
      return File;
    }

    DevNumber = EblConvertDevStringToNumber ((CHAR8 *)PathName);
  }

  File->DeviceName = AllocatePool (StrLen);
  AsciiStrCpy (File->DeviceName, PathName);
  File->DeviceName[FileStart - 1] = '\0';
  File->FileName = &File->DeviceName[FileStart];
  if (File->FileName[0] == '\0') {
    // if it is just a file name use / as root
    File->FileName = "\\";
  }

  //
  // Use best match algorithm on the dev names so we only need to look at the
  // first few charters to match the full device name. Short name forms are
  // legal from the caller.
  //
  Status = EFI_SUCCESS;
  if (*PathName == 'f' || *PathName == 'F' || VolumeNameMatch) {
    if (PathName[1] == 's' || PathName[1] == 'S' || VolumeNameMatch) {
      if (DevNumber >= mFsCount) {
        goto ErrorExit;
      }
      File->Type = EfiOpenFileSystem;
      File->EfiHandle = mFs[DevNumber];
      Status = EblFileDevicePath (File, &PathName[FileStart], OpenMode);

    } else if (PathName[1] == 'v' || PathName[1] == 'V') {
      if (DevNumber >= mFvCount) {
        goto ErrorExit;
      }
      File->Type = EfiOpenFirmwareVolume;
      File->EfiHandle = mFv[DevNumber];

      if ((PathName[FileStart] == '/') || (PathName[FileStart] == '\\')) {
        // Skip leading / as its not really needed for the FV since no directories are supported
        FileStart++;
      }

      // Check for 2nd :
      ModifiedSectionType = SectionType;
      for (Index = FileStart; PathName[Index] != '\0'; Index++) {
        if (PathName[Index] == ':') {
          // Support fv0:\DxeCore:0x10
          // This means open the PE32 Section of the file
          ModifiedSectionType = (EFI_SECTION_TYPE)AsciiStrHexToUintn (&PathName[Index + 1]);
          PathName[Index] = '\0';
        }
      }
      File->FvSectionType = ModifiedSectionType;
      Status = EblFvFileDevicePath (File, &PathName[FileStart], ModifiedSectionType);
    }
  } else if ((*PathName == 'A') || (*PathName == 'a')) {
    // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
    File->Type = EfiOpenMemoryBuffer;
    // 1st colon is at PathName[FileStart - 1]
    File->Buffer = (VOID *)AsciiStrHexToUintn (&PathName[FileStart]);

    // Find 2nd colon
    while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) {
      FileStart++;
    }

    // If we ran out of string, there's no extra data
    if (PathName[FileStart] == '\0') {
      File->Size = 0;
    } else {
      File->Size = AsciiStrHexToUintn (&PathName[FileStart + 1]);
    }

    // if there's no number after the second colon, default
    // the end of memory
    if (File->Size == 0) {
      File->Size =  (UINTN)(0 - (UINTN)File->Buffer);
    }

    File->MaxPosition = File->Size;
    File->BaseOffset = (UINTN)File->Buffer;

  } else if (*PathName== 'l' || *PathName == 'L') {
    if (DevNumber >= mLoadFileCount) {
      goto ErrorExit;
    }
    File->Type = EfiOpenLoadFile;
    File->EfiHandle = mLoadFile[DevNumber];

    Status = gBS->HandleProtocol (File->EfiHandle, &gEfiLoadFileProtocolGuid, (VOID **)&File->LoadFile);
    if (EFI_ERROR (Status)) {
      goto ErrorExit;
    }

    Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
    if (EFI_ERROR (Status)) {
      goto ErrorExit;
    }
    File->DevicePath = DuplicateDevicePath (DevicePath);

  } else if (*PathName == 'b' || *PathName == 'B') {
    // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
    if (DevNumber >= mBlkIoCount) {
      goto ErrorExit;
    }
    File->Type = EfiOpenBlockIo;
    File->EfiHandle = mBlkIo[DevNumber];
    EblFileDevicePath (File, "", OpenMode);

    // 1st colon is at PathName[FileStart - 1]
    File->DiskOffset = AsciiStrHexToUintn (&PathName[FileStart]);

    // Find 2nd colon
    while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) {
      FileStart++;
    }

    // If we ran out of string, there's no extra data
    if (PathName[FileStart] == '\0') {
      Size = 0;
    } else {
      Size = AsciiStrHexToUintn (&PathName[FileStart + 1]);
    }

    // if a zero size is passed in (or the size is left out entirely),
    // go to the end of the device.
    if (Size == 0) {
      File->Size = File->Size - File->DiskOffset;
    } else {
      File->Size = Size;
    }

    File->MaxPosition = File->Size;
    File->BaseOffset = File->DiskOffset;
  } else if ((*PathName) >= '0' && (*PathName <= '9')) {

    // Get current IP address
    Status = EblGetCurrentIpAddress (&Ip);
    if (EFI_ERROR(Status)) {
      AsciiPrint("Device IP Address is not configured.\n");
      goto ErrorExit;
    }


    // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
    File->Type = EfiOpenTftp;
    File->IsDirty = FALSE;
    File->IsBufferValid = FALSE;

    Status = ConvertIpStringToEfiIp (PathName, &File->ServerIp);
  }

  if (EFI_ERROR (Status)) {
    goto ErrorExit;
  }

  GuardFile = (EFI_OPEN_FILE_GUARD *)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD));
  if (GuardFile == NULL) {
    goto ErrorExit;
  }

  GuardFile->Header = EFI_OPEN_FILE_GUARD_HEADER;
  CopyMem (&(GuardFile->File), &FileData, sizeof (EFI_OPEN_FILE));
  GuardFile->Footer = EFI_OPEN_FILE_GUARD_FOOTER;

  return &(GuardFile->File);

ErrorExit:
  FreePool (File->DeviceName);
  return NULL;
}
Example #17
0
/**
  Toggle page break global. This turns on and off prompting to Quit or hit any
  key to continue when a command is about to scroll the screen with its output

  Argv[0] - "hexdump"[.#]  # is optional 1,2, or 4 for width
  Argv[1] - Device or File to dump.
  Argv[2] - Optional offset to start dumping
  Argv[3] - Optional number of bytes to dump

  @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
EblHexdumpCmd (
  IN UINTN  Argc,
  IN CHAR8  **Argv
  )
{
  EFI_OPEN_FILE *File;
  VOID          *Location;
  UINTN         Size;
  UINTN         Width;
  UINTN         Offset = 0;
  EFI_STATUS    Status;
  UINTN         Chunk = HEXDUMP_CHUNK;

  if ((Argc < 2) || (Argc > 4)) {
    return EFI_INVALID_PARAMETER;
  }

  Width = WidthFromCommandName (Argv[0], 1);
  if ((Width != 1) && (Width != 2) && (Width != 4)) {
    return EFI_INVALID_PARAMETER;
  }

  File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
  if (File == NULL) {
    return EFI_NOT_FOUND;
  }

  Location = AllocatePool (Chunk);
  Size     = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : EfiTell (File, NULL);

  Offset = 0;
  if (Argc > 2) {
    Offset = AsciiStrHexToUintn (Argv[2]);
    if (Offset > 0) {
      // Make sure size includes the part of the file we have skipped
      Size += Offset;
    }
  }

  Status = EfiSeek (File, Offset, EfiSeekStart);
  if (EFI_ERROR (Status)) {
    goto Exit;
  }

  for (; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk) {
    Chunk = HEXDUMP_CHUNK;
    Status = EfiRead (File, Location, &Chunk);
    if (EFI_ERROR(Status)) {
      AsciiPrint ("Error reading file content\n");
      goto Exit;
    }

    Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset);
    if (EFI_ERROR(Status)) {
      if (Status == EFI_END_OF_FILE) {
        Status = EFI_SUCCESS;
      }
      goto Exit;
    }
  }

  // Any left over?
  if (Offset < Size) {
    Chunk = Size - Offset;
    Status = EfiRead (File, Location, &Chunk);
    if (EFI_ERROR(Status)) {
      AsciiPrint ("Error reading file content\n");
      goto Exit;
    }

    Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset);
    if (EFI_ERROR(Status)) {
      if (Status == EFI_END_OF_FILE) {
        Status = EFI_SUCCESS;
      }
      goto Exit;
    }
  }

Exit:
  EfiClose (File);

  FreePool (Location);

  return EFI_SUCCESS;
}