From mboxrd@z Thu Jan 1 00:00:00 1970 Subject: Re: [edk2-devel] [PATCH] UefiPayloadPkg: Add support for logging to CBMEM console To: Benjamin Doron ,devel@edk2.groups.io From: "Sean Rhodes" X-Originating-Location: Surbiton, England, GB (217.155.46.38) X-Originating-Platform: Linux Chrome 97 User-Agent: GROUPS.IO Web Poster MIME-Version: 1.0 Date: Sat, 29 Jan 2022 01:06:48 -0800 References: In-Reply-To: Message-ID: <23914.1643447208925426608@groups.io> Content-Type: multipart/alternative; boundary="kDzNW6RDakMaOI3cDVRY" --kDzNW6RDakMaOI3cDVRY Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hey Benjamin The commit has been around for a while now and is perfectly functional. Why= don't we upstream it and then `FindCbTag()` and `CopyMem()` can be a follo= w-up patch when/if time allows? Cheers Sean Squashing that commit in: [PATCH] UefiPayloadPkg: Add support for logging to CBMEM console Tested on QEMU, dumping the appropriate memory region in UEFI shell shows the TianoCore log. `find_cb_subtable` is sourced from STM/SeaBIOS. Signed-off-by: Benjamin Doron --- UefiPayloadPkg/Include/Coreboot.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0|=C2=A0 14 + .../Library/CbSerialPortLib/CbSerialPortLib.c | 272 ++++++++++++++++++ .../CbSerialPortLib/CbSerialPortLib.inf=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 2= 7 ++ UefiPayloadPkg/UefiPayloadPkg.dsc=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0|=C2=A0 =C2=A05 + UefiPayloadPkg/UefiPayloadPkg.fdf=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0|=C2=A0 =C2=A06 +- 5 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.c create mode 100644 UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.i= nf diff --git a/UefiPayloadPkg/Include/Coreboot.h b/UefiPayloadPkg/Include/Cor= eboot.h index a3e1109fe8..f2f577a02e 100644 --- a/UefiPayloadPkg/Include/Coreboot.h +++ b/UefiPayloadPkg/Include/Coreboot.h @@ -199,7 +199,14 @@ struct cb_forward { UINT64=C2=A0 =C2=A0 forward; }; +struct cb_cbmem_ref { +=C2=A0 UINT32 tag; +=C2=A0 UINT32 size; +=C2=A0 UINT64 cbmem_addr; +}; + #define CB_TAG_FRAMEBUFFER=C2=A0 0x0012 + struct cb_framebuffer { UINT32=C2=A0 =C2=A0 tag; UINT32=C2=A0 =C2=A0 size; @@ -230,6 +237,13 @@ struct cb_vdat { #define CB_TAG_TIMESTAMPS=C2=A0 =C2=A0 =C2=A00x0016 #define CB_TAG_CBMEM_CONSOLE=C2=A0 0x0017 #define CB_TAG_MRC_CACHE=C2=A0 =C2=A0 =C2=A0 0x0018 + +struct cbmem_console { +=C2=A0 UINT32 size; +=C2=A0 UINT32 cursor; +=C2=A0 UINT8=C2=A0 body[0]; +} __attribute__((packed)); + struct cb_cbmem_tab { UINT32=C2=A0 =C2=A0 tag; UINT32=C2=A0 =C2=A0 size; diff --git a/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.c b/Uef= iPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.c new file mode 100644 index 0000000000..7b26c08dd7 --- /dev/null +++ b/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.c @@ -0,0 +1,272 @@ +/** @file +=C2=A0 CBMEM console SerialPortLib instance + +=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +#include +#include +#include + +// +// We can't use DebugLib due to a constructor dependency cycle between Deb= ugLib +// and ourselves. +// +#define ASSERT(Expression)=C2=A0 =C2=A0 =C2=A0 \ +=C2=A0 do {=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 \ +=C2=A0 =C2=A0 if (!(Expression)) {=C2=A0 =C2=A0 =C2=A0 =C2=A0 \ +=C2=A0 =C2=A0 =C2=A0 CpuDeadLoop ();=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0\ +=C2=A0 =C2=A0 }=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0\ +=C2=A0 } while (FALSE) + +#define CBMC_CURSOR_MASK ((1 << 28) - 1) +#define CBMC_OVERFLOW (1 << 31) + +STATIC struct cbmem_console=C2=A0 *gCbConsole =3D NULL; +STATIC UINT32 STM_cursor =3D 0; + +// Try to find the coreboot memory table in the given coreboot table. +static void * +find_cb_subtable(struct cb_header *cbh, UINT32 tag) +{ +=C2=A0 char *tbl =3D (char *)cbh + sizeof(*cbh); +=C2=A0 UINT32 count =3D cbh->table_entries; +=C2=A0 int i; +=C2=A0 for (i=3D0; isize; +=C2=A0 =C2=A0 if (cbm->tag =3D=3D tag) +=C2=A0 =C2=A0 =C2=A0 return cbm; +=C2=A0 } +=C2=A0 =C2=A0 return NULL; +} + +/** +=C2=A0 Initialize the serial device hardware. + +=C2=A0 If no initialization is required, then return RETURN_SUCCESS. +=C2=A0 If the serial device was successfully initialized, then return RETU= RN_SUCCESS. +=C2=A0 If the serial device could not be initialized, then return RETURN_D= EVICE_ERROR. + +=C2=A0 @retval RETURN_SUCCESS=C2=A0 =C2=A0 =C2=A0 =C2=A0 The serial device= was initialized. +=C2=A0 @retval RETURN_DEVICE_ERROR=C2=A0 =C2=A0The serial device could not= be initialized. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( +=C2=A0 VOID +=C2=A0 ) +{ +=C2=A0 /* `FindCbTag` doesn't work because we need direct access to the me= mory addresses? */ +=C2=A0 struct cb_header *cbh =3D GetParameterBase(); +=C2=A0 if (!cbh) { +=C2=A0 =C2=A0 return RETURN_DEVICE_ERROR; +=C2=A0 } + +=C2=A0 struct cb_cbmem_ref *cbref =3D find_cb_subtable(cbh, CB_TAG_CBMEM_C= ONSOLE); +=C2=A0 if (!cbref) { +=C2=A0 =C2=A0 return RETURN_DEVICE_ERROR; +=C2=A0 } + +=C2=A0 gCbConsole =3D (void *)(UINTN)cbref->cbmem_addr; // Support PEI and= DXE +=C2=A0 if (gCbConsole =3D=3D NULL) { +=C2=A0 =C2=A0 return RETURN_DEVICE_ERROR; +=C2=A0 } + +=C2=A0 // set the cursor such that the STM console will not overwrite the +=C2=A0 // coreboot console output +=C2=A0 STM_cursor =3D gCbConsole->cursor & CBMC_CURSOR_MASK; + +=C2=A0 return RETURN_SUCCESS; +} + +/** +=C2=A0 Write data from buffer to serial device. + +=C2=A0 Writes NumberOfBytes data bytes from Buffer to the serial device. +=C2=A0 The number of bytes actually written to the serial device is return= ed. +=C2=A0 If the return value is less than NumberOfBytes, then the write oper= ation failed. +=C2=A0 If Buffer is NULL, then ASSERT(). +=C2=A0 If NumberOfBytes is zero, then return 0. + +=C2=A0 @param=C2=A0 Buffer=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Pointer= to the data buffer to be written. +=C2=A0 @param=C2=A0 NumberOfBytes=C2=A0 =C2=A0 Number of bytes to written = to the serial device. + +=C2=A0 @retval 0=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Nu= mberOfBytes is 0. +=C2=A0 @retval >0=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Th= e number of bytes written to the serial device. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0If this value is less than NumberOfBytes, then the = write operation failed. + +**/ +UINTN +EFIAPI +SerialPortWrite ( +=C2=A0 IN UINT8=C2=A0 =C2=A0 =C2=A0*Buffer, +=C2=A0 IN UINTN=C2=A0 =C2=A0 =C2=A0NumberOfBytes +=C2=A0 ) +{ +=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Sent; +=C2=A0 UINT32=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cursor; +=C2=A0 UINT32=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flags; + +=C2=A0 ASSERT (Buffer !=3D NULL); + +=C2=A0 if (NumberOfBytes =3D=3D 0) { +=C2=A0 =C2=A0 return 0; +=C2=A0 } + +=C2=A0 if (!gCbConsole) { +=C2=A0 =C2=A0 return 0; +=C2=A0 } + +=C2=A0 Sent =3D 0; +=C2=A0 do { +=C2=A0 =C2=A0 cursor =3D gCbConsole->cursor & CBMC_CURSOR_MASK; +=C2=A0 =C2=A0 flags =3D gCbConsole->cursor & ~CBMC_CURSOR_MASK; + +=C2=A0 =C2=A0 if (cursor >=3D gCbConsole->size) { +=C2=A0 =C2=A0 =C2=A0 return 0; // Old coreboot version with legacy overflo= w mechanism. +=C2=A0 =C2=A0 } + +=C2=A0 =C2=A0 gCbConsole->body[cursor++] =3D Buffer[Sent++]; + +=C2=A0 =C2=A0 if (cursor >=3D gCbConsole->size) { +=C2=A0 =C2=A0 =C2=A0 cursor =3D STM_cursor; +=C2=A0 =C2=A0 =C2=A0 flags |=3D CBMC_OVERFLOW; +=C2=A0 =C2=A0 } + +=C2=A0 =C2=A0 gCbConsole->cursor =3D flags | cursor; +=C2=A0 } while (Sent < NumberOfBytes); + +=C2=A0 return Sent; +} + +/** +=C2=A0 Read data from serial device and save the datas in buffer. + +=C2=A0 Reads NumberOfBytes data bytes from a serial device into the buffer +=C2=A0 specified by Buffer. The number of bytes actually read is returned. +=C2=A0 If Buffer is NULL, then ASSERT(). +=C2=A0 If NumberOfBytes is zero, then return 0. + +=C2=A0 @param=C2=A0 Buffer=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Pointer= to the data buffer to store the data read from the serial device. +=C2=A0 @param=C2=A0 NumberOfBytes=C2=A0 =C2=A0 Number of bytes which will = be read. + +=C2=A0 @retval 0=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Re= ad data failed, no data is to be read. +=C2=A0 @retval >0=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Ac= tual number of bytes read from serial device. + +**/ +UINTN +EFIAPI +SerialPortRead ( +=C2=A0 OUT UINT8=C2=A0 =C2=A0 =C2=A0*Buffer, +=C2=A0 IN=C2=A0 UINTN=C2=A0 =C2=A0 =C2=A0NumberOfBytes +) +{ +=C2=A0 return 0; +} + +/** +=C2=A0 Polls a serial device to see if there is any data waiting to be rea= d. + +=C2=A0 @retval TRUE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Data is= waiting to be read from the serial device. +=C2=A0 @retval FALSE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 There is no = data waiting to be read from the serial device. + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( +=C2=A0 VOID +=C2=A0 ) +{ +=C2=A0 return FALSE; +} + +/** +=C2=A0 Sets the control bits on a serial device. + +=C2=A0 @param Control=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 Sets the bits of Control that are settable. + +=C2=A0 @retval RETURN_SUCCESS=C2=A0 =C2=A0 =C2=A0 =C2=A0 The new control b= its were set on the serial device. +=C2=A0 @retval RETURN_UNSUPPORTED=C2=A0 =C2=A0 The serial device does not = support this operation. +=C2=A0 @retval RETURN_DEVICE_ERROR=C2=A0 =C2=A0The serial device is not fu= nctioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetControl ( +=C2=A0 IN UINT32 Control +=C2=A0 ) +{ +=C2=A0 return RETURN_UNSUPPORTED; +} + +/** +=C2=A0 Retrieve the status of the control bits on a serial device. + +=C2=A0 @param Control=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 A pointer to return the current control signals from the serial device. + +=C2=A0 @retval RETURN_SUCCESS=C2=A0 =C2=A0 =C2=A0 =C2=A0 The control bits = were read from the serial device. +=C2=A0 @retval RETURN_UNSUPPORTED=C2=A0 =C2=A0 The serial device does not = support this operation. +=C2=A0 @retval RETURN_DEVICE_ERROR=C2=A0 =C2=A0The serial device is not fu= nctioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortGetControl ( +=C2=A0 OUT UINT32 *Control +=C2=A0 ) +{ +=C2=A0 return RETURN_UNSUPPORTED; +} + +/** +=C2=A0 Sets the baud rate, receive FIFO depth, transmit/receive time out, = parity, +=C2=A0 data bits, and stop bits on a serial device. + +=C2=A0 @param BaudRate=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The request= ed baud rate. A BaudRate value of 0 will use the +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 device's default interface speed. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 On output, the value actually set. +=C2=A0 @param ReceiveFifoDepth=C2=A0 =C2=A0The requested depth of the FIFO= on the receive side of the +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 serial interface. A ReceiveFifoDepth value of 0 wi= ll use +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 the device's default FIFO depth. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 On output, the value actually set. +=C2=A0 @param Timeout=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 The request= ed time out for a single character in microseconds. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 This timeout applies to both the transmit and rece= ive side of the +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 interface. A Timeout value of 0 will use the devic= e's default time +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 out value. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 On output, the value actually set. +=C2=A0 @param Parity=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The ty= pe of parity to use on this serial device. A Parity value of +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 DefaultParity will use the device's default parity= value. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 On output, the value actually set. +=C2=A0 @param DataBits=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The number = of data bits to use on the serial device. A DataBits +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 value of 0 will use the device's default data bit = setting. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 On output, the value actually set. +=C2=A0 @param StopBits=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The number = of stop bits to use on this serial device. A StopBits +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 value of DefaultStopBits will use the device's def= ault number of +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 stop bits. +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 On output, the value actually set. + +=C2=A0 @retval RETURN_SUCCESS=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 The= new attributes were set on the serial device. +=C2=A0 @retval RETURN_UNSUPPORTED=C2=A0 =C2=A0 =C2=A0 =C2=A0 The serial de= vice does not support this operation. +=C2=A0 @retval RETURN_INVALID_PARAMETER=C2=A0 One or more of the attribute= s has an unsupported value. +=C2=A0 @retval RETURN_DEVICE_ERROR=C2=A0 =C2=A0 =C2=A0 =C2=A0The serial de= vice is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetAttributes ( +=C2=A0 IN OUT UINT64=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*BaudR= ate, +=C2=A0 IN OUT UINT32=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*Recei= veFifoDepth, +=C2=A0 IN OUT UINT32=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*Timeo= ut, +=C2=A0 IN OUT EFI_PARITY_TYPE=C2=A0 =C2=A0 *Parity, +=C2=A0 IN OUT UINT8=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 *DataB= its, +=C2=A0 IN OUT EFI_STOP_BITS_TYPE *StopBits +=C2=A0 ) +{ +=C2=A0 return RETURN_UNSUPPORTED; +} diff --git a/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.inf b/U= efiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.inf new file mode 100644 index 0000000000..37b33c24ad --- /dev/null +++ b/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.inf @@ -0,0 +1,27 @@ +## @file +#=C2=A0 Component description file for CbSerialPortLib module. +# +#=C2=A0 SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] +=C2=A0 INF_VERSION=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =3D 0x00010005 +=C2=A0 BASE_NAME=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =3D CbSerialPortLib +=C2=A0 FILE_GUID=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =3D 0DB3EF12-1426-4086-B012-113184C4CE11 +=C2=A0 MODULE_TYPE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =3D BASE +=C2=A0 VERSION_STRING=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0=3D 0.5 +=C2=A0 LIBRARY_CLASS=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =3D SerialPortLib +=C2=A0 CONSTRUCTOR=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =3D SerialPortInitialize + +[Sources] +=C2=A0 CbSerialPortLib.c + +[Packages] +=C2=A0 MdeModulePkg/MdeModulePkg.dec +=C2=A0 MdePkg/MdePkg.dec +=C2=A0 UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] +=C2=A0 BaseLib +=C2=A0 BlParseLib diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayload= Pkg.dsc index 3d08edfe31..b3770b9be6 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -33,6 +33,7 @@ DEFINE UNIVERSAL_PAYLOAD=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D FALSE DEFINE SECURITY_STUB_ENABLE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D TRUE DEFINE SMM_SUPPORT=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =3D FALSE +=C2=A0 DEFINE USE_CBMEM_FOR_CONSOLE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D FALSE # # SBL:=C2=A0 =C2=A0 =C2=A0 UEFI payload for Slim Bootloader # COREBOOT: UEFI payload for coreboot @@ -223,7 +224,11 @@ TimerLib|UefiPayloadPkg/Library/AcpiTimerLib/AcpiTimerLib.inf !endif ResetSystemLib|UefiPayloadPkg/Library/ResetSystemLib/ResetSystemLib.inf +!if $(USE_CBMEM_FOR_CONSOLE) =3D=3D TRUE +=C2=A0 SerialPortLib|UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLi= b.inf +!else SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib= 16550.inf +!endif PlatformHookLib|UefiPayloadPkg/Library/PlatformHookLib/PlatformHookLib.inf PlatformBootManagerLib|UefiPayloadPkg/Library/PlatformBootManagerLib/Platfo= rmBootManagerLib.inf IoApicLib|PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayload= Pkg.fdf index f619a23139..0df8342252 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.fdf +++ b/UefiPayloadPkg/UefiPayloadPkg.fdf @@ -15,8 +15,12 @@ DEFINE FD_BLOCK_SIZE =3D 0x00001000 !if $(TARGET) =3D=3D "NOOPT" DEFINE FD_SIZE=C2=A0 =C2=A0 =C2=A0=3D 0x00850000 DEFINE NUM_BLOCKS=C2=A0 =3D 0x850 -!else +!elseif $(USE_CBMEM_FOR_CONSOLE) =3D=3D TRUE +DEFINE FD_SIZE=C2=A0 =C2=A0 =C2=A0=3D 0x00600000 +DEFINE NUM_BLOCKS=C2=A0 =3D 0x600 + +!else DEFINE FD_SIZE=C2=A0 =C2=A0 =C2=A0=3D 0x00590000 DEFINE NUM_BLOCKS=C2=A0 =3D 0x590 !endif -- 2.32.0 --kDzNW6RDakMaOI3cDVRY Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hey Benjamin

The commit has been around for a while now and is p= erfectly functional. Why don't we upstream it and then `FindCbTag()` and `C= opyMem()` can be a follow-up patch when/if time allows?

CheersSean

Squashing that commit in:
[PATCH] UefiPayloadPkg: Add support for logging to CBMEM console
 
Tested on QEMU, dumping the appropriate memory region in UEFI shell
shows the TianoCore log. `find_cb_subtable` is sourced from STM/SeaBIO= S.
 
Signed-off-by: Benjamin Doron <benjamin.doron00@gmail.com>
---
 UefiPayloadPkg/Include/Coreboot.h        &nb= sp;    |  14 +
 .../Library/CbSerialPortLib/CbSerialPortLib.c | 272 ++++++++++++= ++++++
 .../CbSerialPortLib/CbSerialPortLib.inf      &nbs= p;|  27 ++
 UefiPayloadPkg/UefiPayloadPkg.dsc        &nb= sp;    |   5 +
 UefiPayloadPkg/UefiPayloadPkg.fdf        &nb= sp;    |   6 +-
 5 files changed, 323 insertions(+), 1 deletion(-)
 create mode 100644 UefiPayloadPkg/Library/CbSerialPortLib/CbSeri= alPortLib.c
 create mode 100644 UefiPayloadPkg/Library/CbSerialPortLib/CbSeri= alPortLib.inf
 
diff --git a/UefiPayloadPkg/Include/Coreboot.h b/UefiPayloadPkg/Includ= e/Coreboot.h
index a3e1109fe8..f2f577a02e 100644
--- a/UefiPayloadPkg/Include/Coreboot.h
+++ b/UefiPayloadPkg/Include/Coreboot.h
@@ -199,7 +199,14 @@ struct cb_forward {
   UINT64    forward;
 };
 
+struct cb_cbmem_ref {
+  UINT32 tag;
+  UINT32 size;
+  UINT64 cbmem_addr;
+};
+
 #define CB_TAG_FRAMEBUFFER  0x0012
+
 struct cb_framebuffer {
   UINT32    tag;
   UINT32    size;
@@ -230,6 +237,13 @@ struct cb_vdat {
 #define CB_TAG_TIMESTAMPS     0x0016
 #define CB_TAG_CBMEM_CONSOLE  0x0017
 #define CB_TAG_MRC_CACHE      0x0018
+
+struct cbmem_console {
+  UINT32 size;
+  UINT32 cursor;
+  UINT8  body[0];
+} __attribute__((packed));
+
 struct cb_cbmem_tab {
   UINT32    tag;
   UINT32    size;
diff --git a/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.c = b/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.c
new file mode 100644
index 0000000000..7b26c08dd7
--- /dev/null
+++ b/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.c
@@ -0,0 +1,272 @@
+/** @file
+  CBMEM console SerialPortLib instance
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Coreboot.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BlParseLib.h>
+#include <Library/SerialPortLib.h>
+
+//
+// We can't use DebugLib due to a constructor dependency cycle betwee= n DebugLib
+// and ourselves.
+//
+#define ASSERT(Expression)      \
+  do {                &n= bsp;         \
+    if (!(Expression)) {        \
+      CpuDeadLoop ();         = ;  \
+    }               = ;            \
+  } while (FALSE)
+
+#define CBMC_CURSOR_MASK ((1 << 28) - 1)
+#define CBMC_OVERFLOW (1 << 31)
+
+STATIC struct cbmem_console  *gCbConsole =3D NULL;
+STATIC UINT32 STM_cursor =3D 0;
+
+// Try to find the coreboot memory table in the given coreboot table.=
+static void *
+find_cb_subtable(struct cb_header *cbh, UINT32 tag)
+{
+  char *tbl =3D (char *)cbh + sizeof(*cbh);
+  UINT32 count =3D cbh->table_entries;
+  int i;
+  for (i=3D0; i<count; i++) {
+    struct cb_memory *cbm =3D (void*)tbl;
+    tbl +=3D cbm->size;
+    if (cbm->tag =3D=3D tag)
+      return cbm;
+  }
+    return NULL;
+}
+
+/**
+  Initialize the serial device hardware.
+
+  If no initialization is required, then return RETURN_SUCCESS.<= /div>
+  If the serial device was successfully initialized, then return= RETURN_SUCCESS.
+  If the serial device could not be initialized, then return RET= URN_DEVICE_ERROR.
+
+  @retval RETURN_SUCCESS        The serial d= evice was initialized.
+  @retval RETURN_DEVICE_ERROR   The serial device coul= d not be initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+  VOID
+  )
+{
+  /* `FindCbTag` doesn't work because we need direct access to t= he memory addresses? */
+  struct cb_header *cbh =3D GetParameterBase();
+  if (!cbh) {
+    return RETURN_DEVICE_ERROR;
+  }
+
+  struct cb_cbmem_ref *cbref =3D find_cb_subtable(cbh, CB_TAG_CB= MEM_CONSOLE);
+  if (!cbref) {
+    return RETURN_DEVICE_ERROR;
+  }
+
+  gCbConsole =3D (void *)(UINTN)cbref->cbmem_addr; // Support= PEI and DXE
+  if (gCbConsole =3D=3D NULL) {
+    return RETURN_DEVICE_ERROR;
+  }
+
+  // set the cursor such that the STM console will not overwrite= the
+  // coreboot console output
+  STM_cursor =3D gCbConsole->cursor & CBMC_CURSOR_MASK;
+
+  return RETURN_SUCCESS;
+}
+
+/**
+  Write data from buffer to serial device.
+
+  Writes NumberOfBytes data bytes from Buffer to the serial devi= ce.
+  The number of bytes actually written to the serial device is r= eturned.
+  If the return value is less than NumberOfBytes, then the write= operation failed.
+  If Buffer is NULL, then ASSERT().
+  If NumberOfBytes is zero, then return 0.
+
+  @param  Buffer           Po= inter to the data buffer to be written.
+  @param  NumberOfBytes    Number of bytes to wri= tten to the serial device.
+
+  @retval 0              &nbs= p; NumberOfBytes is 0.
+  @retval >0              =  The number of bytes written to the serial device.
+                   =        If this value is less than NumberOfBytes, then = the write operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+  IN UINT8     *Buffer,
+  IN UINTN     NumberOfBytes
+  )
+{
+  UINTN             Sent;
+  UINT32            cursor;
+  UINT32            flags;
+
+  ASSERT (Buffer !=3D NULL);
+
+  if (NumberOfBytes =3D=3D 0) {
+    return 0;
+  }
+
+  if (!gCbConsole) {
+    return 0;
+  }
+
+  Sent =3D 0;
+  do {
+    cursor =3D gCbConsole->cursor & CBMC_CURSOR_MASK= ;
+    flags =3D gCbConsole->cursor & ~CBMC_CURSOR_MASK= ;
+
+    if (cursor >=3D gCbConsole->size) {
+      return 0; // Old coreboot version with legacy ov= erflow mechanism.
+    }
+
+    gCbConsole->body[cursor++] =3D Buffer[Sent++];
+
+    if (cursor >=3D gCbConsole->size) {
+      cursor =3D STM_cursor;
+      flags |=3D CBMC_OVERFLOW;
+    }
+
+    gCbConsole->cursor =3D flags | cursor;
+  } while (Sent < NumberOfBytes);
+
+  return Sent;
+}
+
+/**
+  Read data from serial device and save the datas in buffer.
+
+  Reads NumberOfBytes data bytes from a serial device into the b= uffer
+  specified by Buffer. The number of bytes actually read is retu= rned.
+  If Buffer is NULL, then ASSERT().
+  If NumberOfBytes is zero, then return 0.
+
+  @param  Buffer           Po= inter to the data buffer to store the data read from the serial device.
+  @param  NumberOfBytes    Number of bytes which = will be read.
+
+  @retval 0              &nbs= p; Read data failed, no data is to be read.
+  @retval >0              =  Actual number of bytes read from serial device.
+
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+  OUT UINT8     *Buffer,
+  IN  UINTN     NumberOfBytes
+)
+{
+  return 0;
+}
+
+/**
+  Polls a serial device to see if there is any data waiting to b= e read.
+
+  @retval TRUE             Da= ta is waiting to be read from the serial device.
+  @retval FALSE            There i= s no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+/**
+  Sets the control bits on a serial device.
+
+  @param Control             =   Sets the bits of Control that are settable.
+
+  @retval RETURN_SUCCESS        The new cont= rol bits were set on the serial device.
+  @retval RETURN_UNSUPPORTED    The serial device does= not support this operation.
+  @retval RETURN_DEVICE_ERROR   The serial device is n= ot functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetControl (
+  IN UINT32 Control
+  )
+{
+  return RETURN_UNSUPPORTED;
+}
+
+/**
+  Retrieve the status of the control bits on a serial device.
+
+  @param Control             =   A pointer to return the current control signals from the serial dev= ice.
+
+  @retval RETURN_SUCCESS        The control = bits were read from the serial device.
+  @retval RETURN_UNSUPPORTED    The serial device does= not support this operation.
+  @retval RETURN_DEVICE_ERROR   The serial device is n= ot functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortGetControl (
+  OUT UINT32 *Control
+  )
+{
+  return RETURN_UNSUPPORTED;
+}
+
+/**
+  Sets the baud rate, receive FIFO depth, transmit/receive time = out, parity,
+  data bits, and stop bits on a serial device.
+
+  @param BaudRate           The re= quested baud rate. A BaudRate value of 0 will use the
+                   =         device's default interface speed.
+                   =         On output, the value actually set.
+  @param ReceiveFifoDepth   The requested depth of the= FIFO on the receive side of the
+                   =         serial interface. A ReceiveFifoDepth value of = 0 will use
+                   =         the device's default FIFO depth.
+                   =         On output, the value actually set.
+  @param Timeout            The re= quested time out for a single character in microseconds.
+                   =         This timeout applies to both the transmit and = receive side of the
+                   =         interface. A Timeout value of 0 will use the d= evice's default time
+                   =         out value.
+                   =         On output, the value actually set.
+  @param Parity             T= he type of parity to use on this serial device. A Parity value of
+                   =         DefaultParity will use the device's default pa= rity value.
+                   =         On output, the value actually set.
+  @param DataBits           The nu= mber of data bits to use on the serial device. A DataBits
+                   =         value of 0 will use the device's default data = bit setting.
+                   =         On output, the value actually set.
+  @param StopBits           The nu= mber of stop bits to use on this serial device. A StopBits
+                   =         value of DefaultStopBits will use the device's= default number of
+                   =         stop bits.
+                   =         On output, the value actually set.
+
+  @retval RETURN_SUCCESS           = ; The new attributes were set on the serial device.
+  @retval RETURN_UNSUPPORTED        The seri= al device does not support this operation.
+  @retval RETURN_INVALID_PARAMETER  One or more of the attr= ibutes has an unsupported value.
+  @retval RETURN_DEVICE_ERROR       The seri= al device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetAttributes (
+  IN OUT UINT64             *= BaudRate,
+  IN OUT UINT32             *= ReceiveFifoDepth,
+  IN OUT UINT32             *= Timeout,
+  IN OUT EFI_PARITY_TYPE    *Parity,
+  IN OUT UINT8              *= DataBits,
+  IN OUT EFI_STOP_BITS_TYPE *StopBits
+  )
+{
+  return RETURN_UNSUPPORTED;
+}
diff --git a/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.in= f b/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.inf
new file mode 100644
index 0000000000..37b33c24ad
--- /dev/null
+++ b/UefiPayloadPkg/Library/CbSerialPortLib/CbSerialPortLib.inf
@@ -0,0 +1,27 @@
+## @file
+#  Component description file for CbSerialPortLib module.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION              &n= bsp;     =3D 0x00010005
+  BASE_NAME              &nbs= p;       =3D CbSerialPortLib
+  FILE_GUID              &nbs= p;       =3D 0DB3EF12-1426-4086-B012-113184C4CE11
+  MODULE_TYPE              &n= bsp;     =3D BASE
+  VERSION_STRING             =    =3D 0.5
+  LIBRARY_CLASS              =     =3D SerialPortLib
+  CONSTRUCTOR              &n= bsp;     =3D SerialPortInitialize
+
+[Sources]
+  CbSerialPortLib.c
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  UefiPayloadPkg/UefiPayloadPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BlParseLib
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPa= yloadPkg.dsc
index 3d08edfe31..b3770b9be6 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -33,6 +33,7 @@
   DEFINE UNIVERSAL_PAYLOAD         = ;   =3D FALSE
   DEFINE SECURITY_STUB_ENABLE        &n= bsp;=3D TRUE
   DEFINE SMM_SUPPORT          &nbs= p;       =3D FALSE
+  DEFINE USE_CBMEM_FOR_CONSOLE        =3D FA= LSE
   #
   # SBL:      UEFI payload for Slim Bootload= er
   # COREBOOT: UEFI payload for coreboot
@@ -223,7 +224,11 @@
   TimerLib|UefiPayloadPkg/Library/AcpiTimerLib/AcpiTimerLib= .inf
 !endif
   ResetSystemLib|UefiPayloadPkg/Library/ResetSystemLib/Rese= tSystemLib.inf
+!if $(USE_CBMEM_FOR_CONSOLE) =3D=3D TRUE
+  SerialPortLib|UefiPayloadPkg/Library/CbSerialPortLib/CbSerialP= ortLib.inf
+!else
   SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550= /BaseSerialPortLib16550.inf
+!endif
   PlatformHookLib|UefiPayloadPkg/Library/PlatformHookLib/Pl= atformHookLib.inf
   PlatformBootManagerLib|UefiPayloadPkg/Library/PlatformBoo= tManagerLib/PlatformBootManagerLib.inf
   IoApicLib|PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApic= Lib.inf
diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPa= yloadPkg.fdf
index f619a23139..0df8342252 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.fdf
+++ b/UefiPayloadPkg/UefiPayloadPkg.fdf
@@ -15,8 +15,12 @@ DEFINE FD_BLOCK_SIZE =3D 0x00001000
 !if $(TARGET) =3D=3D "NOOPT"
 DEFINE FD_SIZE     =3D 0x00850000
 DEFINE NUM_BLOCKS  =3D 0x850
-!else
 
+!elseif $(USE_CBMEM_FOR_CONSOLE) =3D=3D TRUE
+DEFINE FD_SIZE     =3D 0x00600000
+DEFINE NUM_BLOCKS  =3D 0x600
+
+!else
 DEFINE FD_SIZE     =3D 0x00590000
 DEFINE NUM_BLOCKS  =3D 0x590
 !endif
-- 
2.32.0
 
--kDzNW6RDakMaOI3cDVRY--