diff --git a/include/libflashrom.h b/include/libflashrom.h index 73261dd24..46d710b70 100644 --- a/include/libflashrom.h +++ b/include/libflashrom.h @@ -550,6 +550,21 @@ int flashrom_layout_get_region_range(struct flashrom_layout *layout, const char * @param layout Layout to free. */ void flashrom_layout_release(struct flashrom_layout *layout); +/** + * @brief Compare two flashrom layouts for equality. + * + * Compares all regions in both layouts. Two layouts are considered equal if they + * contain the same number of regions, in the same order, with identical start/end + * addresses and names. + * + * @param layout1 First layout to compare. + * @param layout2 Second layout to compare. + * + * @return 0 if layouts are identical, + * 1 if they differ or if either layout is NULL. + */ +int flashrom_layout_compare(const struct flashrom_layout *layout1, + const struct flashrom_layout *layout2); /** * @brief Set the active layout for a flash context. * diff --git a/libflashrom.c b/libflashrom.c index f4d69a655..b5902d7c9 100644 --- a/libflashrom.c +++ b/libflashrom.c @@ -458,12 +458,49 @@ bool flashrom_flag_get(const struct flashrom_flashctx *const flashctx, const enu #ifdef __FLASHROM_LITTLE_ENDIAN__ static int compare_region_with_dump(const struct romentry *const a, const struct romentry *const b) { - if (a->region.start != b->region.end + if (a->region.start != b->region.start || a->region.end != b->region.end || strcmp(a->region.name, b->region.name)) return 1; return 0; } + +int flashrom_layout_compare(const struct flashrom_layout *layout1, + const struct flashrom_layout *layout2) +{ + if (!layout1 || !layout2) { + msg_gerr("Error: NULL layout pointer in comparison.\n"); + return 1; + } + + const struct romentry *entry1 = layout_next(layout1, NULL); + const struct romentry *entry2 = layout_next(layout2, NULL); + + while (entry1 && entry2) { + if (compare_region_with_dump(entry1, entry2)) { + msg_gerr("Layout region mismatch:\n"); + msg_gerr(" Region 1: '%s' [0x%08" PRIx32 ":0x%08" PRIx32 "]\n", + entry1->region.name, entry1->region.start, entry1->region.end); + msg_gerr(" Region 2: '%s' [0x%08" PRIx32 ":0x%08" PRIx32 "]\n", + entry2->region.name, entry2->region.start, entry2->region.end); + return 1; + } + entry1 = layout_next(layout1, entry1); + entry2 = layout_next(layout2, entry2); + } + + /* If one layout has more regions than the other */ + if (entry1 || entry2) { + msg_gerr("Layout region count mismatch.\n"); + if (entry1) + msg_gerr(" Extra region in layout 1: '%s'\n", entry1->region.name); + if (entry2) + msg_gerr(" Extra region in layout 2: '%s'\n", entry2->region.name); + return 1; + } + + return 0; +} #endif /* __FLASHROM_LITTLE_ENDIAN__ */ int flashrom_layout_read_from_ifd(struct flashrom_layout **const layout, struct flashctx *const flashctx, diff --git a/libflashrom.map b/libflashrom.map index 2b757e5c2..358280ad3 100644 --- a/libflashrom.map +++ b/libflashrom.map @@ -13,6 +13,7 @@ LIBFLASHROM_1.0 { flashrom_image_write; flashrom_init; flashrom_layout_add_region; + flashrom_layout_compare; flashrom_layout_exclude_region; flashrom_layout_get_region_range; flashrom_layout_include_region; diff --git a/tests/libflashrom.c b/tests/libflashrom.c index 668e74fdb..5ae4b2d96 100644 --- a/tests/libflashrom.c +++ b/tests/libflashrom.c @@ -163,3 +163,60 @@ void probe_v2_error_code_propagation(void **state) #else SKIP_TEST(probe_v2_error_code_propagation) #endif /* CONFIG_DUMMY */ + +void flashrom_layout_compare_test_success(void **state) +{ + (void)state; /* unused */ + struct flashrom_layout *layout1 = NULL; + struct flashrom_layout *layout2 = NULL; + struct flashrom_layout *layout3 = NULL; + + /* Create three layouts */ + assert_int_equal(0, flashrom_layout_new(&layout1)); + assert_int_equal(0, flashrom_layout_new(&layout2)); + assert_int_equal(0, flashrom_layout_new(&layout3)); + + /* Test 1: NULL pointer handling */ + assert_int_not_equal(0, flashrom_layout_compare(NULL, layout1)); + assert_int_not_equal(0, flashrom_layout_compare(layout1, NULL)); + assert_int_not_equal(0, flashrom_layout_compare(NULL, NULL)); + + /* Test 2: Empty layouts should match */ + assert_int_equal(0, flashrom_layout_compare(layout1, layout2)); + + /* Test 3: Add same regions to layout1 and layout2 */ + assert_int_equal(0, flashrom_layout_add_region(layout1, 0x00000000, 0x000fffff, "REGION1")); + assert_int_equal(0, flashrom_layout_add_region(layout1, 0x00100000, 0x001fffff, "REGION2")); + + assert_int_equal(0, flashrom_layout_add_region(layout2, 0x00000000, 0x000fffff, "REGION1")); + assert_int_equal(0, flashrom_layout_add_region(layout2, 0x00100000, 0x001fffff, "REGION2")); + + /* Identical layouts should match */ + assert_int_equal(0, flashrom_layout_compare(layout1, layout2)); + + /* Test 4: Add different region to layout3 */ + assert_int_equal(0, flashrom_layout_add_region(layout3, 0x00000000, 0x000fffff, "REGION1")); + assert_int_equal(0, flashrom_layout_add_region(layout3, 0x00100000, 0x002fffff, "REGION2")); /* different end */ + + /* Different layouts should not match */ + assert_int_not_equal(0, flashrom_layout_compare(layout1, layout3)); + + /* Test 5: Different number of regions */ + flashrom_layout_release(layout3); + assert_int_equal(0, flashrom_layout_new(&layout3)); + assert_int_equal(0, flashrom_layout_add_region(layout3, 0x00000000, 0x000fffff, "REGION1")); + /* layout3 has only 1 region, layout1 has 2 */ + assert_int_not_equal(0, flashrom_layout_compare(layout1, layout3)); + + /* Test 6: Same regions but different names */ + flashrom_layout_release(layout3); + assert_int_equal(0, flashrom_layout_new(&layout3)); + assert_int_equal(0, flashrom_layout_add_region(layout3, 0x00000000, 0x000fffff, "DIFFERENT_NAME")); + assert_int_equal(0, flashrom_layout_add_region(layout3, 0x00100000, 0x001fffff, "REGION2")); + assert_int_not_equal(0, flashrom_layout_compare(layout1, layout3)); + + /* Cleanup */ + flashrom_layout_release(layout1); + flashrom_layout_release(layout2); + flashrom_layout_release(layout3); +} diff --git a/tests/tests.c b/tests/tests.c index 2fabdced7..bc513eff5 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -476,6 +476,7 @@ int main(int argc, char *argv[]) cmocka_unit_test(flashrom_set_log_level_test_success), cmocka_unit_test(flashrom_supported_programmers_test_success), cmocka_unit_test(probe_v2_error_code_propagation), + cmocka_unit_test(flashrom_layout_compare_test_success), }; ret |= cmocka_run_group_tests_name("libflashrom.c tests", libflashrom_tests, NULL, NULL); diff --git a/tests/tests.h b/tests/tests.h index 6842be970..ed12cbd38 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -29,6 +29,7 @@ void flashrom_set_log_callback_v2_test_success(void **state); void flashrom_set_log_level_test_success(void **state); void flashrom_supported_programmers_test_success(void **state); void probe_v2_error_code_propagation(void **state); +void flashrom_layout_compare_test_success(void **state); /* spi25.c */ void spi_write_enable_test_success(void **state);