diff --git a/CHANGELOG.md b/CHANGELOG.md index 314adf4..c9cd615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## [6.1.0] + +### Fixed + - fix cpp wrapper and add sample + - efi: use %s in external debug prefix + +### Changed + - Linux: import libmei 1.8.0 + +### Added + - samples: gsc: search for gscfi device + - samples: print FW status in GSC + - CMake: Windows: add release and debug 64 all preset + ## [6.0.2] - Windows: drop un-needed assert - EFI: do not send disconnect when not connected diff --git a/CMakePresets.json b/CMakePresets.json index 7239d7c..87e78f7 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -31,32 +31,6 @@ "BUILD_MSVC_RUNTIME_STATIC": "YES" } }, - { - "name": "Debug32AllStatic", - "displayName": "Windows x86 Debug Static All", - "description": "Build x86 Debug, VS2019, including test and samples", - "inherits": "base32", - "binaryDir": "${sourceDir}/Debug", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "BUILD_TEST": "YES", - "BUILD_SAMPLES": "YES", - "BUILD_SHARED_LIBS": "NO" - } - }, - { - "name": "Release32AllStatic", - "displayName": "Windows x86 Release Static All", - "description": "Build x86 Release, VS2019, including test and samples", - "inherits": "base32", - "binaryDir": "${sourceDir}/Release", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release", - "BUILD_TEST": "YES", - "BUILD_SAMPLES": "YES", - "BUILD_SHARED_LIBS": "NO" - } - }, { "name": "Release32Static", "displayName": "Windows x86 Release Static", @@ -99,6 +73,19 @@ "BUILD_SHARED_LIBS": "NO" } }, + { + "name": "Release64AllStatic", + "displayName": "Windows x86-64 Release Static", + "description": "Build x86-64 Release, VS2019", + "inherits": "base64", + "binaryDir": "${sourceDir}/Release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "BUILD_TEST": "YES", + "BUILD_SAMPLES": "YES", + "BUILD_SHARED_LIBS": "NO" + } + }, { "name": "Debug64All", "displayName": "Windows x86-64 Debug All", @@ -110,19 +97,22 @@ "BUILD_TEST": "YES", "BUILD_SAMPLES": "YES" } + }, + { + "name": "Debug64AllStatic", + "displayName": "Windows x86-64 Debug Static All", + "description": "Build x86-64 Debug, VS2019, including test and samples", + "inherits": "base64", + "binaryDir": "${sourceDir}/Debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "BUILD_TEST": "YES", + "BUILD_SAMPLES": "YES", + "BUILD_SHARED_LIBS": "NO" + } } ], "buildPresets": [ - { - "name": "Debug32AllStatic", - "configurePreset": "Debug32AllStatic", - "configuration": "Debug" - }, - { - "name": "Release32AllStatic", - "configurePreset": "Release32AllStatic", - "configuration": "Release" - }, { "name": "Release32Static", "configurePreset": "Release32Static", @@ -143,10 +133,20 @@ "configurePreset": "Release64Static", "configuration": "Release" }, + { + "name": "Release64AllStatic", + "configurePreset": "Release64AllStatic", + "configuration": "Release" + }, { "name": "Debug64All", "configurePreset": "Debug64All", "configuration": "Debug" + }, + { + "name": "Debug64AllStatic", + "configurePreset": "Debug64AllStatic", + "configuration": "Debug" } ] } diff --git a/VERSION b/VERSION index 9b9a244..dfda3e0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.2 +6.1.0 diff --git a/include/helpers.h b/include/helpers.h index 628a1ee..8838456 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: Apache-2.0 */ /* - * Copyright (C) 2014-2024 Intel Corporation + * Copyright (C) 2014-2025 Intel Corporation */ #ifndef __HELPERS_H #define __HELPERS_H @@ -34,7 +34,7 @@ extern "C" { #define INIT_STATUS TEE_INTERNAL_ERROR #elif defined(EFI) #define DEBUG_PRINT_ME_PREFIX_INTERNAL "TEELIB: (%a:%a():%d) " - #define DEBUG_PRINT_ME_PREFIX_EXTERNAL "TEELIB: (%a:%a():%d) " + #define DEBUG_PRINT_ME_PREFIX_EXTERNAL "TEELIB: (%s:%s():%d) " #define DebugPrintMe(fmt, ...) AsciiPrint(fmt, ##__VA_ARGS__) #define ErrorPrintMe(fmt, ...) AsciiPrint(fmt, ##__VA_ARGS__) #else diff --git a/include/meteepp.h b/include/meteepp.h index 383ce57..e2c28ef 100644 --- a/include/meteepp.h +++ b/include/meteepp.h @@ -84,24 +84,63 @@ namespace intel { class metee { public: - /*! Default constructor */ - metee() + /*! Default constructor, when connection to specific client is not required */ + metee() : metee(METEE_GUID_ZERO) {} + + /*! Constructor without client GUID, when connection to specific client is not required + * \param log_level log level to set (from enum tee_log_level) + * \param log_callback pointer to function to run for log write (type 2) + */ + metee(uint32_t log_level, TeeLogCallback2 log_callback) : metee(METEE_GUID_ZERO, log_level, log_callback) {} + + /*! Constructor + * \param guid GUID of the FW client that want to start a session + */ + metee(const GUID& guid) { - TEESTATUS status = TeeInit(&_handle, &METEE_GUID_ZERO, NULL); + TEESTATUS status = TeeInit(&_handle, &guid, nullptr); if (!TEE_IS_SUCCESS(status)) { throw metee_exception("Init failed", status); } } + /*! Constructor + * \param guid GUID of the FW client that want to start a session + * \param log_level log level to set (from enum tee_log_level) + */ + metee(const GUID& guid, uint32_t log_level) : metee(guid, log_level, static_cast(nullptr)) {} /*! Constructor * \param guid GUID of the FW client that want to start a session * \param log_level log level to set (from enum tee_log_level) - * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \param log_callback pointer to function to run for log write */ - metee(const GUID &guid, - uint32_t log_level = TEE_LOG_LEVEL_VERBOSE, TeeLogCallback log_callback = nullptr) + metee(const GUID& guid, uint32_t log_level, TeeLogCallback log_callback) : + metee(guid, { tee_device_address::TEE_DEVICE_TYPE_NONE , nullptr }, log_level, log_callback) {} + + /*! Constructor + * \param guid GUID of the FW client that want to start a session + * \param log_level log level to set (from enum tee_log_level) + * \param log_callback pointer to function to run for log write (type 2) + */ + metee(const GUID& guid, uint32_t log_level, TeeLogCallback2 log_callback) : + metee(guid, { tee_device_address::TEE_DEVICE_TYPE_NONE , nullptr }, log_level, log_callback) {} + + /*! Constructor + * \param guid GUID of the FW client that want to start a session + * \param device device address structure + * \param log_level log level to set (from enum tee_log_level) + */ + metee(const GUID& guid, const struct tee_device_address& device, uint32_t log_level) : + metee(guid, device, log_level, static_cast(nullptr)) {} + + /*! Constructor + * \param guid GUID of the FW client that want to start a session + * \param device device address structure + * \param log_level log level to set (from enum tee_log_level) + * \param log_callback pointer to function to run for log write + */ + metee(const GUID &guid, const struct tee_device_address &device, uint32_t log_level, TeeLogCallback log_callback) { - struct tee_device_address device = { tee_device_address::TEE_DEVICE_TYPE_NONE , nullptr }; TEESTATUS status = TeeInitFull(&_handle, &guid, device, log_level, log_callback); if (!TEE_IS_SUCCESS(status)) { throw metee_exception("Init failed", status); @@ -112,12 +151,11 @@ namespace intel { * \param guid GUID of the FW client that want to start a session * \param device device address structure * \param log_level log level to set (from enum tee_log_level) - * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \param log_callback pointer to function to run for log write (type 2) */ - metee(const GUID &guid, const struct tee_device_address &device, - uint32_t log_level = TEE_LOG_LEVEL_VERBOSE, TeeLogCallback log_callback = nullptr) + metee(const GUID& guid, const struct tee_device_address& device, uint32_t log_level, TeeLogCallback2 log_callback) { - TEESTATUS status = TeeInitFull(&_handle, &guid, device, log_level, log_callback); + TEESTATUS status = TeeInitFull2(&_handle, &guid, device, log_level, log_callback); if (!TEE_IS_SUCCESS(status)) { throw metee_exception("Init failed", status); } diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 63d80f9..c53f8e5 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -30,6 +30,10 @@ add_executable(metee-basic metee_basic.c) target_link_libraries(metee-basic metee) install(TARGETS metee-basic RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +add_executable(meteepp-basic meteepp_basic.cpp) +target_link_libraries(meteepp-basic metee) +install(TARGETS meteepp-basic RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + if(BUILD_SHARED_LIBS AND WIN32) add_subdirectory(csharp) endif(BUILD_SHARED_LIBS AND WIN32) \ No newline at end of file diff --git a/samples/metee_gsc.c b/samples/metee_gsc.c index 2dfaa4b..404e5e2 100644 --- a/samples/metee_gsc.c +++ b/samples/metee_gsc.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: Apache-2.0 */ /* - * Copyright (C) 2020-2024 Intel Corporation + * Copyright (C) 2020-2025 Intel Corporation */ #include #include @@ -106,23 +106,82 @@ struct mk_host_if { bool verbose; }; +static void mk_host_if_fw_status(struct mk_host_if *acmd) +{ + uint32_t fwStatus = 0; + + for (uint32_t i = 0; i < 6; i++) + if (TeeFWStatus(&acmd->mei_cl, i, &fwStatus) == TEE_SUCCESS) + printf("FW Status[%u] = 0x%08X\n", i, fwStatus); +} + +static bool mk_host_if_is_gscfi(struct mk_host_if *acmd) +{ + char kind[32]; + size_t kind_size = sizeof(kind); + + if (TeeGetKind(&acmd->mei_cl, kind, &kind_size) != TEE_SUCCESS) + return false; + + return !strcmp(kind, "gscfi"); +} + static bool mk_host_if_connect(struct mk_host_if *acmd) { acmd->initialized = (TeeConnect(&acmd->mei_cl) == 0); return acmd->initialized; } +static void mk_host_if_log(bool is_error, const char* data) +{ + fprintf((is_error) ? stderr : stdout, "LIB: %s", data); +} + static bool mk_host_if_init(struct mk_host_if *acmd, const GUID *guid, bool reconnect, bool verbose) { - acmd->reconnect = reconnect; - acmd->verbose = verbose; #ifdef WIN32 - TeeInitGUID(&acmd->mei_cl, guid, &GUID_DEVINTERFACE_HECI_GSC_CHILD); +#define ADDR_NUM 1 + struct tee_device_address addr[ADDR_NUM] = { + { + .type = TEE_DEVICE_TYPE_GUID, + .data.guid = &GUID_DEVINTERFACE_HECI_GSC_CHILD + } + }; #else - TeeInit(&acmd->mei_cl, guid, NULL); +#define ADDR_NUM 3 + struct tee_device_address addr[ADDR_NUM] = { + { + .type = TEE_DEVICE_TYPE_PATH, + .data.path = "/dev/mei0" + }, + { + .type = TEE_DEVICE_TYPE_PATH, + .data.path = "/dev/mei1" + }, + { + .type = TEE_DEVICE_TYPE_PATH, + .data.path = "/dev/mei2" + }, + }; #endif /* WIN32 */ - return mk_host_if_connect(acmd); + + acmd->reconnect = reconnect; + acmd->verbose = verbose; + for (size_t i = 0; i < ADDR_NUM; i++) { + if (TeeInitFull2(&acmd->mei_cl, guid, addr[i], + (verbose) ? TEE_LOG_LEVEL_VERBOSE : TEE_LOG_LEVEL_ERROR, + mk_host_if_log) != TEE_SUCCESS) + return false; + + if (!mk_host_if_is_gscfi(acmd)) { + TeeDisconnect(&acmd->mei_cl); + continue; + } + mk_host_if_fw_status(acmd); + return mk_host_if_connect(acmd); + } + return false; } static void mk_host_if_deinit(struct mk_host_if *acmd) diff --git a/samples/meteepp_basic.cpp b/samples/meteepp_basic.cpp new file mode 100644 index 0000000..8fb128b --- /dev/null +++ b/samples/meteepp_basic.cpp @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include +#include +#include + +DEFINE_GUID(MEI_MKHIF, 0x8e6a6715, 0x9abc, 0x4043, + 0x88, 0xef, 0x9e, 0x39, 0xc6, 0xf6, 0x3e, 0x0f); + +static const uint32_t MKHI_TIMEOUT = 10000; +static const int CONNECT_RETRIES = 3; + +#pragma pack(1) +struct mkhi_msg_hdr { + union { + uint32_t data; + struct { + uint32_t GroupId : 8; + uint32_t Command : 7; + uint32_t IsResponse : 1; + uint32_t Reserved : 8; + uint32_t Result : 8; + }; + }; +}; + +struct mkhi_fwver_req { + struct mkhi_msg_hdr header; +}; + +struct mkhi_fw_version_block { + uint16_t minor; + uint16_t major; + uint16_t buildNo; + uint16_t hotFix; +}; + +struct mkhi_fw_version { + struct mkhi_fw_version_block code; + struct mkhi_fw_version_block NFTP; + struct mkhi_fw_version_block FITC; +}; + +struct mkhi_fwver_rsp { + struct mkhi_msg_hdr header; + struct mkhi_fw_version version; +}; +#pragma pack() + +int main(int argc, char* argv[]) +{ + int retry = CONNECT_RETRIES; + + try { + intel::security::metee metee(MEI_MKHIF, TEE_LOG_LEVEL_VERBOSE); + + try { + std::cout << "Device kind is " << metee.kind() << std::endl; + } + catch (const intel::security::metee_exception& ex) { + std::cerr << ex.what() << std::endl; + } + + while (retry--) { + try { + metee.connect(); + break; + } + catch (const intel::security::metee_exception& ex) { + if (ex.code().value() != TEE_BUSY && + ex.code().value() != TEE_UNABLE_TO_COMPLETE_OPERATION) /* windows return this error on busy */ + throw; + std::cerr << "Client is busy, retrying" << std::endl; + } + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + } + + if (metee.max_msg_len() == 0) + { + std::cerr << "Client reported zero MTU. Aborting." << std::endl; + return 1; + } + + struct mkhi_fwver_req req; + uint8_t* u = reinterpret_cast(&req); + /* Write */ + req.header.data = 0; /* Reset */ + req.header.GroupId = 0xFF; /* MKHI */ + req.header.Command = 0x02; /* GET FW Version */ + req.header.IsResponse = 0; + req.header.Reserved = 0; + + size_t written = metee.write(std::vector(u, u + sizeof req), MKHI_TIMEOUT); + if (written != sizeof(req)) { + std::cerr << "Write failed written " << written << std::endl; + return 1; + } + + std::vector res = metee.read(MKHI_TIMEOUT); + if (res.size() < sizeof(struct mkhi_msg_hdr)) { + std::cerr << "Returned less than header = " << res.size() << std::endl; + return 1; + } + + if (res.size() < sizeof(struct mkhi_fwver_rsp)) { + std::cerr << "Returned less than response = " << res.size() << std::endl; + return 1; + } + + struct mkhi_fwver_rsp* rsp; + rsp = reinterpret_cast(res.data()); + + + if (rsp->header.Result) { + std::cerr << "Result = " << rsp->header.Result << std::endl; + return 1; + } + + std::cout << "Version: " << rsp->version.code.major << "." << rsp->version.code.minor << "." + << rsp->version.code.hotFix << "." << rsp->version.code.buildNo << std::endl; + + return 0; + } + catch (const intel::security::metee_exception& ex) { + std::cerr << ex.what() << std::endl; + return 1; + } +} diff --git a/src/linux/libmei.h b/src/linux/libmei.h index c81f8d3..c4e10ff 100644 --- a/src/linux/libmei.h +++ b/src/linux/libmei.h @@ -46,6 +46,7 @@ enum mei_cl_state { MEI_CL_STATE_NOT_PRESENT, /**< client with GUID is not present in the system */ MEI_CL_STATE_VERSION_MISMATCH, /**< client version not supported */ MEI_CL_STATE_ERROR, /**< client is in error state */ + MEI_CL_STATE_DISABLED, /**< client is in disabled state */ }; /*! log level diff --git a/src/linux/mei.c b/src/linux/mei.c index 3a500ce..d48245f 100644 --- a/src/linux/mei.c +++ b/src/linux/mei.c @@ -394,13 +394,14 @@ static inline int __mei_getkind(struct mei *me, const char *device, char *kind, } *kind_size = (size_t)len; memcpy(kind, buf, (size_t)len); + kind[len - 1] = '\0'; return 0; #undef KIND_FILENAME_LEN #undef KIND_LEN } -static int mei_init_with_log_int(struct mei *me, const char *device, const uuid_le *guid, +static int __mei_init_with_log_int(struct mei *me, const char *device, const uuid_le *guid, unsigned char req_protocol_version, bool verbose, mei_log_callback log_callback, mei_log_callback2 log_callback2) { @@ -425,13 +426,18 @@ static int mei_init_with_log_int(struct mei *me, const char *device, const uuid_ rc = __mei_open(me, device); if (rc < 0) { - mei_err(me, "Cannot establish a handle to the Intel MEI driver %.20s [%d]:%s\n", + if (rc != -ENODEV) { + mei_err(me, "Cannot establish a handle to the Intel MEI driver %.20s [%d]:%s\n", + device, rc, strerror(-rc)); + return rc; + } + mei_msg(me, "Intel MEI driver %.20s returned [%d]:%s\n", device, rc, strerror(-rc)); - return rc; + me->state = MEI_CL_STATE_DISABLED; + } else { + mei_msg(me, "Opened %.20s: fd = %d\n", device, me->fd); + me->state = MEI_CL_STATE_INITIALIZED; } - - mei_msg(me, "Opened %.20s: fd = %d\n", device, me->fd); - memcpy(&me->guid, guid, sizeof(*guid)); me->prot_ver = req_protocol_version; me->device = strdup(device); @@ -440,8 +446,6 @@ static int mei_init_with_log_int(struct mei *me, const char *device, const uuid_ return -ENOMEM; } - me->state = MEI_CL_STATE_INITIALIZED; - return 0; } @@ -449,7 +453,7 @@ int mei_init_with_log(struct mei *me, const char *device, const uuid_le *guid, unsigned char req_protocol_version, bool verbose, mei_log_callback log_callback) { - return mei_init_with_log_int(me, device, guid, + return __mei_init_with_log_int(me, device, guid, req_protocol_version, verbose, log_callback, NULL); } @@ -457,7 +461,7 @@ int mei_init_with_log2(struct mei *me, const char *device, const uuid_le *guid, unsigned char req_protocol_version, bool verbose, mei_log_callback2 log_callback) { - return mei_init_with_log_int(me, device, guid, + return __mei_init_with_log_int(me, device, guid, req_protocol_version, verbose, NULL, log_callback); } @@ -610,6 +614,11 @@ static int __int_mei_connect(struct mei *me, uint8_t vtag) return -EINVAL; } + if (me->state == MEI_CL_STATE_DISABLED) { + mei_err(me, "client is disabled\n"); + return -EINVAL; + } + me->vtag = vtag; if (me->vtag) { memset(&data_v, 0, sizeof(data_v)); @@ -665,6 +674,11 @@ ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer, size_t len) if (!me || !buffer) return -EINVAL; + if (me->state != MEI_CL_STATE_CONNECTED) { + mei_err(me, "client is not connected [%d]\n", me->state); + return -EINVAL; + } + mei_msg(me, "call read length = %zu\n", len); rc = __mei_read(me, buffer, len); @@ -686,6 +700,11 @@ ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer, size_t len) if (!me || !buffer) return -EINVAL; + if (me->state != MEI_CL_STATE_CONNECTED) { + mei_err(me, "client is not connected [%d]\n", me->state); + return -EINVAL; + } + mei_msg(me, "call write length = %zu\n", len); mei_dump_hex_buffer(me, buffer, len); diff --git a/tests/meteepp_test.cpp b/tests/meteepp_test.cpp index 6cbc30b..8e72ed7 100644 --- a/tests/meteepp_test.cpp +++ b/tests/meteepp_test.cpp @@ -66,7 +66,7 @@ TEST_P(MeTeePPTEST, PROD_MKHI_InitFull) try { struct tee_device_address device = {tee_device_address::TEE_DEVICE_TYPE_NONE, { NULL }}; - intel::security::metee metee(*intf.client, device, TEE_LOG_LEVEL_VERBOSE, NULL); + intel::security::metee metee(*intf.client, device, TEE_LOG_LEVEL_VERBOSE); ASSERT_NE(TEE_INVALID_DEVICE_HANDLE, metee.device_handle()); metee.connect();