diff mbox

acpi: crsdump: dump ACPI _CRS buffers in an annotated form

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

Commit Message

Colin Ian King Jan. 23, 2013, 6:59 p.m. UTC
From: Colin Ian King <colin.king@canonical.com>

Add a new utility that scans for all the _CRS buffers and dumps the
buffer contents in an annotated form.  Tested against my data base
of ACPI tables.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 src/Makefile.am            |   1 +
 src/acpi/crsdump/crsdump.c | 892 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 893 insertions(+)
 create mode 100644 src/acpi/crsdump/crsdump.c

Comments

Ivan Hu Feb. 1, 2013, 8:52 a.m. UTC | #1
On 01/24/2013 02:59 AM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Add a new utility that scans for all the _CRS buffers and dumps the
> buffer contents in an annotated form.  Tested against my data base
> of ACPI tables.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>   src/Makefile.am            |   1 +
>   src/acpi/crsdump/crsdump.c | 892 +++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 893 insertions(+)
>   create mode 100644 src/acpi/crsdump/crsdump.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index d62574b..f80936d 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -27,6 +27,7 @@ fwts_SOURCES = main.c 				\
>   	acpi/battery/battery.c 			\
>   	acpi/brightness/brightness.c 		\
>   	acpi/checksum/checksum.c 		\
> +	acpi/crsdump/crsdump.c			\
>   	acpi/cstates/cstates.c 			\
>   	acpi/dmar/dmar.c 			\
>   	acpi/fadt/fadt.c 			\
> diff --git a/src/acpi/crsdump/crsdump.c b/src/acpi/crsdump/crsdump.c
> new file mode 100644
> index 0000000..d6dd6df
> --- /dev/null
> +++ b/src/acpi/crsdump/crsdump.c
> @@ -0,0 +1,892 @@
> +/*
> + * Copyright (C) 2013 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +#include "fwts.h"
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <inttypes.h>
> +
> +/* acpica headers */
> +#include "acpi.h"
> +#include "fwts_acpi_object_eval.h"
> +
> +typedef struct {
> +	const char *label;				/* Field label */
> +	size_t offset;					/* Offset into _CRS buffer */
> +	size_t bitlength;				/* Size of field in bits */
> +	uint64_t bitmask;				/* Bit mask, 0 = use all bits */
> +	uint8_t shift;					/* Value shift */
> +	const char **annotation;			/* Annotations */
> +	const char *(*callback)(const uint64_t val);	/* val -> string mapping callback for CRS_UINTX */
> +} crsdump_info;
> +
> +#define CRS_UINT(label, offset, bitlength)		{ label, offset, bitlength, 0, 0, NULL, NULL }
> +#define CRS_UINT24(label, offset, bitlength)		{ label, offset, bitlength, 0, 8, NULL, NULL }
> +#define CRS_UINTX(label, offset, bitlength, callback)	{ label, offset, bitlength, 0, 0, NULL, callback }
> +
> +#define CRS_BITS(label, offset, bitmask)		{ label, offset, 8, bitmask, 0, NULL, NULL }
> +#define CRS_BITX(label, offset, bitmask, annotation) 	{ label, offset, 8, bitmask, 0, annotation, NULL }
> +#define CRS_END						{ NULL, 0, 0, 0, 0, 0, NULL }
> +
> +static void crsdump_show_header(
> +	fwts_framework *fw,
> +	const char *objname,
> +	const char *crs_name)
> +{
> +	fwts_log_info_verbatum(fw, "%s (%s):", objname, crs_name);
> +}
> +
> +static void crsdump_show_info(
> +	fwts_framework *fw,
> +	const uint8_t *data,
> +	const size_t length,
> +	const crsdump_info *info)
> +{
> +	/*
> +	 *  Walk through fields and dump data according to the mapping
> +	 */
> +	for ( ; info->label; info++) {
> +		uint64_t val;
> +		uint64_t mask = info->bitmask;
> +		int hexdigits = info->bitlength >> 2;
> +
> +		if (info->offset + (info->bitlength >> 3) > length)
> +			continue;
> +
> +		if (info->bitmask) {
> +			/*
> +			 *  CRS_BIT*() data
> +			 */
> +			val = (uint64_t)*(uint8_t*)(data + info->offset);
> +			while (mask && ((mask & 1) == 0)) {
> +				val >>= 1;
> +				mask >>= 1;
> +			}
> +			val &= mask;
> +			hexdigits = 2;
> +		} else {
> +			/*
> +			 *  CRS_UINT*() data
> +			 */
> +			switch (info->bitlength) {
> +			case 8:
> +				val = (uint64_t)*(uint8_t*)(data + info->offset);
> +				break;
> +			case 16:
> +				val = (uint64_t)*(uint16_t*)(data + info->offset);
> +				break;
> +			case 32:
> +				val = (uint64_t)*(uint32_t*)(data + info->offset);
> +				break;
> +			case 64:
> +				val = (uint64_t)*(uint64_t*)(data + info->offset);
> +				break;
> +			default:
> +				val = ~0;
> +				break;
> +			}
> +		}
> +		val = val << info->shift;
> +
> +		if (info->annotation) {
> +			fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64 " (%s)",
> +				(uint16_t)info->offset, info->label, hexdigits, hexdigits, val,
> +				info->annotation[val]);
> +		} else if (info->callback) {
> +			fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64 " (%s)",
> +				(uint16_t)info->offset, info->label, hexdigits, hexdigits, val,
> +				info->callback(val));
> +		} else {
> +			fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64,
> +				(uint16_t)info->offset, info->label, hexdigits, hexdigits, val);
> +		}
> +	}
> +}
> +
> +static void crsdump_show(
> +	fwts_framework *fw,
> +	const char *objname,
> +	const char *crs_name,
> +	const uint8_t *data,
> +	const size_t length,
> +	const crsdump_info *header,
> +	const crsdump_info *info)
> +{
> +	crsdump_show_header(fw, objname, crs_name);
> +	crsdump_show_info(fw, data, length, header);
> +	crsdump_show_info(fw, data, length, info);
> +}
> +
> +static void crsdump_data(
> +	fwts_framework *fw,
> +	const uint8_t *data,
> +	const size_t from,
> +	const size_t to)
> +{
> +	size_t i;
> +	char buffer[120];
> +
> +	for (i = from; i < to; i+= 16) {
> +		size_t n = to - i;
> +
> +		fwts_dump_raw_data(buffer, sizeof(buffer), data + i, i, n > 16 ? 16 : n);
> +		buffer[56] = '\0';	/* Truncate off text version of hex dump */
> +
> +		fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: %s",
> +			(uint16_t)i, "Hex Dump", buffer + 8);
> +	}
> +}
> +
> +/*
> + *  crsdump_init()
> + *	initialize ACPI
> + */
> +static int crsdump_init(fwts_framework *fw)
> +{
> +	if (fwts_acpi_init(fw) != FWTS_OK) {
> +		fwts_log_error(fw, "Cannot initialise ACPI.");
> +		return FWTS_ERROR;
> +	}
> +
> +	return FWTS_OK;
> +}
> +
> +/*
> + *  crsdump_deinit
> + *	de-intialize ACPI
> + */
> +static int crsdump_deinit(fwts_framework *fw)
> +{
> +	return fwts_acpi_deinit(fw);
> +}
> +
> +/*
> + *  See section 6.4.2.7 Fixed DMA Descriptor, DMA transfer width
> + */
> +static const char *crs_dma_transfer_width(const uint64_t val)
> +{
> +	switch (val) {
> +	case 0x00:
> +		return "8 bit";
> +	case 0x01:
> +		return "16 bit";
> +	case 0x02:
> +		return "32 bit";
> +	case 0x03:
> +		return "64 bit";
> +	case 0x04:
> +		return "128 bit";
> +	case 0x05:
> +		return "256 bit";
> +	default:
> +		return "reserved";
> +	}
> +}
> +
> +/*
> + *  See section 6.4.3.5.2 DWord Address Space Descriptor Resource Type
> + */
> +static const char *crs_resource_type(const uint64_t val)
> +{
> +	switch (val) {
> +	case 0x00:
> +		return "Memory range";
> +	case 0x01:
> +		return "I/O range";
> +	case 0x02:
> +		return "Bus number range";
> +	case 0xc0 ... 0xff:
> +		return "Hardware Vendor Defined";
> +	default:
> +		return "Reserved";
> +	}
> +}
> +
> +/*
> + *  See section 6.4.8.1. Generic Register Descriptor Address Space ID
> + */
> +static const char *crs_address_space_id(const uint64_t val)
> +{
> +	switch (val) {
> +	case 0x00:
> +		return "System Memory";
> +	case 0x01:
> +		return "System I/O";
> +	case 0x02:
> +		return "PCI Configuration Space";
> +	case 0x03:
> +		return "Embedded Controller";
> +	case 0x04:
> +		return "SMBus";
> +	case 0x0a:
> +		return "PCC";
> +	case 0x7f:
> +		return "Functional Fixed Hardware";
> +	default:
> +		return "Uknown";
> +	}
> +}
> +
> +/*
> + *  See section 6.4.8.1. Generic Register Descriptor Address Size
> + */
> +static const char *crs_address_size(const uint64_t val)
> +{
> +	switch (val) {
> +	case 0x00:
> +		return "Undefined (legacy)";
> +	case 0x01:
> +		return "Byte Access";
> +	case 0x02:
> +		return "Word Access";
> +	case 0x04:
> +		return "Dword Access";
> +	case 0x08:
> +		return "Qword Access";
> +	default:
> +		return "Unknown";
> +	}
> +}
> +
> +/*
> + *  See section 6.4.3.8.1 GPIO Connection Description
> + */
> +static const char *crs_gpio_connection_type(const uint64_t val)
> +{
> +	switch (val) {
> +	case 0x00:
> +		return "Interrupt Connection";
> +	case 0x01:
> +		return "I/O Connection";
> +	default:
> +		return "Reserved";
> +	}
> +}
> +
> +/*
> + *  See section 6.4.3.8.1 GPIO Connection Description
> + */
> +static const char *crs_pin_configuration(const uint64_t val)
> +{
> +	switch (val) {
> +	case 0x00:
> +		return "Default Configuration";
> +	case 0x01:
> +		return "Pull-Up";
> +	case 0x02:
> +		return "Pull-Down";
> +	case 0x03:
> +		return "No Pull";
> +	case 0x80 ... 0xff:
> +		return "Vendor Defined";
> +	default:
> +		return "Reserved";
> +	}
> +}
> +
> +/*
> + *  CRS small resource checks, simple checking
> + */
> +static void crsdump_small_resource_items(
> +	fwts_framework *fw,
> +	const char *objname,
> +	const uint8_t *data,
> +	const size_t length)
> +{
> +	uint8_t tag_item = (data[0] >> 3) & 0xf;
> +	size_t crs_length = 1 + (data[0] & 7);
> +
> +	static const crsdump_info header[] = {
> +		CRS_BITS("Tag Type",		0, 128),
> +		CRS_BITS("Tag Item ID",		0, 64 | 32 | 16 | 8),
> +		CRS_BITS("Tag Length",		0, 4 | 2 | 1),
> +	};
> +
> +	/* Ensure we just dump minimum _CRS buffer length */
> +	if (crs_length > length)
> +		crs_length = length;
> +
> +	switch (tag_item) {
> +	case 0x4: /* 6.4.2.1 IRQ Descriptor */
> +		{
> +			static const char *sharing[] = {
> +				"Exclusive",
> +				"Shared",
> +				"Exclusive And Wake",
> +				"Shared And Wake"
> +			};
> +
> +			static const char *polarity[] = {
> +				"Active-High",
> +				"Active-Low"
> +			};
> +
> +			static const char *mode[] = {
> +				"Level-Triggered",
> +				"Edge-Triggered"
> +			};
> +
> +			static const crsdump_info info[] = {
> +				CRS_UINT("IRQ Mask",		1, 16),
> +				CRS_BITS("Reserved",		3, 128 | 64),
> +				CRS_BITX("Interrupt Sharing",	3, 32 | 16, sharing),
> +				CRS_BITX("Interrupt Polarity",	3, 8, polarity),
> +				CRS_BITS("Ignored",		3, 4 | 2),
> +				CRS_BITX("Interrupt Mode",	3, 1, mode),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "IRQ Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x5: /* 6.4.2.2 DMA Descriptor */
> +		{
> +			static const char *dma_speed[] = {
> +				"Compatibility Mode",
> +				"Type A DMA",
> +				"Type B DMA",
> +				"Type F DMA"
> +			};
> +
> +			static const char *bus_master[] = {
> +				"Not a bus master",
> +				"Is a bus master"
> +			};
> +
> +			static const char *dma_size[] = {
> +				"8 bit only",
> +				"8 and 16 bit",
> +				"16 bit only",
> +				"Reserved"
> +			};
> +
> +			static const crsdump_info info[] = {
> +				CRS_UINT("DMA channel mask",		1, 16),
> +				CRS_BITS("Reserved",			2, 128),
> +				CRS_BITX("DMA channel speed",		2, 64 | 32, dma_speed),
> +				CRS_BITS("Ignored",			2, 16 | 8),
> +				CRS_BITX("Logical device bus master",	2, 4, bus_master),
> +				CRS_BITX("DMA transfer type preference",2, 2 | 1, dma_size),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "DMA Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x6: /* 6.4.2.3 Start Dependent Functions Descriptor */
> +		{
> +			static const char *config[] = {
> +				"Good configurarion",
> +				"Acceptable configuration",
> +				"Sub-optimal configuration",
> +				"Reserved"
> +			};
> +
> +			static const crsdump_info info[] = {
> +				CRS_BITS("Reserved",			1, 0xf0),
> +				CRS_BITX("Performance/robustness",	1, 8 | 4, config),
> +				CRS_BITX("Compatibility priority",	1, 2 | 1, config),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "Start Dependent Functions Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x7: /* 6.4.2.4 End Dependent Functions Descriptor */
> +		crsdump_show_header(fw, objname, "End Dependent Functions Descriptor");
> +		break;
> +	case 0x8: /* 6.4.2.5 I/O Port Descriptor */
> +		{
> +			static const char *decodes[] = {
> +				"16 bit addresses",
> +				"10 bit addresses"
> +			};
> +			static const crsdump_info info[] = {
> +				CRS_BITS("Reserved",			1, 0xfe),
> +				CRS_BITX("Logical Device Decode",	1, 1, decodes),
> +				CRS_UINT("Minimum Base Address",	2, 16),
> +				CRS_UINT("Maximum Base Address",	4, 16),
> +				CRS_UINT("Base Alignment",		6, 8),
> +				CRS_UINT("Range Length",		7, 8),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "I/O Port Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x9: /* 6.4.2.6 Fixed Location I/O Port Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINT("Range Base Address",		1, 16),
> +				CRS_UINT("Range Length",		3, 8),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "Fixed Location I/O Port Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0xa: /* 6.4.2.7 Fixed DMA Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINT("DMA Request Line",		1, 16),
> +				CRS_UINT("DMA Channel",			3, 16),
> +				CRS_UINTX("DMA Transfer Width",		5, 1, crs_dma_transfer_width),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "Fixed DMA Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0xe: /* 6.4.2.8 Vendor-Defined Descriptor */
> +		crsdump_show_header(fw, objname, "Vendor-Defined Descriptor");
> +		crsdump_show_info(fw, data, crs_length, header);
> +		crsdump_data(fw, data, 3, crs_length);
> +		break;
> +	case 0xf: /* 6.4.2.9 End Tag */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINT("Checksum",			1, 8),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "End Tag",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	default:
> +		crsdump_show_header(fw, objname, "Unknown type");
> +		crsdump_show_info(fw, data, crs_length, header);
> +		crsdump_data(fw, data, 1, crs_length);
> +		break;
> +	}
> +
> +	fwts_log_nl(fw);
> +}
> +
> +/*
> + *  CRS large resource checks, simple checking
> + */
> +static void crsdump_large_resource_items(
> +	fwts_framework *fw,
> +	const char *objname,
> +	const uint8_t *data,
> +	const uint64_t length)
> +{
> +	uint8_t tag_item = data[0] & 0x7f;
> +	size_t crs_length = data[1];
> +
> +	static const crsdump_info header[] = {
> +		CRS_BITS("Tag Type",		0, 128),
> +		CRS_BITS("Tag Item ID",		0, 0x7f),
> +		CRS_UINT("Length",		1, 16),
> +		CRS_END
> +	};
> +
> +	static const char *write_status[] = {
> +		"non-writeable, read-only",
> +		"writeable, read/write"
> +	};
> +
> +	static const char *mifmaf[] = {
> +		"Not fixed",
> +		"Fixed"
> +	};
> +
> +	static const char *decode_type[] = {
> +		"Bridge Positively decodes this address",
> +		"Bridge Subtractively decode this address"
> +	};
> +
> +	static const char *sharing[] = {
> +		"Exclusive",
> +		"Shared",
> +		"Exclusive and Wake",
> +		"Shared and Wake"
> +	};
> +
> +	static const char *polarity[] = {
> +		"Active-High",
> +		"Active-Low",
> +		"Active-Both",
> +		"Reserved"
> +	};
> +
> +	static const char *mode[] = {
> +		"Level-Triggered",
> +		"Edge-Triggered"
> +	};
> +
> +	static const char *consumer[] = {
> +		"producer and consumer",
> +		"consumer"
> +	};
> +
> +	/* Ensure we just dump minimum _CRS buffer length */
> +	if (crs_length > length)
> +		crs_length = length;
> +
> +	switch (tag_item) {
> +	case 0x1: /* 6.4.3.1 24-Bit Memory Range Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_BITX("Write Status",		3, 1, write_status),
> +				CRS_UINT24("Range Minimum Base",	4, 16),
> +				CRS_UINT24("Range Maximum Base",	6, 16),
> +				CRS_UINT("Base Alignment",		8, 16),
> +				CRS_UINT("Range Length",		10, 16),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "24-Bit Memory Range Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x2: /* 6.4.3.7 Generic Register Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINTX("Address Space ID",		3, 8, crs_address_space_id),
> +				CRS_UINT("Address Bit Width",		4, 8),
> +				CRS_UINT("Register Bit Offset",		5, 8),
> +				CRS_UINTX("Address Size",		6, 8, crs_address_size),
> +				CRS_UINT("Register Address",		7, 64),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "Generic Register Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x4: /* 6.4.3.2 Vendor-Defined Descriptor */
> +		crsdump_show_header(fw, objname, "Vendor-Defined Descriptor");
> +		crsdump_show_info(fw, data, crs_length, header);
> +		crsdump_data(fw, data, 3, crs_length);
> +		break;
> +	case 0x5: /* 6.4.3.3 32-Bit Memory Range Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_BITX("Write Status",		3, 1, write_status),
> +				CRS_UINT("Range Minimum Address",	4, 32),
> +				CRS_UINT("Range Maximum Address",	8, 32),
> +				CRS_UINT("Base Alignment",		12, 32),
> +				CRS_UINT("Range Length",		16, 32),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "32-Bit Memory Range Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x6: /* 6.4.3.4 32-Bit Fixed Memory Range Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_BITX("Write Status",		3, 1, write_status),
> +				CRS_UINT("Range Base Address",		4, 32),
> +				CRS_UINT("Range Length",		8, 32),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "32-Bit Fixed Memory Range Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x7: /* 6.4.3.5.2 DWord Address Space Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
> +				CRS_BITS("Reserved",			4, 0xf0),
> +				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
> +				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
> +				CRS_BITX("Decode Type",			4, 2, decode_type),
> +				CRS_BITS("Ignored",			4, 1),
> +				CRS_UINT("Type Specific Flags",		5, 8),
> +				CRS_UINT("Address Space Granularity",	6, 32),
> +				CRS_UINT("Address Range Minimum",	10, 32),
> +				CRS_UINT("Address Range Maximum",	14, 32),
> +				CRS_UINT("Address Translation Offset",	18, 32),
> +				CRS_UINT("Address Length",		22, 32),
> +				CRS_UINT("Resource Source Index",	26, 1),
> +				/* Skip Resource Source String */
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "DWord Address Space Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x8: /* 6.4.3.5.3 Word Address Space Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
> +				CRS_BITS("Reserved",			4, 0xf0),
> +				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
> +				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
> +				CRS_BITX("Decode Type",			4, 2, decode_type),
> +				CRS_BITS("Ignored",			4, 1),
> +				CRS_UINT("Type Specific Flags",		5, 8),
> +				CRS_UINT("Address Space Granularity",	6, 16),
> +				CRS_UINT("Address Range Minimum",	8, 16),
> +				CRS_UINT("Address Range Maximum",	10, 16),
> +				CRS_UINT("Address Translation Offset",	12, 16),
> +				CRS_UINT("Address Length",		14, 16),
> +				CRS_UINT("Resource Source Index",	16, 1),
> +				/* Skip Resource Source String */
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "Word Address Space Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0x9: /* 6.4.3.6 Extended Interrupt Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_BITS("Reserved",			3, 128 | 64 | 32),
> +				CRS_BITX("Interrupt Sharing",		3, 16 | 8, sharing),
> +				CRS_BITX("Interrupt Polarity",		7, 4, polarity),
> +				CRS_BITX("Interrupt Mode",		7, 2, mode),
> +				CRS_BITX("Interrupt Consumer/Producer",	7, 1, consumer),
> +				CRS_UINT("Interrupt Table Length",	8, 8),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "Extended Interrupt Descriptor",
> +				data, crs_length, header, info);
> +			crsdump_data(fw, data, 5, crs_length);
> +		}
> +		break;
> +	case 0xa: /* 6.4.3.5.1 QWord Address Space Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
> +				CRS_BITS("Reserved",			4, 0xf0),
> +				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
> +				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
> +				CRS_BITX("Decode Type",			4, 2, decode_type),
> +				CRS_BITS("Ignored",			4, 1),
> +				CRS_UINT("Type Specific Flags",		5, 8),
> +				CRS_UINT("Address Space Granularity",	6, 64),
> +				CRS_UINT("Address Range Minimum",	14, 64),
> +				CRS_UINT("Address Range Maximum",	22, 64),
> +				CRS_UINT("Address Translation Offset",	30, 64),
> +				CRS_UINT("Address Length",		38, 64),
> +				CRS_UINT("Resource Source Index",	46, 1),
> +				/* Skip Resource Source String */
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "QWord Address Space Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0xb: /* 6.4.3.5.4 Extended Address Space Descriptor */
> +		{
> +			static const crsdump_info info[] = {
> +				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
> +				CRS_BITS("Reserved",			4, 0xf0),
> +				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
> +				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
> +				CRS_BITX("Decode Type",			4, 2, decode_type),
> +				CRS_BITX("Consumer/Producer",		4, 1, consumer),
> +				CRS_UINT("Type Specific Flags",		5, 8),
> +				CRS_UINT("Revision ID",			6, 8),
> +				CRS_UINT("Reserved",			7, 8),
> +				CRS_UINT("Address Space Granularity",	8, 64),
> +				CRS_UINT("Address Range Minimum",	16, 64),
> +				CRS_UINT("Address Range Maximum",	24, 64),
> +				CRS_UINT("Address Translation Offset",	32, 64),
> +				CRS_UINT("Address Length",		40, 64),
> +				CRS_UINT("Type Specific Attribute",	48, 64),
> +				CRS_END
> +			};
> +
> +			crsdump_show(fw, objname, "Extended Address Space Descriptor",
> +				data, crs_length, header, info);
> +		}
> +		break;
> +	case 0xc: /* 6.4.3.8.1 GPIO Connection Descriptor */
> +		{
> +			if (crs_length < 4)
> +				break;
> +
> +			if (data[4] == 0) {
> +
> +				/* Interrupt connection */
> +				static const crsdump_info info[] = {
> +					CRS_UINT("Revision ID",			3, 8),
> +					CRS_UINTX("GPIO Connection Type",	4, 8, crs_gpio_connection_type),
> +					CRS_BITS("Reserved",			5, 0xfe),
> +					CRS_BITX("Consumer/Producer",		5, 1, consumer),
> +					CRS_UINT("Reserved",			6, 8),
> +					CRS_BITS("Reserved",			7, 128 | 64 | 32),
> +					CRS_BITX("Interrupt Sharing and Wake",	7, 16 | 8, sharing),
> +					CRS_BITX("Interrupt Polarity",		7, 4 | 2, polarity),
> +					CRS_BITX("Interrupt Mode",		7, 1, mode),
> +					CRS_UINT("Interrupt and I/O Flags",	8, 8),
> +					CRS_UINTX("Pin Configuration",		9, 8, crs_pin_configuration),
> +					CRS_UINT("Output Driver Strength",	10, 16),
> +					CRS_UINT("Debounce Timeout (bits)",	12, 16),
> +					CRS_UINT("Pin Table Offset",		14, 16),
> +					CRS_UINT("Resource Source Index",	16, 8),
> +					CRS_UINT("Resource Name Offset",	17, 16),
> +					CRS_UINT("Vendor Data Offset",		19, 16),
> +					CRS_UINT("Vendor Data Length",		21, 16),
> +					/* Skip pin table */
> +					CRS_END
> +				};
> +
> +				crsdump_show(fw, objname, "GPIO Connection Descriptor",
> +					data, crs_length, header, info);
> +			} else if (data[4] == 1) {
> +				static const char *sharing[] = {
> +					"Exclusive",
> +					"Shared",
> +				};
> +
> +				static const char *restriction[] = {
> +					"Input or Output",
> +					"Input Only",
> +					"Output Only",
> +					"Input or Ouput, config must be preserved"
> +				};
> +
> +				/* I/O connection */
> +				static const crsdump_info info[] = {
> +					CRS_UINT("Revision ID",			3, 8),
> +					CRS_UINTX("GPIO Connection Type",	4, 8, crs_gpio_connection_type),
> +					CRS_BITS("Reserved",			5, 0xfe),
> +					CRS_BITX("Consumer/Producer",		5, 1, consumer),
> +					CRS_UINT("Reserved",			6, 8),
> +					CRS_BITS("Reserved",			7, 128 | 64 | 32 | 16),
> +					CRS_BITX("Interrupt Sharing",		7, 8, sharing),
> +					CRS_BITS("Reserved",			7, 4),
> +					CRS_BITX("I/O Restriction",		7, 2 | 1, restriction),
> +					CRS_UINT("Interrupt and I/O Flags",	8, 8),
> +					CRS_UINTX("Pin Configuration",		9, 8, crs_pin_configuration),
> +					CRS_UINT("Output Driver Strength",	10, 16),
> +					CRS_UINT("Debounce Timeout (bits)",	12, 16),
> +					CRS_UINT("Pin Table Offset",		14, 16),
> +					CRS_UINT("Resource Source Index",	16, 8),
> +					CRS_UINT("Resource Name Offset",	17, 16),
> +					CRS_UINT("Vendor Data Offset",		19, 16),
> +					CRS_UINT("Vendor Data Length",		21, 16),
> +					/* Skip pin table */
> +					CRS_END
> +				};
> +
> +				crsdump_show(fw, objname, "GPIO Connection Descriptor",
> +					data, crs_length, header, info);
> +			} else {
> +				/* No idea of the connection type */
> +				static const crsdump_info info[] = {
> +					CRS_UINT("Revision ID",			3, 8),
> +					CRS_UINT("GPIO Connection Type",	4, 8),
> +					CRS_END
> +				};
> +
> +				crsdump_show(fw, objname, "GPIO Connection Descriptor",
> +					data, crs_length, header, info);
> +			}
> +
> +		}
> +		break;
> +	case 0xe: /* 6.4.3.8.2 Serial Bus Connection Descriptors */
> +		/*  This is not frequently used, deferring implementation to later */
> +		crsdump_show_header(fw, objname, "Serial Bus Connection Descriptor");
> +		crsdump_show_info(fw, data, crs_length, header);
> +		crsdump_data(fw, data, 3, crs_length);
> +		break;
> +	default:
> +		crsdump_show_header(fw, objname, "Unknown type");
> +		crsdump_show_info(fw, data, crs_length, header);
> +		crsdump_data(fw, data, 3, crs_length);
> +		break;
> +	}
> +
> +	fwts_log_nl(fw);
> +}
> +
> +static int crsdump_test1(fwts_framework *fw)
> +{
> +	fwts_list_link	*item;
> +	fwts_list *objects;
> +	const size_t name_len = 4;
> +
> +	if ((objects = fwts_acpi_object_get_names()) == NULL) {
> +		fwts_log_info(fw, "Cannot find any ACPI objects");
> +		return FWTS_ERROR;
> +	}
> +
> +	fwts_list_foreach(item, objects) {
> +		char *name = fwts_list_data(char*, item);
> +		const size_t len = strlen(name);
> +		if (strncmp("_CRS", name + len - name_len, name_len) == 0) {
> +			ACPI_OBJECT_LIST arg_list;
> +			ACPI_BUFFER buf;
> +			ACPI_OBJECT *obj;
> +			uint8_t *data;
> +			int ret;
> +
> +			arg_list.Count   = 0;
> +			arg_list.Pointer = NULL;
> +
> +			ret = fwts_acpi_object_evaluate(fw, name, &arg_list, &buf);
> +			if ((ACPI_FAILURE(ret) != AE_OK) || (buf.Pointer == NULL))
> +				continue;
> +
> +			/*  Do we have a valid _CRS buffer to dump? */
> +			obj = buf.Pointer;
> +			if ((obj->Type == ACPI_TYPE_BUFFER) &&
> +			    (obj->Buffer.Pointer != NULL) &&
> +			    (obj->Buffer.Length > 0)) {
> +				data = (uint8_t*)obj->Buffer.Pointer;
> +
> +				if (data[0] & 128)
> +					crsdump_large_resource_items(fw, name, data, obj->Buffer.Length);
> +				else
> +					crsdump_small_resource_items(fw, name, data, obj->Buffer.Length);
> +			}
> +
> +			if (buf.Length && buf.Pointer)
> +				free(buf.Pointer);
> +		}
> +	}
> +	return FWTS_OK;
> +}
> +
> +static fwts_framework_minor_test crsdump_tests[] = {
> +	{ crsdump_test1, "Dump ACPI _CRS buffers." },
> +	{ NULL, NULL }
> +};
> +
> +static fwts_framework_ops crsdump_ops = {
> +	.description = "Dump ACPI _CRS buffers.",
> +	.init        = crsdump_init,
> +	.deinit      = crsdump_deinit,
> +	.minor_tests = crsdump_tests
> +};
> +
> +FWTS_REGISTER("crsdump", &crsdump_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UTILS);
>
Acked-by: Ivan Hu <ivan.hu@canonical.com>
Keng-Yu Lin Feb. 1, 2013, 10:32 a.m. UTC | #2
On Thu, Jan 24, 2013 at 2:59 AM, Colin King <colin.king@canonical.com> wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Add a new utility that scans for all the _CRS buffers and dumps the
> buffer contents in an annotated form.  Tested against my data base
> of ACPI tables.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>  src/Makefile.am            |   1 +
>  src/acpi/crsdump/crsdump.c | 892 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 893 insertions(+)
>  create mode 100644 src/acpi/crsdump/crsdump.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index d62574b..f80936d 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -27,6 +27,7 @@ fwts_SOURCES = main.c                                 \
>         acpi/battery/battery.c                  \
>         acpi/brightness/brightness.c            \
>         acpi/checksum/checksum.c                \
> +       acpi/crsdump/crsdump.c                  \
>         acpi/cstates/cstates.c                  \
>         acpi/dmar/dmar.c                        \
>         acpi/fadt/fadt.c                        \
> diff --git a/src/acpi/crsdump/crsdump.c b/src/acpi/crsdump/crsdump.c
> new file mode 100644
> index 0000000..d6dd6df
> --- /dev/null
> +++ b/src/acpi/crsdump/crsdump.c
> @@ -0,0 +1,892 @@
> +/*
> + * Copyright (C) 2013 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +#include "fwts.h"
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <inttypes.h>
> +
> +/* acpica headers */
> +#include "acpi.h"
> +#include "fwts_acpi_object_eval.h"
> +
> +typedef struct {
> +       const char *label;                              /* Field label */
> +       size_t offset;                                  /* Offset into _CRS buffer */
> +       size_t bitlength;                               /* Size of field in bits */
> +       uint64_t bitmask;                               /* Bit mask, 0 = use all bits */
> +       uint8_t shift;                                  /* Value shift */
> +       const char **annotation;                        /* Annotations */
> +       const char *(*callback)(const uint64_t val);    /* val -> string mapping callback for CRS_UINTX */
> +} crsdump_info;
> +
> +#define CRS_UINT(label, offset, bitlength)             { label, offset, bitlength, 0, 0, NULL, NULL }
> +#define CRS_UINT24(label, offset, bitlength)           { label, offset, bitlength, 0, 8, NULL, NULL }
> +#define CRS_UINTX(label, offset, bitlength, callback)  { label, offset, bitlength, 0, 0, NULL, callback }
> +
> +#define CRS_BITS(label, offset, bitmask)               { label, offset, 8, bitmask, 0, NULL, NULL }
> +#define CRS_BITX(label, offset, bitmask, annotation)   { label, offset, 8, bitmask, 0, annotation, NULL }
> +#define CRS_END                                                { NULL, 0, 0, 0, 0, 0, NULL }
> +
> +static void crsdump_show_header(
> +       fwts_framework *fw,
> +       const char *objname,
> +       const char *crs_name)
> +{
> +       fwts_log_info_verbatum(fw, "%s (%s):", objname, crs_name);
> +}
> +
> +static void crsdump_show_info(
> +       fwts_framework *fw,
> +       const uint8_t *data,
> +       const size_t length,
> +       const crsdump_info *info)
> +{
> +       /*
> +        *  Walk through fields and dump data according to the mapping
> +        */
> +       for ( ; info->label; info++) {
> +               uint64_t val;
> +               uint64_t mask = info->bitmask;
> +               int hexdigits = info->bitlength >> 2;
> +
> +               if (info->offset + (info->bitlength >> 3) > length)
> +                       continue;
> +
> +               if (info->bitmask) {
> +                       /*
> +                        *  CRS_BIT*() data
> +                        */
> +                       val = (uint64_t)*(uint8_t*)(data + info->offset);
> +                       while (mask && ((mask & 1) == 0)) {
> +                               val >>= 1;
> +                               mask >>= 1;
> +                       }
> +                       val &= mask;
> +                       hexdigits = 2;
> +               } else {
> +                       /*
> +                        *  CRS_UINT*() data
> +                        */
> +                       switch (info->bitlength) {
> +                       case 8:
> +                               val = (uint64_t)*(uint8_t*)(data + info->offset);
> +                               break;
> +                       case 16:
> +                               val = (uint64_t)*(uint16_t*)(data + info->offset);
> +                               break;
> +                       case 32:
> +                               val = (uint64_t)*(uint32_t*)(data + info->offset);
> +                               break;
> +                       case 64:
> +                               val = (uint64_t)*(uint64_t*)(data + info->offset);
> +                               break;
> +                       default:
> +                               val = ~0;
> +                               break;
> +                       }
> +               }
> +               val = val << info->shift;
> +
> +               if (info->annotation) {
> +                       fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64 " (%s)",
> +                               (uint16_t)info->offset, info->label, hexdigits, hexdigits, val,
> +                               info->annotation[val]);
> +               } else if (info->callback) {
> +                       fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64 " (%s)",
> +                               (uint16_t)info->offset, info->label, hexdigits, hexdigits, val,
> +                               info->callback(val));
> +               } else {
> +                       fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64,
> +                               (uint16_t)info->offset, info->label, hexdigits, hexdigits, val);
> +               }
> +       }
> +}
> +
> +static void crsdump_show(
> +       fwts_framework *fw,
> +       const char *objname,
> +       const char *crs_name,
> +       const uint8_t *data,
> +       const size_t length,
> +       const crsdump_info *header,
> +       const crsdump_info *info)
> +{
> +       crsdump_show_header(fw, objname, crs_name);
> +       crsdump_show_info(fw, data, length, header);
> +       crsdump_show_info(fw, data, length, info);
> +}
> +
> +static void crsdump_data(
> +       fwts_framework *fw,
> +       const uint8_t *data,
> +       const size_t from,
> +       const size_t to)
> +{
> +       size_t i;
> +       char buffer[120];
> +
> +       for (i = from; i < to; i+= 16) {
> +               size_t n = to - i;
> +
> +               fwts_dump_raw_data(buffer, sizeof(buffer), data + i, i, n > 16 ? 16 : n);
> +               buffer[56] = '\0';      /* Truncate off text version of hex dump */
> +
> +               fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: %s",
> +                       (uint16_t)i, "Hex Dump", buffer + 8);
> +       }
> +}
> +
> +/*
> + *  crsdump_init()
> + *     initialize ACPI
> + */
> +static int crsdump_init(fwts_framework *fw)
> +{
> +       if (fwts_acpi_init(fw) != FWTS_OK) {
> +               fwts_log_error(fw, "Cannot initialise ACPI.");
> +               return FWTS_ERROR;
> +       }
> +
> +       return FWTS_OK;
> +}
> +
> +/*
> + *  crsdump_deinit
> + *     de-intialize ACPI
> + */
> +static int crsdump_deinit(fwts_framework *fw)
> +{
> +       return fwts_acpi_deinit(fw);
> +}
> +
> +/*
> + *  See section 6.4.2.7 Fixed DMA Descriptor, DMA transfer width
> + */
> +static const char *crs_dma_transfer_width(const uint64_t val)
> +{
> +       switch (val) {
> +       case 0x00:
> +               return "8 bit";
> +       case 0x01:
> +               return "16 bit";
> +       case 0x02:
> +               return "32 bit";
> +       case 0x03:
> +               return "64 bit";
> +       case 0x04:
> +               return "128 bit";
> +       case 0x05:
> +               return "256 bit";
> +       default:
> +               return "reserved";
> +       }
> +}
> +
> +/*
> + *  See section 6.4.3.5.2 DWord Address Space Descriptor Resource Type
> + */
> +static const char *crs_resource_type(const uint64_t val)
> +{
> +       switch (val) {
> +       case 0x00:
> +               return "Memory range";
> +       case 0x01:
> +               return "I/O range";
> +       case 0x02:
> +               return "Bus number range";
> +       case 0xc0 ... 0xff:
> +               return "Hardware Vendor Defined";
> +       default:
> +               return "Reserved";
> +       }
> +}
> +
> +/*
> + *  See section 6.4.8.1. Generic Register Descriptor Address Space ID
> + */
> +static const char *crs_address_space_id(const uint64_t val)
> +{
> +       switch (val) {
> +       case 0x00:
> +               return "System Memory";
> +       case 0x01:
> +               return "System I/O";
> +       case 0x02:
> +               return "PCI Configuration Space";
> +       case 0x03:
> +               return "Embedded Controller";
> +       case 0x04:
> +               return "SMBus";
> +       case 0x0a:
> +               return "PCC";
> +       case 0x7f:
> +               return "Functional Fixed Hardware";
> +       default:
> +               return "Uknown";
> +       }
> +}
> +
> +/*
> + *  See section 6.4.8.1. Generic Register Descriptor Address Size
> + */
> +static const char *crs_address_size(const uint64_t val)
> +{
> +       switch (val) {
> +       case 0x00:
> +               return "Undefined (legacy)";
> +       case 0x01:
> +               return "Byte Access";
> +       case 0x02:
> +               return "Word Access";
> +       case 0x04:
> +               return "Dword Access";
> +       case 0x08:
> +               return "Qword Access";
> +       default:
> +               return "Unknown";
> +       }
> +}
> +
> +/*
> + *  See section 6.4.3.8.1 GPIO Connection Description
> + */
> +static const char *crs_gpio_connection_type(const uint64_t val)
> +{
> +       switch (val) {
> +       case 0x00:
> +               return "Interrupt Connection";
> +       case 0x01:
> +               return "I/O Connection";
> +       default:
> +               return "Reserved";
> +       }
> +}
> +
> +/*
> + *  See section 6.4.3.8.1 GPIO Connection Description
> + */
> +static const char *crs_pin_configuration(const uint64_t val)
> +{
> +       switch (val) {
> +       case 0x00:
> +               return "Default Configuration";
> +       case 0x01:
> +               return "Pull-Up";
> +       case 0x02:
> +               return "Pull-Down";
> +       case 0x03:
> +               return "No Pull";
> +       case 0x80 ... 0xff:
> +               return "Vendor Defined";
> +       default:
> +               return "Reserved";
> +       }
> +}
> +
> +/*
> + *  CRS small resource checks, simple checking
> + */
> +static void crsdump_small_resource_items(
> +       fwts_framework *fw,
> +       const char *objname,
> +       const uint8_t *data,
> +       const size_t length)
> +{
> +       uint8_t tag_item = (data[0] >> 3) & 0xf;
> +       size_t crs_length = 1 + (data[0] & 7);
> +
> +       static const crsdump_info header[] = {
> +               CRS_BITS("Tag Type",            0, 128),
> +               CRS_BITS("Tag Item ID",         0, 64 | 32 | 16 | 8),
> +               CRS_BITS("Tag Length",          0, 4 | 2 | 1),
> +       };
> +
> +       /* Ensure we just dump minimum _CRS buffer length */
> +       if (crs_length > length)
> +               crs_length = length;
> +
> +       switch (tag_item) {
> +       case 0x4: /* 6.4.2.1 IRQ Descriptor */
> +               {
> +                       static const char *sharing[] = {
> +                               "Exclusive",
> +                               "Shared",
> +                               "Exclusive And Wake",
> +                               "Shared And Wake"
> +                       };
> +
> +                       static const char *polarity[] = {
> +                               "Active-High",
> +                               "Active-Low"
> +                       };
> +
> +                       static const char *mode[] = {
> +                               "Level-Triggered",
> +                               "Edge-Triggered"
> +                       };
> +
> +                       static const crsdump_info info[] = {
> +                               CRS_UINT("IRQ Mask",            1, 16),
> +                               CRS_BITS("Reserved",            3, 128 | 64),
> +                               CRS_BITX("Interrupt Sharing",   3, 32 | 16, sharing),
> +                               CRS_BITX("Interrupt Polarity",  3, 8, polarity),
> +                               CRS_BITS("Ignored",             3, 4 | 2),
> +                               CRS_BITX("Interrupt Mode",      3, 1, mode),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "IRQ Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x5: /* 6.4.2.2 DMA Descriptor */
> +               {
> +                       static const char *dma_speed[] = {
> +                               "Compatibility Mode",
> +                               "Type A DMA",
> +                               "Type B DMA",
> +                               "Type F DMA"
> +                       };
> +
> +                       static const char *bus_master[] = {
> +                               "Not a bus master",
> +                               "Is a bus master"
> +                       };
> +
> +                       static const char *dma_size[] = {
> +                               "8 bit only",
> +                               "8 and 16 bit",
> +                               "16 bit only",
> +                               "Reserved"
> +                       };
> +
> +                       static const crsdump_info info[] = {
> +                               CRS_UINT("DMA channel mask",            1, 16),
> +                               CRS_BITS("Reserved",                    2, 128),
> +                               CRS_BITX("DMA channel speed",           2, 64 | 32, dma_speed),
> +                               CRS_BITS("Ignored",                     2, 16 | 8),
> +                               CRS_BITX("Logical device bus master",   2, 4, bus_master),
> +                               CRS_BITX("DMA transfer type preference",2, 2 | 1, dma_size),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "DMA Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x6: /* 6.4.2.3 Start Dependent Functions Descriptor */
> +               {
> +                       static const char *config[] = {
> +                               "Good configurarion",
> +                               "Acceptable configuration",
> +                               "Sub-optimal configuration",
> +                               "Reserved"
> +                       };
> +
> +                       static const crsdump_info info[] = {
> +                               CRS_BITS("Reserved",                    1, 0xf0),
> +                               CRS_BITX("Performance/robustness",      1, 8 | 4, config),
> +                               CRS_BITX("Compatibility priority",      1, 2 | 1, config),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "Start Dependent Functions Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x7: /* 6.4.2.4 End Dependent Functions Descriptor */
> +               crsdump_show_header(fw, objname, "End Dependent Functions Descriptor");
> +               break;
> +       case 0x8: /* 6.4.2.5 I/O Port Descriptor */
> +               {
> +                       static const char *decodes[] = {
> +                               "16 bit addresses",
> +                               "10 bit addresses"
> +                       };
> +                       static const crsdump_info info[] = {
> +                               CRS_BITS("Reserved",                    1, 0xfe),
> +                               CRS_BITX("Logical Device Decode",       1, 1, decodes),
> +                               CRS_UINT("Minimum Base Address",        2, 16),
> +                               CRS_UINT("Maximum Base Address",        4, 16),
> +                               CRS_UINT("Base Alignment",              6, 8),
> +                               CRS_UINT("Range Length",                7, 8),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "I/O Port Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x9: /* 6.4.2.6 Fixed Location I/O Port Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINT("Range Base Address",          1, 16),
> +                               CRS_UINT("Range Length",                3, 8),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "Fixed Location I/O Port Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0xa: /* 6.4.2.7 Fixed DMA Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINT("DMA Request Line",            1, 16),
> +                               CRS_UINT("DMA Channel",                 3, 16),
> +                               CRS_UINTX("DMA Transfer Width",         5, 1, crs_dma_transfer_width),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "Fixed DMA Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0xe: /* 6.4.2.8 Vendor-Defined Descriptor */
> +               crsdump_show_header(fw, objname, "Vendor-Defined Descriptor");
> +               crsdump_show_info(fw, data, crs_length, header);
> +               crsdump_data(fw, data, 3, crs_length);
> +               break;
> +       case 0xf: /* 6.4.2.9 End Tag */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINT("Checksum",                    1, 8),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "End Tag",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       default:
> +               crsdump_show_header(fw, objname, "Unknown type");
> +               crsdump_show_info(fw, data, crs_length, header);
> +               crsdump_data(fw, data, 1, crs_length);
> +               break;
> +       }
> +
> +       fwts_log_nl(fw);
> +}
> +
> +/*
> + *  CRS large resource checks, simple checking
> + */
> +static void crsdump_large_resource_items(
> +       fwts_framework *fw,
> +       const char *objname,
> +       const uint8_t *data,
> +       const uint64_t length)
> +{
> +       uint8_t tag_item = data[0] & 0x7f;
> +       size_t crs_length = data[1];
> +
> +       static const crsdump_info header[] = {
> +               CRS_BITS("Tag Type",            0, 128),
> +               CRS_BITS("Tag Item ID",         0, 0x7f),
> +               CRS_UINT("Length",              1, 16),
> +               CRS_END
> +       };
> +
> +       static const char *write_status[] = {
> +               "non-writeable, read-only",
> +               "writeable, read/write"
> +       };
> +
> +       static const char *mifmaf[] = {
> +               "Not fixed",
> +               "Fixed"
> +       };
> +
> +       static const char *decode_type[] = {
> +               "Bridge Positively decodes this address",
> +               "Bridge Subtractively decode this address"
> +       };
> +
> +       static const char *sharing[] = {
> +               "Exclusive",
> +               "Shared",
> +               "Exclusive and Wake",
> +               "Shared and Wake"
> +       };
> +
> +       static const char *polarity[] = {
> +               "Active-High",
> +               "Active-Low",
> +               "Active-Both",
> +               "Reserved"
> +       };
> +
> +       static const char *mode[] = {
> +               "Level-Triggered",
> +               "Edge-Triggered"
> +       };
> +
> +       static const char *consumer[] = {
> +               "producer and consumer",
> +               "consumer"
> +       };
> +
> +       /* Ensure we just dump minimum _CRS buffer length */
> +       if (crs_length > length)
> +               crs_length = length;
> +
> +       switch (tag_item) {
> +       case 0x1: /* 6.4.3.1 24-Bit Memory Range Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_BITX("Write Status",                3, 1, write_status),
> +                               CRS_UINT24("Range Minimum Base",        4, 16),
> +                               CRS_UINT24("Range Maximum Base",        6, 16),
> +                               CRS_UINT("Base Alignment",              8, 16),
> +                               CRS_UINT("Range Length",                10, 16),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "24-Bit Memory Range Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x2: /* 6.4.3.7 Generic Register Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINTX("Address Space ID",           3, 8, crs_address_space_id),
> +                               CRS_UINT("Address Bit Width",           4, 8),
> +                               CRS_UINT("Register Bit Offset",         5, 8),
> +                               CRS_UINTX("Address Size",               6, 8, crs_address_size),
> +                               CRS_UINT("Register Address",            7, 64),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "Generic Register Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x4: /* 6.4.3.2 Vendor-Defined Descriptor */
> +               crsdump_show_header(fw, objname, "Vendor-Defined Descriptor");
> +               crsdump_show_info(fw, data, crs_length, header);
> +               crsdump_data(fw, data, 3, crs_length);
> +               break;
> +       case 0x5: /* 6.4.3.3 32-Bit Memory Range Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_BITX("Write Status",                3, 1, write_status),
> +                               CRS_UINT("Range Minimum Address",       4, 32),
> +                               CRS_UINT("Range Maximum Address",       8, 32),
> +                               CRS_UINT("Base Alignment",              12, 32),
> +                               CRS_UINT("Range Length",                16, 32),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "32-Bit Memory Range Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x6: /* 6.4.3.4 32-Bit Fixed Memory Range Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_BITX("Write Status",                3, 1, write_status),
> +                               CRS_UINT("Range Base Address",          4, 32),
> +                               CRS_UINT("Range Length",                8, 32),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "32-Bit Fixed Memory Range Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x7: /* 6.4.3.5.2 DWord Address Space Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINTX("Resource Type",              3, 8, crs_resource_type),
> +                               CRS_BITS("Reserved",                    4, 0xf0),
> +                               CRS_BITX("Max Address Fixed",           4, 8, mifmaf),
> +                               CRS_BITX("Min Address Fixed",           4, 4, mifmaf),
> +                               CRS_BITX("Decode Type",                 4, 2, decode_type),
> +                               CRS_BITS("Ignored",                     4, 1),
> +                               CRS_UINT("Type Specific Flags",         5, 8),
> +                               CRS_UINT("Address Space Granularity",   6, 32),
> +                               CRS_UINT("Address Range Minimum",       10, 32),
> +                               CRS_UINT("Address Range Maximum",       14, 32),
> +                               CRS_UINT("Address Translation Offset",  18, 32),
> +                               CRS_UINT("Address Length",              22, 32),
> +                               CRS_UINT("Resource Source Index",       26, 1),
> +                               /* Skip Resource Source String */
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "DWord Address Space Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x8: /* 6.4.3.5.3 Word Address Space Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINTX("Resource Type",              3, 8, crs_resource_type),
> +                               CRS_BITS("Reserved",                    4, 0xf0),
> +                               CRS_BITX("Max Address Fixed",           4, 8, mifmaf),
> +                               CRS_BITX("Min Address Fixed",           4, 4, mifmaf),
> +                               CRS_BITX("Decode Type",                 4, 2, decode_type),
> +                               CRS_BITS("Ignored",                     4, 1),
> +                               CRS_UINT("Type Specific Flags",         5, 8),
> +                               CRS_UINT("Address Space Granularity",   6, 16),
> +                               CRS_UINT("Address Range Minimum",       8, 16),
> +                               CRS_UINT("Address Range Maximum",       10, 16),
> +                               CRS_UINT("Address Translation Offset",  12, 16),
> +                               CRS_UINT("Address Length",              14, 16),
> +                               CRS_UINT("Resource Source Index",       16, 1),
> +                               /* Skip Resource Source String */
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "Word Address Space Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0x9: /* 6.4.3.6 Extended Interrupt Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_BITS("Reserved",                    3, 128 | 64 | 32),
> +                               CRS_BITX("Interrupt Sharing",           3, 16 | 8, sharing),
> +                               CRS_BITX("Interrupt Polarity",          7, 4, polarity),
> +                               CRS_BITX("Interrupt Mode",              7, 2, mode),
> +                               CRS_BITX("Interrupt Consumer/Producer", 7, 1, consumer),
> +                               CRS_UINT("Interrupt Table Length",      8, 8),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "Extended Interrupt Descriptor",
> +                               data, crs_length, header, info);
> +                       crsdump_data(fw, data, 5, crs_length);
> +               }
> +               break;
> +       case 0xa: /* 6.4.3.5.1 QWord Address Space Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINTX("Resource Type",              3, 8, crs_resource_type),
> +                               CRS_BITS("Reserved",                    4, 0xf0),
> +                               CRS_BITX("Max Address Fixed",           4, 8, mifmaf),
> +                               CRS_BITX("Min Address Fixed",           4, 4, mifmaf),
> +                               CRS_BITX("Decode Type",                 4, 2, decode_type),
> +                               CRS_BITS("Ignored",                     4, 1),
> +                               CRS_UINT("Type Specific Flags",         5, 8),
> +                               CRS_UINT("Address Space Granularity",   6, 64),
> +                               CRS_UINT("Address Range Minimum",       14, 64),
> +                               CRS_UINT("Address Range Maximum",       22, 64),
> +                               CRS_UINT("Address Translation Offset",  30, 64),
> +                               CRS_UINT("Address Length",              38, 64),
> +                               CRS_UINT("Resource Source Index",       46, 1),
> +                               /* Skip Resource Source String */
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "QWord Address Space Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0xb: /* 6.4.3.5.4 Extended Address Space Descriptor */
> +               {
> +                       static const crsdump_info info[] = {
> +                               CRS_UINTX("Resource Type",              3, 8, crs_resource_type),
> +                               CRS_BITS("Reserved",                    4, 0xf0),
> +                               CRS_BITX("Max Address Fixed",           4, 8, mifmaf),
> +                               CRS_BITX("Min Address Fixed",           4, 4, mifmaf),
> +                               CRS_BITX("Decode Type",                 4, 2, decode_type),
> +                               CRS_BITX("Consumer/Producer",           4, 1, consumer),
> +                               CRS_UINT("Type Specific Flags",         5, 8),
> +                               CRS_UINT("Revision ID",                 6, 8),
> +                               CRS_UINT("Reserved",                    7, 8),
> +                               CRS_UINT("Address Space Granularity",   8, 64),
> +                               CRS_UINT("Address Range Minimum",       16, 64),
> +                               CRS_UINT("Address Range Maximum",       24, 64),
> +                               CRS_UINT("Address Translation Offset",  32, 64),
> +                               CRS_UINT("Address Length",              40, 64),
> +                               CRS_UINT("Type Specific Attribute",     48, 64),
> +                               CRS_END
> +                       };
> +
> +                       crsdump_show(fw, objname, "Extended Address Space Descriptor",
> +                               data, crs_length, header, info);
> +               }
> +               break;
> +       case 0xc: /* 6.4.3.8.1 GPIO Connection Descriptor */
> +               {
> +                       if (crs_length < 4)
> +                               break;
> +
> +                       if (data[4] == 0) {
> +
> +                               /* Interrupt connection */
> +                               static const crsdump_info info[] = {
> +                                       CRS_UINT("Revision ID",                 3, 8),
> +                                       CRS_UINTX("GPIO Connection Type",       4, 8, crs_gpio_connection_type),
> +                                       CRS_BITS("Reserved",                    5, 0xfe),
> +                                       CRS_BITX("Consumer/Producer",           5, 1, consumer),
> +                                       CRS_UINT("Reserved",                    6, 8),
> +                                       CRS_BITS("Reserved",                    7, 128 | 64 | 32),
> +                                       CRS_BITX("Interrupt Sharing and Wake",  7, 16 | 8, sharing),
> +                                       CRS_BITX("Interrupt Polarity",          7, 4 | 2, polarity),
> +                                       CRS_BITX("Interrupt Mode",              7, 1, mode),
> +                                       CRS_UINT("Interrupt and I/O Flags",     8, 8),
> +                                       CRS_UINTX("Pin Configuration",          9, 8, crs_pin_configuration),
> +                                       CRS_UINT("Output Driver Strength",      10, 16),
> +                                       CRS_UINT("Debounce Timeout (bits)",     12, 16),
> +                                       CRS_UINT("Pin Table Offset",            14, 16),
> +                                       CRS_UINT("Resource Source Index",       16, 8),
> +                                       CRS_UINT("Resource Name Offset",        17, 16),
> +                                       CRS_UINT("Vendor Data Offset",          19, 16),
> +                                       CRS_UINT("Vendor Data Length",          21, 16),
> +                                       /* Skip pin table */
> +                                       CRS_END
> +                               };
> +
> +                               crsdump_show(fw, objname, "GPIO Connection Descriptor",
> +                                       data, crs_length, header, info);
> +                       } else if (data[4] == 1) {
> +                               static const char *sharing[] = {
> +                                       "Exclusive",
> +                                       "Shared",
> +                               };
> +
> +                               static const char *restriction[] = {
> +                                       "Input or Output",
> +                                       "Input Only",
> +                                       "Output Only",
> +                                       "Input or Ouput, config must be preserved"
> +                               };
> +
> +                               /* I/O connection */
> +                               static const crsdump_info info[] = {
> +                                       CRS_UINT("Revision ID",                 3, 8),
> +                                       CRS_UINTX("GPIO Connection Type",       4, 8, crs_gpio_connection_type),
> +                                       CRS_BITS("Reserved",                    5, 0xfe),
> +                                       CRS_BITX("Consumer/Producer",           5, 1, consumer),
> +                                       CRS_UINT("Reserved",                    6, 8),
> +                                       CRS_BITS("Reserved",                    7, 128 | 64 | 32 | 16),
> +                                       CRS_BITX("Interrupt Sharing",           7, 8, sharing),
> +                                       CRS_BITS("Reserved",                    7, 4),
> +                                       CRS_BITX("I/O Restriction",             7, 2 | 1, restriction),
> +                                       CRS_UINT("Interrupt and I/O Flags",     8, 8),
> +                                       CRS_UINTX("Pin Configuration",          9, 8, crs_pin_configuration),
> +                                       CRS_UINT("Output Driver Strength",      10, 16),
> +                                       CRS_UINT("Debounce Timeout (bits)",     12, 16),
> +                                       CRS_UINT("Pin Table Offset",            14, 16),
> +                                       CRS_UINT("Resource Source Index",       16, 8),
> +                                       CRS_UINT("Resource Name Offset",        17, 16),
> +                                       CRS_UINT("Vendor Data Offset",          19, 16),
> +                                       CRS_UINT("Vendor Data Length",          21, 16),
> +                                       /* Skip pin table */
> +                                       CRS_END
> +                               };
> +
> +                               crsdump_show(fw, objname, "GPIO Connection Descriptor",
> +                                       data, crs_length, header, info);
> +                       } else {
> +                               /* No idea of the connection type */
> +                               static const crsdump_info info[] = {
> +                                       CRS_UINT("Revision ID",                 3, 8),
> +                                       CRS_UINT("GPIO Connection Type",        4, 8),
> +                                       CRS_END
> +                               };
> +
> +                               crsdump_show(fw, objname, "GPIO Connection Descriptor",
> +                                       data, crs_length, header, info);
> +                       }
> +
> +               }
> +               break;
> +       case 0xe: /* 6.4.3.8.2 Serial Bus Connection Descriptors */
> +               /*  This is not frequently used, deferring implementation to later */
> +               crsdump_show_header(fw, objname, "Serial Bus Connection Descriptor");
> +               crsdump_show_info(fw, data, crs_length, header);
> +               crsdump_data(fw, data, 3, crs_length);
> +               break;
> +       default:
> +               crsdump_show_header(fw, objname, "Unknown type");
> +               crsdump_show_info(fw, data, crs_length, header);
> +               crsdump_data(fw, data, 3, crs_length);
> +               break;
> +       }
> +
> +       fwts_log_nl(fw);
> +}
> +
> +static int crsdump_test1(fwts_framework *fw)
> +{
> +       fwts_list_link  *item;
> +       fwts_list *objects;
> +       const size_t name_len = 4;
> +
> +       if ((objects = fwts_acpi_object_get_names()) == NULL) {
> +               fwts_log_info(fw, "Cannot find any ACPI objects");
> +               return FWTS_ERROR;
> +       }
> +
> +       fwts_list_foreach(item, objects) {
> +               char *name = fwts_list_data(char*, item);
> +               const size_t len = strlen(name);
> +               if (strncmp("_CRS", name + len - name_len, name_len) == 0) {
> +                       ACPI_OBJECT_LIST arg_list;
> +                       ACPI_BUFFER buf;
> +                       ACPI_OBJECT *obj;
> +                       uint8_t *data;
> +                       int ret;
> +
> +                       arg_list.Count   = 0;
> +                       arg_list.Pointer = NULL;
> +
> +                       ret = fwts_acpi_object_evaluate(fw, name, &arg_list, &buf);
> +                       if ((ACPI_FAILURE(ret) != AE_OK) || (buf.Pointer == NULL))
> +                               continue;
> +
> +                       /*  Do we have a valid _CRS buffer to dump? */
> +                       obj = buf.Pointer;
> +                       if ((obj->Type == ACPI_TYPE_BUFFER) &&
> +                           (obj->Buffer.Pointer != NULL) &&
> +                           (obj->Buffer.Length > 0)) {
> +                               data = (uint8_t*)obj->Buffer.Pointer;
> +
> +                               if (data[0] & 128)
> +                                       crsdump_large_resource_items(fw, name, data, obj->Buffer.Length);
> +                               else
> +                                       crsdump_small_resource_items(fw, name, data, obj->Buffer.Length);
> +                       }
> +
> +                       if (buf.Length && buf.Pointer)
> +                               free(buf.Pointer);
> +               }
> +       }
> +       return FWTS_OK;
> +}
> +
> +static fwts_framework_minor_test crsdump_tests[] = {
> +       { crsdump_test1, "Dump ACPI _CRS buffers." },
> +       { NULL, NULL }
> +};
> +
> +static fwts_framework_ops crsdump_ops = {
> +       .description = "Dump ACPI _CRS buffers.",
> +       .init        = crsdump_init,
> +       .deinit      = crsdump_deinit,
> +       .minor_tests = crsdump_tests
> +};
> +
> +FWTS_REGISTER("crsdump", &crsdump_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UTILS);
> --
> 1.8.0
>
Acked-by: Keng-Yu Lin <kengyu@canonical.com>
diff mbox

Patch

diff --git a/src/Makefile.am b/src/Makefile.am
index d62574b..f80936d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -27,6 +27,7 @@  fwts_SOURCES = main.c 				\
 	acpi/battery/battery.c 			\
 	acpi/brightness/brightness.c 		\
 	acpi/checksum/checksum.c 		\
+	acpi/crsdump/crsdump.c			\
 	acpi/cstates/cstates.c 			\
 	acpi/dmar/dmar.c 			\
 	acpi/fadt/fadt.c 			\
diff --git a/src/acpi/crsdump/crsdump.c b/src/acpi/crsdump/crsdump.c
new file mode 100644
index 0000000..d6dd6df
--- /dev/null
+++ b/src/acpi/crsdump/crsdump.c
@@ -0,0 +1,892 @@ 
+/*
+ * Copyright (C) 2013 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#include "fwts.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+/* acpica headers */
+#include "acpi.h"
+#include "fwts_acpi_object_eval.h"
+
+typedef struct {
+	const char *label;				/* Field label */
+	size_t offset;					/* Offset into _CRS buffer */
+	size_t bitlength;				/* Size of field in bits */
+	uint64_t bitmask;				/* Bit mask, 0 = use all bits */
+	uint8_t shift;					/* Value shift */
+	const char **annotation;			/* Annotations */
+	const char *(*callback)(const uint64_t val);	/* val -> string mapping callback for CRS_UINTX */
+} crsdump_info;
+
+#define CRS_UINT(label, offset, bitlength)		{ label, offset, bitlength, 0, 0, NULL, NULL }
+#define CRS_UINT24(label, offset, bitlength)		{ label, offset, bitlength, 0, 8, NULL, NULL }
+#define CRS_UINTX(label, offset, bitlength, callback)	{ label, offset, bitlength, 0, 0, NULL, callback }
+
+#define CRS_BITS(label, offset, bitmask)		{ label, offset, 8, bitmask, 0, NULL, NULL }
+#define CRS_BITX(label, offset, bitmask, annotation) 	{ label, offset, 8, bitmask, 0, annotation, NULL }
+#define CRS_END						{ NULL, 0, 0, 0, 0, 0, NULL }
+
+static void crsdump_show_header(
+	fwts_framework *fw,
+	const char *objname,
+	const char *crs_name)
+{
+	fwts_log_info_verbatum(fw, "%s (%s):", objname, crs_name);
+}
+
+static void crsdump_show_info(
+	fwts_framework *fw,
+	const uint8_t *data,
+	const size_t length,
+	const crsdump_info *info)
+{
+	/*
+	 *  Walk through fields and dump data according to the mapping
+	 */
+	for ( ; info->label; info++) {
+		uint64_t val;
+		uint64_t mask = info->bitmask;
+		int hexdigits = info->bitlength >> 2;
+
+		if (info->offset + (info->bitlength >> 3) > length)
+			continue;
+
+		if (info->bitmask) {
+			/*
+			 *  CRS_BIT*() data
+			 */
+			val = (uint64_t)*(uint8_t*)(data + info->offset);
+			while (mask && ((mask & 1) == 0)) {
+				val >>= 1;
+				mask >>= 1;
+			}
+			val &= mask;
+			hexdigits = 2;
+		} else {
+			/*
+			 *  CRS_UINT*() data
+			 */
+			switch (info->bitlength) {
+			case 8:
+				val = (uint64_t)*(uint8_t*)(data + info->offset);
+				break;
+			case 16:
+				val = (uint64_t)*(uint16_t*)(data + info->offset);
+				break;
+			case 32:
+				val = (uint64_t)*(uint32_t*)(data + info->offset);
+				break;
+			case 64:
+				val = (uint64_t)*(uint64_t*)(data + info->offset);
+				break;
+			default:
+				val = ~0;
+				break;
+			}
+		}
+		val = val << info->shift;
+
+		if (info->annotation) {
+			fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64 " (%s)",
+				(uint16_t)info->offset, info->label, hexdigits, hexdigits, val,
+				info->annotation[val]);
+		} else if (info->callback) {
+			fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64 " (%s)",
+				(uint16_t)info->offset, info->label, hexdigits, hexdigits, val,
+				info->callback(val));
+		} else {
+			fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: 0x%-*.*" PRIx64,
+				(uint16_t)info->offset, info->label, hexdigits, hexdigits, val);
+		}
+	}
+}
+
+static void crsdump_show(
+	fwts_framework *fw,
+	const char *objname,
+	const char *crs_name,
+	const uint8_t *data,
+	const size_t length,
+	const crsdump_info *header,
+	const crsdump_info *info)
+{
+	crsdump_show_header(fw, objname, crs_name);
+	crsdump_show_info(fw, data, length, header);
+	crsdump_show_info(fw, data, length, info);
+}
+
+static void crsdump_data(
+	fwts_framework *fw,
+	const uint8_t *data,
+	const size_t from,
+	const size_t to)
+{
+	size_t i;
+	char buffer[120];
+
+	for (i = from; i < to; i+= 16) {
+		size_t n = to - i;
+
+		fwts_dump_raw_data(buffer, sizeof(buffer), data + i, i, n > 16 ? 16 : n);
+		buffer[56] = '\0';	/* Truncate off text version of hex dump */
+
+		fwts_log_info_verbatum(fw, "  0x%4.4" PRIx16 ": %-30.30s: %s",
+			(uint16_t)i, "Hex Dump", buffer + 8);
+	}
+}
+
+/*
+ *  crsdump_init()
+ *	initialize ACPI
+ */
+static int crsdump_init(fwts_framework *fw)
+{
+	if (fwts_acpi_init(fw) != FWTS_OK) {
+		fwts_log_error(fw, "Cannot initialise ACPI.");
+		return FWTS_ERROR;
+	}
+
+	return FWTS_OK;
+}
+
+/*
+ *  crsdump_deinit
+ *	de-intialize ACPI
+ */
+static int crsdump_deinit(fwts_framework *fw)
+{
+	return fwts_acpi_deinit(fw);
+}
+
+/*
+ *  See section 6.4.2.7 Fixed DMA Descriptor, DMA transfer width
+ */
+static const char *crs_dma_transfer_width(const uint64_t val)
+{
+	switch (val) {
+	case 0x00:
+		return "8 bit";
+	case 0x01:
+		return "16 bit";
+	case 0x02:
+		return "32 bit";
+	case 0x03:
+		return "64 bit";
+	case 0x04:
+		return "128 bit";
+	case 0x05:
+		return "256 bit";
+	default:
+		return "reserved";
+	}
+}
+
+/*
+ *  See section 6.4.3.5.2 DWord Address Space Descriptor Resource Type
+ */
+static const char *crs_resource_type(const uint64_t val)
+{
+	switch (val) {
+	case 0x00:
+		return "Memory range";
+	case 0x01:
+		return "I/O range";
+	case 0x02:
+		return "Bus number range";
+	case 0xc0 ... 0xff:
+		return "Hardware Vendor Defined";
+	default:
+		return "Reserved";
+	}
+}
+
+/*
+ *  See section 6.4.8.1. Generic Register Descriptor Address Space ID
+ */
+static const char *crs_address_space_id(const uint64_t val)
+{
+	switch (val) {
+	case 0x00:
+		return "System Memory";
+	case 0x01:
+		return "System I/O";
+	case 0x02:
+		return "PCI Configuration Space";
+	case 0x03:
+		return "Embedded Controller";
+	case 0x04:
+		return "SMBus";
+	case 0x0a:
+		return "PCC";
+	case 0x7f:
+		return "Functional Fixed Hardware";
+	default:
+		return "Uknown";
+	}
+}
+
+/*
+ *  See section 6.4.8.1. Generic Register Descriptor Address Size
+ */
+static const char *crs_address_size(const uint64_t val)
+{
+	switch (val) {
+	case 0x00:
+		return "Undefined (legacy)";
+	case 0x01:
+		return "Byte Access";
+	case 0x02:
+		return "Word Access";
+	case 0x04:
+		return "Dword Access";
+	case 0x08:
+		return "Qword Access";
+	default:
+		return "Unknown";
+	}
+}
+
+/*
+ *  See section 6.4.3.8.1 GPIO Connection Description
+ */
+static const char *crs_gpio_connection_type(const uint64_t val)
+{
+	switch (val) {
+	case 0x00:
+		return "Interrupt Connection";
+	case 0x01:
+		return "I/O Connection";
+	default:
+		return "Reserved";
+	}
+}
+
+/*
+ *  See section 6.4.3.8.1 GPIO Connection Description
+ */
+static const char *crs_pin_configuration(const uint64_t val)
+{
+	switch (val) {
+	case 0x00:
+		return "Default Configuration";
+	case 0x01:
+		return "Pull-Up";
+	case 0x02:
+		return "Pull-Down";
+	case 0x03:
+		return "No Pull";
+	case 0x80 ... 0xff:
+		return "Vendor Defined";
+	default:
+		return "Reserved";
+	}
+}
+
+/*
+ *  CRS small resource checks, simple checking
+ */
+static void crsdump_small_resource_items(
+	fwts_framework *fw,
+	const char *objname,
+	const uint8_t *data,
+	const size_t length)
+{
+	uint8_t tag_item = (data[0] >> 3) & 0xf;
+	size_t crs_length = 1 + (data[0] & 7);
+
+	static const crsdump_info header[] = {
+		CRS_BITS("Tag Type",		0, 128),
+		CRS_BITS("Tag Item ID",		0, 64 | 32 | 16 | 8),
+		CRS_BITS("Tag Length",		0, 4 | 2 | 1),
+	};
+
+	/* Ensure we just dump minimum _CRS buffer length */
+	if (crs_length > length)
+		crs_length = length;
+
+	switch (tag_item) {
+	case 0x4: /* 6.4.2.1 IRQ Descriptor */
+		{
+			static const char *sharing[] = {
+				"Exclusive",
+				"Shared",
+				"Exclusive And Wake",
+				"Shared And Wake"
+			};
+
+			static const char *polarity[] = {
+				"Active-High",
+				"Active-Low"
+			};
+
+			static const char *mode[] = {
+				"Level-Triggered",
+				"Edge-Triggered"
+			};
+
+			static const crsdump_info info[] = {
+				CRS_UINT("IRQ Mask",		1, 16),
+				CRS_BITS("Reserved",		3, 128 | 64),
+				CRS_BITX("Interrupt Sharing",	3, 32 | 16, sharing),
+				CRS_BITX("Interrupt Polarity",	3, 8, polarity),
+				CRS_BITS("Ignored",		3, 4 | 2),
+				CRS_BITX("Interrupt Mode",	3, 1, mode),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "IRQ Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x5: /* 6.4.2.2 DMA Descriptor */
+		{
+			static const char *dma_speed[] = {
+				"Compatibility Mode",
+				"Type A DMA",
+				"Type B DMA",
+				"Type F DMA"
+			};
+
+			static const char *bus_master[] = {
+				"Not a bus master",
+				"Is a bus master"
+			};
+
+			static const char *dma_size[] = {
+				"8 bit only",
+				"8 and 16 bit",
+				"16 bit only",
+				"Reserved"
+			};
+
+			static const crsdump_info info[] = {
+				CRS_UINT("DMA channel mask",		1, 16),
+				CRS_BITS("Reserved",			2, 128),
+				CRS_BITX("DMA channel speed",		2, 64 | 32, dma_speed),
+				CRS_BITS("Ignored",			2, 16 | 8),
+				CRS_BITX("Logical device bus master",	2, 4, bus_master),
+				CRS_BITX("DMA transfer type preference",2, 2 | 1, dma_size),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "DMA Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x6: /* 6.4.2.3 Start Dependent Functions Descriptor */
+		{
+			static const char *config[] = {
+				"Good configurarion",
+				"Acceptable configuration",
+				"Sub-optimal configuration",
+				"Reserved"
+			};
+
+			static const crsdump_info info[] = {
+				CRS_BITS("Reserved",			1, 0xf0),
+				CRS_BITX("Performance/robustness",	1, 8 | 4, config),
+				CRS_BITX("Compatibility priority",	1, 2 | 1, config),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "Start Dependent Functions Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x7: /* 6.4.2.4 End Dependent Functions Descriptor */
+		crsdump_show_header(fw, objname, "End Dependent Functions Descriptor");
+		break;
+	case 0x8: /* 6.4.2.5 I/O Port Descriptor */
+		{
+			static const char *decodes[] = {
+				"16 bit addresses",
+				"10 bit addresses"
+			};
+			static const crsdump_info info[] = {
+				CRS_BITS("Reserved",			1, 0xfe),
+				CRS_BITX("Logical Device Decode",	1, 1, decodes),
+				CRS_UINT("Minimum Base Address",	2, 16),
+				CRS_UINT("Maximum Base Address",	4, 16),
+				CRS_UINT("Base Alignment",		6, 8),
+				CRS_UINT("Range Length",		7, 8),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "I/O Port Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x9: /* 6.4.2.6 Fixed Location I/O Port Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINT("Range Base Address",		1, 16),
+				CRS_UINT("Range Length",		3, 8),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "Fixed Location I/O Port Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0xa: /* 6.4.2.7 Fixed DMA Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINT("DMA Request Line",		1, 16),
+				CRS_UINT("DMA Channel",			3, 16),
+				CRS_UINTX("DMA Transfer Width",		5, 1, crs_dma_transfer_width),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "Fixed DMA Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0xe: /* 6.4.2.8 Vendor-Defined Descriptor */
+		crsdump_show_header(fw, objname, "Vendor-Defined Descriptor");
+		crsdump_show_info(fw, data, crs_length, header);
+		crsdump_data(fw, data, 3, crs_length);
+		break;
+	case 0xf: /* 6.4.2.9 End Tag */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINT("Checksum",			1, 8),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "End Tag",
+				data, crs_length, header, info);
+		}
+		break;
+	default:
+		crsdump_show_header(fw, objname, "Unknown type");
+		crsdump_show_info(fw, data, crs_length, header);
+		crsdump_data(fw, data, 1, crs_length);
+		break;
+	}
+
+	fwts_log_nl(fw);
+}
+
+/*
+ *  CRS large resource checks, simple checking
+ */
+static void crsdump_large_resource_items(
+	fwts_framework *fw,
+	const char *objname,
+	const uint8_t *data,
+	const uint64_t length)
+{
+	uint8_t tag_item = data[0] & 0x7f;
+	size_t crs_length = data[1];
+
+	static const crsdump_info header[] = {
+		CRS_BITS("Tag Type",		0, 128),
+		CRS_BITS("Tag Item ID",		0, 0x7f),
+		CRS_UINT("Length",		1, 16),
+		CRS_END
+	};
+
+	static const char *write_status[] = {
+		"non-writeable, read-only",
+		"writeable, read/write"
+	};
+
+	static const char *mifmaf[] = {
+		"Not fixed",
+		"Fixed"
+	};
+
+	static const char *decode_type[] = {
+		"Bridge Positively decodes this address",
+		"Bridge Subtractively decode this address"
+	};
+
+	static const char *sharing[] = {
+		"Exclusive",
+		"Shared",
+		"Exclusive and Wake",
+		"Shared and Wake"
+	};
+
+	static const char *polarity[] = {
+		"Active-High",
+		"Active-Low",
+		"Active-Both",
+		"Reserved"
+	};
+
+	static const char *mode[] = {
+		"Level-Triggered",
+		"Edge-Triggered"
+	};
+
+	static const char *consumer[] = {
+		"producer and consumer",
+		"consumer"
+	};
+
+	/* Ensure we just dump minimum _CRS buffer length */
+	if (crs_length > length)
+		crs_length = length;
+
+	switch (tag_item) {
+	case 0x1: /* 6.4.3.1 24-Bit Memory Range Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_BITX("Write Status",		3, 1, write_status),
+				CRS_UINT24("Range Minimum Base",	4, 16),
+				CRS_UINT24("Range Maximum Base",	6, 16),
+				CRS_UINT("Base Alignment",		8, 16),
+				CRS_UINT("Range Length",		10, 16),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "24-Bit Memory Range Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x2: /* 6.4.3.7 Generic Register Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINTX("Address Space ID",		3, 8, crs_address_space_id),
+				CRS_UINT("Address Bit Width",		4, 8),
+				CRS_UINT("Register Bit Offset",		5, 8),
+				CRS_UINTX("Address Size",		6, 8, crs_address_size),
+				CRS_UINT("Register Address",		7, 64),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "Generic Register Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x4: /* 6.4.3.2 Vendor-Defined Descriptor */
+		crsdump_show_header(fw, objname, "Vendor-Defined Descriptor");
+		crsdump_show_info(fw, data, crs_length, header);
+		crsdump_data(fw, data, 3, crs_length);
+		break;
+	case 0x5: /* 6.4.3.3 32-Bit Memory Range Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_BITX("Write Status",		3, 1, write_status),
+				CRS_UINT("Range Minimum Address",	4, 32),
+				CRS_UINT("Range Maximum Address",	8, 32),
+				CRS_UINT("Base Alignment",		12, 32),
+				CRS_UINT("Range Length",		16, 32),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "32-Bit Memory Range Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x6: /* 6.4.3.4 32-Bit Fixed Memory Range Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_BITX("Write Status",		3, 1, write_status),
+				CRS_UINT("Range Base Address",		4, 32),
+				CRS_UINT("Range Length",		8, 32),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "32-Bit Fixed Memory Range Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x7: /* 6.4.3.5.2 DWord Address Space Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
+				CRS_BITS("Reserved",			4, 0xf0),
+				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
+				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
+				CRS_BITX("Decode Type",			4, 2, decode_type),
+				CRS_BITS("Ignored",			4, 1),
+				CRS_UINT("Type Specific Flags",		5, 8),
+				CRS_UINT("Address Space Granularity",	6, 32),
+				CRS_UINT("Address Range Minimum",	10, 32),
+				CRS_UINT("Address Range Maximum",	14, 32),
+				CRS_UINT("Address Translation Offset",	18, 32),
+				CRS_UINT("Address Length",		22, 32),
+				CRS_UINT("Resource Source Index",	26, 1),
+				/* Skip Resource Source String */
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "DWord Address Space Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x8: /* 6.4.3.5.3 Word Address Space Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
+				CRS_BITS("Reserved",			4, 0xf0),
+				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
+				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
+				CRS_BITX("Decode Type",			4, 2, decode_type),
+				CRS_BITS("Ignored",			4, 1),
+				CRS_UINT("Type Specific Flags",		5, 8),
+				CRS_UINT("Address Space Granularity",	6, 16),
+				CRS_UINT("Address Range Minimum",	8, 16),
+				CRS_UINT("Address Range Maximum",	10, 16),
+				CRS_UINT("Address Translation Offset",	12, 16),
+				CRS_UINT("Address Length",		14, 16),
+				CRS_UINT("Resource Source Index",	16, 1),
+				/* Skip Resource Source String */
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "Word Address Space Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0x9: /* 6.4.3.6 Extended Interrupt Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_BITS("Reserved",			3, 128 | 64 | 32),
+				CRS_BITX("Interrupt Sharing",		3, 16 | 8, sharing),
+				CRS_BITX("Interrupt Polarity",		7, 4, polarity),
+				CRS_BITX("Interrupt Mode",		7, 2, mode),
+				CRS_BITX("Interrupt Consumer/Producer",	7, 1, consumer),
+				CRS_UINT("Interrupt Table Length",	8, 8),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "Extended Interrupt Descriptor",
+				data, crs_length, header, info);
+			crsdump_data(fw, data, 5, crs_length);
+		}
+		break;
+	case 0xa: /* 6.4.3.5.1 QWord Address Space Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
+				CRS_BITS("Reserved",			4, 0xf0),
+				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
+				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
+				CRS_BITX("Decode Type",			4, 2, decode_type),
+				CRS_BITS("Ignored",			4, 1),
+				CRS_UINT("Type Specific Flags",		5, 8),
+				CRS_UINT("Address Space Granularity",	6, 64),
+				CRS_UINT("Address Range Minimum",	14, 64),
+				CRS_UINT("Address Range Maximum",	22, 64),
+				CRS_UINT("Address Translation Offset",	30, 64),
+				CRS_UINT("Address Length",		38, 64),
+				CRS_UINT("Resource Source Index",	46, 1),
+				/* Skip Resource Source String */
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "QWord Address Space Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0xb: /* 6.4.3.5.4 Extended Address Space Descriptor */
+		{
+			static const crsdump_info info[] = {
+				CRS_UINTX("Resource Type",		3, 8, crs_resource_type),
+				CRS_BITS("Reserved",			4, 0xf0),
+				CRS_BITX("Max Address Fixed",		4, 8, mifmaf),
+				CRS_BITX("Min Address Fixed",		4, 4, mifmaf),
+				CRS_BITX("Decode Type",			4, 2, decode_type),
+				CRS_BITX("Consumer/Producer",		4, 1, consumer),
+				CRS_UINT("Type Specific Flags",		5, 8),
+				CRS_UINT("Revision ID",			6, 8),
+				CRS_UINT("Reserved",			7, 8),
+				CRS_UINT("Address Space Granularity",	8, 64),
+				CRS_UINT("Address Range Minimum",	16, 64),
+				CRS_UINT("Address Range Maximum",	24, 64),
+				CRS_UINT("Address Translation Offset",	32, 64),
+				CRS_UINT("Address Length",		40, 64),
+				CRS_UINT("Type Specific Attribute",	48, 64),
+				CRS_END
+			};
+
+			crsdump_show(fw, objname, "Extended Address Space Descriptor",
+				data, crs_length, header, info);
+		}
+		break;
+	case 0xc: /* 6.4.3.8.1 GPIO Connection Descriptor */
+		{
+			if (crs_length < 4)
+				break;
+
+			if (data[4] == 0) {
+
+				/* Interrupt connection */
+				static const crsdump_info info[] = {
+					CRS_UINT("Revision ID",			3, 8),
+					CRS_UINTX("GPIO Connection Type",	4, 8, crs_gpio_connection_type),
+					CRS_BITS("Reserved",			5, 0xfe),
+					CRS_BITX("Consumer/Producer",		5, 1, consumer),
+					CRS_UINT("Reserved",			6, 8),
+					CRS_BITS("Reserved",			7, 128 | 64 | 32),
+					CRS_BITX("Interrupt Sharing and Wake",	7, 16 | 8, sharing),
+					CRS_BITX("Interrupt Polarity",		7, 4 | 2, polarity),
+					CRS_BITX("Interrupt Mode",		7, 1, mode),
+					CRS_UINT("Interrupt and I/O Flags",	8, 8),
+					CRS_UINTX("Pin Configuration",		9, 8, crs_pin_configuration),
+					CRS_UINT("Output Driver Strength",	10, 16),
+					CRS_UINT("Debounce Timeout (bits)",	12, 16),
+					CRS_UINT("Pin Table Offset",		14, 16),
+					CRS_UINT("Resource Source Index",	16, 8),
+					CRS_UINT("Resource Name Offset",	17, 16),
+					CRS_UINT("Vendor Data Offset",		19, 16),
+					CRS_UINT("Vendor Data Length",		21, 16),
+					/* Skip pin table */
+					CRS_END
+				};
+
+				crsdump_show(fw, objname, "GPIO Connection Descriptor",
+					data, crs_length, header, info);
+			} else if (data[4] == 1) {
+				static const char *sharing[] = {
+					"Exclusive",
+					"Shared",
+				};
+
+				static const char *restriction[] = {
+					"Input or Output",
+					"Input Only",
+					"Output Only",
+					"Input or Ouput, config must be preserved"
+				};
+
+				/* I/O connection */
+				static const crsdump_info info[] = {
+					CRS_UINT("Revision ID",			3, 8),
+					CRS_UINTX("GPIO Connection Type",	4, 8, crs_gpio_connection_type),
+					CRS_BITS("Reserved",			5, 0xfe),
+					CRS_BITX("Consumer/Producer",		5, 1, consumer),
+					CRS_UINT("Reserved",			6, 8),
+					CRS_BITS("Reserved",			7, 128 | 64 | 32 | 16),
+					CRS_BITX("Interrupt Sharing",		7, 8, sharing),
+					CRS_BITS("Reserved",			7, 4),
+					CRS_BITX("I/O Restriction",		7, 2 | 1, restriction),
+					CRS_UINT("Interrupt and I/O Flags",	8, 8),
+					CRS_UINTX("Pin Configuration",		9, 8, crs_pin_configuration),
+					CRS_UINT("Output Driver Strength",	10, 16),
+					CRS_UINT("Debounce Timeout (bits)",	12, 16),
+					CRS_UINT("Pin Table Offset",		14, 16),
+					CRS_UINT("Resource Source Index",	16, 8),
+					CRS_UINT("Resource Name Offset",	17, 16),
+					CRS_UINT("Vendor Data Offset",		19, 16),
+					CRS_UINT("Vendor Data Length",		21, 16),
+					/* Skip pin table */
+					CRS_END
+				};
+
+				crsdump_show(fw, objname, "GPIO Connection Descriptor",
+					data, crs_length, header, info);
+			} else {
+				/* No idea of the connection type */
+				static const crsdump_info info[] = {
+					CRS_UINT("Revision ID",			3, 8),
+					CRS_UINT("GPIO Connection Type",	4, 8),
+					CRS_END
+				};
+
+				crsdump_show(fw, objname, "GPIO Connection Descriptor",
+					data, crs_length, header, info);
+			}
+
+		}
+		break;
+	case 0xe: /* 6.4.3.8.2 Serial Bus Connection Descriptors */
+		/*  This is not frequently used, deferring implementation to later */
+		crsdump_show_header(fw, objname, "Serial Bus Connection Descriptor");
+		crsdump_show_info(fw, data, crs_length, header);
+		crsdump_data(fw, data, 3, crs_length);
+		break;
+	default:
+		crsdump_show_header(fw, objname, "Unknown type");
+		crsdump_show_info(fw, data, crs_length, header);
+		crsdump_data(fw, data, 3, crs_length);
+		break;
+	}
+
+	fwts_log_nl(fw);
+}
+
+static int crsdump_test1(fwts_framework *fw)
+{
+	fwts_list_link	*item;
+	fwts_list *objects;
+	const size_t name_len = 4;
+
+	if ((objects = fwts_acpi_object_get_names()) == NULL) {
+		fwts_log_info(fw, "Cannot find any ACPI objects");
+		return FWTS_ERROR;
+	}
+
+	fwts_list_foreach(item, objects) {
+		char *name = fwts_list_data(char*, item);
+		const size_t len = strlen(name);
+		if (strncmp("_CRS", name + len - name_len, name_len) == 0) {
+			ACPI_OBJECT_LIST arg_list;
+			ACPI_BUFFER buf;
+			ACPI_OBJECT *obj;
+			uint8_t *data;
+			int ret;
+
+			arg_list.Count   = 0;
+			arg_list.Pointer = NULL;
+
+			ret = fwts_acpi_object_evaluate(fw, name, &arg_list, &buf);
+			if ((ACPI_FAILURE(ret) != AE_OK) || (buf.Pointer == NULL))
+				continue;
+
+			/*  Do we have a valid _CRS buffer to dump? */
+			obj = buf.Pointer;
+			if ((obj->Type == ACPI_TYPE_BUFFER) &&
+			    (obj->Buffer.Pointer != NULL) &&
+			    (obj->Buffer.Length > 0)) {
+				data = (uint8_t*)obj->Buffer.Pointer;
+
+				if (data[0] & 128)
+					crsdump_large_resource_items(fw, name, data, obj->Buffer.Length);
+				else
+					crsdump_small_resource_items(fw, name, data, obj->Buffer.Length);
+			}
+
+			if (buf.Length && buf.Pointer)
+				free(buf.Pointer);
+		}
+	}
+	return FWTS_OK;
+}
+
+static fwts_framework_minor_test crsdump_tests[] = {
+	{ crsdump_test1, "Dump ACPI _CRS buffers." },
+	{ NULL, NULL }
+};
+
+static fwts_framework_ops crsdump_ops = {
+	.description = "Dump ACPI _CRS buffers.",
+	.init        = crsdump_init,
+	.deinit      = crsdump_deinit,
+	.minor_tests = crsdump_tests
+};
+
+FWTS_REGISTER("crsdump", &crsdump_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UTILS);