Add a runtime instance of FdtPL011SerialPortLib to support runtime
serial port debug for UEFI runtime services.

The framework is based on below discussion:
https://lists.01.org/pipermail/edk2-devel/2019-March/037986.html

We have decided to use an individual firmware UART for UEFI runtime
debug, however this depends on QEMU to provide this virtual device, so
we still use the OS visible system UART at the moment, with the
potential *risk* of conflicting OS serial port read/write.

Once QEMU implements individual firmware UART, we need rewrite
PlatformGetRtSerialBase() to get the real runtime serial port base
address.

Cc: Laszlo Ersek <ler...@redhat.com>
Cc: Ard Biesheuvel <ard.biesheu...@linaro.org>
Cc: Julien Grall <julien.gr...@arm.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Heyi Guo <guoh...@huawei.com>
Signed-off-by: Heyi Guo <heyi....@linaro.org>
---
 ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c          |   
6 +-
 ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.h          |  
32 ++++
 ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.c   | 
187 ++++++++++++++++++++
 ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.inf |  
59 ++++++
 4 files changed, 282 insertions(+), 2 deletions(-)

diff --git a/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c 
b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c
index 2f10fb7..017ca30 100644
--- a/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c
+++ b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.c
@@ -3,9 +3,10 @@
 
   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
   Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.<BR>
-  Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2014 - 2019, Linaro Ltd. All rights reserved.<BR>
   Copyright (c) 2014, Red Hat, Inc.<BR>
   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2019, Huawei Technologies Co., Ltd. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
@@ -28,8 +29,9 @@
 #include <Pi/PiHob.h>
 #include <Library/HobLib.h>
 #include <Guid/EarlyPL011BaseAddress.h>
+#include "FdtPL011SerialPortLib.h"
 
-STATIC UINTN mSerialBaseAddress;
+UINTN mSerialBaseAddress;
 
 RETURN_STATUS
 EFIAPI
diff --git a/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.h 
b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.h
new file mode 100644
index 0000000..32c0b9b
--- /dev/null
+++ b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.h
@@ -0,0 +1,32 @@
+/** @file
+  Serial I/O Port library internal header
+
+  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+  Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2014 - 2019, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2014, Red Hat, Inc.<BR>
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2019, Huawei Technologies Co., Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _FDT_PL011_SERIAL_PORT_LIB_H_
+#define _FDT_PL011_SERIAL_PORT_LIB_H_
+
+extern UINTN mSerialBaseAddress;
+
+RETURN_STATUS
+EFIAPI
+FdtPL011SerialPortLibInitialize (
+  VOID
+  );
+
+#endif
diff --git 
a/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.c 
b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.c
new file mode 100644
index 0000000..4a7b0b5
--- /dev/null
+++ b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.c
@@ -0,0 +1,187 @@
+/** @file
+  Initialization for runtime serial I/O port library
+
+  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+  Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2014 - 2019, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2014, Red Hat, Inc.<BR>
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2019, Huawei Technologies Co., Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// UEFI runtime serial port debug framework:
+// - Use BaseDebugLibSerialPort for DebugLib
+// - Boot time debug message of runtime modules will be directed to the same
+//   serial port of other modules
+// - Runtime debug message should be directed to an individual firmware serial
+//   port to avoid conflict with OS serial port access
+//
+
+#include <Uefi.h>
+#include <Guid/EventGroup.h>
+#include <Library/BaseMemoryLib.h>
+#include "FdtPL011SerialPortLib.h"
+
+STATIC UINTN mRtSerialBaseAddress;
+STATIC EFI_EVENT mSerialVirtualAddressChangeEvent = NULL;
+// We can't use gRT directly due to library dependency.
+STATIC EFI_RUNTIME_SERVICES *gInternalRT = NULL;
+
+VOID
+EFIAPI
+SerialVirtualAddressChangeCallBack (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  gInternalRT->ConvertPointer (0, (VOID **) &mRtSerialBaseAddress);
+  mSerialBaseAddress = mRtSerialBaseAddress;
+}
+
+//
+// To avoid library constructor looped dependence, we copy
+// EfiGetSystemConfigurationTable() here instead of using UefiLib.
+//
+STATIC
+RETURN_STATUS
+InternalGetSystemConfigurationTable (
+  IN  EFI_SYSTEM_TABLE  *SystemTable,
+  IN  EFI_GUID  *TableGuid,
+  OUT VOID      **Table
+  )
+{
+  UINTN             Index;
+
+  *Table = NULL;
+  for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
+    if (CompareGuid (TableGuid, 
&(SystemTable->ConfigurationTable[Index].VendorGuid))) {
+      *Table = SystemTable->ConfigurationTable[Index].VendorTable;
+      return RETURN_SUCCESS;
+    }
+  }
+
+  return RETURN_NOT_FOUND;
+}
+
+STATIC
+RETURN_STATUS
+PlatformGetRtSerialBase (
+    IN EFI_HANDLE        ImageHandle,
+    IN EFI_SYSTEM_TABLE  *SystemTable,
+    IN OUT UINTN         *SerialBase
+    )
+{
+  //
+  // FIXME: Using system serial port will probably cause conflict with OS 
serial
+  // port access, so this code can ONLY be used for debug purpose and may cause
+  // unexpected system behaviour!
+  // We need change to the individual firmware serial port as soon as QEMU
+  // implements that.
+  //
+  *SerialBase = mSerialBaseAddress;
+  return RETURN_SUCCESS;
+}
+
+RETURN_STATUS
+EFIAPI
+SerialPortLibConstructorRuntime (
+    IN EFI_HANDLE        ImageHandle,
+    IN EFI_SYSTEM_TABLE  *SystemTable
+    )
+{
+  RETURN_STATUS                   Status;
+  UINT64                          Length = SIZE_4KB;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc = {0};
+  EFI_DXE_SERVICES                *InternalDS = NULL;
+
+  Status = FdtPL011SerialPortLibInitialize();
+  if (RETURN_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = PlatformGetRtSerialBase (ImageHandle, SystemTable, 
&mRtSerialBaseAddress);
+  if (RETURN_ERROR (Status)) {
+    return Status;
+  }
+
+  gInternalRT = SystemTable->RuntimeServices;
+
+  Status = InternalGetSystemConfigurationTable (
+      SystemTable,
+      &gEfiDxeServicesTableGuid,
+      (VOID **) &InternalDS
+      );
+  if (RETURN_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // For the serial port register space length is only 4KB, we don't need to
+  // check if the descriptor is large enough to cover the space.
+  //
+  Status = InternalDS->GetMemorySpaceDescriptor(mRtSerialBaseAddress, &Desc);
+  if (RETURN_ERROR (Status) ||
+      Desc.GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+    Status = InternalDS->AddMemorySpace (
+        EfiGcdMemoryTypeMemoryMappedIo,
+        mRtSerialBaseAddress,
+        Length,
+        EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+        );
+    if (RETURN_ERROR (Status)) {
+      return Status;
+    }
+    Desc.Attributes = EFI_MEMORY_UC;
+  }
+
+  if ((Desc.Attributes & EFI_MEMORY_RUNTIME) == 0) {
+    Desc.Attributes |= EFI_MEMORY_RUNTIME;
+    Status = InternalDS->SetMemorySpaceAttributes (
+        mRtSerialBaseAddress,
+        Length,
+        Desc.Attributes
+        );
+    if(RETURN_ERROR (Status)){
+      return Status;
+    }
+  }
+
+  Status = SystemTable->BootServices->CreateEventEx (
+      EVT_NOTIFY_SIGNAL,
+      TPL_NOTIFY,
+      SerialVirtualAddressChangeCallBack,
+      NULL,
+      &gEfiEventVirtualAddressChangeGuid,
+      &mSerialVirtualAddressChangeEvent
+      );
+  if (RETURN_ERROR (Status)) {
+    mSerialVirtualAddressChangeEvent = NULL;
+  }
+
+  return Status;
+}
+
+RETURN_STATUS
+EFIAPI
+SerialPortLibDestructor (
+    IN EFI_HANDLE        ImageHandle,
+    IN EFI_SYSTEM_TABLE  *SystemTable
+    )
+{
+
+  if (!mSerialVirtualAddressChangeEvent) {
+    return RETURN_SUCCESS;
+  }
+
+  return SystemTable->BootServices->CloseEvent 
(mSerialVirtualAddressChangeEvent);
+}
diff --git 
a/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.inf 
b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.inf
new file mode 100644
index 0000000..9403030
--- /dev/null
+++ b/ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLibRuntime.inf
@@ -0,0 +1,59 @@
+#/** @file
+#
+#  Component description file for FdtPL011SerialPortLibRuntime module
+#
+#  Copyright (c) 2011-2015, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2019, Linaro Ltd. All rights reserved.<BR>
+#  Copyright (c) 2019, Huawei Technologies Co., Ltd. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD 
License
+#  which accompanies this distribution.  The full text of the license may be 
found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
IMPLIED.
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = FdtPL011SerialPortLibRuntime
+  FILE_GUID                      = 83afbb90-38c6-11e9-aeab-203db202c950
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SerialPortLib|DXE_RUNTIME_DRIVER
+  CONSTRUCTOR                    = SerialPortLibConstructorRuntime
+  DESTRUCTOR                     = SerialPortLibDestructor
+
+[Sources.common]
+  FdtPL011SerialPortLib.c
+  FdtPL011SerialPortLibRuntime.c
+
+[LibraryClasses]
+  BaseMemoryLib
+  HobLib
+  PL011UartLib
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  ArmVirtPkg/ArmVirtPkg.dec
+  ArmPkg/ArmPkg.dec
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+  gArmPlatformTokenSpaceGuid.PL011UartClkInHz
+
+[Guids]
+  gEarlyPL011BaseAddressGuid
+  gEfiDxeServicesTableGuid
+  gEfiEventVirtualAddressChangeGuid
+
+[Depex]
+  gEfiCpuArchProtocolGuid
-- 
1.8.3.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to