Skip to content

Commit

Permalink
Add V5 of Adv Logger Info Structure
Browse files Browse the repository at this point in the history
The V4 Adv Logger Info structure uses pointers for LogCurrent and
LogBuffer. These pointers are not required and have additional
safety overhead. Furthermore, the pointers do not support a
runtime logger in an ARM64 environment, as StMM requires the
pointers to be physical but the runtime logger requires the
pointers to be virtual.

The V5 structure moves these to two new fields, LogCurrentOffset
and LogBufferOffset, respectively, to avoid using pointers and
be able to support runtime logging on ARM64.

- [x] Impacts functionality?
- **Functionality** - Does the change ultimately impact how firmware
functions?
- Examples: Add a new library, publish a new PPI, update an algorithm,
...
- [x] Impacts security?
- **Security** - Does the change have a direct security impact on an
application,
    flow, or firmware?
  - Examples: Crypto algorithm change, buffer overflow fix, parameter
    validation improvement, ...
- [x] Breaking change?
- **Breaking change** - Will anyone consuming this change experience a
break
    in build or boot behavior?
- Examples: Add a new library class, move a module to a different repo,
call
    a function in a new library class in a pre-existing module, ...
- [ ] Includes tests?
  - **Tests** - Does the change include any explicit test code?
  - Examples: Unit tests, integration tests, robot tests, ...
- [ ] Includes documentation?
- **Documentation** - Does the change contain explicit documentation
additions
    outside direct code modifications (and comments)?
- Examples: Update readme file, add feature readme file, link to
documentation
    on an a separate Web page, ...

Tested on various physical and virtual platforms to confirm the
log is output as expected with the V5 structure.

Update to this commit and use the new version of DecodeUefiLog.py
to correctly decode a V5 Adv Logger Log.
  • Loading branch information
os-d committed May 2, 2024
1 parent b35d771 commit be9a3d2
Show file tree
Hide file tree
Showing 16 changed files with 284 additions and 195 deletions.
72 changes: 72 additions & 0 deletions AdvLoggerPkg/Application/DecodeUefiLog/DecodeUefiLog.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,30 @@ class AdvLogParser ():
V4_LOGGER_INFO_SIZE = V3_LOGGER_INFO_SIZE
V4_LOGGER_INFO_VERSION = 4

# typedef volatile struct {
# UINT32 Signature; // Signature 'ALOG'
# UINT16 Version; // Current Version
# UINT16 Reserved[3]; // Reserved for future
# UINT32 LogBufferOffset; // Offset from LoggerInfo to start of log, expected to be the size of this structure, 8 byte aligned
# UINT32 Reserved4;
# UINT32 LogCurrentOffset; // Offset from LoggerInfo to where to store next log entry.
# UINT32 DiscardedSize; // Number of bytes of messages missed
# UINT32 LogBufferSize; // Size of allocated buffer
# BOOLEAN InPermanentRAM; // Log in permanent RAM
# BOOLEAN AtRuntime; // After ExitBootServices
# BOOLEAN GoneVirtual; // After VirtualAddressChange
# BOOLEAN HdwPortInitialized; // HdwPort initialized
# BOOLEAN HdwPortDisabled; // HdwPort is Disabled
# BOOLEAN Reserved2[3]; //
# UINT64 TimerFrequency; // Ticks per second for log timing
# UINT64 TicksAtTime; // Ticks when Time Acquired
# EFI_TIME Time; // Uefi Time Field
# UINT32 HwPrintLevel; // Logging level to be printed at hw port
# UINT32 Reserved3; //
# } ADVANCED_LOGGER_INFO;
V5_LOGGER_INFO_SIZE = 80
V5_LOGGER_INFO_VERSION = 5

# ---------------------------------------------------------------------- #
#
#
Expand Down Expand Up @@ -379,6 +403,54 @@ def _InitializeLoggerInfo(self, InFile, StartLine):
if InFile.tell() != (Size):
raise Exception('Error initializing logger info. AmountRead: %d' % InFile.tell())

elif Version == self.V5_LOGGER_INFO_VERSION:
InFile.read(4) # skip over rest of reserved section
Size = self.V5_LOGGER_INFO_SIZE
# we no longer have this field in the struct but for compatibility can calculate it
# to be used
LoggerInfo["LogBuffer"] = Size
# this is only used to calculate LogCurrent as an offset, but V5 uses
# LogCurrentOffset already, so we do this just to share the common code
BaseAddress = 0
LoggerInfo["LogBufferOffset"] = struct.unpack("=I", InFile.read(4))[0]
InFile.read(4) # skip over reserved4 field
LoggerInfo["LogCurrentOffset"] = struct.unpack("=I", InFile.read(4))[0]
# we don't have this field anymore, but to share the common code we
# can calculate it
LoggerInfo["LogCurrent"] = LoggerInfo["LogCurrentOffset"]
LoggerInfo["DiscardedSize"] = struct.unpack("=I", InFile.read(4))[0]
LoggerInfo["LogBufferSize"] = struct.unpack("=I", InFile.read(4))[0]
LoggerInfo["InPermanentRAM"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["AtRuntime"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["GoneVirtual"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["HdwInitialized"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["HdwDisabled"] = struct.unpack("=B", InFile.read(1))[0]
InFile.read(3) # skip reserved2 field
LoggerInfo["Frequency"] = struct.unpack("=Q", InFile.read(8))[0]
LoggerInfo["TicksAtTime"] = struct.unpack("=Q", InFile.read(8))[0]

# Reading in the EFI_TIME structure
LoggerInfo["Year"] = struct.unpack("=H", InFile.read(2))[0]
LoggerInfo["Month"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["Day"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["Hour"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["Minute"] = struct.unpack("=B", InFile.read(1))[0]
LoggerInfo["Second"] = struct.unpack("=B", InFile.read(1))[0]
InFile.read(1) # skip Pad1 field
LoggerInfo["Nanosecond"] = struct.unpack("=I", InFile.read(4))[0]
LoggerInfo["TimeZone"] = struct.unpack("=H", InFile.read(2))[0]
LoggerInfo["DayLight"] = struct.unpack("=B", InFile.read(1))[0]
InFile.read(1) # skip Pad2 field

# If at v3, there will be 8 bytes for print level and pads, which we do not care.
InFile.read(4)
InFile.read(4)

self._Compute_Basetime(LoggerInfo)

if InFile.tell() != (Size):
raise Exception('Error initializing logger info. AmountRead: %d' % InFile.tell())

else:
raise Exception('Error initializing logger info. Unsupported version: 0x%X' % LoggerInfo["Version"])

Expand Down
50 changes: 29 additions & 21 deletions AdvLoggerPkg/Include/AdvancedLoggerInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#define __ADVANCED_LOGGER_INTERNAL_H__

#define ADVANCED_LOGGER_SIGNATURE SIGNATURE_32('A','L','O','G')
#define ADVANCED_LOGGER_HW_LVL_VER 4
#define ADVANCED_LOGGER_HW_LVL_VER 5
#define ADVANCED_LOGGER_MSG_MAJ_VER 2
#define ADVANCED_LOGGER_MSG_MIN_VER 0

Expand Down Expand Up @@ -46,24 +46,25 @@
#pragma pack (push, 1)

typedef volatile struct {
UINT32 Signature; // Signature 'ALOG'
UINT16 Version; // Current Version
UINT16 Reserved; // Reserved for future
EFI_PHYSICAL_ADDRESS LogBuffer; // Fixed pointer to start of log
EFI_PHYSICAL_ADDRESS LogCurrent; // Where to store next log entry.
UINT32 DiscardedSize; // Number of bytes of messages missed
UINT32 LogBufferSize; // Size of allocated buffer
BOOLEAN InPermanentRAM; // Log in permanent RAM
BOOLEAN AtRuntime; // After ExitBootServices
BOOLEAN GoneVirtual; // After VirtualAddressChange
BOOLEAN HdwPortInitialized; // HdwPort initialized
BOOLEAN HdwPortDisabled; // HdwPort is Disabled
BOOLEAN Reserved2[3]; //
UINT64 TimerFrequency; // Ticks per second for log timing
UINT64 TicksAtTime; // Ticks when Time Acquired
EFI_TIME Time; // Uefi Time Field
UINT32 HwPrintLevel; // Logging level to be printed at hw port
UINT32 Reserved3; //
UINT32 Signature; // Signature 'ALOG'
UINT16 Version; // Current Version
UINT16 Reserved[3]; // Reserved for future
UINT32 LogBufferOffset; // Offset from LoggerInfo to start of log, expected to be the size of this structure 8 byte aligned
UINT32 Reserved4;
UINT32 LogCurrentOffset; // Offset from LoggerInfo to where to store next log entry.
UINT32 DiscardedSize; // Number of bytes of messages missed
UINT32 LogBufferSize; // Size of allocated buffer
BOOLEAN InPermanentRAM; // Log in permanent RAM
BOOLEAN AtRuntime; // After ExitBootServices
BOOLEAN GoneVirtual; // After VirtualAddressChange
BOOLEAN HdwPortInitialized; // HdwPort initialized
BOOLEAN HdwPortDisabled; // HdwPort is Disabled
BOOLEAN Reserved2[3]; //
UINT64 TimerFrequency; // Ticks per second for log timing
UINT64 TicksAtTime; // Ticks when Time Acquired
EFI_TIME Time; // Uefi Time Field
UINT32 HwPrintLevel; // Logging level to be printed at hw port
UINT32 Reserved3; //
} ADVANCED_LOGGER_INFO;

typedef struct {
Expand All @@ -87,8 +88,8 @@ typedef struct {
CHAR8 MessageText[]; // Message Text
} ADVANCED_LOGGER_MESSAGE_ENTRY_V2;

#define MESSAGE_ENTRY_SIZE(LenOfMessage) (ALIGN_VALUE(sizeof(ADVANCED_LOGGER_MESSAGE_ENTRY) + LenOfMessage ,8))
#define MESSAGE_ENTRY_SIZE_V2(LenOfEntry, LenOfMessage) (ALIGN_VALUE(LenOfEntry + LenOfMessage ,8))
#define MESSAGE_ENTRY_SIZE(LenOfMessage) (ALIGN_VALUE(sizeof(ADVANCED_LOGGER_MESSAGE_ENTRY) + LenOfMessage, 8))
#define MESSAGE_ENTRY_SIZE_V2(LenOfEntry, LenOfMessage) (ALIGN_VALUE(LenOfEntry + LenOfMessage, 8))

#define NEXT_LOG_ENTRY(LogEntry) ((ADVANCED_LOGGER_MESSAGE_ENTRY *)((UINTN)LogEntry + MESSAGE_ENTRY_SIZE(LogEntry->MessageLen)))
#define NEXT_LOG_ENTRY_V2(LogEntryV2) ((ADVANCED_LOGGER_MESSAGE_ENTRY_V2 *)((UINTN)LogEntryV2 + MESSAGE_ENTRY_SIZE_V2(LogEntryV2->MessageOffset, LogEntryV2->MessageLen)))
Expand Down Expand Up @@ -116,6 +117,13 @@ STATIC_ASSERT (sizeof (ADVANCED_LOGGER_INFO) % 8 == 0, "Logger Info Misaligned")
#define PA_FROM_PTR(Address) ((EFI_PHYSICAL_ADDRESS) (UINTN) (Address))
#define PTR_FROM_PA(Address) ((VOID *) (UINTN) (Address))

#define LOG_BUFFER_FROM_ALI(LoggerInfo) ((UINT8 *)LoggerInfo + LoggerInfo->LogBufferOffset)
#define LOG_CURRENT_FROM_ALI(LoggerInfo) ((UINT8 *)LoggerInfo + LoggerInfo->LogCurrentOffset)
#define USED_LOG_SIZE(LoggerInfo) (LoggerInfo->LogCurrentOffset < LoggerInfo->LogBufferOffset ? 0 : LoggerInfo->LogCurrentOffset - LoggerInfo->LogBufferOffset)
#define TOTAL_LOG_SIZE_WITH_ALI(LoggerInfo) (LoggerInfo->LogBufferOffset + LoggerInfo->LogBufferSize)
#define LOG_MAX_ADDRESS(LoggerInfo) (PA_FROM_PTR ((UINT8 *)LoggerInfo + TOTAL_LOG_SIZE_WITH_ALI (LoggerInfo)))
#define EXPECTED_LOG_BUFFER_OFFSET(LoggerInfo) (ALIGN_VALUE (sizeof (*LoggerInfo), 8))// 8 byte align the log buffer offset

//
// Log Buffer Base PCD points to this structure. This is also the structure of the
// Advanced Logger HOB.
Expand Down
14 changes: 7 additions & 7 deletions AdvLoggerPkg/Library/AdvLoggerMmAccessLib/AdvLoggerMmAccessLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ extern UINTN mVariableBufferPayloadSize;
/**
CheckAddress
The address of the ADVANCE_LOGGER_INFO block pointer is captured before END_OF_DXE. The
pointers LogBuffer and LogCurrent, and LogBufferSize, could be written to by untrusted code. Here, we check that
the pointers are within the allocated mLoggerInfo space, and that LogBufferSize, which is used in multiple places
The address of the ADVANCE_LOGGER_INFO block pointer is captured before END_OF_DXE.
LogBuffer, LogCurrentOffset, and LogBufferSize could be written to by untrusted code. Here, we check that
the offsets are within the allocated mLoggerInfo space, and that LogBufferSize, which is used in multiple places
to see if a new message will fit into the log buffer, is valid.
@param NONE
Expand All @@ -57,12 +57,12 @@ ValidateInfoBlock (
return FALSE;
}

if (mLoggerInfo->LogBuffer != (PA_FROM_PTR (mLoggerInfo + 1))) {
if (mLoggerInfo->LogBufferOffset != EXPECTED_LOG_BUFFER_OFFSET (mLoggerInfo)) {
return FALSE;
}

if ((mLoggerInfo->LogCurrent > mMaxAddress) ||
(mLoggerInfo->LogCurrent < mLoggerInfo->LogBuffer))
if ((PA_FROM_PTR (LOG_CURRENT_FROM_ALI (mLoggerInfo)) > mMaxAddress) ||
(mLoggerInfo->LogCurrentOffset < mLoggerInfo->LogBufferOffset))
{
return FALSE;
}
Expand Down Expand Up @@ -109,7 +109,7 @@ AdvLoggerAccessInit (
}

if (mLoggerInfo != NULL) {
mMaxAddress = mLoggerInfo->LogBuffer + mLoggerInfo->LogBufferSize;
mMaxAddress = LOG_MAX_ADDRESS (mLoggerInfo);
}

//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ extern UINTN mVariableBufferPayloadSize;
/**
CheckAddress
The address of the ADVANCE_LOGGER_INFO block pointer is captured before END_OF_DXE. The
pointers LogBuffer and LogCurrent, and LogBufferSize, could be written to by untrusted code. Here, we check that
the pointers are within the allocated mLoggerInfo space, and that LogBufferSize, which is used in multiple places
The address of the ADVANCE_LOGGER_INFO block pointer is captured before END_OF_DXE. LogBufferOffset,
LogCurrentOffset, and LogBufferSize, could be written to by untrusted code. Here, we check that
the offsets are within the allocated mLoggerInfo space, and that LogBufferSize, which is used in multiple places
to see if a new message will fit into the log buffer, is valid.
@param NONE
Expand All @@ -57,12 +57,12 @@ ValidateInfoBlock (
return FALSE;
}

if (mLoggerInfo->LogBuffer != (PA_FROM_PTR (mLoggerInfo + 1))) {
if (mLoggerInfo->LogBufferOffset != sizeof (*mLoggerInfo)) {
return FALSE;
}

if ((mLoggerInfo->LogCurrent > mMaxAddress) ||
(mLoggerInfo->LogCurrent < mLoggerInfo->LogBuffer))
if ((PA_FROM_PTR (LOG_CURRENT_FROM_ALI (mLoggerInfo)) > mMaxAddress) ||
(mLoggerInfo->LogCurrentOffset < mLoggerInfo->LogBufferOffset))
{
return FALSE;
}
Expand Down Expand Up @@ -126,7 +126,7 @@ AdvLoggerAccessInit (
if (!EFI_ERROR (Status)) {
mLoggerInfo = LOGGER_INFO_FROM_PROTOCOL (LoggerProtocol);
if (mLoggerInfo != NULL) {
mMaxAddress = mLoggerInfo->LogBuffer + mLoggerInfo->LogBufferSize;
mMaxAddress = LOG_MAX_ADDRESS (mLoggerInfo);
}

if (!ValidateInfoBlock ()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@ AdvancedLoggerAccessLibGetNextMessageBlock (
return EFI_INVALID_PARAMETER;
}

if (mLoggerInfo->LogCurrent == mLoggerInfo->LogBuffer) {
if (mLoggerInfo->LogCurrentOffset == mLoggerInfo->LogBufferOffset) {
return EFI_END_OF_FILE;
}

if (BlockEntry->Message == NULL) {
LogEntry = (ADVANCED_LOGGER_MESSAGE_ENTRY *)PTR_FROM_PA (mLoggerInfo->LogBuffer);
LogEntry = (ADVANCED_LOGGER_MESSAGE_ENTRY *)LOG_BUFFER_FROM_ALI (mLoggerInfo);
if (LogEntry->Signature == MESSAGE_ENTRY_SIGNATURE_V2) {
// This is actually a v2 entry.
LogEntryV2 = (ADVANCED_LOGGER_MESSAGE_ENTRY_V2 *)LogEntry;
Expand Down Expand Up @@ -223,7 +223,7 @@ AdvancedLoggerAccessLibGetNextMessageBlock (
return EFI_INVALID_PARAMETER;
}

if (LogEntry >= (ADVANCED_LOGGER_MESSAGE_ENTRY *)PTR_FROM_PA (mLoggerInfo->LogCurrent)) {
if (LogEntry >= (ADVANCED_LOGGER_MESSAGE_ENTRY *)LOG_CURRENT_FROM_ALI (mLoggerInfo)) {
return EFI_END_OF_FILE;
}

Expand Down Expand Up @@ -438,8 +438,8 @@ AdvancedLoggerAccessLibUnitTestInitialize (

if (!EFI_ERROR (Status)) {
mLoggerInfo = LOGGER_INFO_FROM_PROTOCOL (LoggerProtocol);
mLowAddress = mLoggerInfo->LogBuffer;
mHighAddress = mLoggerInfo->LogBuffer + mLoggerInfo->LogBufferSize;
mLowAddress = PA_FROM_PTR (LOG_BUFFER_FROM_ALI (mLoggerInfo));
mHighAddress = PA_FROM_PTR (TOTAL_LOG_SIZE_WITH_ALI (mLoggerInfo));
}

return Status;
Expand All @@ -465,8 +465,8 @@ AdvancedLoggerAccessLibConstructor (
);
if (!EFI_ERROR (Status)) {
mLoggerInfo = LOGGER_INFO_FROM_PROTOCOL (LoggerProtocol);
mLowAddress = mLoggerInfo->LogBuffer;
mHighAddress = mLoggerInfo->LogBuffer + mLoggerInfo->LogBufferSize;
mLowAddress = PA_FROM_PTR (LOG_BUFFER_FROM_ALI (mLoggerInfo));
mHighAddress = PA_FROM_PTR (TOTAL_LOG_SIZE_WITH_ALI (mLoggerInfo));

// Leave this debug message as ERROR.

Expand Down
33 changes: 17 additions & 16 deletions AdvLoggerPkg/Library/AdvancedLoggerLib/AdvancedLoggerCommon.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ AdvancedLoggerMemoryLoggerWrite (
)
{
ADVANCED_LOGGER_INFO *LoggerInfo;
EFI_PHYSICAL_ADDRESS CurrentBuffer;
EFI_PHYSICAL_ADDRESS NewBuffer;
EFI_PHYSICAL_ADDRESS OldValue;
UINT32 CurrentBuffer;
UINT32 NewBuffer;
UINT32 OldValue;
UINT32 OldSize;
UINT32 NewSize;
UINT32 CurrentSize;
Expand All @@ -63,20 +63,20 @@ AdvancedLoggerMemoryLoggerWrite (
if (LoggerInfo != NULL) {
EntrySize = MESSAGE_ENTRY_SIZE_V2 (OFFSET_OF (ADVANCED_LOGGER_MESSAGE_ENTRY_V2, MessageText), NumberOfBytes);
do {
CurrentBuffer = LoggerInfo->LogCurrent;
UsedSize = (UINTN)(CurrentBuffer - LoggerInfo->LogBuffer);
CurrentBuffer = LoggerInfo->LogCurrentOffset;
UsedSize = USED_LOG_SIZE (LoggerInfo);
if ((UsedSize >= LoggerInfo->LogBufferSize) ||
((LoggerInfo->LogBufferSize - UsedSize) < EntrySize))
{
if (FeaturePcdGet (PcdAdvancedLoggerAutoWrapEnable) && (LoggerInfo->AtRuntime)) {
//
// Wrap around the current cursor when auto wrap is enabled on buffer full during runtime.
//
NewBuffer = LoggerInfo->LogBuffer;
OldValue = InterlockedCompareExchange64 (
(UINT64 *)&LoggerInfo->LogCurrent,
(UINT64)CurrentBuffer,
(UINT64)NewBuffer
NewBuffer = LoggerInfo->LogBufferOffset;
OldValue = InterlockedCompareExchange32 (
&LoggerInfo->LogCurrentOffset,
CurrentBuffer,
NewBuffer
);
if (OldValue != CurrentBuffer) {
//
Expand Down Expand Up @@ -108,15 +108,16 @@ AdvancedLoggerMemoryLoggerWrite (
}
}

NewBuffer = PA_FROM_PTR ((CHAR8_FROM_PA (CurrentBuffer) + EntrySize));
OldValue = InterlockedCompareExchange64 (
(UINT64 *)&LoggerInfo->LogCurrent,
(UINT64)CurrentBuffer,
(UINT64)NewBuffer
// EntrySize is contained within a UINT32, this is safe to do
NewBuffer = (UINT32)(CurrentBuffer + EntrySize);
OldValue = InterlockedCompareExchange32 (
&LoggerInfo->LogCurrentOffset,
CurrentBuffer,
NewBuffer
);
} while (OldValue != CurrentBuffer);

Entry = (ADVANCED_LOGGER_MESSAGE_ENTRY_V2 *)PTR_FROM_PA (CurrentBuffer);
Entry = (ADVANCED_LOGGER_MESSAGE_ENTRY_V2 *)((UINT8 *)LoggerInfo + CurrentBuffer);
Entry->MajorVersion = ADVANCED_LOGGER_MSG_MAJ_VER;
Entry->MinorVersion = ADVANCED_LOGGER_MSG_MIN_VER;
Entry->TimeStamp = GetPerformanceCounter (); // AdvancedLoggerGetTimeStamp();
Expand Down

0 comments on commit be9a3d2

Please sign in to comment.