/** @file | |
Emulator Thunk to abstract OS services from pure EFI code | |
Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR> | |
Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Uefi.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Protocol/EmuIoThunk.h> | |
#define EMU_IO_THUNK_PROTOCOL_DATA_SIGNATURE SIGNATURE_32('E','m','u','T') | |
typedef struct { | |
UINTN Signature; | |
EMU_IO_THUNK_PROTOCOL Data; | |
BOOLEAN EmuBusDriver; | |
LIST_ENTRY Link; | |
} EMU_IO_THUNK_PROTOCOL_DATA; | |
LIST_ENTRY mThunkList = INITIALIZE_LIST_HEAD_VARIABLE (mThunkList); | |
EFI_STATUS | |
EFIAPI | |
AddThunkProtocol ( | |
IN EMU_IO_THUNK_PROTOCOL *ThunkIo, | |
IN CHAR16 *ConfigString, | |
IN BOOLEAN EmuBusDriver | |
) | |
{ | |
UINTN Size; | |
CHAR16 *StartString; | |
CHAR16 *SubString; | |
UINTN Instance; | |
EMU_IO_THUNK_PROTOCOL_DATA *Private; | |
if (ThunkIo == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Instance = 0; | |
Size = StrSize (ConfigString); | |
StartString = AllocatePool (Size); | |
if (StartString == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
StrCpyS (StartString, Size / sizeof (CHAR16), ConfigString); | |
while (*StartString != '\0') { | |
// | |
// Find the end of the sub string | |
// | |
SubString = StartString; | |
while (*SubString != '\0' && *SubString != '!') { | |
SubString++; | |
} | |
if (*SubString == '!') { | |
// | |
// Replace token with '\0' to make sub strings. If this is the end | |
// of the string SubString will already point to NULL. | |
// | |
*SubString = '\0'; | |
SubString++; | |
} | |
Private = AllocatePool (sizeof (EMU_IO_THUNK_PROTOCOL_DATA)); | |
if (Private == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Private->Signature = EMU_IO_THUNK_PROTOCOL_DATA_SIGNATURE; | |
Private->EmuBusDriver = EmuBusDriver; | |
CopyMem (&Private->Data, ThunkIo, sizeof (EMU_IO_THUNK_PROTOCOL)); | |
Private->Data.Instance = (UINT16)Instance++; | |
Private->Data.ConfigString = StartString; | |
InsertTailList (&mThunkList, &Private->Link); | |
// | |
// Parse Next sub string. This will point to '\0' if we are at the end. | |
// | |
StartString = SubString; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
GetNextThunkProtocol ( | |
IN BOOLEAN EmuBusDriver, | |
OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL | |
) | |
{ | |
LIST_ENTRY *Link; | |
EMU_IO_THUNK_PROTOCOL_DATA *Private; | |
if (mThunkList.ForwardLink == &mThunkList) { | |
// Skip parsing an empty list | |
return EFI_NOT_FOUND; | |
} | |
for (Link = mThunkList.ForwardLink; Link != &mThunkList; Link = Link->ForwardLink) { | |
Private = CR (Link, EMU_IO_THUNK_PROTOCOL_DATA, Link, EMU_IO_THUNK_PROTOCOL_DATA_SIGNATURE); | |
if (EmuBusDriver & !Private->EmuBusDriver) { | |
continue; | |
} else if (*Instance == NULL) { | |
// Find 1st match in list | |
*Instance = &Private->Data; | |
return EFI_SUCCESS; | |
} else if (*Instance == &Private->Data) { | |
// Matched previous call so look for valid next entry | |
Link = Link->ForwardLink; | |
if (Link == &mThunkList) { | |
return EFI_NOT_FOUND; | |
} | |
Private = CR (Link, EMU_IO_THUNK_PROTOCOL_DATA, Link, EMU_IO_THUNK_PROTOCOL_DATA_SIGNATURE); | |
*Instance = &Private->Data; | |
return EFI_SUCCESS; | |
} | |
} | |
return EFI_NOT_FOUND; | |
} |