ACK: [PATCH] acpi: fwts_acpi_tables: fix up missing FACS (LP: #1284097)

IvanHu ivan.hu at canonical.com
Tue Mar 4 02:57:11 UTC 2014


On 02/24/2014 11:58 PM, Colin King wrote:
> From: Colin Ian King <colin.king at canonical.com>
>
> If fwts loads ACPI tables from file that don't have an FACS
> we get all sorts of weird issues, for example, we are missing
> the global lock. The best bet is to fix this table up by hand
> and warn about this rather than cause all sorts of false
> positives on the method tests.
>
> This patch also re-works the table fixup to ensure we fixup
> with the correct fixed-up table addresses for any tables that
> we have to create because they are missing.
>
> Signed-off-by: Colin Ian King <colin.king at canonical.com>
> ---
>   src/lib/src/fwts_acpi_tables.c | 121 +++++++++++++++++++++++++++++------------
>   1 file changed, 86 insertions(+), 35 deletions(-)
>
> diff --git a/src/lib/src/fwts_acpi_tables.c b/src/lib/src/fwts_acpi_tables.c
> index 0a656cd..cccf9ba 100644
> --- a/src/lib/src/fwts_acpi_tables.c
> +++ b/src/lib/src/fwts_acpi_tables.c
> @@ -625,44 +625,62 @@ static bool fwts_acpi_table_fixable(fwts_acpi_table_info *table)
>    */
>   static int fwts_acpi_load_tables_fixup(fwts_framework *fw)
>   {
> -	int i;
> -	int j;
> -	int count;
> +	int i, j, count;
>   	char *oem_tbl_id = "FWTS    ";
>   	fwts_acpi_table_info *table;
>   	fwts_acpi_table_rsdp *rsdp = NULL;
>   	fwts_acpi_table_rsdt *rsdt = NULL;
>   	fwts_acpi_table_xsdt *xsdt = NULL;
>   	fwts_acpi_table_fadt *fadt = NULL;
> +	fwts_acpi_table_facs *facs = NULL;
> +	uint64_t rsdt_fake_addr = 0, xsdt_fake_addr = 0;
>
>   	/* Fetch the OEM Table ID */
> -	if (fwts_acpi_find_table(fw, "FACP", 0, &table) != FWTS_OK)
> +	if (fwts_acpi_find_table(fw, "FACP", 0, &table) != FWTS_OK) {
> +		fwts_log_error(fw, "ACPI table find failure.");
>   		return FWTS_ERROR;
> +	}
>   	if (table) {
>   		fadt = (fwts_acpi_table_fadt *)table->data;
>   		oem_tbl_id = fadt->header.oem_tbl_id;
> -	}
> -
> -	/* Get RSDP */
> -	if (fwts_acpi_find_table(fw, "RSDP", 0, &table) != FWTS_OK)
> +	} else {
> +		fwts_log_error(fw, "Cannot find FACP.");
>   		return FWTS_ERROR;
> -	if (table)
> -		rsdp = (fwts_acpi_table_rsdp *)table->data;
> -
> -	/* Get RSDT */
> -	if (fwts_acpi_find_table(fw, "RSDT", 0, &table) != FWTS_OK)
> -		return FWTS_ERROR;
> -	if (table)
> -		rsdt = (fwts_acpi_table_rsdt *)table->data;
> +	}
>
> -	/* Get XSDT */
> -	if (fwts_acpi_find_table(fw, "XSDT", 0, &table) != FWTS_OK)
> +	/* Get FACS */
> +	if (fwts_acpi_find_table(fw, "FACS", 0, &table) != FWTS_OK) {
> +		fwts_log_error(fw, "ACPI table find failure.");
>   		return FWTS_ERROR;
> +	}
>   	if (table)
> -		xsdt = (fwts_acpi_table_xsdt *)table->data;
> +		facs = (fwts_acpi_table_facs *)table->data;
> +	else {
> +		size_t size = 64;
> +		uint64_t facs_fake_addr;
> +
> +		/* This is most unexpected, so warn about it */
> +		fwts_log_warning(fw, "No FACS found, fwts has faked one instead.");
> +		if ((facs = fwts_low_calloc(1, size)) == NULL) {
> +			fwts_log_error(fw, "Cannot allocate fake FACS.");
> +			return FWTS_ERROR;
> +		}
> +		strncpy(facs->signature, "FACS", 4);
> +		facs->length = size;
> +		facs->hardware_signature = 0xf000a200;	/* Some signature */
> +		facs->flags = 0;
> +		facs->version = 2;
> +		facs_fake_addr = fwts_fake_physical_addr(size);
> +		fadt->firmware_control = (uint32_t)facs_fake_addr;
> +		if (fadt->header.length >= 140)
> +			fadt->x_firmware_ctrl = (uint64_t)facs_fake_addr;
> +
> +		fwts_acpi_add_table("FACS", facs, (uint64_t)facs_fake_addr,
> +			size, FWTS_ACPI_TABLE_FROM_FIXUP);
> +	}
>
>   	/* Figure out how many tables we need to put into RSDT and XSDT */
> -	for (count=0,i=0;;i++) {
> +	for (count = 0, i = 0; ; i++) {
>   		if (fwts_acpi_get_table(fw, i, &table) != FWTS_OK)
>   			break;
>   		if (table == NULL)	/* No more tables */
> @@ -671,11 +689,22 @@ static int fwts_acpi_load_tables_fixup(fwts_framework *fw)
>   			count++;
>   	}
>
> -	/* No RSDT? go and fake one */
> -	if (rsdt == NULL) {
> +	/* Get RSDT */
> +	if (fwts_acpi_find_table(fw, "RSDT", 0, &table) != FWTS_OK) {
> +		fwts_log_error(fw, "ACPI table find failure.");
> +		return FWTS_ERROR;
> +	}
> +	if (table) {
> +		rsdt = (fwts_acpi_table_rsdt *)table->data;
> +		rsdt_fake_addr = table->addr;
> +	} else {
> +		/* No RSDT? go and fake one */
>   		size_t size = sizeof(fwts_acpi_table_rsdt) + (count * sizeof(uint32_t));
> -		if ((rsdt = fwts_low_calloc(1, size)) == NULL)
> +
> +		if ((rsdt = fwts_low_calloc(1, size)) == NULL) {
> +			fwts_log_error(fw, "Cannot allocate fake RSDT.");
>   			return FWTS_ERROR;
> +		}
>
>   		for (i=0,j=0; j<count ;i++)
>   			if (fwts_acpi_get_table(fw, i, &table) == FWTS_OK)
> @@ -692,15 +721,26 @@ static int fwts_acpi_load_tables_fixup(fwts_framework *fw)
>   		rsdt->header.creator_revision = 1;
>   		rsdt->header.checksum = 256 - fwts_checksum((uint8_t*)rsdt, size);
>
> -		fwts_acpi_add_table("RSDT", rsdt, (uint64_t)fwts_fake_physical_addr(size),
> -			size, FWTS_ACPI_TABLE_FROM_FIXUP);
> +		rsdt_fake_addr = fwts_fake_physical_addr(size);
> +		fwts_acpi_add_table("RSDT", rsdt, rsdt_fake_addr, size, FWTS_ACPI_TABLE_FROM_FIXUP);
>   	}
>
> -	/* No XSDT? go and fake one */
> -	if (xsdt == NULL) {
> +	/* Get XSDT */
> +	if (fwts_acpi_find_table(fw, "XSDT", 0, &table) != FWTS_OK) {
> +		fwts_log_error(fw, "ACPI table find failure.");
> +		return FWTS_ERROR;
> +	}
> +	if (table) {
> +		xsdt = (fwts_acpi_table_xsdt *)table->data;
> +		xsdt_fake_addr = table->addr;
> +	} else {
> +		/* No XSDT? go and fake one */
>   		size_t size = sizeof(fwts_acpi_table_rsdt) + (count * sizeof(uint64_t));
> -		if ((xsdt = fwts_low_calloc(1, size)) == NULL)
> +
> +		if ((xsdt = fwts_low_calloc(1, size)) == NULL) {
> +			fwts_log_error(fw, "Cannot allocate fake XSDT.");
>   			return FWTS_ERROR;
> +		}
>
>   		for (i=0,j=0; j<count ;i++)
>   			if (fwts_acpi_get_table(fw, i, &table) == FWTS_OK)
> @@ -717,22 +757,28 @@ static int fwts_acpi_load_tables_fixup(fwts_framework *fw)
>   		xsdt->header.creator_revision = 1;
>   		xsdt->header.checksum = 256 - fwts_checksum((uint8_t*)xsdt, size);
>
> -		fwts_acpi_add_table("XSDT", xsdt, (uint64_t)fwts_fake_physical_addr(size),
> -			size, FWTS_ACPI_TABLE_FROM_FIXUP);
> +		xsdt_fake_addr = fwts_fake_physical_addr(size);
> +		fwts_acpi_add_table("XSDT", xsdt, xsdt_fake_addr, size, FWTS_ACPI_TABLE_FROM_FIXUP);
>   	}
>
> -	/* No RSDP? go and fake one */
> -	if (rsdp == NULL) {
> +	/* Get RSDP */
> +	if (fwts_acpi_find_table(fw, "RSDP", 0, &table) != FWTS_OK)
> +		return FWTS_ERROR;
> +	if (table)
> +		rsdp = (fwts_acpi_table_rsdp *)table->data;
> +	else {
> +		/* No RSDP? go and fake one */
>   		size_t size = sizeof(fwts_acpi_table_rsdp);
> -		if ((rsdp = fwts_low_calloc(1, size)) == NULL)
> +
> +		if ((rsdp = fwts_low_calloc(1, size)) == NULL) {
> +			fwts_log_error(fw, "Cannot allocate fake RSDP.");
>   			return FWTS_ERROR;
> +		}
>
>   		strncpy(rsdp->signature, "RSD PTR ", 8);
>   		strncpy(rsdp->oem_id, "FWTS  ", 6);
>   		rsdp->revision = 2;
> -		rsdp->rsdt_address = (unsigned long)rsdt;
>   		rsdp->length = sizeof(fwts_acpi_table_rsdp);
> -		rsdp->xsdt_address = (uint64_t)(unsigned long)xsdt;
>   		rsdp->reserved[0] = 0;
>   		rsdp->reserved[1] = 0;
>   		rsdp->reserved[2] = 0;
> @@ -743,6 +789,11 @@ static int fwts_acpi_load_tables_fixup(fwts_framework *fw)
>   		fwts_acpi_add_table("RSDP", rsdp, (uint64_t)fwts_fake_physical_addr(size),
>   			sizeof(fwts_acpi_table_rsdp), FWTS_ACPI_TABLE_FROM_FIXUP);
>   	}
> +
> +	/* Now we have all the tables, final fix up is required */
> +	rsdp->rsdt_address = rsdt_fake_addr;
> +	rsdp->xsdt_address = xsdt_fake_addr;
> +
>   	return FWTS_OK;
>   }
>
>

Acked-by: Ivan Hu <ivan.hu at canonical.com>



More information about the fwts-devel mailing list