TianoCore EDK2 master
Loading...
Searching...
No Matches
ReportStatusCodeRouterRuntimeDxe.c
Go to the documentation of this file.
1
12
14LIST_ENTRY mCallbackListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackListHead);
15EFI_EVENT mVirtualAddressChangeEvent = NULL;
16
17//
18// Report operation nest status.
19// If it is set, then the report operation has nested.
20//
21UINT32 mStatusCodeNestStatus = 0;
22
23EFI_STATUS_CODE_PROTOCOL mStatusCodeProtocol = {
25};
26
27EFI_RSC_HANDLER_PROTOCOL mRscHandlerProtocol = {
30};
31
40VOID
41EFIAPI
43 IN EFI_EVENT Event,
44 IN VOID *Context
45 )
46{
47 RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
49 RSC_DATA_ENTRY *RscData;
50
51 CallbackEntry = (RSC_HANDLER_CALLBACK_ENTRY *)Context;
52
53 //
54 // Traverse the status code data buffer to parse all
55 // data to report.
56 //
57 Address = CallbackEntry->StatusCodeDataBuffer;
58 while (Address < CallbackEntry->EndPointer) {
59 RscData = (RSC_DATA_ENTRY *)(UINTN)Address;
60 CallbackEntry->RscHandlerCallback (
61 RscData->Type,
62 RscData->Value,
63 RscData->Instance,
64 &RscData->CallerId,
65 &RscData->Data
66 );
67
68 Address += (OFFSET_OF (RSC_DATA_ENTRY, Data) + RscData->Data.HeaderSize + RscData->Data.Size);
69 Address = ALIGN_VARIABLE (Address);
70 }
71
72 CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;
73}
74
104EFIAPI
106 IN EFI_RSC_HANDLER_CALLBACK Callback,
107 IN EFI_TPL Tpl
108 )
109{
110 EFI_STATUS Status;
111 LIST_ENTRY *Link;
112 RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
113
114 if (Callback == NULL) {
115 return EFI_INVALID_PARAMETER;
116 }
117
118 for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
119 CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
120 if (CallbackEntry->RscHandlerCallback == Callback) {
121 //
122 // If the function was already registered. It can't be registered again.
123 //
124 return EFI_ALREADY_STARTED;
125 }
126 }
127
128 CallbackEntry = AllocateRuntimeZeroPool (sizeof (RSC_HANDLER_CALLBACK_ENTRY));
129 ASSERT (CallbackEntry != NULL);
130
131 CallbackEntry->Signature = RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;
132 CallbackEntry->RscHandlerCallback = Callback;
133 CallbackEntry->Tpl = Tpl;
134
135 //
136 // If TPL of registered callback funtion is not TPL_HIGH_LEVEL, then event should be created
137 // for it, and related buffer for status code data should be prepared.
138 // Here the data buffer must be prepared in advance, because Report Status Code Protocol might
139 // be invoked under TPL_HIGH_LEVEL and no memory allocation is allowed then.
140 // If TPL is TPL_HIGH_LEVEL, then all status code will be reported immediately, without data
141 // buffer and event trigger.
142 //
143 if (Tpl != TPL_HIGH_LEVEL) {
144 CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (EFI_PAGE_SIZE);
145 CallbackEntry->BufferSize = EFI_PAGE_SIZE;
146 CallbackEntry->EndPointer = CallbackEntry->StatusCodeDataBuffer;
147 Status = gBS->CreateEvent (
148 EVT_NOTIFY_SIGNAL,
149 Tpl,
151 CallbackEntry,
152 &CallbackEntry->Event
153 );
154 ASSERT_EFI_ERROR (Status);
155 }
156
157 InsertTailList (&mCallbackListHead, &CallbackEntry->Node);
158
159 return EFI_SUCCESS;
160}
161
177EFIAPI
179 IN EFI_RSC_HANDLER_CALLBACK Callback
180 )
181{
182 LIST_ENTRY *Link;
183 RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
184
185 if (Callback == NULL) {
186 return EFI_INVALID_PARAMETER;
187 }
188
189 for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
190 CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
191 if (CallbackEntry->RscHandlerCallback == Callback) {
192 //
193 // If the function is found in list, delete it and return.
194 //
195 if (CallbackEntry->Tpl != TPL_HIGH_LEVEL) {
196 FreePool ((VOID *)(UINTN)CallbackEntry->StatusCodeDataBuffer);
197 gBS->CloseEvent (CallbackEntry->Event);
198 }
199
200 RemoveEntryList (&CallbackEntry->Node);
201 FreePool (CallbackEntry);
202 return EFI_SUCCESS;
203 }
204 }
205
206 return EFI_NOT_FOUND;
207}
208
228EFIAPI
232 IN UINT32 Instance,
233 IN EFI_GUID *CallerId OPTIONAL,
234 IN EFI_STATUS_CODE_DATA *Data OPTIONAL
235 )
236{
237 LIST_ENTRY *Link;
238 RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
239 RSC_DATA_ENTRY *RscData;
240 EFI_STATUS Status;
241 VOID *NewBuffer;
242 EFI_PHYSICAL_ADDRESS FailSafeEndPointer;
243
244 //
245 // Use atom operation to avoid the reentant of report.
246 // If current status is not zero, then the function is reentrancy.
247 //
248 if (InterlockedCompareExchange32 (&mStatusCodeNestStatus, 0, 1) == 1) {
249 return EFI_DEVICE_ERROR;
250 }
251
252 for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link);) {
253 CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
254 //
255 // The handler may remove itself, so get the next handler in advance.
256 //
257 Link = GetNextNode (&mCallbackListHead, Link);
258 if ((CallbackEntry->Tpl == TPL_HIGH_LEVEL) || EfiAtRuntime ()) {
259 CallbackEntry->RscHandlerCallback (
260 Type,
261 Value,
262 Instance,
263 CallerId,
264 Data
265 );
266 continue;
267 }
268
269 //
270 // If callback is registered with TPL lower than TPL_HIGH_LEVEL, event must be signaled at boot time to possibly wait for
271 // allowed TPL to report status code. Related data should also be stored in data buffer.
272 //
273 FailSafeEndPointer = CallbackEntry->EndPointer;
274 CallbackEntry->EndPointer = ALIGN_VARIABLE (CallbackEntry->EndPointer);
275 RscData = (RSC_DATA_ENTRY *)(UINTN)CallbackEntry->EndPointer;
276 CallbackEntry->EndPointer += sizeof (RSC_DATA_ENTRY);
277 if (Data != NULL) {
278 CallbackEntry->EndPointer += (Data->Size + Data->HeaderSize - sizeof (EFI_STATUS_CODE_DATA));
279 }
280
281 //
282 // If data buffer is about to be used up (7/8 here), try to reallocate a buffer with double size, if not at TPL_HIGH_LEVEL.
283 //
284 if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + (CallbackEntry->BufferSize / 8) * 7)) {
285 if (EfiGetCurrentTpl () < TPL_HIGH_LEVEL) {
286 NewBuffer = ReallocatePool (
287 CallbackEntry->BufferSize,
288 CallbackEntry->BufferSize * 2,
289 (VOID *)(UINTN)CallbackEntry->StatusCodeDataBuffer
290 );
291 if (NewBuffer != NULL) {
292 FailSafeEndPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)NewBuffer + (FailSafeEndPointer - CallbackEntry->StatusCodeDataBuffer);
293 CallbackEntry->EndPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)NewBuffer + (CallbackEntry->EndPointer - CallbackEntry->StatusCodeDataBuffer);
294 RscData = (RSC_DATA_ENTRY *)(UINTN)((UINTN)NewBuffer + ((UINTN)RscData - CallbackEntry->StatusCodeDataBuffer));
295 CallbackEntry->StatusCodeDataBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)NewBuffer;
296 CallbackEntry->BufferSize *= 2;
297 }
298 }
299 }
300
301 //
302 // If data buffer is used up, do not report for this time.
303 //
304 if (CallbackEntry->EndPointer > (CallbackEntry->StatusCodeDataBuffer + CallbackEntry->BufferSize)) {
305 CallbackEntry->EndPointer = FailSafeEndPointer;
306 continue;
307 }
308
309 RscData->Type = Type;
310 RscData->Value = Value;
311 RscData->Instance = Instance;
312 if (CallerId != NULL) {
313 CopyGuid (&RscData->CallerId, CallerId);
314 }
315
316 if (Data != NULL) {
317 CopyMem (&RscData->Data, Data, Data->HeaderSize + Data->Size);
318 } else {
319 ZeroMem (&RscData->Data, sizeof (RscData->Data));
320 RscData->Data.HeaderSize = sizeof (RscData->Data);
321 }
322
323 Status = gBS->SignalEvent (CallbackEntry->Event);
324 ASSERT_EFI_ERROR (Status);
325 }
326
327 //
328 // Restore the nest status of report
329 //
330 InterlockedCompareExchange32 (&mStatusCodeNestStatus, 1, 0);
331
332 return EFI_SUCCESS;
333}
334
344VOID
345EFIAPI
347 IN EFI_EVENT Event,
348 IN VOID *Context
349 )
350{
351 EFI_STATUS Status;
352 LIST_ENTRY *Link;
353 RSC_HANDLER_CALLBACK_ENTRY *CallbackEntry;
354
355 for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {
356 CallbackEntry = CR (Link, RSC_HANDLER_CALLBACK_ENTRY, Node, RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);
357 Status = EfiConvertFunctionPointer (0, (VOID **)&CallbackEntry->RscHandlerCallback);
358 ASSERT_EFI_ERROR (Status);
359 }
360
361 Status = EfiConvertList (
362 0,
363 &mCallbackListHead
364 );
365 ASSERT_EFI_ERROR (Status);
366}
367
382EFIAPI
384 IN EFI_HANDLE ImageHandle,
385 IN EFI_SYSTEM_TABLE *SystemTable
386 )
387{
388 EFI_STATUS Status;
389
390 Status = gBS->InstallMultipleProtocolInterfaces (
391 &mHandle,
392 &gEfiRscHandlerProtocolGuid,
393 &mRscHandlerProtocol,
394 &gEfiStatusCodeRuntimeProtocolGuid,
395 &mStatusCodeProtocol,
396 NULL
397 );
398 ASSERT_EFI_ERROR (Status);
399
400 Status = gBS->CreateEventEx (
401 EVT_NOTIFY_SIGNAL,
402 TPL_NOTIFY,
404 NULL,
405 &gEfiEventVirtualAddressChangeGuid,
406 &mVirtualAddressChangeEvent
407 );
408 ASSERT_EFI_ERROR (Status);
409
410 return EFI_SUCCESS;
411}
UINT64 UINTN
BOOLEAN EFIAPI IsNull(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:443
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)
Definition: BaseLib.h:2904
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
Definition: MemLibGuid.c:39
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI ReallocatePool(IN UINTN OldSize, IN UINTN NewSize, IN VOID *OldBuffer OPTIONAL)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID *EFIAPI AllocateRuntimeZeroPool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define ALIGN_VARIABLE(Value)
Definition: Base.h:977
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define CR(Record, TYPE, Field, TestSignature)
Definition: DebugLib.h:659
UINT32 EFI_STATUS_CODE_VALUE
Definition: PiStatusCode.h:67
UINT32 EFI_STATUS_CODE_TYPE
Definition: PiStatusCode.h:24
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_STATUS EFIAPI ReportDispatcher(IN EFI_STATUS_CODE_TYPE Type, IN EFI_STATUS_CODE_VALUE Value, IN UINT32 Instance, IN EFI_GUID *CallerId OPTIONAL, IN EFI_STATUS_CODE_DATA *Data OPTIONAL)
EFI_STATUS EFIAPI Register(IN EFI_RSC_HANDLER_CALLBACK Callback, IN EFI_TPL Tpl)
EFI_STATUS EFIAPI GenericStatusCodeRuntimeDxeEntry(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
VOID EFIAPI VirtualAddressChangeCallBack(IN EFI_EVENT Event, IN VOID *Context)
VOID EFIAPI RscHandlerNotification(IN EFI_EVENT Event, IN VOID *Context)
EFI_STATUS EFIAPI Unregister(IN EFI_RSC_HANDLER_CALLBACK Callback)
EFI_HANDLE mHandle
UINT32 EFIAPI InterlockedCompareExchange32(IN OUT volatile UINT32 *Value, IN UINT32 CompareValue, IN UINT32 ExchangeValue)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_TPL EFIAPI EfiGetCurrentTpl(VOID)
Definition: UefiLib.c:375
BOOLEAN EFIAPI EfiAtRuntime(VOID)
Definition: RuntimeLib.c:167
EFI_STATUS EFIAPI EfiConvertList(IN UINTN DebugDisposition, IN OUT LIST_ENTRY *ListHead)
Definition: RuntimeLib.c:617
EFI_STATUS EFIAPI EfiConvertFunctionPointer(IN UINTN DebugDisposition, IN OUT VOID **Address)
Definition: RuntimeLib.c:593
Definition: Base.h:213