[AMD Official Use Only - General] Hi Nickle, Thanks for catching those issue. I am fixing it now.
There is few feedbacks below, > -----Original Message----- > From: Nickle Wang <nick...@nvidia.com> > Sent: Monday, March 20, 2023 9:32 PM > To: Chang, Abner <abner.ch...@amd.com>; devel@edk2.groups.io > Cc: Liming Gao <gaolim...@byosoft.com.cn>; Isaac Oram > <isaac.w.o...@intel.com>; Nate DeSimone > <nathaniel.l.desim...@intel.com>; Attar, AbdulLateef (Abdul Lateef) > <abdullateef.at...@amd.com>; Igor Kulchytskyy <ig...@ami.com> > Subject: RE: [edk2-platforms][PATCH V2 5/8] > ManageabilityPkg/ManageabilityTransportKcsLib > > Caution: This message originated from an External Source. Use proper > caution when opening attachments, clicking links, or responding. > > > Please see my comments inline below. > > Regards, > Nickle > > -----Original Message----- > From: abner.ch...@amd.com <abner.ch...@amd.com> > Sent: Wednesday, March 8, 2023 10:17 PM > To: devel@edk2.groups.io > Cc: Liming Gao <gaolim...@byosoft.com.cn>; Isaac Oram > <isaac.w.o...@intel.com>; Nate DeSimone > <nathaniel.l.desim...@intel.com>; Abdul Lateef Attar > <abdat...@amd.com>; Nickle Wang <nick...@nvidia.com>; Igor Kulchytskyy > <ig...@ami.com> > Subject: [edk2-platforms][PATCH V2 5/8] > ManageabilityPkg/ManageabilityTransportKcsLib > > External email: Use caution opening links or attachments > > > From: Abner Chang <abner.ch...@amd.com> > > This is the KCS manageability transport library instance follows the design > guidance described in Readme file under ManageabilityPkg. > > Signed-off-by: Abner Chang <abner.ch...@amd.com> > Cc: Liming Gao <gaolim...@byosoft.com.cn> > Cc: Isaac Oram <isaac.w.o...@intel.com> > Cc: Nate DeSimone <nathaniel.l.desim...@intel.com> > Cc: Abdul Lateef Attar <abdat...@amd.com> > Cc: Nickle Wang <nick...@nvidia.com> > Cc: Igor Kulchytskyy <ig...@ami.com> > --- > .../ManageabilityPkg/ManageabilityPkg.dsc | 3 + > .../Dxe/DxeManageabilityTransportKcs.inf | 44 ++ > .../Common/ManageabilityTransportKcs.h | 106 ++++ > .../Common/KcsCommon.c | 480 ++++++++++++++++++ > .../Dxe/ManageabilityTransportKcs.c | 384 ++++++++++++++ > .../Dxe/ManageabilityTransportKcs.uni | 13 + > 6 files changed, 1030 insertions(+) > create mode 100644 > Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/Dxe > ManageabilityTransportKcs.inf > create mode 100644 > Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Common > /ManageabilityTransportKcs.h > create mode 100644 > Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Common > /KcsCommon.c > create mode 100644 > Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/Man > ageabilityTransportKcs.c > create mode 100644 > Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/Man > ageabilityTransportKcs.uni > > diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dsc > b/Features/ManageabilityPkg/ManageabilityPkg.dsc > index 0dd0ab41fc..45e07ac34f 100644 > --- a/Features/ManageabilityPkg/ManageabilityPkg.dsc > +++ b/Features/ManageabilityPkg/ManageabilityPkg.dsc > @@ -36,6 +36,9 @@ > !include MinPlatformPkg/Include/Dsc/CorePeiLib.dsc > !include MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc > > +[Components] > + > +ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/DxeManagea > bil > +ityTransportKcs.inf > + > [LibraryClasses] > > ManageabilityTransportLib|ManageabilityPkg/Library/BaseManageabilityTra > nsportNullLib/BaseManageabilityTransportNull.inf > > diff --git > a/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/Dx > eManageabilityTransportKcs.inf > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/Dx > eManageabilityTransportKcs.inf > new file mode 100644 > index 0000000000..f0a6afa074 > --- /dev/null > +++ > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe > +++ /DxeManageabilityTransportKcs.inf > @@ -0,0 +1,44 @@ > +## @file > +# KCS instance of Manageability Transport Library # # Copyright (C) > +2023 Advanced Micro Devices, Inc. All rights reserved.<BR> # > +SPDX-License-Identifier: BSD-2-Clause-Patent # ## > + > +[Defines] > + INF_VERSION = 0x0001001B > + BASE_NAME = DxeManageabilityTransportKcs > + MODULE_UNI_FILE = ManageabilityTransportKcs.uni > + FILE_GUID = FCCC8B34-145A-4927-9F08-553ADC579AF7 > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = ManageabilityTransportLib > + > +# > +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 > +# > + > +[Sources] > + ManageabilityTransportKcs.c > + ../Common/KcsCommon.c > + ../Common/ManageabilityTransportKcs.h > + > +[Packages] > + ManageabilityPkg/ManageabilityPkg.dec > + MdePkg/MdePkg.dec > + > +[LibraryClasses] > + DebugLib > + IoLib > + TimerLib > + MemoryAllocationLib > + > +[Guids] > + gManageabilityTransportKcsGuid > + gManageabilityProtocolMctpGuid > + gManageabilityProtocolIpmiGuid > + > +[FixedPcd] > + gEfiMdePkgTokenSpaceGuid.PcdIpmiKcsBaseAddress # Used as default > KCS I/O base adddress > + > diff --git > a/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Commo > n/ManageabilityTransportKcs.h > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Comm > on/ManageabilityTransportKcs.h > new file mode 100644 > index 0000000000..d5a16efc81 > --- /dev/null > +++ > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Com > +++ mon/ManageabilityTransportKcs.h > @@ -0,0 +1,106 @@ > +/** @file > + > + Manageability transport KCS internal used definitions. > + > + Copyright (C) 2023 Advanced Micro Devices, Inc. All rights > +reserved.<BR> > + SPDX-License-Identifier: BSD-2-Clause-Patent **/ > + > +#ifndef MANAGEABILITY_TRANSPORT_KCS_LIB_H_ > +#define MANAGEABILITY_TRANSPORT_KCS_LIB_H_ > + > +#include <Library/ManageabilityTransportLib.h> > + > +#define MANAGEABILITY_TRANSPORT_KCS_SIGNATURE SIGNATURE_32 > ('M', 'T', > +'K', 'C') > + > +#define KCS_BASE_ADDRESS mKcsHardwareInfo.IoBaseAddress > +#define KCS_REG_DATA_IN mKcsHardwareInfo.IoDataInAddress > +#define KCS_REG_DATA_OUT mKcsHardwareInfo.IoDataOutAddress > +#define KCS_REG_COMMAND mKcsHardwareInfo.IoCommandAddress > +#define KCS_REG_STATUS mKcsHardwareInfo.IoStatusAddress > + > +/// > +/// Manageability transport KCS internal data structure. > +/// > +typedef struct { > + UINTN Signature; > + MANAGEABILITY_TRANSPORT_TOKEN Token; > +} MANAGEABILITY_TRANSPORT_KCS; > + > +#define MANAGEABILITY_TRANSPORT_KCS_FROM_LINK(a) CR (a, > +MANAGEABILITY_TRANSPORT_KCS, Token, > +MANAGEABILITY_TRANSPORT_KCS_SIGNATURE) > + > +#define IPMI_KCS_GET_STATE(s) (s >> 6) #define IPMI_KCS_SET_STATE(s) > +(s << 6) > + > +/// 5 sec, according to IPMI spec > +#define IPMI_KCS_TIMEOUT_5_SEC 5000*1000 > +#define IPMI_KCS_TIMEOUT_1MS 1000 > + > +/** > + This service communicates with BMC using KCS protocol. > + > + @param[in] NetFunction Net function of the command. > + @param[in] Command IPMI Command. > + @param[in] RequestData Command Request Data. > + @param[in] RequestDataSize Size of Command Request Data. > + @param[out] ResponseData Command Response Data. The > completion > + code is the first byte of response > + data. > + @param[in, out] ResponseDataSize Size of Command Response Data. > + > + @retval EFI_SUCCESS The command byte stream was > + successfully submit to the device > and a > + response was successfully received. > + @retval EFI_NOT_FOUND The command was not successfully sent > + to the device or a response was not > + successfully received from the > device. > + @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi > + command access. > + @retval EFI_DEVICE_ERROR Ipmi Device hardware error. > + @retval EFI_TIMEOUT The command time out. > + @retval EFI_UNSUPPORTED The command was not successfully > sent to > + the device. > + @retval EFI_OUT_OF_RESOURCES The resource allocation is out of > + resource or data size error. > +**/ > + > +EFI_STATUS > +EFIAPI > +KcsTransportSendCommand ( > + IN UINT8 NetFunction, > + IN UINT8 Command, > + IN UINT8 *RequestData, > + IN UINT32 RequestDataSize, > + OUT UINT8 *ResponseData, > + IN OUT UINT32 *ResponseDataSize > + ); > + > +/** > + This function reads 8-bit value from register address. > + > + @param[in] Address This represents either 16-bit IO > address > + or 32-bit memory mapped address. > + > + @retval UINT8 8-bit value. > +**/ > +UINT8 > +KcsRegisterRead8 ( > + MANAGEABILITY_TRANSPORT_HARDWARE_IO Address > + ); > + > +/** > + This function writes 8-bit value to register address. > + > + @param[in] Address This represents either 16-bit IO > address > + or 32-bit memory mapped address. > + @param[in] Value 8-bit value write to register address > + > + @retval UINT8 8-bit value. > > This is VOID function so there is no return value here. > > +**/ > +VOID > +KcsRegisterWrite8 ( > + MANAGEABILITY_TRANSPORT_HARDWARE_IO Address, > + UINT8 Value > + ); > + > +#endif > diff --git > a/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Commo > n/KcsCommon.c > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Comm > on/KcsCommon.c > new file mode 100644 > index 0000000000..ff20f4a18e > --- /dev/null > +++ > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Com > +++ mon/KcsCommon.c > @@ -0,0 +1,480 @@ > +/** @file > + > + KCS instance of Manageability Transport Library > + > + Copyright (C) 2023 Advanced Micro Devices, Inc. All rights > + reserved.<BR> > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > +#include <Uefi.h> > +#include <IndustryStandard/IpmiKcs.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/IoLib.h> > +#include <Library/DebugLib.h> > +#include <Library/MemoryAllocationLib.h> #include <Library/TimerLib.h> > + > +#include "ManageabilityTransportKcs.h" > + > +extern MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO > mKcsHardwareInfo; > + > +/** > + This function waits for parameter Flag to set. > + Checks status flag in every 1ms internal till 5 seconds elapses. > + > + @param[in] Flag KCS Flag to test. > + @retval EFI_SUCCESS The KCS flag under test is set. > + @retval EFI_TIMEOUT The KCS flag didn't set in 5 second windows. > +**/ > +EFI_STATUS > +WaitStatusSet ( > + IN UINT8 Flag > + ) > +{ > + UINT64 Timeout = 0; > + > + while (!(KcsRegisterRead8 (KCS_REG_STATUS) & Flag)) { > + MicroSecondDelay (IPMI_KCS_TIMEOUT_1MS); > + Timeout = Timeout + IPMI_KCS_TIMEOUT_1MS; > + if (Timeout >= IPMI_KCS_TIMEOUT_5_SEC) { > + return EFI_TIMEOUT; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function waits for parameter Flag to get cleared. > + Checks status flag in every 1ms internal till 5 seconds elapses. > + > + @param[in] Flag KCS Flag to test. > + > + @retval EFI_SUCCESS The KCS flag under test is clear. > + @retval EFI_TIMEOUT The KCS flag didn't cleared in 5 second windows. > +**/ > +EFI_STATUS > +WaitStatusClear ( > + IN UINT8 Flag > + ) > +{ > + UINT64 Timeout = 0; > + > + while (KcsRegisterRead8 (KCS_REG_STATUS) & Flag) { > + MicroSecondDelay (IPMI_KCS_TIMEOUT_1MS); > + Timeout = Timeout + IPMI_KCS_TIMEOUT_1MS; > + if (Timeout >= IPMI_KCS_TIMEOUT_5_SEC) { > + return EFI_TIMEOUT; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function validates KCS OBF bit. > + Checks whether OBF bit is set or not. > + > + @retval EFI_SUCCESS OBF bit is set. > + @retval EFI_NOT_READY OBF bit is not set. > +**/ > +EFI_STATUS > +ClearOBF ( > + VOID > + ) > +{ > + if (KcsRegisterRead8 (KCS_REG_STATUS) & IPMI_KCS_OBF) { > + KcsRegisterRead8 (KCS_REG_DATA_IN); // read the data to clear the OBF > + if (KcsRegisterRead8 (KCS_REG_STATUS) & IPMI_KCS_OBF) { > + return EFI_NOT_READY; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function writes/sends data to the KCS port. > + Algorithm is based on flow chart provided in IPMI spec 2.0 > + Figure 9-6, KCS Interface BMC to SMS Write Transfer Flow Chart > + > + @param[in] NetFunction Net function of the command. > + @param[in] Command IPMI Command. > + @param[in] RequestData Command Request Data. > + @param[in] RequestDataSize Size of Command Request Data. > + > + @retval EFI_SUCCESS The command byte stream was successfully > + submit to the device and a response was > + successfully received. > + @retval EFI_NOT_FOUND The command was not successfully sent to > the > + device or a response was not successfully > + received from the device. > + @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command > + access. > + @retval EFI_DEVICE_ERROR Ipmi Device hardware error. > + @retval EFI_TIMEOUT The command time out. > + @retval EFI_UNSUPPORTED The command was not successfully sent > to > + the device. > + @retval EFI_OUT_OF_RESOURCES The resource allocation is out of > resource or > + data size error. > +**/ > +EFI_STATUS > +KcsTransportWrite ( > + IN UINT8 NetFunction, > + IN UINT8 Command, > + IN UINT8 *RequestData, > + IN UINT32 RequestDataSize > + ) > > It looks like the RequestData can be NULL. If it is, we can add "OPTIONAL" > above. > > We can also check to see if RequestDataSize is not 0 when RequestData is > not NULL. > > +{ > + EFI_STATUS Status; > + UINT32 Length; > + UINT8 *Buffer; > + UINT8 *BufferPtr; > + > + Length = sizeof (NetFunction) + sizeof (Command); if (RequestData != > + NULL) { > + Length = Length + RequestDataSize; > + } > + > + Buffer = AllocateZeroPool (Length); > + if (Buffer == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Buffer[0] = NetFunction > + // Buffer[1] = Command > + // Buffer [2..RequestDataSize] = RequestData // BufferPtr = Buffer; > + CopyMem (BufferPtr, &NetFunction, sizeof (NetFunction)); BufferPtr += > + sizeof (NetFunction); CopyMem (BufferPtr, &Command, sizeof > + (Command)); BufferPtr += sizeof (Command); if (Length > (sizeof > + (NetFunction) + sizeof (Command))) { > + CopyMem (BufferPtr, RequestData, RequestDataSize); } > + > + BufferPtr = Buffer; > + > + // Step 1. wait for IBF to get clear > + Status = WaitStatusClear (IPMI_KCS_IBF); if (EFI_ERROR (Status)) { > + FreePool (Buffer); > + return Status; > + } > + > + // Step 2. clear OBF > + if (EFI_ERROR (ClearOBF ())) { > + FreePool (Buffer); > + return EFI_NOT_READY; > + } > + > + // Step 3. WR_START to CMD, phase=wr_start > + KcsRegisterWrite8 (KCS_REG_COMMAND, > + IPMI_KCS_CONTROL_CODE_WRITE_START); > + > + // Step 4. wait for IBF to get clear > + Status = WaitStatusClear (IPMI_KCS_IBF); if (EFI_ERROR (Status)) { > + FreePool (Buffer); > + return Status; > + } > + > + // Step 5. check state it should be WRITE_STATE, else exit with error > + if (IPMI_KCS_GET_STATE (KcsRegisterRead8 (KCS_REG_STATUS)) != > IPMI_KCS_WRITE_STATE) { > + FreePool (Buffer); > + return EFI_NOT_READY; > + } > + > + // Step 6, Clear OBF > + if (EFI_ERROR (ClearOBF ())) { > + FreePool (Buffer); > + return EFI_NOT_READY; > + } > + > + while (Length > 1) { > + // Step 7, phase wr_data, write one byte of Data > + KcsRegisterWrite8 (KCS_REG_DATA_OUT, *BufferPtr); > + Length--; > + BufferPtr++; > + > + // Step 8. wait for IBF clear > + Status = WaitStatusClear (IPMI_KCS_IBF); > + if (EFI_ERROR (Status)) { > + FreePool (Buffer); > + return Status; > + } > + > + // Step 9. check state it should be WRITE_STATE, else exit with error > + if (IPMI_KCS_GET_STATE (KcsRegisterRead8 (KCS_REG_STATUS)) != > IPMI_KCS_WRITE_STATE) { > + FreePool (Buffer); > + return EFI_NOT_READY; > + } > + > + // Step 10 > + if (EFI_ERROR (ClearOBF ())) { > + FreePool (Buffer); > + return EFI_NOT_READY; > + } > + > + // > + // Step 11, check for DATA completion if more than one byte; > + // if still need to be transferred then go to step 7 and repeat > + // > + } > + > + // Step 12, WR_END to CMD > + KcsRegisterWrite8 (KCS_REG_COMMAND, > IPMI_KCS_CONTROL_CODE_WRITE_END); > + > + // Step 13. wait for IBF to get clear Status = WaitStatusClear > + (IPMI_KCS_IBF); if (EFI_ERROR (Status)) { > + FreePool (Buffer); > + return Status; > + } > + > + // Step 14. check state it should be WRITE_STATE, else exit with > + error if (IPMI_KCS_GET_STATE (KcsRegisterRead8 (KCS_REG_STATUS)) != > IPMI_KCS_WRITE_STATE) { > + FreePool (Buffer); > + return EFI_NOT_READY; > + } > + > + // Step 15 > + if (EFI_ERROR (ClearOBF ())) { > + FreePool (Buffer); > + return EFI_NOT_READY; > + } > + > + // Step 16, write the last byte > + KcsRegisterWrite8 (KCS_REG_DATA_OUT, *BufferPtr); > + FreePool (Buffer); > + return EFI_SUCCESS; > +} > + > +/** > + This function sends/receives data from KCS port. > + Algorithm is based on flow chart provided in IPMI spec 2.0 > + Figure 9-7, KCS Interface BMC to SMS Read Transfer Flow Chart > + > + @param [in] DataBytes Buffer to hold the read Data. > + @param [in, out] Length Number of Bytes read from KCS port. > + @retval EFI_SUCCESS The command byte stream was > + successfully submit to the device > and > + a response was successfully > received. > + @retval EFI_NOT_FOUND The command was not successfully > sent > + to the device or a response was not > + successfully received from the > + device. > + @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi > + command access. > + @retval EFI_DEVICE_ERROR Ipmi Device hardware error. > + @retval EFI_TIMEOUT The command time out. > + @retval EFI_UNSUPPORTED The command was not successfully > set > + to the device. > + @retval EFI_OUT_OF_RESOURCES The resource allocation is out of > + resource or data size error. > +**/ > +EFI_STATUS > +KcsTransportRead ( > + OUT UINT8 *DataByte, > + IN OUT UINT32 *Length > + ) > +{ > + EFI_STATUS Status; > + UINT32 ReadLength; > > It would be good if we check and see if input pointer is NULL or not. If it > is, > return EFI_INVALID_PARAMETER back to caller. > > + > + ReadLength = 0; > + while (ReadLength < *Length) { > + // Step 1. wait for IBF to get clear > + Status = WaitStatusClear (IPMI_KCS_IBF); > + if (EFI_ERROR (Status)) { > + *Length = ReadLength; > + return Status; > + } > + > + // Step 2. check state it should be READ_STATE, else exit with error > + if (IPMI_KCS_GET_STATE (KcsRegisterRead8 (KCS_REG_STATUS)) == > IPMI_KCS_READ_STATE) { > + // Step 2.1.1 check of OBF to get clear > + Status = WaitStatusSet (IPMI_KCS_OBF); > + if (EFI_ERROR (Status)) { > + *Length = ReadLength; > + return Status; > + } > + > + // Step 2.1.2 read data from data out > + DataByte[ReadLength++] = KcsRegisterRead8 (KCS_REG_DATA_IN); > + Status = WaitStatusClear (IPMI_KCS_IBF); > + if (EFI_ERROR (Status)) { > + *Length = ReadLength; > + return Status; > + } > + > + // Step 2.1.3 Write READ byte to data in register. > + KcsRegisterWrite8 (KCS_REG_DATA_OUT, > IPMI_KCS_CONTROL_CODE_READ); > + } else if (IPMI_KCS_GET_STATE (KcsRegisterRead8 (KCS_REG_STATUS)) > == IPMI_KCS_IDLE_STATE) { > + // Step 2.2.1 > + Status = WaitStatusSet (IPMI_KCS_OBF); > + if (EFI_ERROR (Status)) { > + *Length = ReadLength; > + return Status; > + } > + > + // Step 2.2.2 read dummy data > + KcsRegisterRead8 (KCS_REG_DATA_IN); // Dummy read as per IPMI > spec > + *Length = ReadLength; > + return EFI_SUCCESS; > + } else { > + *Length = ReadLength; > + return EFI_DEVICE_ERROR; > + } > + } > + > + *Length = ReadLength; > + return EFI_SUCCESS; > +} > + > +/** > + This service communicates with BMC using KCS protocol. > + > + @param[in] NetFunction Net function of the command. > + @param[in] Command IPMI Command. > + @param[in] RequestData Command Request Data. > + @param[in] RequestDataSize Size of Command Request Data. > + @param[out] ResponseData Command Response Data. The > completion > + code is the first byte of response > + data. > + @param[in, out] ResponseDataSize Size of Command Response Data. > + > + @retval EFI_SUCCESS The command byte stream was > + successfully submit to the device > and a > + response was successfully received. > + @retval EFI_NOT_FOUND The command was not successfully sent > + to the device or a response was not > + successfully received from the > device. > + @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi > + command access. > + @retval EFI_DEVICE_ERROR Ipmi Device hardware error. > + @retval EFI_TIMEOUT The command time out. > + @retval EFI_UNSUPPORTED The command was not successfully > sent to > + the device. > + @retval EFI_OUT_OF_RESOURCES The resource allocation is out of > + resource or data size error. > +**/ > +EFI_STATUS > +EFIAPI > +KcsTransportSendCommand ( > + IN UINT8 NetFunction, > + IN UINT8 Command, > + IN UINT8 *RequestData, > + IN UINT32 RequestDataSize, > + OUT UINT8 *ResponseData, > + IN OUT UINT32 *ResponseDataSize > > Form the function header, this is just OUT, right? ResponseDataSize is in and out. I will also add more descriptions in function header. > + ) > +{ > + EFI_STATUS Status; > + UINT32 RspHeaderSize; > + IPMI_KCS_RESPONSE_HEADER RspHeader; > + > + if ((RequestData != NULL) && (RequestDataSize <= 0)) { > + return EFI_INVALID_PARAMETER; > + } > > Do we need similar check to ResponseData and ResponseDataSize? Yes, I also add OPTIONAL to those parameters in function prototype. Thanks Abner > > + > + Status = KcsTransportWrite ( > + (NetFunction << 2), > + Command, > + RequestData, > + RequestDataSize > + ); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "IPMI KCS Write Failed with Status(%r) for NetFunction(0x%x)," \ > + " Command(0x%x).\n", > + Status, > + NetFunction, > + Command > + )); > + return Status; > + } > + > + // > + // Read the response header > + RspHeaderSize = sizeof (IPMI_KCS_RESPONSE_HEADER); > + Status = KcsTransportRead ((UINT8 *)&RspHeader, &RspHeaderSize); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "IPMI KCS read response header failed Status(%r), " \ > + "RspNetFunctionLun = 0x%x, " \ > + "Comamnd = 0x%x \n", > + Status, > + RspHeader.NetFunc, > + RspHeader.Command > + )); > + return (Status); > + } > + > + Status = KcsTransportRead ((UINT8 *)ResponseData, ResponseDataSize); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "IPMI KCS response read Failed with Status(%r) for NetFunction(0x%x)," > \ > + " Command(0x%x).\n", > + Status, > + NetFunction, > + Command > + )); > + } > + > + return Status; > +} > + > +/** > + This function reads 8-bit value from register address. > + > + @param[in] Address This represents either 16-bit IO > address > + or 32-bit memory mapped address. > + > + @retval UINT8 8-bit value. > +**/ > +UINT8 > +KcsRegisterRead8 ( > + MANAGEABILITY_TRANSPORT_HARDWARE_IO Address > + ) > +{ > + UINT8 Value; > + > + if (mKcsHardwareInfo.MemoryMap == > MANAGEABILITY_TRANSPORT_KCS_MEMORY_MAP_IO) { > + // Read 8-bit value from 32-bit Memory mapped address. > + Value = MmioRead8 ((UINTN)Address.IoAddress32); } else { > + // Read 8-bit value from 16-bit I/O address > + Value = IoRead8 ((UINTN)Address.IoAddress16); } > + > + return Value; > +} > + > +/** > + This function writes 8-bit value to register address. > + > + @param[in] Address This represents either 16-bit IO > address > + or 32-bit memory mapped address. > + @param[in] Value 8-bit value write to register address > + > + @retval UINT8 8-bit value. > +**/ > +VOID > +KcsRegisterWrite8 ( > + MANAGEABILITY_TRANSPORT_HARDWARE_IO Address, > + UINT8 Value > + ) > +{ > + if (mKcsHardwareInfo.MemoryMap == > MANAGEABILITY_TRANSPORT_KCS_MEMORY_MAP_IO) { > + // Write 8-bit value to 32-bit Memory mapped address. > + MmioWrite8 ((UINTN)Address.IoAddress32, Value); > + } else { > + // Write 8-bit value to 16-bit I/O address > + IoWrite8 ((UINTN)Address.IoAddress16, Value); > + } > +} > diff --git > a/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/M > anageabilityTransportKcs.c > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/M > anageabilityTransportKcs.c > new file mode 100644 > index 0000000000..7eb39ddc7a > --- /dev/null > +++ > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe > +++ /ManageabilityTransportKcs.c > @@ -0,0 +1,384 @@ > +/** @file > + > + KCS instance of Manageability Transport Library > + > + Copyright (C) 2023 Advanced Micro Devices, Inc. All rights > + reserved.<BR> > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +*/ > + > +#include <Uefi.h> > +#include <IndustryStandard/IpmiKcs.h> > +#include <Library/IoLib.h> > +#include <Library/DebugLib.h> > +#include <Library/MemoryAllocationLib.h> #include > +<Library/ManageabilityTransportLib.h> > +#include <Library/ManageabilityTransportIpmiLib.h> > +#include <Library/ManageabilityTransportHelperLib.h> > + > +#include "ManageabilityTransportKcs.h" > + > +MANAGEABILITY_TRANSPORT_KCS *mSingleSessionToken = NULL; > + > +EFI_GUID *SupportedManageabilityProtocol[] = { > + &gManageabilityProtocolIpmiGuid, > + &gManageabilityProtocolMctpGuid > +}; > + > +UINT8 NumberOfSupportedProtocol = (sizeof > +(SupportedManageabilityProtocol)/sizeof (EFI_GUID *)); > + > +MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO mKcsHardwareInfo; > + > +/** > + This function initializes the transport interface. > + > + @param [in] TransportToken The transport token acquired through > + AcquireTransportSession function. > + @param [in] HardwareInfo The hardware information > + assigned to KCS transport interface. > + > + @retval EFI_SUCCESS Transport interface is initialized > + successfully. > + @retval EFI_INVALID_PARAMETER The invalid transport token. > + @retval EFI_NOT_READY The transport interface works fine > but > + @retval is not ready. > + @retval EFI_DEVICE_ERROR The transport interface has problems. > + @retval EFI_ALREADY_STARTED Teh protocol interface has already > initialized. > + @retval Otherwise Other errors. > + > +**/ > +EFI_STATUS > +EFIAPI > +KcsTransportInit ( > + IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, > + IN MANAGEABILITY_TRANSPORT_HARDWARE_INFORMATION > HardwareInfo > +OPTIONAL > + ) > +{ > + CHAR16 *ManageabilityProtocolName; > + > + if (TransportToken == NULL) { > + DEBUG ((DEBUG_ERROR, "%a: Invalid transport token.\n", > __FUNCTION__)); > + return EFI_INVALID_PARAMETER; > + } > + > + if (HardwareInfo.Kcs == NULL) { > + DEBUG ((DEBUG_INFO, "%a: Hardware information is not provided, use > dfault settings.\n", __FUNCTION__)); > + mKcsHardwareInfo.MemoryMap = > MANAGEABILITY_TRANSPORT_KCS_IO_MAP_IO; > + mKcsHardwareInfo.IoBaseAddress.IoAddress16 = PcdGet16 > (PcdIpmiKcsBaseAddress); > + mKcsHardwareInfo.IoDataInAddress.IoAddress16 = > mKcsHardwareInfo.IoBaseAddress.IoAddress16 + > IPMI_KCS_DATA_IN_REGISTER_OFFSET; > + mKcsHardwareInfo.IoDataOutAddress.IoAddress16 = > mKcsHardwareInfo.IoBaseAddress.IoAddress16 + > IPMI_KCS_DATA_OUT_REGISTER_OFFSET; > + mKcsHardwareInfo.IoCommandAddress.IoAddress16 = > mKcsHardwareInfo.IoBaseAddress.IoAddress16 + > IPMI_KCS_COMMAND_REGISTER_OFFSET; > + mKcsHardwareInfo.IoStatusAddress.IoAddress16 = > + mKcsHardwareInfo.IoBaseAddress.IoAddress16 + > IPMI_KCS_STATUS_REGISTER_OFFSET; } else { > + mKcsHardwareInfo.MemoryMap = > ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO > *)HardwareInfo.Kcs)->MemoryMap; > + mKcsHardwareInfo.IoBaseAddress = > ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO > *)HardwareInfo.Kcs)->IoBaseAddress; > + mKcsHardwareInfo.IoDataInAddress = > ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO > *)HardwareInfo.Kcs)->IoDataInAddress; > + mKcsHardwareInfo.IoDataOutAddress = > ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO > *)HardwareInfo.Kcs)->IoDataOutAddress; > + mKcsHardwareInfo.IoCommandAddress = > ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO > *)HardwareInfo.Kcs)->IoCommandAddress; > + mKcsHardwareInfo.IoStatusAddress = > + ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO > + *)HardwareInfo.Kcs)->IoStatusAddress; > + } > + > + // Get protocol specification name. > + ManageabilityProtocolName = HelperManageabilitySpecName > + (TransportToken->ManageabilityProtocolSpecification); > + > + DEBUG ((DEBUG_INFO, "%a: KCS transport hardware for %s is:\n", > + __FUNCTION__, ManageabilityProtocolName)); if > (mKcsHardwareInfo.MemoryMap) { > + DEBUG ((DEBUG_INFO, "Memory Map I/O\n", __FUNCTION__)); > + DEBUG ((DEBUG_INFO, "Base Memory Address : 0x%08x\n", > mKcsHardwareInfo.IoBaseAddress.IoAddress32)); > + DEBUG ((DEBUG_INFO, "Data in Address : 0x%08x\n", > mKcsHardwareInfo.IoDataInAddress.IoAddress32)); > + DEBUG ((DEBUG_INFO, "Data out Address : 0x%08x\n", > mKcsHardwareInfo.IoDataOutAddress.IoAddress32)); > + DEBUG ((DEBUG_INFO, "Command Address : 0x%08x\n", > mKcsHardwareInfo.IoCommandAddress.IoAddress32)); > + DEBUG ((DEBUG_INFO, "Status Address : 0x%08x\n", > mKcsHardwareInfo.IoStatusAddress.IoAddress32)); > + } else { > + DEBUG ((DEBUG_INFO, "I/O Map I/O\n")); > + DEBUG ((DEBUG_INFO, "Base I/O port : 0x%04x\n", > mKcsHardwareInfo.IoBaseAddress.IoAddress16)); > + DEBUG ((DEBUG_INFO, "Data in I/O port : 0x%04x\n", > mKcsHardwareInfo.IoDataInAddress.IoAddress16)); > + DEBUG ((DEBUG_INFO, "Data out I/O port: 0x%04x\n", > mKcsHardwareInfo.IoDataOutAddress.IoAddress16)); > + DEBUG ((DEBUG_INFO, "Command I/O port : 0x%04x\n", > mKcsHardwareInfo.IoCommandAddress.IoAddress16)); > + DEBUG ((DEBUG_INFO, "Status I/O port : 0x%04x\n", > + mKcsHardwareInfo.IoStatusAddress.IoAddress16)); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function returns the transport interface status. > + The generic EFI_STATUS is returned to caller directly, The additional > + information of transport interface could be optionally returned in > + TransportAdditionalStatus to describes the status that can't be > + described obviously through EFI_STATUS. > + See the definition of MANAGEABILITY_TRANSPORT_STATUS. > + > + @param [in] TransportToken The transport token acquired > through > + AcquireTransportSession function. > + @param [out] TransportAdditionalStatus The additional status of > transport > + interface. > + NULL means no additional status > of this > + transport interface. > + > + @retval EFI_SUCCESS Transport interface status is > returned. > + @retval EFI_INVALID_PARAMETER The invalid transport token. > + @retval EFI_DEVICE_ERROR The transport interface has problems > to > return > + @retval EFI_UNSUPPORTED The transport interface doesn't have > status report. > + Otherwise Other errors. > + > +**/ > +EFI_STATUS > +EFIAPI > +KcsTransportStatus ( > + IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, > + OUT MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS > +*TransportAdditionalStatus OPTIONAL > + ) > +{ > + UINT8 TransportStatus; > + > + if (TransportToken == NULL) { > + DEBUG ((DEBUG_ERROR, "%a: Invalid transport token.\n", > __FUNCTION__)); > + return EFI_INVALID_PARAMETER; > + } > + > + if (TransportAdditionalStatus == NULL) { > + return EFI_SUCCESS; > + } > + > + TransportStatus = IPMI_KCS_GET_STATE (KcsRegisterRead8 > (KCS_REG_STATUS)); > + *TransportAdditionalStatus = > + MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS_NO_ERRORS; > > TransportAdditionalStatus can be NULL. This may create CPU assertion. We checked if TransportAdditionalStatus==NULL in few lines above. Thanks Abner > > + if (TransportStatus != IPMI_KCS_IDLE_STATE) { > + if (TransportStatus == IPMI_KCS_READ_STATE) { > + // > + // Transport is in read state. > + *TransportAdditionalStatus |= > MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS_BUSY_IN_READ; > + return EFI_NOT_READY; > + } else if (TransportStatus == IPMI_KCS_WRITE_STATE) { > + // > + // Transport is in read state. > + *TransportAdditionalStatus |= > MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS_BUSY_IN_WRITE; > + return EFI_NOT_READY; > + } else { > + return EFI_DEVICE_ERROR; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This function resets the transport interface. > + The generic EFI_STATUS is returned to caller directly after reseting > +transport > + interface. The additional information of transport interface could be > +optionally > + returned in TransportAdditionalStatus to describes the status that > +can't be > + described obviously through EFI_STATUS. > + See the definition of MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS. > + > + @param [in] TransportToken The transport token acquired > through > + AcquireTransportSession function. > + @param [out] TransportAdditionalStatus The additional status of specific > transport > + interface after the reset. > + NULL means no additional status > of this > + transport interface. > + > + @retval EFI_SUCCESS Transport interface status is > returned. > + @retval EFI_INVALID_PARAMETER The invalid transport token. > + @retval EFI_TIMEOUT The reset process is time out. > + @retval EFI_DEVICE_ERROR The transport interface has problems > to > return > + status. > + Otherwise Other errors. > + > +**/ > +EFI_STATUS > +EFIAPI > +KcsTransportReset ( > + IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, > + OUT MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS > +*TransportAdditionalStatus OPTIONAL > + ) > +{ > + return EFI_UNSUPPORTED; > +} > + > +/** > + This function transmit the request over target transport interface. > + The generic EFI_STATUS is returned to caller directly after reseting > +transport > + interface. The additional information of transport interface could be > +optionally > + returned in TransportAdditionalStatus to describes the status that > +can't be > + described obviously through EFI_STATUS. > + See the definition of MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS. > + > + @param [in] TransportToken The transport token acquired through > + AcquireTransportSession function. > + @param [in] TransferToken The transfer token, see the > definition of > + MANAGEABILITY_TRANSFER_TOKEN. > + > + @retval The EFI status is returned in > MANAGEABILITY_TRANSFER_TOKEN. > + > +**/ > +VOID > +EFIAPI > +KcsTransportTransmitReceive ( > + IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, > + IN MANAGEABILITY_TRANSFER_TOKEN *TransferToken > + ) > +{ > + EFI_STATUS Status; > + MANAGEABILITY_IPMI_TRANSPORT_HEADER *TransmitHeader; > + > + if (TransportToken == NULL) { > + DEBUG ((DEBUG_ERROR, "%a: Invalid transport token.\n", > __FUNCTION__)); > + return; > + } > > We need same check to TransferToken. > > + > + TransmitHeader = (MANAGEABILITY_IPMI_TRANSPORT_HEADER > + *)TransferToken->TransmitHeader; if (TransmitHeader == NULL) { > + TransferToken->TransferStatus = EFI_INVALID_PARAMETER; > + return; > + } > + > + Status = KcsTransportSendCommand ( > + TransmitHeader->NetFn, > + TransmitHeader->Command, > + TransferToken->TransmitPackage.TransmitPayload, > + TransferToken->TransmitPackage.TransmitSizeInByte, > + TransferToken->ReceivePackage.ReceiveBuffer, > + &TransferToken->ReceivePackage.ReceiveSizeInByte > + ); > + > + TransferToken->TransferStatus = Status; > + KcsTransportStatus (TransportToken, > +&TransferToken->TransportAdditionalStatus); > +} > + > +/** > + This function acquires to create a transport session to transmit > +manageability > + packet. A transport token is returned to caller for the follow up > operations. > + > + @param [in] ManageabilityProtocolSpec The protocol spec the transport > interface is acquired. > + @param [out] TransportToken The pointer to receive the > transport > token created by > + the target transport interface > library. > + @retval EFI_SUCCESS Token is created successfully. > + @retval EFI_OUT_OF_RESOURCES Out of resource to create a new > transport session. > + @retval EFI_UNSUPPORTED Protocol is not supported on this > transport interface. > + @retval Otherwise Other errors. > + > +**/ > +EFI_STATUS > +AcquireTransportSession ( > + IN EFI_GUID *ManageabilityProtocolSpec, > + OUT MANAGEABILITY_TRANSPORT_TOKEN **TransportToken > + ) > +{ > + EFI_STATUS Status; > + MANAGEABILITY_TRANSPORT_KCS *KcsTransportToken; > + > + if (ManageabilityProtocolSpec == NULL) { > + DEBUG ((DEBUG_ERROR, "%a: No Manageability protocol specification > specified.\n", __FUNCTION__)); > + return EFI_INVALID_PARAMETER; > + } > > Please also check TransportToken pointer. > > + > + Status = HelperManageabilityCheckSupportedSpec ( > + &gManageabilityTransportKcsGuid, > + SupportedManageabilityProtocol, > + NumberOfSupportedProtocol, > + ManageabilityProtocolSpec > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a: Protocol is not supported on this transport > interface.\n", __FUNCTION__)); > + return EFI_UNSUPPORTED; > + } > + > + if (mSingleSessionToken != NULL) { > + DEBUG ((DEBUG_ERROR, "%a: This manageability transport library only > supports one session transport token.\n", __FUNCTION__)); > + return EFI_OUT_OF_RESOURCES; > + } > + > + KcsTransportToken = AllocateZeroPool (sizeof > + (MANAGEABILITY_TRANSPORT_KCS)); if (KcsTransportToken == NULL) { > + DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for > MANAGEABILITY_TRANSPORT_KCS\n", __FUNCTION__)); > + return EFI_OUT_OF_RESOURCES; > + } > + KcsTransportToken->Token.Transport = AllocateZeroPool (sizeof > + (MANAGEABILITY_TRANSPORT)); if (KcsTransportToken->Token.Transport > == NULL) { > + FreePool (KcsTransportToken); > + DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for > MANAGEABILITY_TRANSPORT\n", __FUNCTION__)); > + return EFI_OUT_OF_RESOURCES; > + } > + > + KcsTransportToken->Signature = > MANAGEABILITY_TRANSPORT_KCS_SIGNATURE; > + KcsTransportToken->Token.ManageabilityProtocolSpecification = > ManageabilityProtocolSpec; > + KcsTransportToken->Token.Transport->TransportVersion = > MANAGEABILITY_TRANSPORT_TOKEN_VERSION; > + KcsTransportToken->Token.Transport- > >ManageabilityTransportSpecification = &gManageabilityTransportKcsGuid; > + KcsTransportToken->Token.Transport->TransportName = > L"KCS"; > + KcsTransportToken->Token.Transport->Function.Version1_0 = > AllocateZeroPool (sizeof (MANAGEABILITY_TRANSPORT_FUNCTION_V1_0)); > + if (KcsTransportToken->Token.Transport->Function.Version1_0 == NULL) { > + DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for > MANAGEABILITY_TRANSPORT_FUNCTION_V1_0\n", __FUNCTION__)); > + FreePool (KcsTransportToken); > + FreePool (KcsTransportToken->Token.Transport); > + return EFI_OUT_OF_RESOURCES; > + } > + > + KcsTransportToken->Token.Transport->Function.Version1_0- > >TransportInit = KcsTransportInit; > + KcsTransportToken->Token.Transport->Function.Version1_0- > >TransportReset = KcsTransportReset; > + KcsTransportToken->Token.Transport->Function.Version1_0- > >TransportStatus = KcsTransportStatus; > + > + KcsTransportToken->Token.Transport->Function.Version1_0- > >TransportTran > + smitReceive = KcsTransportTransmitReceive; > + > + mSingleSessionToken = KcsTransportToken; > + *TransportToken = &KcsTransportToken->Token; > + return EFI_SUCCESS; > +} > + > +/** > + This function returns the transport capabilities. > + > + @param [out] TransportFeature Pointer to receive transport > capabilities. > + See the definitions of > + MANAGEABILITY_TRANSPORT_CAPABILITY. > + > +**/ > +VOID > +GetTransportCapability ( > + OUT MANAGEABILITY_TRANSPORT_CAPABILITY *TransportCapability > + ) > +{ > + if (TransportCapability != NULL) { > + *TransportCapability = 0; > + } > +} > + > +/** > + This function releases the manageability session. > + > + @param [in] TransportToken The transport token acquired through > + AcquireTransportSession. > + @retval EFI_SUCCESS Token is released successfully. > + @retval EFI_INVALID_PARAMETER Invalid TransportToken. > + @retval Otherwise Other errors. > + > +**/ > +EFI_STATUS > +ReleaseTransportSession ( > + IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken > + ) > +{ > + EFI_STATUS Status; > + MANAGEABILITY_TRANSPORT_KCS *KcsTransportToken; > + > + if (TransportToken == NULL) { > + Status = EFI_INVALID_PARAMETER; > + } > + > + KcsTransportToken = MANAGEABILITY_TRANSPORT_KCS_FROM_LINK > + (TransportToken); if (mSingleSessionToken != KcsTransportToken) { > + Status = EFI_INVALID_PARAMETER; > + } > + > + if (KcsTransportToken != NULL) { > + FreePool (KcsTransportToken->Token.Transport->Function.Version1_0); > + FreePool (KcsTransportToken->Token.Transport); > + FreePool (KcsTransportToken); > + mSingleSessionToken = NULL; > + Status = EFI_SUCCESS; > + } > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a: Fail to release KCS transport token > + (%r).\n", __FUNCTION__, Status)); } > + > + return Status; > +} > diff --git > a/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/M > anageabilityTransportKcs.uni > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/M > anageabilityTransportKcs.uni > new file mode 100644 > index 0000000000..61a3e8b588 > --- /dev/null > +++ > b/Features/ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe > +++ /ManageabilityTransportKcs.uni > @@ -0,0 +1,13 @@ > +// /** @file > +// KCS instance of Manageability Transport Library // // Copyright (C) > +2023 Advanced Micro Devices, Inc. All rights reserved.<BR> // // > +SPDX-License-Identifier: BSD-2-Clause-Patent // // **/ > + > +#string STR_MODULE_ABSTRACT #language en-US "KCS instance of > Manageability Transport Library" > + > +#string STR_MODULE_DESCRIPTION #language en-US "KCS > Manageability Transport library implementation." > + > -- > 2.37.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#101462): https://edk2.groups.io/g/devel/message/101462 Mute This Topic: https://groups.io/mt/97473057/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-