diff --git a/.gitignore b/.gitignore index 5881234..afcf7ab 100644 --- a/.gitignore +++ b/.gitignore @@ -419,6 +419,12 @@ FodyWeavers.xsd !/vendor/webview2/arm64 !/vendor/webview2/arm64/** +# Vendored ARM64 devcon.exe — same explicit un-ignore (the arm64/ rule above +# otherwise catches it). The x64 devcon at vendor/devcon/devcon.exe is tracked +# directly; the ARM64 build stages this copy into bin\Release-ARM64\drivers\. +!/vendor/devcon/arm64 +!/vendor/devcon/arm64/** + # Local-only planning and notes — kept on disk for context, not pushed. /docs/ diff --git a/AppSandbox.sln b/AppSandbox.sln index e1ac8b5..43906af 100644 --- a/AppSandbox.sln +++ b/AppSandbox.sln @@ -178,6 +178,7 @@ Global {0FA17E55-9C3D-4B21-AE60-5D7C1B2E3F40}.Release|ARM64.ActiveCfg = Release|ARM64 {0FA17E55-9C3D-4B21-AE60-5D7C1B2E3F40}.Release|x64.ActiveCfg = Release|x64 {0FA17E55-9C3D-4B21-AE60-5D7C1B2E3F40}.Release|x64.Build.0 = Release|x64 + {0FA17E55-9C3D-4B21-AE60-5D7C1B2E3F40}.Release|ARM64.Build.0 = Release|ARM64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Directory.Build.props b/Directory.Build.props index d477a4d..104a162 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,4 +33,19 @@ true + + + + false + diff --git a/src/backend_win/d3dlayers.c b/src/backend_win/d3dlayers.c index ccd66ee..66f4bfa 100644 --- a/src/backend_win/d3dlayers.c +++ b/src/backend_win/d3dlayers.c @@ -7,8 +7,8 @@ * 2. Windows Update FE3 client protocol over WinHTTP (HTTPS): * GetCookie -> SyncUpdates(filtered by WuCategoryId) * -> GetExtendedUpdateInfo2 -> time-limited CDN url. - * The x64 package is located by identifier in the response, so version - * changes / extra updates do not break resolution. + * The package for the build architecture is located by identifier in the + * response, so version changes / extra updates do not break resolution. * 3. Download the .appx (a zip) from the Microsoft CDN. * 4. Extract with the in-box tar.exe (libarchive handles zip natively). * 5. Copy the mapping-layer files into \d3dlayers\ (cached). @@ -36,17 +36,33 @@ #define DL_FE3_PATH_SECURED L"/ClientWebService/client.asmx/secured" #define DL_SOAP_HEADERS L"Content-Type: application/soap+xml; charset=utf-8\r\n" #define DL_CACHE_SUBDIR L"d3dlayers" -#define DL_APPX_NAME L"D3DMappingLayers_x64.appx" +/* The D3D Mapping Layers Store package ships a per-architecture .appx; pick the + one matching the guest (= build) architecture. The host downloads it, so on + the ARM64 build we fetch and stage the arm64 layers for the arm64 guest. */ +#if defined(_M_ARM64) +# define DL_ARCH L"arm64" +# define DL_ARCH_A "arm64" +#else +# define DL_ARCH L"x64" +# define DL_ARCH_A "x64" +#endif +#define DL_APPX_NAME L"D3DMappingLayers_" DL_ARCH L".appx" +/* Substring identifying the package file in the SyncUpdates response — the + InstallerSpecificIdentifier contains e.g. "..._x64_..." / "..._arm64_...". */ +#define DL_ISI_ARCH "_" DL_ARCH_A "_" #define DL_MAX_ROUNDS 5 /* FE3 faults intermittently; retry the chain */ -/* Files to extract: dest leaf name <- source path inside the .appx. */ +/* Files to extract: dest leaf name <- source path inside the .appx. The arch + subfolder inside the package (x64\ / arm64\) is selected by DL_ARCH; the + Vulkan ICD manifest is staged under the arch-neutral name dzn_icd.json so the + guest agent references one fixed filename regardless of architecture. */ static const wchar_t *const DL_DST[] = { L"OpenGLOn12.dll", L"dxil.dll", L"OpenCLOn12.dll", - L"clon12compiler.dll", L"vulkan_dzn.dll", L"dzn_icd.x64.json" + L"clon12compiler.dll", L"vulkan_dzn.dll", L"dzn_icd.json" }; static const wchar_t *const DL_SRC[] = { - L"x64\\OpenGLOn12.dll", L"x64\\dxil.dll", L"x64\\OpenCLOn12.dll", - L"x64\\clon12compiler.dll", L"x64\\vulkan_dzn.dll", L"dzn_icd.x64.json" + DL_ARCH L"\\OpenGLOn12.dll", DL_ARCH L"\\dxil.dll", DL_ARCH L"\\OpenCLOn12.dll", + DL_ARCH L"\\clon12compiler.dll", DL_ARCH L"\\vulkan_dzn.dll", L"dzn_icd." DL_ARCH L".json" }; #define DL_NFILES ((int)(sizeof(DL_DST)/sizeof(DL_DST[0]))) @@ -318,10 +334,10 @@ done: /* ---- response parsing ---- */ -/* Find the x64 D3DMappingLayers .appx in a (decoded) SyncUpdates response and - * resolve its UpdateIdentity by joining the file's enclosing to - * the matching NewUpdates . */ -static BOOL parse_x64_leaf(const char *buf, char *uid, size_t uid_cch, +/* Find the D3DMappingLayers .appx matching the build architecture in a + * (decoded) SyncUpdates response and resolve its UpdateIdentity by joining the + * file's enclosing to the matching NewUpdates . */ +static BOOL parse_leaf(const char *buf, char *uid, size_t uid_cch, char *rev, size_t rev_cch, char *digest, size_t dig_cch) { const char *p = buf; @@ -340,11 +356,11 @@ static BOOL parse_x64_leaf(const char *buf, char *uid, size_t uid_cch, !attr_in(tag, "InstallerSpecificIdentifier", isi, sizeof(isi))) { p = gt + 1; continue; } - if (!strstr(isi, "D3DMappingLayers") || !strstr(isi, "_x64_") || + if (!strstr(isi, "D3DMappingLayers") || !strstr(isi, DL_ISI_ARCH) || !strstr(fn, ".appx")) { p = gt + 1; continue; } - /* matched the x64 package file */ + /* matched the package file for this architecture */ attr_in(tag, "Digest", digest, dig_cch); /* nearest N before this = the ExtendedUpdateInfo id */ @@ -404,7 +420,7 @@ static BOOL parse_file_url(const char *buf, const char *digest, return FALSE; } -/* Resolve the x64 package CDN url from Microsoft. Returns 0 on success. */ +/* Resolve the (build-architecture) package CDN url from Microsoft. Returns 0 on success. */ static int resolve_url(const char *wucatid, wchar_t *url_out, size_t url_cch) { int round, rc = -1; @@ -438,8 +454,8 @@ static int resolve_url(const char *wucatid, wchar_t *url_out, size_t url_cch) if (t1) { sync_req = str_replace_all(t1, "%CATID%", wucatid); free(t1); } if (sync_req) { sync_resp = fe3_post(DL_FE3_PATH, sync_req); free(sync_req); } if (sync_resp) html_unescape(sync_resp); - if (!sync_resp || !parse_x64_leaf(sync_resp, uid, sizeof(uid), rev, sizeof(rev), - digest, sizeof(digest))) { + if (!sync_resp || !parse_leaf(sync_resp, uid, sizeof(uid), rev, sizeof(rev), + digest, sizeof(digest))) { free(sync_resp); Sleep(1500); continue; } free(sync_resp); @@ -462,7 +478,7 @@ static int resolve_url(const char *wucatid, wchar_t *url_out, size_t url_cch) return rc; } -/* The shipped dzn_icd.x64.json gives library_path as "x64\vulkan_dzn.dll", +/* The shipped dzn_icd..json gives library_path as "\vulkan_dzn.dll", * relative to the manifest. The layers are staged into one flat directory, so * point library_path at the DLL's fully-qualified location in the guest. * @@ -479,7 +495,7 @@ static void rewrite_dzn_json(const wchar_t *dir) char *buf, *fixed; size_t rd; - swprintf_s(path, MAX_PATH, L"%s\\dzn_icd.x64.json", dir); + swprintf_s(path, MAX_PATH, L"%s\\dzn_icd.json", dir); if (_wfopen_s(&f, path, L"rb") != 0 || !f) return; fseek(f, 0, SEEK_END); sz = ftell(f); fseek(f, 0, SEEK_SET); if (sz <= 0 || sz > 65536) { fclose(f); return; } @@ -489,10 +505,10 @@ static void rewrite_dzn_json(const wchar_t *dir) fclose(f); buf[rd] = 0; - /* On disk the JSON value is the 18 bytes x64\\vulkan_dzn.dll (two - * backslash characters, JSON-escaped). Match that exactly and replace it - * with the absolute guest path (each backslash JSON-escaped). */ - fixed = str_replace_all(buf, "x64\\\\vulkan_dzn.dll", + /* On disk the JSON value is \\vulkan_dzn.dll (two backslash + * characters, JSON-escaped). Match that exactly and replace it with the + * absolute guest path (each backslash JSON-escaped). */ + fixed = str_replace_all(buf, DL_ARCH_A "\\\\vulkan_dzn.dll", "C:\\\\Windows\\\\AppSandbox\\\\d3dlayers\\\\vulkan_dzn.dll"); free(buf); if (!fixed) return; diff --git a/src/backend_win/d3dlayers.h b/src/backend_win/d3dlayers.h index 41c5588..69222b5 100644 --- a/src/backend_win/d3dlayers.h +++ b/src/backend_win/d3dlayers.h @@ -14,7 +14,8 @@ * OpenCLOn12.dll OpenCL -> D3D12 * clon12compiler.dll OpenCL compiler backend * vulkan_dzn.dll Vulkan (Mesa Dozen) -> D3D12 - * dzn_icd.x64.json Vulkan ICD manifest (points at vulkan_dzn.dll) + * dzn_icd.json Vulkan ICD manifest (points at vulkan_dzn.dll); staged under + * this arch-neutral name from the package's dzn_icd..json */ #ifndef D3DLAYERS_H diff --git a/src/backend_win/disk_util.c b/src/backend_win/disk_util.c index 1d2916d..7f22096 100644 --- a/src/backend_win/disk_util.c +++ b/src/backend_win/disk_util.c @@ -15,8 +15,27 @@ #include -#define SSH_MSI_URL L"https://github.com/PowerShell/Win32-OpenSSH/releases/download/10.0.0.0p2-Preview/OpenSSH-Win64-v10.0.0.0.msi" -#define SSH_MSI_NAME L"OpenSSH-Win64-v10.0.0.0.msi" +/* Architecture token written into every autounattend/unattend component's + processorArchitecture attribute. Matches the guest, which is the build arch + (see ASB_IS_ARM64 in disk_util.h). */ +#if ASB_IS_ARM64 +# define ASB_UA_ARCH L"arm64" +#else +# define ASB_UA_ARCH L"amd64" +#endif + +/* OpenSSH Server MSI, staged into the guest and installed by SetupComplete.cmd. + The Win32-OpenSSH release ships a per-architecture MSI; pick the one matching + the guest (= build) architecture so it installs on an ARM64 guest. */ +#if ASB_IS_ARM64 +# define SSH_MSI_URL L"https://github.com/PowerShell/Win32-OpenSSH/releases/download/10.0.0.0p2-Preview/OpenSSH-ARM64-v10.0.0.0.msi" +# define SSH_MSI_NAME L"OpenSSH-ARM64-v10.0.0.0.msi" +# define SSH_MSI_NAME_A "OpenSSH-ARM64-v10.0.0.0.msi" /* narrow, for the cmd scripts */ +#else +# define SSH_MSI_URL L"https://github.com/PowerShell/Win32-OpenSSH/releases/download/10.0.0.0p2-Preview/OpenSSH-Win64-v10.0.0.0.msi" +# define SSH_MSI_NAME L"OpenSSH-Win64-v10.0.0.0.msi" +# define SSH_MSI_NAME_A "OpenSSH-Win64-v10.0.0.0.msi" /* narrow, for the cmd scripts */ +#endif static const GUID VHDX_VENDOR_MS = { 0xec984aec, 0xa0f9, 0x47e9, @@ -212,6 +231,32 @@ static const wchar_t *lang_to_input_locale(const wchar_t *lang) return L"0409:00000409"; /* fallback */ } +#if ASB_IS_ARM64 +/* Emit RunSynchronousCommand entries (inside an already-open ) + that disable the Windows 11 setup hardware requirement checks by writing the + HKLM\SYSTEM\Setup\LabConfig bypass keys. ARM Windows HCS exposes no vTPM, so + without these Windows Setup's appraiser would refuse to install. `order` is + the next value to use; returns the order after the last entry. + ARM-only: on x64 the guest gets a real vTPM from HCS and needs no bypass. */ +static int write_tpm_bypass_commands(FILE *f, int order) +{ + static const wchar_t *const keys[] = { + L"BypassTPMCheck", L"BypassSecureBootCheck", L"BypassRAMCheck", + L"BypassStorageCheck", L"BypassCPUCheck" + }; + int i; + for (i = 0; i < (int)(sizeof(keys) / sizeof(keys[0])); i++) { + fwprintf(f, + L" \n" + L" %d\n" + L" reg add HKLM\\SYSTEM\\Setup\\LabConfig /v %s /t REG_DWORD /d 1 /f\n" + L" \n", + order++, keys[i]); + } + return order; +} +#endif + /* Generate autounattend.xml with credentials and VM name substituted. If is_template, adds SecureStartup-FilterDriver to disable BitLocker (required for sysprep). */ @@ -238,7 +283,7 @@ static BOOL generate_autounattend(const wchar_t *output_path, L"\n" L" \n" L" \n" L" %s\n" @@ -248,7 +293,7 @@ static BOOL generate_autounattend(const wchar_t *output_path, L" %s\n" L" \n" L" \n" L" \n" @@ -274,19 +319,32 @@ static BOOL generate_autounattend(const wchar_t *output_path, L" 22\n" L" 33NTFSC\n" L" \n" - L" \n" + L" \n", + lang, lang_to_input_locale(lang), lang, lang, lang); + + /* ARM only: disable the Windows 11 Setup hardware checks via the + HKLM\SYSTEM\Setup\LabConfig keys, from a windowsPE RunSynchronous in the + Setup component (runs before the appraiser). ARM Windows HCS has no vTPM, + so Setup would otherwise refuse to install. */ +#if ASB_IS_ARM64 + fwprintf(f, L" \n"); + write_tpm_bypass_commands(f, 1); + fwprintf(f, L" \n"); +#endif + + fwprintf(f, L" \n" L" \n" L"\n" L" \n" L" \n" L" %s\n" L" \n" L" \n" L" \n" @@ -294,7 +352,6 @@ static BOOL generate_autounattend(const wchar_t *output_path, L" 1\n" L" reg add HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE /v BypassNRO /t REG_DWORD /d 1 /f\n" L" \n", - lang, lang_to_input_locale(lang), lang, lang, lang, comp_name); { @@ -336,7 +393,7 @@ static BOOL generate_autounattend(const wchar_t *output_path, if (is_template) { fwprintf(f, L" \n" L" true\n" @@ -353,7 +410,7 @@ static BOOL generate_autounattend(const wchar_t *output_path, fwprintf(f, L" \n" L" \n" L" \n" @@ -364,7 +421,7 @@ static BOOL generate_autounattend(const wchar_t *output_path, L"\n" L" \n" L" \n" L" \n" @@ -382,7 +439,7 @@ static BOOL generate_autounattend(const wchar_t *output_path, fwprintf(f, L" \n" L" \n" L" %s\n" @@ -391,7 +448,7 @@ static BOOL generate_autounattend(const wchar_t *output_path, L" %s\n" L" \n" L" \n" L" \n" @@ -730,9 +787,9 @@ HRESULT iso_create_resources(const wchar_t *iso_path, if (ssh_enabled) { fputs( "REM Install OpenSSH Server\r\n" - "if exist \"%ISODRV%\\OpenSSH-Win64-v10.0.0.0.msi\" (\r\n" + "if exist \"%ISODRV%\\" SSH_MSI_NAME_A "\" (\r\n" " echo [SSH] Installing OpenSSH Server... >> \"%LOG%\"\r\n" - " msiexec /i \"%ISODRV%\\OpenSSH-Win64-v10.0.0.0.msi\" /qn /norestart >> \"%LOG%\" 2>&1\r\n" + " msiexec /i \"%ISODRV%\\" SSH_MSI_NAME_A "\" /qn /norestart >> \"%LOG%\" 2>&1\r\n" " echo [SSH] msiexec exit code: %errorlevel% >> \"%LOG%\"\r\n" " sc config sshd start= auto >> \"%LOG%\" 2>&1\r\n" " net start sshd >> \"%LOG%\" 2>&1\r\n" @@ -791,13 +848,13 @@ static BOOL generate_unattend_instance(const wchar_t *output_path, L"\n" L" \n" L" \n" L" %s\n" L" \n" L" \n" L" \n" @@ -821,13 +878,37 @@ static BOOL generate_unattend_instance(const wchar_t *output_path, L" 5\n" L" cmd /c for %%d in (D E F G H I J) do @if exist %%d:\\SetupComplete.cmd copy /Y %%d:\\SetupComplete.cmd C:\\Windows\\Setup\\Scripts\\\n" L" \n" +#if ASB_IS_ARM64 + /* ARM only: Windows 11 LabConfig hardware-check bypass keys (no vTPM on + ARM). Orders 6-10 continue this component's RunSynchronous. */ + L" \n" + L" 6\n" + L" reg add HKLM\\SYSTEM\\Setup\\LabConfig /v BypassTPMCheck /t REG_DWORD /d 1 /f\n" + L" \n" + L" \n" + L" 7\n" + L" reg add HKLM\\SYSTEM\\Setup\\LabConfig /v BypassSecureBootCheck /t REG_DWORD /d 1 /f\n" + L" \n" + L" \n" + L" 8\n" + L" reg add HKLM\\SYSTEM\\Setup\\LabConfig /v BypassRAMCheck /t REG_DWORD /d 1 /f\n" + L" \n" + L" \n" + L" 9\n" + L" reg add HKLM\\SYSTEM\\Setup\\LabConfig /v BypassStorageCheck /t REG_DWORD /d 1 /f\n" + L" \n" + L" \n" + L" 10\n" + L" reg add HKLM\\SYSTEM\\Setup\\LabConfig /v BypassCPUCheck /t REG_DWORD /d 1 /f\n" + L" \n" +#endif L" \n" L" \n" L" \n" L"\n" L" \n" L" \n" L" %s\n" @@ -836,7 +917,7 @@ static BOOL generate_unattend_instance(const wchar_t *output_path, L" %s\n" L" \n" L" \n" L" \n" @@ -1204,9 +1285,9 @@ static void stage_agent_and_setup(const wchar_t *staging, const wchar_t *res_dir if (ssh_enabled) { fputs( "REM Install OpenSSH Server\r\n" - "if exist \"%ISODRV%\\OpenSSH-Win64-v10.0.0.0.msi\" (\r\n" + "if exist \"%ISODRV%\\" SSH_MSI_NAME_A "\" (\r\n" " echo [SSH] Installing OpenSSH Server... >> \"%LOG%\"\r\n" - " msiexec /i \"%ISODRV%\\OpenSSH-Win64-v10.0.0.0.msi\" /qn /norestart >> \"%LOG%\" 2>&1\r\n" + " msiexec /i \"%ISODRV%\\" SSH_MSI_NAME_A "\" /qn /norestart >> \"%LOG%\" 2>&1\r\n" " echo [SSH] msiexec exit code: %errorlevel% >> \"%LOG%\"\r\n" " sc config sshd start= auto >> \"%LOG%\" 2>&1\r\n" " net start sshd >> \"%LOG%\" 2>&1\r\n" @@ -1329,13 +1410,13 @@ BOOL generate_unattend_vhdx(const wchar_t *output_path, L"\n" L" \n" L" \n" L" %s\n" L" \n" L" \n" L" \n" @@ -1364,6 +1445,10 @@ BOOL generate_unattend_vhdx(const wchar_t *output_path, L" bcdedit /set testsigning on\n" L" \n", order++); } +#if ASB_IS_ARM64 + /* ARM only: Windows 11 LabConfig hardware-check bypass keys (no vTPM on ARM). */ + write_tpm_bypass_commands(f, order); +#endif } fwprintf(f, @@ -1376,7 +1461,7 @@ BOOL generate_unattend_vhdx(const wchar_t *output_path, fwprintf(f, L" \n" L" \n" L" %s\n" @@ -1385,7 +1470,7 @@ BOOL generate_unattend_vhdx(const wchar_t *output_path, L" %s\n" L" \n" L" \n" L" \n" @@ -1455,13 +1540,13 @@ BOOL generate_unattend_vhdx_template(const wchar_t *output_path, L"\n" L" \n" L" \n" L" %s\n" L" \n" L" \n" L" \n" @@ -1490,13 +1575,17 @@ BOOL generate_unattend_vhdx_template(const wchar_t *output_path, L" bcdedit /set testsigning on\n" L" \n", order++); } +#if ASB_IS_ARM64 + /* ARM only: Windows 11 LabConfig hardware-check bypass keys (no vTPM on ARM). */ + write_tpm_bypass_commands(f, order); +#endif } fwprintf(f, L" \n" L" \n" L" \n" L" true\n" @@ -1509,7 +1598,7 @@ BOOL generate_unattend_vhdx_template(const wchar_t *output_path, fwprintf(f, L" \n" L" \n" L" \n" @@ -1520,7 +1609,7 @@ BOOL generate_unattend_vhdx_template(const wchar_t *output_path, L"\n" L" \n" L" \n" L" \n" @@ -1604,9 +1693,9 @@ BOOL generate_vhdx_setupcomplete(const wchar_t *output_path, BOOL ssh_enabled) fputs( "REM Install OpenSSH Server\r\n" "set SSHDIR=%SystemRoot%\\AppSandbox\r\n" - "if exist \"%SSHDIR%\\OpenSSH-Win64-v10.0.0.0.msi\" (\r\n" + "if exist \"%SSHDIR%\\" SSH_MSI_NAME_A "\" (\r\n" " echo [SSH] Installing OpenSSH Server... >> \"%LOG%\"\r\n" - " msiexec /i \"%SSHDIR%\\OpenSSH-Win64-v10.0.0.0.msi\" /qn /norestart >> \"%LOG%\" 2>&1\r\n" + " msiexec /i \"%SSHDIR%\\" SSH_MSI_NAME_A "\" /qn /norestart >> \"%LOG%\" 2>&1\r\n" " echo [SSH] msiexec exit code: %errorlevel% >> \"%LOG%\"\r\n" " sc config sshd start= auto >> \"%LOG%\" 2>&1\r\n" " net start sshd >> \"%LOG%\" 2>&1\r\n" diff --git a/src/backend_win/disk_util.h b/src/backend_win/disk_util.h index a890d9d..2414534 100644 --- a/src/backend_win/disk_util.h +++ b/src/backend_win/disk_util.h @@ -3,6 +3,19 @@ #include +/* Target architecture, resolved at compile time. The supported pairing is + x64 build -> x64 host -> x64 guest, and ARM64 build -> ARM host -> ARM guest + (no cross-arch installs), so build arch == host arch == guest arch and a + single compile-time flag drives every architecture decision: the HCS + SecuritySettings (ARM Windows HCS has no vTPM / guest-state isolation), the + autounattend processorArchitecture token + Win11 TPM-check bypass, the + OpenSSH MSI variant, and the GPU-PV D3D mapping-layer package. */ +#if defined(_M_ARM64) +# define ASB_IS_ARM64 1 +#else +# define ASB_IS_ARM64 0 +#endif + /* Create a new dynamically-expanding VHDX file. size_gb: maximum virtual size in gigabytes. */ HRESULT vhdx_create(const wchar_t *path, ULONGLONG size_gb); diff --git a/src/backend_win/gpu_enum.h b/src/backend_win/gpu_enum.h index e64fa01..abce334 100644 --- a/src/backend_win/gpu_enum.h +++ b/src/backend_win/gpu_enum.h @@ -61,7 +61,7 @@ BOOL gpu_append_lxsslib_share(GpuDriverShareList *list); /* Append a synthetic Plan9 share (name "AppSandbox.GlLayers") exposing the host directory that holds the D3D mapping layers (OpenGLOn12/dxil/OpenCLOn12/ - clon12compiler/vulkan_dzn + dzn_icd.x64.json) and the OpenGL ICD shim. The + clon12compiler/vulkan_dzn + dzn_icd.json) and the OpenGL ICD shim. The Windows guest agent copies this share AFTER the GPU driver shares and then provisions it (stages dxil to System32, sets AppInit_DLLs + the Khronos OpenCL/Vulkan ICD registry keys). guest_path is C:\Windows\AppSandbox\d3dlayers. diff --git a/src/backend_win/hcs_vm.c b/src/backend_win/hcs_vm.c index 2403147..ae10de8 100644 --- a/src/backend_win/hcs_vm.c +++ b/src/backend_win/hcs_vm.c @@ -1,6 +1,7 @@ #include "hcs_vm.h" #include "vm_agent.h" #include "ui.h" +#include "disk_util.h" /* ASB_IS_ARM64 */ #include #include #include @@ -1041,9 +1042,14 @@ BOOL hcs_build_vm_json(const VmConfig *config, const wchar_t *endpoint_guid, name_esc); } - /* SecuritySettings with TPM — enabled for all Windows VMs. - TPM does not block test-signed drivers; only Secure Boot does. */ + /* SecuritySettings (virtual TPM + GuestStateOnly isolation) — x64 only. + The vTPM is required by the Windows 11 guest on x64. ARM Windows HCS + supports neither a vTPM nor guest-state isolation, so the whole block is + emitted only on x64. The Windows 11 Setup TPM/SecureBoot requirement + check is bypassed via the autounattend LabConfig keys (see + generate_autounattend in disk_util.c). */ security_section[0] = L'\0'; +#if !ASB_IS_ARM64 if (is_windows) { wcscpy_s(security_section, 512, L",\"SecuritySettings\":{" @@ -1051,6 +1057,7 @@ BOOL hcs_build_vm_json(const VmConfig *config, const wchar_t *endpoint_guid, L"\"Isolation\":{\"IsolationType\":\"GuestStateOnly\"}" L"}"); } +#endif /* Plan9 shares — GPU driver directories for agent p9copy. Skip for template VMs (no GPU assigned during template creation). */ diff --git a/tools/agent/agent.c b/tools/agent/agent.c index 372e5fd..24c454b 100644 --- a/tools/agent/agent.c +++ b/tools/agent/agent.c @@ -454,7 +454,7 @@ static void gl_provision(const wchar_t *dir) The manifest's library_path is the absolute guest DLL path (set host-side in d3dlayers.c) so the loader can LoadLibraryEx it under LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, which requires a fully-qualified path. */ - swprintf_s(path, MAX_PATH, L"%s\\dzn_icd.x64.json", dir); + swprintf_s(path, MAX_PATH, L"%s\\dzn_icd.json", dir); if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) { if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Khronos\\Vulkan\\Drivers", 0, NULL, 0, KEY_SET_VALUE, NULL, &key, NULL) == ERROR_SUCCESS) { diff --git a/tools/sign/AppSandboxPackage.vcxproj b/tools/sign/AppSandboxPackage.vcxproj index 65c1737..b27a463 100644 --- a/tools/sign/AppSandboxPackage.vcxproj +++ b/tools/sign/AppSandboxPackage.vcxproj @@ -1,7 +1,7 @@