mirror of
https://github.com/dockur/windows.git
synced 2026-10-09 19:04:56 +01:00
feat: Install VMWare driver during unattended setup (#2221)
This commit is contained in:
+36
-58
@@ -71,11 +71,6 @@ updateXML() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! updateLogonCommandXML "$asset"; then
|
||||
error "Failed to update first-logon command in answer file!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! updateEditionXML "$asset"; then
|
||||
error "Failed to update edition settings in answer file!"
|
||||
return 1
|
||||
@@ -526,49 +521,6 @@ updateAutologinXML() {
|
||||
return 0
|
||||
}
|
||||
|
||||
usesWscriptLogonLauncher() {
|
||||
|
||||
case "${DETECTED,,}" in
|
||||
"winvista"* | "win7"* | "win2008r2"* ) return 0 ;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
updateLogonCommandXML() {
|
||||
|
||||
local asset="$1"
|
||||
|
||||
local command="$XML_COMPONENT_SHELL_OOBE/u:FirstLogonCommands/u:SynchronousCommand/u:CommandLine"
|
||||
local expected='cmd.exe /d /c call "%WINDIR%\Setup\Scripts\SetupComplete.cmd" logon'
|
||||
local hidden
|
||||
|
||||
if usesWscriptLogonLauncher; then
|
||||
hidden='wscript.exe //B //NoLogo C:\Windows\Setup\Scripts\RunHidden.vbs'
|
||||
else
|
||||
hidden="powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -Command \"\$cmd = 'call ' + [char]34 + \$env:WINDIR + '\Setup\Scripts\SetupComplete.cmd' + [char]34 + ' logon'; & \$env:ComSpec /d /c \$cmd; exit \$LASTEXITCODE\""
|
||||
fi
|
||||
|
||||
local count value
|
||||
count=$(getXMLNodeCount "$asset" "$command") || return 1
|
||||
|
||||
if [ "$count" != "1" ]; then
|
||||
error "Failed to find a unique first-logon command in answer file: $asset"
|
||||
return 1
|
||||
fi
|
||||
|
||||
value=$(xmlstarlet sel -N "$XML_NS_UNATTEND_ARG" -T -t -v "string($command)" "$asset") || return 1
|
||||
|
||||
if [ "$value" != "$expected" ]; then
|
||||
error "Unexpected first-logon command in answer file: $asset"
|
||||
return 1
|
||||
fi
|
||||
|
||||
xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -u "$command" -v "$hidden" "$asset" || return 1
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
updateProductKey() {
|
||||
|
||||
local script="$1"
|
||||
@@ -1968,43 +1920,69 @@ prepareSetupScript() {
|
||||
|
||||
[ -n "$staged" ] || return 0
|
||||
|
||||
stageHiddenLogonLauncher "$stage" || return 1
|
||||
stageUnattendLauncher "$stage" || return 1
|
||||
updateSetupScript "$staged" "$asset" || return 1
|
||||
finalizeSetupScript "$staged" || return 1
|
||||
stageSetupCompleteWrapper "$stage" || return 1
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
stageHiddenLogonLauncher() {
|
||||
stageSetupCompleteWrapper() {
|
||||
|
||||
local stage="$1"
|
||||
local target="$stage/\$OEM\$/\$\$/Setup/Scripts/SetupComplete.cmd"
|
||||
|
||||
usesWscriptLogonLauncher || return 0
|
||||
if ! cat > "$target" <<'EOF'
|
||||
@echo off
|
||||
call "%~dp0Unattend.cmd" setup
|
||||
exit /b %errorlevel%
|
||||
EOF
|
||||
then
|
||||
error "Failed to create SetupComplete wrapper!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local target="$stage/\$OEM\$/\$\$/Setup/Scripts/RunHidden.vbs"
|
||||
if ! unix2dos -q "$target"; then
|
||||
error "Failed to convert SetupComplete wrapper to DOS format!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
stageUnattendLauncher() {
|
||||
|
||||
local stage="$1"
|
||||
local target="$stage/\$OEM\$/\$\$/Setup/Scripts/Unattend.vbs"
|
||||
|
||||
if ! mkdir -p "$(dirname "$target")"; then
|
||||
error "Failed to create hidden logon launcher directory!"
|
||||
error "Failed to create unattended launcher directory!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! cat > "$target" <<'EOF'
|
||||
Option Explicit
|
||||
|
||||
Dim shell, command, result
|
||||
Dim shell, command, result, pass
|
||||
|
||||
If WScript.Arguments.Count <> 1 Then
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
pass = WScript.Arguments(0)
|
||||
Set shell = CreateObject("WScript.Shell")
|
||||
command = shell.ExpandEnvironmentStrings("%ComSpec% /d /c call " & Chr(34) & "%WINDIR%\Setup\Scripts\SetupComplete.cmd" & Chr(34) & " logon")
|
||||
command = shell.ExpandEnvironmentStrings("%ComSpec% /d /c call " & Chr(34) & "%WINDIR%\Setup\Scripts\Unattend.cmd" & Chr(34) & " " & pass)
|
||||
result = shell.Run(command, 0, True)
|
||||
WScript.Quit result
|
||||
EOF
|
||||
then
|
||||
error "Failed to create hidden logon launcher!"
|
||||
error "Failed to create unattended launcher!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! unix2dos -q "$target"; then
|
||||
error "Failed to convert hidden logon launcher to DOS format!"
|
||||
error "Failed to convert unattended launcher to DOS format!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -2124,7 +2102,7 @@ stageSetupScript() {
|
||||
source=$(findSetupScript "$asset") || return 1
|
||||
[ -n "$source" ] || return 0
|
||||
|
||||
target="$stage/\$OEM\$/\$\$/Setup/Scripts/SetupComplete.cmd"
|
||||
target="$stage/\$OEM\$/\$\$/Setup/Scripts/Unattend.cmd"
|
||||
|
||||
if ! mkdir -p "$(dirname "$target")"; then
|
||||
error "Failed to create setup script directory!"
|
||||
|
||||
+63
-103
@@ -138,7 +138,6 @@ Win9xInstall() {
|
||||
local display="$win9x/vmdisp9x"
|
||||
local audio95="$win9x/alcx95"
|
||||
local audiowdm="$win9x/alcxwdm"
|
||||
local vmware_display="$win9x/vmsvga"
|
||||
|
||||
extractDrivers "$drivers" || return 1
|
||||
|
||||
@@ -172,7 +171,7 @@ Win9xInstall() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! patchWin9xSetupFiles "$id" "$target" "$desc" "$patcher" "$qemouse" "$display" "$vmware_display"; then
|
||||
if ! patchWin9xSetupFiles "$id" "$target" "$desc" "$patcher" "$qemouse" "$display"; then
|
||||
rm -rf "$drivers" || :
|
||||
return 1
|
||||
fi
|
||||
@@ -559,7 +558,6 @@ patchWin9xSetupFiles() {
|
||||
local patcher="$4"
|
||||
local qemouse="$5"
|
||||
local display="$6"
|
||||
local vmware_display="$7"
|
||||
|
||||
chmod 755 "$patcher" || {
|
||||
error "Failed to make Patcher9x executable!"
|
||||
@@ -584,12 +582,13 @@ patchWin9xSetupFiles() {
|
||||
fi
|
||||
|
||||
stageWin9xDisplayDriver "$target" "$display" "$desc" || return 1
|
||||
stageWin9xVMwareDriver "$target" "$vmware_display" "$desc" || return 1
|
||||
|
||||
if ! mv -f -- \
|
||||
"$target/VMDISP9X/vmdisp9x.inf" \
|
||||
"$target/VMDISP9X/qemumini.drv" \
|
||||
"$target/VMDISP9X/qemumini.vxd" \
|
||||
"$target/VMDISP9X/vmwsmini.drv" \
|
||||
"$target/VMDISP9X/vmwsmini.vxd" \
|
||||
"$target/VMDISP9X/vmhal9x.dll" \
|
||||
"$target/VMDISP9X/vmhal486.dll" \
|
||||
"$target/VMDISP9X/vmdisp9x.dll" \
|
||||
@@ -1139,6 +1138,8 @@ stageWin9xDisplayDriver() {
|
||||
vmdisp9x.inf \
|
||||
qemumini.drv \
|
||||
qemumini.vxd \
|
||||
vmwsmini.drv \
|
||||
vmwsmini.vxd \
|
||||
vmhal9x.dll \
|
||||
vmhal486.dll \
|
||||
vmdisp9x.dll; do
|
||||
@@ -1157,6 +1158,8 @@ stageWin9xDisplayDriver() {
|
||||
"$source/vmdisp9x.inf" \
|
||||
"$source/qemumini.drv" \
|
||||
"$source/qemumini.vxd" \
|
||||
"$source/vmwsmini.drv" \
|
||||
"$source/vmwsmini.vxd" \
|
||||
"$source/vmhal9x.dll" \
|
||||
"$source/vmhal486.dll" \
|
||||
"$source/vmdisp9x.dll" \
|
||||
@@ -1166,6 +1169,50 @@ stageWin9xDisplayDriver() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# VMDisp9x identifies QEMU by the absence of SVGA_FIFO_CAP_FENCE. Our
|
||||
# enhanced SVGA device supports fences, so force the driver's existing QEMU
|
||||
# compatibility path instead. This keeps fence support while enabling its V86
|
||||
# VGA-memory mapping workaround for KVM/WHPX shutdown. Match the surrounding
|
||||
# machine code exactly and fail closed if an upstream driver build changes it.
|
||||
if ! python3 - "$dest/vmwsmini.vxd" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
data = bytearray(path.read_bytes())
|
||||
|
||||
old = bytes.fromhex(
|
||||
"6A 01 "
|
||||
"E8 CE 0B 00 00 "
|
||||
"83 C4 04 "
|
||||
"85 C0 "
|
||||
"75 48 "
|
||||
"68 20 00 00 00 "
|
||||
"68 CE 01 00 00"
|
||||
)
|
||||
new = old[:12] + b"\x90\x90" + old[14:]
|
||||
|
||||
old_count = bytes(data).count(old)
|
||||
new_count = bytes(data).count(new)
|
||||
if old_count != 1 or new_count != 0:
|
||||
raise SystemExit(
|
||||
"VMDisp9x QEMU compatibility signature mismatch: "
|
||||
f"original={old_count}, patched={new_count}"
|
||||
)
|
||||
|
||||
offset = bytes(data).index(old)
|
||||
data[offset + 12:offset + 14] = b"\x90\x90"
|
||||
path.write_bytes(data)
|
||||
|
||||
verify = path.read_bytes()
|
||||
if verify.count(old) != 0 or verify.count(new) != 1:
|
||||
raise SystemExit("VMDisp9x QEMU compatibility patch verification failed")
|
||||
PY
|
||||
then
|
||||
error "Failed to enable the VMDisp9x QEMU compatibility path!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# VMDisp9x's DDC flag makes Win9x enumerate a Plug and Play monitor after
|
||||
# the display driver starts. The unattended setup already selects the monitor
|
||||
# and display mode, and VMDisp9x carries a fixed mode list, so disable DDC in
|
||||
@@ -1181,100 +1228,6 @@ stageWin9xDisplayDriver() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Keep VMDisp9x available for QEMU STD VGA, but let the official VMware
|
||||
# driver own VMware SVGA-II. Comment only the matching model in our staged
|
||||
# INF so the original driver archive remains untouched.
|
||||
if ! python3 - "$dest/vmdisp9x.inf" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
lines = path.read_bytes().splitlines(keepends=True)
|
||||
needle = br'PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD'
|
||||
matches = []
|
||||
|
||||
for index, line in enumerate(lines):
|
||||
stripped = line.lstrip(b' \t')
|
||||
if stripped.startswith(b';'):
|
||||
continue
|
||||
if needle in stripped.upper():
|
||||
matches.append(index)
|
||||
|
||||
if len(matches) != 1:
|
||||
raise SystemExit(f'expected exactly one active VMware SVGA-II model, found {len(matches)}')
|
||||
|
||||
index = matches[0]
|
||||
indent = len(lines[index]) - len(lines[index].lstrip(b' \t'))
|
||||
lines[index] = lines[index][:indent] + b'; ' + lines[index][indent:]
|
||||
path.write_bytes(b''.join(lines))
|
||||
PY
|
||||
then
|
||||
error "Failed to reserve VMware SVGA-II for the official VMware driver!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if grep -iF 'PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD' "$dest/vmdisp9x.inf" |
|
||||
grep -Ev '^[[:space:]]*;' >/dev/null; then
|
||||
error "Failed to remove the active VMware SVGA-II VMDisp9x model!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! grep -iF 'PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD' "$dest/vmdisp9x.inf" |
|
||||
grep -Eq '^[[:space:]]*;'; then
|
||||
error "Failed to verify the VMware SVGA-II VMDisp9x model change!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
stageWin9xVMwareDriver() {
|
||||
|
||||
local target="$1"
|
||||
local source="$2"
|
||||
local desc="$3"
|
||||
|
||||
local file
|
||||
|
||||
for file in \
|
||||
vmx_svga.inf \
|
||||
VMX_SVGA.DRV \
|
||||
VMX_SVGA.vxd; do
|
||||
|
||||
if [ ! -s "$source/$file" ]; then
|
||||
error "Failed to locate required VMware SVGA driver file: $file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if ! cp -f -- \
|
||||
"$source/vmx_svga.inf" \
|
||||
"$source/VMX_SVGA.DRV" \
|
||||
"$source/VMX_SVGA.vxd" \
|
||||
"$target/"; then
|
||||
|
||||
error "Failed to add the VMware SVGA driver to $desc setup files!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
for file in \
|
||||
vmx_svga.inf \
|
||||
VMX_SVGA.DRV \
|
||||
VMX_SVGA.vxd; do
|
||||
|
||||
if ! cmp -s -- "$source/$file" "$target/$file"; then
|
||||
error "Failed to verify the staged VMware SVGA driver file: $file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if ! grep -Fqi 'PCI\VEN_15AD&DEV_0405' "$target/vmx_svga.inf"; then
|
||||
error "Failed to verify the VMware SVGA-II hardware ID!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -3210,15 +3163,22 @@ createWin9xSystemImage() {
|
||||
fi
|
||||
|
||||
local boot_gui=0
|
||||
[[ "${id,,}" == "win9x"* ]] && boot_gui=1
|
||||
[[ "${id,,}" == "win9x" ]] && boot_gui=1
|
||||
|
||||
local auto_scan=2
|
||||
[[ "${id,,}" == "win95" ]] && auto_scan=0
|
||||
|
||||
{
|
||||
printf '%s\n' \
|
||||
'[Options]' \
|
||||
"[Options]" \
|
||||
"BootGUI=$boot_gui" \
|
||||
'BootDelay=0' \
|
||||
'AutoScan=2' \
|
||||
'Logo=0' \
|
||||
"BootMenu=0" \
|
||||
"BootMenuDefault=1" \
|
||||
"BootWarn=0" \
|
||||
"BootSafe=0" \
|
||||
"BootDelay=0" \
|
||||
"AutoScan=$auto_scan" \
|
||||
"Logo=0" \
|
||||
''
|
||||
} | unix2dos > "$msdos" || return 1
|
||||
|
||||
|
||||
+1106
File diff suppressed because it is too large
Load Diff
+9
-8
@@ -1423,8 +1423,7 @@ addDrivers() {
|
||||
fi
|
||||
|
||||
if ! bsdtar -xf /var/drivers.txz -C "$drivers" \
|
||||
--exclude='win9x' --exclude='sata' --exclude='qbochs' \
|
||||
--exclude='vmsvga'; then
|
||||
--exclude='win9x' --exclude='sata' --exclude='qbochs'; then
|
||||
error "Failed to extract drivers from archive!" && return 1
|
||||
fi
|
||||
|
||||
@@ -1439,11 +1438,10 @@ addDrivers() {
|
||||
mkdir -p "$dst" || return 1
|
||||
cp -Lr "$dest/." "$dst" || return 1
|
||||
|
||||
# Install the VirtIO display driver explicitly from SetupComplete.cmd so it
|
||||
# Install display drivers explicitly from Unattend.cmd so it
|
||||
# cannot disrupt Windows Setup by loading through the WinPE driver path.
|
||||
if ! isLegacy "$version"; then
|
||||
rm -rf "$dest/viogpudo" || return 1
|
||||
fi
|
||||
rm -rf "$dest/vmsvga" || return 1
|
||||
rm -rf "$dest/viogpudo" || return 1
|
||||
|
||||
local winpe="$stage/$target"
|
||||
rm -rf "$winpe" || return 1
|
||||
@@ -1470,6 +1468,7 @@ selectDrivers() {
|
||||
viorng
|
||||
viostor
|
||||
viomem
|
||||
vmsvga
|
||||
NetKVM
|
||||
Balloon
|
||||
vioscsi
|
||||
@@ -1723,8 +1722,10 @@ setDiskMinimum() {
|
||||
local id="$1"
|
||||
local required
|
||||
|
||||
required=$(getRequiredDisk "$id") || return
|
||||
DISK_MINIMUM="$required"
|
||||
if [ -z "${DISK_MINIMUM:-}" ]; then
|
||||
required=$(getRequiredDisk "$id") || return
|
||||
DISK_MINIMUM="$required"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
+13
-12
@@ -26,18 +26,6 @@ setMachine() {
|
||||
|
||||
esac
|
||||
|
||||
case "${id,,}" in
|
||||
|
||||
"winnt4" )
|
||||
writeState "vga" "cirrus" || return 1 ;;
|
||||
|
||||
"win9"* | "win2k"* | "winxp"* | "win2003"* )
|
||||
writeState "vga" "vmware" || return 1 ;;
|
||||
|
||||
*) writeState "vga" "std" || return 1 ;;
|
||||
|
||||
esac
|
||||
|
||||
case "${id,,}" in
|
||||
|
||||
"win9"* | "winnt4" )
|
||||
@@ -76,6 +64,19 @@ setMachine() {
|
||||
esac
|
||||
fi
|
||||
|
||||
case "${id,,}" in
|
||||
|
||||
"winnt4" )
|
||||
writeState "vga" "cirrus" || return 1 ;;
|
||||
|
||||
"win9"* | "win2k"* | "winxp"* | \
|
||||
"win2003"* | "win2008"* | "win2012"*| \
|
||||
"winvista"* | "win7"* | "win8"* | "reactos" )
|
||||
|
||||
writeState "vga" "vmvga" || return 1 ;;
|
||||
|
||||
esac
|
||||
|
||||
restoreMachine || return 1
|
||||
restoreBootMode || return 1
|
||||
|
||||
|
||||
+2
-8
@@ -301,19 +301,15 @@ addVMSVGADriver() {
|
||||
local drivers="$4"
|
||||
|
||||
local vmsvga_arch="$arch"
|
||||
[[ "${vmsvga_arch,,}" == "amd64" ]] && vmsvga_arch="x64"
|
||||
|
||||
local source="$drivers/vmsvga/$driver/$vmsvga_arch"
|
||||
local destination="$dir/\$OEM\$/\$1/Drivers/VMSVGA"
|
||||
local destination="$dir/\$OEM\$/\$1/Drivers/vmsvga"
|
||||
|
||||
if [ ! -d "$source" ]; then
|
||||
error "Failed to locate required VMware SVGA display driver directory: $source"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local files="vmx_svgaver.dll vmx_svga.cat vmx_mode.dll vmx_svga.sys vmwogl32.dll vmx_fb.dll vmx_svga.inf"
|
||||
[[ "$vmsvga_arch" == "x64" ]] && files+=" vmwogl64.dll"
|
||||
|
||||
local files="vmx_svgaver.dll vmx_svga.cat vmx_mode.dll vmx_svga.sys vmx_fb.dll vmx_svga.inf"
|
||||
local file
|
||||
|
||||
for file in $files; do
|
||||
@@ -339,8 +335,6 @@ addDisplayDriver() {
|
||||
local drivers="$4"
|
||||
|
||||
local qbochs_arch="$arch"
|
||||
[[ "${qbochs_arch,,}" == "amd64" ]] && qbochs_arch="x64"
|
||||
|
||||
local source="$drivers/qbochs/$driver/$qbochs_arch"
|
||||
local destination="$dir/\$OEM\$/\$1/Drivers/QBochs"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user