From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Universal/DebugPortDxe/DebugPort.c | 739 +++++++++++++++++++++ 1 file changed, 739 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c (limited to 'roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c') diff --git a/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c new file mode 100644 index 000000000..172c1cbca --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/DebugPortDxe/DebugPort.c @@ -0,0 +1,739 @@ +/** @file + Top level C file for debugport driver. Contains initialization function. + This driver layers on top of SerialIo. + ALL CODE IN THE SERIALIO STACK MUST BE RE-ENTRANT AND CALLABLE FROM + INTERRUPT CONTEXT + +Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DebugPort.h" + +// +// Globals +// +EFI_DRIVER_BINDING_PROTOCOL gDebugPortDriverBinding = { + DebugPortSupported, + DebugPortStart, + DebugPortStop, + DEBUGPORT_DRIVER_VERSION, + NULL, + NULL +}; + +DEBUGPORT_DEVICE mDebugPortDevice = { + DEBUGPORT_DEVICE_SIGNATURE, + (EFI_HANDLE) 0, + (EFI_HANDLE) 0, + (EFI_DEVICE_PATH_PROTOCOL *) NULL, + { + DebugPortReset, + DebugPortWrite, + DebugPortRead, + DebugPortPoll + }, + (EFI_HANDLE) 0, + (EFI_SERIAL_IO_PROTOCOL *) NULL, + DEBUGPORT_UART_DEFAULT_BAUDRATE, + DEBUGPORT_UART_DEFAULT_FIFO_DEPTH, + DEBUGPORT_UART_DEFAULT_TIMEOUT, + (EFI_PARITY_TYPE) DEBUGPORT_UART_DEFAULT_PARITY, + DEBUGPORT_UART_DEFAULT_DATA_BITS, + (EFI_STOP_BITS_TYPE) DEBUGPORT_UART_DEFAULT_STOP_BITS +}; + +/** + Local worker function to obtain device path information from DebugPort variable. + + Records requested settings in DebugPort device structure. + +**/ +EFI_DEVICE_PATH_PROTOCOL * +GetDebugPortVariable ( + VOID + ) +{ + UINTN DataSize; + EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + GetVariable2 (EFI_DEBUGPORT_VARIABLE_NAME, &gEfiDebugPortVariableGuid, (VOID **) &DebugPortVariable, &DataSize); + if (DebugPortVariable == NULL) { + return NULL; + } + + DevicePath = DebugPortVariable; + while (!IsDevicePathEnd (DevicePath) && !IS_UART_DEVICEPATH (DevicePath)) { + DevicePath = NextDevicePathNode (DevicePath); + } + + if (IsDevicePathEnd (DevicePath)) { + FreePool (DebugPortVariable); + return NULL; + } else { + CopyMem ( + &mDebugPortDevice.BaudRate, + &((UART_DEVICE_PATH *) DevicePath)->BaudRate, + sizeof (((UART_DEVICE_PATH *) DevicePath)->BaudRate) + ); + mDebugPortDevice.ReceiveFifoDepth = DEBUGPORT_UART_DEFAULT_FIFO_DEPTH; + mDebugPortDevice.Timeout = DEBUGPORT_UART_DEFAULT_TIMEOUT; + CopyMem ( + &mDebugPortDevice.Parity, + &((UART_DEVICE_PATH *) DevicePath)->Parity, + sizeof (((UART_DEVICE_PATH *) DevicePath)->Parity) + ); + CopyMem ( + &mDebugPortDevice.DataBits, + &((UART_DEVICE_PATH *) DevicePath)->DataBits, + sizeof (((UART_DEVICE_PATH *) DevicePath)->DataBits) + ); + CopyMem ( + &mDebugPortDevice.StopBits, + &((UART_DEVICE_PATH *) DevicePath)->StopBits, + sizeof (((UART_DEVICE_PATH *) DevicePath)->StopBits) + ); + return DebugPortVariable; + } +} + +/** + Debug Port Driver entry point. + + Reads DebugPort variable to determine what device and settings to use as the + debug port. Binds exclusively to SerialIo. Reverts to defaults if no variable + is found. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeDebugPortDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gDebugPortDriverBinding, + ImageHandle, + &gDebugPortComponentName, + &gDebugPortComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Checks to see if there's not already a DebugPort interface somewhere. + + If there's a DEBUGPORT variable, the device path must match exactly. If there's + no DEBUGPORT variable, then device path is not checked and does not matter. + Checks to see that there's a serial io interface on the controller handle + that can be bound BY_DRIVER | EXCLUSIVE. + If all these tests succeed, then we return EFI_SUCCESS, else, EFI_UNSUPPORTED + or other error returned by OpenProtocol. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to test. + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED Debug Port device is not supported. + @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device. + @retval others Some error occurs. + +**/ +EFI_STATUS +EFIAPI +DebugPortSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DebugPortVariable; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEBUGPORT_PROTOCOL *DebugPortInterface; + EFI_HANDLE TempHandle; + + // + // Check to see that there's not a debugport protocol already published, + // since only one standard UART serial port could be supported by this driver. + // + if (gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **) &DebugPortInterface) != EFI_NOT_FOUND) { + return EFI_UNSUPPORTED; + } + // + // Read DebugPort variable to determine debug port selection and parameters + // + DebugPortVariable = GetDebugPortVariable (); + + if (DebugPortVariable != NULL) { + // + // There's a DEBUGPORT variable, so do LocateDevicePath and check to see if + // the closest matching handle matches the controller handle, and if it does, + // check to see that the remaining device path has the DebugPort GUIDed messaging + // device path only. Otherwise, it's a mismatch and EFI_UNSUPPORTED is returned. + // + DevicePath = DebugPortVariable; + Status = gBS->LocateDevicePath ( + &gEfiSerialIoProtocolGuid, + &DevicePath, + &TempHandle + ); + + if (Status == EFI_SUCCESS && TempHandle != ControllerHandle) { + Status = EFI_UNSUPPORTED; + } + + if (Status == EFI_SUCCESS && + (DevicePath->Type != MESSAGING_DEVICE_PATH || + DevicePath->SubType != MSG_VENDOR_DP || + *((UINT16 *) DevicePath->Length) != sizeof (DEBUGPORT_DEVICE_PATH))) { + + Status = EFI_UNSUPPORTED; + } + + if (Status == EFI_SUCCESS && !CompareGuid (&gEfiDebugPortDevicePathGuid, (GUID *) (DevicePath + 1))) { + Status = EFI_UNSUPPORTED; + } + + FreePool (DebugPortVariable); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &SerialIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return Status; +} + +/** + Binds exclusively to serial io on the controller handle, Produces DebugPort + protocol and DevicePath on new handle. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to bind driver to. + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle. + @retval EFI_OUT_OF_RESOURCES Fails to allocate memory for device. + @retval others Some error occurs. + +**/ +EFI_STATUS +EFIAPI +DebugPortStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + DEBUGPORT_DEVICE_PATH DebugPortDP; + EFI_DEVICE_PATH_PROTOCOL EndDP; + EFI_DEVICE_PATH_PROTOCOL *Dp1; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &mDebugPortDevice.SerialIoBinding, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + mDebugPortDevice.SerialIoDeviceHandle = ControllerHandle; + + // + // Initialize the Serial Io interface... + // + Status = mDebugPortDevice.SerialIoBinding->SetAttributes ( + mDebugPortDevice.SerialIoBinding, + mDebugPortDevice.BaudRate, + mDebugPortDevice.ReceiveFifoDepth, + mDebugPortDevice.Timeout, + mDebugPortDevice.Parity, + mDebugPortDevice.DataBits, + mDebugPortDevice.StopBits + ); + if (EFI_ERROR (Status)) { + mDebugPortDevice.BaudRate = 0; + mDebugPortDevice.Parity = DefaultParity; + mDebugPortDevice.DataBits = 0; + mDebugPortDevice.StopBits = DefaultStopBits; + mDebugPortDevice.ReceiveFifoDepth = 0; + Status = mDebugPortDevice.SerialIoBinding->SetAttributes ( + mDebugPortDevice.SerialIoBinding, + mDebugPortDevice.BaudRate, + mDebugPortDevice.ReceiveFifoDepth, + mDebugPortDevice.Timeout, + mDebugPortDevice.Parity, + mDebugPortDevice.DataBits, + mDebugPortDevice.StopBits + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + } + + mDebugPortDevice.SerialIoBinding->Reset (mDebugPortDevice.SerialIoBinding); + + // + // Create device path instance for DebugPort + // + DebugPortDP.Header.Type = MESSAGING_DEVICE_PATH; + DebugPortDP.Header.SubType = MSG_VENDOR_DP; + SetDevicePathNodeLength (&(DebugPortDP.Header), sizeof (DebugPortDP)); + CopyGuid (&DebugPortDP.Guid, &gEfiDebugPortDevicePathGuid); + + Dp1 = DevicePathFromHandle (ControllerHandle); + if (Dp1 == NULL) { + Dp1 = &EndDP; + SetDevicePathEndNode (Dp1); + } + + mDebugPortDevice.DebugPortDevicePath = AppendDevicePathNode (Dp1, (EFI_DEVICE_PATH_PROTOCOL *) &DebugPortDP); + if (mDebugPortDevice.DebugPortDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Publish DebugPort and Device Path protocols + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mDebugPortDevice.DebugPortDeviceHandle, + &gEfiDevicePathProtocolGuid, + mDebugPortDevice.DebugPortDevicePath, + &gEfiDebugPortProtocolGuid, + &mDebugPortDevice.DebugPortInterface, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + // + // Connect debugport child to serial io + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &mDebugPortDevice.SerialIoBinding, + This->DriverBindingHandle, + mDebugPortDevice.DebugPortDeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + + return EFI_SUCCESS; +} + +/** + Stop this driver on ControllerHandle by removing Serial IO protocol on + the ControllerHandle. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle. + @retval other This driver was not removed from this device. + +**/ +EFI_STATUS +EFIAPI +DebugPortStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + mDebugPortDevice.SerialIoBinding = NULL; + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + FreePool (mDebugPortDevice.DebugPortDevicePath); + + return EFI_SUCCESS; + } else { + // + // Disconnect SerialIo child handle + // + Status = gBS->CloseProtocol ( + mDebugPortDevice.SerialIoDeviceHandle, + &gEfiSerialIoProtocolGuid, + This->DriverBindingHandle, + mDebugPortDevice.DebugPortDeviceHandle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Unpublish our protocols (DevicePath, DebugPort) + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + mDebugPortDevice.DebugPortDeviceHandle, + &gEfiDevicePathProtocolGuid, + mDebugPortDevice.DebugPortDevicePath, + &gEfiDebugPortProtocolGuid, + &mDebugPortDevice.DebugPortInterface, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + ControllerHandle, + &gEfiSerialIoProtocolGuid, + (VOID **) &mDebugPortDevice.SerialIoBinding, + This->DriverBindingHandle, + mDebugPortDevice.DebugPortDeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + mDebugPortDevice.DebugPortDeviceHandle = NULL; + } + } + + return Status; +} + +/** + DebugPort protocol member function. Calls SerialIo:GetControl to flush buffer. + We cannot call SerialIo:SetAttributes because it uses pool services, which use + locks, which affect TPL, so it's not interrupt context safe or re-entrant. + SerialIo:Reset() calls SetAttributes, so it can't be used either. + + The port itself should be fine since it was set up during initialization. + + @param This Protocol instance pointer. + + @return EFI_SUCCESS Always. + +**/ +EFI_STATUS +EFIAPI +DebugPortReset ( + IN EFI_DEBUGPORT_PROTOCOL *This + ) +{ + UINTN BufferSize; + UINTN BitBucket; + + while (This->Poll (This) == EFI_SUCCESS) { + BufferSize = 1; + This->Read (This, 0, &BufferSize, &BitBucket); + } + + return EFI_SUCCESS; +} + +/** + DebugPort protocol member function. Calls SerialIo:Read() after setting + if it's different than the last SerialIo access. + + @param This Pointer to DebugPort protocol. + @param Timeout Timeout value. + @param BufferSize On input, the size of Buffer. + On output, the amount of data actually written. + @param Buffer Pointer to buffer to read. + + @retval EFI_SUCCESS + @retval others + +**/ +EFI_STATUS +EFIAPI +DebugPortRead ( + IN EFI_DEBUGPORT_PROTOCOL *This, + IN UINT32 Timeout, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + DEBUGPORT_DEVICE *DebugPortDevice; + UINTN LocalBufferSize; + EFI_STATUS Status; + UINT8 *BufferPtr; + + DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); + BufferPtr = Buffer; + LocalBufferSize = *BufferSize; + + do { + Status = DebugPortDevice->SerialIoBinding->Read ( + DebugPortDevice->SerialIoBinding, + &LocalBufferSize, + BufferPtr + ); + if (Status == EFI_TIMEOUT) { + if (Timeout > DEBUGPORT_UART_DEFAULT_TIMEOUT) { + Timeout -= DEBUGPORT_UART_DEFAULT_TIMEOUT; + } else { + Timeout = 0; + } + } else if (EFI_ERROR (Status)) { + break; + } + + BufferPtr += LocalBufferSize; + LocalBufferSize = *BufferSize - (BufferPtr - (UINT8 *) Buffer); + } while (LocalBufferSize != 0 && Timeout > 0); + + *BufferSize = (UINTN) BufferPtr - (UINTN) Buffer; + + return Status; +} + +/** + DebugPort protocol member function. Calls SerialIo:Write() Writes 8 bytes at + a time and does a GetControl between 8 byte writes to help insure reads are + interspersed This is poor-man's flow control. + + @param This Pointer to DebugPort protocol. + @param Timeout Timeout value. + @param BufferSize On input, the size of Buffer. + On output, the amount of data actually written. + @param Buffer Pointer to buffer to read. + + @retval EFI_SUCCESS The data was written. + @retval others Fails when writting datas to debug port device. + +**/ +EFI_STATUS +EFIAPI +DebugPortWrite ( + IN EFI_DEBUGPORT_PROTOCOL *This, + IN UINT32 Timeout, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + DEBUGPORT_DEVICE *DebugPortDevice; + UINTN Position; + UINTN WriteSize; + EFI_STATUS Status; + UINT32 SerialControl; + + Status = EFI_SUCCESS; + DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); + + WriteSize = 8; + for (Position = 0; Position < *BufferSize && !EFI_ERROR (Status); Position += WriteSize) { + DebugPortDevice->SerialIoBinding->GetControl ( + DebugPortDevice->SerialIoBinding, + &SerialControl + ); + if (*BufferSize - Position < 8) { + WriteSize = *BufferSize - Position; + } + + Status = DebugPortDevice->SerialIoBinding->Write ( + DebugPortDevice->SerialIoBinding, + &WriteSize, + &((UINT8 *) Buffer)[Position] + ); + } + + *BufferSize = Position; + return Status; +} + +/** + DebugPort protocol member function. Calls SerialIo:Write() after setting + if it's different than the last SerialIo access. + + @param This Pointer to DebugPort protocol. + + @retval EFI_SUCCESS At least 1 character is ready to be read from + the DebugPort interface. + @retval EFI_NOT_READY There are no characters ready to read from the + DebugPort interface + @retval EFI_DEVICE_ERROR A hardware failure occurred... (from SerialIo) + +**/ +EFI_STATUS +EFIAPI +DebugPortPoll ( + IN EFI_DEBUGPORT_PROTOCOL *This + ) +{ + EFI_STATUS Status; + UINT32 SerialControl; + DEBUGPORT_DEVICE *DebugPortDevice; + + DebugPortDevice = DEBUGPORT_DEVICE_FROM_THIS (This); + + Status = DebugPortDevice->SerialIoBinding->GetControl ( + DebugPortDevice->SerialIoBinding, + &SerialControl + ); + + if (!EFI_ERROR (Status)) { + if ((SerialControl & EFI_SERIAL_INPUT_BUFFER_EMPTY) != 0) { + Status = EFI_NOT_READY; + } else { + Status = EFI_SUCCESS; + } + } + + return Status; +} + +/** + Unload function that is registered in the LoadImage protocol. It un-installs + protocols produced and deallocates pool used by the driver. Called by the core + when unloading the driver. + + @param ImageHandle + + @retval EFI_SUCCESS Unload Debug Port driver successfully. + @retval EFI_ABORTED Serial IO is still binding. + +**/ +EFI_STATUS +EFIAPI +ImageUnloadHandler ( + EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + VOID *ComponentName; + VOID *ComponentName2; + + if (mDebugPortDevice.SerialIoBinding != NULL) { + return EFI_ABORTED; + } + + // + // Driver is stopped already. + // + Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName); + if (EFI_ERROR (Status)) { + ComponentName = NULL; + } + + Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2); + if (EFI_ERROR (Status)) { + ComponentName2 = NULL; + } + + if (ComponentName == NULL) { + if (ComponentName2 == NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding, + NULL + ); + } else { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding, + &gEfiComponentName2ProtocolGuid, ComponentName2, + NULL + ); + } + } else { + if (ComponentName2 == NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding, + &gEfiComponentNameProtocolGuid, ComponentName, + NULL + ); + } else { + Status = gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, &gDebugPortDriverBinding, + &gEfiComponentNameProtocolGuid, ComponentName, + &gEfiComponentName2ProtocolGuid, ComponentName2, + NULL + ); + } + } + + return Status; +} -- cgit 1.2.3-korg