예제 #1
0
파일: battery.c 프로젝트: 9elements/fwts
static int battery_test1(fwts_framework *fw)
{
	uint32_t count = 0;
	uint32_t i;

	fwts_log_info(fw,
	   "This test reports which (if any) batteries there are in the system. "
	   "In addition, for charging or discharging batteries, the test validates "
	   "that the reported 'current capacity' properly increments/decrements "
	   "in line with the charge/discharge state. "
	   "This test also stresses the battery state reporting codepath "
	   "in the ACPI BIOS, and any warnings given by the ACPI interpreter "
	   "will be reported.");

	if (fwts_battery_get_count(fw, &count) != FWTS_OK) {
		fwts_log_info(fw, "No battery information present: cannot test.");
		return FWTS_OK;
	}

	fwts_log_info(fw, "Found %" PRIu32 " batteries.", count);

	for (i = 0; i < count; i++)
		do_battery_test(fw, i);

	return FWTS_OK;
}
예제 #2
0
파일: prd_info.c 프로젝트: 9elements/fwts
static int prd_restart(fwts_framework *fw)
{
	int status = 0;
	char *command;
	char *output = NULL;

	command = "systemctl start opal-prd.service 2>&1";
	status = fwts_exec2(command, &output);

	if (output)
		free(output);

	if (status) {
		fwts_log_info(fw, "OPAL PRD service (opal-prd.service)"
			" was restarted after stopping it to allow "
			"checks.  Please re-check since processing "
			"was not able to be confirmed, "
			"\"sudo systemctl status opal-prd.service\"");
	} else {
		fwts_log_info(fw, "OPAL PRD service (opal-prd.service)"
			" was restarted after stopping it to allow "
			"checks.  This is informational only, "
			"no action needed.");
	}

	return status; /* ignored by caller */
}
예제 #3
0
파일: version.c 프로젝트: 9elements/fwts
static int version_test3(fwts_framework *fw)
{
	char *str;

	if ((str = fwts_get("/proc/cmdline")) == NULL)
		fwts_log_info(fw, "Cannot get version info from /proc/cmdline");
	else {
		fwts_chop_newline(str);
		fwts_log_info(fw, "Kernel boot command line: %s", str);
		free(str);
	}
	fwts_infoonly(fw);

	return FWTS_OK;
}
예제 #4
0
파일: battery.c 프로젝트: 9elements/fwts
static void do_battery_test(fwts_framework *fw, const uint32_t index)
{
	char name[PATH_MAX];
	char state[1024];

	*state = '\0';

	fwts_battery_get_name(fw, index, name);

	fwts_log_info(fw, "Test battery '%s'.", name);

	fwts_printf(fw, "==== Please PLUG IN the AC power of the machine ====\n");
	fwts_press_enter(fw);

	fwts_printf(fw, "==== Please now UNPLUG the AC power of the machine ====\n");
	wait_for_acpi_event(fw, name);
	check_discharging(fw, index, name);
	fwts_printf(fw, "==== Please wait 30 seconds while the battery is discharged a little ====\n");
	battery_discharge(fw, 30);
	fwts_printf(fw, "==== Please now PLUG IN the AC power of the machine ====\n");
	wait_for_acpi_event(fw, name);
	check_charging(fw, index, name);
	check_battery_cycle_count(fw, index, name);
	check_battery_trip_point(fw, index, name);
}
예제 #5
0
파일: version.c 프로젝트: 9elements/fwts
static int version_test1(fwts_framework *fw)
{
	char *str;
	fwts_release *release;

	release = fwts_release_get();
        if (release) {
		bool not_ubuntu = strcmp(release->distributor, "Ubuntu");

		fwts_release_free(release);
		/* Following is Ubuntu specific, so don't fail */
		if (not_ubuntu) {
			fwts_skipped(fw, "Information not available with this kernel.");
			return FWTS_OK;
		}
        }

	if ((str = fwts_get("/proc/version_signature")) == NULL)
		fwts_skipped(fw,
			"Cannot get version signature info from "
			"/proc/version_signature");
	else {
		fwts_chop_newline(str);
		fwts_log_info(fw, "Signature: %s", str);
		free(str);
	}

	fwts_infoonly(fw);

	return FWTS_OK;
}
예제 #6
0
파일: prd_info.c 프로젝트: 9elements/fwts
static int prd_info_init(fwts_framework *fw)
{
	if (fw->fdt) {
#ifdef HAVE_LIBFDT
		int node;
		node = fdt_path_offset(fw->fdt,
			"/ibm,opal/diagnostics");
		if (node >= 0) {
			if (!fdt_node_check_compatible(fw->fdt, node,
				"ibm,opal-prd")) {
				return FWTS_OK;
			} else {
				return FWTS_SKIP;
			}
		}
#endif
	} else {
		fwts_log_info(fw, "The OPAL PRD device tree node is not"
			" able to be detected so skipping the prd_info"
			" test.  There may be tools missing such as"
			" libfdt-dev or dtc, check that the packages"
			" are installed and re-build if needed."
			" If this condition persists try running the"
			" dt_base test to further diagnose. If dt_base"
			" test is not available this is probably a"
			" setup problem.");
		return FWTS_SKIP;
	}

	/* only run test when fdt node is confirmed */
	return FWTS_SKIP;
}
예제 #7
0
static int ebda_test1(fwts_framework *fw)
{
	const char *memory_map_name = fwts_memory_map_name(fw->firmware_type);
	fwts_memory_map_entry *entry;

	if (memory_map == NULL)
		return FWTS_ERROR;

	fwts_log_info(fw,
		"The Extended BIOS Data Area (EBDA) is normally located at "
		"the end of the low 640K region and is typically 2-4K in "
		"size. It should be reserved in the %s table.",
		memory_map_name);

	entry = fwts_memory_map_info(memory_map, (uint64_t)ebda_addr);
	if ((entry != NULL) &&
	    (entry->type == FWTS_MEMORY_MAP_RESERVED ||
	     entry->type == FWTS_MEMORY_MAP_ACPI)) {
		fwts_passed(fw, "EBDA region mapped at 0x%lx and reserved as a %" PRId64
			"K region in the %s table at 0x%" PRIx64 "..0x%" PRIx64 ".",
			ebda_addr,
			(entry->end_address - entry->start_address) / 1024,
			memory_map_name,
			entry->start_address,
			entry->end_address);
	} else
		fwts_failed(fw, LOG_LEVEL_MEDIUM,
			"EBDAMappedNotReserved",
			"EBDA region mapped at 0x%lx but not reserved in the %s table.",
			ebda_addr, memory_map_name);
		
	return FWTS_OK;
}
예제 #8
0
파일: prd_info.c 프로젝트: 9elements/fwts
static int prd_dev_query(fwts_framework *fw)
{

	int fd = 0;
	struct opal_prd_info info;

	if ((fd = open(prd_devnode, O_RDWR)) < 0) {
		fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL PRD Info",
			"Cannot get data from the OPAL PRD "
			" device interface,"
			" check if opal-prd daemon may be in use "
			"or check your user privileges.");
		return FWTS_ERROR;
	}

	memset(&info, 0, sizeof(info));

	if (ioctl(fd, OPAL_PRD_GET_INFO, &info)) {
		(void)close(fd);
		fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL PRD Info",
			"Cannot get data from the"
			" OPAL PRD device interface.");
		return FWTS_ERROR;
	} else {
		fwts_log_info(fw, "OPAL PRD Version is %lu",
			info.version);
		(void)close(fd);
		return FWTS_OK;
	}
}
예제 #9
0
파일: version.c 프로젝트: 9elements/fwts
static int version_test4(fwts_framework *fw)
{
	char *str;

        if (((str = fwts_get("/sys/module/acpi/parameters/acpica_version")) == NULL) &&
	    ((str = fwts_get("/proc/acpi/info")) == NULL))
		fwts_log_info(fw,
			"Cannot get ACPI version info from "
			"/sys/module/acpi/parameters/acpica_version "
			"or /proc/acpi/info, system does not have ACPI.");
	else {
		fwts_chop_newline(str);
		fwts_log_info(fw, "ACPI Version: %s", str);
		free(str);
	}
	fwts_infoonly(fw);

	return FWTS_OK;
}
예제 #10
0
파일: battery.c 프로젝트: 9elements/fwts
static void check_battery_trip_point(
	fwts_framework *fw,
	const uint32_t index,
	const char *name)
{
	uint32_t trip_point;
	uint32_t trip_point_org;

	fwts_printf(fw, "==== Checking trip point of battery '%s' ====\n", name);

	if (!fwts_battery_check_trip_point_support(fw, index)) {
		fwts_printf(fw, "==== Not supported - skip test ====\n");
		return;
	}

	if (fwts_battery_get_trip_point(fw, index, &trip_point) == FWTS_OK)
		trip_point_org = trip_point;
	else
		trip_point_org = 0;

	fwts_log_info(fw, "Test battery '%s' downward trip point.", name);
	fwts_printf(fw, "==== Please now UNPLUG the AC power of the machine ====\n");
	fwts_press_enter(fw);
	sleep(1);
	trip_point = get_full(fw, index) - 5;
	fwts_battery_set_trip_point(fw, index, trip_point);
	fwts_cpu_consume_start();
	wait_for_acpi_event(fw, name);
	fwts_cpu_consume_complete();

	fwts_log_info(fw, "Test battery '%s' upwards trip point.", name);
	fwts_printf(fw, "==== Please PLUG IN the AC power of the machine ====\n");
	fwts_press_enter(fw);
	sleep(1);
	trip_point = get_full(fw, index) + 3;
	fwts_battery_set_trip_point(fw, index, trip_point);
	wait_for_acpi_event(fw, name);

	if (trip_point_org != 0)
		fwts_battery_set_trip_point(fw, index, trip_point_org);

}
예제 #11
0
파일: romdump.c 프로젝트: 9elements/fwts
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;
}
예제 #12
0
static int uefivarinfo_init(fwts_framework *fw)
{
	if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) {
		fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted.");
		return FWTS_ABORTED;
	}

	if (fwts_lib_efi_runtime_load_module(fw) != FWTS_OK) {
		fwts_log_info(fw, "Cannot load efi_runtime module. Aborted.");
		return FWTS_ABORTED;
	}

	fd = fwts_lib_efi_runtime_open();
	if (fd == -1) {
		fwts_log_info(fw, "Cannot open EFI test driver. Aborted.");
		return FWTS_ABORTED;
	}

	return FWTS_OK;
}
예제 #13
0
static int uefirtauthvar_init(fwts_framework *fw)
{
	if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) {
		fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted.");
		return FWTS_ABORTED;
	}

	if (fwts_lib_efi_runtime_load_module(fw) != FWTS_OK) {
		fwts_log_info(fw, "Cannot load efi_runtime module. Aborted.");
		return FWTS_ABORTED;
	}

	fd = open("/dev/efi_runtime", O_WRONLY | O_RDWR);
	if (fd == -1) {
		fwts_log_info(fw, "Cannot open efi_runtime driver. Aborted.");
		return FWTS_ABORTED;
	}

	uefirtvariable_env_cleanup();

	return FWTS_OK;
}
예제 #14
0
파일: clog.c 프로젝트: ColinIanKing/fwts
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;
}
예제 #15
0
파일: s4.c 프로젝트: 9elements/fwts
static int wrap_logind_do_s4(fwts_pm_method_vars *fwts_settings,
	const int percent,
	int *duration,
	const char *str)
{
	FWTS_UNUSED(str);
	char *action = PM_HIBERNATE_LOGIND;
	fwts_progress_message(fwts_settings->fw, percent, "(Hibernating)");

	/* This blocks by entering a glib mainloop */
	*duration = fwts_logind_wait_for_resume_from_action(fwts_settings, action, s4_min_delay);
	fwts_log_info(fwts_settings->fw, "S4 duration = %d.", *duration);
	fwts_progress_message(fwts_settings->fw, percent, "(Resumed)");

	return *duration > 0 ? 0 : 1;
}
예제 #16
0
파일: dt_sysinfo.c 프로젝트: 9elements/fwts
static bool machine_matches_reference_model(fwts_framework *fw,
	const char *compatible,
	int compat_len,
	const char *model)
{
	bool compatible_is_reference = false, model_is_reference = false;
	struct reference_platform *plat;
	int i;

	for (i = 0; i < (int)FWTS_ARRAY_LEN(openpower_reference_platforms);
			i++) {
		plat = &openpower_reference_platforms[i];
		if (dt_fdt_stringlist_contains_last(compatible,
				compat_len, plat->compatible)) {
			compatible_is_reference = true;
			break;
		}
	}

	/* Not a reference platform, nothing to check */
	if (!compatible_is_reference) {
		fwts_log_info(fw, "Informational: no reference model found,"
			" device tree \"compatible\" is \"%s\" and"
			" \"model\" is \"%s\"",
			compatible, model);
		return true;
	}

	/* Since we're on a reference platform, ensure that the model is also
	 * one of the reference model numbers */
	for (i = 0; i < plat->n_models; i++) {
		if (!strcmp(model, plat->models[i])) {
			model_is_reference = true;
			break;
		}
	}

	if (model_is_reference) {
		fwts_log_info_verbatim(fw,
			"Matched reference model, device tree "
			"\"compatible\" is \"%s\" and \"model\" is "
			"\"%s\"",
			plat->compatible, model);
	}

	return model_is_reference;
}
예제 #17
0
파일: lid.c 프로젝트: ahs3/fwts-sbbr
static int lid_test3(fwts_framework *fw)
{
	int i;
	fwts_log_info(fw, "Some machines may have EC or ACPI faults that cause detection of multiple open/close events to fail.");

	for (i = 1; i < 4; i++) {
		int ret;

		fwts_printf(fw, "==== %d of %d: Please close laptop lid for 2 seconds and then re-open. ====\n", i,3);

		if ((ret = lid_test_state(fw, FWTS_BUTTON_LID_CLOSED)) != FWTS_OK)
			return ret;
		if ((ret = lid_test_state(fw, FWTS_BUTTON_LID_OPENED)) != FWTS_OK)
			return ret;
	}

	return FWTS_OK;
}
예제 #18
0
파일: clog.c 프로젝트: ColinIanKing/fwts
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;
}
예제 #19
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;
}
예제 #20
0
파일: battery.c 프로젝트: 9elements/fwts
static void check_battery_cycle_count(
	fwts_framework *fw,
	const uint32_t index,
	const char *name)
{
	uint32_t cycle_count;

	fwts_printf(fw, "==== Checking cycle count of battery '%s' ====\n", name);
	if (fwts_battery_get_cycle_count(fw, index, &cycle_count) == FWTS_OK) {
		if (cycle_count == 0) {
			fwts_log_info(fw,
				"Please ignore this error with a new battery");
			fwts_failed(fw, LOG_LEVEL_LOW, "BatteryZeroCycleCount",
			"System firmware may not support cycle count interface "
			"or it reports it incorrectly for battery %s.",
			name);
		}
	}

}
예제 #21
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;
}
예제 #22
0
static int uefivarinfo_test1(fwts_framework *fw)
{
	uint64_t status;
	uint64_t remvarstoragesize;
	uint64_t maxvariablesize;
	uint64_t maxvarstoragesize;

	uint64_t usedvars;
	uint64_t usedvarssize;

	if (do_queryvariableinfo(&status, &maxvarstoragesize, &remvarstoragesize, &maxvariablesize) == FWTS_ERROR) {
		if (status == EFI_UNSUPPORTED) {
			fwts_skipped(fw,
				"QueryVariableInfo UEFI runtime interface not supported: cannot test.");
			fwts_advice(fw,
				"Firmware also needs to check if the revision "
				"of system table is correct or not. Linux "
				"kernel returns EFI_UNSUPPORTED as well, if "
				"the FirmwareRevision of system table is less "
				"than EFI_2_00_SYSTEM_TABLE_REVISION.");
			return FWTS_SKIP;
		} else {
			fwts_log_info(fw, "Failed to query variable info with UEFI runtime service.");
			fwts_uefi_print_status_info(fw, status);
			return FWTS_ERROR;
		}
	}

	fwts_log_info_verbatim(fw, "UEFI NVRAM storage:");
	fwts_log_info_verbatim(fw, "  Maximum storage:       %8" PRIu64 " bytes", maxvarstoragesize);
	fwts_log_info_verbatim(fw, "  Remaining storage:     %8" PRIu64 " bytes", remvarstoragesize);
	fwts_log_info_verbatim(fw, "  Maximum variable size: %8" PRIu64 " bytes", maxvariablesize);

	if (do_checkvariables(fw, &usedvars, &usedvarssize, maxvariablesize) == FWTS_OK) {
		fwts_log_info_verbatim(fw, "Currently used:");
		fwts_log_info_verbatim(fw, "  %" PRIu64 " variables, storage used: %" PRIu64 " bytes", usedvars, usedvarssize);
	}

	return FWTS_OK;
}
예제 #23
0
파일: hpet.c 프로젝트: 9elements/fwts
static int hpet_check_test1(fwts_framework *fw)
{
	fwts_list_link *item;

	if (klog == NULL)
		return FWTS_ERROR;

	fwts_log_info(fw,
		"This test checks the HPET PCI BAR for each timer block "
		"in the timer. The base address is passed by the firmware "
		"via an ACPI table. IRQ routing and initialization is also "
		"verified by the test.");

	fwts_list_foreach(item, klog) {
		char *text = fwts_text_list_text(item);
		/* Old format */
		if (strstr(text, "ACPI: HPET id:") != NULL) {
			char *str = strstr(text, "base: ");
			if (str) {
				hpet_base_p = strtoul(str+6,  NULL, 0x10);
				fwts_passed(fw,
					"Found HPET base 0x%" PRIx64 " in kernel log.",
					hpet_base_p);
				break;
			}
		}
		/* New format */
		/* [    0.277934] hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0 */
		if ((strstr(text, "hpet") != NULL) &&
		    (strstr(text, "IRQs") != NULL)) {
			char *str = strstr(text, "at MMIO ");
			if (str) {
				hpet_base_p = strtoul(str+8,  NULL, 0x10);
				fwts_passed(fw,
					"Found HPET base 0x%" PRIx64 " in kernel log.",
					hpet_base_p);
				break;
			}
		}
	}
예제 #24
0
파일: ebdadump.c 프로젝트: ahs3/fwts-sbbr
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;
}
예제 #25
0
static int do_checkvariables(
	fwts_framework *fw,
	uint64_t *usedvars,
	uint64_t *usedvarssize,
	const uint64_t maxvarsize)
{
	uint64_t status;

	struct efi_getnextvariablename getnextvariablename;
	uint64_t variablenamesize = MAX_VARNAME_LENGTH;
	uint16_t variablename[MAX_VARNAME_LENGTH];
	EFI_GUID vendorguid;

	uint8_t *data;
	uint64_t getdatasize;

	uint32_t attributestest;
	struct efi_getvariable getvariable;
	getvariable.Attributes = &attributestest;
	getvariable.status = &status;

	getnextvariablename.VariableNameSize = &variablenamesize;
	getnextvariablename.VariableName = variablename;
	getnextvariablename.VendorGuid = &vendorguid;
	getnextvariablename.status = &status;

	*usedvars = 0;
	*usedvarssize = 0;

	/*
	 * To start the search, need to pass a Null-terminated string
	 * in VariableName
	 */
	variablename[0] = '\0';
	while (true) {
		long ioret;
		status = ~0ULL;

		variablenamesize = MAX_VARNAME_LENGTH;
		ioret = ioctl(fd, EFI_RUNTIME_GET_NEXTVARIABLENAME, &getnextvariablename);

		if (ioret == -1) {

			/* no next variable was found*/
			if (*getnextvariablename.status == EFI_NOT_FOUND)
				break;

			fwts_log_info(fw, "Failed to get next variable name with UEFI runtime service.");
			fwts_uefi_print_status_info(fw, status);
			return FWTS_ERROR;
		}

		(*usedvars)++;

		data = malloc(maxvarsize);
		if (!data) {
			fwts_log_info(fw, "Failed to allocate memory for test.");
			return FWTS_ERROR;
		}

		getdatasize = maxvarsize;
		getvariable.VariableName = variablename;
		getvariable.VendorGuid = &vendorguid;
		getvariable.DataSize = &getdatasize;
		getvariable.Data = data;
		status = ~0ULL;

		ioret = ioctl(fd, EFI_RUNTIME_GET_VARIABLE, &getvariable);
		if (ioret == -1) {
			if (status != EFI_BUFFER_TOO_SMALL) {
				free(data);
				fwts_log_info(fw, "Failed to get variable with UEFI runtime service.");
				fwts_uefi_print_status_info(fw, status);
				return FWTS_ERROR;
			} else if (getdatasize > maxvarsize) {
				free(data);
				fwts_log_info(fw, "Variable is larger than maximum variable length.");
				fwts_uefi_print_status_info(fw, status);

				/*
				 * Although the variable is larger than maximum variable length,
				 * still try to calculate the total sizes of the used variables.
				 */
				data = malloc(getdatasize);
				if (!data) {
					fwts_log_info(fw, "Failed to allocate memory for test.");
					return FWTS_ERROR;
				}

				getvariable.Data = data;
				status = ~0ULL;

				ioret = ioctl(fd, EFI_RUNTIME_GET_VARIABLE, &getvariable);
				if (ioret == -1) {
					fwts_log_info(fw, "Failed to get variable with variable larger than maximum variable length.");
					fwts_uefi_print_status_info(fw, status);
					free(data);
					return FWTS_ERROR;
				}
			}
		}
		free(data);

		(*usedvarssize) += getdatasize;

	};

	return FWTS_OK;

}
예제 #26
0
static int pstate_limits_test(fwts_framework *fw)
{
	int pstate_min, pstate_max, pstates[MAX_PSTATES];
	bool ok = true;
	int  nr_pstates, offset, len, ret, i;

	switch (proc_gen) {
	case proc_gen_p8:
		cmp_pstates = cmp_negative_pstates;
		break;
	case proc_gen_p9:
		cmp_pstates = cmp_positive_pstates;
		break;
	default:
		fwts_failed(fw, LOG_LEVEL_HIGH, "UnknownProcessorChip",
			"Unknown processor generation %d", proc_gen);
		return FWTS_ERROR;
	}

	offset = fdt_path_offset(fw->fdt, power_mgt_path);
	if (offset < 0) {
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTNodeMissing",
			"power management node %s is missing", power_mgt_path);
		return FWTS_ERROR;
	}

	ret = fwts_dt_property_read_u32(fw->fdt, offset, "ibm,pstate-min",
					&pstate_min);
	if (ret != FWTS_OK) {
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
			"Failed to read property ibm,pstate-min %s",
			fdt_strerror(pstate_min));
		return FWTS_ERROR;
	}

	ret = fwts_dt_property_read_u32(fw->fdt, offset, "ibm,pstate-max",
					&pstate_max);
	if (ret != FWTS_OK) {
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
			"Failed to read property ibm,pstate-max %s",
			fdt_strerror(pstate_max));
		return FWTS_ERROR;
	}

	ret = fwts_dt_property_read_u32_arr(fw->fdt, offset, "ibm,pstate-ids",
					pstates, &len);
	if (ret != FWTS_OK) {
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
			"Failed to read property ibm,pstate-ids %s",
			fdt_strerror(len));
		return FWTS_ERROR;
	}

	nr_pstates = abs(pstate_max - pstate_min) + 1;

	fwts_log_info(fw, "Pstates info: "
			"Pstate min: %d "
			"Pstate max: %d "
			"nr_pstates: %d "
			"Pstate ID's:  ",
			pstate_min, pstate_max, nr_pstates);

	for (i = 0; i < nr_pstates; i++)
		fwts_log_info(fw, " %d ", pstates[i]);

	if (nr_pstates <= 1)
		fwts_log_warning(fw, "Pstates range %d is not valid",
				 nr_pstates);

	if (proc_gen == proc_gen_p8 && nr_pstates > 128)
		fwts_log_warning(fw,
				"More than 128 pstates found,nr_pstates = %d",
				 nr_pstates);

	if (proc_gen == proc_gen_p9 && nr_pstates > 255)
		fwts_log_warning(fw,
				"More than 255 pstates found,nr_pstates = %d",
				 nr_pstates);

	if (len != nr_pstates)
		fwts_log_warning(fw, "Wrong number of pstates."
				"Expected %d pstates, found %d pstates",
				nr_pstates, len);

	for (i = 0; i < nr_pstates; i++) {
		if (cmp_pstates(pstate_max, pstates[i]) < 0) {
			fwts_log_warning(fw, "Invalid Pstate id %d "
					"greater than max pstate %d",
					pstates[i], pstate_max);
			ok = false;
		}
		if (cmp_pstates(pstates[i], pstate_min) < 0) {
			fwts_log_warning(fw, "Invalid Pstate id %d "
					"lesser than min pstate %d",
					pstates[i], pstate_min);
			ok = false;
		}
	}

	/* Pstates should be in monotonic descending order */
	for (i = 0; i < nr_pstates; i++) {
		if ((i == 0) && (cmp_pstates(pstates[i], pstate_max) != 0)) {
			fwts_log_warning(fw, "Pstates mismatch: "
					"Expected Pmax %d,"
					"Actual Pmax %d",
					pstate_max, pstates[i]);
			ok = false;
		} else if ((i == nr_pstates - 1) &&
			(cmp_pstates(pstates[i], pstate_min) != 0)) {
			fwts_log_warning(fw, "Pstates mismatch: "
					"Expected Pmin %d,"
					"Actual Pmin %d",
					pstate_min, pstates[i]);
			ok = false;
		} else if (i != 0 && i != nr_pstates) {
			int previous_pstate;
			previous_pstate = pstates[i-1];
			if (cmp_pstates(pstates[i], previous_pstate) > 0) {
				fwts_log_warning(fw, "Non monotonicity ...,"
						"Pstate %d greater then"
						" previous Pstate %d",
						pstates[i], previous_pstate);
				ok = false;
			}
		}
	}

	if (!ok) {
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUPstateLimitsTestFail",
		"One or few CPU Pstates DT validation tests failed");
		return FWTS_ERROR;
	}
	fwts_passed(fw, "CPU Frequency pstates are validated");
	return FWTS_OK;

}
예제 #27
0
파일: slit.c 프로젝트: ahs3/fwts-sbbr
/*
 *  For SLIT System Locality Distance Information refer to
 *    section 5.2.17 of the ACPI specification version 6.0
 */
static int slit_test1(fwts_framework *fw)
{
	bool passed = true;
	uint64_t i, j, size, n, reserved = 0, bad_entry = 0;
	uint8_t *entry;
	fwts_acpi_table_slit *slit = (fwts_acpi_table_slit *)table->data;

	/* Size sanity check #1, got enough table to at least get matrix size */
	if (table->length < sizeof(fwts_acpi_table_slit)) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SLITTooShort",
			"SLIT table too short, must be at least %zu bytes, "
			"instead got %zu bytes",
			sizeof(fwts_acpi_table_spmi), table->length);
		goto done;
	}

	n = slit->num_of_system_localities;
	fwts_log_info_verbatum(fw, "SLIT System Locality Distance Information Table:");
	fwts_log_info_verbatum(fw, "  Number of Localities:     0x%" PRIx64, n);

	/*
	 *  ACPI table length is 32 bits, so maximum matrix of entries size is
	 *  is 2^32 - sizeof(fwts_acpi_table_slit) = 2^32 - 44 = 4294967252
	 *  and table is a N x N matrix, so maxium number of localities is
	 *  limited to int(sqrt(4294967252)) = 65535.
	 */
	if (n > 0xffff) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SLITTooManySystemLocalities",
			"SLIT table size is %zu, however, the number of "
			"System Locality Entries is %" PRIu64 " which "
			"results in an ACPI table larger than the maximum "
			"32 bit ACPI table size of 4MB",
			table->length,
			n);
		goto done;
	}

	/*
	 *  Now that we are confident of no overflow, check that the matrix
	 *  + SLIT table header is not bigger than the actual table.
	 */
	size = (n * n) + sizeof(fwts_acpi_table_slit);
	if ((uint64_t)table->length < size) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SLITTooManySystemLocalities",
			"SLIT table size is %zu, however, the number of "
			"System Locality Entries is %" PRIu64 " and this "
			"results in a table of size %" PRIu64 " which "
			"is larger than the SLIT table size",
			table->length, size, n);
		goto done;
	}

	entry = (uint8_t *)table->data + sizeof(fwts_acpi_table_slit);

	/*
	 *  Now sanity check the entries..
	 */
	if (entry[INDEX(0,0)] != 10) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SLITBadCornerEntry",
			"SLIT Entry[0][0] is 0x%" PRIx8 ", expecting value 0x0a.",
			entry[INDEX(0,0)]);
	}
	if (entry[INDEX(n - 1, n - 1)] != 10) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SLITBadCornerEntry",
			"SLIT Entry[%" PRIu64 "][%" PRIu64 "] is 0x%" PRIx8 ", expecting value 0x0a.",
			n - 1, n - 1,
			entry[INDEX(n - 1, n - 1)]);
	}

	for (i = 0; i < n; i++) {
		for (j = 0; j < n; j++) {
			uint8_t val1 = entry[INDEX(i, j)],
				val2 = entry[INDEX(j, i)];

			/* Check for distances less than 10 (reserved, no meaning) */
			if (val1 < 10) {
				reserved++;
				/* Report first 16 errors */
				if (reserved < 16) {
					fwts_failed(fw, LOG_LEVEL_HIGH,
						"SLITEntryReserved",
						"SLIT Entry[%" PRIu64 "][%" PRIu64 "]"
						" is 0x%" PRIx8 " which is a reserved value"
						" and has no defined meaning",
						i, j, val1);
				}
			}

			if (val1 != val2) {
				bad_entry++;
				/* Report first 16 bad entries */
				if (bad_entry < 16) {
					fwts_failed(fw, LOG_LEVEL_HIGH,
						"SLITEntryReserved",
						"SLIT Entry[%" PRIu64 "][%" PRIu64 "]"
						" is 0x%" PRIx8 " and not the same as "
						"SLIT Entry[%" PRIu64 "][%" PRIu64 "]"
						" which is 0x%" PRIx8,
						i, j, val1, j, i, val2);
				}
			}
		}
	}

	if (reserved)
		fwts_log_info(fw, "Total of %" PRIu64 " entries were using reserved values",
			reserved);
	if (bad_entry)
		fwts_log_info(fw, "Total of %" PRIu64 " entries were not matching "
			"their diagonal parner element", bad_entry);
done:
	if (passed)
		fwts_passed(fw, "No issues found in SLIT table.");

	return FWTS_OK;
}
예제 #28
0
파일: s4.c 프로젝트: 9elements/fwts
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;
}
예제 #29
0
파일: s4.c 프로젝트: 9elements/fwts
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;
}
예제 #30
0
파일: mcfg.c 프로젝트: 9elements/fwts
static int mcfg_test1(fwts_framework *fw)
{
	int nr, i;
	fwts_acpi_table_mcfg *mcfg = (fwts_acpi_table_mcfg*)mcfg_table->data;
	fwts_acpi_mcfg_configuration *config;
	bool failed = false;
	ssize_t mcfg_size;
	const char *memory_map_name;

	memory_map_name = fwts_memory_map_name(fw->firmware_type);

	fwts_log_info(fw,
		"This test tries to validate the MCFG table by comparing the first "
		"16 bytes in the MMIO mapped config space with the 'traditional' config "
		"space of the first PCI device (root bridge). The MCFG data is only "
		"trusted if it is marked reserved in the %s",
		memory_map_name);
	fwts_log_nl(fw);

	if ((memory_map_list = fwts_memory_map_table_load(fw)) == NULL) {
		/* Not fatal, just means test will be less comprehensive */
		fwts_log_warning(fw, "No memory map table found");
	} else {
		fwts_memory_map_table_dump(fw, memory_map_list);
		fwts_log_nl(fw);
	}

	mcfg_size = mcfg_table->length;
	mcfg_size -= sizeof(fwts_acpi_table_mcfg);

	if (mcfg_size < 0) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "MCFGInvalidSize",
			"Invalid MCFG ACPI table size: got %zd bytes expecting more",
			mcfg_size + sizeof(fwts_acpi_table_mcfg));
		fwts_advice(fw,
			"MCFG table must be least %zd bytes (header size) with "
			"multiples of %zd bytes for each MCFG entry.",
			sizeof(fwts_acpi_table_mcfg),
			sizeof(fwts_acpi_mcfg_configuration));
		return FWTS_ERROR;
	}
	nr = mcfg_size / sizeof(fwts_acpi_mcfg_configuration);

	if (!nr) {
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MCFGNoEntries",
			"No MCFG ACPI table entries");
		return FWTS_ERROR;
	}

	if (mcfg_size != (ssize_t)(nr * sizeof(fwts_acpi_mcfg_configuration))) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "MCFGInvalidSize2",
			"MCFG table is not a multiple of record size");
		return FWTS_ERROR;
	}

	fwts_log_info(fw,
		"MCFG table found, size is %zd bytes (excluding header) (%i entries).",
		mcfg_size, nr);

	if (mcfg == NULL) {
		fwts_failed(fw, LOG_LEVEL_HIGH, "MCFGInvalidTable",
			"Invalid MCFG ACPI table");
		return FWTS_ERROR;
	}

	if (memory_map_list == NULL)
		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MMapUnreadable",
			"Cannot check MCFG MMIO space against memory map table: could not read memory map table.");

	config = &mcfg->configuration[0];
	for (i = 0; i < nr; i++, config++) {
		fwts_log_info_verbatim(fw, "Configuration Entry #%d:", i);
		fwts_log_info_verbatim(fw, "  Base Address  : 0x%" PRIx64, config->base_address);
		fwts_log_info_verbatim(fw, "  Segment       : %" PRIu8, config->pci_segment_group_number);
		fwts_log_info_verbatim(fw, "  Start bus     : %" PRIu8, config->start_bus_number);
		fwts_log_info_verbatim(fw, "  End bus       : %" PRIu8, config->end_bus_number);

		if ((memory_map_list != NULL) &&
		    (!fwts_memory_map_is_reserved(memory_map_list, config->base_address))) {

			fwts_failed(fw, LOG_LEVEL_LOW, "MCFGMMIONotReserved",
				"MCFG MMIO config space at 0x%" PRIx64
				" is not reserved in the memory map table",
				config->base_address);
			fwts_advice(fw,
				"The PCI Express specification states that the "
				"PCI Express configuration space should "
				"be defined in the MCFG table and *maybe* "
				"optionally defined in the %s if ACPI MCFG is "
				"present. Linux checks if the region is reserved "
				"in the memory map table and will reject the "
				"MMCONFIG if there is a discrepency between MCFG "
				"and the memory map table for the PCI Express region. "
				"[See arch/x86/pci/mmconfig-shared.c pci_mmcfg_reject_broken()]. "
				"It is recommended that this is defined in the "
				"%s table for Linux.",
				memory_map_name, memory_map_name);
			failed = true;
		}
	}
	if (!failed)
		fwts_passed(fw, "MCFG MMIO config space is reserved in memory map table.");

	return FWTS_OK;
}