From 48acd7fe90faf87d8dcb5c3873aadcd8d9444d6c Mon Sep 17 00:00:00 2001 From: anonymix007 <48598263+anonymix007@users.noreply.github.com> Date: Thu, 12 Dec 2024 23:56:56 +0300 Subject: [PATCH 1/4] boot: Deduplicate efi.h and efi-fundamental.h These definitions are needed for both userspace and EFI, so keep them in efi-fundamental.h --- src/boot/efi.h | 34 +------------------------------ src/fundamental/efi-fundamental.h | 14 +++++++------ 2 files changed, 9 insertions(+), 39 deletions(-) diff --git a/src/boot/efi.h b/src/boot/efi.h index e1042635b9..9cac172072 100644 --- a/src/boot/efi.h +++ b/src/boot/efi.h @@ -6,6 +6,7 @@ #include #include +#include "efi-fundamental.h" #include "macro-fundamental.h" #if SD_BOOT @@ -118,30 +119,11 @@ typedef uint64_t EFI_PHYSICAL_ADDRESS; #define EFI_IP_ADDRESS_CONFLICT EFIERR(34) #define EFI_HTTP_ERROR EFIERR(35) -typedef struct { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; -} EFI_GUID; - -#define GUID_DEF(d1, d2, d3, d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8) \ - { d1, d2, d3, { d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8 } } - -/* Creates a EFI_GUID pointer suitable for EFI APIs. Use of const allows the compiler to merge multiple - * uses (although, currently compilers do that regardless). Most EFI APIs declare their EFI_GUID input - * as non-const, but almost all of them are in fact const. */ -#define MAKE_GUID_PTR(name) ((EFI_GUID *) &(const EFI_GUID) name##_GUID) - /* These allow MAKE_GUID_PTR() to work without requiring an extra _GUID in the passed name. We want to * keep the GUID definitions in line with the UEFI spec. */ #define EFI_GLOBAL_VARIABLE_GUID EFI_GLOBAL_VARIABLE #define EFI_FILE_INFO_GUID EFI_FILE_INFO_ID -#define EFI_GLOBAL_VARIABLE \ - GUID_DEF(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) -#define EFI_IMAGE_SECURITY_DATABASE_GUID \ - GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f) #define EFI_CUSTOM_MODE_ENABLE_GUID \ GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f) @@ -238,20 +220,6 @@ typedef enum { EfiResetPlatformSpecific, } EFI_RESET_TYPE; -typedef struct { - uint16_t Year; - uint8_t Month; - uint8_t Day; - uint8_t Hour; - uint8_t Minute; - uint8_t Second; - uint8_t Pad1; - uint32_t Nanosecond; - int16_t TimeZone; - uint8_t Daylight; - uint8_t Pad2; -} EFI_TIME; - typedef struct { uint32_t Resolution; uint32_t Accuracy; diff --git a/src/fundamental/efi-fundamental.h b/src/fundamental/efi-fundamental.h index f6729293a9..de7ae6cd8a 100644 --- a/src/fundamental/efi-fundamental.h +++ b/src/fundamental/efi-fundamental.h @@ -1,10 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#if !SD_BOOT -# include -# include -# include +#include /* Matches EFI API definition of the same structure for userspace */ typedef struct { @@ -14,9 +11,13 @@ typedef struct { uint8_t Data4[8]; } EFI_GUID; +#if !SD_BOOT +# include +# include static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) { return memcmp(a, b, sizeof(EFI_GUID)) == 0; } +#endif typedef struct { EFI_GUID SignatureOwner; @@ -66,6 +67,9 @@ typedef struct { #define GUID_DEF(d1, d2, d3, d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8) \ { d1, d2, d3, { d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8 } } +/* Creates a EFI_GUID pointer suitable for EFI APIs. Use of const allows the compiler to merge multiple + * uses (although, currently compilers do that regardless). Most EFI APIs declare their EFI_GUID input + * as non-const, but almost all of them are in fact const. */ #define MAKE_GUID_PTR(name) ((EFI_GUID *) &(const EFI_GUID) name##_GUID) #define EFI_GLOBAL_VARIABLE \ @@ -77,5 +81,3 @@ typedef struct { GUID_DEF(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72) #define EFI_CERT_TYPE_PKCS7_GUID \ GUID_DEF(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7) - -#endif From f28cedfa311958bccaf0870b7ee567a9a2f4fc67 Mon Sep 17 00:00:00 2001 From: anonymix007 <48598263+anonymix007@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:31:02 +0300 Subject: [PATCH 2/4] boot: Add chid.c to libefitest Also fix compilation for testing CHID matching in userspace --- src/boot/chid.c | 4 ++++ src/boot/meson.build | 1 + src/boot/util.h | 15 +++++++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/boot/chid.c b/src/boot/chid.c index cd82958dcf..dca2f364e0 100644 --- a/src/boot/chid.c +++ b/src/boot/chid.c @@ -104,7 +104,11 @@ EFI_STATUS chid_match(const void *hwid_buffer, size_t hwid_length, const Device status = populate_board_chids(chids); if (EFI_STATUS_IS_ERROR(status)) +#if SD_BOOT return log_error_status(status, "Failed to populate board CHIDs: %m"); +#else + return status; +#endif size_t n_devices = 0; diff --git a/src/boot/meson.build b/src/boot/meson.build index 29c5455dbd..9c7483d6d1 100644 --- a/src/boot/meson.build +++ b/src/boot/meson.build @@ -7,6 +7,7 @@ libefitest = static_library( 'efitest', files( 'bcd.c', + 'chid.c', 'efi-string.c', ), build_by_default : false, diff --git a/src/boot/util.h b/src/boot/util.h index af14a0e31e..90da8ad69d 100644 --- a/src/boot/util.h +++ b/src/boot/util.h @@ -3,11 +3,14 @@ #include "efi.h" #include "efi-string.h" -#include "log.h" #include "memory-util-fundamental.h" -#include "proto/file-io.h" #include "string-util-fundamental.h" +#if SD_BOOT + +#include "log.h" +#include "proto/file-io.h" + /* This is provided by the linker. */ extern uint8_t __executable_start[]; @@ -236,3 +239,11 @@ char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path); #define bswap_16(x) __builtin_bswap16(x) #define bswap_32(x) __builtin_bswap32(x) + +#else + +#include "alloc-util.h" + +#define xnew0(type, n) ASSERT_PTR(new0(type, n)) + +#endif From 7c4e351861197ec0e20096d0bb3c7564663e8218 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 17 Dec 2024 01:25:27 +0900 Subject: [PATCH 3/4] boot: introduce smbios_raw_info_get_cached() to cache populated SMBIOS raw info Then, drop cache in smbios_info_populate(). No functional change, just refactoring and preparation for later commit. --- src/boot/chid.c | 9 +++------ src/boot/smbios.c | 14 ++++++++++++++ src/boot/smbios.h | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/boot/chid.c b/src/boot/chid.c index dca2f364e0..38fbc61d7c 100644 --- a/src/boot/chid.c +++ b/src/boot/chid.c @@ -58,13 +58,10 @@ typedef struct SmbiosInfo { } SmbiosInfo; static void smbios_info_populate(SmbiosInfo *ret_info) { - static RawSmbiosInfo raw = {}; - static bool raw_info_populated = false; + assert(ret_info); - if (!raw_info_populated) { - smbios_raw_info_populate(&raw); - raw_info_populated = true; - } + RawSmbiosInfo raw; + smbios_raw_info_get_cached(&raw); ret_info->smbios_fields[CHID_SMBIOS_MANUFACTURER] = smbios_to_hashable_string(raw.manufacturer); ret_info->smbios_fields[CHID_SMBIOS_PRODUCT_NAME] = smbios_to_hashable_string(raw.product_name); diff --git a/src/boot/smbios.c b/src/boot/smbios.c index 329619f85b..e1bcd62e2c 100644 --- a/src/boot/smbios.c +++ b/src/boot/smbios.c @@ -259,3 +259,17 @@ void smbios_raw_info_populate(RawSmbiosInfo *ret_info) { ret_info->baseboard_product = NULL; } } + +void smbios_raw_info_get_cached(RawSmbiosInfo *ret_info) { + static RawSmbiosInfo info = {}; + static bool cached = false; + + assert(ret_info); + + if (!cached) { + smbios_raw_info_populate(&info); + cached = true; + } + + *ret_info = info; +} diff --git a/src/boot/smbios.h b/src/boot/smbios.h index 34625c8572..83c3c43589 100644 --- a/src/boot/smbios.h +++ b/src/boot/smbios.h @@ -17,3 +17,4 @@ typedef struct RawSmbiosInfo { } RawSmbiosInfo; void smbios_raw_info_populate(RawSmbiosInfo *ret_info); +void smbios_raw_info_get_cached(RawSmbiosInfo *ret_info); From 640f8c3eb8dc21539500e92a5c69cdb6cbda3381 Mon Sep 17 00:00:00 2001 From: anonymix007 <48598263+anonymix007@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:32:24 +0300 Subject: [PATCH 4/4] test: Add test-chid-match --- .github/workflows/linter.yml | 8 ++-- src/boot/generate-hwids-section.py | 39 +++++++++++++++ src/boot/hwids/device1.json | 8 ++++ src/boot/hwids/device2.json | 8 ++++ src/boot/hwids/device3.json | 8 ++++ src/boot/meson.build | 15 ++++++ src/boot/test-chid-match.c | 77 ++++++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 src/boot/generate-hwids-section.py create mode 100644 src/boot/hwids/device1.json create mode 100644 src/boot/hwids/device2.json create mode 100644 src/boot/hwids/device3.json create mode 100644 src/boot/test-chid-match.c diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 4bcd594a09..dde1477d5d 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -37,7 +37,7 @@ jobs: VALIDATE_GITHUB_ACTIONS: true - name: Check that tabs are not used in Python code - run: sh -c '! git grep -P "\\t" -- src/ukify/ukify.py test/integration-test-wrapper.py' + run: sh -c '! git grep -P "\\t" -- src/boot/generate-hwids-section.py src/ukify/ukify.py test/integration-test-wrapper.py' - name: Install ruff and mypy run: | @@ -47,14 +47,14 @@ jobs: - name: Run mypy run: | python3 -m mypy --version - python3 -m mypy src/test/generate-sym-test.py src/ukify/ukify.py test/integration-test-wrapper.py + python3 -m mypy src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-test-wrapper.py - name: Run ruff check run: | ruff --version - ruff check src/test/generate-sym-test.py src/ukify/ukify.py test/integration-test-wrapper.py + ruff check src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-test-wrapper.py - name: Run ruff format run: | ruff --version - ruff format --check src/test/generate-sym-test.py src/ukify/ukify.py test/integration-test-wrapper.py + ruff format --check src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-test-wrapper.py diff --git a/src/boot/generate-hwids-section.py b/src/boot/generate-hwids-section.py new file mode 100644 index 0000000000..621183c20f --- /dev/null +++ b/src/boot/generate-hwids-section.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + +import os +import sys +from pathlib import Path + +# We import ukify.py, which is a template file. But only __version__ is +# substituted, which we don't care about here. Having the .py suffix makes it +# easier to import the file. +sys.path.append(os.path.dirname(__file__) + '/../ukify') +import ukify + +BYTES_PER_LINE = 16 + +hwids = ukify.parse_hwid_dir(Path(sys.argv[1])) + +print( + """/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include +#include + +const uint8_t hwids_section_data[] = { + """, + end='', +) + +for i, b in enumerate(hwids): + print(f'0x{b:02X}, ', end='') + if i % BYTES_PER_LINE == BYTES_PER_LINE - 1: + print('\n ', end='') + elif i == len(hwids) - 1: + print('') + +print( + """}; +const size_t hwids_section_len =""", + f'{len(hwids)};', +) diff --git a/src/boot/hwids/device1.json b/src/boot/hwids/device1.json new file mode 100644 index 0000000000..030afc8ef5 --- /dev/null +++ b/src/boot/hwids/device1.json @@ -0,0 +1,8 @@ +{ + "name": "Device 1", + "compatible": "test,device-1", + "hwids": [ + "2bdcafa9-727c-5e8b-b13b-236f1391c25a", + "c87886da-8026-5149-8c95-6d2504c1b7f9" + ] +} diff --git a/src/boot/hwids/device2.json b/src/boot/hwids/device2.json new file mode 100644 index 0000000000..dc9b8e8521 --- /dev/null +++ b/src/boot/hwids/device2.json @@ -0,0 +1,8 @@ +{ + "name": "Device 2", + "compatible": "test,device-2", + "hwids": [ + "6ff16153-a32f-548a-9cd7-3574a5d0caa4", + "0afb4762-c5bb-5fba-887b-d56ce73ee793" + ] +} diff --git a/src/boot/hwids/device3.json b/src/boot/hwids/device3.json new file mode 100644 index 0000000000..d139462c16 --- /dev/null +++ b/src/boot/hwids/device3.json @@ -0,0 +1,8 @@ +{ + "name": "Device 3", + "compatible": "test,device-3", + "hwids": [ + "06b74502-e5d8-5ecd-a67a-e77654cf3b17", + "a8d84e4e-23d9-5629-86da-a49d859b5cde" + ] +} diff --git a/src/boot/meson.build b/src/boot/meson.build index 9c7483d6d1..13b35b47b2 100644 --- a/src/boot/meson.build +++ b/src/boot/meson.build @@ -26,6 +26,16 @@ efitest_base = { efi_test_template = test_template + efitest_base efi_fuzz_template = fuzz_template + efitest_base +generate_hwids_section_py = find_program('generate-hwids-section.py') + +test_hwids_section_c = custom_target( + 'test-hwids-section.c', + input : ['hwids/device1.json', 'hwids/device2.json', 'hwids/device2.json'], + output : 'test-hwids-section.c', + command : [generate_hwids_section_py, meson.current_source_dir()/'hwids'], + capture : true, + build_by_default : want_tests != 'false') + executables += [ efi_test_template + { 'sources' : files('test-bcd.c'), @@ -36,6 +46,11 @@ executables += [ 'sources' : files('test-efi-string.c'), 'conditions' : ['ENABLE_BOOTLOADER'], }, + efi_test_template + { + 'sources' : files('test-chid-match.c') + + test_hwids_section_c, + 'conditions' : ['ENABLE_BOOTLOADER'], + }, efi_fuzz_template + { 'sources' : files('fuzz-bcd.c'), }, diff --git a/src/boot/test-chid-match.c b/src/boot/test-chid-match.c new file mode 100644 index 0000000000..e9df4e1226 --- /dev/null +++ b/src/boot/test-chid-match.c @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "chid.h" +#include "smbios.h" +#include "tests.h" + +extern uint8_t hwids_section_data[]; +extern size_t hwids_section_len; + +static const RawSmbiosInfo smbios_info[] = { + { + .manufacturer = "First Vendor", + .product_name = "Device 1", + .product_sku = "KD01", + .family = "Laptop X", + .baseboard_product = "FODM1", + .baseboard_manufacturer = "First ODM", + }, + { + .manufacturer = "Second Vendor", + .product_name = "Device 2", + .product_sku = "KD02", + .family = "Laptop 2", + .baseboard_product = "SODM2", + .baseboard_manufacturer = "Second ODM", + }, + { + .manufacturer = "First Vendor", + .product_name = "Device 3", + .product_sku = "KD03", + .family = "Tablet Y", + .baseboard_product = "FODM2", + .baseboard_manufacturer = "First ODM", + }, +}; + +static struct { + const char *name; + const char *compatible; +} results[] = { + { "Device 1", "test,device-1" }, + { "Device 2", "test,device-2" }, + { "Device 3", "test,device-3" }, +}; + +static RawSmbiosInfo current_info = {}; + +/* This is a dummy implementation for testing purposes */ +void smbios_raw_info_get_cached(RawSmbiosInfo *ret_info) { + assert(ret_info); + *ret_info = current_info; +} + +TEST(chid_match) { + for (size_t i = 0; i < ELEMENTSOF(smbios_info); i++) { + current_info = smbios_info[i]; + const Device *dev = NULL; + /* Match and check */ + ASSERT_EQ(chid_match(hwids_section_data, hwids_section_len, &dev), EFI_SUCCESS); + ASSERT_NOT_NULL(dev); + ASSERT_STREQ(device_get_name(hwids_section_data, dev), results[i].name); + ASSERT_STREQ(device_get_compatible(hwids_section_data, dev), results[i].compatible); + } +} + +static int intro(void) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return EXIT_SUCCESS; +#else + return log_tests_skipped("cannot run CHID calculation on big-endian machine"); +#endif +} + +DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);