| /* |
| * Copyright (c) 2023 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/ztest.h> |
| #include <string.h> |
| #include <inttypes.h> |
| |
| #include "mock.h" |
| |
| #include <zephyr/acpi/acpi.h> |
| #include <lib/acpi/acpi.c> |
| #include "assert.h" |
| |
| #include <zephyr/fff.h> |
| DEFINE_FFF_GLOBALS; |
| |
| struct DMAR { |
| ACPI_TABLE_DMAR header; |
| |
| /* Hardware Unit 0 */ |
| struct { |
| ACPI_DMAR_HARDWARE_UNIT header; |
| |
| struct { |
| ACPI_DMAR_DEVICE_SCOPE header; |
| ACPI_DMAR_PCI_PATH path0; |
| } ds0; |
| |
| struct { |
| ACPI_DMAR_DEVICE_SCOPE header; |
| ACPI_DMAR_PCI_PATH path0; |
| } ds1; |
| } unit0; |
| |
| /* Hardware Unit 1 */ |
| struct { |
| ACPI_DMAR_HARDWARE_UNIT header; |
| |
| struct { |
| ACPI_DMAR_DEVICE_SCOPE header; |
| ACPI_DMAR_PCI_PATH path0; |
| } ds0; |
| |
| struct { |
| ACPI_DMAR_DEVICE_SCOPE header; |
| ACPI_DMAR_PCI_PATH path0; |
| } ds1; |
| } unit1; |
| }; |
| |
| static struct DMAR dmar0; |
| |
| static void dmar_initialize(struct DMAR *dmar) |
| { |
| dmar->header.Header.Length = sizeof(struct DMAR); |
| |
| dmar->unit0.header.Header.Length = sizeof(dmar->unit0); |
| dmar->unit0.ds0.header.Length = sizeof(dmar->unit0.ds0); |
| dmar->unit0.ds1.header.Length = sizeof(dmar->unit0.ds1); |
| |
| dmar->unit1.header.Header.Length = sizeof(dmar->unit1); |
| dmar->unit1.ds0.header.Length = sizeof(dmar->unit1.ds0); |
| dmar->unit1.ds1.header.Length = sizeof(dmar->unit1.ds1); |
| } |
| |
| ZTEST(lib_acpi, test_nop) |
| { |
| } |
| |
| static void count_subtables(ACPI_DMAR_HEADER *subtable, void *arg) |
| { |
| uint8_t *count = arg; |
| |
| (*count)++; |
| } |
| |
| FAKE_VOID_FUNC(subtable_nop, ACPI_DMAR_HEADER *, void *); |
| |
| ZTEST(lib_acpi, test_dmar_foreach_subtable) |
| { |
| uint8_t count = 0; |
| |
| dmar_initialize(&dmar0); |
| |
| acpi_dmar_foreach_subtable((void *)&dmar0, count_subtables, &count); |
| zassert_equal(count, 2); |
| |
| TC_PRINT("Counted %u hardware units\n", count); |
| } |
| |
| ZTEST(lib_acpi, test_dmar_foreach_subtable_invalid_unit_size_zero) |
| { |
| ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit1.header; |
| |
| dmar_initialize(&dmar0); |
| |
| /* Set invalid hardware unit size */ |
| hu->Header.Length = 0; |
| |
| expect_assert(); |
| |
| /* Expect assert, use fake void function as a callback */ |
| acpi_dmar_foreach_subtable((void *)&dmar0, subtable_nop, NULL); |
| |
| zassert_unreachable("Missed assert catch"); |
| } |
| |
| ZTEST(lib_acpi, test_dmar_foreach_subtable_invalid_unit_size_big) |
| { |
| ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit1.header; |
| |
| dmar_initialize(&dmar0); |
| |
| /* Set invalid hardware unit size */ |
| hu->Header.Length = sizeof(dmar0.unit1) + 1; |
| |
| expect_assert(); |
| |
| /* Expect assert, use fake void function as a callback */ |
| acpi_dmar_foreach_subtable((void *)&dmar0, subtable_nop, NULL); |
| |
| zassert_unreachable("Missed assert catch"); |
| } |
| |
| static void count_devscopes(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg) |
| { |
| uint8_t *count = arg; |
| |
| (*count)++; |
| } |
| |
| FAKE_VOID_FUNC(devscope_nop, ACPI_DMAR_DEVICE_SCOPE *, void *); |
| |
| ZTEST(lib_acpi, test_dmar_foreach_devscope) |
| { |
| ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit0.header; |
| uint8_t count = 0; |
| |
| dmar_initialize(&dmar0); |
| |
| acpi_dmar_foreach_devscope(hu, count_devscopes, &count); |
| zassert_equal(count, 2); |
| |
| TC_PRINT("Counted %u device scopes\n", count); |
| } |
| |
| ZTEST(lib_acpi, test_dmar_foreach_devscope_invalid_unit_size) |
| { |
| ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit0.header; |
| |
| dmar_initialize(&dmar0); |
| |
| /* Set invalid hardware unit size */ |
| hu->Header.Length = 0; |
| |
| expect_assert(); |
| |
| /* Expect assert, use fake void function as a callback */ |
| acpi_dmar_foreach_devscope(hu, devscope_nop, NULL); |
| |
| zassert_unreachable("Missed assert catch"); |
| } |
| |
| ZTEST(lib_acpi, test_dmar_foreach_devscope_invalid_devscope_size_zero) |
| { |
| ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit0.header; |
| ACPI_DMAR_DEVICE_SCOPE *devscope = &dmar0.unit0.ds0.header; |
| |
| dmar_initialize(&dmar0); |
| |
| /* Set invalid device scope size */ |
| devscope->Length = 0; |
| |
| expect_assert(); |
| |
| /* Expect assert, use fake void function as a callback */ |
| acpi_dmar_foreach_devscope(hu, devscope_nop, NULL); |
| |
| zassert_unreachable("Missed assert catch"); |
| } |
| |
| ZTEST(lib_acpi, test_dmar_foreach_devscope_invalid_devscope_size_big) |
| { |
| ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit1.header; |
| ACPI_DMAR_DEVICE_SCOPE *devscope = &dmar0.unit1.ds1.header; |
| |
| dmar_initialize(&dmar0); |
| |
| /* Set invalid device scope size */ |
| devscope->Length = sizeof(dmar0.unit1.ds1) + 1; |
| |
| expect_assert(); |
| |
| /* Expect assert, use fake void function as a callback */ |
| acpi_dmar_foreach_devscope(hu, devscope_nop, NULL); |
| |
| zassert_unreachable("Missed assert catch"); |
| } |
| |
| /** |
| * Redefine AcpiGetTable to provide our static table |
| */ |
| DECLARE_FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetTable, char *, UINT32, |
| struct acpi_table_header **); |
| static ACPI_STATUS dmar_custom_get_table(char *Signature, UINT32 Instance, |
| ACPI_TABLE_HEADER **OutTable) |
| { |
| *OutTable = (ACPI_TABLE_HEADER *)&dmar0; |
| |
| return AE_OK; |
| } |
| |
| ZTEST(lib_acpi, test_dmar_ioapic_get) |
| { |
| union acpi_dmar_id fake_path = { |
| .bits.bus = 0xab, |
| .bits.device = 0xc, |
| .bits.function = 0b101, |
| }; |
| uint16_t ioapic; |
| int ret; |
| |
| dmar_initialize(&dmar0); |
| |
| /* Set IOAPIC device scope */ |
| dmar0.unit1.ds1.header.EntryType = ACPI_DMAR_SCOPE_TYPE_IOAPIC; |
| |
| /* Set some arbitrary Bus and PCI path */ |
| dmar0.unit1.ds1.header.Bus = fake_path.bits.bus; |
| dmar0.unit1.ds1.path0.Device = fake_path.bits.device; |
| dmar0.unit1.ds1.path0.Function = fake_path.bits.function; |
| |
| /* Return our dmar0 table */ |
| AcpiGetTable_fake.custom_fake = dmar_custom_get_table; |
| |
| zassert_equal(AcpiGetTable_fake.call_count, 0); |
| |
| ret = acpi_dmar_ioapic_get(&ioapic); |
| zassert_ok(ret, "Failed getting ioapic"); |
| |
| /* Verify AcpiGetTable called */ |
| zassert_equal(AcpiGetTable_fake.call_count, 1); |
| |
| zassert_equal(ioapic, fake_path.raw, "Got wrong ioapic"); |
| |
| TC_PRINT("Found ioapic id 0x%x\n", ioapic); |
| } |
| |
| static void test_before(void *data) |
| { |
| ASSERT_FFF_FAKES_LIST(RESET_FAKE); |
| } |
| |
| ZTEST_SUITE(lib_acpi, NULL, NULL, test_before, NULL, NULL); |