Skip to content

Commit

Permalink
Tables: Back port acpi_get_table_with_size() and early_acpi_os_unmap_…
Browse files Browse the repository at this point in the history
…memory() from Linux kernel

This patch back ports Linux acpi_get_table_with_size() and
early_acpi_os_unmap_memory() into ACPICA upstream to reduce divergences.

The 2 APIs are used by Linux as table management APIs for long time, it
contains a hidden logic that during the early stage, the mapped tables
should be unmapped before the early stage ends.

During the early stage, tables are handled by the following sequence:
 acpi_get_table_with_size();
 parse the table
 early_acpi_os_unmap_memory();
During the late stage, tables are handled by the following sequence:
 acpi_get_table();
 parse the table
Linux uses acpi_gbl_permanent_mmap to distinguish the early stage and the
late stage.

The reasoning of introducing acpi_get_table_with_size() is: ACPICA will
remember the early mapped pointer in AcpiGetTable() and Linux isn't able to
prevent ACPICA from using the wrong early mapped pointer during the late
stage as there is no API provided from ACPICA to be an inverse of
AcpiGetTable() to forget the early mapped pointer.

But how ACPICA can work with the early/late stage requirement? Inside of
ACPICA, tables are ensured to be remained in "INSTALLED" state during the
early stage, and they are carefully not transitioned to "VALIDATED" state
until the late stage. So the same logic is in fact implemented inside of
ACPICA in a different way. The gap is only that the feature is not provided
to the OSPMs in an accessible external API style.

It then is possible to fix the gap by providing an inverse of
AcpiGetTable() from ACPICA, so that the two Linux sequences can be
combined:
 AcpiGetTable();
 parse the table
 AcpiPutTable();
In order to work easier with the current Linux code, AcpiGetTable() and
AcpiPutTable() is implemented in a usage counting based style:
 1. When the usage count of the table is increased from 0 to 1, table is
    mapped and .Pointer is set with the mapping address (VALIDATED);
 2. When the usage count of the table is decreased from 1 to 0, .Pointer
    is unset and the mapping address is unmapped (INVALIDATED).
So that we can deploy the new APIs to Linux with minimal effort by just
invoking AcpiGetTable() in acpi_get_table_with_size() and invoking
AcpiPutTable() in early_acpi_os_unmap_memory(). Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
  • Loading branch information
Lv Zheng committed Nov 3, 2016
1 parent 68af3c3 commit cac6790
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 28 deletions.
96 changes: 96 additions & 0 deletions source/components/tables/tbutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,99 @@ AcpiTbParseRootTable (
AcpiOsUnmapMemory (Table, Length);
return_ACPI_STATUS (AE_OK);
}


/*******************************************************************************
*
* FUNCTION: AcpiTbGetTable
*
* PARAMETERS: TableDesc - Table descriptor
* OutTable - Where the pointer to the table is returned
*
* RETURN: Status and pointer to the requested table
*
* DESCRIPTION: Increase a reference to a table descriptor and return the
* validated table pointer.
* If the table descriptor is an entry of the root table list,
* this API must be invoked with ACPI_MTX_TABLES acquired.
*
******************************************************************************/

ACPI_STATUS
AcpiTbGetTable (
ACPI_TABLE_DESC *TableDesc,
ACPI_TABLE_HEADER **OutTable)
{
ACPI_STATUS Status;


ACPI_FUNCTION_TRACE (AcpiTbGetTable);


if (TableDesc->ValidationCount == 0)
{
/* Table need to be "VALIDATED" */

Status = AcpiTbValidateTable (TableDesc);
if (ACPI_FAILURE (Status))
{
return_ACPI_STATUS (Status);
}
}

TableDesc->ValidationCount++;
if (TableDesc->ValidationCount == 0)
{
ACPI_ERROR ((AE_INFO,
"Table %p, Validation count is zero after increment\n",
TableDesc));
TableDesc->ValidationCount--;
return_ACPI_STATUS (AE_LIMIT);
}

*OutTable = TableDesc->Pointer;
return_ACPI_STATUS (AE_OK);
}


/*******************************************************************************
*
* FUNCTION: AcpiTbPutTable
*
* PARAMETERS: TableDesc - Table descriptor
*
* RETURN: None
*
* DESCRIPTION: Decrease a reference to a table descriptor and release the
* validated table pointer if no references.
* If the table descriptor is an entry of the root table list,
* this API must be invoked with ACPI_MTX_TABLES acquired.
*
******************************************************************************/

void
AcpiTbPutTable (
ACPI_TABLE_DESC *TableDesc)
{

ACPI_FUNCTION_TRACE (AcpiTbPutTable);


if (TableDesc->ValidationCount == 0)
{
ACPI_WARNING ((AE_INFO,
"Table %p, Validation count is zero before decrement\n",
TableDesc));
return_VOID;
}
TableDesc->ValidationCount--;

if (TableDesc->ValidationCount == 0)
{
/* Table need to be "INVALIDATED" */

AcpiTbInvalidateTable (TableDesc);
}

return_VOID;
}
116 changes: 88 additions & 28 deletions source/components/tables/tbxface.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,11 @@ ACPI_EXPORT_SYMBOL (AcpiGetTableHeader)
*
* DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
* RSDT/XSDT.
* Note that an early stage AcpiGetTable() call must be paired
* with an early stage AcpiPutTable() call. otherwise the table
* pointer mapped by the early stage mapping implementation may be
* erroneously unmapped by the late stage unmapping implementation
* in an AcpiPutTable() invoked during the late stage.
*
******************************************************************************/

Expand All @@ -407,7 +412,8 @@ AcpiGetTable (
{
UINT32 i;
UINT32 j;
ACPI_STATUS Status;
ACPI_STATUS Status = AE_NOT_FOUND;
ACPI_TABLE_DESC *TableDesc;


/* Parameter validation */
Expand All @@ -417,12 +423,22 @@ AcpiGetTable (
return (AE_BAD_PARAMETER);
}

/*
* Note that the following line is required by some OSPMs, they only
* check if the returned table is NULL instead of the returned status
* to determined if this function is succeeded.
*/
*OutTable = NULL;

(void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);

/* Walk the root table list */

for (i = 0, j = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
{
if (!ACPI_COMPARE_NAME (
&(AcpiGbl_RootTableList.Tables[i].Signature), Signature))
TableDesc = &AcpiGbl_RootTableList.Tables[i];

if (!ACPI_COMPARE_NAME (&TableDesc->Signature, Signature))
{
continue;
}
Expand All @@ -432,27 +448,74 @@ AcpiGetTable (
continue;
}

Status = AcpiTbValidateTable (&AcpiGbl_RootTableList.Tables[i]);
if (ACPI_SUCCESS (Status))
Status = AcpiTbGetTable (TableDesc, OutTable);
break;
}

(void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
return (Status);
}

ACPI_EXPORT_SYMBOL (AcpiGetTable)


/*******************************************************************************
*
* FUNCTION: AcpiPutTable
*
* PARAMETERS: Table - The pointer to the table
*
* RETURN: None
*
* DESCRIPTION: Release a table returned by AcpiGetTable() and its clones.
* Note that it is not safe if this function was invoked after an
* uninstallation happened to the original table descriptor.
* Currently there is no OSPMs' requirement to handle such
* situations.
*
******************************************************************************/

void
AcpiPutTable (
ACPI_TABLE_HEADER *Table)
{
UINT32 i;
ACPI_TABLE_DESC *TableDesc;


ACPI_FUNCTION_TRACE (AcpiPutTable);


(void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);

/* Walk the root table list */

for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
{
TableDesc = &AcpiGbl_RootTableList.Tables[i];

if (TableDesc->Pointer != Table)
{
*OutTable = AcpiGbl_RootTableList.Tables[i].Pointer;
continue;
}

return (Status);
AcpiTbPutTable (TableDesc);
break;
}

return (AE_NOT_FOUND);
(void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
return_VOID;
}

ACPI_EXPORT_SYMBOL (AcpiGetTable)
ACPI_EXPORT_SYMBOL (AcpiPutTable)


/*******************************************************************************
*
* FUNCTION: AcpiGetTableByIndex
*
* PARAMETERS: TableIndex - Table index
* Table - Where the pointer to the table is returned
* OutTable - Where the pointer to the table is returned
*
* RETURN: Status and pointer to the requested table
*
Expand All @@ -464,7 +527,7 @@ ACPI_EXPORT_SYMBOL (AcpiGetTable)
ACPI_STATUS
AcpiGetTableByIndex (
UINT32 TableIndex,
ACPI_TABLE_HEADER **Table)
ACPI_TABLE_HEADER **OutTable)
{
ACPI_STATUS Status;

Expand All @@ -474,37 +537,34 @@ AcpiGetTableByIndex (

/* Parameter validation */

if (!Table)
if (!OutTable)
{
return_ACPI_STATUS (AE_BAD_PARAMETER);
}

/*
* Note that the following line is required by some OSPMs, they only
* check if the returned table is NULL instead of the returned status
* to determined if this function is succeeded.
*/
*OutTable = NULL;

(void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);

/* Validate index */

if (TableIndex >= AcpiGbl_RootTableList.CurrentTableCount)
{
(void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
return_ACPI_STATUS (AE_BAD_PARAMETER);
Status = AE_BAD_PARAMETER;
goto UnlockAndExit;
}

if (!AcpiGbl_RootTableList.Tables[TableIndex].Pointer)
{
/* Table is not mapped, map it */

Status = AcpiTbValidateTable (
&AcpiGbl_RootTableList.Tables[TableIndex]);
if (ACPI_FAILURE (Status))
{
(void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
return_ACPI_STATUS (Status);
}
}
Status = AcpiTbGetTable (
&AcpiGbl_RootTableList.Tables[TableIndex], OutTable);

*Table = AcpiGbl_RootTableList.Tables[TableIndex].Pointer;
UnlockAndExit:
(void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
return_ACPI_STATUS (AE_OK);
return_ACPI_STATUS (Status);
}

ACPI_EXPORT_SYMBOL (AcpiGetTableByIndex)
Expand Down
5 changes: 5 additions & 0 deletions source/include/acpixf.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,11 @@ AcpiGetTable (
UINT32 Instance,
ACPI_TABLE_HEADER **OutTable))

ACPI_EXTERNAL_RETURN_VOID (
void
AcpiPutTable (
ACPI_TABLE_HEADER *Table))

ACPI_EXTERNAL_RETURN_STATUS (
ACPI_STATUS
AcpiGetTableByIndex (
Expand Down
9 changes: 9 additions & 0 deletions source/include/actables.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,15 @@ ACPI_STATUS
AcpiTbParseRootTable (
ACPI_PHYSICAL_ADDRESS RsdpAddress);

ACPI_STATUS
AcpiTbGetTable (
ACPI_TABLE_DESC *TableDesc,
ACPI_TABLE_HEADER **OutTable);

void
AcpiTbPutTable (
ACPI_TABLE_DESC *TableDesc);


/*
* tbxfload
Expand Down
1 change: 1 addition & 0 deletions source/include/actbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ typedef struct acpi_table_desc
ACPI_NAME_UNION Signature;
ACPI_OWNER_ID OwnerId;
UINT8 Flags;
UINT16 ValidationCount;

} ACPI_TABLE_DESC;

Expand Down

0 comments on commit cac6790

Please sign in to comment.