/* * 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; }
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); }
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.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."); }
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); }
/* * 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; }
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; }
/* * 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; }
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; }
/* * 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); }
/* * 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); }
/* * 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; }
/* * 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; }