diff mbox

[RESEND] Allow RSDP to be provided manually or scan for it in klog (LP: #1260400)

Message ID 1386879568-31608-1-git-send-email-colin.king@canonical.com
State Accepted
Headers show

Commit Message

Colin Ian King Dec. 12, 2013, 8:19 p.m. UTC
From: Colin Ian King <colin.king@canonical.com>

During work on an early development machine we found a situation where
the RSDP could not be automatically probed using the current methods.
So, allow the RSDP to be specified either manually using the new -R or
--rsdp options or found by scanning the kernel log (ugly, but is our
final easy option).

We should also sanity check the RDSP by ensuring it lies on a 16 byte
boundary and contains a valid signature.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 doc/fwts.1                       |  4 +++
 src/lib/include/fwts_framework.h |  1 +
 src/lib/src/fwts_acpi_tables.c   | 64 +++++++++++++++++++++++++++++++++-------
 src/lib/src/fwts_framework.c     |  7 +++++
 4 files changed, 66 insertions(+), 10 deletions(-)

Comments

Ivan Hu Dec. 16, 2013, 3:29 a.m. UTC | #1
On 12/13/2013 04:19 AM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> During work on an early development machine we found a situation where
> the RSDP could not be automatically probed using the current methods.
> So, allow the RSDP to be specified either manually using the new -R or
> --rsdp options or found by scanning the kernel log (ugly, but is our
> final easy option).
>
> We should also sanity check the RDSP by ensuring it lies on a 16 byte
> boundary and contains a valid signature.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>   doc/fwts.1                       |  4 +++
>   src/lib/include/fwts_framework.h |  1 +
>   src/lib/src/fwts_acpi_tables.c   | 64 +++++++++++++++++++++++++++++++++-------
>   src/lib/src/fwts_framework.c     |  7 +++++
>   4 files changed, 66 insertions(+), 10 deletions(-)
>
> diff --git a/doc/fwts.1 b/doc/fwts.1
> index 234278d..a12aca9 100644
> --- a/doc/fwts.1
> +++ b/doc/fwts.1
> @@ -201,6 +201,10 @@ no pretty printing of horizontal separators in the results log file.
>   specify the results output log file.
>   One can also specify stdout and stderr to redirect to these output streams.
>   .TP
> +.B \-R, \-\-rsdp=physaddr
> +specify the physical address of ACPI RSDP. This is useful on some systems where
> +it cannot be automatically detected.
> +.TP
>   .B \-\-s3\-delay\-delta=N
>   time to be added onto delay between each S3 iteration.
>   .TP
> diff --git a/src/lib/include/fwts_framework.h b/src/lib/include/fwts_framework.h
> index f365d74..1e5171c 100644
> --- a/src/lib/include/fwts_framework.h
> +++ b/src/lib/include/fwts_framework.h
> @@ -144,6 +144,7 @@ typedef struct {
>   	fwts_list errors_filter_discard;	/* Results to discard, empty = discard none */
>   	bool error_filtered_out;		/* True if a klog message has been filtered out */
>   	fwts_acpica_mode acpica_mode;		/* ACPICA mode flags */
> +	void *rsdp;				/* ACPI RSDP address */
>   } fwts_framework;
>
>   typedef struct {
> diff --git a/src/lib/src/fwts_acpi_tables.c b/src/lib/src/fwts_acpi_tables.c
> index 6f1e964..f9f6ba0 100644
> --- a/src/lib/src/fwts_acpi_tables.c
> +++ b/src/lib/src/fwts_acpi_tables.c
> @@ -52,6 +52,34 @@ static void *fwts_acpi_find_rsdp_efi(void)
>   }
>
>   /*
> + *  fwts_acpi_find_rsdp_klog()
> + *	Get RSDP by parsing kernel log
> + */
> +static void *fwts_acpi_find_rsdp_klog(void)
> +{
> +	fwts_list *klog;
> +	fwts_list_link *item;
> +	void *rsdp = NULL;
> +
> +	if ((klog = fwts_klog_read()) == NULL)
> +		return NULL;
> +
> +	fwts_list_foreach(item, klog) {
> +		char *text = fwts_text_list_text(item);
> +		char *ptr = strstr(text, "ACPI: RSDP");
> +
> +		if (ptr) {
> +			rsdp = (void *)strtoul(ptr + 11, NULL, 16);
> +			break;
> +		}
> +	}
> +
> +	fwts_text_list_free(klog);
> +
> +	return rsdp;
> +}
> +
> +/*
>    *  fwts_acpi_find_rsdp_bios()
>    *	Find RSDP address by scanning BIOS memory
>    */
> @@ -94,21 +122,26 @@ static void *fwts_acpi_find_rsdp_bios(void)
>   static fwts_acpi_table_rsdp *fwts_acpi_get_rsdp(void *addr, size_t *rsdp_len)
>   {
>   	uint8_t *mem;
> -	fwts_acpi_table_rsdp *rsdp;
> +	fwts_acpi_table_rsdp *rsdp = NULL;
>   	*rsdp_len = 0;
>
>   	if ((mem = fwts_mmap((off_t)addr, sizeof(fwts_acpi_table_rsdp))) == FWTS_MAP_FAILED)
>   		return NULL;
>
> -	/* Determine original RSDP size from revision. */
>   	rsdp = (fwts_acpi_table_rsdp*)mem;
> +	/* Determine original RSDP size from revision. */
>   	*rsdp_len = (rsdp->revision < 1) ? 20 : 36;
>
> +	/* Must have the correct signature */
> +	if (strncmp(rsdp->signature, "RSD PTR ", 8))
> +		goto out;
> +
>   	/* Assume version 2.0 size, we don't care about a few bytes over allocation if it's version 1.0 */
>   	if ((rsdp = (fwts_acpi_table_rsdp*)fwts_low_calloc(1, sizeof(fwts_acpi_table_rsdp))) == NULL)
> -		return NULL;
> +		goto out;
>
>   	memcpy(rsdp, mem, *rsdp_len);
> +out:
>   	(void)fwts_munmap(mem, sizeof(fwts_acpi_table_rsdp));
>
>   	return rsdp;
> @@ -238,22 +271,33 @@ static void fwts_acpi_handle_fadt(fwts_acpi_table_fadt *fadt, fwts_acpi_table_pr
>    *  fwts_acpi_load_tables_from_firmware()
>    *  	Load up cached copies of all the ACPI tables
>    */
> -static int fwts_acpi_load_tables_from_firmware(void)
> +static int fwts_acpi_load_tables_from_firmware(fwts_framework *fw)
>   {
>   	fwts_acpi_table_rsdp *rsdp;
>   	fwts_acpi_table_xsdt *xsdt;
>   	fwts_acpi_table_rsdt *rsdt;
>   	fwts_acpi_table_header *header;
>
> -	void *	rsdp_addr;
> +	void *	rsdp_addr = NULL;
>   	size_t	rsdp_len;
>   	int 	num_entries;
>   	int 	i;
>
> -	/* Check for RSDP in EFI, then BIOS, if not found, give up */
> -	if ((rsdp_addr = fwts_acpi_find_rsdp_efi()) == NULL)
> -		if ((rsdp_addr = fwts_acpi_find_rsdp_bios()) == NULL)
> -			return FWTS_ERROR;
> +	/* Check for RSDP as EFI, then BIOS, parsed klog, if not found, give up */
> +	if (fw->rsdp)
> +		rsdp_addr = (void*)fw->rsdp;
> +	if (!rsdp_addr)
> +		rsdp_addr = fwts_acpi_find_rsdp_efi();
> +	if (!rsdp_addr)
> +		rsdp_addr = fwts_acpi_find_rsdp_bios();
> +	if (!rsdp_addr)
> +		rsdp_addr = fwts_acpi_find_rsdp_klog();
> +	if (!rsdp_addr)
> +		return FWTS_ERROR;
> +
> +	/* Must be on a 16 byte boundary */
> +	if (((unsigned long)rsdp_addr & 0xf))
> +		return FWTS_ERROR;
>
>   	/* Load and save cached RSDP */
>   	if ((rsdp = fwts_acpi_get_rsdp(rsdp_addr, &rsdp_len)) == NULL)
> @@ -712,7 +756,7 @@ int fwts_acpi_load_tables(fwts_framework *fw)
>   	else if (fw->acpi_table_acpidump_file != NULL)
>   		ret = fwts_acpi_load_tables_from_acpidump(fw);
>   	else if (fwts_check_root_euid(fw, true) == FWTS_OK)
> -		ret = fwts_acpi_load_tables_from_firmware();
> +		ret = fwts_acpi_load_tables_from_firmware(fw);
>   	else
>   		ret = FWTS_ERROR_NO_PRIV;
>
> diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c
> index eae5907..92aa74d 100644
> --- a/src/lib/src/fwts_framework.c
> +++ b/src/lib/src/fwts_framework.c
> @@ -83,6 +83,7 @@ static fwts_option fwts_framework_options[] = {
>   	{ "acpica-debug",	"",   0, "Enable ACPICA debug/warning messages." },
>   	{ "acpica",		"",   1, "Enable ACPICA run time options." },
>   	{ "uefi",		"",   0, "Run UEFI tests." },
> +	{ "rsdp",		"R:", 1, "Specify the physical address of the ACPI RSDP." },
>   	{ NULL, NULL, 0, NULL }
>   };
>
> @@ -1138,6 +1139,9 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
>   		case 38: /* --uefi */
>   			fw->flags |= FWTS_FLAG_TEST_UEFI;
>   			break;
> +		case 39: /* --rsdp */
> +			fw->rsdp = (void *)strtoul(optarg, NULL, 0);
> +			break;
>   		}
>   		break;
>   	case 'a': /* --all */
> @@ -1214,6 +1218,9 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
>   	case 'w': /* --log-width=N */
>   		fwts_log_set_line_width(atoi(optarg));
>   		break;
> +	case 'R': /* --rsdp=addr */
> +		fw->rsdp = (void *)strtoul(optarg, NULL, 0);
> +		break;
>   	}
>   	return FWTS_OK;
>   }
>

Acked-by: Ivan Hu <ivan.hu@canonical.com>
Keng-Yu Lin Dec. 20, 2013, 9:15 a.m. UTC | #2
On Mon, Dec 16, 2013 at 11:29 AM, IvanHu <ivan.hu@canonical.com> wrote:
> On 12/13/2013 04:19 AM, Colin King wrote:
>>
>> From: Colin Ian King <colin.king@canonical.com>
>>
>> During work on an early development machine we found a situation where
>> the RSDP could not be automatically probed using the current methods.
>> So, allow the RSDP to be specified either manually using the new -R or
>> --rsdp options or found by scanning the kernel log (ugly, but is our
>> final easy option).
>>
>> We should also sanity check the RDSP by ensuring it lies on a 16 byte
>> boundary and contains a valid signature.
>>
>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>> ---
>>   doc/fwts.1                       |  4 +++
>>   src/lib/include/fwts_framework.h |  1 +
>>   src/lib/src/fwts_acpi_tables.c   | 64
>> +++++++++++++++++++++++++++++++++-------
>>   src/lib/src/fwts_framework.c     |  7 +++++
>>   4 files changed, 66 insertions(+), 10 deletions(-)
>>
>> diff --git a/doc/fwts.1 b/doc/fwts.1
>> index 234278d..a12aca9 100644
>> --- a/doc/fwts.1
>> +++ b/doc/fwts.1
>> @@ -201,6 +201,10 @@ no pretty printing of horizontal separators in the
>> results log file.
>>   specify the results output log file.
>>   One can also specify stdout and stderr to redirect to these output
>> streams.
>>   .TP
>> +.B \-R, \-\-rsdp=physaddr
>> +specify the physical address of ACPI RSDP. This is useful on some systems
>> where
>> +it cannot be automatically detected.
>> +.TP
>>   .B \-\-s3\-delay\-delta=N
>>   time to be added onto delay between each S3 iteration.
>>   .TP
>> diff --git a/src/lib/include/fwts_framework.h
>> b/src/lib/include/fwts_framework.h
>> index f365d74..1e5171c 100644
>> --- a/src/lib/include/fwts_framework.h
>> +++ b/src/lib/include/fwts_framework.h
>> @@ -144,6 +144,7 @@ typedef struct {
>>         fwts_list errors_filter_discard;        /* Results to discard,
>> empty = discard none */
>>         bool error_filtered_out;                /* True if a klog message
>> has been filtered out */
>>         fwts_acpica_mode acpica_mode;           /* ACPICA mode flags */
>> +       void *rsdp;                             /* ACPI RSDP address */
>>   } fwts_framework;
>>
>>   typedef struct {
>> diff --git a/src/lib/src/fwts_acpi_tables.c
>> b/src/lib/src/fwts_acpi_tables.c
>> index 6f1e964..f9f6ba0 100644
>> --- a/src/lib/src/fwts_acpi_tables.c
>> +++ b/src/lib/src/fwts_acpi_tables.c
>> @@ -52,6 +52,34 @@ static void *fwts_acpi_find_rsdp_efi(void)
>>   }
>>
>>   /*
>> + *  fwts_acpi_find_rsdp_klog()
>> + *     Get RSDP by parsing kernel log
>> + */
>> +static void *fwts_acpi_find_rsdp_klog(void)
>> +{
>> +       fwts_list *klog;
>> +       fwts_list_link *item;
>> +       void *rsdp = NULL;
>> +
>> +       if ((klog = fwts_klog_read()) == NULL)
>> +               return NULL;
>> +
>> +       fwts_list_foreach(item, klog) {
>> +               char *text = fwts_text_list_text(item);
>> +               char *ptr = strstr(text, "ACPI: RSDP");
>> +
>> +               if (ptr) {
>> +                       rsdp = (void *)strtoul(ptr + 11, NULL, 16);
>> +                       break;
>> +               }
>> +       }
>> +
>> +       fwts_text_list_free(klog);
>> +
>> +       return rsdp;
>> +}
>> +
>> +/*
>>    *  fwts_acpi_find_rsdp_bios()
>>    *    Find RSDP address by scanning BIOS memory
>>    */
>> @@ -94,21 +122,26 @@ static void *fwts_acpi_find_rsdp_bios(void)
>>   static fwts_acpi_table_rsdp *fwts_acpi_get_rsdp(void *addr, size_t
>> *rsdp_len)
>>   {
>>         uint8_t *mem;
>> -       fwts_acpi_table_rsdp *rsdp;
>> +       fwts_acpi_table_rsdp *rsdp = NULL;
>>         *rsdp_len = 0;
>>
>>         if ((mem = fwts_mmap((off_t)addr, sizeof(fwts_acpi_table_rsdp)))
>> == FWTS_MAP_FAILED)
>>                 return NULL;
>>
>> -       /* Determine original RSDP size from revision. */
>>         rsdp = (fwts_acpi_table_rsdp*)mem;
>> +       /* Determine original RSDP size from revision. */
>>         *rsdp_len = (rsdp->revision < 1) ? 20 : 36;
>>
>> +       /* Must have the correct signature */
>> +       if (strncmp(rsdp->signature, "RSD PTR ", 8))
>> +               goto out;
>> +
>>         /* Assume version 2.0 size, we don't care about a few bytes over
>> allocation if it's version 1.0 */
>>         if ((rsdp = (fwts_acpi_table_rsdp*)fwts_low_calloc(1,
>> sizeof(fwts_acpi_table_rsdp))) == NULL)
>> -               return NULL;
>> +               goto out;
>>
>>         memcpy(rsdp, mem, *rsdp_len);
>> +out:
>>         (void)fwts_munmap(mem, sizeof(fwts_acpi_table_rsdp));
>>
>>         return rsdp;
>> @@ -238,22 +271,33 @@ static void
>> fwts_acpi_handle_fadt(fwts_acpi_table_fadt *fadt, fwts_acpi_table_pr
>>    *  fwts_acpi_load_tables_from_firmware()
>>    *    Load up cached copies of all the ACPI tables
>>    */
>> -static int fwts_acpi_load_tables_from_firmware(void)
>> +static int fwts_acpi_load_tables_from_firmware(fwts_framework *fw)
>>   {
>>         fwts_acpi_table_rsdp *rsdp;
>>         fwts_acpi_table_xsdt *xsdt;
>>         fwts_acpi_table_rsdt *rsdt;
>>         fwts_acpi_table_header *header;
>>
>> -       void *  rsdp_addr;
>> +       void *  rsdp_addr = NULL;
>>         size_t  rsdp_len;
>>         int     num_entries;
>>         int     i;
>>
>> -       /* Check for RSDP in EFI, then BIOS, if not found, give up */
>> -       if ((rsdp_addr = fwts_acpi_find_rsdp_efi()) == NULL)
>> -               if ((rsdp_addr = fwts_acpi_find_rsdp_bios()) == NULL)
>> -                       return FWTS_ERROR;
>> +       /* Check for RSDP as EFI, then BIOS, parsed klog, if not found,
>> give up */
>> +       if (fw->rsdp)
>> +               rsdp_addr = (void*)fw->rsdp;
>> +       if (!rsdp_addr)
>> +               rsdp_addr = fwts_acpi_find_rsdp_efi();
>> +       if (!rsdp_addr)
>> +               rsdp_addr = fwts_acpi_find_rsdp_bios();
>> +       if (!rsdp_addr)
>> +               rsdp_addr = fwts_acpi_find_rsdp_klog();
>> +       if (!rsdp_addr)
>> +               return FWTS_ERROR;
>> +
>> +       /* Must be on a 16 byte boundary */
>> +       if (((unsigned long)rsdp_addr & 0xf))
>> +               return FWTS_ERROR;
>>
>>         /* Load and save cached RSDP */
>>         if ((rsdp = fwts_acpi_get_rsdp(rsdp_addr, &rsdp_len)) == NULL)
>> @@ -712,7 +756,7 @@ int fwts_acpi_load_tables(fwts_framework *fw)
>>         else if (fw->acpi_table_acpidump_file != NULL)
>>                 ret = fwts_acpi_load_tables_from_acpidump(fw);
>>         else if (fwts_check_root_euid(fw, true) == FWTS_OK)
>> -               ret = fwts_acpi_load_tables_from_firmware();
>> +               ret = fwts_acpi_load_tables_from_firmware(fw);
>>         else
>>                 ret = FWTS_ERROR_NO_PRIV;
>>
>> diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c
>> index eae5907..92aa74d 100644
>> --- a/src/lib/src/fwts_framework.c
>> +++ b/src/lib/src/fwts_framework.c
>> @@ -83,6 +83,7 @@ static fwts_option fwts_framework_options[] = {
>>         { "acpica-debug",       "",   0, "Enable ACPICA debug/warning
>> messages." },
>>         { "acpica",             "",   1, "Enable ACPICA run time options."
>> },
>>         { "uefi",               "",   0, "Run UEFI tests." },
>> +       { "rsdp",               "R:", 1, "Specify the physical address of
>> the ACPI RSDP." },
>>         { NULL, NULL, 0, NULL }
>>   };
>>
>> @@ -1138,6 +1139,9 @@ int fwts_framework_options_handler(fwts_framework
>> *fw, int argc, char * const ar
>>                 case 38: /* --uefi */
>>                         fw->flags |= FWTS_FLAG_TEST_UEFI;
>>                         break;
>> +               case 39: /* --rsdp */
>> +                       fw->rsdp = (void *)strtoul(optarg, NULL, 0);
>> +                       break;
>>                 }
>>                 break;
>>         case 'a': /* --all */
>> @@ -1214,6 +1218,9 @@ int fwts_framework_options_handler(fwts_framework
>> *fw, int argc, char * const ar
>>         case 'w': /* --log-width=N */
>>                 fwts_log_set_line_width(atoi(optarg));
>>                 break;
>> +       case 'R': /* --rsdp=addr */
>> +               fw->rsdp = (void *)strtoul(optarg, NULL, 0);
>> +               break;
>>         }
>>         return FWTS_OK;
>>   }
>>
>
> Acked-by: Ivan Hu <ivan.hu@canonical.com>
>

Acked-by: Keng-Yu Lin <kengyu@canonical.com>
diff mbox

Patch

diff --git a/doc/fwts.1 b/doc/fwts.1
index 234278d..a12aca9 100644
--- a/doc/fwts.1
+++ b/doc/fwts.1
@@ -201,6 +201,10 @@  no pretty printing of horizontal separators in the results log file.
 specify the results output log file.
 One can also specify stdout and stderr to redirect to these output streams.
 .TP
+.B \-R, \-\-rsdp=physaddr
+specify the physical address of ACPI RSDP. This is useful on some systems where
+it cannot be automatically detected.
+.TP
 .B \-\-s3\-delay\-delta=N
 time to be added onto delay between each S3 iteration.
 .TP
diff --git a/src/lib/include/fwts_framework.h b/src/lib/include/fwts_framework.h
index f365d74..1e5171c 100644
--- a/src/lib/include/fwts_framework.h
+++ b/src/lib/include/fwts_framework.h
@@ -144,6 +144,7 @@  typedef struct {
 	fwts_list errors_filter_discard;	/* Results to discard, empty = discard none */
 	bool error_filtered_out;		/* True if a klog message has been filtered out */
 	fwts_acpica_mode acpica_mode;		/* ACPICA mode flags */
+	void *rsdp;				/* ACPI RSDP address */
 } fwts_framework;
 
 typedef struct {
diff --git a/src/lib/src/fwts_acpi_tables.c b/src/lib/src/fwts_acpi_tables.c
index 6f1e964..f9f6ba0 100644
--- a/src/lib/src/fwts_acpi_tables.c
+++ b/src/lib/src/fwts_acpi_tables.c
@@ -52,6 +52,34 @@  static void *fwts_acpi_find_rsdp_efi(void)
 }
 
 /*
+ *  fwts_acpi_find_rsdp_klog()
+ *	Get RSDP by parsing kernel log
+ */
+static void *fwts_acpi_find_rsdp_klog(void)
+{
+	fwts_list *klog;
+	fwts_list_link *item;
+	void *rsdp = NULL;
+
+	if ((klog = fwts_klog_read()) == NULL)
+		return NULL;
+
+	fwts_list_foreach(item, klog) {
+		char *text = fwts_text_list_text(item);
+		char *ptr = strstr(text, "ACPI: RSDP");
+
+		if (ptr) {
+			rsdp = (void *)strtoul(ptr + 11, NULL, 16);
+			break;
+		}
+	}
+
+	fwts_text_list_free(klog);
+
+	return rsdp;
+}
+
+/*
  *  fwts_acpi_find_rsdp_bios()
  *	Find RSDP address by scanning BIOS memory
  */
@@ -94,21 +122,26 @@  static void *fwts_acpi_find_rsdp_bios(void)
 static fwts_acpi_table_rsdp *fwts_acpi_get_rsdp(void *addr, size_t *rsdp_len)
 {
 	uint8_t *mem;
-	fwts_acpi_table_rsdp *rsdp;
+	fwts_acpi_table_rsdp *rsdp = NULL;
 	*rsdp_len = 0;
 
 	if ((mem = fwts_mmap((off_t)addr, sizeof(fwts_acpi_table_rsdp))) == FWTS_MAP_FAILED)
 		return NULL;
 
-	/* Determine original RSDP size from revision. */
 	rsdp = (fwts_acpi_table_rsdp*)mem;
+	/* Determine original RSDP size from revision. */
 	*rsdp_len = (rsdp->revision < 1) ? 20 : 36;
 
+	/* Must have the correct signature */
+	if (strncmp(rsdp->signature, "RSD PTR ", 8))
+		goto out;
+
 	/* Assume version 2.0 size, we don't care about a few bytes over allocation if it's version 1.0 */
 	if ((rsdp = (fwts_acpi_table_rsdp*)fwts_low_calloc(1, sizeof(fwts_acpi_table_rsdp))) == NULL)
-		return NULL;
+		goto out;
 
 	memcpy(rsdp, mem, *rsdp_len);
+out:
 	(void)fwts_munmap(mem, sizeof(fwts_acpi_table_rsdp));
 
 	return rsdp;
@@ -238,22 +271,33 @@  static void fwts_acpi_handle_fadt(fwts_acpi_table_fadt *fadt, fwts_acpi_table_pr
  *  fwts_acpi_load_tables_from_firmware()
  *  	Load up cached copies of all the ACPI tables
  */
-static int fwts_acpi_load_tables_from_firmware(void)
+static int fwts_acpi_load_tables_from_firmware(fwts_framework *fw)
 {
 	fwts_acpi_table_rsdp *rsdp;
 	fwts_acpi_table_xsdt *xsdt;
 	fwts_acpi_table_rsdt *rsdt;
 	fwts_acpi_table_header *header;
 
-	void *	rsdp_addr;
+	void *	rsdp_addr = NULL;
 	size_t	rsdp_len;
 	int 	num_entries;
 	int 	i;
 
-	/* Check for RSDP in EFI, then BIOS, if not found, give up */
-	if ((rsdp_addr = fwts_acpi_find_rsdp_efi()) == NULL)
-		if ((rsdp_addr = fwts_acpi_find_rsdp_bios()) == NULL)
-			return FWTS_ERROR;
+	/* Check for RSDP as EFI, then BIOS, parsed klog, if not found, give up */
+	if (fw->rsdp)
+		rsdp_addr = (void*)fw->rsdp;
+	if (!rsdp_addr)
+		rsdp_addr = fwts_acpi_find_rsdp_efi();
+	if (!rsdp_addr)
+		rsdp_addr = fwts_acpi_find_rsdp_bios();
+	if (!rsdp_addr)
+		rsdp_addr = fwts_acpi_find_rsdp_klog();
+	if (!rsdp_addr)
+		return FWTS_ERROR;
+
+	/* Must be on a 16 byte boundary */
+	if (((unsigned long)rsdp_addr & 0xf))
+		return FWTS_ERROR;
 
 	/* Load and save cached RSDP */
 	if ((rsdp = fwts_acpi_get_rsdp(rsdp_addr, &rsdp_len)) == NULL)
@@ -712,7 +756,7 @@  int fwts_acpi_load_tables(fwts_framework *fw)
 	else if (fw->acpi_table_acpidump_file != NULL)
 		ret = fwts_acpi_load_tables_from_acpidump(fw);
 	else if (fwts_check_root_euid(fw, true) == FWTS_OK)
-		ret = fwts_acpi_load_tables_from_firmware();
+		ret = fwts_acpi_load_tables_from_firmware(fw);
 	else
 		ret = FWTS_ERROR_NO_PRIV;
 
diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c
index eae5907..92aa74d 100644
--- a/src/lib/src/fwts_framework.c
+++ b/src/lib/src/fwts_framework.c
@@ -83,6 +83,7 @@  static fwts_option fwts_framework_options[] = {
 	{ "acpica-debug",	"",   0, "Enable ACPICA debug/warning messages." },
 	{ "acpica",		"",   1, "Enable ACPICA run time options." },
 	{ "uefi",		"",   0, "Run UEFI tests." },
+	{ "rsdp",		"R:", 1, "Specify the physical address of the ACPI RSDP." },
 	{ NULL, NULL, 0, NULL }
 };
 
@@ -1138,6 +1139,9 @@  int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
 		case 38: /* --uefi */
 			fw->flags |= FWTS_FLAG_TEST_UEFI;
 			break;
+		case 39: /* --rsdp */
+			fw->rsdp = (void *)strtoul(optarg, NULL, 0);
+			break;
 		}
 		break;
 	case 'a': /* --all */
@@ -1214,6 +1218,9 @@  int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
 	case 'w': /* --log-width=N */
 		fwts_log_set_line_width(atoi(optarg));
 		break;
+	case 'R': /* --rsdp=addr */
+		fw->rsdp = (void *)strtoul(optarg, NULL, 0);
+		break;
 	}
 	return FWTS_OK;
 }