Module: wine Branch: master Commit: c722353c87da017df25cc9f42b49f0c9f4ce50fd URL: https://gitlab.winehq.org/wine/wine/-/commit/c722353c87da017df25cc9f42b49f0c...
Author: Alexandre Julliard julliard@winehq.org Date: Tue May 9 12:40:32 2023 +0200
ntdll: Support the ARM64EC code map.
---
dlls/ntdll/unix/env.c | 12 +++++- dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 86 +++++++++++++++++++++++++++++++++++++++++- include/winternl.h | 2 +- 4 files changed, 97 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 3c178350f2b..8b3b9bcd43f 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -1857,13 +1857,21 @@ static void init_peb( RTL_USER_PROCESS_PARAMETERS *params, void *module ) peb->ImageSubSystemMinorVersion = main_image_info.MinorSubsystemVersion;
#ifdef _WIN64 - if (main_image_info.Machine != current_machine) + switch (main_image_info.Machine) { + case IMAGE_FILE_MACHINE_I386: + case IMAGE_FILE_MACHINE_ARMNT: NtCurrentTeb()->WowTebOffset = teb_offset; NtCurrentTeb()->Tib.ExceptionList = (void *)((char *)NtCurrentTeb() + teb_offset); wow_peb = (PEB32 *)((char *)peb + page_size); - set_thread_id( NtCurrentTeb(), GetCurrentProcessId(), GetCurrentThreadId() ); + set_thread_id( NtCurrentTeb(), GetCurrentProcessId(), GetCurrentThreadId() ); ERR( "starting %s in experimental wow64 mode\n", debugstr_us(¶ms->ImagePathName) ); + break; + case IMAGE_FILE_MACHINE_AMD64: + if (main_image_info.Machine == current_machine) break; + peb->EcCodeBitMap = virtual_alloc_arm64ec_map(); + ERR( "starting %s in experimental ARM64EC mode\n", debugstr_us(¶ms->ImagePathName) ); + break; } #endif
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index e72b435c65a..d7b591e71f3 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -234,6 +234,7 @@ extern void virtual_free_teb( TEB *teb ) DECLSPEC_HIDDEN; extern NTSTATUS virtual_clear_tls_index( ULONG index ) DECLSPEC_HIDDEN; extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SIZE_T reserve_size, SIZE_T commit_size, BOOL guard_page ) DECLSPEC_HIDDEN; +extern void *virtual_alloc_arm64ec_map(void) DECLSPEC_HIDDEN; extern void virtual_map_user_shared_data(void) DECLSPEC_HIDDEN; extern NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack ) DECLSPEC_HIDDEN; extern unsigned int virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index b048d0f52d2..0908e6b60bd 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -175,6 +175,8 @@ static void *user_space_limit = (void *)0x7fff0000; static void *working_set_limit = (void *)0x7fff0000; #endif
+static UINT64 *arm64ec_map; + struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000;
/* TEB allocation blocks */ @@ -998,6 +1000,52 @@ static BOOL alloc_pages_vprot( const void *addr, size_t size ) }
+static inline UINT64 maskbits( size_t idx ) +{ + return ~(UINT64)0 << (idx & 63); +} + +/*********************************************************************** + * set_arm64ec_range + */ +#ifdef __aarch64__ +static void set_arm64ec_range( const void *addr, size_t size ) +{ + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; + size_t pos = idx / 64; + size_t end_pos = end / 64; + + if (end_pos > pos) + { + arm64ec_map[pos++] |= maskbits( idx ); + while (pos < end_pos) arm64ec_map[pos++] = ~(UINT64)0; + if (end & 63) arm64ec_map[pos] |= ~maskbits( end ); + } + else arm64ec_map[pos] |= maskbits( idx ) & ~maskbits( end ); +} +#endif + +/*********************************************************************** + * clear_arm64ec_range + */ +static void clear_arm64ec_range( const void *addr, size_t size ) +{ + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; + size_t pos = idx / 64; + size_t end_pos = end / 64; + + if (end_pos > pos) + { + arm64ec_map[pos++] &= ~maskbits( idx ); + while (pos < end_pos) arm64ec_map[pos++] = 0; + if (end & 63) arm64ec_map[pos] &= maskbits( end ); + } + else arm64ec_map[pos] &= ~maskbits( idx ) | maskbits( end ); +} + + /*********************************************************************** * compare_view * @@ -1526,6 +1574,7 @@ static void delete_view( struct file_view *view ) /* [in] View */ { if (!(view->protect & VPROT_SYSTEM)) unmap_area( view->base, view->size ); set_page_vprot( view->base, view->size, 0 ); + if (arm64ec_map) clear_arm64ec_range( view->base, view->size ); if (mmap_is_in_reserved_area( view->base, view->size )) free_ranges_remove_view( view ); wine_rb_remove( &views_tree, &view->entry ); @@ -2225,9 +2274,10 @@ static void apply_arm64x_relocations( char *base, const IMAGE_BASE_RELOCATION *r */ static void update_arm64x_mapping( char *base, IMAGE_NT_HEADERS *nt, IMAGE_SECTION_HEADER *sections ) { - ULONG size, sec, offset; + ULONG i, size, sec, offset; const IMAGE_DATA_DIRECTORY *dir; const IMAGE_LOAD_CONFIG_DIRECTORY *cfg; + const IMAGE_ARM64EC_METADATA *metadata; const IMAGE_DYNAMIC_RELOCATION_TABLE *table; const char *ptr, *end;
@@ -2239,6 +2289,21 @@ static void update_arm64x_mapping( char *base, IMAGE_NT_HEADERS *nt, IMAGE_SECTI cfg = (void *)(base + dir->VirtualAddress); size = min( dir->Size, cfg->Size );
+ /* update code ranges */ + + if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer )) return; + metadata = (void *)(base + (cfg->CHPEMetadataPointer - nt->OptionalHeader.ImageBase)); + if (metadata->CodeMap && arm64ec_map) + { + const IMAGE_CHPE_RANGE_ENTRY *map = (void *)(base + metadata->CodeMap); + + for (i = 0; i < metadata->CodeMapCount; i++) + { + if ((map[i].StartOffset & 0x3) != 1 /* arm64ec */) continue; + set_arm64ec_range( base + (map[i].StartOffset & ~3), map[i].Length ); + } + } + /* apply dynamic relocations */
if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, DynamicValueRelocTableSection )) return; @@ -3264,6 +3329,25 @@ done: }
+/*********************************************************************** + * virtual_alloc_arm64ec_map + */ +void *virtual_alloc_arm64ec_map(void) +{ +#ifdef __aarch64__ + SIZE_T size = ((ULONG_PTR)user_space_limit + page_size) >> (page_shift + 3); /* one bit per page */ + unsigned int status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&arm64ec_map, 0, &size, + MEM_COMMIT, PAGE_READWRITE ); + if (status) + { + ERR( "failed to allocate ARM64EC map: %08x\n", status ); + exit(1); + } +#endif + return arm64ec_map; +} + + /*********************************************************************** * virtual_map_user_shared_data */ diff --git a/include/winternl.h b/include/winternl.h index 04676fe4b99..5ee05097915 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -394,7 +394,7 @@ typedef struct _PEB ULONG FlsHighIndex; /* 22c/350 */ PVOID WerRegistrationData; /* 230/358 */ PVOID WerShipAssertPtr; /* 234/360 */ - PVOID pUnused; /* 238/368 */ + PVOID EcCodeBitMap; /* 238/368 */ PVOID pImageHeaderHash; /* 23c/370 */ ULONG HeapTracingEnabled : 1; /* 240/378 */ ULONG CritSecTracingEnabled : 1;