Skip to content

Commit

Permalink
[core] add ARM64 driver installation support
Browse files Browse the repository at this point in the history
* Requires x86 emulation on the ARM64 platform since we are not compiling
  native libraries or examples (only the internal installer is native).
* Only WinUSB and USBSer drivers are supported.
* Addresses #155.
  • Loading branch information
pbatard committed Feb 25, 2023
1 parent 11689ba commit d273d4b
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 51 deletions.
8 changes: 4 additions & 4 deletions examples/wdi-simple.rc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#endif

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,1,779
PRODUCTVERSION 1,4,1,779
FILEVERSION 1,4,1,780
PRODUCTVERSION 1,4,1,780
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -25,13 +25,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "WDI-Simple"
VALUE "FileVersion", "1.4.1.779"
VALUE "FileVersion", "1.4.1.780"
VALUE "InternalName", "WDI-Simple"
VALUE "LegalCopyright", "� 2010-2021 Pete Batard (LGPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/lesser.html"
VALUE "OriginalFilename", "wdi-simple.exe"
VALUE "ProductName", "WDI-Simple"
VALUE "ProductVersion", "1.4.1.779"
VALUE "ProductVersion", "1.4.1.780"
VALUE "Comments", "https://libwdi.akeo.ie"
END
END
Expand Down
2 changes: 1 addition & 1 deletion examples/zadig.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
#define FIELD_ORANGE RGB(255,240,200)
#define ARROW_GREEN RGB(92,228,65)
#define ARROW_ORANGE RGB(253,143,56)
#define APP_VERSION "Zadig 2.7.779"
#define APP_VERSION "Zadig 2.7.780"

// These are used to flag end users about the driver they are going to replace
enum driver_type {
Expand Down
8 changes: 4 additions & 4 deletions examples/zadig.rc
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,7,779,0
PRODUCTVERSION 2,7,779,0
FILEVERSION 2,7,780,0
PRODUCTVERSION 2,7,780,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -264,13 +264,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "Zadig"
VALUE "FileVersion", "2.7.779"
VALUE "FileVersion", "2.7.780"
VALUE "InternalName", "Zadig"
VALUE "LegalCopyright", "� 2010-2021 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "zadig.exe"
VALUE "ProductName", "Zadig"
VALUE "ProductVersion", "2.7.779"
VALUE "ProductVersion", "2.7.780"
VALUE "Comments", "https://libwdi.akeo.ie"
END
END
Expand Down
100 changes: 72 additions & 28 deletions libwdi/libwdi.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,37 @@ static FILE *fopen_as_userU(const char *filename, const char *mode)
return _fdopen(lowlevel_fd, mode);
}

// Detect the underlying platform arch.
static USHORT get_platform_arch(void)
{
BOOL is_64bit = FALSE;
USHORT ProcessMachine = IMAGE_FILE_MACHINE_UNKNOWN, NativeMachine = IMAGE_FILE_MACHINE_UNKNOWN;

PF_DECL_LIBRARY(Kernel32);
PF_TYPE_DECL(WINAPI, BOOL, IsWow64Process2, (HANDLE, USHORT*, USHORT*));
PF_LOAD_LIBRARY(Kernel32);
PF_INIT(IsWow64Process2, Kernel32);

// Best way to find the underlying platform, is to use IsWow64Process2() and look at
// NativeMachine. However this API is only available on Windows 10 1511 or later, so
// we first try to detect the x86 arch in case we need a fallback.
if (sizeof(uintptr_t) < 8) {
// This application is not 64 bit, but it might be 32 bit
// running in WOW64
IsWow64Process(GetCurrentProcess(), &is_64bit);
} else {
is_64bit = TRUE;
}

if ((pfIsWow64Process2 == NULL) ||
!pfIsWow64Process2(GetCurrentProcess(), &ProcessMachine, &NativeMachine)) {
// Couldn't get NativeMachine from IsWow64Process2() so assume x86
NativeMachine = (is_64bit) ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386;
}

PF_FREE_LIBRARY(Kernel32);
return NativeMachine;
}

// Retrieve the version info from the WinUSB, libusbK or libusb0 drivers
int get_version_info(int driver_type, VS_FIXEDFILEINFO* driver_info)
Expand Down Expand Up @@ -647,8 +678,13 @@ int get_version_info(int driver_type, VS_FIXEDFILEINFO* driver_info)


// Find out if the driver selected is actually embedded in this version of the library
// or supported by the underlying platform architecture.
BOOL LIBWDI_API wdi_is_driver_supported(int driver_type, VS_FIXEDFILEINFO* driver_info)
{
#if (defined(LIBUSB0_DIR) || defined(LIBUSBK_DIR))
USHORT platform_arch = get_platform_arch();
#endif

if (driver_type < WDI_USER) { // github issue #40
if (driver_type != WDI_CDC) {
// The CDC driver does not have embedded binaries
Expand All @@ -668,13 +704,13 @@ BOOL LIBWDI_API wdi_is_driver_supported(int driver_type, VS_FIXEDFILEINFO* drive
#endif
case WDI_LIBUSB0:
#if defined(LIBUSB0_DIR)
return TRUE;
return (platform_arch == IMAGE_FILE_MACHINE_AMD64 || platform_arch == IMAGE_FILE_MACHINE_I386);
#else
return FALSE;
#endif
case WDI_LIBUSBK:
#if defined(LIBUSBK_DIR)
return TRUE;
return (platform_arch == IMAGE_FILE_MACHINE_AMD64 || platform_arch == IMAGE_FILE_MACHINE_I386);
#else
return FALSE;
#endif
Expand All @@ -700,7 +736,7 @@ BOOL LIBWDI_API wdi_is_file_embedded(const char* path, const char* name)
{
int i;

for (i=0; i<nb_resources; i++) {
for (i = 0; i < nb_resources; i++) {
if (safe_strcmp(name, resource[i].name) == 0) {
if (path == NULL) {
return TRUE;
Expand Down Expand Up @@ -1235,7 +1271,7 @@ int LIBWDI_API wdi_prepare_driver(struct wdi_device_info* device_info, const cha
inf_name = (char*)filename(inf);

// Check the inf file provided and create the cat file name
if (strcmp(inf_name+safe_strlen(inf_name)-4, inf_ext) != 0) {
if (strcmp(inf_name + safe_strlen(inf_name) - 4, inf_ext) != 0) {
wdi_err("Inf name provided must have a '.inf' extension");
r = WDI_ERROR_INVALID_PARAM;
goto out;
Expand Down Expand Up @@ -1268,14 +1304,14 @@ int LIBWDI_API wdi_prepare_driver(struct wdi_device_info* device_info, const cha
}

// Ensure driver_type is what we expect
if ( (driver_type < 0) || (driver_type > WDI_USER) ) {
if ((driver_type < 0) || (driver_type > WDI_USER)) {
wdi_err("Program assertion failed - Unknown driver type");
r = WDI_ERROR_INVALID_PARAM;
goto out;
}

if (!wdi_is_driver_supported(driver_type, &driver_version[driver_type])) {
for (driver_type=0; driver_type<WDI_NB_DRIVERS; driver_type++) {
for (driver_type = 0; driver_type < WDI_NB_DRIVERS; driver_type++) {
if (wdi_is_driver_supported(driver_type, NULL)) {
wdi_warn("unsupported or no driver type specified, will use %s",
driver_display_name[driver_type]);
Expand Down Expand Up @@ -1627,6 +1663,20 @@ static int process_message(char* buffer, DWORD size)
return WDI_SUCCESS;
}

static const char* get_installer_arch(USHORT uArch)
{
switch (uArch) {
case IMAGE_FILE_MACHINE_AMD64:
return "x64";
case IMAGE_FILE_MACHINE_I386:
return "x86";
case IMAGE_FILE_MACHINE_ARM64:
return "arm64";
default:
return "unknown_arch";
}
}

// Run the elevated installer
static int install_driver_internal(void* arglist)
{
Expand All @@ -1637,13 +1687,13 @@ static int install_driver_internal(void* arglist)
STARTUPINFOA si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
char path[MAX_PATH], exename[MAX_PATH], exeargs[MAX_PATH];
HANDLE stdout_w = INVALID_HANDLE_VALUE;
HANDLE handle[3] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
OVERLAPPED overlapped;
int r;
DWORD err, rd_count, to_read, offset, bufsize = LOGBUF_SIZE;
BOOL is_x64 = FALSE;
USHORT platform_arch = get_platform_arch();
int r;
char path[MAX_PATH], exename[MAX_PATH], exeargs[MAX_PATH], installer_name[32];
char *buffer = NULL, *new_buffer;
const char* filter_name = "libusb0";

Expand Down Expand Up @@ -1692,16 +1742,6 @@ static int install_driver_internal(void* arglist)
wdi_dbg("CMP_WaitNoPendingInstallEvents not available");
}

// Detect whether if we should run the 64 bit installer, without
// relying on external libs
if (sizeof(uintptr_t) < 8) {
// This application is not 64 bit, but it might be 32 bit
// running in WOW64
IsWow64Process(GetCurrentProcess(), &is_x64);
} else {
is_x64 = TRUE;
}

// Use a pipe to communicate with our installer
pipe_handle = CreateNamedPipeA(INSTALLER_PIPE_NAME, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE, 1, 4096, 4096, 0, NULL);
Expand All @@ -1721,14 +1761,15 @@ static int install_driver_internal(void* arglist)
overlapped.hEvent = handle[0];

if (!filter_driver) {
// Why do we need two installers? Glad you asked. If you try to run the x86 installer on an x64
// Why do we need multiple installers? Glad you asked. If you try to run the x86 installer on an x64
// system, you will get a "System does not work under WOW64 and requires 64-bit version" message.
static_sprintf(exename, "\"%s\\installer_x%s.exe\"", path, is_x64?"64":"86");
// And of course, Windows ARM64 won't let you use an x86 installer either...
static_sprintf(installer_name, "installer_%s.exe", get_installer_arch(platform_arch));
static_sprintf(exeargs, "\"%s\"", params->inf_name);
} else {
// Use libusb-win32's filter driver installer
static_strcat(path, is_x64 ? "\\amd64" : "\\x86");
static_sprintf(exename, "\"%s\\install-filter.exe\"", path);
static_strcat(installer_name, "install-filter.exe");
static_strcat(path, (platform_arch == IMAGE_FILE_MACHINE_AMD64) ? "\\amd64" : "\\x86");
if (safe_stricmp(current_device->upper_filter, filter_name) == 0) {
// Device already has the libusb-win32 filter => remove
static_strcpy(exeargs, "uninstall -d=");
Expand All @@ -1748,12 +1789,15 @@ static int install_driver_internal(void* arglist)
goto out;
}
}
// At this stage, if either the 32 or 64 bit installer version is missing,
static_sprintf(exename, "\"%s\\%s\"", path, installer_name);

// At this stage, if the installer for the relevant arch is missing,
// it is the application developer's fault...
if (GetFileAttributesU(exename) == INVALID_FILE_ATTRIBUTES) {
wdi_err("This application does not contain the required %s bit installer", is_x64?"64":"32");
wdi_err("Please contact the application provider for a %s bit compatible version", is_x64?"64":"32");
r = WDI_ERROR_NOT_FOUND; goto out;
wdi_err("This application does not contain the required %s installer", installer_name);
wdi_err("Please contact the application provider for a compatible version");
r = WDI_ERROR_NOT_FOUND;
goto out;
}

if (IsUserAnAdmin()) {
Expand All @@ -1762,7 +1806,7 @@ static int install_driver_internal(void* arglist)
shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = "runas";
shExecInfo.lpFile = filter_driver?"install-filter.exe":(is_x64?"installer_x64.exe":"installer_x86.exe");
shExecInfo.lpFile = installer_name;
shExecInfo.lpParameters = exeargs;
shExecInfo.lpDirectory = path;
shExecInfo.lpClass = NULL;
Expand Down
8 changes: 4 additions & 4 deletions libwdi/libwdi.rc
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,1,779
PRODUCTVERSION 1,4,1,779
FILEVERSION 1,4,1,780
PRODUCTVERSION 1,4,1,780
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -68,13 +68,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "libwdi: Windows Driver Installer Library"
VALUE "FileVersion", "1.4.1.779"
VALUE "FileVersion", "1.4.1.780"
VALUE "InternalName", "libwdi"
VALUE "LegalCopyright", "� 2010-2022 Pete Batard (LGPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/lesser.html"
VALUE "OriginalFilename", "libwdi"
VALUE "ProductName", "libwdi"
VALUE "ProductVersion", "1.4.1.779"
VALUE "ProductVersion", "1.4.1.780"
VALUE "Comments", "https://libwdi.akeo.ie"
END
END
Expand Down
6 changes: 3 additions & 3 deletions libwdi/usbser.inf.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; #INF_FILENAME#
; Copyright (c) 2016 Pete Batard <[email protected]> (GNU LGPL)
; Copyright (c) 2016-2023 Pete Batard <[email protected]> (GNU LGPL)
; Based on the USB CDC .inf sample file provided by James Stephanick
; at https://community.freescale.com/message/493287#493287
; With acknowledgement to Sensics, Inc. <https://sensics.com/osvr>,
Expand All @@ -22,15 +22,15 @@ CatalogFile = #CAT_FILENAME#
DriverVer = #DRIVER_DATE#, 1.0.0.0

[Manufacturer]
%VendorName% = DeviceList,NTx86,NTamd64,NTarm
%VendorName% = DeviceList,NTx86,NTamd64,NTarm64

[DeviceList.NTx86]
%DeviceName% = UsbSer_Install, USB\%DeviceID%

[DeviceList.NTamd64]
%DeviceName% = UsbSer_Install, USB\%DeviceID%

[DeviceList.NTarm]
[DeviceList.NTarm64]
%DeviceName% = UsbSer_Install, USB\%DeviceID%

[UsbSer_Install]
Expand Down
20 changes: 13 additions & 7 deletions libwdi/winusb.inf.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; #INF_FILENAME#
; Copyright (c) 2010-2016 Pete Batard <[email protected]> (GNU LGPL)
; Copyright (c) 2010-2023 Pete Batard <[email protected]> (GNU LGPL)
[Strings]
DeviceName = "#DEVICE_DESCRIPTION#"
VendorName = "#DEVICE_MANUFACTURER#"
Expand All @@ -23,15 +23,15 @@ HKR,,,0,"Universal Serial Bus devices"
HKR,,Icon,,-20

[Manufacturer]
%VendorName% = libusbDevice_WinUSB,NTx86,NTamd64,NTarm
%VendorName% = libusbDevice_WinUSB,NTx86,NTamd64,NTarm64

[libusbDevice_WinUSB.NTx86]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTamd64]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTarm]
[libusbDevice_WinUSB.NTarm64]
%DeviceName% = USB_Install, USB\%DeviceID%

[USB_Install]
Expand Down Expand Up @@ -64,10 +64,17 @@ AddReg = #USE_DEVICE_INTERFACE_GUID#
[AddDeviceInterfaceGUID]
HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%

[USB_Install.CoInstallers]
[USB_Install.NTx86.CoInstallers]
AddReg = CoInstallers_AddReg
CopyFiles = CoInstallers_CopyFiles

[USB_Install.NTamd64.CoInstallers]
AddReg = CoInstallers_AddReg
CopyFiles = CoInstallers_CopyFiles

[USB_Install.NTarm64.CoInstallers]
;

[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller#WDF_VERSION#.dll,WdfCoInstaller","WinUSBCoInstaller2.dll"

Expand All @@ -89,6 +96,5 @@ WdfCoInstaller#WDF_VERSION#.dll = 1,x86
WinUSBCoInstaller2.dll = 1,amd64
WdfCoInstaller#WDF_VERSION#.dll = 1,amd64

[SourceDisksFiles.arm]
WinUSBCoInstaller2.dll = 1,arm
WdfCoInstaller#WDF_VERSION#.dll = 1,arm
[SourceDisksFiles.arm64]
;

0 comments on commit d273d4b

Please sign in to comment.