Exemple #1
0
static int uefi_init(fwts_framework *fw)
{
	if (fwts_acpi_find_table(fw, "UEFI", 0, &table) != FWTS_OK) {
		fwts_log_error(fw, "Cannot read ACPI tables.");
		return FWTS_ERROR;
	}
	if (table == NULL || (table && table->length == 0)) {
		fwts_log_error(fw, "ACPI UEFI table does not exist, skipping test");
		return FWTS_SKIP;
	}
	return FWTS_OK;
}
Exemple #2
0
static int pdtt_init(fwts_framework *fw)
{
	if (fwts_acpi_find_table(fw, "PDTT", 0, &table) != FWTS_OK) {
		fwts_log_error(fw, "Cannot load ACPI table");
		return FWTS_ERROR;
	}
	if (table == NULL) {
		fwts_log_error(fw, "ACPI PDTT table does not exist, skipping test");
		return FWTS_SKIP;
	}

	return FWTS_OK;
}
Exemple #3
0
/*
 *  fwts_check_executable()
 *	check if given file is an executable
 */
int fwts_check_executable(fwts_framework *fw, const char *path, const char *name)
{
	struct stat statbuf;

	if (stat(path, &statbuf)) {
		fwts_log_error(fw, "ERROR: Cannot find %s, make sure %s is installed.", path, name);
		return FWTS_ERROR;
	}
	if ((statbuf.st_mode & FLAGS) != FLAGS) {
		fwts_log_error(fw, "ERROR: Cannot read/execute %s.", path);
		return FWTS_ERROR;
	}
	return FWTS_OK;
}
Exemple #4
0
static int mcfg_init(fwts_framework *fw)
{
	if (fwts_acpi_find_table(fw, "MCFG", 0, &mcfg_table) != FWTS_OK) {
		fwts_log_error(fw, "Cannot load ACPI table");
		return FWTS_ERROR;
	}
	if (mcfg_table == NULL) {
		fwts_log_error(fw,
			"ACPI table MCFG not found. This table is "
			"required to check for PCI Express*");
		return FWTS_ERROR;
	}

	return FWTS_OK;
}
Exemple #5
0
static int get_config(fwts_framework *fw,
	char *filename,
	plat_config_t *configstruct)
{
	FILE *file;
	char *p;
	char line[MAXBUF];

	file = fopen(filename, "r");
	if (!file) {
		skip = true;
		fwts_log_error(fw, "Platform config file doesn't exist, "
				"skipping region size validation check");
		return FWTS_SKIP;
	}

	while (fgets(line, sizeof(line), file) != NULL) {
		char *cfline;
		uint64_t value;

		cfline = strstr((char *)line, DELIM);
		cfline = cfline + strlen(DELIM);
		value = strtoul(cfline, &p, 16);

		if (strstr(line, "homer"))
			configstruct->homer = value;
		else if (strstr(line, "occ-common-area"))
			configstruct->occ_common = value;
		else if (strstr(line, "slw-image"))
			configstruct->slw = value;
	}
	fclose(file);

	return FWTS_OK;
}
Exemple #6
0
static int hpet_check_init(fwts_framework *fw)
{
	if ((klog = fwts_klog_read()) == NULL) {
		fwts_log_error(fw, "Cannot read kernel log.");
		return FWTS_ERROR;
	}
	return FWTS_OK;
}
Exemple #7
0
static int gtdt_init(fwts_framework *fw)
{
	if (fwts_acpi_find_table(fw, "GTDT", 0, &table) != FWTS_OK) {
		fwts_log_error(fw, "Cannot read ACPI tables.");
		return FWTS_ERROR;
	}
	if (table == NULL || (table && table->length == 0)) {
		if (fw->flags & FWTS_FLAG_TEST_SBBR) {
			fwts_log_error(fw, "ACPI GTDT table does not exist");
			return FWTS_ERROR;
		} else {
			fwts_log_error(fw, "ACPI GTDT table does not exist, skipping test");
			return FWTS_SKIP;
		}
	}
	return FWTS_OK;
}
Exemple #8
0
/*
 *  fwts_check_root_euid()
 *	Check if user has privileges to access ports, memory, etc
 */
int fwts_check_root_euid(fwts_framework *fw, const bool warn)
{
	if (geteuid() != 0) {
		if (warn)
			fwts_log_error(fw, "Must be run as root or sudo to be able to read system information.");
		return FWTS_ERROR;
	}
	return FWTS_OK;
}
Exemple #9
0
static int ebda_init(fwts_framework *fw)
{
	if (fw->firmware_type != FWTS_FIRMWARE_BIOS) {
		fwts_log_info(fw, "Machine is not using traditional BIOS firmware, skipping test.");
		return FWTS_SKIP;
	}

	if ((memory_map = fwts_memory_map_table_load(fw)) == NULL) {
		fwts_log_error(fw, "Failed to read memory map.");
		return FWTS_ERROR;
	}

	if ((ebda_addr = fwts_ebda_get()) == FWTS_NO_EBDA) {
		fwts_log_error(fw, "Failed to locate EBDA region.");
		return FWTS_ERROR;
	}

	return FWTS_OK;
}
Exemple #10
0
static int microcode_init(fwts_framework *fw)
{
	bool intel;

	if (fwts_cpu_is_Intel(&intel) != FWTS_OK) {
		fwts_log_error(fw, "Cannot determine processor type.");
		return FWTS_ERROR;
	}

	if (!intel) {
		fwts_log_info(fw, "The microcode test currently only supports Intel processors.");
		return FWTS_SKIP;
	}

	klog = fwts_klog_read();
	if (klog == NULL) {
		fwts_log_error(fw, "Cannot read kernel log.");
		return FWTS_ERROR;
	}
	return FWTS_OK;
}
Exemple #11
0
static int spcr_init(fwts_framework *fw)
{
	fwts_acpi_table_info *table;

	if (fwts_acpi_find_table(fw, "SPCR", 0, &table) != FWTS_OK) {
		fwts_log_error(fw, "Cannot read ACPI tables.");
		return FWTS_ERROR;
	}
	if (table == NULL || (table && table->length == 0)) {
		if (fw->flags & FWTS_FLAG_TEST_SBBR) {
			fwts_log_error(fw, "ACPI SPCR table does not exist");
			return FWTS_ERROR;
		} else {
			fwts_log_error(fw, "ACPI SPCR table does not exist, skipping test");
			return FWTS_SKIP;
		}
	}
	spcr = (const fwts_acpi_table_spcr*)table->data;

	return FWTS_OK;
}
Exemple #12
0
static void s4_check_log(fwts_framework *fw,
	fwts_list *klog, int *errors, int *oopses, int *warn_ons)
{
	int error;
	int oops;
	int warn_on;

	/* Check for kernel errors reported in the log */
	if (fwts_klog_pm_check(fw, NULL, klog, &error))
		fwts_log_error(fw, "Error parsing kernel log.");
	*errors += error;

	if (fwts_klog_firmware_check(fw, NULL, klog, &error))
		fwts_log_error(fw, "Error parsing kernel log.");
	*errors += error;

	if (fwts_oops_check(fw, klog, &oops, &warn_on))
		fwts_log_error(fw, "Error parsing kernel log.");
	*oopses += oops;
	*warn_ons += warn_on;
}
Exemple #13
0
static int oops_init(fwts_framework *fw)
{
	if (fw->klog)
		klog = fwts_file_open_and_read(fw->klog);
	else
		klog = fwts_klog_read();

	if (klog == NULL) {
		fwts_log_error(fw, "Cannot read kernel log.");
		return FWTS_ERROR;
	}
	return FWTS_OK;
}
Exemple #14
0
static int clog_init(fwts_framework *fw)
{
	if (!fwts_clog_available(fw)) {
		fwts_log_info(fw, "coreboot log not available, skipping test");
		return FWTS_SKIP;
	}

	clog_list = fwts_clog_read(fw);
	if (clog_list == NULL) {
		fwts_log_error(fw, "Cannot read coreboot log.");
		return FWTS_ERROR;
	}
	return FWTS_OK;
}
Exemple #15
0
static int ebdadump_test1(fwts_framework *fw)
{
	off_t  ebda_addr;
	uint8_t *mem;
	size_t len;

	if ((ebda_addr = fwts_ebda_get()) == FWTS_NO_EBDA) {
		fwts_log_error(fw, "Failed to local EBDA region.");
		return FWTS_ERROR;
	}

	len = BIOS_ROM_START - ebda_addr;

	if (ebda_addr > BIOS_ROM_START) {
		fwts_log_error(fw, "EBDA start address is greater than the "
			"BIOS ROM start address.");
		return FWTS_ERROR;
	}

        if ((mem = fwts_mmap(ebda_addr, len)) == FWTS_MAP_FAILED) {
		fwts_log_error(fw, "Cannot mmap BIOS ROM region.");
		return FWTS_ERROR;
	}

	fwts_log_info(fw, "EBDA region: %" PRIx32 "..%x (%zd bytes)",
		(uint32_t)ebda_addr,
		BIOS_ROM_START,
		len);

	ebdadump_data(fw, mem, ebda_addr, len);
        (void)fwts_munmap(mem, len);

	fwts_infoonly(fw);

	return FWTS_OK;
}
Exemple #16
0
static int crs_get_bios_date(fwts_framework *fw, int *day, int *mon, int *year)
{
	char *date;
	static const char *bios_date = "/sys/class/dmi/id/bios_date";

	*mon = *day = *year = 0;
	if ((date = fwts_get(bios_date)) == NULL) {
		fwts_log_error(fw, "Cannot read %s.", bios_date);
		return FWTS_ERROR;
	}

	/* Assume mon/day/year, but we only care about the year anyway */
	sscanf(date, "%d/%d/%d", mon, day, year);
	free(date);

	return FWTS_OK;
}
Exemple #17
0
static int clog_test1(fwts_framework *fw)
{
	int errors = 0;

	if (fwts_clog_firmware_check(fw, clog_progress, clog_list, &errors)) {
		fwts_log_error(fw, "Error parsing coreboot log.");
		return FWTS_ERROR;
	}

	if (errors > 0)
		/* Checks will log errors as failures automatically */
		fwts_log_info(fw, "Found %d unique errors in coreboot log.",
			errors);
	else
		fwts_passed(fw, "Found no errors in coreboot log.");

	return FWTS_OK;
}
Exemple #18
0
/*
 *  fwts_press_entrer()
 *	prompt and wait for enter key
 */
int fwts_press_enter(fwts_framework *fw)
{
	int ch;

	fprintf(stdout, "Press <Enter> to continue");
	fflush(stdout);

	do {
		if (fwts_getchar(&ch) == FWTS_ERROR) {
			fwts_log_error(fw, "fwts_getchar() failed.");
			break;
		}
	} while (ch != '\n');

	fprintf(stdout, "\n");
	fflush(stdout);

	return FWTS_OK;
}
Exemple #19
0
static int romdump_test1(fwts_framework *fw)
{
	uint8_t *mem;
	int i;

        if ((mem = fwts_mmap(BIOS_ROM_REGION_START, BIOS_ROM_REGION_SIZE)) == FWTS_MAP_FAILED) {
		fwts_log_error(fw, "Cannot mmap BIOS ROM region.");
		return FWTS_ERROR;
	}

	for (i = 0; i < BIOS_ROM_REGION_SIZE; i += 512) {
		/* Ensure we can safely read the memory */
		if (fwts_safe_memread(mem + i, 512) != FWTS_OK)
			continue;

		if ((*(mem+i) == 0x55) && (*(mem+i+1) == 0xaa)) {
			int length = *(mem+i+2) << 9;

			fwts_log_info(fw,
				"Found ROM: %x..%x (%d bytes)",
				BIOS_ROM_REGION_START+i,
				BIOS_ROM_REGION_START+i+length,
				length);
			romdump_data(fw, mem+i, BIOS_ROM_REGION_START+i, length);
			fwts_log_nl(fw);
		}
	}

	fwts_log_info(fw,
		"BIOS ROM: %x..%x (%d bytes)",
		BIOS_ROM_START,
		BIOS_ROM_END,
		BIOS_ROM_SIZE);

	romdump_data(fw, mem+BIOS_ROM_OFFSET, BIOS_ROM_START, BIOS_ROM_SIZE);

	fwts_infoonly(fw);

        (void)fwts_munmap(mem, BIOS_ROM_REGION_SIZE);

	return FWTS_OK;
}
Exemple #20
0
/*
 *  fwts_get_reply()
 *	prompt and wait for a given reply that matches given options string
 */
int fwts_get_reply(fwts_framework *fw, const char *message, const char *options)
{
	int ch;

	fprintf(stdout, "%s", message);
	fflush(stdout);

	for (;;) {

		if (fwts_getchar(&ch) == FWTS_ERROR) {
			fwts_log_error(fw, "fwts_getchar() failed.");
			break;
		}
		if (index(options, ch) != NULL)
			break;
	}
	fprintf(stdout, "\n");
	fflush(stdout);

	return ch;
}
Exemple #21
0
static int s4_init(fwts_framework *fw)
{
	fwts_list* swap_devs;

	swap_devs = fwts_file_open_and_read("/proc/swaps");
	if (fwts_text_list_strstr(swap_devs, "/dev/") == NULL) {
		fwts_list_free(swap_devs, free);
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoSwap",
			"Cannot run hibernate test - machine appears to have NO swap.");
		return FWTS_ERROR;
	}
	fwts_list_free(swap_devs, free);

	if (fwts_wakealarm_test_firing(fw, 1)) {
		fwts_log_error(fw, "Cannot automatically wake machine up - aborting S4 test.");
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "BadWakeAlarmS4",
			"Check if wakealarm works reliably for S4 tests.");
		return FWTS_ERROR;
	}

	return FWTS_OK;
}
Exemple #22
0
static int oops_test1(fwts_framework *fw)
{
	int oopses = 0;
	int warn_ons = 0;

	if (fwts_oops_check(fw, klog, &oopses, &warn_ons) != FWTS_OK) {
		fwts_log_error(fw, "Error parsing kernel log.");
		return FWTS_ERROR;
	}

	if (oopses > 0)
		fwts_failed(fw, LOG_LEVEL_CRITICAL,
			"KernelOops", "Found %d oopses in kernel log.", oopses);
	else
		fwts_passed(fw, "Found no oopses in kernel log.");

	if (warn_ons > 0)
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"KernelWarnOns", "Found %d WARN_ON warnings in kernel log.", warn_ons);
	else
		fwts_passed(fw, "Found no WARN_ON warnings in kernel log.");

	return FWTS_OK;
}
Exemple #23
0
static int s4_test_multiple(fwts_framework *fw)
{
	int i;
	int klog_errors = 0;
	int hw_errors = 0;
	int pm_errors = 0;
	int klog_oopses = 0;
	int klog_warn_ons = 0;
	int awake_delay = s4_min_delay * 1000;
	int delta = (int)(s4_delay_delta * 1000.0);
	int tracing_buffer_size = -1;
	int ret = FWTS_OK;
	bool retried = false;

#if FWTS_ENABLE_LOGIND
#if !GLIB_CHECK_VERSION(2,35,0)
	/* This is for backward compatibility with old glib versions */
	g_type_init();
#endif
#endif

        if (s4_multiple == 1)
                fwts_log_info(fw, "Defaulted to run 1 test, run --s4-multiple=N to run more S4 cycles\n");

	for (i = 0; i < s4_multiple; i++) {
		struct timeval tv;
		int failed_alloc_image = 0;
		int percent = (i * 100) / s4_multiple;

		fwts_log_info(fw, "S4 cycle %d of %d\n",i+1,s4_multiple);

		if (s4_hibernate(fw,
			&klog_errors, &hw_errors, &pm_errors,
			&klog_oopses, &klog_warn_ons,
			&failed_alloc_image, percent) != FWTS_OK) {
			fwts_log_error(fw, "Aborting S4 multiple tests.");
			return FWTS_ERROR;
		}

		/* Sometimes we just fail at the first S4 cycle, so
		   shrink tracing buffer size and retry */
		if (failed_alloc_image) {
			if (fwts_get_int(FWTS_TRACING_BUFFER_SIZE, &tracing_buffer_size) != FWTS_OK) {
				fwts_log_error(fw, "Could not get size from %s.", FWTS_TRACING_BUFFER_SIZE);
			} else {
				if ((!retried) && (tracing_buffer_size > 4096)) {
					retried = true;

					fwts_failed(fw, LOG_LEVEL_HIGH,
						"TracingBufferTooBig",
						"/sys/kernel/debug/tracing/buffer_size_kb is set to %d Kbytes which "
						"may cause hibernate to fail. Programs such as ureadahead may have "
						"set this enable fast boot and not freed up the tracing buffer.", tracing_buffer_size);

					fwts_log_info(fw, "Setting tracing buffer size to 1K for subsequent tests.");

					fwts_set("1", FWTS_TRACING_BUFFER_SIZE);
					failed_alloc_image = 0;

					if (s4_hibernate(fw,
						&klog_errors, &hw_errors, &pm_errors,
						&klog_oopses, &klog_warn_ons,
						&failed_alloc_image, percent) != FWTS_OK) {
						fwts_log_error(fw, "Aborting S4 multiple tests.");
						ret = FWTS_ABORTED;
						break;
					};

					if (failed_alloc_image) {
						ret = FWTS_ABORTED;
						break;
					}
				}
			}
		}

		if (!s4_device_check) {
			char buffer[80];
			int j;

			tv.tv_sec  = 0;
			tv.tv_usec = (awake_delay % 1000)*1000;
			select(0, NULL, NULL, NULL, &tv);

			for (j = 0; j < awake_delay / 1000; j++) {
				snprintf(buffer, sizeof(buffer), "(Waiting %d/%d seconds)",
					j + 1, awake_delay / 1000);
				fwts_progress_message(fw, percent, buffer);
				sleep(1);
			}

			awake_delay += delta;
			if (awake_delay > (s4_max_delay * 1000))
				awake_delay = s4_min_delay * 1000;
		}
	}

	if (tracing_buffer_size > 0) {
		char tmp[32];

		/* Restore tracking buffer size */
		snprintf(tmp, sizeof(tmp), "%d", tracing_buffer_size);
		fwts_set(tmp, FWTS_TRACING_BUFFER_SIZE);
	}

	if (klog_errors > 0)
		fwts_log_info(fw, "Found %d errors in kernel log.", klog_errors);
	else
		fwts_passed(fw, "No kernel log errors detected.");

	if (pm_errors > 0)
		fwts_log_info(fw, "Found %d PM related hibernate issues.", pm_errors);
	else
		fwts_passed(fw, "No PM related hibernate issues detected.");

	if (hw_errors > 0)
		fwts_log_info(fw, "Found %d device errors.", hw_errors);
	else
		fwts_passed(fw, "No device errors detected.");

	if (klog_oopses > 0)
		fwts_log_info(fw, "Found %d kernel oopses.", klog_oopses);
	else
		fwts_passed(fw, "No kernel oopses detected.");

	if (klog_warn_ons > 0)
		fwts_log_info(fw, "Found %d kernel WARN_ON warnings.", klog_warn_ons);
	else
		fwts_passed(fw, "No kernel WARN_ON warnings detected.");


	/* Really passed or failed? */
	if ((klog_errors + pm_errors + hw_errors + klog_oopses) > 0) {
                fwts_log_info(fw, "Found %d errors and %d oopses doing %d hibernate/resume cycle(s).",
			klog_errors + pm_errors + hw_errors,
			klog_oopses, s4_multiple);
	} else
		fwts_passed(fw, "Found no errors and no oopses  doing %d hibernate/resume cycle(s).", s4_multiple);

	return ret;
}
Exemple #24
0
static int s4_hibernate(fwts_framework *fw,
	int *klog_errors,
	int *hw_errors,
	int *pm_errors,
	int *klog_oopses,
	int *klog_warn_ons,
	int *failed_alloc_image,
	int percent)
{
	fwts_list *klog_pre, *klog_post, *klog_diff;
	fwts_hwinfo hwinfo1, hwinfo2;
	int status;
	int duration;
	int differences;
	int rc = FWTS_OK;
	char *command = NULL;
	char *quirks = NULL;
	fwts_pm_method_vars *fwts_settings;

	int (*do_s4)(fwts_pm_method_vars *, const int, int*, const char*);

	fwts_settings = calloc(1, sizeof(fwts_pm_method_vars));
	if (fwts_settings == NULL)
		return FWTS_OUT_OF_MEMORY;
	fwts_settings->fw = fw;

	if (fw->pm_method == FWTS_PM_UNDEFINED) {
		/* Autodetection */
		fwts_log_info(fw, "Detecting the power method.");
		detect_pm_method(fwts_settings);
	}

	switch (fw->pm_method) {
#if FWTS_ENABLE_LOGIND
		case FWTS_PM_LOGIND:
			fwts_log_info(fw, "Using logind as the default power method.");
			if (fwts_logind_init_proxy(fwts_settings) != 0) {
				fwts_log_error(fw, "Failure to connect to Logind.");
				rc = FWTS_ERROR;
				goto tidy;
			}
			do_s4 = &wrap_logind_do_s4;
			break;
#endif
		case FWTS_PM_PMUTILS:
			fwts_log_info(fw, "Using pm-utils as the default power method.");
			do_s4 = &wrap_pmutils_do_s4;
			break;
		case FWTS_PM_SYSFS:
			fwts_log_info(fw, "Using sysfs as the default power method.");
			do_s4 = &wrap_sysfs_do_s4;
			break;
		default:
			/* This should never happen */
			fwts_log_info(fw, "Using sysfs as the default power method.");
			do_s4 = &wrap_sysfs_do_s4;
			break;
	}

	if (s4_device_check)
		fwts_hwinfo_get(fw, &hwinfo1);

	if (fw->pm_method == FWTS_PM_PMUTILS) {
		/* Format up pm-hibernate command with optional quirking arguments */
		if ((command = fwts_realloc_strcat(NULL, PM_HIBERNATE)) == NULL) {
			rc = FWTS_OUT_OF_MEMORY;
			goto tidy;
		}

		/* For now we only support quirks with pm-utils */
		if (s4_quirks) {
			if ((command = fwts_realloc_strcat(command, " ")) == NULL) {
				rc = FWTS_OUT_OF_MEMORY;
				goto tidy;
			}
			if ((quirks = fwts_args_comma_list(s4_quirks)) == NULL) {
				rc = FWTS_OUT_OF_MEMORY;
				goto tidy;
			}
			if ((command = fwts_realloc_strcat(command, quirks)) == NULL) {
				rc = FWTS_OUT_OF_MEMORY;
				goto tidy;
			}
		}
	}

	fwts_wakealarm_trigger(fw, s4_sleep_delay);

	/* Do s4 here */
	if ((klog_pre = fwts_klog_read()) == NULL)
		fwts_log_error(fw, "S4: hibernate: Cannot read kernel log.");

	status = do_s4(fwts_settings, percent, &duration, command);

	if ((klog_post = fwts_klog_read()) == NULL)
		fwts_log_error(fw, "S4: hibernate: Cannot re-read kernel log.");

	if (s4_device_check) {
		int i;

		for (i = 0; i < s4_device_check_delay; i++) {
			char buffer[80];

			snprintf(buffer, sizeof(buffer), "(Waiting %d/%d seconds)", i+1, s4_device_check_delay);
			fwts_progress_message(fw, percent, buffer);
			sleep(1);
		}
		fwts_progress_message(fw, percent, "(Checking devices)");
		fwts_hwinfo_get(fw, &hwinfo2);
		fwts_hwinfo_compare(fw, &hwinfo1, &hwinfo2, &differences);
		fwts_hwinfo_free(&hwinfo1);
		fwts_hwinfo_free(&hwinfo2);

		if (differences > 0) {
			fwts_failed(fw, LOG_LEVEL_HIGH, "DevConfigDiffAfterS4",
				"Found %d differences in device configuation during S4 cycle.", differences);
			(*hw_errors)++;
		}
	}

	fwts_progress_message(fw, percent, "(Checking for errors)");

	klog_diff = fwts_klog_find_changes(klog_pre, klog_post);
	s4_check_log(fw, klog_diff, klog_errors, klog_oopses, klog_warn_ons);

	fwts_progress_message(fw, percent, "(Checking for PM errors)");

	/* Add in error check for pm-hibernate status */
	if ((status > 0) && (status < 128)) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "PMActionFailedPreS4",
			"pm-action failed before trying to put the system "
			"in the requested power saving state.");
		(*pm_errors)++;
	} else if (status == 128) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "PMActionPowerStateS4",
			"pm-action tried to put the machine in the requested "
			"power state but failed.");
		(*pm_errors)++;
	} else if (status > 128) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "PMActionFailedS4",
			"pm-action encountered an error and also failed to "
			"enter the requested power saving state.");
		(*pm_errors)++;
	}

	if (fwts_klog_regex_find(fw, klog_diff, "Freezing user space processes.*done") < 1) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "UserSpaceTaskFreeze",
			"Failed to freeze user space processes.");
		(*pm_errors)++;
	}

	if (fwts_klog_regex_find(fw, klog_diff, "Freezing remaining freezable tasks.*done") < 1) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "KernelTaskFreeze",
			"Failed to freeze remaining non-user space processes.");
		(*pm_errors)++;
	}

	if ((fwts_klog_regex_find(fw, klog_diff, "PM: freeze of devices complete") < 1) &&
	    (fwts_klog_regex_find(fw, klog_diff, "PM: late freeze of devices complete") < 1)) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "DeviceFreeze",
			"Failed to freeze devices.");
		(*pm_errors)++;
	}

	if (fwts_klog_regex_find(fw, klog_diff, "PM: Allocated.*kbytes") < 1) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "HibernateImageAlloc",
			"Failed to allocate memory for hibernate image.");
		*failed_alloc_image = 1;
		(*pm_errors)++;
	}

	if (fwts_klog_regex_find(fw, klog_diff, "PM: Image restored successfully") < 1) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "HibernateImageRestore",
			"Failed to restore hibernate image.");
		(*pm_errors)++;
	}

	fwts_klog_free(klog_pre);
	fwts_klog_free(klog_post);
	fwts_list_free(klog_diff, NULL);
tidy:
	free(command);
	free(quirks);
	free_pm_method_vars(fwts_settings);

	return rc;
}
Exemple #25
0
static int lid_test_state(fwts_framework *fw, int button)
{
	int gpe_count = 0;
	int fd;
	int matching = 0;
	int not_matching = 0;
	int events = 0;
	size_t len;
	char *state;
	int i;

	fwts_gpe *gpes_start;
	fwts_gpe *gpes_end;

	switch (button) {
	case FWTS_BUTTON_LID_OPENED:
		state = "open";
		break;
	case FWTS_BUTTON_LID_CLOSED:
		state = "closed";
		break;
	default:
		state = "unknown";
		break;
	}

	if ((gpe_count = fwts_gpe_read(&gpes_start)) == FWTS_ERROR) {
		fwts_log_error(fw, "Cannot read GPEs.");
		return FWTS_ERROR;
	}

	if ((fd = fwts_acpi_event_open()) < 0) {
		fwts_log_error(fw, "Cannot connect to acpid.");
		fwts_gpe_free(gpes_start, gpe_count);
		return FWTS_ERROR;
	}

	for (i = 0; i <= 20; i++) {
		char *buffer;

		if ((buffer = fwts_acpi_event_read(fd, &len, 1)) != NULL) {
			if (strstr(buffer, "button/lid")) {
				events++;
				lid_check_field_poll(fw, button, &matching, &not_matching);
				break;
			}
			free(buffer);
		}
		fwts_printf(fw, "Waiting %2.2d/20\r", 20-i);
	}
	fwts_acpi_event_close(fd);

	if ((gpe_count = fwts_gpe_read(&gpes_end)) == FWTS_ERROR) {
		fwts_log_error(fw, "Cannot read GPEs.");
		fwts_gpe_free(gpes_start, gpe_count);
		return FWTS_ERROR;
	}

	fwts_gpe_test(fw, gpes_start, gpes_end, gpe_count);
	fwts_gpe_free(gpes_start, gpe_count);
	fwts_gpe_free(gpes_end, gpe_count);

	if (events == 0)
		fwts_failed(fw, LOG_LEVEL_HIGH, "NoLidEvents",
			"Did not detect any ACPI LID events while waiting for to LID %s.", state);
	else {
		fwts_passed(fw, "Detected ACPI LID events while waiting for LID to %s.", state);
		if ((matching == 0) || (not_matching > 0))
			fwts_failed(fw, LOG_LEVEL_HIGH, "NoLidState",
				"Could not detect lid %s state.", state);
		else
			fwts_passed(fw, "Detected lid %s state.", state);
	}

	return FWTS_OK;
}
Exemple #26
0
static int cmosdump_test1(fwts_framework *fw)
{
	int i;
	unsigned long tmp;

	static char *cmos_shutdown_status[] = {
		"Power on or soft reset",
		"Memory size pass",
		"Memory test pass",
		"Memory test fail",

		"INT 19h reboot",
		"Flush keyboard and jmp via 40h:67h",
		"Protected mode tests pass",
		"Protected mode tests fail",

		"Used by POST during protected-mode RAM test",
		"Int 15h (block move)",
		"Jmp via 40h:67h",
		"Used by 80386",
	};

	static char *floppy_disk[] = {
		"None",
		"360KB 5.25\" Drive",
		"1.2MB 5.25\" Drive",
		"720KB 3.5\" Drive",
		"1.44MB 3.5\" Drive",
		"2.88MB 3.5\" Drive",
		"Unknown",
		"Unknown"
	};

	static char *hard_disk[] = {
		"None",
		"Type 1",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Unknown",
		"Type 14",
		"Type 16-47"
	};

	static char *primary_display[] = {
		"BIOS selected",
		"CGA 40 column",
		"CGA 80 column",
		"Monochrome"
	};

	static char *divider[8] = {
		"4.194 MHz",
		"1.049 MHz",
		"32.768 KHz (default)",
		"unknown",
		"test mode",
		"test mode",
		"reset / disable",
		"reset / disable",
	};

	static char *rate_selection[16] = {
		"none",
		"3.90625 millseconds",
		"7.8215 milliseconds",
		"122.070 microseconds",
		"244.141 microseconds",
		"488.281 microseconds",
		"976.562 microseconds (default)",
		"1.953125 milliseconds",
		"3.90625 milliseconds",
		"7.8215 milliseconds",
		"15.625 milliseconds",
		"31.25 milliseconds",
		"62.5 milliseconds",
		"125 milliseconds",
		"250 milliseconds",
		"500 milliseconds"
	};

	unsigned char data[0x80];

	/* Read CMOS Data */
	for (i = 0;i < (int)sizeof(data); i++) {
		if (fwts_cmos_read(i, &data[i]) != FWTS_OK) {
			fwts_log_error(fw, "Cannot get read/write permission on I/O ports.");
			return FWTS_ERROR;
		}
	}

	fwts_log_info_verbatum(fw, "CMOS Memory Dump:");
	for (i = 0; i < (int)sizeof(data); i += 16) {
		char buffer[128];
		fwts_dump_raw_data(buffer, sizeof(buffer), data + i, i, 16);
		fwts_log_info_verbatum(fw, "%s", buffer);
	}
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "RTC Current Time: (CMOS 0x00..0x09)");
	fwts_log_info_verbatum(fw, "  RTC seconds:            %2.2x", data[0]);
	fwts_log_info_verbatum(fw, "  RTC minutes:            %2.2x", data[2]);
	fwts_log_info_verbatum(fw, "  RTC hours:              %2.2x", data[4]);
	fwts_log_info_verbatum(fw, "  RTC day of week:        %2.2x", data[6]);
	fwts_log_info_verbatum(fw, "  RTC date day:           %2.2x", data[7]);
	fwts_log_info_verbatum(fw, "  RTC date month:         %2.2x", data[8]);
	fwts_log_info_verbatum(fw, "  RTC date year:          %2.2x", data[9]);
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "RTC Alarm:");
	fwts_log_info_verbatum(fw, "  RTC seconds:            %2.2x", data[1]);
	fwts_log_info_verbatum(fw, "  RTC minutes:            %2.2x", data[3]);
	fwts_log_info_verbatum(fw, "  RTC hours:              %2.2x", data[5]);
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Status Register A: (CMOS 0x0a): 0x%2.2x",
		data[10]);
	fwts_log_info_verbatum(fw, "  Rate freq:              %1.1x (%s)",
		data[10] & 0xf, rate_selection[data[10] & 0xf]);
	fwts_log_info_verbatum(fw, "  Timer freq divider:     %1.1x (%s)",
		(data[10] >> 4) & 0x7, divider[(data[10] >> 4) & 0x7]);
	fwts_log_info_verbatum(fw, "  Update in progress:     %1.1x",
		(data[10] >> 7) & 1);
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Status Register B: (CMOS 0x0b): 0x%2.2x",
		data[11]);
	fwts_log_info_verbatum(fw, "  Daylight savings:       %1.1x (%s)",
		data[11] & 1,
		(data[11] & 1) ? "Enabled" : "Disabled");
	fwts_log_info_verbatum(fw, "  24 Hour Clock:          %1.1x (%s)",
		(data[11] >> 1) & 1,
		((data[11] >> 1) & 1) ? "24 Hour" : "12 Hour");
	fwts_log_info_verbatum(fw, "  Data Mode (DM):         %1.1x (%s)",
		(data[11] >> 2) & 1,
		((data[11] >> 2) & 1) ? "Binary" : "BCD");
	fwts_log_info_verbatum(fw, "  Square Wave:            %1.1x (%s)",
		(data[11] >> 3) & 1,
		((data[11] >> 3) & 1) ? "Enabled" : "Disabled");
	fwts_log_info_verbatum(fw, "  Update ended IRQ:       %1.1x (%s)",
		(data[11] >> 4) & 1,
		((data[11] >> 4) & 1) ? "Enabled" : "Disabled");
	fwts_log_info_verbatum(fw, "  Alarm IRQ:              %1.1x (%s)",
		(data[11] >> 5) & 1,
		((data[11] >> 5) & 1) ? "Enabled" : "Disabled");
	fwts_log_info_verbatum(fw, "  Periodic IRQ:           %1.1x (%s)",
		(data[11] >> 6) & 1,
		((data[11] >> 6) & 1) ? "Enabled" : "Disabled");
	fwts_log_info_verbatum(fw, "  Clock update cycle:     %1.1x (%s)",
		(data[11] >> 7) & 1,
		((data[11] >> 7) & 1) ? "Abort update in progress" : "Update normally");
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Status Register C: (CMOS 0x0c): 0x%2.2x",
		data[12]);
	fwts_log_info_verbatum(fw, "  UF flag:                0x%1.1x",
		(data[12] >> 4) & 1);
	fwts_log_info_verbatum(fw, "  AF flag:                0x%1.1x",
		(data[12] >> 5) & 1);
	fwts_log_info_verbatum(fw, "  PF flag:                0x%1.1x",
		(data[12] >> 6) & 1);
	fwts_log_info_verbatum(fw, "  IRQF flag:              0x%1.1x",
		(data[12] >> 7) & 1);
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Status Register D: (CMOS 0x0d): 0x%2.2x",
		data[13]);
	fwts_log_info_verbatum(fw, "  Valid CMOS RAM flag:    0x%1.1x (%s)",
		(data[13] >> 7) & 1,
		((data[13] >> 7) & 1) ? "Battery Good": "Battery Dead");
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Diagnostic Status: (CMOS 0x0e): 0x%2.2x",
		data[14]);
	fwts_log_info_verbatum(fw, "  CMOS time status:       0x%1.1x (%s)",
		(data[14] >> 2) & 1,
		((data[14] >> 2) & 1) ? "Invalid": "Valid");
	fwts_log_info_verbatum(fw, "  Fixed disk init:        0x%1.1x (%s)",
		(data[14] >> 3) & 1,
		((data[14] >> 3) & 1) ? "Bad": "Good");
	fwts_log_info_verbatum(fw, "  Memory size check:      0x%1.1x (%s)",
		(data[14] >> 4) & 1,
		((data[14] >> 4) & 1) ? "Bad": "Good");
	fwts_log_info_verbatum(fw, "  Config info status:     0x%1.1x (%s)",
		(data[14] >> 5) & 1,
		((data[14] >> 5) & 1) ? "Invalid": "Valid");
	fwts_log_info_verbatum(fw, "  CMOS checksum status:   0x%1.1x (%s)",
		(data[14] >> 6) & 1,
		((data[14] >> 6) & 1) ? "Bad": "Good");
	fwts_log_info_verbatum(fw, "  CMOS power loss:        0x%1.1x (%s)",
		(data[14] >> 7) & 1,
		((data[14] >> 7) & 1) ? "Lost power": "Not lost power");
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "CMOS Shutdown Status: (CMOS 0x0f): 0x%2.2x (%s)",
		data[15],
		data[15] < 0xb ? cmos_shutdown_status[data[15]] : "Perform power-on reset");
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Floppy Disk Type: (CMOS 0x10): 0x%2.2x",
		data[16]);
	fwts_log_info_verbatum(fw, "  Drive 0: %s",
		floppy_disk[((data[16] >> 4) & 0xf)]);
	fwts_log_info_verbatum(fw, "  Drive 1: %s",
		floppy_disk[((data[16] >> 0) & 0xf)]);
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Hard Disk Type: (CMOS 0x12, Obsolete): 0x%2.2x", data[18]);
	fwts_log_info_verbatum(fw, "  Drive 0: %s",
		hard_disk[((data[18] >> 4) & 0xf)]);
	fwts_log_info_verbatum(fw, "  Drive 1: %s",
		hard_disk[((data[18] >> 0) & 0xf)]);
	fwts_log_nl(fw);

	fwts_log_info_verbatum(fw, "Installed H/W: (CMOS 0x14): 0x%2.2x",
		data[20]);
	fwts_log_info_verbatum(fw, "  Maths Coprocessor:      0x%1.1x (%s)",
		(data[20] >> 1) & 1,
		((data[20] >> 1) & 1) ? "Installed": "Not Installed");
	fwts_log_info_verbatum(fw, "  Keyboard:               0x%1.1x (%s)",
		(data[20] >> 2) & 1,
		((data[20] >> 2) & 1) ? "Installed": "Not Installed");
	fwts_log_info_verbatum(fw, "  Display Adaptor:        0x%1.1x (%s)",
		(data[20] >> 3) & 1,
		((data[20] >> 3) & 1) ? "Installed": "Not Installed");
	fwts_log_info_verbatum(fw, "  Primary Display:        0x%1.1x (%s)",
		(data[20] >> 4) & 3,
		primary_display[(data[20] >> 4) & 3]);
	if (data[20] & 1) {
		int drives = (data[20] >> 6) & 3;
		fwts_log_info_verbatum(fw, "  Floppy Drives:          0x%2.2x (%d drive%s)",
			drives, drives + 1, drives > 0 ? "s" : "");
	} else {
Exemple #27
0
static int crs_test1(fwts_framework *fw)
{
	fwts_list *klog;
	int day, mon, year;
	char *cmdline;

	if ((cmdline = fwts_get("/proc/cmdline")) == NULL) {
		fwts_log_error(fw, "Cannot read /proc/cmdline");
		return FWTS_ERROR;
	}

	if (crs_get_bios_date(fw, &day, &mon, &year) != FWTS_OK) {
		fwts_log_error(fw, "Cannot determine age of BIOS.");
		free(cmdline);
		return FWTS_ERROR;
	}

	if ((klog = fwts_klog_read()) == NULL) {
		fwts_log_error(fw, "Cannot read kernel log.");
		free(cmdline);
		return FWTS_ERROR;
	}

        if (fwts_klog_regex_find(fw, klog,
		"PCI: Ignoring host bridge windows from ACPI;") > 0) {
		if (strstr(cmdline, "pci=nocrs") != NULL) {
			fwts_skipped(fw, "Kernel was booted with pci=nocrs, Ignoring host bridge windows _CRS settings from ACPI, skipping test.");
		}
		else {
			if (year == 0) {
				fwts_failed(fw, LOG_LEVEL_MEDIUM,
					"BIOSTooOld",
					"The kernel could not determine the BIOS age "
					"and has assumed that your BIOS is too old to correctly "
					"specify the host bridge MMIO aperture using _CRS.");
				fwts_log_advice(fw, "You can override this by booting with \"pci=use_crs\".");
			} else if (year < 2008) {
				fwts_passed(fw,
					"The kernel has detected an old BIOS (%d/%d/%d) "
					"and has assumed that your BIOS is too old to correctly "
					"specify the host bridge MMIO aperture using _CRS.", mon, day, year);
				fwts_log_advice(fw, "You can override this by booting with \"pci=use_crs\".");
			} else {
				fwts_failed(fw, LOG_LEVEL_MEDIUM,
					"HostBridgeWindows",
					"The kernel is ignoring host bridge windows from ACPI for some unknown reason. "
					"pci=nocrs has not been used as a boot parameter and the BIOS may be recent enough "
					"to support this (%d/%d/%d)", mon, day, year);
			}
		}
	} else if (fwts_klog_regex_find(fw, klog, "PCI: Using host bridge windows from ACPI;") > 0) {
		if (strstr(cmdline, "pci=use_crs") != NULL) {
			if (year == 0)  {
				fwts_failed(fw, LOG_LEVEL_MEDIUM,
					"BIOSNoReleaseDate",
					"The BIOS does not seem to have release date, hence pci=use_crs was required.");
			} else if (year < 2008) {
				fwts_passed(fw,
					"The BIOS is relatively old (%d/%d/%d) and hence pci=use_crs was required to "
					"enable host bridge windows _CRS settings from ACPI.", mon, day, year);
			} else {
				fwts_failed(fw, LOG_LEVEL_LOW,
					"BIOSSupportBridgeWindows",
					"Kernel was booted with pci=use_crs but this may be uncessary as "
					"the BIOS is new enough to support automatic bridge windows configuring using _CRS from ACPI. "
					"However, the workaround may be necessary because _CRS is incorrect or not implemented in the "
					"DSDT.");
			}
		}
		else {
			fwts_passed(fw,
				"The kernel has detected a BIOS newer than the end of 2007 (%d/%d/%d) "
				"and has assumed that your BIOS can correctly "
				"specify the host bridge MMIO aperture using _CRS.  If this does not work "
				"correctly you can override this by booting with \"pci=nocrs\".", mon, day, year);
		}
	} else {
		fwts_skipped(fw, "Cannot find host bridge message in kernel log, skipping test.");
	}

	fwts_list_free(klog, free);
	free(cmdline);

	return FWTS_OK;
}
Exemple #28
0
static int wait_for_acpi_event(fwts_framework *fw, const char *name)
{
	int gpe_count = 0;
	int fd;
	int events = 0;
	int matching = 0;
	size_t len;
	int i;

	fwts_gpe *gpes_start;
	fwts_gpe *gpes_end;

	if ((gpe_count = fwts_gpe_read(&gpes_start)) == FWTS_ERROR) {
		fwts_log_error(fw, "Cannot read GPEs.");
		return FWTS_ERROR;
	}

	if ((fd = fwts_acpi_event_open()) < 0) {
		fwts_log_error(fw, "Cannot connect to acpid.");
		fwts_gpe_free(gpes_start, gpe_count);
		return FWTS_ERROR;
	}

	for (i = 0; i <= 20; i++) {
		char *buffer;

		if ((buffer = fwts_acpi_event_read(fd, &len, 1)) != NULL) {
			char *str;
			if ((str = strstr(buffer, "battery")) != NULL) {
				events++;
				if (strstr(str, name) != NULL) {
					matching++;
					free(buffer);
					break;
				}
			}
			free(buffer);
		}
		fwts_printf(fw, "Waiting %2.2d/20\r", 20-i);
	}
	fwts_acpi_event_close(fd);

	if ((gpe_count = fwts_gpe_read(&gpes_end)) == FWTS_ERROR) {
		fwts_log_error(fw, "Cannot read GPEs.");
		fwts_gpe_free(gpes_start, gpe_count);
		return FWTS_ERROR;
	}

	fwts_gpe_test(fw, gpes_start, gpes_end, gpe_count);
	fwts_gpe_free(gpes_start, gpe_count);
	fwts_gpe_free(gpes_end, gpe_count);

	if (events == 0)
		fwts_failed(fw, LOG_LEVEL_HIGH, "BatteryNoEvents",
			"Did not detect any ACPI battery events.");
	else {
		fwts_passed(fw, "Detected ACPI battery events.");
		if (matching == 0)
			fwts_failed(fw, LOG_LEVEL_HIGH, "BatteryNoEvents",
			"Could not detect ACPI events for battery %s.", name);
		else
			fwts_passed(fw, "Detected ACPI event for battery %s.",
				name);
	}

	return FWTS_OK;
}
Exemple #29
0
static int auto_brightness_test2(fwts_framework *fw)
{
	struct dirent *entry;
	int max_brightness;
	int actual_brightness;
	int saved_brightness;
	DIR *brightness_dir = brightness_get_dir();

	rewinddir(brightness_dir);
	do {
		int i;
		int failures = 0;
		bool *brightness_fail;

		entry = readdir(brightness_dir);
		if (entry == NULL || entry->d_name[0] == '.')
			continue;

		if (brightness_get_setting(entry->d_name, "max_brightness", &max_brightness) != FWTS_OK) {
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"BrightnessNotExist",
				"Maximum brightness could not be accessed for %s.",
				entry->d_name);
			continue;
		}

		if (max_brightness <= 0) {
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"BrightnessMaxTest2",
				"Maximum brightness for %s is %d and should be > 0.",
				entry->d_name, max_brightness);
			continue;
		}

		if (brightness_get_setting(entry->d_name, "actual_brightness", &saved_brightness) != FWTS_OK) {
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"BrightnessNotExist",
				"Maximum brightness could not be accessed for %s.",
				entry->d_name);
			continue;
		}

		brightness_fail = calloc(sizeof(bool), max_brightness + 1);
		if (brightness_fail == NULL) {
			fwts_log_error(fw, "Cannot allocate brightness table.");
			continue;
		}

		for (i = 0; i <= max_brightness; i++) {
			brightness_set_setting(entry->d_name, "brightness", i);
			if (brightness_get_setting(entry->d_name, "actual_brightness", &actual_brightness) != FWTS_OK) {
				fwts_log_info(fw, "Cannot get brightness setting %d for backlight %s.", i, entry->d_name);
				failures++;
				brightness_fail[i] = true;
				continue;
			}
			if (actual_brightness != i) {
				failures++;
				brightness_fail[i] = true;
			} else {
				brightness_fail[i] = false;
			}
		}

		if (failures) {
			char *msg = NULL;
			char buf[40];

			/* Find the ranges of the failed levels */
			for (i = 0; i <= max_brightness; i++) {
				int end = i;

				if (brightness_fail[i]) {
					int j;

					/* Scan until we don't find a failure */
					for (j = i; j <= max_brightness && brightness_fail[j]; j++)
						end = j;

					if (i == end) {
						/* Just one failure */
						snprintf(buf, sizeof(buf), " %d", i);
					} else {
						/* A contiguous range of failures */
						snprintf(buf, sizeof(buf), " %d-%d", i, end);
						i = end;
					}
					msg = fwts_realloc_strcat(msg, buf);
				}
			}
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"BrightnessMismatch",
				"%d brightness levels did not match the brightnesss level "
				"just set for backlight %s.",
				failures, entry->d_name);
			fwts_log_info(fw, "The failed brightness levels were:%s.", msg);
			free(msg);
		} else
			fwts_passed(fw, "Actual brightness matches the brightnesss level for "
				"all %d levels for backlight %s.", max_brightness, entry->d_name);

		free(brightness_fail);

		/* Restore original setting */
		brightness_set_setting(entry->d_name, "brightness", saved_brightness);
	} while (entry);

	return FWTS_OK;
}
Exemple #30
0
static int compare_config_space(
	fwts_framework *fw,
	const fwts_acpi_mcfg_configuration *config)
{
	uint8_t *mapped_config_space;
	uint8_t config_space[16];
	size_t page_size, n;
	bool match;
	char path[PATH_MAX];
	FILE *fp;
	int i;

	page_size = fwts_page_size();

	/*
 	 * Sanity check on first config, this is enough to
	 * see if MMIO base is OK or not
	 */
	snprintf(path, sizeof(path),
		"/sys/bus/pci/devices/%4.4" PRIx16 ":00:00.0/config",
		config->pci_segment_group_number);

	if ((fp = fopen(path, "r")) == NULL) {
		fwts_log_warning(fw, "Could not open %s.", path);
		return FWTS_ERROR;
	}
	n = fread(config_space, 1, sizeof(config_space), fp);
	(void)fclose(fp);
	if (n != sizeof(config_space)) {
		fwts_log_warning(fw, "Could only read %zd bytes from %s, expecting %zd.", n, path, sizeof(config_space));
		return FWTS_ERROR;
	}

	if ((mapped_config_space = fwts_mmap(config->base_address, page_size)) == FWTS_MAP_FAILED) {
		fwts_log_error(fw, "Cannot mmap PCI config space at 0x%" PRIx64 ".",
			config->base_address);
		return FWTS_ERROR;
	}

	/* We only need to check if just the config space is readable */
	if (fwts_safe_memread(mapped_config_space, sizeof(config_space)) != FWTS_OK) {
		fwts_log_error(fw, "Cannot read PCI config space at 0x%" PRIx64 ".",
			config->base_address);
		(void)fwts_munmap(mapped_config_space, page_size);
		return FWTS_ERROR;
	}

	/*
	 * Need to explicitly do byte comparisons on region
	 * memcmp() fails as this can do 64 bit reads
	 */
	for (match = true, i = 0; i < 16; i++) {
		if (config_space[i] != mapped_config_space[i]) {
			match = false;
			break;
		}
	}
	(void)fwts_munmap(mapped_config_space, page_size);

	if (match)
		fwts_passed(fw, "PCI config space verified.");
	else
		fwts_failed(fw, LOG_LEVEL_MEDIUM,
			"PCIConfigSpaceBad",
			"PCI config space appears to not work.");

	return FWTS_OK;
}