错误日志:
ACPI Error: Table [PPTT] is not invalidated during early boot stage (20180810/tbxface-165)
linux版本:4.19(注意:以下所有代码虽然是linux-4.19,但是与主线版本不同,只能作为参考)
首先查询到此日志在linux代码中的位置,位于“drivers/acpi/acpica/tbxface.c”文件的164行,相关代码块如下:
/*
* Ensure OS early boot logic, which is required by some hosts. If the
* table state is reported to be wrong, developers should fix the
* issue by invoking acpi_put_table() for the reported table during the
* early stage.
*/
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
table_desc = &acpi_gbl_root_table_list.tables[i];
if (table_desc->pointer) {
ACPI_ERROR((AE_INFO,
"Table [%4.4s] is not invalidated during early boot stage",
table_desc->signature.ascii));
}
}
在此处有一段注释,大意是如果ACPI表状态出错,要检查“acpi_put_table()”函数。那么这个函数是什么呢?
此函数也位于“drivers/acpi/acpica/tbxface.c”文件,在359行。函数的注释如下:
/*******************************************************************************
*
* FUNCTION: acpi_put_table
*
* PARAMETERS: table - The pointer to the table
*
* RETURN: None
*
* DESCRIPTION: Release a table returned by acpi_get_table() 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 acpi_put_table(struct acpi_table_header *table)
"acpi_put_table()"用来释放由“acpi_get_table()”获取的表。那就看看"acpi_get_table()"函数,位于“drivers/acpi/acpica/tbxface.c”文件297行:
/*******************************************************************************
*
* FUNCTION: acpi_get_table
*
* PARAMETERS: signature - ACPI signature of needed table
* instance - Which instance (for SSDTs)
* out_table - Where the pointer to the table is returned
*
* RETURN: Status and pointer to the requested table
*
* DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
* RSDT/XSDT.
* Note that an early stage acpi_get_table() call must be paired
* with an early stage acpi_put_table() call. otherwise the table
* pointer mapped by the early stage mapping implementation may be
* erroneously unmapped by the late stage unmapping implementation
* in an acpi_put_table() invoked during the late stage.
*
******************************************************************************/
acpi_status
acpi_get_table(char *signature,
u32 instance, struct acpi_table_header ** out_table)
很明显,这里的注释告诉我们,“acpi_get_table()”和“acpi_put_table()”要配对使用。再来看一个“acpi_put_table()”调用的函数“acpi_tb_put_table()”:
void acpi_tb_put_table(struct acpi_table_desc *table_desc)
{
ACPI_FUNCTION_TRACE(acpi_tb_put_table);
if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
table_desc->validation_count--;
/*
* Detect validation_count underflows to ensure that the warning
* message will only be printed once.
*/
if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
ACPI_WARNING((AE_INFO,
"Table %p, Validation count underflows\n",
table_desc));
return_VOID;
}
}
if (table_desc->validation_count == 0) {
/* Table need to be "INVALIDATED" */
acpi_tb_invalidate_table(table_desc);
}
return_VOID;
}
最后面的注释说“Table need to be “INVALIDATED””,和错误“ACPI Error: Table [PPTT] is not invalidated during early boot stage (20180810/tbxface-165)”中的信息对上了,因此大概率就可以猜测是很有可能是某处代码没有将“Table”释放,造成这个错误。接下来就查找调用了“acpi_get_table()”的函数,看看存不存在直接返回没有释放“Table”或者干脆就没调用“acpi_put_table()”的情况。
很幸运,很快就找到了,位于“drivers/acpi/pptt.c”的"find_acpi_cpu_id()"函数,以下为此函数的代码:
/*
* find_acpi_cpu_id() - Determine a unique cpu signature
* Return 0 if found a matched cpu.
*/
int find_acpi_cpu_id(bool (*match_f)(struct acpi_pptt_id *))
{
struct acpi_table_header *table_hdr;
struct acpi_subtable_header *entry;
struct acpi_pptt_id *cpu_id;
u32 id_sz;
unsigned long table_end;
acpi_status status;
status = acpi_get_table(ACPI_SIG_PPTT, 0, &table_hdr);
if (ACPI_FAILURE(status)) {
pr_warn_once("No PPTT table found, can't find cpu id through acpi\n");
return -ENOENT;
}
table_end = (unsigned long)table_hdr + table_hdr->length;
entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr,
sizeof(struct acpi_table_pptt));
id_sz = sizeof(struct acpi_pptt_id *);
/* iterate the tables until find an expected cpu signature */
while ((unsigned long)entry + id_sz < table_end) {
cpu_id = (struct acpi_pptt_id *)entry;
if (entry->length == 0) {
pr_warn("Invalid zero length subtable\n");
return -EINVAL;
}
if (entry->type == ACPI_PPTT_TYPE_ID && match_f(cpu_id))
return 0;
entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry,
entry->length);
}
return -1;
}
可以看到没有使用“acpi_put_table()”,修改结果如下,这是使用"git diff"生成的文件,可以看到修改前后对比:
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index f6d640acff5f..036bf8ed13e9 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -909,6 +909,7 @@ int find_acpi_cpu_id(bool (*match_f)(struct acpi_pptt_id *))
u32 id_sz;
unsigned long table_end;
acpi_status status;
+ int ret = -1;
status = acpi_get_table(ACPI_SIG_PPTT, 0, &table_hdr);
if (ACPI_FAILURE(status)) {
@@ -927,15 +928,19 @@ int find_acpi_cpu_id(bool (*match_f)(struct acpi_pptt_id *))
if (entry->length == 0) {
pr_warn("Invalid zero length subtable\n");
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
- if (entry->type == ACPI_PPTT_TYPE_ID && match_f(cpu_id))
- return 0;
+ if (entry->type == ACPI_PPTT_TYPE_ID && match_f(cpu_id)){
+ ret = 0;
+ break;
+ }
entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry,
entry->length);
}
- return -1;
+ acpi_put_table(table_hdr);
+ return ret;
}