Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
(cherry picked from commit 5eecb45af0)
		
	
		
			
				
	
	
		
			221 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This contains the business logic for the module-specific Reset Helper functions.
 | 
						|
 | 
						|
  Copyright (c) 2017 - 2018 Intel Corporation. All rights reserved.<BR>
 | 
						|
  Copyright (c) 2016 Microsoft Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  This program and the accompanying materials are licensed and made available under
 | 
						|
  the terms and conditions of the BSD License that accompanies this distribution.
 | 
						|
  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php.
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
#include <Uefi.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/ResetSystemLib.h>
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  CHAR16 NullTerminator;
 | 
						|
  GUID   ResetSubtype;
 | 
						|
} RESET_UTILITY_GUID_SPECIFIC_RESET_DATA;
 | 
						|
 | 
						|
/**
 | 
						|
  This is a shorthand helper function to reset with a subtype so that
 | 
						|
  the caller doesn't have to bother with a function that has half a dozen
 | 
						|
  parameters.
 | 
						|
 | 
						|
  This will generate a reset with status EFI_SUCCESS, a NULL string, and
 | 
						|
  no custom data. The subtype will be formatted in such a way that it can be
 | 
						|
  picked up by notification registrations and custom handlers.
 | 
						|
 | 
						|
  NOTE: This call will fail if the architectural ResetSystem underpinnings
 | 
						|
        are not initialized. For DXE, you can add gEfiResetArchProtocolGuid
 | 
						|
        to your DEPEX.
 | 
						|
 | 
						|
  @param[in]  ResetSubtype  GUID pointer for the reset subtype to be used.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
ResetPlatformSpecificGuid (
 | 
						|
  IN CONST  GUID        *ResetSubtype
 | 
						|
  )
 | 
						|
{
 | 
						|
  RESET_UTILITY_GUID_SPECIFIC_RESET_DATA  ResetData;
 | 
						|
 | 
						|
  ResetData.NullTerminator = CHAR_NULL;
 | 
						|
  CopyGuid (&ResetData.ResetSubtype, ResetSubtype);
 | 
						|
  ResetPlatformSpecific (sizeof (ResetData), &ResetData);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function examines the DataSize and ResetData parameters passed to
 | 
						|
  to ResetSystem() and detemrines if the ResetData contains a Null-terminated
 | 
						|
  Unicode string followed by a GUID specific subtype.  If the GUID specific 
 | 
						|
  subtype is present, then a pointer to the GUID value in ResetData is returned.
 | 
						|
 | 
						|
  @param[in]  DataSize    The size, in bytes, of ResetData.
 | 
						|
  @param[in]  ResetData   Pointer to the data buffer passed into ResetSystem().
 | 
						|
 | 
						|
  @retval     Pointer     Pointer to the GUID value in ResetData.
 | 
						|
  @retval     NULL        ResetData is NULL.
 | 
						|
  @retval     NULL        ResetData does not start with a Null-terminated
 | 
						|
                          Unicode string.
 | 
						|
  @retval     NULL        A Null-terminated Unicode string is present, but there
 | 
						|
                          are less than sizeof (GUID) bytes after the string.
 | 
						|
  @retval     NULL        No subtype is found.
 | 
						|
 | 
						|
**/
 | 
						|
GUID *
 | 
						|
EFIAPI
 | 
						|
GetResetPlatformSpecificGuid (
 | 
						|
  IN UINTN       DataSize,
 | 
						|
  IN CONST VOID  *ResetData
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN          ResetDataStringSize;
 | 
						|
  GUID           *ResetSubtypeGuid;
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure parameters are valid
 | 
						|
  //
 | 
						|
  if ((ResetData == NULL) || (DataSize < sizeof (GUID))) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Determine the number of bytes in the Null-terminated Unicode string
 | 
						|
  // at the beginning of ResetData including the Null terminator.
 | 
						|
  //
 | 
						|
  ResetDataStringSize = StrnSizeS (ResetData, (DataSize / sizeof (CHAR16)));
 | 
						|
 | 
						|
  //
 | 
						|
  // Now, assuming that we have enough data for a GUID after the string, the
 | 
						|
  // GUID should be immediately after the string itself.
 | 
						|
  //
 | 
						|
  if ((ResetDataStringSize < DataSize) && (DataSize - ResetDataStringSize) >= sizeof (GUID)) {
 | 
						|
    ResetSubtypeGuid = (GUID *)((UINT8 *)ResetData + ResetDataStringSize);
 | 
						|
    DEBUG ((DEBUG_VERBOSE, "%a - Detected reset subtype %g...\n", __FUNCTION__, ResetSubtypeGuid));
 | 
						|
    return ResetSubtypeGuid;
 | 
						|
  }
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This is a helper function that creates the reset data buffer that can be 
 | 
						|
  passed into ResetSystem().
 | 
						|
 | 
						|
  The reset data buffer is returned in ResetData and contains ResetString
 | 
						|
  followed by the ResetSubtype GUID followed by the ExtraData.
 | 
						|
 | 
						|
  NOTE: Strings are internally limited by MAX_UINT16.
 | 
						|
 | 
						|
  @param[in, out] ResetDataSize  On input, the size of the ResetData buffer. On
 | 
						|
                                 output, either the total number of bytes
 | 
						|
                                 copied, or the required buffer size.
 | 
						|
  @param[in, out] ResetData      A pointer to the buffer in which to place the
 | 
						|
                                 final structure.
 | 
						|
  @param[in]      ResetSubtype   Pointer to the GUID specific subtype.  This
 | 
						|
                                 parameter is optional and may be NULL.
 | 
						|
  @param[in]      ResetString    Pointer to a Null-terminated Unicode string
 | 
						|
                                 that describes the reset.  This parameter is
 | 
						|
                                 optional and may be NULL.
 | 
						|
  @param[in]      ExtraDataSize  The size, in bytes, of ExtraData buffer.
 | 
						|
  @param[in]      ExtraData      Pointer to a buffer of extra data.  This
 | 
						|
                                 parameter is optional and may be NULL.
 | 
						|
 | 
						|
  @retval     RETURN_SUCCESS             ResetDataSize and ResetData are updated.
 | 
						|
  @retval     RETURN_INVALID_PARAMETER   ResetDataSize is NULL.
 | 
						|
  @retval     RETURN_INVALID_PARAMETER   ResetData is NULL.
 | 
						|
  @retval     RETURN_INVALID_PARAMETER   ExtraData was provided without a
 | 
						|
                                         ResetSubtype. This is not supported by the
 | 
						|
                                         UEFI spec.
 | 
						|
  @retval     RETURN_BUFFER_TOO_SMALL    An insufficient buffer was provided.
 | 
						|
                                         ResetDataSize is updated with minimum size
 | 
						|
                                         required.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
BuildResetData (
 | 
						|
  IN OUT   UINTN     *ResetDataSize,
 | 
						|
  IN OUT   VOID      *ResetData,
 | 
						|
  IN CONST GUID      *ResetSubtype  OPTIONAL,
 | 
						|
  IN CONST CHAR16    *ResetString   OPTIONAL,
 | 
						|
  IN       UINTN     ExtraDataSize  OPTIONAL,
 | 
						|
  IN CONST VOID      *ExtraData     OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  ResetStringSize;
 | 
						|
  UINTN  ResetDataBufferSize;
 | 
						|
  UINT8  *Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // If the size return pointer is NULL.
 | 
						|
  //
 | 
						|
  if (ResetDataSize == NULL) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If extra data is indicated, but pointer is NULL.
 | 
						|
  //
 | 
						|
  if (ExtraDataSize > 0 && ExtraData == NULL) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If extra data is indicated, but no subtype GUID is supplied.
 | 
						|
  //
 | 
						|
  if (ResetSubtype == NULL && ExtraDataSize > 0) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Determine the final string.
 | 
						|
  //
 | 
						|
  if (ResetString == NULL) {
 | 
						|
    ResetString = L"";     // Use an empty string.
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Calculate the total buffer required for ResetData.
 | 
						|
  //
 | 
						|
  ResetStringSize     = StrnSizeS (ResetString, MAX_UINT16);
 | 
						|
  ResetDataBufferSize = ResetStringSize + ExtraDataSize;
 | 
						|
  if (ResetSubtype != NULL) {
 | 
						|
    ResetDataBufferSize += sizeof (GUID);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // At this point, if the buffer isn't large enough (or if
 | 
						|
  // the buffer is NULL) we cannot proceed.
 | 
						|
  //
 | 
						|
  if (*ResetDataSize < ResetDataBufferSize) {
 | 
						|
    *ResetDataSize = ResetDataBufferSize;
 | 
						|
    return RETURN_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
  *ResetDataSize = ResetDataBufferSize;
 | 
						|
  if (ResetData == NULL) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill in ResetData with ResetString, the ResetSubtype GUID, and extra data
 | 
						|
  //
 | 
						|
  Data = (UINT8 *)ResetData;
 | 
						|
  CopyMem (Data, ResetString, ResetStringSize);
 | 
						|
  Data += ResetStringSize;
 | 
						|
  if (ResetSubtype != NULL) {
 | 
						|
    CopyMem (Data, ResetSubtype, sizeof (GUID));
 | 
						|
    Data += sizeof (GUID);
 | 
						|
  }
 | 
						|
  if (ExtraDataSize > 0) {
 | 
						|
    CopyMem (Data, ExtraData, ExtraDataSize);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 |