Use of DebugLib in StandaloneMmCoreEntryPoint for AArch64 platforms


Thomas Abraham
 

Hi All,

The StandaloneMmCoreEntryPoint library for AArch64 platforms uses DebugLib APIs in the code path starting from '_ModuleEntryPoint' to the point at which 'ProcessModuleEntryPointList' is called. In this code path, the DebugLib APIs are invoked even before the DebugLib's constructor has executed. The DebugLib's constructor executes only after the execution reaches 'StandaloneMmMain' and 'ProcessLibraryConstructorList' is executed.

Due to this, on AArch64 platforms, the calls to DebugLib APIs in the above mentioned code path is incorrect because the constructor of the DebugLib has not executed. As an example, on AArch64 platforms that use 'BaseDebugLibSerialPort' as the DebugLib implementation, the serial port is not initialized prior to the call to DebugLib APIs causing serial port writes to fail and stall the execution.

Some solutions for this issue but not preferred ones are -


* Remove the DebugLib calls in the above mentioned code path (no DebugLib calls to be used until its constructor is called).
* Ensure that a previous boot stage has configured required hardware (serial port in case of BaseDebugLibSerialPort).

Are there better solutions for this particular problem?

Thanks,
Thomas.


Laszlo Ersek
 

On 03/29/21 09:37, Thomas Abraham wrote:
Hi All,

The StandaloneMmCoreEntryPoint library for AArch64 platforms uses DebugLib APIs in the code path starting from '_ModuleEntryPoint' to the point at which 'ProcessModuleEntryPointList' is called. In this code path, the DebugLib APIs are invoked even before the DebugLib's constructor has executed. The DebugLib's constructor executes only after the execution reaches 'StandaloneMmMain' and 'ProcessLibraryConstructorList' is executed.

Due to this, on AArch64 platforms, the calls to DebugLib APIs in the above mentioned code path is incorrect because the constructor of the DebugLib has not executed. As an example, on AArch64 platforms that use 'BaseDebugLibSerialPort' as the DebugLib implementation, the serial port is not initialized prior to the call to DebugLib APIs causing serial port writes to fail and stall the execution.

Some solutions for this issue but not preferred ones are -


* Remove the DebugLib calls in the above mentioned code path (no DebugLib calls to be used until its constructor is called).
* Ensure that a previous boot stage has configured required hardware (serial port in case of BaseDebugLibSerialPort).

Are there better solutions for this particular problem?
Not necessarily "better", just different:

(1) Use (write) a DebugLib instance that has no constructor, and calls
SerialPortInitialize() the first time an actual DebugLib API needs to
produce output.

(2) Or, stick with BaseDebugLibSerialPort, but use (write) such a
SerialPortLib instance whose SerialPortInitialize() function does
nothing, but the output-producing SerialPortLib functions initialize the
hardware (and associated global variables) upon first use. Something
similar can be seen in
"ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c".

Laszlo


Thanks,
Thomas.