[Openvpn-devel] win32: detect arm64 architecture and emulations

Message ID 20221104090247.167-1-lstipakov@gmail.com
State Accepted
Headers show
Series [Openvpn-devel] win32: detect arm64 architecture and emulations | expand

Commit Message

Lev Stipakov Nov. 3, 2022, 10:02 p.m. UTC
From: Lev Stipakov <lev@openvpn.net>

Properly detect process architecture and
machine architecture, including arm64.

Print process architecture and, if machine
architecture is different (we are running in
emulation), print that too.

Signed-off-by: Lev Stipakov <lev@openvpn.net>
---
 src/openvpn/win32.c | 123 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 112 insertions(+), 11 deletions(-)

Comments

Gert Doering Nov. 4, 2022, 10:40 p.m. UTC | #1
Hi,

On Fri, Nov 04, 2022 at 11:02:47AM +0200, Lev Stipakov wrote:
> From: Lev Stipakov <lev@openvpn.net>
> 
> Properly detect process architecture and
> machine architecture, including arm64.
> 
> Print process architecture and, if machine
> architecture is different (we are running in
> emulation), print that too.

This looks generally good, so definitely a "feature ACK".

Do you have a set of installers available so we can ask for testers?  
I can do win10+win11 on arm64, but would perfer if someone else would
do i386/amd64 win7/10/11/server* testing.

gert
Lev Stipakov Nov. 5, 2022, 1 a.m. UTC | #2
I have tested following configurations:

On my Volterra:
- x86 on arm64 win11
- x64 on arm64 win11
- arm64 on arm64 win11

On my laptop:
- x86 on amd64 win10 
- amd64 on amd64 win10

On VM:
- x86 on amd64 win7
- amd64 on amd64 win7

If you want to test, you could get binaries (enough to run openvpn —version) from my GHA fork (https://github.com/lstipakov/openvpn/actions/runs/3392266010). I can also open a PR to openvpn-build and modify GHA script so that it points to my openvpn branch, this way we could get MSIs. 

Lähetetty iPhonesta

> Gert Doering <gert@greenie.muc.de> kirjoitti 5.11.2022 kello 11.40:
> 
> Hi,
> 
>> On Fri, Nov 04, 2022 at 11:02:47AM +0200, Lev Stipakov wrote:
>> From: Lev Stipakov <lev@openvpn.net>
>> 
>> Properly detect process architecture and
>> machine architecture, including arm64.
>> 
>> Print process architecture and, if machine
>> architecture is different (we are running in
>> emulation), print that too.
> 
> This looks generally good, so definitely a "feature ACK".
> 
> Do you have a set of installers available so we can ask for testers?  
> I can do win10+win11 on arm64, but would perfer if someone else would
> do i386/amd64 win7/10/11/server* testing.
> 
> gert
> -- 
> "If was one thing all people took for granted, was conviction that if you 
> feed honest figures into a computer, honest figures come out. Never doubted 
> it myself till I met a computer with a sense of humor."
>                             Robert A. Heinlein, The Moon is a Harsh Mistress
> 
> Gert Doering - Munich, Germany                             gert@greenie.muc.de
Gert Doering Nov. 8, 2022, 2:33 a.m. UTC | #3
Acked-by: Gert Doering <gert@greenie.muc.de>

The tester's echo was really overwhelming here... so I've stared-at-code
and fed this to my github instance for test building with msvc & mingw
(builds fine).

Compareing the patch to MS documentation (IsWow64Process2() etc.) - the
code seems to be reasonable, and matches the intent.

Regarding feature-ACK - yes, printing specific "what compile on what
type of windows" is a useful feature when looking at log files and
trying to figure out the environment where something happened, to be
able to easier reproduce it.

Your patch has been applied to the master branch.

commit 99af056fad3cd0aef4af68d0eacc1fb9ef9b50c7
Author: Lev Stipakov
Date:   Fri Nov 4 11:02:47 2022 +0200

     win32: detect arm64 architecture and emulations

     Signed-off-by: Lev Stipakov <lev@openvpn.net>
     Acked-by: Gert Doering <gert@greenie.muc.de>
     Message-Id: <20221104090247.167-1-lstipakov@gmail.com>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg25476.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c
index 82f0c73f..cfe4dbde 100644
--- a/src/openvpn/win32.c
+++ b/src/openvpn/win32.c
@@ -1345,18 +1345,106 @@  win32_version_info(void)
     return WIN_10;
 }
 
-bool
-win32_is_64bit(void)
+typedef enum {
+    ARCH_X86,
+    ARCH_AMD64,
+    ARCH_ARM64,
+    ARCH_NATIVE, /* means no emulation, makes sense for host arch */
+    ARCH_UNKNOWN
+} arch_t;
+
+static void
+win32_get_arch(arch_t *process_arch, arch_t *host_arch)
 {
-#if defined(_WIN64)
-    return true;  /* 64-bit programs run only on Win64 */
+    *process_arch = ARCH_UNKNOWN;
+    *host_arch = ARCH_NATIVE;
+
+    typedef BOOL (__stdcall *is_wow64_process2_t)(HANDLE, USHORT *, USHORT *);
+    is_wow64_process2_t is_wow64_process2 = (is_wow64_process2_t)
+                                            GetProcAddress(GetModuleHandle("Kernel32.dll"), "IsWow64Process2");
+
+    USHORT process_machine = 0;
+    USHORT native_machine = 0;
+    BOOL is_wow64 = FALSE;
+
+#ifdef _ARM64_
+    *process_arch = ARCH_ARM64;
+#elif defined(_WIN64)
+    *process_arch = ARCH_AMD64;
+    if (is_wow64_process2)
+    {
+        /* this could be amd64 on arm64 */
+        BOOL is_wow64 = is_wow64_process2(GetCurrentProcess(),
+                                          &process_machine, &native_machine);
+        if (is_wow64 && native_machine == IMAGE_FILE_MACHINE_ARM64)
+        {
+            *host_arch = ARCH_ARM64;
+        }
+    }
 #elif defined(_WIN32)
-    /* 32-bit programs run on both 32-bit and 64-bit Windows */
-    BOOL f64 = FALSE;
-    return IsWow64Process(GetCurrentProcess(), &f64) && f64;
-#else  /* if defined(_WIN64) */
-    return false; /* Win64 does not support Win16 */
-#endif
+    *process_arch = ARCH_X86;
+
+    if (is_wow64_process2)
+    {
+        /* check if we're running on arm64 or amd64 machine */
+        is_wow64 = is_wow64_process2(GetCurrentProcess(),
+                                     &process_machine, &native_machine);
+        if (is_wow64)
+        {
+            switch (native_machine)
+            {
+                case IMAGE_FILE_MACHINE_ARM64:
+                    *host_arch = ARCH_ARM64;
+                    break;
+
+                case IMAGE_FILE_MACHINE_AMD64:
+                    *host_arch = ARCH_AMD64;
+                    break;
+
+                default:
+                    *host_arch = ARCH_UNKNOWN;
+                    break;
+            }
+        }
+    }
+    else
+    {
+        BOOL w64 = FALSE;
+        is_wow64 = IsWow64Process(GetCurrentProcess(), &w64) && w64;
+        if (is_wow64)
+        {
+            /* we are unable to differentiate between arm64 and amd64
+             * machines here, so assume we are running on amd64 */
+            *host_arch = ARCH_AMD64;
+        }
+    }
+#endif /* _ARM64_ */
+}
+
+static void
+win32_print_arch(arch_t arch, struct buffer *out)
+{
+    switch (arch)
+    {
+        case ARCH_X86:
+            buf_printf(out, "x86");
+            break;
+
+        case ARCH_AMD64:
+            buf_printf(out, "amd64");
+            break;
+
+        case ARCH_ARM64:
+            buf_printf(out, "arm64");
+            break;
+
+        case ARCH_UNKNOWN:
+            buf_printf(out, "(unknown)");
+            break;
+
+        default:
+            break;
+    }
 }
 
 const char *
@@ -1397,7 +1485,20 @@  win32_version_string(struct gc_arena *gc, bool add_name)
             break;
     }
 
-    buf_printf(&out, win32_is_64bit() ? " 64bit" : " 32bit");
+    buf_printf(&out, ", ");
+
+    arch_t process_arch, host_arch;
+    win32_get_arch(&process_arch, &host_arch);
+    win32_print_arch(process_arch, &out);
+
+    buf_printf(&out, " executable");
+
+    if (host_arch != ARCH_NATIVE)
+    {
+        buf_printf(&out, " running on ");
+        win32_print_arch(host_arch, &out);
+        buf_printf(&out, " host");
+    }
 
     return (const char *)out.data;
 }