/** @file
Emulator Thunk to abstract OS services from pure EFI code
Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.
Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#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;
}