/**
*OemPlatformEarlyPhasePei - PEI Driver
*
*Module: OemPlatformEarlyPhasePei (0423)
*
*This PEI module handles early platform initialization phase:
* - CMOS-based baud rate configuration
* - UART baud rate sync between CMOS and Setup variables
* - Warm reset trigger on baud rate mismatch
*/
#include <PiPei.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/IoLib.h>
#include <Library/PeiServicesTablePointerLib.h>
#include <Library/BaseLib.h>
// Forward declarations EFI_STATUS EFIAPI ModuleEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
/**Reads IDTR register.
@param[out] Idtr Pointer to IDTR descriptor structure.
@return Pointer to IDTR descriptor.
**/
VOID *EFIAPI ReadIdtr(
OUT VOID *Idtr
)
{
if (Idtr == NULL) {
DEBUG((EFI_D_ERROR, "Idtr != ((void *) 0)\n"));
ASSERT(Idtr != NULL);
}
__sidt(Idtr);
return Idtr;
}
/**Retrieves the PEI Services Table pointer via IDT-based table pointer.
@return Pointer to PEI Services Table, or NULL if not available.
**/
INTN EFIAPI GetPeiServicesTablePtr(
VOID
)
{
IA32_DESCRIPTOR Idtr;
INTN PeiServices;
ReadIdtr(&Idtr);
PeiServices = *(INTN *)((UINTN)&Idtr + 2); // Extract base from IDTR if (PeiServices == 0) {
DEBUG((EFI_D_ERROR,
"PeiServices != ((void *) 0)\n"));
}
return PeiServices;
}
/**Checks debug printing enable mask via CMOS.
@return Debug mask flags:
- 0 if debug disabled
- EFI_SUCCESS (0) if mask is 0xFF
- EFI_INVALID_PARAMETER (-2) if mask is 1
- EFI_NOT_FOUND (-13) otherwise
**/
INTN EFIAPI DebugMaskCheck(
VOID
)
{
UINT8 CmosIndex;
UINT8 DebugMask;
UINT8 FinalMask;
CmosIndex = __inbyte(0x70);
__outbyte(0x70, CmosIndex & 0x80 | 0x4A);
DebugMask = __inbyte(0x71);
FinalMask = DebugMask;
if (DebugMask <= 3) {
if (FinalMask == 0)
return 0;
goto CheckDone;
}
FinalMask = DebugMask;
if (DebugMask == 0) {
FinalMask = (MmioRead8(0xFDAF0490) & 2) | 1;
if (FinalMask == 0)
return 0;
goto CheckDone;
}
CheckDone:
if (FinalMask != 0xFF) {
return (FinalMask == 1) ? EFI_INVALID_PARAMETER : EFI_NOT_FOUND;
}
return 0;
}
/**Gets the debug print function pointer from the PEI services table.
@return Pointer to the debug print function, or 0 if unavailable.
**/
INTN EFIAPI GetDebugFuncPtr(
VOID
)
{
INTN PeiServices;
UINT8 Buffer[4];
INTN DebugFunc;
PeiServices = GetPeiServicesTablePtr();
// Locate PPI in PEI services if (PeiServices == 0 ||
((INTN (*)(INTN, VOID *, UINT32, UINT8 *, INTN *))(*(UINT32 *)PeiServices + 32))(
PeiServices, &gEfiDebugPortProtocolGuid, 0, Buffer, &DebugFunc) < 0)
{
return 0;
}
return DebugFunc;
}
/**Debug print function.
@param[in] ErrorLevel Debug error level mask.
@param[in] Format Format string.
@param[in] ... Variable arguments.
@return Status of debug print.
**/
INTN EFIAPI DebugPrint(
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
INTN Result;
INTN ( **DebugFunc)(UINTN, CONST CHAR8 *, VA_LIST);
VA_LIST Va;
VA_START(Va, Format);
Result = GetDebugFuncPtr();
DebugFunc = (INTN ( **)(UINTN, CONST CHAR8 *, VA_LIST))Result;
if (Result != 0) {
Result = DebugMaskCheck();
if ((Result & ErrorLevel) != 0) {
return (*DebugFunc)(ErrorLevel, Format, Va);
}
}
VA_END(Va);
return Result;
}
/**Report ASSERT condition.
@param[in] FileName Source file name.
@param[in] LineNumber Line number.
@param[in] Description ASSERT description string.
**/
VOID EFIAPI ReportAssert(
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
INTN Result;
Result = GetDebugFuncPtr();
if (Result != 0) {
(*(INTN ( *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))(Result + 4))(
FileName, LineNumber, Description);
}
}
/**Fills a buffer with a specified value.
@param[out] buf Pointer to buffer to fill.
@param[in] count Number of bytes to fill.
@param[in] value Value to fill.
@return Pointer to buffer.
**/
VOID *EFIAPI SetMem(
OUT VOID *buf,
IN UINTN count,
IN UINT8 value
)
{
return memset(buf, value, count);
}
/**Fills a buffer with a 32-bit value.
@param[out] buf Pointer to buffer to fill.
@param[in] count Number of UINT32 elements to fill.
@param[in] value Value to fill.
@return Pointer to buffer.
**/
VOID *EFIAPI SetMem32(
OUT VOID *buf,
IN UINTN count,
IN UINT32 value
)
{
return memset32(buf, value, count);
}
/**Copies a memory buffer (handles overlapping regions correctly).
@param[out] dst Pointer to destination buffer.
@param[in] src Pointer to source buffer.
@param[in] count Number of bytes to copy.
@return Pointer to destination buffer.
**/
CHAR8 *EFIAPI CopyMem(
OUT CHAR8 *dst,
IN CONST CHAR8 *src,
IN UINTN count
)
{
UINTN AlignCount;
if (src < dst && src + count - 1 >= dst) {
// Overlapping: copy backwards src = src + count - 1;
dst = dst + count - 1;
AlignCount = count & 3;
} else {
// No overlap: copy forwards aligned AlignCount = count & 3;
qmemcpy(dst, src, count - AlignCount);
src += count - AlignCount;
dst += count - AlignCount;
}
// Copy remaining bytes qmemcpy(dst, src, AlignCount);
return dst;
}
/**Sets an array of 64-bit values (pairs of DWORDs).
@param[in] a1 Base address of array.
@param[in] a2 Number of elements.
@param[in] a3 Low DWORD value.
@param[in] a4 High DWORD value.
@return Base address.
**/
INTN EFIAPI SetInt64Array(
IN INTN a1,
IN INTN a2,
IN INT32 a3,
IN INT32 a4
)
{
do {
*(UINT32 *)(a1 + 8 *a2 - 8) = a3;
*(UINT32 *)(a1 + 8 *a2 - 4) = a4;
a2--;
} while (a2);
return a1;
}
/**Module Entry Point - OemPlatformEarlyPhaseEntry.
This function:
1. Reads CMOS register 0x6C for baud rate setting 2. Validates CMOS access via signature (0x55)
3. Reads CMOS register 0x5C for platform boot indicator 4. Gets Setup variable via PEI services 5. Syncs CMOS baud rate with Setup baud rate 6. Performs warm reset on mismatch
@param[in] ImageHandle Module image handle.
@param[in] SystemTable Pointer to EFI System Table.
@return EFI_STATUS.
**/
EFI_STATUS EFIAPI ModuleEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT8 CmosVal6C;
UINT8 SavedCmos6C;
UINT8 CmosCheck;
UINT8 CmosVal5C;
UINT8 SetupBaudRateLow;
BOOLEAN NeedsSync;
INTN Status;
UINT32 SetupGuid[4];
INTN DataSize;
UINT32 PpiServices[2];
UINT8 SetupBuffer[52];
DataSize = sizeof(SetupBuffer);
// GUID: 0xEC87B643-0xEBA4-4B9E-A5C5-D4E345B547B6 SetupGuid[0] = 0xEC87B643;
SetupGuid[1] = 0x4E9BEBA4;
SetupGuid[2] = 0xC5A59E4B;
SetupGuid[3] = 0xB647B545;
DEBUG((EFI_D_INFO, "OemPlatformEarlyPhaseEntry\n"));
// Read CMOS register 0x6C (baud rate setting)
__outbyte(0x72, 0x6C);
CmosVal6C = __inbyte(0x73);
SavedCmos6C = CmosVal6C;
// Write signature 0x55 to validate CMOS access __outbyte(0x72, 0x6C);
__outbyte(0x73, 0x55);
CmosCheck = __inbyte(0x73);
// If CMOS write didn't stick, CMOS may be disabled if (CmosCheck != 0x55) {
return EFI_UNSUPPORTED;
}
// Restore original CMOS 0x6C value and read 0x5C __outbyte(0x72, 0x6C);
__outbyte(0x73, SavedCmos6C);
__outbyte(0x72, 0x5C);
CmosVal5C = __inbyte(0x73);
// Locate PPI and get Setup variable
// SystemTable->Hdr.Signature reinterpreted as PPI locator function
((VOID (*)(EFI_SYSTEM_TABLE *, VOID *, UINT32, UINT32, UINT32 *))
(SystemTable->Hdr.Signature & 0xFFFFFFFF) + 32)(
SystemTable, &gEfiSetupVariableGuid, 0, 0, PpiServices);
Status = ((INTN (*)(UINT32, CONST UINT16 *, UINT32 *, UINT32, INTN *, UINT8 *))
PpiServices[0])(
PpiServices[0], L"Setup", SetupGuid, 0, &DataSize, SetupBuffer);
DEBUG((EFI_D_INFO,
"OemPlatformEarlyPhaseEntry: Status of GetVariable(Setup) = %r\n"));
DEBUG((EFI_D_INFO,
"OemPlatformEarlyPhaseEntry: CmosValue[6C]: %d\n"));
DEBUG((EFI_D_INFO,
"OemPlatformEarlyPhaseEntry: Setup.BaudRate[0]: %d\n"));
NeedsSync = (Status != EFI_SUCCESS);
if ((CmosVal6C & 0xA0) != 0xA0) {
NeedsSync = TRUE;
}
if (NeedsSync) {
// Baud rate mismatch - need to update CMOS if (CmosVal5C == 0x51) {
// Warm reset in progress with specific indicator __outbyte(0x72, 0x6C);
__outbyte(0x73, 0xA3); // 9600 baud
} else {
if (CmosVal5C == 0x21) {
__outbyte(0x72, 0x6C);
__outbyte(0x73, 0xA4); // 19200 baud
} else {
__outbyte(0x72, 0x6C);
__outbyte(0x73, 0xA7); // 115200 baud (default)
}
}
} else if (CmosVal6C != (SetupBaudRateLow | 0xA0)) {
// Sync CMOS and Setup values, then warm reset DEBUG((EFI_D_INFO,
"OemPlatformEarlyPhaseEntry: Sync CmosValue[6C] and Setup.BaudRate[0]!!\n"));
__outbyte(0x72, 0x6C);
__outbyte(0x73, SetupBaudRateLow | 0xA0);
DEBUG((EFI_D_INFO,
"OemPlatformEarlyPhaseEntry: Setup.BaudRate[0]: %d\n"));
DEBUG((EFI_D_INFO,
"OemPlatformEarlyPhaseEntry: Sync completed, do warm reset!!\n"));
// Reset control port: warm reset __outbyte(0xCF9, 0x06);
PpiServices[1] = 1;
// Halt while (TRUE);
}
return EFI_SUCCESS;
}