Re: [Patch V3 8/9] MdeModulePkg/ACPI: Install ACPI table from HOB.


Wu, Hao A
 

-----Original Message-----
From: Liu, Zhiguang <zhiguang.liu@intel.com>
Sent: Friday, June 4, 2021 5:42 PM
To: devel@edk2.groups.io
Cc: Wang, Jian J <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>;
Bi, Dandan <dandan.bi@intel.com>; Liming Gao
<gaoliming@byosoft.com.cn>; Ni, Ray <ray.ni@intel.com>
Subject: [Patch V3 8/9] MdeModulePkg/ACPI: Install ACPI table from HOB.

V1:
If HOB contains APCI table information, entry point of AcpiTableDxe.inf
should parse the APCI table from HOB, and install these tables.
We assume the whole ACPI table (starting with
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
is contained by a single gEfiAcpiTableGuid HOB.

V2:
If error happens when installing ACPI table, stop installing and removing all
the tables that
are already added.

Reviewed-by: Hao A Wu <hao.a.wu@intel.com>

Best Regards,
Hao Wu



Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Ray Ni <ray.ni@intel.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
---
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c | 92
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++---------------------------
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h | 38
+++++++++++++++++++++++++++++++++++++-
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf | 8
+++++---
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c | 171
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++-------
4 files changed, 271 insertions(+), 38 deletions(-)

diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
index 14ced68e64..d98573d613 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
@@ -1,7 +1,7 @@
/** @file

ACPI Sdt Protocol Driver



- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>

+ Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved. <BR>

SPDX-License-Identifier: BSD-2-Clause-Patent



**/

@@ -191,8 +191,7 @@ SdtNotifyAcpiList (
/**

Returns a requested ACPI table.



- The GetAcpiTable() function returns a pointer to a buffer containing the
ACPI table associated

- with the Index that was input. The following structures are not considered
elements in the list of

+ The following structures are not considered elements in the list of

ACPI tables:

- Root System Description Pointer (RSD_PTR)

- Root System Description Table (RSDT)

@@ -201,42 +200,32 @@ SdtNotifyAcpiList (
member. For tables installed via the
EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,

the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.



- @param[in] Index The zero-based index of the table to retrieve.

- @param[out] Table Pointer for returning the table buffer.

- @param[out] Version On return, updated with the ACPI versions to
which this table belongs. Type

- EFI_ACPI_TABLE_VERSION is defined in "Related Definitions"
in the

- EFI_ACPI_SDT_PROTOCOL.

- @param[out] TableKey On return, points to the table key for the
specified ACPI system definition table.

- This is identical to the table key used in the
EFI_ACPI_TABLE_PROTOCOL.

- The TableKey can be passed to
EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()

- to uninstall the table.

- @retval EFI_SUCCESS The function completed successfully.

- @retval EFI_NOT_FOUND The requested index is too large and a table
was not found.

+ @param[in] AcpiTableInstance ACPI table Instance.

+ @param[in] Index The zero-based index of the table to retrieve.

+ @param[out] Table Pointer for returning the table buffer.

+ @param[out] Version On return, updated with the ACPI versions to
which this table belongs. Type

+ EFI_ACPI_TABLE_VERSION is defined in "Related
Definitions" in the

+ EFI_ACPI_SDT_PROTOCOL.

+ @param[out] TableKey On return, points to the table key for the
specified ACPI system definition table.

+ This is identical to the table key used in the
EFI_ACPI_TABLE_PROTOCOL.

+ The TableKey can be passed to
EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()

+ to uninstall the table.

+ @retval EFI_SUCCESS The function completed successfully.

+ @retval EFI_NOT_FOUND The requested index is too large and a
table was not found.

**/

EFI_STATUS

-EFIAPI

-GetAcpiTable2 (

+SdtGetAcpiTable (

+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,

IN UINTN Index,

OUT EFI_ACPI_SDT_HEADER **Table,

OUT EFI_ACPI_TABLE_VERSION *Version,

OUT UINTN *TableKey

)

{

- EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;

UINTN TableIndex;

LIST_ENTRY *CurrentLink;

LIST_ENTRY *StartLink;

EFI_ACPI_TABLE_LIST *CurrentTable;

-

- ASSERT (Table != NULL);

- ASSERT (Version != NULL);

- ASSERT (TableKey != NULL);

-

- //

- // Get the instance of the ACPI Table

- //

- AcpiTableInstance = SdtGetAcpiTableInstance ();

-

//

// Find the table

//

@@ -270,6 +259,55 @@ GetAcpiTable2 (
return EFI_SUCCESS;

}



+/**

+ Returns a requested ACPI table.

+

+ The GetAcpiTable() function returns a pointer to a buffer containing the
ACPI table associated

+ with the Index that was input. The following structures are not considered
elements in the list of

+ ACPI tables:

+ - Root System Description Pointer (RSD_PTR)

+ - Root System Description Table (RSDT)

+ - Extended System Description Table (XSDT)

+ Version is updated with a bit map containing all the versions of ACPI of
which the table is a

+ member. For tables installed via the
EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,

+ the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.

+

+ @param[in] Index The zero-based index of the table to retrieve.

+ @param[out] Table Pointer for returning the table buffer.

+ @param[out] Version On return, updated with the ACPI versions to
which this table belongs. Type

+ EFI_ACPI_TABLE_VERSION is defined in "Related Definitions"
in the

+ EFI_ACPI_SDT_PROTOCOL.

+ @param[out] TableKey On return, points to the table key for the
specified ACPI system definition table.

+ This is identical to the table key used in the
EFI_ACPI_TABLE_PROTOCOL.

+ The TableKey can be passed to
EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()

+ to uninstall the table.

+ @retval EFI_SUCCESS The function completed successfully.

+ @retval EFI_NOT_FOUND The requested index is too large and a table
was not found.

+**/

+EFI_STATUS

+EFIAPI

+GetAcpiTable2 (

+ IN UINTN Index,

+ OUT EFI_ACPI_SDT_HEADER **Table,

+ OUT EFI_ACPI_TABLE_VERSION *Version,

+ OUT UINTN *TableKey

+ )

+{

+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;

+

+ ASSERT (Table != NULL);

+ ASSERT (Version != NULL);

+ ASSERT (TableKey != NULL);

+

+ //

+ // Get the instance of the ACPI Table

+ //

+ AcpiTableInstance = SdtGetAcpiTableInstance ();

+

+ return SdtGetAcpiTable (AcpiTableInstance, Index, Table, Version,
TableKey);

+}

+

+

/**

Register a callback when an ACPI table is installed.



diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
index 9d7cf7ccfc..0af2d11a1a 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
@@ -1,7 +1,7 @@
/** @file

ACPI Table Protocol Driver



- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

+ Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent



**/

@@ -24,6 +24,8 @@
#include <Library/MemoryAllocationLib.h>

#include <Library/UefiBootServicesTableLib.h>

#include <Library/PcdLib.h>

+#include <Library/HobLib.h>

+#include <UniversalPayload/AcpiTable.h>



//

// Statements that include other files

@@ -228,6 +230,40 @@ SdtAcpiTableAcpiSdtConstructor (
IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance

);



+/**

+ Returns a requested ACPI table.

+

+ The following structures are not considered elements in the list of

+ ACPI tables:

+ - Root System Description Pointer (RSD_PTR)

+ - Root System Description Table (RSDT)

+ - Extended System Description Table (XSDT)

+ Version is updated with a bit map containing all the versions of ACPI of
which the table is a

+ member. For tables installed via the
EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,

+ the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.

+

+ @param[in] AcpiTableInstance ACPI table Instance.

+ @param[in] Index The zero-based index of the table to retrieve.

+ @param[out] Table Pointer for returning the table buffer.

+ @param[out] Version On return, updated with the ACPI versions to
which this table belongs. Type

+ EFI_ACPI_TABLE_VERSION is defined in "Related
Definitions" in the

+ EFI_ACPI_SDT_PROTOCOL.

+ @param[out] TableKey On return, points to the table key for the
specified ACPI system definition table.

+ This is identical to the table key used in the
EFI_ACPI_TABLE_PROTOCOL.

+ The TableKey can be passed to
EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()

+ to uninstall the table.

+ @retval EFI_SUCCESS The function completed successfully.

+ @retval EFI_NOT_FOUND The requested index is too large and a
table was not found.

+**/

+EFI_STATUS

+SdtGetAcpiTable (

+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,

+ IN UINTN Index,

+ OUT EFI_ACPI_SDT_HEADER **Table,

+ OUT EFI_ACPI_TABLE_VERSION *Version,

+ OUT UINTN *TableKey

+ );

+

//

// export PrivateData symbol, because we need that in AcpiSdtProtol
implementation

//

diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
index d341df439e..9e34f8ea41 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
@@ -4,7 +4,7 @@
# This driver initializes ACPI tables (Rsdp, Rsdt and Xsdt) and produces
UEFI/PI

# services to install/uninstall/manage ACPI tables.

#

-# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>

# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>

# SPDX-License-Identifier: BSD-2-Clause-Patent

#

@@ -51,10 +51,12 @@
DebugLib

BaseLib

PcdLib

+ HobLib



[Guids]

- gEfiAcpi10TableGuid ## PRODUCES ## SystemTable

- gEfiAcpiTableGuid ## PRODUCES ## SystemTable

+ gEfiAcpi10TableGuid ## PRODUCES ## SystemTable

+ gEfiAcpiTableGuid ## PRODUCES ## SystemTable

+ gPldAcpiTableGuid ## SOMETIMES_CONSUMES ## HOB



[FeaturePcd]

gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol ##
CONSUMES

diff --git
a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
index 5a2afdff27..cd79a1082c 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
@@ -1,7 +1,7 @@
/** @file

ACPI Table Protocol Implementation



- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

+ Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>

Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent



@@ -30,6 +30,7 @@ STATIC EFI_ALLOCATE_TYPE mAcpiTableAllocType;
@param Table Table to add.

@param Checksum Does the table require checksumming.

@param Version The version of the list to add the table to.

+ @param IsFromHob True, if add Apci Table from Hob List.

@param Handle Pointer for returning the handle.



@return EFI_SUCCESS The function completed successfully.

@@ -44,6 +45,7 @@ AddTableToList (
IN VOID *Table,

IN BOOLEAN Checksum,

IN EFI_ACPI_TABLE_VERSION Version,

+ IN BOOLEAN IsFromHob,

OUT UINTN *Handle

);



@@ -238,6 +240,7 @@ InstallAcpiTable (
AcpiTableBufferConst,

TRUE,

Version,

+ FALSE,

TableKey

);

if (!EFI_ERROR (Status)) {

@@ -472,6 +475,7 @@ FreeTableMemory (
@param Table Table to add.

@param Checksum Does the table require checksumming.

@param Version The version of the list to add the table to.

+ @param IsFromHob True, if add Apci Table from Hob List.

@param Handle Pointer for returning the handle.



@return EFI_SUCCESS The function completed successfully.

@@ -487,6 +491,7 @@ AddTableToList (
IN VOID *Table,

IN BOOLEAN Checksum,

IN EFI_ACPI_TABLE_VERSION Version,

+ IN BOOLEAN IsFromHob,

OUT UINTN *Handle

)

{

@@ -553,12 +558,17 @@ AddTableToList (
// SMM communication ACPI table.

//

ASSERT ((EFI_PAGE_SIZE % 64) == 0);

- Status = gBS->AllocatePages (

- AllocateMaxAddress,

- EfiACPIMemoryNVS,

- EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),

- &AllocPhysAddress

- );

+ if (IsFromHob){

+ AllocPhysAddress = (UINTN)Table;

+ Status = EFI_SUCCESS;

+ } else {

+ Status = gBS->AllocatePages (

+ AllocateMaxAddress,

+ EfiACPIMemoryNVS,

+ EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),

+ &AllocPhysAddress

+ );

+ }

} else if (mAcpiTableAllocType == AllocateAnyPages) {

//

// If there is no allocation limit, there is also no need to use page

@@ -1689,6 +1699,151 @@ ChecksumCommonTables (
return EFI_SUCCESS;

}



+/**

+ This function will find gPldAcpiTableGuid Guid Hob, and install Acpi table
from it.

+

+ @param AcpiTableInstance Protocol instance private data.

+

+ @return EFI_SUCCESS The function completed successfully.

+ @return EFI_NOT_FOUND The function doesn't find the
gEfiAcpiTableGuid Guid Hob.

+ @return EFI_ABORTED The function could not complete successfully.

+

+**/

+EFI_STATUS

+InstallAcpiTableFromHob (

+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance

+ )

+{

+ EFI_HOB_GUID_TYPE *GuidHob;

+ EFI_ACPI_TABLE_VERSION Version;

+ EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;

+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt;

+ EFI_ACPI_DESCRIPTION_HEADER *ChildTable;

+ UINT64 ChildTableAddress;

+ UINTN Count;

+ UINTN Index;

+ UINTN TableKey;

+ EFI_STATUS Status;

+ UINTN EntrySize;

+ PLD_ACPI_TABLE *AcpiTableAdress;

+ VOID *TableToInstall;

+ EFI_ACPI_SDT_HEADER *Table;

+ PLD_GENERIC_HEADER *GenericHeader;

+

+ TableKey = 0;

+ Version = PcdGet32 (PcdAcpiExposedTableVersions);

+ Status = EFI_SUCCESS;

+ //

+ // HOB only contains the ACPI table in 2.0+ format.

+ //

+ GuidHob = GetFirstGuidHob (&gPldAcpiTableGuid);

+ if (GuidHob == NULL) {

+ return EFI_NOT_FOUND;

+ }

+

+ GenericHeader = (PLD_GENERIC_HEADER *) GET_GUID_HOB_DATA
(GuidHob);

+ if ((sizeof (PLD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE
(GuidHob)) || (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE
(GuidHob))) {

+ return EFI_NOT_FOUND;

+ }

+ if (GenericHeader->Revision == PLD_ACPI_TABLE_REVISION) {

+ //

+ // PLD_ACPI_TABLE structure is used when Revision equals to
PLD_ACPI_TABLE_REVISION

+ //

+ AcpiTableAdress = (PLD_ACPI_TABLE *) GET_GUID_HOB_DATA
(GuidHob);

+ if (AcpiTableAdress->PldHeader.Length < PLD_SIZEOF_THROUGH_FIELD
(PLD_ACPI_TABLE, Rsdp)) {

+ //

+ // Retrun if can't find the ACPI Info Hob with enough length

+ //

+ return EFI_NOT_FOUND;

+ }

+ Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) (UINTN)
(AcpiTableAdress->Rsdp);

+

+ //

+ // An ACPI-compatible OS must use the XSDT if present.

+ // It shouldn't happen that XsdtAddress points beyond 4G range in 32-bit
environment.

+ //

+ ASSERT ((UINTN) Rsdp->XsdtAddress == Rsdp->XsdtAddress);

+

+ EntrySize = sizeof (UINT64);

+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;

+ if (Rsdt == NULL) {

+ //

+ // XsdtAddress is zero, then we use Rsdt which has 32 bit entry

+ //

+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;

+ EntrySize = sizeof (UINT32);

+ }

+

+ if (Rsdt->Length <= sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {

+ return EFI_ABORTED;

+ }

+

+ Count = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) /
EntrySize;

+

+ for (Index = 0; Index < Count; Index++){

+ ChildTableAddress = 0;

+ CopyMem (&ChildTableAddress, (UINT8 *) (Rsdt + 1) + EntrySize * Index,
EntrySize);

+ //

+ // If the address is of UINT64 while this module runs at 32 bits,

+ // make sure the upper bits are all-zeros.

+ //

+ ASSERT (ChildTableAddress == (UINTN) ChildTableAddress);

+ if (ChildTableAddress != (UINTN) ChildTableAddress) {

+ Status = EFI_ABORTED;

+ break;

+ }

+

+ ChildTable = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN)
ChildTableAddress;

+ Status = AddTableToList (AcpiTableInstance, ChildTable, TRUE, Version,
TRUE, &TableKey);

+ if (EFI_ERROR (Status)) {

+ DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI
table at 0x%p\n", ChildTable));

+ ASSERT_EFI_ERROR (Status);

+ break;

+ }

+ if (ChildTable->Signature ==
EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE){

+ //

+ // Add the FACS and DSDT tables if it is not NULL.

+ //

+ if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)-
FirmwareCtrl != 0) {
+ TableToInstall = (VOID *) (UINTN)
((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)-
FirmwareCtrl;
+ Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE,
Version, TRUE, &TableKey);

+ if (EFI_ERROR (Status)) {

+ DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI
table FACS\n"));

+ ASSERT_EFI_ERROR (Status);

+ break;

+ }

+ }

+

+ if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)-
Dsdt != 0) {
+ TableToInstall = (VOID *) (UINTN)
((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->Dsdt;

+ Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE,
Version, TRUE, &TableKey);

+ if (EFI_ERROR (Status)) {

+ DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI
table DSDT\n"));

+ ASSERT_EFI_ERROR (Status);

+ break;

+ }

+ }

+ }

+ }

+ } else {

+ return EFI_NOT_FOUND;

+ }

+

+ if (EFI_ERROR (Status)) {

+ //

+ // Error happens when trying to add ACPI table to the list.

+ // Remove all of them from list because at this time, no other tables
except from HOB are in the list

+ //

+ while (SdtGetAcpiTable (AcpiTableInstance, 0, &Table, &Version,
&TableKey) == EFI_SUCCESS) {

+ RemoveTableFromList (AcpiTableInstance, Version, TableKey);

+ }

+ } else {

+ Status = PublishTables (AcpiTableInstance, Version);

+ }

+

+ ASSERT_EFI_ERROR (Status);

+ return Status;

+}



/**

Constructor for the ACPI table protocol. Initializes instance

@@ -1918,6 +2073,8 @@ AcpiTableAcpiTableConstructor (


ChecksumCommonTables (AcpiTableInstance);



+ InstallAcpiTableFromHob (AcpiTableInstance);

+

//

// Completed successfully

//

--
2.30.0.windows.2

Join devel@edk2.groups.io to automatically receive all group messages.