Let's revive this old thread:

On 09/11/13 03:38, Andrew Fish wrote:

> A dependency tree is constructed so the library constructors get
> called in the correct sequence. If it does not work it is likely a
> bug in the libraries INF file not listing the LibraryClass it depends
> on. If the driver also listed this library it could appear that the
> library works, when in reality it has a bug in the INF file. A good
> rule of thumb is to look in your library at the libraries that where
> included via an #include statement and make sure they are listed in
> the library INF file. If you miss an #include of a library function
> you call you will get a compiler error.
> 
> Since the DSC gets  to chose the library instance for the library
> class this dependency is only known at build time and the constructor
> ends up in the build generated AutoGen.c file.

Consider the following library dependencies, in a DXE module:

module +-> BaseDebugLibSerialPort -> CustomSerialPortLib -> DxePcdLib -+
       |       ^                                                       |
       |       |                                                       |
       |       +-------------------------------------------------------+
       |                                                               |
       +-> UefiBootServicesTableLib                                    |
               ^                                                       |
               |                                                       |
               +-------------------------------------------------------+

The DebugLib instance is the "stock" one in
MdePkg/Library/BaseDebugLibSerialPort.

Its SerialPortLib dependency is resolved by a custom instance
("CustomSerialPortLib") that retrieves some properties of the serial
port from dynamic PCD(s).

Since the module is one of the DXE types, the PcdLib dependency is
resolved with DxePcdLib. However, that library instance depends on
DebugLib, which creates a cycle.

The build tools don't choke on this cycle. However, the cycle causes an
"impossible" situation where library constructors cannot be ordered
properly, in any way.

When BaseDebugLibSerialPort is constructed, the following happens:

  BaseDebugLibSerialPortConstructor() [BaseDebugLibSerialPort]
    SerialPortInitialize()            [CustomSerialPortLib]
      LibPcdGet64()                   [DxePcdLib]
        GetPcdProtocol()
          gBS->LocateProtocol()

At this point the system crashes, because gBS is NULL, *despite*
DxePcdLib depending on UefiBootServicesTableLib. The latter library's
constructor function sets gBS to non-NULL.

  UefiBootServicesTableLibConstructor() [UefiBootServicesTableLib]
    gBS = SystemTable->BootServices

The build tools cannot satisfy the DxePcdLib->UefiBootServicesTableLib
dependency (ie. they can't generate a correctly ordered set of calls to
constructor functions) because elsewhere in the module's library
dependency graph there is a cycle (ie. it's not a tree). The build tools
must cut that cycle somewhere, and the way it happens to be cut breaks
DxePcdLib.

What is the recommended solution here? Obviously, the unique property of
this graph is the CustomSerialPortLib -> DxePcdLib edge, ie. that the
SerialPortLib instance tries to figure out serial port properties from a
dynamic PCD (which has been set during PEI).

I'm not sure how one of the three edges constituting the cycle could be
cut. I think the "functionally" most straightforward way would be to
create a custom copy of DxePcdLib, and to remove all the ASSERT()s -- or
at least reimplement all of them with *silent* CpuDeadLoop() calls.

Thanks,
Laszlo


------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to