Home | History | Annotate | Download | only in BsDataHubStatusCode
      1 /*++
      2 
      3 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   BsDataHubStatusCode.c
     15 
     16 Abstract:
     17 
     18   This implements a status code listener that logs status codes into the data
     19   hub.  This is only active during non-runtime DXE.
     20   The status codes are recorded in a extensible buffer, and a event is signalled
     21   to log them to the data hub. The recorder is the producer of the status code in
     22   buffer and the event notify function the consumer.
     23 
     24 --*/
     25 
     26 #include "BsDataHubStatusCode.h"
     27 
     28 //
     29 // Initialize FIFO to cache records.
     30 //
     31 STATIC EFI_LIST_ENTRY   mRecordsFifo    = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);
     32 STATIC EFI_LIST_ENTRY   mRecordsBuffer  = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);
     33 STATIC EFI_EVENT        mLogDataHubEvent;
     34 STATIC BOOLEAN          mEventHandlerActive = FALSE;
     35 
     36 //
     37 // Cache data hub protocol.
     38 //
     39 STATIC EFI_DATA_HUB_PROTOCOL     *mDataHubProtocol;
     40 
     41 STATIC
     42 DATA_HUB_STATUS_CODE_DATA_RECORD *
     43 AcquireRecordBuffer (
     44   VOID
     45   )
     46 /*++
     47 
     48 Routine Description:
     49 
     50   Return one DATAHUB_STATUSCODE_RECORD space.
     51   The size of free record pool would be extend, if the pool is empty.
     52 
     53 Arguments:
     54 
     55   None
     56 
     57 Returns:
     58 
     59   A pointer to the new allocated node or NULL if non available
     60 
     61 --*/
     62 {
     63   DATAHUB_STATUSCODE_RECORD *Record;
     64   EFI_TPL                   CurrentTpl;
     65   EFI_LIST_ENTRY            *Node;
     66   UINT32                    Index;
     67 
     68   Record     = NULL;
     69   CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
     70 
     71   if (!IsListEmpty (&mRecordsBuffer)) {
     72     Node = GetFirstNode (&mRecordsBuffer);
     73     RemoveEntryList (Node);
     74 
     75     Record = _CR (Node, DATAHUB_STATUSCODE_RECORD, Node);
     76   } else {
     77     if (CurrentTpl > EFI_TPL_NOTIFY) {
     78       gBS->RestoreTPL (CurrentTpl);
     79       return NULL;
     80     }
     81 
     82     gBS->RestoreTPL (CurrentTpl);
     83 
     84     gBS->AllocatePool (EfiBootServicesData, sizeof (DATAHUB_STATUSCODE_RECORD) * 16, (VOID **) &Record);
     85     if (Record == NULL) {
     86       return NULL;
     87     }
     88     EfiCommonLibZeroMem (Record, sizeof (DATAHUB_STATUSCODE_RECORD) * 16);
     89 
     90 
     91     CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
     92     for (Index = 1; Index < 16; Index++) {
     93       InsertTailList (&mRecordsBuffer, &Record[Index].Node);
     94     }
     95   }
     96 
     97   Record->Signature = BS_DATA_HUB_STATUS_CODE_SIGNATURE;
     98   InsertTailList (&mRecordsFifo, &Record->Node);
     99 
    100   gBS->RestoreTPL (CurrentTpl);
    101 
    102   return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data);
    103 }
    104 
    105 STATIC
    106 DATA_HUB_STATUS_CODE_DATA_RECORD *
    107 RetrieveRecord (
    108   VOID
    109   )
    110 /*++
    111 
    112 Routine Description:
    113 
    114   Retrieve one record from Records FIFO. The record would be removed from FIFO and
    115   release to free record buffer.
    116 
    117 Arguments:
    118 
    119   None
    120 
    121 Returns:
    122 
    123   Point to record which is ready to be logged, or NULL if the FIFO of record is empty.
    124 
    125 --*/
    126 {
    127   DATA_HUB_STATUS_CODE_DATA_RECORD  *RecordData;
    128   DATAHUB_STATUSCODE_RECORD   *Record;
    129   EFI_LIST_ENTRY              *Node;
    130   EFI_TPL                     CurrentTpl;
    131 
    132   RecordData = NULL;
    133 
    134   CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
    135 
    136   if (!IsListEmpty (&mRecordsFifo)) {
    137     Node = GetFirstNode (&mRecordsFifo);
    138     Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, BS_DATA_HUB_STATUS_CODE_SIGNATURE);
    139 
    140     RemoveEntryList (&Record->Node);
    141     InsertTailList (&mRecordsBuffer, &Record->Node);
    142     Record->Signature = 0;
    143     RecordData = (DATA_HUB_STATUS_CODE_DATA_RECORD *) Record->Data;
    144   }
    145 
    146   gBS->RestoreTPL (CurrentTpl);
    147 
    148   return RecordData;
    149 }
    150 
    151 EFI_STATUS
    152 EFIAPI
    153 BsDataHubReportStatusCode (
    154   IN EFI_STATUS_CODE_TYPE     CodeType,
    155   IN EFI_STATUS_CODE_VALUE    Value,
    156   IN UINT32                   Instance,
    157   IN EFI_GUID                 * CallerId,
    158   IN EFI_STATUS_CODE_DATA     * Data OPTIONAL
    159   )
    160 /*++
    161 
    162 Routine Description:
    163 
    164   Boot service report status code listener.  This function logs the status code
    165   into the data hub.
    166 
    167 Arguments:
    168 
    169   Same as gRT->ReportStatusCode (See Tiano Runtime Specification)
    170 
    171 Returns:
    172 
    173   None
    174 
    175 --*/
    176 {
    177   DATA_HUB_STATUS_CODE_DATA_RECORD  *Record;
    178   UINT32                     ErrorLevel;
    179   VA_LIST                    Marker;
    180   CHAR8                      *Format;
    181   CHAR16                     FormatBuffer[BYTES_PER_RECORD];
    182   UINTN                      Index;
    183 
    184   //
    185   // See whether in runtime phase or not.
    186   //
    187   if (EfiAtRuntime ()) {
    188     //
    189     // For now all we do is post code at runtime
    190     //
    191     return EFI_SUCCESS;
    192   }
    193 
    194   //
    195   // Discard new DataHubRecord caused by DataHub->LogData()
    196   //
    197   if (mEventHandlerActive) {
    198     return EFI_SUCCESS;
    199   }
    200 
    201   Record = AcquireRecordBuffer ();
    202   if (Record == NULL) {
    203     //
    204     // There are no empty record buffer in private buffers
    205     //
    206     return EFI_OUT_OF_RESOURCES;
    207   }
    208   //
    209   // Construct Data Hub Extended Data
    210   //
    211   Record->CodeType = CodeType;
    212   Record->Value    = Value;
    213   Record->Instance = Instance;
    214 
    215   if (CallerId != NULL) {
    216     EfiCopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));
    217   }
    218 
    219   if (Data != NULL) {
    220     if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
    221       //
    222       // Convert Ascii Format string to Unicode.
    223       //
    224       for (Index = 0; Format[Index] != '\0' && Index < (BYTES_PER_RECORD - 1); Index += 1) {
    225         FormatBuffer[Index] = (CHAR16) Format[Index];
    226       }
    227 
    228       FormatBuffer[Index] = L'\0';
    229 
    230       //
    231       // Put processed string into the buffer
    232       //
    233       Index = VSPrint (
    234                 (CHAR16 *) (Record + 1),
    235                 BYTES_PER_RECORD - (sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)),
    236                 FormatBuffer,
    237                 Marker
    238                 );
    239 
    240       EfiCopyMem (&Record->Data.Type, &gEfiStatusCodeDataTypeDebugGuid, sizeof (EFI_GUID));
    241       Record->Data.HeaderSize = Data->HeaderSize;
    242       Record->Data.Size = (UINT16) (Index * sizeof (CHAR16));
    243     } else {
    244       //
    245       // Copy status code data header
    246       //
    247       EfiCopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));
    248 
    249       if (Data->Size > BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)) {
    250         Record->Data.Size = (UINT16) (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD));
    251       }
    252       EfiCopyMem ((VOID *) (Record + 1), Data + 1, Record->Data.Size);
    253     }
    254   }
    255 
    256   gBS->SignalEvent (mLogDataHubEvent);
    257 
    258   return EFI_SUCCESS;
    259 }
    260 
    261 VOID
    262 EFIAPI
    263 LogDataHubEventHandler (
    264   IN  EFI_EVENT     Event,
    265   IN  VOID          *Context
    266   )
    267 /*++
    268 
    269 Routine Description:
    270 
    271   The Event handler which will be notified to log data in Data Hub.
    272 
    273 Arguments:
    274 
    275   Event     -   Instance of the EFI_EVENT to signal whenever data is
    276                 available to be logged in the system.
    277   Context   -   Context of the event.
    278 
    279 Returns:
    280 
    281   None.
    282 
    283 --*/
    284 {
    285   DATA_HUB_STATUS_CODE_DATA_RECORD  *Record;
    286   UINT32                            Size;
    287   UINT64                            DataRecordClass;
    288 
    289   //
    290   // Set global flag so we don't recurse if DataHub->LogData eventually causes new DataHubRecord
    291   //
    292   mEventHandlerActive = TRUE;
    293 
    294   //
    295   // Log DataRecord in Data Hub.
    296   // Journal records fifo to find all record entry.
    297   //
    298   while (1) {
    299     Record = RetrieveRecord ();
    300     if (Record == NULL) {
    301       break;
    302     }
    303     //
    304     // Add in the size of the header we added.
    305     //
    306     Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + (UINT32) Record->Data.Size;
    307 
    308     if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
    309       DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
    310     } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
    311       DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;
    312     } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
    313       DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;
    314     } else {
    315       //
    316       // Should never get here.
    317       //
    318       DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |
    319         EFI_DATA_RECORD_CLASS_ERROR |
    320         EFI_DATA_RECORD_CLASS_DATA |
    321         EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
    322     }
    323 
    324     //
    325     // Log DataRecord in Data Hub
    326     //
    327 
    328     mDataHubProtocol->LogData (
    329                         mDataHubProtocol,
    330                         &gEfiStatusCodeGuid,
    331                         &gEfiStatusCodeRuntimeProtocolGuid,
    332                         DataRecordClass,
    333                         Record,
    334                         Size
    335                         );
    336 
    337   }
    338 
    339   mEventHandlerActive = FALSE;
    340 
    341 }
    342 
    343 EFI_STATUS
    344 EFIAPI
    345 BsDataHubInitializeStatusCode (
    346   IN EFI_HANDLE         ImageHandle,
    347   IN EFI_SYSTEM_TABLE   *SystemTable
    348   )
    349 /*++
    350 
    351 Routine Description:
    352 
    353   Install a data hub listener.
    354 
    355 Arguments:
    356 
    357   (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
    358 
    359 Returns:
    360 
    361   EFI_SUCCESS - Logging Hub protocol installed
    362   Other       - No protocol installed, unload driver.
    363 
    364 --*/
    365 {
    366   EFI_STATUS              Status;
    367 
    368   Status = gBS->LocateProtocol (
    369                   &gEfiDataHubProtocolGuid,
    370                   NULL,
    371                   (VOID **) &mDataHubProtocol
    372                   );
    373   ASSERT_EFI_ERROR (Status);
    374 
    375   //
    376   // Create a Notify Event to log data in Data Hub
    377   //
    378   Status = gBS->CreateEvent (
    379                   EFI_EVENT_NOTIFY_SIGNAL,
    380                   EFI_TPL_CALLBACK,
    381                   LogDataHubEventHandler,
    382                   NULL,
    383                   &mLogDataHubEvent
    384                   );
    385 
    386   ASSERT_EFI_ERROR (Status);
    387 
    388   return EFI_SUCCESS;
    389 }
    390 
    391 
    392