/** @file | |
This contains the business logic for the module-specific Reset Helper functions. | |
Copyright (c) 2017 - 2019 Intel Corporation. All rights reserved.<BR> | |
Copyright (c) 2016 Microsoft Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Uefi.h> | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/ResetSystemLib.h> | |
#pragma pack(1) | |
typedef struct { | |
CHAR16 NullTerminator; | |
GUID ResetSubtype; | |
} RESET_UTILITY_GUID_SPECIFIC_RESET_DATA; | |
#pragma pack() | |
STATIC_ASSERT ( | |
sizeof (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA) == 18, | |
"sizeof (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA) is expected to be 18 bytes" | |
); | |
/** | |
This is a shorthand helper function to reset with reset type and 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] ResetType The default EFI_RESET_TYPE of the reset. | |
@param[in] ResetSubtype GUID pointer for the reset subtype to be used. | |
**/ | |
VOID | |
EFIAPI | |
ResetSystemWithSubtype ( | |
IN EFI_RESET_TYPE ResetType, | |
IN CONST GUID *ResetSubtype | |
) | |
{ | |
RESET_UTILITY_GUID_SPECIFIC_RESET_DATA ResetData; | |
ResetData.NullTerminator = CHAR_NULL; | |
CopyGuid ( | |
(GUID *)((UINT8 *)&ResetData + OFFSET_OF (RESET_UTILITY_GUID_SPECIFIC_RESET_DATA, ResetSubtype)), | |
ResetSubtype | |
); | |
ResetSystem (ResetType, EFI_SUCCESS, sizeof (ResetData), &ResetData); | |
} | |
/** | |
This is a shorthand helper function to reset with the reset type | |
'EfiResetPlatformSpecific' and 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 | |
) | |
{ | |
ResetSystemWithSubtype (EfiResetPlatformSpecific, ResetSubtype); | |
} | |
/** | |
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", __func__, 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; | |
} |