static int uefirttime_test_setwakeuptime_invalid( fwts_framework *fw, struct efi_setwakeuptime *setwakeuptime ) { long ioret; uint64_t status; setwakeuptime->status = &status; ioret = ioctl(fd, EFI_RUNTIME_SET_WAKETIME, setwakeuptime); if (ioret == -1) { if (status == EFI_UNSUPPORTED) { fwts_skipped(fw, "Skipping test, GetWakeupTime runtime " "service is not supported on this platform."); return FWTS_OK; } if (status == EFI_INVALID_PARAMETER) { fwts_passed(fw, "UEFI runtime service SetTimeWakeupTime interface test " "passed, returned EFI_INVALID_PARAMETER as expected."); return FWTS_OK; } else { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetWakeupTime", "Failed to get correct return status from UEFI runtime service, " "expecting EFI_INVALID_PARAMETER."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetWakeupTime", "Failed to get error return status from UEFI runtime service, expected EFI_INVALID_PARAMETER."); return FWTS_ERROR; }
static int uefirttime_test_settime_invalid( fwts_framework *fw, struct efi_settime *settime) { long ioret; uint64_t status; settime->status = &status; ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, settime); if (ioret == -1) { if (status == EFI_INVALID_PARAMETER) { fwts_passed(fw, "UEFI runtime service SetTime interface test " "passed, returned EFI_INVALID_PARAMETER as expected."); return FWTS_OK; } else { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", "Failed to get correct return status from UEFI runtime service, expecting EFI_INVALID_PARAMETER."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", "Failed to get error return status from UEFI runtime service, expected EFI_INVALID_PARAMETER."); return FWTS_ERROR; }
static int uefirttime_test_getwaketime_invalid( fwts_framework *fw, struct efi_getwakeuptime *getwakeuptime) { long ioret; uint64_t status; getwakeuptime->status = &status; ioret = ioctl(fd, EFI_RUNTIME_GET_WAKETIME, getwakeuptime); if (ioret == -1) { if (status == EFI_INVALID_PARAMETER || status == EFI_UNSUPPORTED) { fwts_passed(fw, "UEFI runtime service GetTimeWakeupTime interface test " "passed, returned EFI_INVALID_PARAMETER or " "EFI_UNSUPPORTED as expected."); return FWTS_OK; } else { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetWakeupTime", "Failed to get correct return status from UEFI " "runtime service, expecting EFI_INVALID_PARAMETER " "or EFI_UNSUPPORTED."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetWakeupTime", "Failed to get error return status from UEFI runtime service, expected EFI_INVALID_PARAMETER."); return FWTS_ERROR; }
/* * The authenticated variable is followed EFI_VARIABLE_AUTHENTICATION_2 descriptor, * set the authenticated variable with invalid * EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS instead of * EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute should * return EFI_SECURITY_VIOLATION. */ static int uefirtauthvar_test11(fwts_framework *fw) { long ioret; uint64_t status; uint32_t attr = FWTS_UEFI_VAR_NON_VOLATILE | FWTS_UEFI_VAR_BOOTSERVICE_ACCESS | FWTS_UEFI_VAR_RUNTIME_ACCESS | FWTS_UEFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; ioret = setvar(>estguid, attr, sizeof(AuthVarCreate), AuthVarCreate, &status); if (ioret == -1) { int supcheck = check_fw_support(fw, status); if (supcheck != FWTS_OK) return supcheck; if (status == EFI_SECURITY_VIOLATION) { fwts_passed(fw, "Set authenticated variable test with invalid attributes passed."); return FWTS_OK; } fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISetAuthVarInvalidAttr", "Set authenticated variable fail"); fwts_uefi_print_status_info(fw, status); } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFISetAuthVarInvalidAttr", "Set authenticated variable expected fail but success"); return FWTS_ERROR; }
static int uefirttime_test_gettime_invalid( fwts_framework *fw, EFI_TIME *efi_time, EFI_TIME_CAPABILITIES *efi_time_cap) { long ioret; struct efi_gettime gettime; uint64_t status; gettime.Capabilities = efi_time_cap; gettime.Time = efi_time; gettime.status = &status; ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); if (ioret == -1) { if (status == EFI_INVALID_PARAMETER) { fwts_passed(fw, "UEFI runtime service GetTime interface test " "passed, returned EFI_INVALID_PARAMETER as expected."); return FWTS_OK; } else { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", "Failed to get correct return status from UEFI runtime service, expecting EFI_INVALID_PARAMETER."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", "Failed to get error return status from UEFI runtime service, expected EFI_INAVLID_PARAMETER."); return FWTS_ERROR; }
/* * Set the authenticated variable with invalid modified timestamp, expect * EFI_SECURITY_VIOLATION returned. */ static int uefirtauthvar_test9(fwts_framework *fw) { long ioret; uint64_t status; ioret = setvar(>estguid, attributes, sizeof(AuthVarModTime), AuthVarModTime, &status); if (ioret == -1) { int supcheck = check_fw_support(fw, status); if (supcheck != FWTS_OK) return supcheck; if (status == EFI_SECURITY_VIOLATION) { fwts_passed(fw, "Set authenticated variable test with invalid modified timestamp passed."); return FWTS_OK; } fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISetAuthVarInvalidTime", "Set authenticated variable fail"); fwts_uefi_print_status_info(fw, status); } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFISetAuthVarInvalidTime", "Set authenticated variable expected fail but success"); return FWTS_ERROR; }
/* * Set the authenticated variable with different guid, expect * EFI_SECURITY_VIOLATION returned. */ static int uefirtauthvar_test10(fwts_framework *fw) { long ioret; uint64_t status; EFI_GUID gtestguiddiff = TEST_GUID1; ioret = setvar(>estguiddiff, attributes, sizeof(AuthVarCreate), AuthVarCreate, &status); if (ioret == -1) { int supcheck = check_fw_support(fw, status); if (supcheck != FWTS_OK) return supcheck; if (status == EFI_SECURITY_VIOLATION) { fwts_passed(fw, "Set authenticated variable test with different guid passed."); return FWTS_OK; } fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISetAuthVarDiffGuid", "Set authenticated variable fail"); fwts_uefi_print_status_info(fw, status); } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFISetAuthVarDiffGuid", "Set authenticated variable expected fail but success"); return FWTS_ERROR; }
/* * After updated, set the old data and timestamp authenticated variable, * AuthVarCreate, expect EFI_SECURITY_VIOLATION returned. */ static int uefirtauthvar_test6(fwts_framework *fw) { long ioret; uint64_t status; if (!(data_exist & E_AUTHVARUPDATE)) { fwts_skipped(fw,"The test variable, AuthVarUpdate, doesn't exist, skip the test."); return FWTS_SKIP; } ioret = setvar(>estguid, attributes, sizeof(AuthVarCreate), AuthVarCreate, &status); if (ioret == -1) { int supcheck = check_fw_support(fw, status); if (supcheck != FWTS_OK) return supcheck; if (status == EFI_SECURITY_VIOLATION) { fwts_passed(fw, "Authenticated variable test with old authenticated variable passed."); return FWTS_OK; } fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISetOldAuthVar", "Set authenticated variable fail"); fwts_uefi_print_status_info(fw, status); } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFISetOldAuthVar", "Set authenticated variable expected fail but success"); return FWTS_ERROR; }
static void memory_length(fwts_framework *fw, uint8_t type, uint64_t memory_range, uint64_t min_length, bool *passed) { switch (type) { case 0 ... 2: fwts_log_info_verbatim(fw, " Length: 0x%16.16" PRIx64, memory_range); if (memory_range <= min_length) { *passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "PCCTBadSubtypeMemoryLength", "PCCT Subspace Type %" PRId8 " must have memory length > 0x%16.16" PRIx64 ", got 0x%16.16" PRIx64 " instead", type, min_length, memory_range); } break; case 3 ... 4: fwts_log_info_verbatim(fw, " Length: 0x%8.8" PRIx32, (uint32_t)memory_range); if (memory_range <= min_length) { *passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "PCCTBadSubtypeMemoryLength", "PCCT Subspace Type %" PRId8 " must have memory length > 0x%8.8" PRIx32 ", got 0x%8.8" PRIx32 " instead", type, (uint32_t)min_length, (uint32_t)memory_range); } break; } }
/* * Set the created authenticated variable, AuthVarCreate, * and checking the data size and data. * expect EFI_SUCCESS returned. */ static int uefirtauthvar_test1(fwts_framework *fw) { long ioret; uint8_t data[getvar_buf_size]; uint64_t getdatasize = sizeof(data); uint64_t status; uint32_t attributestest; size_t i; ioret = setvar(>estguid, attributes, sizeof(AuthVarCreate), AuthVarCreate, &status); if (ioret == -1) { int supcheck = check_fw_support(fw, status); if (supcheck != FWTS_OK) return supcheck; fwts_failed(fw, LOG_LEVEL_HIGH, "UEFICreateAuthVar", "Failed to create authenticated variable with UEFI " "runtime service."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } ioret = getvar(>estguid, &attributestest, &getdatasize, data, &status); if (ioret == -1) { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFICreateAuthVar", "Failed to get authenticated variable with UEFI " "runtime service."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } if (getdatasize != sizeof(AuthVarCreateData)) { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFICreateAuthVar", "Get authenticated variable data size is not the " "same as it set."); return FWTS_ERROR; } for (i = 0; i < sizeof(AuthVarCreateData); i++) { if (data[i] != AuthVarCreateData[i]) { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFICreateAuthVar", "Get authenticated variable data are not the " "same as it set."); return FWTS_ERROR; } } data_exist |= E_AUTHVARCREATE; fwts_passed(fw, "Create authenticated variable test passed."); return FWTS_OK; }
static int apicedge_test1(fwts_framework *fw) { FILE *file; if ((file = fopen("/proc/interrupts", "r")) == NULL) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoProcInterrupts", "Could not open file /proc/interrupts."); return FWTS_ERROR; } while (!feof(file)) { char line[4096], *c; int edge = -1; int irq = 0; memset(line, 0, sizeof(line)); if (fgets(line, sizeof(line) - 1, file) == NULL) break; if (! (line[0] == ' ' || (line[0] >= '0' && line[0] <= '9')) ) continue; irq = strtoul(line, &c, 10); if (c == line) continue; if (strstr(line, "IO-APIC-edge")) edge = 1; if (strstr(line, "IO-APIC-fasteoi")) edge = 0; if (strstr(line, "PCI-MSI-level")) edge = 0; if (strstr(line, "PCI-MSI-edge")) edge = 1; if (strstr(line, "IO-APIC-level")) edge = 0; if (strstr(line,"acpi")) { if (edge == 1) fwts_failed(fw, LOG_LEVEL_MEDIUM, "ACPIIRQEdgeTrig", "ACPI Interrupt is incorrectly edge triggered."); continue; } if ((irq < 15) && (edge == 0)) fwts_failed(fw, LOG_LEVEL_MEDIUM, "LegacyIRQLevelTrig", "Legacy interrupt %i is incorrectly level triggered.", irq); if ((irq < 15) && (edge == -1)) fwts_failed(fw, LOG_LEVEL_MEDIUM, "NonLegacyIRQLevelTrig", "Non-Legacy interrupt %i is incorrectly level triggered.", irq); } fclose(file); if (fwts_tests_passed(fw)) fwts_passed(fw, "Legacy interrupts are edge and PCI interrupts are level triggered."); return FWTS_OK; }
static int power_mgmt_init(fwts_framework *fw) { int ret; if (fwts_firmware_detect() != FWTS_FIRMWARE_OPAL) { fwts_skipped(fw, "The firmware type detected was non OPAL " "so skipping the OPAL Power Management DT checks."); return FWTS_SKIP; } if (!fw->fdt) { fwts_failed(fw, LOG_LEVEL_HIGH, "NoDeviceTree", "Device tree not found"); return FWTS_ERROR; } ret = get_proc_gen(fw); if (ret != FWTS_OK) { fwts_failed(fw, LOG_LEVEL_HIGH, "ProcGenFail", "Failed to get the Processor generation"); return FWTS_ERROR; } return FWTS_OK; }
static int prd_dev_query(fwts_framework *fw) { int fd = 0; struct opal_prd_info info; if ((fd = open(prd_devnode, O_RDWR)) < 0) { fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL PRD Info", "Cannot get data from the OPAL PRD " " device interface," " check if opal-prd daemon may be in use " "or check your user privileges."); return FWTS_ERROR; } memset(&info, 0, sizeof(info)); if (ioctl(fd, OPAL_PRD_GET_INFO, &info)) { (void)close(fd); fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL PRD Info", "Cannot get data from the" " OPAL PRD device interface."); return FWTS_ERROR; } else { fwts_log_info(fw, "OPAL PRD Version is %lu", info.version); (void)close(fd); return FWTS_OK; } }
/* * ACPI Section 18.3.2.2.1, IA-32 Architecture Non-Maskable Interrupt * - note, this should be a higher section number, the ACPI 6.0 * specification seems to have numbered this incorrectly. */ static void hest_check_acpi_table_hest_nmi_error( fwts_framework *fw, ssize_t *length, uint8_t **data, bool *passed) { fwts_acpi_table_hest_nmi_error *err = (fwts_acpi_table_hest_nmi_error *)*data; if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_nmi_error)) { fwts_failed(fw, LOG_LEVEL_HIGH, "HESTIA-32ArchitectureNmiTooShort", "HEST IA-32 Architecture Non-Mastable Interrupt " "too short, expecting %zu bytes, " "instead got %zu bytes", sizeof(fwts_acpi_table_hest_nmi_error), *length); *passed = false; *length = 0; /* Forces an early abort */ return; } fwts_log_info_verbatim(fw, "HEST IA-32 Architecture Non-Maskable Interrupt:"); fwts_log_info_verbatim(fw, " Type: 0x%2.2" PRIx8, err->type); fwts_log_info_verbatim(fw, " Source ID: 0x%4.4" PRIx16, err->source_id); fwts_log_info_verbatim(fw, " Reserved: 0x%4.4" PRIx16, err->reserved1); fwts_log_info_verbatim(fw, " Number of Records: 0x%8.8" PRIx32, err->number_of_records_to_preallocate); fwts_log_info_verbatim(fw, " Max Sections Per Record: 0x%8.8" PRIx32, err->max_sections_per_record); fwts_log_info_verbatim(fw, " Max Raw Data Length: 0x%8.8" PRIx32, err->max_raw_data_length); fwts_log_nl(fw); if (err->reserved1) { *passed = false; fwts_failed(fw, LOG_LEVEL_LOW, "HESTInvalidRecordsToPreallocate", "HEST IA-32 Architecture NMI Reserved field " "at offset 4 must be zero, instead got 0x%" PRIx16, err->reserved1); } if (err->number_of_records_to_preallocate < 1) { *passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "HESTInvalidRecordsToPreallocate", "HEST IA-32 Architecture NMI Number of Records " "to Preallocate is 0x%" PRIx16 " and must be " "more than zero.", err->number_of_records_to_preallocate); } if (err->max_sections_per_record < 1) { *passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "HESTInvalidMaxSectionsPerRecord", "HEST A-32 Architecture NMI Max Sections Per " "Record is 0x%" PRIx16 " and must be " "more than zero.", err->max_sections_per_record); } *length -= sizeof(fwts_acpi_table_hest_nmi_error); *data += sizeof(fwts_acpi_table_hest_nmi_error); }
static int uefirttime_test_settime_invalid_time( fwts_framework *fw, EFI_TIME *time) { struct efi_gettime gettime; struct efi_settime settime; EFI_TIME oldtime, newtime; uint64_t status = ~0ULL; int ret, ioret; gettime.Time = &oldtime; gettime.status = &status; gettime.Capabilities = NULL; ioret = ioctl(fd, EFI_RUNTIME_GET_TIME, &gettime); if (ioret == -1) { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeGetTime", "Failed to get wakeup time with UEFI runtime service."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } memcpy(&newtime, &oldtime, sizeof(EFI_TIME)); if (time->Year != 0xffff) newtime.Year = time->Year; if (time->Month != 0xff) newtime.Month = time->Month; if (time->Day != 0xff) newtime.Day = time->Day; if (time->Hour != 0xff) newtime.Hour = time->Hour; if (time->Minute != 0xff) newtime.Minute = time->Minute; if (time->Second != 0xff) newtime.Second = time->Second; if (time->Nanosecond != 0xffffffff) newtime.Nanosecond = time->Nanosecond; if ((uint16_t)time->TimeZone != 0xffff) newtime.TimeZone = time->TimeZone; settime.Time = &newtime; settime.status = &status; ret = uefirttime_test_settime_invalid(fw, &settime); /* Restore original time */ settime.Time = &oldtime; status = ~0ULL; settime.status = &status; ioret = ioctl(fd, EFI_RUNTIME_SET_TIME, &settime); if (ioret == -1) { fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIRuntimeSetTime", "Failed to set wakeup time with UEFI runtime service."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } return ret; }
/* * 4.1.2.7 ASF_ADDR */ static void asf_check_addr( fwts_framework *fw, ssize_t record_length, ssize_t length, uint8_t *data, bool *passed, bool *abort) { ssize_t total_length; fwts_acpi_table_asf_addr *addr = (fwts_acpi_table_asf_addr *)data; #if ASF_DUMP uint8_t i; #else (void)data; #endif if (length < (ssize_t)sizeof(fwts_acpi_table_asf_addr)) { fwts_failed(fw, LOG_LEVEL_HIGH, "ASF!AddrRecordTooShort", "ASF! ASF_ADDR Record too short, " "expecting %zu bytes, instead got %zu bytes", sizeof(fwts_acpi_table_asf_addr), length); *passed = false; *abort = true; return; } #if ASF_DUMP fwts_log_info_verbatim(fw, "ASF! ASF_ADDR Record:"); fwts_log_info_verbatim(fw, " SEEPROM Address: 0x%2.2" PRIx8, addr->seeprom_addr); fwts_log_info_verbatim(fw, " Number of Devices: 0x%2.2" PRIx8, addr->number_of_devices); #endif total_length = sizeof(fwts_acpi_table_asf_addr) + (addr->number_of_devices * sizeof(fwts_acpi_table_asf_addr_element)); if (total_length > record_length) { *passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "ASF!AddrArrayElementLengthInvalid", "ASF! ASF_ADDR Number of Devices makes the " "total ASF_ADDR record size to be %zu bytes, however the " "table is only %zu bytes long", total_length, record_length); *passed = false; *abort = true; return; } #if ASF_DUMP data += sizeof(fwts_acpi_table_asf_addr); for (i = 0; i < addr->number_of_devices; i++) { fwts_acpi_table_asf_addr_element *element = (fwts_acpi_table_asf_addr_element *)data; fwts_log_info_verbatim(fw, " Fixed SMBus Address 0x%2.2" PRIx8, element->fixed_smbus_addr); data += sizeof(fwts_acpi_table_asf_addr_element); } #endif if (*passed) fwts_passed(fw, "No issues found in ASF! ASF_ADDR record."); }
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."); }
/* * 4.1.2.6 ASF_RMCP */ static void asf_check_rmcp( fwts_framework *fw, ssize_t length, uint8_t *data, bool *passed, bool *abort) { fwts_acpi_table_asf_rmcp *rmcp = (fwts_acpi_table_asf_rmcp *)data; if (length < (ssize_t)sizeof(fwts_acpi_table_asf_rmcp)) { fwts_failed(fw, LOG_LEVEL_HIGH, "ASF!RmcpRecordTooShort", "ASF! ASF_RMCP Record too short, " "expecting %zu bytes, instead got %zu bytes", sizeof(fwts_acpi_table_asf_rmcp), length); *passed = false; *abort = true; return; } #if ASF_DUMP fwts_log_info_verbatim(fw, "ASF! ASF_RMCP Record:"); fwts_log_info_verbatim(fw, " Remote Control Cap.: " "0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " " "0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8, rmcp->remote_control_capabilities[0], rmcp->remote_control_capabilities[1], rmcp->remote_control_capabilities[2], rmcp->remote_control_capabilities[3], rmcp->remote_control_capabilities[4], rmcp->remote_control_capabilities[5], rmcp->remote_control_capabilities[6]); fwts_log_info_verbatim(fw, " Boot Opt. Completion Code:0x%2.2" PRIx8, rmcp->completion_code); fwts_log_info_verbatim(fw, " IANA Enterprise ID: 0x%8.8" PRIx32, rmcp->iana); fwts_log_info_verbatim(fw, " Special Command: 0x%2.2" PRIx8, rmcp->special_command); fwts_log_info_verbatim(fw, " Special Command Parameter:0x%4.4" PRIx16, rmcp->special_command_param); fwts_log_info_verbatim(fw, " Boot Options: 0x%2.2" PRIx8 " 0x%2.2" PRIx8, rmcp->boot_options[0], rmcp->boot_options[1]); fwts_log_info_verbatim(fw, " OEM Parameters: 0x%4.4" PRIx16, rmcp->oem_parameters); #endif /* Specification, page 33-34 */ if (rmcp->iana == 0x4542) { /* Values 0x00..0x05 and 0xc0..0xff are allowed */ if ((rmcp->special_command > 0x05) && (rmcp->special_command < 0xc0)) { *passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "ASF!RmcpSpecialCommandInvalid", "ASF! ASF_RMCP Special Command is 0x%" PRIx8 "and should be 0x00..0x05 or 0xc0..0xff", rmcp->special_command); } } if (*passed) fwts_passed(fw, "No issues found in ASF! ASF_RMCP record."); }
static void srat_check_gicc_affinity( fwts_framework *fw, ssize_t *length, uint8_t **data, bool *passed) { fwts_acpi_table_gicc_affinity *affinity = (fwts_acpi_table_gicc_affinity *)*data; if ((ssize_t)sizeof(fwts_acpi_table_gicc_affinity) > *length) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "SRATGICCAffinityShort", "SRAT GICC Affinity structure too short, got " "%zu bytes, expecting %zu bytes", *length, sizeof(fwts_acpi_table_gicc_affinity)); *passed = false; goto done; } if (affinity->length != sizeof(fwts_acpi_table_gicc_affinity)) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "SRATGICCAffinityLength", "SRAT GICC Affinity Length incorrect, got " "%" PRIu8 ", expecting %zu", affinity->length, sizeof(fwts_acpi_table_gicc_affinity)); *passed = false; goto done; } fwts_log_info_verbatum(fw, "SRAT GICC Affinity Structure:"); fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, affinity->type); fwts_log_info_verbatum(fw, " Length: 0x%2.2" PRIx8, affinity->length); fwts_log_info_verbatum(fw, " Proximity Domain: 0x%4.4" PRIx32, affinity->proximity_domain); fwts_log_info_verbatum(fw, " ACPI Processor UID: 0x%8.8" PRIx32, affinity->acpi_processor_uid); fwts_log_info_verbatum(fw, " Flags: 0x%8.8" PRIx32, affinity->flags); fwts_log_info_verbatum(fw, " Clock Domain 0x%8.8" PRIx32, affinity->clock_domain); fwts_log_nl(fw); if (affinity->flags & ~0x1UL) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "SRATGICCAffinityFlags", "SRAT GICC Affinity Flags field reserved bits 1..31 should be zero, got " "0x%" PRIx32, affinity->flags); *passed = false; } /* * Clock domain probably needs deeper sanity checking, for now * skip this. */ done: *length -= sizeof(fwts_acpi_table_gicc_affinity); *data += sizeof(fwts_acpi_table_gicc_affinity); }
static void srat_check_memory_affinity( fwts_framework *fw, ssize_t *length, uint8_t **data, bool *passed) { fwts_acpi_table_memory_affinity *affinity = (fwts_acpi_table_memory_affinity *)*data; if ((ssize_t)sizeof(fwts_acpi_table_memory_affinity) > *length) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "SRATMemoryAffinityShort", "SRAT Memory Affinity structure too short, got " "%zu bytes, expecting %zu bytes", *length, sizeof(fwts_acpi_table_memory_affinity)); *passed = false; goto done; } if (affinity->length != sizeof(fwts_acpi_table_memory_affinity)) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "SRATMemoryAffinityLength", "SRAT Memory Affinity Length incorrect, got " "%" PRIu8 ", expecting %zu", affinity->length, sizeof(fwts_acpi_table_memory_affinity)); *passed = false; goto done; } fwts_log_info_verbatum(fw, "SRAT Memory Affinity Structure:"); fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, affinity->type); fwts_log_info_verbatum(fw, " Length: 0x%2.2" PRIx8, affinity->length); fwts_log_info_verbatum(fw, " Proximity Domain: 0x%8.8" PRIx32, affinity->proximity_domain); fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, affinity->reserved1); fwts_log_info_verbatum(fw, " Base Address: 0x%8.8" PRIx32 "%8.8" PRIx32, affinity->base_addr_hi, affinity->base_addr_lo); fwts_log_info_verbatum(fw, " Length: 0x%8.8" PRIx32 "%8.8" PRIx32, affinity->length_hi, affinity->length_lo); fwts_log_info_verbatum(fw, " Reserved: 0x%8.8" PRIx32, affinity->reserved2); fwts_log_info_verbatum(fw, " Flags: 0x%8.8" PRIx32, affinity->flags); fwts_log_info_verbatum(fw, " Reserved: 0x%16.16" PRIx64, affinity->reserved3); fwts_log_nl(fw); if (affinity->flags & ~0x7UL) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "SRATMemoryAffinityFlags", "SRAT Memory Affinity Flags field reserved bits 3..31 should be zero, got " "0x%" PRIx32, affinity->flags); *passed = false; } done: *length -= sizeof(fwts_acpi_table_memory_affinity); *data += sizeof(fwts_acpi_table_memory_affinity); }
static int auto_brightness_test1(fwts_framework *fw) { struct dirent *entry; int actual_brightness; int max_brightness; DIR *brightness_dir = brightness_get_dir(); skip_tests = true; rewinddir(brightness_dir); do { entry = readdir(brightness_dir); if (entry == NULL || entry->d_name[0] == '.') continue; if (brightness_get_setting(entry->d_name, "actual_brightness", &actual_brightness) != FWTS_OK) { fwts_failed(fw, LOG_LEVEL_HIGH, "BrightnessNotFound", "Actual brightness could not be accessed for %s.", entry->d_name); continue; } if (brightness_get_setting(entry->d_name, "max_brightness", &max_brightness) != FWTS_OK) { fwts_failed(fw, LOG_LEVEL_HIGH, "BrightnessNotExist", "Maximum brightness could not be accessed for %s.", entry->d_name); continue; } skip_tests = false; if (max_brightness <= 0) { fwts_failed(fw, LOG_LEVEL_HIGH, "BrightnessMaxTest1", "Maximum brightness for %s is %d and should be > 0.", entry->d_name, max_brightness); continue; } fwts_passed(fw, "Maximum brightness for %s is %d which is sane.", entry->d_name, max_brightness); if ((actual_brightness >=0) && (actual_brightness <= max_brightness)) fwts_passed(fw, "Actual brightness for %s is %d which is in range 0..%d.", entry->d_name, actual_brightness, max_brightness); else fwts_failed(fw, LOG_LEVEL_HIGH, "BrightnessOutofRange", "Actual brightness for %s not in range 0..%d.", entry->d_name, max_brightness); } while (entry); return FWTS_OK; }
/* * TPM2 table * available @ https://trustedcomputinggroup.org/tcg-acpi-specification/ */ static int tpm2_test1(fwts_framework *fw) { fwts_acpi_table_tpm2 *tpm2 = (fwts_acpi_table_tpm2*) table->data; bool passed = true; fwts_log_info_verbatim(fw, "TPM2 Table:"); fwts_log_info_verbatim(fw, " Platform Class: 0x%4.4" PRIx16, tpm2->platform_class); fwts_log_info_verbatim(fw, " Reserved: 0x%4.4" PRIx32, tpm2->reserved); fwts_log_info_verbatim(fw, " Address of Control Area: 0x%16.16" PRIx64, tpm2->address_of_control_area); fwts_log_info_verbatim(fw, " Start Method: 0x%8.8" PRIx32, tpm2->start_method); if (tpm2->platform_class != 0 && tpm2->platform_class != 1) { passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "TPM2BadPlatformClass", "TPM2's platform class must be zero (client) or one (server), got 0x%" PRIx16, tpm2->platform_class); } fwts_acpi_reserved_zero_check(fw, "TPM2", "Reserved", tpm2->reserved, sizeof(tpm2->reserved), &passed); if (tpm2->start_method < 1 || tpm2->start_method >= 12) { passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "TPM2BadStartMethod", "TPM2's Start Method must be between one to eleven, got 0x%" PRIx16, tpm2->start_method); } if (tpm2->start_method == 2 && table->length != sizeof(fwts_acpi_table_tpm2) + 4) { passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "TPM2BadPlatformParameters", "Table length must be 0x%" PRIx32 " if Start method equals 2, got 0x%" PRIx32, (uint32_t) sizeof(fwts_acpi_table_tpm2) + 4, (uint32_t) table->length); } if (tpm2->start_method == 11 && table->length < sizeof(fwts_acpi_table_tpm2) + 12) { passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "TPM2BadPlatformParameters", "Table length must be atleast 0x%" PRIx32 " if Start method equals 11, got 0x%" PRIx32, (uint32_t) sizeof(fwts_acpi_table_tpm2) + 12, (uint32_t) table->length); } if (passed) fwts_passed(fw, "No issues found in TPM2 table."); return FWTS_OK; }
/* * Delete the test authenticated variable. */ static int uefirtauthvar_test7(fwts_framework *fw) { long ioret; uint8_t data[getvar_buf_size]; uint64_t getdatasize = sizeof(data); uint64_t status; uint32_t attributestest; if (!(data_exist & E_AUTHVARCREATE)) { fwts_skipped(fw,"The test data, AuthVarCreate, doesn't exist, skip the test."); return FWTS_SKIP; } ioret = setvar(>estguid, attributes, sizeof(AuthVarDel), AuthVarDel, &status); if (ioret == -1) { int supcheck = check_fw_support(fw, status); if (supcheck != FWTS_OK) return supcheck; fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIDelAuthVar", "Failed to delete authenticated variable with UEFI " "runtime service."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } ioret = getvar(>estguid, &attributestest, &getdatasize, data, &status); if (ioret == -1) { if (status == EFI_NOT_FOUND) { fwts_passed(fw, "Delete authenticated variable tests passed."); return FWTS_OK; } fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIDelAuthVar", "Failed to get authenticated variable with UEFI " "runtime service."); fwts_uefi_print_status_info(fw, status); return FWTS_ERROR; } fwts_failed(fw, LOG_LEVEL_HIGH, "UEFIDelAuthVar", "Failed to delete authenticated variable still get the test" "authenticated variable."); return FWTS_ERROR; }
/* * ASPT Table * (reverse engineered, table is common on AMD machines) */ static int aspt_test1(fwts_framework *fw) { bool passed = true; fwts_acpi_table_aspt *aspt = (fwts_acpi_table_aspt *)table->data; if (table->length < sizeof(fwts_acpi_table_aspt)) { passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "ASPTTooShort", "ASPT table too short, expecting %zu bytes, " "instead got %zu bytes", sizeof(fwts_acpi_table_aspt), table->length); goto done; } fwts_log_info_verbatum(fw, "ASPT Table:"); fwts_log_info_verbatum(fw, " SPTT Start Address: 0x%8.8" PRIx32, aspt->sptt_addr_start); fwts_log_info_verbatum(fw, " SPTT End Address: 0x%8.8" PRIx32, aspt->sptt_addr_end); fwts_log_info_verbatum(fw, " AMRT Start Address: 0x%8.8" PRIx32, aspt->amrt_addr_start); fwts_log_info_verbatum(fw, " AMRT End Address: 0x%8.8" PRIx32, aspt->amrt_addr_end); fwts_log_nl(fw); /* * Without a specification to work with there is very * little we can do to validate this apart from the * simplest sanity check */ if (aspt->sptt_addr_end < aspt->sptt_addr_start) { fwts_failed(fw, LOG_LEVEL_HIGH, "ASPTSpttEndError", "ASPT SPTT end address is less than the APTT start " "address."); passed = false; } if (aspt->amrt_addr_end < aspt->amrt_addr_start) { fwts_failed(fw, LOG_LEVEL_HIGH, "ASPTAmrtEndError", "ASPT AMRT end address is less than the AMRT start " "address."); passed = false; } done: if (passed) fwts_passed(fw, "No issues found in ASPT table."); return FWTS_OK; }
/* * See ACPI 6.0, Section 5.2.16 */ static int srat_test1(fwts_framework *fw) { const fwts_acpi_table_srat *srat = (const fwts_acpi_table_srat *)table->data; uint8_t *data = (uint8_t *)table->data; bool passed = true; ssize_t length = (ssize_t)srat->header.length; if (srat->reserved1 != 1) { fwts_failed(fw, LOG_LEVEL_MEDIUM, "SRATInterfaceReserved", "SRAT reserved field 1 should be 1, instead was " "0x%" PRIx32, srat->reserved1); passed = false; } data += sizeof(fwts_acpi_table_srat); length -= sizeof(fwts_acpi_table_srat); while (length > 0) { switch (*data) { case 0x00: srat_check_local_apic_sapic_affinity(fw, &length, &data, &passed); break; case 0x01: srat_check_memory_affinity(fw, &length, &data, &passed); break; case 0x02: srat_check_local_x2apic_affinity(fw, &length, &data, &passed); break; case 0x03: srat_check_gicc_affinity(fw, &length, &data, &passed); break; default: fwts_failed(fw, LOG_LEVEL_HIGH, "SRATInvalidType", "SRAT Affinity Structure Type 0x%" PRIx8 " is an invalid type, expecting 0x00..0x02", *data); passed = false; length = 0; break; } } if (passed) fwts_passed(fw, "No issues found in SRAT table."); return FWTS_OK; }
/* * brightness_init() * generic brightness test init, if successful * it opens a diretory for the /sys interface */ int brightness_init(fwts_framework *fw) { int i; static const char *sys_path[] = { "/sys/class/backlight", "/sys/devices/virtual/backlight", NULL }; brightness_path = NULL; brightness_dir = NULL; for (i = 0; sys_path[i]; i++) { brightness_dir = opendir(sys_path[i]); if (brightness_dir) { brightness_path = sys_path[i]; return FWTS_OK; } } fwts_failed(fw, LOG_LEVEL_LOW, "BacklightNoPath", "No sysfs backlight directory available: cannot test."); return FWTS_ERROR; }
static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_0 *entry, bool *passed) { fwts_acpi_gas *gas = &entry->doorbell_register; uint64_t reserved; reserved = (uint64_t) entry->reserved[0] + ((uint64_t) entry->reserved[1] << 8) + ((uint64_t) entry->reserved[2] << 16) + ((uint64_t) entry->reserved[3] << 24) + ((uint64_t) entry->reserved[4] << 32) + ((uint64_t) entry->reserved[5] << 40); fwts_log_info_verbatim(fw, " Reserved: 0x%16.16" PRIx64, 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:"); fwts_log_info_verbatim(fw, " Address Space ID 0x%2.2" PRIx8, gas->address_space_id); fwts_log_info_verbatim(fw, " Register Bit Width 0x%2.2" PRIx8, gas->register_bit_width); fwts_log_info_verbatim(fw, " Register Bit Offset 0x%2.2" PRIx8, gas->register_bit_offset); fwts_log_info_verbatim(fw, " Access Size 0x%2.2" PRIx8, gas->access_width); fwts_log_info_verbatim(fw, " Address 0x%16.16" PRIx64, gas->address); 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); if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) && (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY)) { *passed = false; fwts_failed(fw, LOG_LEVEL_HIGH, "PCCTSubspaceInvalidAddrSpaceID", "PCCT Subspace Type 0 has space ID = 0x%2.2" PRIx8 " which is not System I/O or Memory", gas->address_space_id); } }
static int dt_sysinfo_get_version(fwts_framework *fw, int node, char *firmware) { int version_len; /* only output if the platform_firmware node is present */ if (node >= 0) { const char *version_buf = fdt_getprop(fw->fdt, node, firmware, &version_len); if (version_buf) { fwts_passed(fw, "OPAL \"%s\" firmware version from device" " tree node \"%s\" is \"%s\".", firmware, platform_firmware, version_buf); } else { fwts_failed(fw, LOG_LEVEL_CRITICAL, "DTSysInfoCheck", "OPAL \"%s\" firmware version from device" " tree node \"%s\" was not found," " check your installation for" " device tree node \"%s\".", platform_firmware, firmware, platform_firmware); } } return FWTS_OK; }
static void hpet_parse_check_base( fwts_framework *fw, const char *table, fwts_list_link *item, bool *parsed) { char *val; if ((val = strstr(fwts_text_list_text(item), "0x")) != NULL) { uint64_t address_base; char *idx = index(val, ','); if (idx) *idx = '\0'; address_base = strtoul(val, NULL, 0x10); if (hpet_base_p != 0) { *parsed = true; if (hpet_base_p != address_base) fwts_failed(fw, LOG_LEVEL_MEDIUM, "HPETBaseMismatch", "Mismatched HPET base between %s (%" PRIx64 ") " "and the kernel (0x%" PRIx64 ").", table, hpet_base_p, address_base); else fwts_passed(fw, "HPET base matches that between %s and " "the kernel (0x%" PRIx64 ").", table, hpet_base_p); } } }