From: Grigory Vasilyev h0tc0d3@gmail.com
--- dlls/kernel32/Makefile.in | 2 + dlls/kernel32/firmware.c | 122 ++++++++++++++++++++++++++++++++++++ dlls/kernel32/kernel32.spec | 2 + dlls/kernel32/kernel_main.c | 2 + dlls/kernel32/process.c | 58 +++++++++++++++-- dlls/kernel32/unixlib.h | 44 +++++++++++++ 6 files changed, 224 insertions(+), 6 deletions(-) create mode 100644 dlls/kernel32/firmware.c create mode 100644 dlls/kernel32/unixlib.h
diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in index ca5bb437e24..feb02d23e39 100644 --- a/dlls/kernel32/Makefile.in +++ b/dlls/kernel32/Makefile.in @@ -1,5 +1,6 @@ EXTRADEFS = -D_KERNEL32_ -D_NORMALIZE_ MODULE = kernel32.dll +UNIXLIB = kernel32.so IMPORTLIB = kernel32 IMPORTS = kernelbase ntdll winecrt0
@@ -14,6 +15,7 @@ SOURCES = \ console.c \ debugger.c \ file.c \ + firmware.c \ heap.c \ kernel_main.c \ locale.c \ diff --git a/dlls/kernel32/firmware.c b/dlls/kernel32/firmware.c new file mode 100644 index 00000000000..d00710faaf4 --- /dev/null +++ b/dlls/kernel32/firmware.c @@ -0,0 +1,122 @@ +/* + * Kernel32 Firmware Interface + * + * Copyright (C) 2024 Grigory Vasilyev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include <errno.h> +#include <dirent.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "unixlib.h" +#include "windef.h" + +/* Get Firmware Variable */ +static NTSTATUS kernel32_unix_get_firmware_variable(void *args) +{ + int fd, rc; + size_t bytes, pos = 0; + ssize_t ssz; + char tguid[37]; + char filename[128]; + struct stat sb = {0}; + struct wine_get_firmware_variable_params *params = args; + + int gsize = strlen(params->guid); + + if (params->guid[0] == '{' && params->guid[(gsize - 1)] == '}') { + if (gsize - 2 < sizeof(tguid)) + bytes = gsize - 1; + else + bytes = sizeof(tguid); + memcpy(tguid, params->guid + 1, bytes); + tguid[bytes - 1] = '\0'; + snprintf(filename, sizeof(filename), "/sys/firmware/efi/efivars/%s-%s", params->name, tguid); + } else { + snprintf(filename, sizeof(filename), "/sys/firmware/efi/efivars/%s-%s", params->name, params->guid); + } + + fd = open(filename, O_RDONLY | O_NONBLOCK); + if (fd < 0) + goto done; + + rc = fstat(fd, &sb); + if (rc < 0 || sb.st_size == 0) + goto done; + + if (sb.st_size - 4 < params->size) + bytes = sb.st_size - 4; + else + bytes = params->size; + +try_read_attributes: + ssz = read(fd, params->attributes, 4); + if (ssz < 0) { + if (errno == EAGAIN || errno == EINTR) + goto try_read_attributes; + goto done; + } + + while (pos < bytes) { + ssz = read(fd, (char *) params->buffer + pos, bytes - pos); + if (ssz < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + goto done; + } + pos += ssz; + } + + close(fd); + params->status = ssz & 0xFFFFFFFF; + return STATUS_SUCCESS; + +done: + if (fd >= 0) + close(fd); + params->status = 0; + return STATUS_UNSUCCESSFUL; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = { + kernel32_unix_get_firmware_variable, +}; + +C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == kernel32_unix_func_count); + +#ifdef _WIN64 + +const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { + kernel32_unix_get_firmware_variable, +}; + +C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == kernel32_unix_func_count); + +#endif /* _WIN64 */ diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 7ed8048f5d0..5d3556a2078 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -695,7 +695,9 @@ @ stdcall -import GetFileType(long) @ stdcall -import GetFinalPathNameByHandleA(long ptr long long) @ stdcall -import GetFinalPathNameByHandleW(long ptr long long) +@ stdcall GetFirmwareEnvironmentVariableExA(str str ptr long ptr) @ stdcall GetFirmwareEnvironmentVariableA(str str ptr long) +@ stdcall GetFirmwareEnvironmentVariableExW(wstr wstr ptr long ptr) @ stdcall GetFirmwareEnvironmentVariableW(wstr wstr ptr long) @ stdcall GetFirmwareType(ptr) @ stdcall -import GetFullPathNameA(str long ptr ptr) diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index ae16195a550..70443cbce2a 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -31,6 +31,7 @@
#include "kernel_private.h" #include "wine/debug.h" +#include "wine/unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(process);
@@ -161,6 +162,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( hinst ); + if (__wine_init_unix_call()) return FALSE; return process_attach( hinst ); case DLL_PROCESS_DETACH: WritePrivateProfileSectionW( NULL, NULL, NULL ); diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 4d27932a372..2da84d5b899 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -37,6 +37,7 @@ #include "ddk/wdm.h" #include "wine/asm.h" #include "wine/debug.h" +#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(process);
@@ -718,14 +719,60 @@ WORD WINAPI GetMaximumProcessorGroupCount(void) return groups; }
+/*********************************************************************** + * GetFirmwareEnvironmentVariableExA (KERNEL32.@) + */ +DWORD WINAPI GetFirmwareEnvironmentVariableExA(LPCSTR name, LPCSTR guid, PVOID buffer, DWORD size, PDWORD attributes) +{ + struct wine_get_firmware_variable_params params = { 0 }; + params.name = name; + params.guid = guid; + params.buffer = buffer; + params.size = size; + params.attributes = attributes; + WINE_UNIX_CALL( kernel32_unix_func_get_firmware_variable, ¶ms ); + return params.status; +} + /*********************************************************************** * GetFirmwareEnvironmentVariableA (KERNEL32.@) */ DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR name, LPCSTR guid, PVOID buffer, DWORD size) { - FIXME("stub: %s %s %p %lu\n", debugstr_a(name), debugstr_a(guid), buffer, size); - SetLastError(ERROR_INVALID_FUNCTION); - return 0; + DWORD dwAttributes; + return GetFirmwareEnvironmentVariableExA( name, guid, buffer, size, &dwAttributes ); +} + +/*********************************************************************** + * GetFirmwareEnvironmentVariableExW (KERNEL32.@) + */ +DWORD WINAPI GetFirmwareEnvironmentVariableExW(LPCWSTR name, LPCWSTR guid, PVOID buffer, DWORD size, PDWORD attributes) +{ + DWORD ret; + INT len; + char *aname; + char *aguid; + + len = lstrlenW( name ) + 1; + ret = WideCharToMultiByte( GetOEMCP(), 0, name, len, NULL, 0, NULL, NULL ); + if ( !( aname = RtlAllocateHeap( GetProcessHeap(), 0, ret * sizeof(aname) ) ) ) + return 0; + WideCharToMultiByte( GetOEMCP(), 0, name, len, aname, ret, NULL, NULL ); + + len = lstrlenW( guid ) + 1; + ret = WideCharToMultiByte( GetOEMCP(), 0, guid, len, NULL, 0, NULL, NULL ); + if ( !( aguid = RtlAllocateHeap( GetProcessHeap(), 0, ret * sizeof(aguid) ) ) ) { + HeapFree( GetProcessHeap(), 0, aname ); + return 0; + } + WideCharToMultiByte( GetOEMCP(), 0, guid, len, aguid, ret, NULL, NULL ); + + ret = GetFirmwareEnvironmentVariableExA( aname, aguid, buffer, size, attributes ); + + HeapFree( GetProcessHeap(), 0, aname ); + HeapFree( GetProcessHeap(), 0, aguid ); + + return ret; }
/*********************************************************************** @@ -733,9 +780,8 @@ DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR name, LPCSTR guid, PVOID buf */ DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR name, LPCWSTR guid, PVOID buffer, DWORD size) { - FIXME("stub: %s %s %p %lu\n", debugstr_w(name), debugstr_w(guid), buffer, size); - SetLastError(ERROR_INVALID_FUNCTION); - return 0; + DWORD dwAttributes; + return GetFirmwareEnvironmentVariableExW( name, guid, buffer, size, &dwAttributes ); }
/*********************************************************************** diff --git a/dlls/kernel32/unixlib.h b/dlls/kernel32/unixlib.h new file mode 100644 index 00000000000..1f6b7b409d9 --- /dev/null +++ b/dlls/kernel32/unixlib.h @@ -0,0 +1,44 @@ +/* + * Kernel32 Unix interface + * + * Copyright (C) 2024 Grigory Vasilyev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_KERNEL_UNIXLIB_H +#define __WINE_KERNEL_UNIXLIB_H + +#include "wine/unixlib.h" + +struct wine_get_firmware_variable_params +{ + LPCSTR name; + LPCSTR guid; + PVOID buffer; + DWORD size; + PDWORD attributes; + DWORD status; +}; + +enum kernel32_unix_func +{ + kernel32_unix_func_get_firmware_variable, + kernel32_unix_func_count, +}; + +extern unixlib_handle_t __wine_unixlib_handle; + +#endif /* __WINE_KERNEL_UNIXLIB_H */