diff --git a/CMakeLists.txt b/CMakeLists.txt index 52be204..b9a8f35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,8 @@ message(STATUS "Platform: ${CX_PLATFORM}") set(FILENAME_DEP_REPLACE "get_filename_component(SELF_DIR \"$\{CMAKE_CURRENT_LIST_FILE\}\" PATH)") set(SELF_DIR "$\{SELF_DIR\}") +enable_testing() + option(CXPLAT_BUILD_TEST "Builds the test code" OFF) option(CXPLAT_UWP_BUILD "Build for UWP" OFF) option(CXPLAT_GAMECORE_BUILD "Build for GameCore" OFF) @@ -93,9 +95,7 @@ if (CXPLAT_UWP_BUILD OR CXPLAT_GAMECORE_BUILD) set(CXPLAT_BUILD_TEST OFF) endif() -if (NOT CXPLAT_BUILD_SHARED) - cmake_minimum_required(VERSION 3.20) -endif() +cmake_minimum_required(VERSION 3.20) if (CXPLAT_PDBALTPATH AND MSVC) # Disabled in all cases because generation is broken. @@ -131,6 +131,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CXPLAT_OUTPUT_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CXPLAT_OUTPUT_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CXPLAT_OUTPUT_DIR}) +set(CXPLAT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/inc) + if (WIN32) set(CXPLAT_WARNING_FLAGS /WX /W4 /sdl /wd4206 CACHE INTERNAL "") set(CXPLAT_COMMON_FLAGS "") @@ -168,14 +170,26 @@ else() include(CheckSymbolExists) include(CheckFunctionExists) include(CheckIncludeFile) + check_symbol_exists(_SC_PHYS_PAGES unistd.h HAS__SC_PHYS_PAGES) + check_function_exists(sysconf HAS_SYSCONF) if (CX_PLATFORM STREQUAL "linux") include(CheckCCompilerFlag) + elseif(CX_PLATFORM STREQUAL "darwin") + check_function_exists(sysctl HAS_SYSCTL) endif() set(CXPLAT_COMMON_FLAGS "") set(CXPLAT_COMMON_DEFINES _GNU_SOURCE) - + if (HAS__SC_PHYS_PAGES) + list(APPEND CXPLAT_COMMON_DEFINES HAS__SC_PHYS_PAGES) + endif() + if (HAS_SYSCONF) + list(APPEND CXPLAT_COMMON_DEFINES HAS_SYSCONF) + endif() + if (HAS_SYSCTL) + list(APPEND CXPLAT_COMMON_DEFINES HAS_SYSCTL) + endif() set(CXPLAT_WARNING_FLAGS -Werror -Wall -Wextra -Wformat=2 -Wno-type-limits -Wno-unknown-pragmas -Wno-multichar -Wno-missing-field-initializers CACHE INTERNAL "") @@ -347,6 +361,8 @@ else() #!WIN32 set(CXPLAT_CXX_FLAGS ${CXPLAT_COMMON_FLAGS}) endif() +add_subdirectory(src/inc) + # Product code add_subdirectory(src/lib/) diff --git a/inc/cxplat.h b/inc/cxplat.h index 252e0be..1298741 100644 --- a/inc/cxplat.h +++ b/inc/cxplat.h @@ -20,3 +20,33 @@ #else #error "Unsupported Platform" #endif + +#if defined(__cplusplus) +extern "C" { +#endif + +// +// Initializes the cxplat library. Calls to this and CxPlatUninitialize must be +// serialized and cannot overlap. +// +PAGEDX +_IRQL_requires_max_(PASSIVE_LEVEL) +CXPLAT_STATUS +CxPlatInitialize( + void + ); + +// +// Uninitializes the cxplat library. Calls to this and CxPlatInitialize must be +// serialized and cannot overlap. +// +PAGEDX +_IRQL_requires_max_(PASSIVE_LEVEL) +void +CxPlatUninitialize( + void + ); + +#if defined(__cplusplus) +} +#endif diff --git a/inc/cxplat_posix.h b/inc/cxplat_posix.h index 7a3e858..d35e376 100644 --- a/inc/cxplat_posix.h +++ b/inc/cxplat_posix.h @@ -12,12 +12,115 @@ #ifndef CXPLAT_POSIX_H #define CXPLAT_POSIX_H +// For FreeBSD +#if defined(__FreeBSD__) +#include +#include +#define ETIME ETIMEDOUT +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "cxplat_sal_stub.h" #if defined(__cplusplus) extern "C" { #endif +// +// Defines that are present on other platforms but not this one +// + +#define UNREFERENCED_PARAMETER(P) (void)(P) + +// +// Status Codes +// + +#define CXPLAT_STATUS unsigned int +#define CXPLAT_FAILED(X) ((int)(X) > 0) +#define CXPLAT_SUCCEEDED(X) ((int)(X) <= 0) + +#define CXPLAT_STATUS_SUCCESS ((CXPLAT_STATUS)0) // 0 + +// +// Code Annotations +// + +#define INITCODE +#define PAGEDX + +// +// Static Analysis Interfaces +// + +#if defined(__clang__) +#define CXPLAT_NO_SANITIZE(X) __attribute__((no_sanitize(X))) +#else +#define CXPLAT_NO_SANITIZE(X) +#endif + +#define CXPLAT_ANALYSIS_ASSERT(X) +#define CXPLAT_ANALYSIS_ASSUME(X) + +// +// Assertion Interfaces +// + +__attribute__((noinline, noreturn)) +void +cxplat_bugcheck( + _In_z_ const char* File, + _In_ int Line, + _In_z_ const char* Expr + ); + +void +CxPlatLogAssert( + _In_z_ const char* File, + _In_ int Line, + _In_z_ const char* Expr + ); + +#define CXPLAT_STATIC_ASSERT(X,Y) static_assert(X, Y); + +#define CXPLAT_FRE_ASSERT(exp) ((exp) ? (void)0 : (CxPlatLogAssert(__FILE__, __LINE__, #exp), cxplat_bugcheck(__FILE__, __LINE__, #exp))); +#define CXPLAT_FRE_ASSERTMSG(exp, Y) CXPLAT_FRE_ASSERT(exp) + +#ifdef DEBUG +#define CXPLAT_DBG_ASSERT(exp) CXPLAT_FRE_ASSERT(exp) +#define CXPLAT_DBG_ASSERTMSG(exp, msg) CXPLAT_FRE_ASSERT(exp) +#else +#define CXPLAT_DBG_ASSERT(exp) +#define CXPLAT_DBG_ASSERTMSG(exp, msg) +#endif + +// +// Crypto Interfaces +// + +CXPLAT_STATUS +CxPlatRandom( + _In_ uint32_t BufferLen, + _Out_writes_bytes_(BufferLen) void* Buffer + ); #if defined(__cplusplus) } diff --git a/inc/cxplat_winkernel.h b/inc/cxplat_winkernel.h index 5d410e1..e0cae0a 100644 --- a/inc/cxplat_winkernel.h +++ b/inc/cxplat_winkernel.h @@ -12,10 +12,128 @@ #ifndef CXPLAT_WINKERNEL_H #define CXPLAT_WINKERNEL_H +#include + #if defined(__cplusplus) extern "C" { #endif +// +// Defines that are present on other platforms but not this one +// + +typedef INT8 int8_t; +typedef INT16 int16_t; +typedef INT32 int32_t; +typedef INT64 int64_t; + +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef UINT32 uint32_t; +typedef UINT64 uint64_t; + +// +// Status Codes +// + +#define CXPLAT_STATUS NTSTATUS +#define CXPLAT_FAILED(X) (!NT_SUCCESS(X)) +#define CXPLAT_SUCCEEDED(X) NT_SUCCESS(X) + +#define CXPLAT_STATUS_SUCCESS STATUS_SUCCESS // 0x0 + +// +// Code Annotations +// + +#ifndef KRTL_INIT_SEGMENT +#define KRTL_INIT_SEGMENT "INIT" +#endif +#ifndef KRTL_PAGE_SEGMENT +#define KRTL_PAGE_SEGMENT "PAGE" +#endif +#ifndef KRTL_NONPAGED_SEGMENT +#define KRTL_NONPAGED_SEGMENT ".text" +#endif + +// Use on code in the INIT segment. (Code is discarded after DriverEntry returns.) +#define INITCODE __declspec(code_seg(KRTL_INIT_SEGMENT)) + +// Use on pageable functions. +#define PAGEDX __declspec(code_seg(KRTL_PAGE_SEGMENT)) + +// +// Static Analysis Interfaces +// + +#define CXPLAT_NO_SANITIZE(X) + +#if defined(_PREFAST_) +// _Analysis_assume_ will never result in any code generation for _exp, +// so using it will not have runtime impact, even if _exp has side effects. +#define CXPLAT_ANALYSIS_ASSUME(_exp) _Analysis_assume_(_exp) +#else // _PREFAST_ +// CXPLAT_ANALYSIS_ASSUME ensures that _exp is parsed in non-analysis compile. +// On DEBUG, it's guaranteed to be parsed as part of the normal compile, but +// with non-DEBUG, use __noop to ensure _exp is parseable but without code +// generation. +#if DEBUG +#define CXPLAT_ANALYSIS_ASSUME(_exp) ((void) 0) +#else // DEBUG +#define CXPLAT_ANALYSIS_ASSUME(_exp) __noop(_exp) +#endif // DEBUG +#endif // _PREFAST_ + +#define CXPLAT_ANALYSIS_ASSERT(X) __analysis_assert(X) + +// +// Assertion Interfaces +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +CxPlatLogAssert( + _In_z_ const char* File, + _In_ int Line, + _In_z_ const char* Expr + ); + +#define CXPLAT_WIDE_STRING(_str) L##_str + +#define CXPLAT_ASSERT_NOOP(_exp, _msg) \ + (CXPLAT_ANALYSIS_ASSUME(_exp), 0) + +#define CXPLAT_ASSERT_CRASH(_exp, _msg) \ + (CXPLAT_ANALYSIS_ASSUME(_exp), \ + ((!(_exp)) ? \ + (CxPlatLogAssert(__FILE__, __LINE__, #_exp), \ + __annotation(L"Debug", L"AssertFail", _msg), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE)) + +#define CXPLAT_STATIC_ASSERT(X,Y) static_assert(X,Y) + +#define CXPLAT_FRE_ASSERT(_exp) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(#_exp)) +#define CXPLAT_FRE_ASSERTMSG(_exp, _msg) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(_msg)) + +#if DEBUG +#define CXPLAT_DBG_ASSERT(_exp) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(#_exp)) +#define CXPLAT_DBG_ASSERTMSG(_exp, _msg) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(_msg)) +#else +#define CXPLAT_DBG_ASSERT(_exp) CXPLAT_ASSERT_NOOP(_exp, CXPLAT_WIDE_STRING(#_exp)) +#define CXPLAT_DBG_ASSERTMSG(_exp, _msg) CXPLAT_ASSERT_NOOP(_exp, CXPLAT_WIDE_STRING(_msg)) +#endif + +// +// Crypto Interfaces +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +CXPLAT_STATUS +CxPlatRandom( + _In_ uint32_t BufferLen, + _Out_writes_bytes_(BufferLen) void* Buffer + ); #if defined(__cplusplus) } diff --git a/inc/cxplat_winuser.h b/inc/cxplat_winuser.h index 9213264..7795d95 100644 --- a/inc/cxplat_winuser.h +++ b/inc/cxplat_winuser.h @@ -12,10 +12,110 @@ #ifndef CXPLAT_WINUSER_H #define CXPLAT_WINUSER_H +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif + +#include +#include + #if defined(__cplusplus) extern "C" { #endif +// +// Status Codes +// + +#define CXPLAT_STATUS HRESULT +#define CXPLAT_FAILED(X) FAILED(X) +#define CXPLAT_SUCCEEDED(X) SUCCEEDED(X) + +#define CXPLAT_STATUS_SUCCESS S_OK // 0x0 + +// +// Code Annotations +// + +#define INITCODE +#define PAGEDX + +// +// Static Analysis Interfaces +// + +#define CXPLAT_NO_SANITIZE(X) + +#if defined(_PREFAST_) +// _Analysis_assume_ will never result in any code generation for _exp, +// so using it will not have runtime impact, even if _exp has side effects. +#define CXPLAT_ANALYSIS_ASSUME(_exp) _Analysis_assume_(_exp) +#else // _PREFAST_ +// CXPLAT_ANALYSIS_ASSUME ensures that _exp is parsed in non-analysis compile. +// On DEBUG, it's guaranteed to be parsed as part of the normal compile, but +// with non-DEBUG, use __noop to ensure _exp is parseable but without code +// generation. +#if DEBUG +#define CXPLAT_ANALYSIS_ASSUME(_exp) ((void) 0) +#else // DEBUG +#define CXPLAT_ANALYSIS_ASSUME(_exp) __noop(_exp) +#endif // DEBUG +#endif // _PREFAST_ + +#define CXPLAT_ANALYSIS_ASSERT(X) __analysis_assert(X) + +// +// Assertion Interfaces +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +CxPlatLogAssert( + _In_z_ const char* File, + _In_ int Line, + _In_z_ const char* Expr + ); + +#define CXPLAT_WIDE_STRING(_str) L##_str + +#define CXPLAT_ASSERT_NOOP(_exp, _msg) \ + (CXPLAT_ANALYSIS_ASSUME(_exp), 0) + +#define CXPLAT_ASSERT_CRASH(_exp, _msg) \ + (CXPLAT_ANALYSIS_ASSUME(_exp), \ + ((!(_exp)) ? \ + (CxPlatLogAssert(__FILE__, __LINE__, #_exp), \ + __annotation(L"Debug", L"AssertFail", _msg), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE)) + +#ifdef __clang__ +#define CXPLAT_STATIC_ASSERT(X,Y) _Static_assert(X,Y) +#else +#define CXPLAT_STATIC_ASSERT(X,Y) static_assert(X,Y) +#endif + +#define CXPLAT_FRE_ASSERT(_exp) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(#_exp)) +#define CXPLAT_FRE_ASSERTMSG(_exp, _msg) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(_msg)) + +#if DEBUG +#define CXPLAT_DBG_ASSERT(_exp) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(#_exp)) +#define CXPLAT_DBG_ASSERTMSG(_exp, _msg) CXPLAT_ASSERT_CRASH(_exp, CXPLAT_WIDE_STRING(_msg)) +#else +#define CXPLAT_DBG_ASSERT(_exp) CXPLAT_ASSERT_NOOP(_exp, CXPLAT_WIDE_STRING(#_exp)) +#define CXPLAT_DBG_ASSERTMSG(_exp, _msg) CXPLAT_ASSERT_NOOP(_exp, CXPLAT_WIDE_STRING(_msg)) +#endif + +// +// Crypto Interfaces +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +CXPLAT_STATUS +CxPlatRandom( + _In_ uint32_t BufferLen, + _Out_writes_bytes_(BufferLen) void* Buffer + ); #if defined(__cplusplus) } diff --git a/src/inc/CMakeLists.txt b/src/inc/CMakeLists.txt new file mode 100644 index 0000000..ce34348 --- /dev/null +++ b/src/inc/CMakeLists.txt @@ -0,0 +1,57 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# Base target for all other targets. Ensures all arguments required are correctly set + +add_library(inc INTERFACE) + +target_compile_options(inc INTERFACE ${CXPLAT_C_FLAGS}) +target_compile_options(inc INTERFACE $<$:${CXPLAT_CXX_FLAGS}>) + +target_compile_definitions(inc INTERFACE ${CXPLAT_COMMON_DEFINES}) +target_include_directories(inc INTERFACE ${CXPLAT_INCLUDE_DIR}) + +target_compile_features(inc INTERFACE cxx_std_17) +target_compile_features(inc INTERFACE c_std_11) + +add_library(base_link INTERFACE) + +if (HAS_GUARDCF) + target_link_options(base_link INTERFACE /guard:cf /DYNAMICBASE) +endif() + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +target_link_libraries(base_link INTERFACE Threads::Threads ${CMAKE_DL_LIBS}) + +if (ATOMIC) + target_link_libraries(base_link INTERFACE ${ATOMIC}) +endif() + +if (NUMA) + target_link_libraries(base_link INTERFACE ${NUMA}) +endif() + +if(WIN32) + if(CXPLAT_UWP_BUILD) + target_link_libraries(base_link INTERFACE OneCore ws2_32 ntdll) + elseif(CXPLAT_GAMECORE_BUILD) + target_link_options(inc INTERFACE ${Console_LinkOptions}) + target_compile_options(inc INTERFACE ${Console_ArchOptions}) + target_link_directories(inc INTERFACE ${Console_EndpointLibRoot}) + target_link_libraries(base_link INTERFACE xgameplatform ntdll advapi32) + else() + target_link_libraries(base_link INTERFACE bcrypt) + endif() + if (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") + target_link_libraries(base_link INTERFACE softintrin) + endif() +endif() + +add_library(warnings INTERFACE) +target_compile_options(warnings INTERFACE ${CXPLAT_WARNING_FLAGS}) + +add_library(main_binary_link_args INTERFACE) +if (WIN32) + target_compile_options(main_binary_link_args INTERFACE /Zl) +endif() diff --git a/src/inc/cxplat_trace.h b/src/inc/cxplat_trace.h new file mode 100644 index 0000000..b438355 --- /dev/null +++ b/src/inc/cxplat_trace.h @@ -0,0 +1,8 @@ +#pragma once + +#define CxPlatTraceLogError(Fmt, ...) +#define CxPlatTraceLogWarning(Fmt, ...) +#define CxPlatTraceLogInfo(Fmt, ...) +#define CxPlatTraceLogVerbose(Fmt, ...) + +#define CxPlatTraceEvent(Fmt, ...) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 7d1ff22..26f0821 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -9,6 +9,12 @@ endif() add_library(cxplat STATIC ${SOURCES}) -target_include_directories(cxplat PRIVATE ${PROJECT_SOURCE_DIR}/inc) +target_link_libraries(cxplat PUBLIC inc) + +target_link_libraries(cxplat PRIVATE warnings main_binary_link_args) + +set_property(TARGET cxplat PROPERTY FOLDER "${CXPLAT_FOLDER_PREFIX}libraries") + +target_include_directories(cxplat PRIVATE ${PROJECT_SOURCE_DIR}/inc ${PROJECT_SOURCE_DIR}/src/inc) target_compile_definitions(cxplat INTERFACE ${CXPLAT_COMMON_DEFINES}) diff --git a/src/lib/cxplat.kernel.vcxproj b/src/lib/cxplat.kernel.vcxproj index e52687b..070613b 100644 --- a/src/lib/cxplat.kernel.vcxproj +++ b/src/lib/cxplat.kernel.vcxproj @@ -23,6 +23,7 @@ + {1e494654-9bfd-492f-bc31-36e2c73a782e} @@ -74,7 +75,7 @@ - $(SolutionDir)inc;%(AdditionalIncludeDirectories) + $(SolutionDir)inc;$(SolutionDir)\src\inc;%(AdditionalIncludeDirectories) Speed true /Gw /kernel /ZH:SHA_256 diff --git a/src/lib/cxplat_posix.c b/src/lib/cxplat_posix.c index 85f53ec..0da674d 100644 --- a/src/lib/cxplat_posix.c +++ b/src/lib/cxplat_posix.c @@ -1 +1,111 @@ #include "cxplat_posix.h" +#include "cxplat_trace.h" + +// For FreeBSD +#if defined(__FreeBSD__) +#include +#endif +#include +#include +#include +#include +#include + +// +// Used for reading random numbers. +// +int RandomFd = -1; + +#ifdef __clang__ +__attribute__((noinline, noreturn, optnone)) +#else +__attribute__((noinline, noreturn, optimize("O0"))) +#endif +void +cxplat_bugcheck( + _In_z_ const char* File, + _In_ int Line, + _In_z_ const char* Expr + ) +{ + // + // Pass in the error info so it can be seen in the debugger. + // + UNREFERENCED_PARAMETER(File); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(Expr); + + // + // We want to prevent this routine from being inlined so that we can + // easily detect when our bugcheck conditions have occurred just by + // looking at callstack. However, even after specifying inline attribute, + // it is possible certain optimizations will cause inlining. asm technique + // is the gcc documented way to prevent such optimizations. + // + asm(""); + + // + // abort() sends a SIGABRT signal and it triggers termination and coredump. + // + abort(); +} + +void +CxPlatLogAssert( + _In_z_ const char* File, + _In_ int Line, + _In_z_ const char* Expr + ) +{ + UNREFERENCED_PARAMETER(File); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(Expr); + + CxPlatTraceEvent( + "[ lib] ASSERT, %u:%s - %s.", + (uint32_t)Line, + File, + Expr); +} + +CXPLAT_STATUS +CxPlatInitialize( + void + ) +{ + RandomFd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); + if (RandomFd == -1) { + CxPlatTraceEvent( + "[ lib] ERROR, %u, %s.", + errno, + "open(/dev/urandom, O_RDONLY|O_CLOEXEC) failed"); + return (CXPLAT_STATUS)errno; + } + + CxPlatTraceLogInfo( + "[ dso] Initialized"); + + return CXPLAT_STATUS_SUCCESS; +} + +void +CxPlatUninitialize( + void + ) +{ + close(RandomFd); + CxPlatTraceLogInfo( + "[ dso] Uninitialized"); +} + +CXPLAT_STATUS +CxPlatRandom( + _In_ uint32_t BufferLen, + _Out_writes_bytes_(BufferLen) void* Buffer + ) +{ + if (read(RandomFd, Buffer, BufferLen) == -1) { + return (CXPLAT_STATUS)errno; + } + return CXPLAT_STATUS_SUCCESS; +} diff --git a/src/lib/cxplat_winkernel.c b/src/lib/cxplat_winkernel.c index 2f8eb86..2213966 100644 --- a/src/lib/cxplat_winkernel.c +++ b/src/lib/cxplat_winkernel.c @@ -1 +1,84 @@ #include "cxplat_winkernel.h" +#include "cxplat_trace.h" +#include + +typedef struct CX_PLATFORM { + // + // Random number algorithm loaded for DISPATCH_LEVEL usage. + // + BCRYPT_ALG_HANDLE RngAlgorithm; +} CX_PLATFORM; + +CX_PLATFORM CxPlatform = { NULL }; + +PAGEDX +_IRQL_requires_max_(PASSIVE_LEVEL) +CXPLAT_STATUS +CxPlatInitialize( + void + ) +{ + PAGED_CODE(); + + CXPLAT_STATUS Status = + BCryptOpenAlgorithmProvider( + &CxPlatform.RngAlgorithm, + BCRYPT_RNG_ALGORITHM, + NULL, + BCRYPT_PROV_DISPATCH); + if (CXPLAT_FAILED(Status)) { + CxPlatTraceEvent( + "[ lib] ERROR, %u, %s.", + Status, + "BCryptOpenAlgorithmProvider (RNG)"); + goto Error; + } + CXPLAT_DBG_ASSERT(CxPlatform.RngAlgorithm != NULL); + + CxPlatTraceLogInfo( + "[ sys] Initialized"); + +Error: + + if (CXPLAT_FAILED(Status)) { + if (CxPlatform.RngAlgorithm != NULL) { + BCryptCloseAlgorithmProvider(CxPlatform.RngAlgorithm, 0); + CxPlatform.RngAlgorithm = NULL; + } + } + + return Status; +} + +PAGEDX +_IRQL_requires_max_(PASSIVE_LEVEL) +void +CxPlatUninitialize( + void + ) +{ + PAGED_CODE(); + BCryptCloseAlgorithmProvider(CxPlatform.RngAlgorithm, 0); + CxPlatform.RngAlgorithm = NULL; + CxPlatTraceLogInfo( + "[ sys] Uninitialized"); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +CXPLAT_STATUS +CxPlatRandom( + _In_ uint32_t BufferLen, + _Out_writes_bytes_(BufferLen) void* Buffer + ) +{ + // + // Use the algorithm we initialized for DISPATCH_LEVEL usage. + // + CXPLAT_DBG_ASSERT(CxPlatform.RngAlgorithm != NULL); + return (CXPLAT_STATUS) + BCryptGenRandom( + CxPlatform.RngAlgorithm, + (uint8_t*)Buffer, + BufferLen, + 0); +} diff --git a/src/lib/cxplat_winuser.c b/src/lib/cxplat_winuser.c index ae9fc44..b6a19f3 100644 --- a/src/lib/cxplat_winuser.c +++ b/src/lib/cxplat_winuser.c @@ -1 +1,43 @@ #include "cxplat_winuser.h" +#include "cxplat_trace.h" +#include + +_IRQL_requires_max_(PASSIVE_LEVEL) +CXPLAT_STATUS +CxPlatInitialize( + void + ) +{ + CxPlatTraceLogInfo( + "[ dll] Initialized"); + + return CXPLAT_STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +CxPlatUninitialize( + void + ) +{ + CxPlatTraceLogInfo( + "[ dll] Uninitialized"); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +CXPLAT_STATUS +CxPlatRandom( + _In_ uint32_t BufferLen, + _Out_writes_bytes_(BufferLen) void* Buffer + ) +{ + // + // Just use the system-preferred random number generator algorithm. + // + return (CXPLAT_STATUS) + BCryptGenRandom( + NULL, + (uint8_t*)Buffer, + BufferLen, + BCRYPT_USE_SYSTEM_PREFERRED_RNG); +} diff --git a/src/test/CxPlatTests.h b/src/test/CxPlatTests.h index 2dbe3f4..e3d38fc 100644 --- a/src/test/CxPlatTests.h +++ b/src/test/CxPlatTests.h @@ -17,10 +17,10 @@ void CxPlatTestInitialize(); void CxPlatTestUninitialize(); // -// Dummy Tests +// Crypt Tests // -void CxPlatTestDummy(); +void CxPlatTestCryptRandom(); // @@ -77,7 +77,7 @@ static const GUID CXPLAT_TEST_DEVICE_INSTANCE = // IOCTL Interface // -#define IOCTL_CXPLAT_RUN_DUMMY \ +#define IOCTL_CXPLAT_RUN_CRYPT_RANDOM \ CXPLAT_CTL_CODE(1, METHOD_BUFFERED, FILE_WRITE_DATA) #define CXPLAT_MAX_IOCTL_FUNC_CODE 1 diff --git a/src/test/bin/CMakeLists.txt b/src/test/bin/CMakeLists.txt index f126780..b9a80fa 100644 --- a/src/test/bin/CMakeLists.txt +++ b/src/test/bin/CMakeLists.txt @@ -8,16 +8,14 @@ set(SOURCES add_executable(cxplattest ${SOURCES}) -target_include_directories(cxplattest PRIVATE ${PROJECT_SOURCE_DIR}/src/test ${PROJECT_SOURCE_DIR}/inc ${PROJECT_SOURCE_DIR}/submodules/googletest/googletest/include) - -target_compile_definitions(cxplattest INTERFACE ${CXPLAT_COMMON_DEFINES}) +target_include_directories(cxplattest PRIVATE ${PROJECT_SOURCE_DIR}/src/test ${PROJECT_SOURCE_DIR}/src/inc ${PROJECT_SOURCE_DIR}/submodules/googletest/googletest/include) set_property(TARGET cxplattest PROPERTY FOLDER "${CXPLAT_FOLDER_PREFIX}tests") set_property(TARGET cxplattest APPEND PROPERTY BUILD_RPATH "$ORIGIN") target_link_libraries(cxplattest cxplat testlib) -target_link_libraries(cxplattest gtest) - +target_link_libraries(cxplattest cxplat) +target_link_libraries(cxplattest inc gtest base_link) # At least /W3 must be used on all windows builds to pass compliance if(MSVC) diff --git a/src/test/bin/cxplat_driver_helpers.h b/src/test/bin/cxplat_driver_helpers.h index 1077857..719a68f 100644 --- a/src/test/bin/cxplat_driver_helpers.h +++ b/src/test/bin/cxplat_driver_helpers.h @@ -323,8 +323,6 @@ class CxPlatDriverClient { #else -#define UNREFERENCED_PARAMETER(param) - class CxPlatDriverService { public: bool Initialize( diff --git a/src/test/bin/cxplat_gtest.cpp b/src/test/bin/cxplat_gtest.cpp index 07a556c..5fac8a5 100644 --- a/src/test/bin/cxplat_gtest.cpp +++ b/src/test/bin/cxplat_gtest.cpp @@ -105,12 +105,12 @@ struct TestLoggerT { } }; -TEST(DummySuite, Dummy) { - TestLogger Logger("CxPlatTestDummy"); +TEST(CryptSuite, Random) { + TestLogger Logger("CxPlatTestCryptRandom"); if (TestingKernelMode) { - ASSERT_TRUE(DriverClient.Run(IOCTL_CXPLAT_RUN_DUMMY)); + ASSERT_TRUE(DriverClient.Run(IOCTL_CXPLAT_RUN_CRYPT_RANDOM)); } else { - CxPlatTestDummy(); + CxPlatTestCryptRandom(); } } diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 20d2f74..a91dedc 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -469,8 +469,8 @@ CxPlatTestCtlEvtIoDeviceControl( switch (IoControlCode) { - case IOCTL_CXPLAT_RUN_DUMMY: - CxPlatTestCtlRun(CxPlatTestDummy()); + case IOCTL_CXPLAT_RUN_CRYPT_RANDOM: + CxPlatTestCtlRun(CxPlatTestCryptRandom()); break; default: diff --git a/src/test/bin/winkernel/cxplattest.kernel.vcxproj b/src/test/bin/winkernel/cxplattest.kernel.vcxproj index 7393e3d..7f09c8a 100644 --- a/src/test/bin/winkernel/cxplattest.kernel.vcxproj +++ b/src/test/bin/winkernel/cxplattest.kernel.vcxproj @@ -77,7 +77,7 @@ - ..;..\..;$(SolutionDir)build\winkernel\$(Platform)_$(Configuration)\inc;$(IntDir);%(AdditionalIncludeDirectories) + ..;..\..;$(SolutionDir)src\inc;$(SolutionDir)build\winkernel\$(Platform)_$(Configuration)\inc;$(IntDir);%(AdditionalIncludeDirectories) Speed true /Gw /kernel /ZH:SHA_256 diff --git a/src/test/lib/CMakeLists.txt b/src/test/lib/CMakeLists.txt index 5c4c845..5703c0e 100644 --- a/src/test/lib/CMakeLists.txt +++ b/src/test/lib/CMakeLists.txt @@ -2,13 +2,13 @@ # Licensed under the MIT License. set(SOURCES - BasicTest.cpp + CryptTest.cpp ) add_library(testlib STATIC ${SOURCES}) -target_include_directories(testlib PRIVATE ${PROJECT_SOURCE_DIR}/src/test ${PROJECT_SOURCE_DIR}/inc) +target_include_directories(testlib PRIVATE ${PROJECT_SOURCE_DIR}/src/test) -target_compile_definitions(testlib PRIVATE ${CXPLAT_COMMON_DEFINES}) +target_link_libraries(testlib PRIVATE inc warnings) set_property(TARGET testlib PROPERTY FOLDER "${CXPLAT_FOLDER_PREFIX}tests") diff --git a/src/test/lib/CryptTest.cpp b/src/test/lib/CryptTest.cpp new file mode 100644 index 0000000..1c09ba3 --- /dev/null +++ b/src/test/lib/CryptTest.cpp @@ -0,0 +1,30 @@ +/*++ + + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. + +Abstract: + + Cryptography test. + +--*/ + +#include "precomp.h" + +void CxPlatTestInitialize() +{ + TEST_CXPLAT(CxPlatInitialize()); + return; +} + +void CxPlatTestUninitialize() +{ + CxPlatUninitialize(); + return; +} + +void CxPlatTestCryptRandom() +{ + uint32_t RandomValue = 0; + TEST_CXPLAT(CxPlatRandom(sizeof(RandomValue), &RandomValue)); +} diff --git a/src/test/lib/TestAbstractionLayer.h b/src/test/lib/TestAbstractionLayer.h index db81548..a17666a 100644 --- a/src/test/lib/TestAbstractionLayer.h +++ b/src/test/lib/TestAbstractionLayer.h @@ -42,10 +42,10 @@ } \ } -#define TEST_HRESULT(__condition) { \ - HRESULT __hr = __condition; \ - if (FAILED(__hr)) { \ - TEST_FAILURE(#__condition " failed, 0x%x", __hr); \ +#define TEST_CXPLAT(__condition) { \ + CXPLAT_STATUS __status = __condition; \ + if (CXPLAT_FAILED(__status)) { \ + TEST_FAILURE(#__condition " failed, 0x%x", __status); \ return; \ } \ } diff --git a/src/test/lib/testlib.kernel.vcxproj b/src/test/lib/testlib.kernel.vcxproj index f355192..197922a 100644 --- a/src/test/lib/testlib.kernel.vcxproj +++ b/src/test/lib/testlib.kernel.vcxproj @@ -19,7 +19,7 @@ - +