Пример #1
0
/*
 *  WSMT Windows Platform Binary Table
 */
static int wsmt_test1(fwts_framework *fw)
{
	fwts_acpi_table_wsmt *wsmt = (fwts_acpi_table_wsmt*) table->data;
	bool passed = true;

	fwts_log_info_verbatim(fw, "WSMT Windows SMM Security Mitigations Table:");
	fwts_log_info_verbatim(fw, "  Protection Flags:      0x%8.8" PRIx32, wsmt->protection_flags);

	fwts_acpi_reserved_bits_check(fw, "WSMT", "Protection Flags", wsmt->protection_flags, sizeof(wsmt->protection_flags), 3, 31, &passed);

	if ((wsmt->protection_flags & 0x2) && !(wsmt->protection_flags & 0x1)) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_MEDIUM,
			"WSMTBadFlagsValue",
			"WSMT Protection Flags bit[1] must be "
			"set when bit[2] is set");
	}

	fwts_log_nl(fw);

	if (passed)
		fwts_passed(fw, "No issues found in WSMT table.");

	return FWTS_OK;
}
Пример #2
0
static void extended_pcc_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_3_4 *entry, bool *passed)
{
	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
	fwts_log_info_verbatim(fw, "    Platform Interrupt Flags:    0x%2.2"   PRIx8, entry->platform_interrupt_flags);
	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved1);
	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
	memory_length(fw, entry->header.type, entry->length, 16, passed);
	fwts_log_info_verbatim(fw, "    Doorbell Register:");
	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
	fwts_log_info_verbatim(fw, "    Command Complete Check Register:");
	gas_messages(fw, entry->header.type, &entry->platform_ack_register, passed);
	fwts_log_info_verbatim(fw, "    Doorbell Ack Preserve:       0x%16.16" PRIx64, entry->platform_ack_preserve);
	fwts_log_info_verbatim(fw, "    Doorbell Ack Write:          0x%16.16" PRIx64, entry->platform_ack_write);
	fwts_log_info_verbatim(fw, "    Reserved:                    0x%16.16" PRIx64, entry->reserved2);
	fwts_log_info_verbatim(fw, "    Cmd Complete Check Register:");
	gas_messages(fw, entry->header.type, &entry->cmd_complete_register, passed);
	fwts_log_info_verbatim(fw, "    Cmd Complete Check Mask:     0x%16.16" PRIx64, entry->cmd_complete_mask);
	fwts_log_info_verbatim(fw, "    Cmd Complete Update Register:");
	gas_messages(fw, entry->header.type, &entry->cmd_update_register, passed);
	fwts_log_info_verbatim(fw, "    Cmd Complete Update Mask:    0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
	fwts_log_info_verbatim(fw, "    Cmd Complete Set Mask:       0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
	fwts_log_info_verbatim(fw, "    Error Status Register:");
	gas_messages(fw, entry->header.type, &entry->error_status_register, passed);
	fwts_log_info_verbatim(fw, "    Error Status Mask:           0x%16.16" PRIx64, entry->error_status_mask);

	fwts_acpi_reserved_bits_check(fw, "PCCT", "Platform Interrupt Flags", entry->platform_interrupt_flags, sizeof(uint8_t), 2, 7, passed);
}
Пример #3
0
static int pdtt_test1(fwts_framework *fw)
{
	fwts_acpi_table_pdtt *pdtt = (fwts_acpi_table_pdtt*) table->data;
	fwts_acpi_table_pdtt_channel *entry;
	uint32_t offset, count, i;
	uint32_t reserved;
	bool passed = true;

	reserved = (uint32_t) pdtt->reserved[0] + ((uint32_t) pdtt->reserved[1] << 8) +
		   ((uint32_t) pdtt->reserved[2] << 16);

	fwts_log_info_verbatim(fw, "PDTT Platform Debug Trigger Table:");
	fwts_log_info_verbatim(fw, "  Trigger Count:           0x%2.2" PRIx8, pdtt->trigger_count);
	fwts_log_info_verbatim(fw, "  Reserved[3]:             0x%6.6" PRIx32, reserved);
	fwts_log_info_verbatim(fw, "  Trigger ID Array Offset: 0x%2.2" PRIx8, pdtt->array_offset);

	fwts_acpi_reserved_zero_check(fw, "PDTT", "Reserved", reserved, sizeof(reserved), &passed);

	offset = pdtt->array_offset;
	entry = (fwts_acpi_table_pdtt_channel *) (table->data + offset);

	count = (pdtt->header.length - pdtt->array_offset) / sizeof(fwts_acpi_table_pdtt_channel);
	if (count != pdtt->trigger_count) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_CRITICAL,
			"PDTTBadIDCount",
			"PDTT should have %" PRId8 " ids, got %" PRId8,
			pdtt->trigger_count, count);
		return FWTS_OK;
	}

	fwts_log_info_verbatim(fw, "  Platform Communication Channel IDs");

	for (i = 0; i < pdtt->trigger_count; i++) {
		fwts_log_info_verbatim(fw, "    Sub channel ID:          0x%2.2" PRIx8, entry->sub_channel_id);
		fwts_log_info_verbatim(fw, "    Flags:                   0x%2.2" PRIx8, entry->flags);
		fwts_acpi_reserved_bits_check(fw, "PDTT", "Flags", entry->flags, sizeof(entry->flags), 3, 7, &passed);

		if ((offset += sizeof(fwts_acpi_table_pdtt_channel)) > table->length) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_CRITICAL,
				"PDTTBadTableLength",
				"PDTT has more channel IDs than its size can handle");
			break;
		}

		entry = (fwts_acpi_table_pdtt_channel *) (table->data + offset);
	}

	fwts_log_nl(fw);

	if (passed)
		fwts_passed(fw, "No issues found in PDTT table.");

	return FWTS_OK;
}
Пример #4
0
/*
 *  4.1.2.1 ASF_INFO
 */
static void asf_check_info(
	fwts_framework *fw,
	ssize_t length,
	uint8_t *data,
	bool *passed,
	bool *abort)
{
	fwts_acpi_table_asf_info *info = (fwts_acpi_table_asf_info *)data;

	if (length < (ssize_t)sizeof(fwts_acpi_table_asf_info)) {
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"ASF!InfoRecordTooShort",
			"ASF! ASF_INFO Record too short, "
			"expecting %zu bytes, instead got %zu bytes",
			sizeof(fwts_acpi_table_asf_info), length);
		*passed = false;
		*abort = true;
		return;
	}

#if ASF_DUMP
	fwts_log_info_verbatim(fw, "ASF! ASF_INFO Record:");
	fwts_log_info_verbatim(fw, "  Min Watchdog Reset Value: 0x%2.2" PRIx8, info->watchdog_reset_value);
	fwts_log_info_verbatim(fw, "  Min Poll Wait Time:       0x%2.2" PRIx8, info->min_sensor_poll_wait_time);
	fwts_log_info_verbatim(fw, "  System ID:                0x%2.2" PRIx8, info->id);
	fwts_log_info_verbatim(fw, "  IANA Manufacturer ID:     0x%2.2" PRIx8, info->iana_id);
	fwts_log_info_verbatim(fw, "  Feature Flags:            0x%2.2" PRIx8, info->flags);
	fwts_log_info_verbatim(fw, "  Reserved:                 0x%2.2" PRIx8, info->reserved1);
	fwts_log_info_verbatim(fw, "  Reserved:                 0x%2.2" PRIx8, info->reserved2);
	fwts_log_info_verbatim(fw, "  Reserved:                 0x%2.2" PRIx8, info->reserved3);
#endif

	if (info->watchdog_reset_value == 0) {
		*passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"ASF!InfoMinWatchDogInvalid",
			"ASF! ASF_INFO Minimum Watchdog Reset Value is 0x00 and "
			"must be in the range 0x01..0xff");
	}
	if (info->min_sensor_poll_wait_time < 2) {
		*passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"ASF!InfoMinPollWaitTimeInvalid",
			"ASF! ASF_INFO Minimum Poll Wait Time is 0x%" PRIx8
			" and must be in the range 0x02..0xff",
			info->min_sensor_poll_wait_time);
	}

	fwts_acpi_reserved_bits_check(fw, "ASF!", "ASF_INFO Feature Flags", info->flags, sizeof(info->flags), 1, 7, passed);
	fwts_acpi_reserved_zero_check(fw, "ASF!", "ASF_INFO Reserved1", info->reserved1, sizeof(info->reserved1), passed);
	fwts_acpi_reserved_zero_check(fw, "ASF!", "ASF_INFO Reserved2", info->reserved2, sizeof(info->reserved2), passed);
	fwts_acpi_reserved_zero_check(fw, "ASF!", "ASF_INFO Reserved3", info->reserved3, sizeof(info->reserved3), passed);

	if (*passed)
		fwts_passed(fw, "No issues found in ASF! ASF_INFO record.");
}
Пример #5
0
static void hw_reduced_comm_test_type1(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_1 *entry, bool *passed)
{
	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
	fwts_log_info_verbatim(fw, "    Platform Interrupt Flags:    0x%2.2"   PRIx8, entry->platform_interrupt_flags);
	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved);
	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
	memory_length(fw, entry->header.type, entry->length, 8, passed);
	fwts_log_info_verbatim(fw, "    Doorbell Register:");
	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);

	fwts_acpi_reserved_bits_check(fw, "PCCT", "Platform Interrupt Flags", entry->platform_interrupt_flags, sizeof(uint8_t), 2, 7, passed);
}
Пример #6
0
/*
 *  GTDT  Generic Timer Description Table
 */
static int gtdt_test1(fwts_framework *fw)
{
	bool passed = true;
	uint8_t *ptr, *end_ptr;
	uint32_t i = 0, n;
	const fwts_acpi_table_gtdt *gtdt = (const fwts_acpi_table_gtdt *)table->data;

	fwts_acpi_reserved_bits_check(fw, "GTDT", "Flags", gtdt->virtual_timer_flags, sizeof(gtdt->virtual_timer_flags), 3, 31, &passed);

	ptr = (uint8_t *)table->data + gtdt->platform_timer_offset;
	n = gtdt->platform_timer_count;
	end_ptr = (uint8_t *)table->data + table->length;

	while ((i < n) && (ptr < end_ptr)) {
		uint32_t len, j;
		fwts_acpi_table_gtdt_block *block;
		fwts_acpi_table_gtdt_block_timer *block_timer;
		fwts_acpi_table_gtdt_watchdog *watchdog;
		char field[80];

		switch (*ptr) {
		case 0x00:
			/* GT Block Structure */
			block = (fwts_acpi_table_gtdt_block *)ptr;
			if (ptr + 20 > end_ptr) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTShortBlock",
					"GTDT block is too short");
				goto done;
			}
			if (block->length < 20) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTInvalidBlockLength",
					"GTDT block %" PRIu32 " length has in "
					"invalid length: %" PRIu32 " bytes",
					i, block->length);
				goto done;
			}
			if (block->reserved) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTInvalidBlockReserved",
					"GTDT block %" PRIu32 " reserved is "
					"non-zero, got 0x%" PRIx8,
					i, block->reserved);
			}
			if (block->block_timer_count > 8) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTInvalidBlockTimerCount",
					"GTDT block %" PRIu32 " timer count "
					"is too large, %" PRIu32 ", must be <= 8",
					i, block->block_timer_count);
				break;
			}
			len = (block->block_timer_count * 40) + 20;
			if (len != block->length) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTInvalidTimerCountOrLength",
					"GTDT block %" PRIu32 " timer count %"
					PRIu32 " and block length %" PRIu32 ", "
					"expected length of %" PRIu32,
					i, block->block_timer_count,
					block->length, len);
				/* length may be inconsistent, don't trust it so stop here */
				goto done;
			}
			block_timer = &block->block_timers[0];

			for (j = 0; j < block->block_timer_count; j++) {
				if (((uint8_t *)block_timer + sizeof(*block_timer)) > end_ptr)
					break;
				if (block_timer->frame_number > 7) {
					passed = false;
					fwts_failed(fw, LOG_LEVEL_HIGH,
						"GTDTInvalidGTFrameNumber",
						"GTDT block frame number is %" PRIu8
						", expecting 0..7",
						block_timer->frame_number);
				}
				if (block_timer->reserved[0] |
				    block_timer->reserved[1] |
				    block_timer->reserved[2]) {
					passed = false;
					fwts_failed(fw, LOG_LEVEL_HIGH,
						"GTDTBlockTimerReservedNotZero",
						"GTDT block %" PRIu32 " timer reserved "
						"space is not zero, got 0x"
						"%" PRIx8 "%" PRIx8 "%" PRIx8
						" instead", i,
						block_timer->reserved[0],
						block_timer->reserved[1],
						block_timer->reserved[2]);
				}

				snprintf(field, sizeof(field), "block %" PRIu32 " physical timer flags", i);
				fwts_acpi_reserved_bits_check(fw, "GTDT", field, block_timer->phys_timer_flags,
					sizeof(block_timer->phys_timer_flags), 2, 31, &passed);

				snprintf(field, sizeof(field), "block %" PRIu32 " virtual timer flags", i);
				fwts_acpi_reserved_bits_check(fw, "GTDT", field, block_timer->virt_timer_flags,
					sizeof(block_timer->virt_timer_flags), 2, 31, &passed);

				snprintf(field, sizeof(field), "block %" PRIu32 " common flags", i);
				fwts_acpi_reserved_bits_check(fw, "GTDT", field, block_timer->common_flags,
					sizeof(block_timer->common_flags), 2, 31, &passed);
			}
			ptr += block->length;
			break;
		case 0x01:
			/* SBSA Generic Watchdog Timer Structure */
			watchdog = (fwts_acpi_table_gtdt_watchdog *)ptr;
			if (ptr + 28 > end_ptr) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTShortWatchDogTimer",
					"GTDT SBSA generic watchdog timer %"
					PRIu32 " is too short", i);
				goto done;
			}
			if (watchdog->length != 28) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTInvalidWatchDogTimeLength",
					"GTDT SBSA generic watchdog timer %" PRIu32
					" length has in invalid length: %"
					PRIu32 " bytes", i, watchdog->length);
				goto done;
			}
			if (watchdog->reserved) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"GTDTInvalidWatchDogReserved",
					"GTDT SBSA generic watchdog timer %" PRIu32
					" reserved is non-zero, got 0x%" PRIx8,
					i, watchdog->reserved);
			}

			snprintf(field, sizeof(field), "SBSA generic watchdog timer %" PRIu32 " flags", i);
			fwts_acpi_reserved_bits_check(fw, "GTDT", field, watchdog->watchdog_timer_flags,
				sizeof(watchdog->watchdog_timer_flags), 3, 31, &passed);

			ptr += watchdog->length;
			break;
		default:
			passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"GTDTInvalidType",
				"GTDT platform timer strucuture %" PRIu32
				" has an invalid type: 0x%" PRIx8, i, *ptr);
			/* Can't determine field length, so end of parsing */
			goto done;
		}
		i++;
	}

done:
	if (passed)
		fwts_passed(fw, "No issues found in GTDT table.");

	return FWTS_OK;
}
Пример #7
0
static int pcct_test1(fwts_framework *fw)
{
	fwts_acpi_table_pcct *pcct = (fwts_acpi_table_pcct*) table->data;
	fwts_acpi_table_pcct_subspace_header *pcct_sub;
	size_t offset;
	bool passed = true;

	fwts_log_info_verbatim(fw, "PCC Table:");
	fwts_log_info_verbatim(fw, "  Flags:     0x%8.8"   PRIx32, pcct->flags);
	fwts_log_info_verbatim(fw, "  Reserved:  0x%16.16"   PRIx64, pcct->reserved);
	fwts_log_nl(fw);

	fwts_acpi_reserved_bits_check(fw, "PCCT", "Flags", pcct->flags, sizeof(pcct->flags), 1, 31, &passed);
	fwts_acpi_reserved_zero_check(fw, "PCCT", "Reserved", pcct->reserved, sizeof(pcct->reserved), &passed);

	offset = sizeof(fwts_acpi_table_pcct);
	pcct_sub = (fwts_acpi_table_pcct_subspace_header *) (table->data + offset);

	while (offset < table->length) {

		fwts_log_info_verbatim(fw, "  PCC Subspace Structure:");
		fwts_log_info_verbatim(fw, "    Type:                        0x%2.2"   PRIx8, pcct_sub->type);
		fwts_log_info_verbatim(fw, "    Length:                      0x%2.2"   PRIx8, pcct_sub->length);

		if (pcct_sub->type == 0) {
			fwts_acpi_table_pcct_subspace_type_0 *subspace = (fwts_acpi_table_pcct_subspace_type_0 *) pcct_sub;

			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_0), pcct_sub->length)) {
				passed = false;
				break;
			}

			generic_comm_test(fw, subspace, &passed);

		} else if (pcct_sub->type == 1) {
			fwts_acpi_table_pcct_subspace_type_1 *subspace = (fwts_acpi_table_pcct_subspace_type_1 *) pcct_sub;

			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_1), pcct_sub->length)) {
				passed = false;
				break;
			}

			hw_reduced_comm_test_type1(fw, subspace, &passed);

		} else if (pcct_sub->type == 2) {
			fwts_acpi_table_pcct_subspace_type_2 *subspace = (fwts_acpi_table_pcct_subspace_type_2 *) pcct_sub;

			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_2), pcct_sub->length)) {
				passed = false;
				break;
			}

			hw_reduced_comm_test_type2(fw, subspace, &passed);

		} else if (pcct_sub->type == 3) {
			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;

			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
				passed = false;
				break;
			}

			extended_pcc_test(fw, subspace, &passed);

		} else if (pcct_sub->type == 4) {
			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;

			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
				passed = false;
				break;
			}

			if (!(pcct->flags & 0x01)) {
				passed = false;
				fwts_failed(fw, LOG_LEVEL_HIGH,
					"PCCTBadFlags",
					"PCCT Platform Interrupt in flags must be set when subspace "
					"type 4 is present, got 0x%8.8" PRIx32 " instead", pcct->flags);
			}

			extended_pcc_test(fw, subspace, &passed);

		} else {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"PCCTBadSubType",
				"PCCT Subspace Structure supports type 0..4, got "
				"0x%2.2" PRIx8 " instead", pcct_sub->type);
			break;
		}

		fwts_log_nl(fw);

		offset += pcct_sub->length;
		pcct_sub = (fwts_acpi_table_pcct_subspace_header *) (table->data + offset);
	}

	if (passed)
		fwts_passed(fw, "No issues found in PCC table.");

	return FWTS_OK;
}
Пример #8
0
/*
 *  DRTM D-RTM Resources Table
 */
static int drtm_test1(fwts_framework *fw)
{
	fwts_acpi_table_drtm *drtm = (fwts_acpi_table_drtm*) table->data;
	fwts_acpi_table_drtm_vtl *drtm_vtl;
	fwts_acpi_table_drtm_rtl *drtm_rtl;
	fwts_acpi_table_drtm_dps *drtm_dps;
	bool passed = true;
	uint32_t offset;
	uint32_t i;

	fwts_log_info_verbatim(fw, "DRTM D-RTM Resources Table:");
	fwts_log_info_verbatim(fw, "  DL_Entry_Base:            0x%16.16" PRIx64, drtm->entry_base_address);
	fwts_log_info_verbatim(fw, "  DL_Entry_Length:          0x%16.16" PRIx64, drtm->entry_length);
	fwts_log_info_verbatim(fw, "  DL_Entry32:               0x%8.8" PRIx32, drtm->entry_address32);
	fwts_log_info_verbatim(fw, "  DL_Entry64:               0x%16.16" PRIx64, drtm->entry_address64);
	fwts_log_info_verbatim(fw, "  DLME_Exit:                0x%16.16" PRIx64, drtm->exit_address);
	fwts_log_info_verbatim(fw, "  Log_Area_Start:           0x%16.16" PRIx64, drtm->log_area_address);
	fwts_log_info_verbatim(fw, "  Log_Area_Length:          0x%8.8" PRIx32, drtm->log_area_length);
	fwts_log_info_verbatim(fw, "  Architecture_Dependent:   0x%16.16" PRIx64, drtm->arch_dependent_address);
	fwts_log_info_verbatim(fw, "  DRT_Flags:                0x%8.8" PRIx32, drtm->flags);

	fwts_acpi_reserved_bits_check(fw, "DRTM", "DRT_Flags", drtm->flags, sizeof(drtm->flags), 4, 31, &passed);
	fwts_log_nl(fw);

	offset = sizeof(fwts_acpi_table_drtm);
	drtm_vtl = (fwts_acpi_table_drtm_vtl *) (table->data + offset);
	fwts_log_info_verbatim(fw, "  VTL_Length:               0x%8.8" PRIx32, drtm_vtl->validated_table_count);
	offset += sizeof(drtm_vtl->validated_table_count);

	if (drtm->header.length < offset + sizeof(uint64_t) * drtm_vtl->validated_table_count) {
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"DRTMOutOfBound",
			"DRTM's length is too small to contain all fields");
		goto error;
	}

	for (i = 0; i < drtm_vtl->validated_table_count; i++) {
		fwts_log_info_verbatim(fw, "  Validated_Tables:         0x%16.16" PRIx64, drtm_vtl->validated_tables[i]);
		offset += sizeof(drtm_vtl->validated_tables[i]);
	}

	fwts_log_nl(fw);

	drtm_rtl = (fwts_acpi_table_drtm_rtl *) (table->data + offset);
	fwts_log_info_verbatim(fw, "  RL_Length:                0x%8.8" PRIx32, drtm_rtl->resource_count);
	offset += sizeof(drtm_rtl->resource_count);

	if (drtm->header.length < offset + sizeof(fwts_acpi_drtm_resource) * drtm_rtl->resource_count) {
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"DRTMOutOfBound",
			"DRTM's length is too small to contain all fields");
		goto error;
	}

	for (i = 0; i < drtm_rtl->resource_count; i++) {
		fwts_acpi_drtm_resource *resource = (fwts_acpi_drtm_resource *) (table->data + offset);
		uint64_t size;
		size = resource->size[0] + ((uint64_t) resource->size[1] << 8) +
					   ((uint64_t) resource->size[2] << 16) + ((uint64_t) resource->size[3] << 24) +
					   ((uint64_t) resource->size[4] << 32) + ((uint64_t) resource->size[5] << 40) +
					   ((uint64_t) resource->size[6] << 48);

		fwts_log_info_verbatim(fw, "  Resource Size:            0x%16.16" PRIx64, size);
		fwts_log_info_verbatim(fw, "  Resource Type:            0x%2.2" PRIx8, resource->type);
		fwts_log_info_verbatim(fw, "  Resource Address:         0x%16.16" PRIx64, resource->address);

		if (resource->type & 0x7C) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"DRTMBadResourceType",
				"DRTM Resource Type Bits [6:2] are reserved, got 0x%2.2" PRIx8
				" instead",	resource->type);
		}

		offset += sizeof(fwts_acpi_drtm_resource);
		fwts_log_nl(fw);
	}

	drtm_dps = (fwts_acpi_table_drtm_dps *) (table->data + offset);
	fwts_log_info_verbatim(fw, "  DPS_Length:               0x%8.8" PRIx32, drtm_dps->dps_id_length);

	if (drtm->header.length < offset + sizeof(fwts_acpi_table_drtm_dps)) {
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"DRTMOutOfBound",
			"DRTM's length is too small to contain all fields");
		goto error;
	}

	for (i = 0; i < sizeof(drtm_dps->dps_id); i++) {
		fwts_log_info_verbatim(fw, "  DLME Platform Id:         0x%2.2" PRIx8, drtm_dps->dps_id[i]);
	}

	fwts_log_nl(fw);

	if (passed)
		fwts_passed(fw, "No issues found in DRTM table.");

 error:
	return FWTS_OK;
}
Пример #9
0
static int spcr_test1(fwts_framework *fw)
{
	char *str;
	uint32_t reserved1;
	bool reserved = false;
	bool pci = true;
	bool passed = true;

	/*
	 * Assuming revision 2, full list from
	 * http://go.microsoft.com/fwlink/p/?LinkId=234837)
	 */
	switch (spcr->interface_type) {
	case 0x00:
		str = "16550 compatible";
		break;
	case 0x01:
		str = "16450 compatible";
		break;
	case 0x03:
		str = "ARM PL011 UART";
		break;
	case 0x02:
	case 0x04 ... 0x0c:
		str = "Reserved (Do not Use)";
		reserved = true;
		break;
	case 0x0d:
		str = "(deprecated) ARM SBSA";
		break;
	case 0x0e:
		str = "ARM SBSA Generic UART";
		break;
	case 0x0f:
		str = "ARM DCC";
		break;
	case 0x10:
		str = "BCM2835";
		break;
	default:
		str = "Reserved";
		reserved = true;
		break;
	}

	fwts_log_info_verbatim(fw, "Serial Interface: %s", str);
	if (reserved) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SPCRInterfaceReserved",
			"SPCR Serial interface type 0x%2.2" PRIx8
			" is a reserved interface", spcr->interface_type);
	}

	reserved1 = spcr->reserved1[0] + (spcr->reserved1[1] << 8) + (spcr->reserved1[2] << 16);
	fwts_acpi_reserved_zero_check(fw, "SPCR", "Reserved1", reserved1, sizeof(reserved1), &passed);

	if (spcr->interrupt_type == 0) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SPCRUnknownInterruptType",
			"SPCR interrupt type field is zero, expecting support bits to be set");
	}
	if (spcr->interrupt_type & 0xf0) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SPCRIllegalReservedInterruptType",
			"SPCR interrupt type reserved bits are non-zero zero, got 0x%" PRIx8,
				spcr->interrupt_type);
	}

	/* Check PC-AT compatible UART IRQs */
	if (spcr->interrupt_type & 1) {
		switch (spcr->irq) {
		case  2 ...  7:
		case  9 ... 12:
		case 14 ... 15:
			break;
		default:
			passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"SPCRIllegalIRQ",
				"SPCR PC-AT compatible IRQ 0x%" PRIx8 " is invalid", spcr->irq);
			break;
		}
	}

	reserved = false;
	switch (spcr->baud_rate) {
	case 0x03:
		str = "9600";
		break;
	case 0x04:
		str = "19200";
		break;
	case 0x06:
		str = "57600";
		break;
	case 0x07:
		str = "115200";
		break;
	default:
		str = "Reserved";
		reserved = true;
	}
	fwts_log_info_verbatim(fw, "Baud Rate:        %s", str);
	if (reserved) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SPCRBaudRateReserved",
			"SPCR Serial baud rate type 0x%2.2" PRIx8
			" is a reserved baud rate", spcr->baud_rate);
	}

	if (spcr->parity != 0) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SPCRReservedValueUsed",
			"SPCR Parity field must be zero, got 0x%2.2" PRIx8 " instead",
			spcr->parity);
	}

	if (spcr->stop_bits != 1) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SPCRReservedValueUsed",
			"SPCR Stop field must be 1, got 0x%2.2" PRIx8 " instead",
			spcr->stop_bits);
	}

	fwts_acpi_reserved_bits_check(fw, "SPCR", "Flow control", spcr->flow_control, sizeof(spcr->flow_control), 3, 7, &passed);

	reserved = false;
	switch (spcr->terminal_type) {
	case 0x00:
		str = "VT100";
		break;
	case 0x01:
		str = "VT100+";
		break;
	case 0x02:
		str = "VT-UTF8";
		break;
	case 0x03:
		str = "ANSI";
		break;
	default:
		str = "Reserved";
		reserved = true;
	}
	fwts_log_info_verbatim(fw, "Terminal Type:    %s", str);
	if (reserved) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"SPCRTerminalTypeReserved",
			"SPCR terminal type type 0x%2.2" PRIx8
			" is a reserved terminal type", spcr->terminal_type);
	}

	fwts_acpi_reserved_zero_check(fw, "SPCR", "Reserved2", spcr->reserved2, sizeof(spcr->reserved2), &passed);

	/* According to the spec, these values indicate NOT a PCI device */
	if ((spcr->pci_device_id == 0xffff) &&
	    (spcr->pci_vendor_id == 0xffff) &&
	    (spcr->pci_bus_number == 0) &&
	    (spcr->pci_device_number == 0) &&
	    (spcr->pci_function_number == 0))
		pci = false;

	/* Now validate all pci specific fields if not-PCI enabled */
	if (pci) {
		if (spcr->pci_device_id == 0xffff) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"SPCRPciDeviceID",
				"SPCR PCI device ID is 0x%4.4" PRIx16
				", expecting non-0xffff for PCI device",
				spcr->pci_device_id);
		}
		if (spcr->pci_vendor_id == 0xffff) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"SPCRPciVendorID",
				"SPCR PCI vendor ID is 0x%4.4" PRIx16
				", expecting non-0xffff for non-PCI device",
				spcr->pci_vendor_id);
		}
		if ((spcr->pci_flags & 1) == 0) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"SPCRPciFlagsBit0",
				"SPCR PCI flags compatibility bit 0 is %" PRIx32
				", expecting 1 for PCI device",
				spcr->pci_flags & 1);
		}
	}

	fwts_acpi_reserved_bits_check(fw, "SPCR", "PCI Flags", spcr->pci_flags, sizeof(spcr->pci_flags), 1, 31, &passed);
	fwts_acpi_reserved_zero_check(fw, "SPCR", "Reserved3", spcr->reserved3, sizeof(spcr->reserved3), &passed);

	if (passed)
		fwts_passed(fw, "No issues found in SPCR table.");

	return FWTS_OK;
}
Пример #10
0
/*
 *  ACPI Section 18.3.2.8 Generic Error Source version 2
 */
static void hest_check_generic_error_source_v2(
	fwts_framework *fw,
	ssize_t *length,
	uint8_t **data,
	bool *passed)
{
	fwts_acpi_table_hest_generic_hardware_error_source_v2 *source =
		(fwts_acpi_table_hest_generic_hardware_error_source_v2 *)*data;

	/* Enough data for an empty machine check exceptions structure? */
	if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_generic_hardware_error_source_v2)) {
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"HESTGenericHardwareErrorSourceTooShort",
			"HEST Generic Hardware Error Source Too Short "
			"too short, expecting %zu bytes, "
			"instead got %zu bytes",
			sizeof(fwts_acpi_table_hest_generic_hardware_error_source_v2), *length);
		*passed = false;
		*length = 0;	/* Forces an early abort */
		return;
	}

	fwts_log_info_verbatim(fw, "HEST Generic Hardware Error Source version 2");
	fwts_log_info_verbatim(fw, "  Type:                     0x%2.2" PRIx8, source->type);
	fwts_log_info_verbatim(fw, "  Source ID:                0x%4.4" PRIx16, source->source_id);
	fwts_log_info_verbatim(fw, "  Related Source ID:        0x%4.4" PRIx16, source->related_source_id);
	fwts_log_info_verbatim(fw, "  Flags:                    0x%2.2" PRIx8, source->flags);
	fwts_log_info_verbatim(fw, "  Enabled:                  0x%2.2" PRIx8, source->enabled);
	fwts_log_info_verbatim(fw, "  Num. Records. Prealloc.:  0x%8.8" PRIx32, source->number_of_records_to_preallocate);
	fwts_log_info_verbatim(fw, "  Max. Sections Per Rec.:   0x%8.8" PRIx32, source->max_sections_per_record);
	fwts_log_info_verbatim(fw, "  Max. Raw Data Length:     0x%8.8" PRIx32, source->max_raw_data_length);

        fwts_log_info_verbatim(fw, "  Error Status Address:");
        fwts_log_info_verbatim(fw, "    Address Space ID:       0x%2.2" PRIx8,
		source->error_status_address.address_space_id);
        fwts_log_info_verbatim(fw, "    Register Bit Width      0x%2.2" PRIx8,
		source->error_status_address.register_bit_width);
        fwts_log_info_verbatim(fw, "    Register Bit Offset     0x%2.2" PRIx8,
		source->error_status_address.register_bit_offset);
        fwts_log_info_verbatim(fw, "    Access Size             0x%2.2" PRIx8,
		source->error_status_address.access_width);
        fwts_log_info_verbatim(fw, "    Address                 0x%16.16" PRIx64,
			source->error_status_address.address);
        fwts_log_info_verbatim(fw, "  Hardware Error Notification:");
        fwts_log_info_verbatim(fw, "    Type:                   0x%2.2" PRIx8, source->notification.type);
        fwts_log_info_verbatim(fw, "    Length:                 0x%2.2" PRIx8, source->notification.length);
        fwts_log_info_verbatim(fw, "    Config. Write. Enable:  0x%4.4" PRIx16,
		source->notification.configuration_write_enable);
        fwts_log_info_verbatim(fw, "    Poll Interval:          0x%4.4" PRIx16,
		source->notification.poll_interval);
        fwts_log_info_verbatim(fw, "    Interrupt Vector:       0x%4.4" PRIx16,
		source->notification.vector);
        fwts_log_info_verbatim(fw, "    Sw. to Polling Value:   0x%4.4" PRIx16,
		source->notification.switch_to_polling_threshold_value);
        fwts_log_info_verbatim(fw, "    Sw. to Polling Window:  0x%4.4" PRIx16,
		source->notification.switch_to_polling_threshold_window);
        fwts_log_info_verbatim(fw, "    Error: Thresh. Value:   0x%4.4" PRIx16,
		source->notification.error_threshold_value);
        fwts_log_info_verbatim(fw, "    Error: Thresh. Window:  0x%4.4" PRIx16,
		source->notification.error_threshold_window);
	fwts_log_info_verbatim(fw, "  Error Status Blk. Length: 0x%8.8" PRIx32, source->error_status_block_length);
        fwts_log_info_verbatim(fw, "  Read Ack Register:");
        fwts_log_info_verbatim(fw, "    Address Space ID:       0x%2.2" PRIx8,
		source->read_ack_register.address_space_id);
        fwts_log_info_verbatim(fw, "    Register Bit Width      0x%2.2" PRIx8,
		source->read_ack_register.register_bit_width);
        fwts_log_info_verbatim(fw, "    Register Bit Offset     0x%2.2" PRIx8,
		source->read_ack_register.register_bit_offset);
        fwts_log_info_verbatim(fw, "    Access Size             0x%2.2" PRIx8,
		source->read_ack_register.access_width);
        fwts_log_info_verbatim(fw, "    Address                 0x%16.16" PRIx64,
			source->read_ack_register.address);
	fwts_log_info_verbatim(fw, "  Read Ack Preserve:        0x%16.16" PRIx64, source->read_ack_preserve);
	fwts_log_info_verbatim(fw, "  Read Ack Write:           0x%16.16" PRIx64, source->read_ack_write);
	fwts_log_nl(fw);

	if (source->number_of_records_to_preallocate < 1) {
		*passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"HESTInvalidRecordsToPreallocate",
			"HEST Hardware Error Source Number of Records "
			"to Preallocate is 0x%" PRIx16 " and must be "
			"more than zero.",
			source->number_of_records_to_preallocate);
	}
	if (source->max_sections_per_record < 1) {
		*passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"HESTInvalidMaxSectionsPerRecord",
			"HEST Hardware Error Source Max Sections Per "
			"Record is 0x%" PRIx16 " and must be "
			"more than zero.",
			source->max_sections_per_record);
	}
	if (source->notification.type > 11) {
		*passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"HESTInvalidHardwareErrorNotificationType",
			"HEST Hardware Error Notification Type is "
			"an invalid reserved value of %2.2" PRIu8 ","
			"expecting value 0 to 11",
			source->notification.type);
	}

	fwts_acpi_reserved_bits_check(fw, "HEST", "HEST Configuration Write Enabled",
		source->notification.configuration_write_enable,
		sizeof(source->notification.configuration_write_enable), 6, 31, passed);

	*length -= sizeof(fwts_acpi_table_hest_generic_hardware_error_source_v2);
	*data += sizeof(fwts_acpi_table_hest_generic_hardware_error_source_v2);
}
Пример #11
0
/*
 *  ACPI Section 18.3.2.5 PCI Express/PCI-X Bridge AER Structure
 */
static void hest_heck_pci_express_bridge_aer(
	fwts_framework *fw,
	ssize_t *length,
	uint8_t **data,
	bool *passed)
{
	fwts_acpi_table_hest_pci_express_bridge_aer *aer =
		(fwts_acpi_table_hest_pci_express_bridge_aer *)*data;

	if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_pci_express_bridge_aer)) {
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"HESTPciExpressBridgeAerTooShort",
			"HEST PCI Express Bridge AER "
			"too short, expecting %zu bytes, "
			"instead got %zu bytes",
			sizeof(fwts_acpi_table_hest_pci_express_bridge_aer), *length);
		*passed = false;
		*length = 0;	/* Forces an early abort */
		return;
	}

	fwts_log_info_verbatim(fw, "HEST PCI Express Bridge AER:");
	fwts_log_info_verbatim(fw, "  Type:                     0x%2.2" PRIx8, aer->type);
	fwts_log_info_verbatim(fw, "  Source ID:                0x%4.4" PRIx16, aer->source_id);
	fwts_log_info_verbatim(fw, "  Reserved:                 0x%4.4" PRIx16, aer->reserved1);
	fwts_log_info_verbatim(fw, "  Flags:                    0x%2.2" PRIx8, aer->flags);
	fwts_log_info_verbatim(fw, "  Enabled:                  0x%2.2" PRIx8, aer->enabled);
	fwts_log_info_verbatim(fw, "  Number of Records:        0x%8.8" PRIx32, aer->number_of_records_to_preallocate);
	fwts_log_info_verbatim(fw, "  Max Sections Per Record:  0x%8.8" PRIx32, aer->max_sections_per_record);
	fwts_log_info_verbatim(fw, "  Bus:                      0x%8.8" PRIx32, aer->bus);
	fwts_log_info_verbatim(fw, "  Device:                   0x%4.4" PRIx16, aer->device);
	fwts_log_info_verbatim(fw, "  Function:                 0x%4.4" PRIx16, aer->function);
	fwts_log_info_verbatim(fw, "  Device Control:           0x%4.4" PRIx16, aer->device_control);
	fwts_log_info_verbatim(fw, "  Reserved:                 0x%4.4" PRIx16, aer->reserved2);
	fwts_log_info_verbatim(fw, "  Uncorrectable Mask:       0x%8.8" PRIx32, aer->uncorrectable_error_mask);
	fwts_log_info_verbatim(fw, "  Uncorrectable Severity:   0x%8.8" PRIx32, aer->uncorrectable_error_severity);
	fwts_log_info_verbatim(fw, "  Correctable Mask:         0x%8.8" PRIx32, aer->correctable_error_mask);
	fwts_log_info_verbatim(fw, "  Advanced Capabilities:    0x%8.8" PRIx32, aer->advanced_error_capabilities_and_control);
	fwts_log_info_verbatim(fw, "  2nd Uncorrectable Mask:   0x%8.8" PRIx32, aer->secondary_uncorrectable_error_mask);
	fwts_log_info_verbatim(fw, "  2nd Uncurrectable Svrity: 0x%8.8" PRIx32, aer->secondary_uncorrectable_error_severity);
	fwts_log_info_verbatim(fw, "  2nd Advanced Capabilities:0x%8.8" PRIx32, aer->secondary_advanced_error_capabilities_and_control);
	fwts_log_nl(fw);

	fwts_acpi_reserved_zero_check(fw, "HEST", "PCI Express Bridge Reserved1", aer->reserved1, sizeof(aer->reserved1), passed);
	fwts_acpi_reserved_bits_check(fw, "HEST", "PCI Express Bridge Flags", aer->flags, sizeof(aer->flags), 2, 7, passed);
	fwts_acpi_reserved_zero_check(fw, "HEST", "PCI Express Bridge Reserved2", aer->reserved2, sizeof(aer->reserved2), passed);

	if (aer->number_of_records_to_preallocate < 1) {
		*passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"HESTInvalidRecordsToPreallocate",
			"HEST PCI Express Bridge Number of Records "
			"to Preallocate is 0x%" PRIx16 " and must be "
			"more than zero.",
			aer->number_of_records_to_preallocate);
	}
	if (aer->max_sections_per_record < 1) {
		*passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"HESTInvalidMaxSectionsPerRecord",
			"HEST PCI Express Brdige Max Sections Per "
			"Record is 0x%" PRIx16 " and must be "
			"more than zero.",
			aer->max_sections_per_record);
	}
	*length -= sizeof(fwts_acpi_table_hest_pci_express_bridge_aer);
	*data += sizeof(fwts_acpi_table_hest_pci_express_bridge_aer);
}
Пример #12
0
/*
 * ACPI WDAT (Watchdog Action Table)
 *  https://msdn.microsoft.com/en-us/windows/hardware/gg463320.aspx
 */
static int wdat_test1(fwts_framework *fw)
{
	const fwts_acpi_table_wdat *wdat =
		(const fwts_acpi_table_wdat *)table->data;
	bool passed = true;
	bool entries_passed = true;
	size_t total_length;
	uint32_t i;

	if (wdat->header.length > (uint32_t)table->length) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_MEDIUM,
			"WDATBadLength",
			"WDAT header reports that the table is %" PRIu32
			" bytes long, however this is longer than the ACPI "
			"table size of %zu bytes.",
			wdat->header.length,
			table->length);
		goto done;
	}

	/* Now we have got some sane data, dump the WDAT */
#if ACPI_DUMP
	fwts_log_info_verbatim(fw, "WDAT Microsoft Watchdog Action Table:");
	fwts_log_info_verbatim(fw, "  Watchdog Header Length:   0x%8.8" PRIx32, wdat->watchdog_header_length);
	fwts_log_info_verbatim(fw, "  PCI Segment:              0x%4.4" PRIx16, wdat->pci_segment);
	fwts_log_info_verbatim(fw, "  PCI Bus Number:           0x%2.2" PRIx8, wdat->pci_bus_number);
	fwts_log_info_verbatim(fw, "  PCI Device Number:        0x%2.2" PRIx8, wdat->pci_device_number);
	fwts_log_info_verbatim(fw, "  PCI Function Number:      0x%2.2" PRIx8, wdat->pci_function_number);
	fwts_log_info_verbatim(fw, "  Reserved:                 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8,
		wdat->reserved1[0], wdat->reserved1[1], wdat->reserved1[2]);
	fwts_log_info_verbatim(fw, "  Timer Period:             0x%4.4" PRIx32, wdat->timer_period);
	fwts_log_info_verbatim(fw, "  Maximum Count:            0x%4.4" PRIx32, wdat->maximum_count);
	fwts_log_info_verbatim(fw, "  Minimum Count:            0x%4.4" PRIx32, wdat->minimum_count);
	fwts_log_info_verbatim(fw, "  Watchdog Flags:           0x%4.4" PRIx32, wdat->watchdog_flags);
	fwts_log_info_verbatim(fw, "  Reserved:                 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8,
		wdat->reserved2[0], wdat->reserved2[1], wdat->reserved2[2]);
	fwts_log_info_verbatim(fw, "  Watchdog Entries          0x%4.4" PRIx32, wdat->number_of_entries);
#endif

	if (wdat->reserved1[0] | wdat->reserved1[1] | wdat->reserved1[2] |
	    wdat->reserved2[0] | wdat->reserved2[1] | wdat->reserved2[2]) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_MEDIUM,
			"WDATReservedFieldsNonZero",
			"WDAT Reserved Fields contain a non-zero value, these "
			"all should be zero.");
	}

	if (wdat->minimum_count > wdat->maximum_count) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_MEDIUM,
			"WDATMinGreaterThanMax",
			"WDAT Minimum Count is 0x%" PRIx32 " and is greater "
			"than the Maximum Count of 0x%" PRIx32,
			wdat->minimum_count, wdat->maximum_count);
	}

	/*
	 * Check if bits 6..1 are set, just bits 0 and 7 are used
	 * so check if the undefined bits are set. The specification
	 * does not state what these bits should be set as, but
	 * this does sanity check that somebody has not set these
	 * bits accidentally.  This is a LOW issue.
	 */
	fwts_acpi_reserved_bits_check(fw, "WDAT", "Watchdog Flags", wdat->watchdog_flags, sizeof(wdat->watchdog_flags), 1, 6, &passed);

	total_length = sizeof(fwts_acpi_table_wdat) +
		(wdat->number_of_entries * sizeof(fwts_acpi_table_wdat_instr_entries));
	if (total_length > wdat->header.length) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"WDATBadLength",
			"WDAT header reports that the table has %" PRIu32
			" watchdog instruction entries making the table "
			"%zu bytes long, however, the WDAT table is only %" PRIu32
			" bytes in size.",
			wdat->number_of_entries, total_length,
			wdat->header.length);
		goto done;
	}
	for (i = 0; i < wdat->number_of_entries; i++) {
		const fwts_acpi_table_wdat_instr_entries *entry = &wdat->entries[i];
#if ACPI_DUMP
		fwts_log_info_verbatim(fw, "Watchdog Instruction Entry %" PRIu32, i + 1);
		fwts_log_info_verbatim(fw, "  Watchdog Action:          0x%2.2" PRIx8, entry->watchdog_action);
		fwts_log_info_verbatim(fw, "  Instruction Flags:        0x%2.2" PRIx8, entry->instruction_flags);
		fwts_log_info_verbatim(fw, "  Reserved:                 0x%2.2" PRIx8 " 0x%2.2" PRIx8,
			entry->reserved[0], entry->reserved[1]);

		fwts_log_info_verbatim(fw, "    Address Space ID:       0x%2.2" PRIx8, entry->register_region.address_space_id);
		fwts_log_info_verbatim(fw, "    Register Bit Width      0x%2.2" PRIx8, entry->register_region.register_bit_width);
		fwts_log_info_verbatim(fw, "    Register Bit Offset     0x%2.2" PRIx8, entry->register_region.register_bit_offset);
		fwts_log_info_verbatim(fw, "    Access Size             0x%2.2" PRIx8, entry->register_region.access_width);
		fwts_log_info_verbatim(fw, "    Address                 0x%16.16" PRIx64, entry->register_region.address);
		fwts_log_info_verbatim(fw, "  Value:                    0x%8.8" PRIx32, entry->value);
		fwts_log_info_verbatim(fw, "  Mask:                     0x%8.8" PRIx32, entry->mask);
#endif

		switch (entry->watchdog_action) {
		case 0x01:	/* RESET */
		case 0x04:	/* QUERY_CURRENT_COUNTDOWN_PERIOD */
		case 0x05:	/* QUERY_COUNTDOWN_PERIOD */
		case 0x06:	/* SET_COUNTDOWN_PERIOD */
		case 0x08:	/* QUERY_RUNNING_STATE */
		case 0x09:	/* SET_RUNNING_STATE */
		case 0x0a:	/* QUERY_STOPPED_STATE */
		case 0x0b:	/* SET_STOPPED_STATE */
		case 0x10:	/* QUERY_REBOOT */
		case 0x11:	/* SET_REBOOT */
		case 0x12:	/* QUERY_SHUTDOWN */
		case 0x13:	/* SET_SHUTDOWN */
		case 0x20:	/* QUERY_WATCHDOG_STATUS */
		case 0x21:	/* SET_WATCHDOG_STATUS */
			break;
		default:
			entries_passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"WDATWatchdogActionInvalid",
				"WDAT Watchdog Instruction Entry %" PRIu32
				" Watchdog Action field is 0x%" PRIx8
				" and should be one of 0x00, 0x04, 0x05, 0x06, "
				"0x08, 0x09, 0x0a, 0x0b, 0x10, 0x11, 0x12, 0x13, "
				"0x20 or 0x21",
				i + 1, entry->watchdog_action);
			break;
		}
		/*
		 * Instruction flags can be 0x00, 0x01, 0x02, 0x03 with
		 * bit 7 clear or set, so bits 7, 1, 0 are valid, (which
		 * is 0x80 | 0x02 | 0x01)
		 */
		if (entry->instruction_flags & ~0x83) {
			entries_passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"WDATInstructionFlagsInvalid",
				"WDAT Watchdog Instruction Entry %" PRIu32
				" Instruction Flags field is 0x%" PRIx8
				" and should be one of 0x00, 0x01, 0x02, 0x03 or "
				" 0x80, 0x81, 0x82, 0x83",
				i + 1, entry->instruction_flags);
		}
	}
	if (entries_passed)
		fwts_passed(fw, "All %" PRIu32 " WDAT Watchdog Instruction Entries look sane.",
			wdat->number_of_entries);

done:
	passed &= entries_passed;
	if (passed)
		fwts_passed(fw, "No issues found in WDAT table.");

	return FWTS_OK;
}
Пример #13
0
/*
 *  MCHI Management Controller Host Interface Table
 *    http://www.dmtf.org/sites/default/files/standards/documents/DSP0256_1.0.0.pdf
 */
static int mchi_test1(fwts_framework *fw)
{
	bool passed = true;
	fwts_acpi_table_mchi *mchi = (fwts_acpi_table_mchi *)table->data;

	if (!fwts_acpi_table_length_check(fw, "MCHI", table->length, sizeof(fwts_acpi_table_mchi))) {
		passed = false;
		goto done;
	}

#if DUMP_MCHI_TABLE
	fwts_log_info_verbatim(fw, "MCHI Table:");
	fwts_log_info_verbatim(fw, "  Interface Type:           0x%2.2" PRIx8, mchi->interface_type);
	fwts_log_info_verbatim(fw, "  Protocol Identifier       0x%2.2" PRIx8, mchi->protocol_identifier);
	fwts_log_info_verbatim(fw, "  Protocol Data:            "
		"0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8,
			mchi->protocol_data[0], mchi->protocol_data[1],
			mchi->protocol_data[2], mchi->protocol_data[3]);
	fwts_log_info_verbatim(fw, "                            "
		"0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8,
			mchi->protocol_data[4], mchi->protocol_data[5],
			mchi->protocol_data[6], mchi->protocol_data[7]);
	fwts_log_info_verbatim(fw, "  Interrupt Type:           0x%2.2" PRIx8, mchi->interrupt_type);
	fwts_log_info_verbatim(fw, "  GPE:                      0x%2.2" PRIx8, mchi->gpe);
	fwts_log_info_verbatim(fw, "  PCI Device Flag:          0x%2.2" PRIx8, mchi->pci_device_flag);
	fwts_log_info_verbatim(fw, "  Global System Interrupt:  0x%8.8" PRIx32, mchi->global_system_interrupt);
	fwts_log_info_verbatim(fw, "  Base Address:");
	fwts_log_info_verbatim(fw, "    Address Space ID:       0x%2.2" PRIx8, mchi->base_address.address_space_id);
	fwts_log_info_verbatim(fw, "    Register Bit Width      0x%2.2" PRIx8, mchi->base_address.register_bit_width);
	fwts_log_info_verbatim(fw, "    Register Bit Offset     0x%2.2" PRIx8, mchi->base_address.register_bit_offset);
	fwts_log_info_verbatim(fw, "    Access Size             0x%2.2" PRIx8, mchi->base_address.access_width);
	fwts_log_info_verbatim(fw, "    Address                 0x%16.16" PRIx64, mchi->base_address.address);
	if ((mchi->pci_device_flag & 1) == 1) {
		fwts_log_info_verbatim(fw, "  PCI Segment Group:       0x%2.2" PRIx8, mchi->bytes[0]);
		fwts_log_info_verbatim(fw, "  PCI Bus Number:          0x%2.2" PRIx8, mchi->bytes[1]);
		fwts_log_info_verbatim(fw, "  PCI Device Number:       0x%2.2" PRIx8, mchi->bytes[2]);
		fwts_log_info_verbatim(fw, "  PCI Function Number:     0x%2.2" PRIx8, mchi->bytes[3]);
	} else {
		/* Zero -> UIDS */
		fwts_log_info_verbatim(fw, "  UID Bytes 1-4:            "
			"0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8,
			mchi->bytes[0], mchi->bytes[1], mchi->bytes[2], mchi->bytes[3]);
	}
	fwts_log_nl(fw);
#endif
	if ((mchi->interface_type < 2) ||
	    (mchi->interface_type > 8)) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"MCHIInvalidInterfaceType",
			"MCHI Interface Type is 0x%2.2" PRIx8 " which is reserved, "
			"allowed values are 0x02..0x08", mchi->interface_type);
	}
	if ((mchi->protocol_identifier > 2) &&
	    (mchi->protocol_identifier < 255)) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"MCHIInvalidProtocolIdentifier",
			"MCHI Protocol Identifier 0x%2.2" PRIx8 " which is reserved, "
			"allowed values are 0x00 (Unspecifier), 0x01 (MCTP), 0x02 (IPMI) or "
			"255 (OEM defined)", mchi->protocol_identifier);
	}

	fwts_acpi_reserved_bits_check(fw, "MCHI", "Interrupt Type", mchi->interrupt_type, sizeof(mchi->interrupt_type), 2, 7, &passed);

	if (((mchi->interrupt_type & 0x01) == 0) &&
	    (mchi->gpe != 0)) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"MCHIGpeNonZero",
			"MCHI GPE is 0x%2.2" PRIx8 " and should be zero "
			"when bit 0 of the Interrupt Type field is 0 "
			"(SCI triggered through GPE non-supported)",
			mchi->gpe);
	}

	fwts_acpi_reserved_bits_check(fw, "MCHI", "PCI Device Flag", mchi->pci_device_flag, sizeof(mchi->pci_device_flag), 1, 7, &passed);

	if (((mchi->interrupt_type & 0x02) == 0) &&
	    (mchi->global_system_interrupt != 0)) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"MCHIGsiNonZero",
			"MCHI Global System Interrupt is 0x%2.2" PRIx8 " and should be zero "
			"when bit 1 of the Interrupt Type field is 0",
			mchi->global_system_interrupt);
	}

	if ((mchi->base_address.address_space_id != 0x00) &&
	    (mchi->base_address.address_space_id != 0x01) &&
	    (mchi->base_address.address_space_id != 0x04)) {
		passed = false;
		fwts_failed(fw, LOG_LEVEL_HIGH,
			"MCHIAddrSpaceIdInvalid",
			"MCHI Address Space ID is 0x%2.2" PRIx8 " and should be "
			"0x00 (System Memory), 0x01 (System I/O) or 0x04 (SMBus)",
			mchi->base_address.address_space_id);
	}

	/* SMBus specific checks */
	if (mchi->base_address.address_space_id == 0x04) {
		if ((mchi->pci_device_flag & 0x01) == 1) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_HIGH,
				"MCHIPciDeviceFlagInvalid",
				"MCHI PCI Device Flag is 0x%2.2" PRIx8
				" and bit [0] should be 0 for a SMBus Address Space ID",
				mchi->pci_device_flag);
		}
		if (mchi->base_address.register_bit_width != 0) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"MCHISmbusRegBitWidthNonZero",
				"MCHI Base Address Register Bit Width is 0x%2.2" PRIx8
				" and should be zero for a SMBus Address Space ID",
				mchi->base_address.register_bit_width);
		}
		if (mchi->base_address.register_bit_offset != 0) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"MCHISmbusRegBitOffsetNonZero",
				"MCHI Base Address Register Bit Offset is 0x%2.2" PRIx8
				" and should be zero for a SMBus Address Space ID",
				mchi->base_address.register_bit_offset);
		}
		if (mchi->base_address.access_width != 1) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"MCHISmbusRegAddressSizeInvalid",
				"MCHI Base Address Register Address Size is 0x%2.2" PRIx8
				" and should be 1 (byte access) for a SMBus Address Space ID",
				mchi->base_address.access_width);
		}
		if (mchi->base_address.address & ~(0x7fULL)) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"MCHISmbusAddressInvalid",
				"MCHI Base Address is 0x%16.16" PRIx64
				" and should be 0x00..0x7f a SMBus Address Space ID",
				mchi->base_address.address);
		}
	}
	/* PCI Device field specific checks */
	if (mchi->pci_device_flag & 0x01) {
		if (mchi->bytes[2] & ~0x1f) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"MCHIPciDeviceNumberInvalid",
				"MCHI PCI Device Number is 0x%2.2" PRIx8
				" and reserved bits [7:5] should be zero",
				mchi->bytes[2]);
		}
		if (mchi->bytes[3] & ~0x47) {
			passed = false;
			fwts_failed(fw, LOG_LEVEL_MEDIUM,
				"MCHIPciFunctionNumberInvalid",
				"MCHI PCI Function Number is 0x%2.2" PRIx8
				" and reserved bits [7] and [5:3] should be zero",
				mchi->bytes[3]);
		}
	}

done:
	if (passed)
		fwts_passed(fw, "No issues found in MCHI table.");

	return FWTS_OK;
}