From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:4001:c06::231; helo=mail-io0-x231.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-io0-x231.google.com (mail-io0-x231.google.com [IPv6:2607:f8b0:4001:c06::231]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 46967222630CF for ; Thu, 22 Feb 2018 11:51:29 -0800 (PST) Received: by mail-io0-x231.google.com with SMTP id m22so7277005iob.12 for ; Thu, 22 Feb 2018 11:57:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=1nBvcFnsH5PChNtTt7eMMWt0qRaacylZL8bteOA9CxY=; b=GUdO1Ip02xsYUIuUCcUNvxpt6EnFXwC0ChToQ8ZaDH5rR9wg5LB/TiJKIs+YhaSg/A QCI8/BLGEWO6w+zi8oDWKfxKzH8LPpmp/fLDRQxsmEmCgsNGsRiHOONNtK6JnM6SAaJ8 LCD461fAXV9XUC/N0IAn8MOfPOgDoeiAHdpac= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=1nBvcFnsH5PChNtTt7eMMWt0qRaacylZL8bteOA9CxY=; b=TI94sUQa4BZxTx2OUl6igjz+vpu2NlQuNlSlJnA8ryAY2+dHSgaHXWolbkLngQDKTK L4tXaEdko9hq5Vv2LzfBNWyTpsQpp45lGKvvJbs2IUS4vEcedw4REKLz0ReIAZaD9bk8 I/KGQD4L4o/eYyPJS5URN7PTJHhhKbp1YNCzbWuyJl10td8Jdk3FDirXGzeboM4oT6hT zr/CI6uGp+qQTmqRwZoYfg9vkgPy9KJTdu9tWnABhqsSQkfrnE8ANUA+7tx+2f0fIYTU GTUzwJZ3QQnX6c/sVmo+K8Iiej9IrSfvrAyhnTCI+ZF9GzRfPzL2AlxR6WJSZcTLVlwg jqCQ== X-Gm-Message-State: APf1xPBDNZHJ35WwZlkiPgDv1ah0AfefJghRDly+CctYQculnTfIR+K8 wYBbBDthX0E8hAd4EtDE2YNHhLsFJ74hvbDUCbZFFg== X-Google-Smtp-Source: AH8x224aOdGzSZ7aAkPojs2iTGQVEbRHhCT8yApzV2ZvQ1XlBJF5nB7cH/fmrdj0E0QfcXjoMWdzsnkUWY9mskkl2oI= X-Received: by 10.107.56.69 with SMTP id f66mr10172884ioa.170.1519329449344; Thu, 22 Feb 2018 11:57:29 -0800 (PST) MIME-Version: 1.0 Received: by 10.107.138.209 with HTTP; Thu, 22 Feb 2018 11:57:28 -0800 (PST) In-Reply-To: References: <20180222181505.28192-1-ard.biesheuvel@linaro.org> <20180222181505.28192-2-ard.biesheuvel@linaro.org> From: Ard Biesheuvel Date: Thu, 22 Feb 2018 19:57:28 +0000 Message-ID: To: "Kinney, Michael D" Cc: "edk2-devel@lists.01.org" , "leif.lindholm@linaro.org" , "lersek@redhat.com" , "Gao, Liming" , "afish@apple.com" , "Zeng, Star" , "Ni, Ruiyu" Subject: Re: [PATCH v3 1/2] MdePkg: introduce DxeRuntimeDebugLibSerialPort X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 22 Feb 2018 19:51:29 -0000 Content-Type: text/plain; charset="UTF-8" On 22 February 2018 at 19:40, Kinney, Michael D wrote: > > Ard, > > In DebugAssert(), if you have deadloop or BP enabled for > the ASSERT(), then it would be good to have the message > available in the local variable Buffer. > > Perhaps only the call to SerialPortWrite() should be > filtered. > Good point! > >> -----Original Message----- >> From: Ard Biesheuvel [mailto:ard.biesheuvel@linaro.org] >> Sent: Thursday, February 22, 2018 10:15 AM >> To: edk2-devel@lists.01.org >> Cc: leif.lindholm@linaro.org; lersek@redhat.com; Gao, >> Liming ; Kinney, Michael D >> ; afish@apple.com; Zeng, >> Star ; Ni, Ruiyu >> ; Ard Biesheuvel >> >> Subject: [PATCH v3 1/2] MdePkg: introduce >> DxeRuntimeDebugLibSerialPort >> >> Introduce a variant of BaseDebugLibSerialPort that >> behaves correctly with >> regards to the use of the serial port after >> ExitBootServices(). At boot >> time, all DEBUG() prints and ASSERT() invocations are >> executed normally. >> At runtime, DEBUG() prints are dropped entirely, and >> ASSERT()s omit the >> serial output as well, and only perform the configured >> post-ASSERT() >> action, i.e., issue a CPU breakpoint or enter a >> deadloop. >> >> Contributed-under: TianoCore Contribution Agreement 1.1 >> Signed-off-by: Ard Biesheuvel >> >> --- >> MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c >> | 346 ++++++++++++++++++++ >> >> MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDe >> bugLibSerialPort.inf | 55 ++++ >> >> MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDe >> bugLibSerialPort.uni | 21 ++ >> 3 files changed, 422 insertions(+) >> >> diff --git >> a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c >> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c >> new file mode 100644 >> index 000000000000..a987159d8fc8 >> --- /dev/null >> +++ >> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DebugLib.c >> @@ -0,0 +1,346 @@ >> +/** @file >> + DXE runtime Debug library instance based on Serial >> Port library. >> + It takes care not to call into SerialPortLib after >> ExitBootServices() has >> + been called, to prevent touching hardware that is no >> longer owned by the >> + firmware. >> + >> + Copyright (c) 2006 - 2011, Intel Corporation. All >> rights reserved.
>> + Copyright (c) 2018, Linaro, Ltd. All rights >> reserved.
>> + >> + 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. >> + >> +**/ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +STATIC EFI_EVENT mEfiExitBootServicesEvent; >> +STATIC BOOLEAN mEfiAtRuntime; >> + >> +// >> +// Define the maximum debug and assert message length >> that this library supports >> +// >> +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 >> + >> +/** >> + Set AtRuntime flag as TRUE after ExitBootServices. >> + >> + @param[in] Event The Event that is being >> processed. >> + @param[in] Context The Event Context. >> + >> +**/ >> +STATIC >> +VOID >> +EFIAPI >> +ExitBootServicesEvent ( >> + IN EFI_EVENT Event, >> + IN VOID *Context >> + ) >> +{ >> + mEfiAtRuntime = TRUE; >> +} >> + >> +/** >> + The constructor function to initialize the Serial >> Port library and >> + register a callback for the ExitBootServices event. >> + >> + @param[in] ImageHandle The firmware allocated >> handle for the EFI image. >> + @param[in] SystemTable A pointer to the EFI System >> Table. >> + >> + @retval EFI_SUCCESS The operation completed >> successfully. >> + @retval other Either the serial port failed >> to initialize or the >> + ExitBootServices event callback >> registration failed. >> +**/ >> +EFI_STATUS >> +EFIAPI >> +DxeRuntimeDebugLibSerialPortConstructor ( >> + IN EFI_HANDLE ImageHandle, >> + IN EFI_SYSTEM_TABLE *SystemTable >> + ) >> +{ >> + EFI_STATUS Status; >> + >> + Status = SerialPortInitialize (); >> + if (EFI_ERROR (Status)) { >> + return Status; >> + } >> + >> + return SystemTable->BootServices->CreateEventEx >> (EVT_NOTIFY_SIGNAL, >> + TPL_NOTIFY, >> ExitBootServicesEvent, NULL, >> + >> &gEfiEventExitBootServicesGuid, >> + >> &mEfiExitBootServicesEvent); >> +} >> + >> +/** >> + If a runtime driver exits with an error, it must call >> this routine >> + to free the allocated resource before the exiting. >> + >> + @param[in] ImageHandle The firmware allocated >> handle for the EFI image. >> + @param[in] SystemTable A pointer to the EFI System >> Table. >> + >> + @retval EFI_SUCCESS The Runtime Driver Lib >> shutdown successfully. >> + @retval EFI_UNSUPPORTED Runtime Driver lib was >> not initialized. >> +**/ >> +EFI_STATUS >> +EFIAPI >> +DxeRuntimeDebugLibSerialPortDestructor ( >> + IN EFI_HANDLE ImageHandle, >> + IN EFI_SYSTEM_TABLE *SystemTable >> + ) >> +{ >> + return SystemTable->BootServices->CloseEvent >> (mEfiExitBootServicesEvent); >> +} >> + >> +/** >> + Prints a debug message to the debug output device if >> the specified error level is enabled. >> + >> + If any bit in ErrorLevel is also set in >> DebugPrintErrorLevelLib function >> + GetDebugPrintErrorLevel (), then print the message >> specified by Format and the >> + associated variable argument list to the debug output >> device. >> + >> + If Format is NULL, then ASSERT(). >> + >> + @param ErrorLevel The error level of the debug >> message. >> + @param Format Format string for the debug >> message to print. >> + @param ... Variable argument list whose >> contents are accessed >> + based on the format string >> specified by Format. >> + >> +**/ >> +VOID >> +EFIAPI >> +DebugPrint ( >> + IN UINTN ErrorLevel, >> + IN CONST CHAR8 *Format, >> + ... >> + ) >> +{ >> + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; >> + VA_LIST Marker; >> + >> + if (mEfiAtRuntime) { >> + return; >> + } >> + >> + // >> + // If Format is NULL, then ASSERT(). >> + // >> + ASSERT (Format != NULL); >> + >> + // >> + // Check driver debug mask value and global mask >> + // >> + if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) { >> + return; >> + } >> + >> + // >> + // Convert the DEBUG() message to an ASCII String >> + // >> + VA_START (Marker, Format); >> + AsciiVSPrint (Buffer, sizeof (Buffer), Format, >> Marker); >> + VA_END (Marker); >> + >> + // >> + // Send the print string to a Serial Port >> + // >> + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen >> (Buffer)); >> +} >> + >> + >> +/** >> + Prints an assert message containing a filename, line >> number, and description. >> + This may be followed by a breakpoint or a dead loop. >> + >> + Print a message of the form "ASSERT >> (): \n" >> + to the debug output device. If >> DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of >> + PcdDebugProperyMask is set then CpuBreakpoint() is >> called. Otherwise, if >> + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of >> PcdDebugProperyMask is set then >> + CpuDeadLoop() is called. If neither of these bits >> are set, then this function >> + returns immediately after the message is printed to >> the debug output device. >> + DebugAssert() must actively prevent recursion. If >> DebugAssert() is called while >> + processing another DebugAssert(), then DebugAssert() >> must return immediately. >> + >> + If FileName is NULL, then a string of >> "(NULL) Filename" is printed. >> + If Description is NULL, then a string >> of "(NULL) Description" is printed. >> + >> + @param FileName The pointer to the name of the >> source file that generated the assert condition. >> + @param LineNumber The line number in the source >> file that generated the assert condition >> + @param Description The pointer to the description >> of the assert condition. >> + >> +**/ >> +VOID >> +EFIAPI >> +DebugAssert ( >> + IN CONST CHAR8 *FileName, >> + IN UINTN LineNumber, >> + IN CONST CHAR8 *Description >> + ) >> +{ >> + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; >> + >> + if (!mEfiAtRuntime) { >> + // >> + // Generate the ASSERT() message in Ascii format >> + // >> + AsciiSPrint (Buffer, sizeof (Buffer), "ASSERT [%a] >> %a(%d): %a\n", >> + gEfiCallerBaseName, FileName, LineNumber, >> Description); >> + >> + // >> + // Send the print string to the Console Output >> device >> + // >> + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen >> (Buffer)); >> + } >> + >> + // >> + // Generate a Breakpoint, DeadLoop, or NOP based on >> PCD settings >> + // >> + if ((PcdGet8(PcdDebugPropertyMask) & >> DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { >> + CpuBreakpoint (); >> + } else if ((PcdGet8(PcdDebugPropertyMask) & >> DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { >> + CpuDeadLoop (); >> + } >> +} >> + >> + >> +/** >> + Fills a target buffer with PcdDebugClearMemoryValue, >> and returns the target buffer. >> + >> + This function fills Length bytes of Buffer with the >> value specified by >> + PcdDebugClearMemoryValue, and returns Buffer. >> + >> + If Buffer is NULL, then ASSERT(). >> + If Length is greater than (MAX_ADDRESS - Buffer + 1), >> then ASSERT(). >> + >> + @param Buffer The pointer to the target buffer to >> be filled with PcdDebugClearMemoryValue. >> + @param Length The number of bytes in Buffer to >> fill with zeros PcdDebugClearMemoryValue. >> + >> + @return Buffer The pointer to the target buffer >> filled with PcdDebugClearMemoryValue. >> + >> +**/ >> +VOID * >> +EFIAPI >> +DebugClearMemory ( >> + OUT VOID *Buffer, >> + IN UINTN Length >> + ) >> +{ >> + // >> + // If Buffer is NULL, then ASSERT(). >> + // >> + ASSERT (Buffer != NULL); >> + >> + // >> + // SetMem() checks for the the ASSERT() condition on >> Length and returns Buffer >> + // >> + return SetMem (Buffer, Length, >> PcdGet8(PcdDebugClearMemoryValue)); >> +} >> + >> + >> +/** >> + Returns TRUE if ASSERT() macros are enabled. >> + >> + This function returns TRUE if the >> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of >> + PcdDebugProperyMask is set. Otherwise FALSE is >> returned. >> + >> + @retval TRUE The >> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of >> PcdDebugProperyMask is set. >> + @retval FALSE The >> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of >> PcdDebugProperyMask is clear. >> + >> +**/ >> +BOOLEAN >> +EFIAPI >> +DebugAssertEnabled ( >> + VOID >> + ) >> +{ >> + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & >> DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); >> +} >> + >> + >> +/** >> + Returns TRUE if DEBUG() macros are enabled. >> + >> + This function returns TRUE if the >> DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of >> + PcdDebugProperyMask is set. Otherwise FALSE is >> returned. >> + >> + @retval TRUE The >> DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of >> PcdDebugProperyMask is set. >> + @retval FALSE The >> DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of >> PcdDebugProperyMask is clear. >> + >> +**/ >> +BOOLEAN >> +EFIAPI >> +DebugPrintEnabled ( >> + VOID >> + ) >> +{ >> + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & >> DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); >> +} >> + >> + >> +/** >> + Returns TRUE if DEBUG_CODE() macros are enabled. >> + >> + This function returns TRUE if the >> DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of >> + PcdDebugProperyMask is set. Otherwise FALSE is >> returned. >> + >> + @retval TRUE The >> DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of >> PcdDebugProperyMask is set. >> + @retval FALSE The >> DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of >> PcdDebugProperyMask is clear. >> + >> +**/ >> +BOOLEAN >> +EFIAPI >> +DebugCodeEnabled ( >> + VOID >> + ) >> +{ >> + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & >> DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); >> +} >> + >> + >> +/** >> + Returns TRUE if DEBUG_CLEAR_MEMORY() macro is >> enabled. >> + >> + This function returns TRUE if the >> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of >> + PcdDebugProperyMask is set. Otherwise FALSE is >> returned. >> + >> + @retval TRUE The >> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of >> PcdDebugProperyMask is set. >> + @retval FALSE The >> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of >> PcdDebugProperyMask is clear. >> + >> +**/ >> +BOOLEAN >> +EFIAPI >> +DebugClearMemoryEnabled ( >> + VOID >> + ) >> +{ >> + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & >> DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); >> +} >> + >> +/** >> + Returns TRUE if any one of the bit is set both in >> ErrorLevel and PcdFixedDebugPrintErrorLevel. >> + >> + This function compares the bit mask of ErrorLevel and >> PcdFixedDebugPrintErrorLevel. >> + >> + @retval TRUE Current ErrorLevel is supported. >> + @retval FALSE Current ErrorLevel is not supported. >> + >> +**/ >> +BOOLEAN >> +EFIAPI >> +DebugPrintLevelEnabled ( >> + IN CONST UINTN ErrorLevel >> + ) >> +{ >> + return (BOOLEAN) ((ErrorLevel & >> PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0); >> +} >> diff --git >> a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime >> DebugLibSerialPort.inf >> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime >> DebugLibSerialPort.inf >> new file mode 100644 >> index 000000000000..4b5157ca093c >> --- /dev/null >> +++ >> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime >> DebugLibSerialPort.inf >> @@ -0,0 +1,55 @@ >> +## @file >> +# DXE runtime Debug library instance based on Serial >> Port library. >> +# It takes care not to call into SerialPortLib after >> ExitBootServices() has >> +# been called, to prevent touching hardware that is no >> longer owned by the >> +# firmware. >> +# >> +# Copyright (c) 2006 - 2015, Intel Corporation. All >> rights reserved.
>> +# Copyright (c) 2018, Linaro, Ltd. All rights >> reserved.
>> +# >> +# 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 = 0x0001001A >> + BASE_NAME = >> DxeRuntimeDebugLibSerialPort >> + MODULE_UNI_FILE = >> DxeRuntimeDebugLibSerialPort.uni >> + FILE_GUID = 9D914E2F-7CCB-41DB- >> 8E74-9AFF8F3BBFBF >> + MODULE_TYPE = DXE_RUNTIME_DRIVER >> + VERSION_STRING = 1.0 >> + LIBRARY_CLASS = >> DebugLib|DXE_RUNTIME_DRIVER >> + CONSTRUCTOR = >> DxeRuntimeDebugLibSerialPortConstructor >> + DESTRUCTOR = >> DxeRuntimeDebugLibSerialPortDestructor >> + >> +# >> +# VALID_ARCHITECTURES = AARCH64 ARM IA32 X64 >> IPF EBC >> +# >> + >> +[Sources] >> + DebugLib.c >> + >> +[Packages] >> + MdePkg/MdePkg.dec >> + >> +[LibraryClasses] >> + BaseLib >> + BaseMemoryLib >> + DebugPrintErrorLevelLib >> + PcdLib >> + PrintLib >> + SerialPortLib >> + >> +[Guids] >> + gEfiEventExitBootServicesGuid >> ## CONSUMES ## Event >> + >> +[Pcd] >> + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue >> ## CONSUMES >> + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask >> ## CONSUMES >> + gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel >> ## CONSUMES >> diff --git >> a/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime >> DebugLibSerialPort.uni >> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime >> DebugLibSerialPort.uni >> new file mode 100644 >> index 000000000000..cd65515c4177 >> --- /dev/null >> +++ >> b/MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntime >> DebugLibSerialPort.uni >> @@ -0,0 +1,21 @@ >> +// /** @file >> +// Instance of Debug Library based on Serial Port >> Library. >> +// >> +// It uses Print Library to produce formatted output >> strings to seiral port device. >> +// >> +// Copyright (c) 2006 - 2014, Intel Corporation. All >> rights reserved.
>> +// >> +// 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. >> +// >> +// **/ >> + >> + >> +#string STR_MODULE_ABSTRACT #language en-US >> "Instance of Debug Library based on Serial Port Library" >> + >> +#string STR_MODULE_DESCRIPTION #language en-US >> "It uses Print Library to produce formatted output >> strings to a serial port device." >> + >> -- >> 2.11.0 >