This is a useful technique if you don't have an XP installation CD and need to install Windows XP on an old system which supports PXE. I've found that USB installation is unreliable.
There are quite a few moving parts in the Windows XP network install process:
next-server
) and the name of the boot file.pxelinux.0
) from the TFTP server using TFTP and chain itpxelinux.0
:ldlinux.c32
using TFTP and start itpxelinux.cfg/00-11-22-33-44-55-66
)0A00F0E6
) then request e.g. pxelinux.cfg/0A00F0E6
.pxelinux.cfg/default
menu.c32
) which will be downloaded at this stageWindows XP Netinstall
option from the menu (or types it)startrom.0
(the renamed startrom.n12
) via TFTP and chainloads it.startrom.0
– Windows XP stage-0 boot:ntldr
, BOOTFONT.BIN
(optional), ntdetect.com
and winnt.sif
winnt.sif
.SetupSourceDevice
in the [SetupData]
section to obtain the TFTP and SMB relative path from root.i386
directory.SetupSourceDevice
path in winnt.sif
.OriSrc
parameter in the [data]
section of winnt.sif
specifies where Windows will look for install files (e.g. drivers) after it has been installed.Download the following:
Create the share directory and copy the Windows XP CD contents into it:
sudo zfs create zpool/risinstall cd /mnt/zfs/risinstall mkdir winxp_32bit cd winxp_32bit # Unpack the CD. Can also use 'cp -r /media/WINXP/* .' 7z x /media/WINXP.ISO # Fix permissions and convert filenames to lower case find -type d -exec chmod 755 {} \; find -type f -exec chmod 644 {} \; find . -depth -exec rename 's!([^/]*\Z)!lc($1)!e' {} + # Change names of files which stage-0 TFTP requests as uppercase, back to uppercase for i in KDCOM.DL_ BOOTVID.dl_ SETUPREG.HI_ SETUPREG.HIV SPDDLANG.SY_ WMILIB.SY_ OPRGHDLR.SY_ 1394BUS.SY_ PCIIDEX.SY_ USBPORT.SY_ USBD.SY_ HIDCLASS.SY_ HIDPARSE.SY_ VIDEOPRT.SY_ SCSIPORT.SY_ CLASSPNP.SY_ TDI.SY_ ; do mv i386/`echo $i | tr '[:upper:]' '[:lower:]'` i386/$i done # Make the system files needed for Setup executable (required by Samba 4, see manpage https://www.samba.org/samba/docs/current/man-html/smb.conf.5.html#ACLALLOWEXECUTEALWAYS) chmod 755 i386/system32/* i386/*.dll i386/*.exe i386/*.com
Edit /etc/samba/smb.conf
to add the share:
[risinstall] comment = Unattended Windows XP install path = /mnt/zfs/risinstall guest ok = yes browseable = no writeable = yes locking = no
Restart Samba (sudo service smbd restart
).
Add these lines to /etc/dnsmasq.d/pxe.conf
, replacing the XX
'ed MAC address with the target PC's MAC address, and TFTP-SERVER
with the hostname or IP address of the TFTP server.
; Change the MAC address to that of the PC you want to netboot dhcp-host=XX:XX:XX:XX:XX:XX,set:netbootwxp ; Windows XP Netinstall for dhcp-boot=tag:netbootwxp,pxelinux.0,TFTP-SERVER,TFTP-SERVER
Install the TFTP server, PXELinux and Syslinux:
sudo apt install pxelinux syslinux-efi tftpd-hpa
Windows XP requests files from TFTP using Windows naming conventions, so we need to use a TFTP map file to convert these names to Unix
# Convert Windows naming conventions to Linux (backslashes to forward-slashes) rg \\ / # Convert non-absolute files to absolute. r ^[^/] /srv/tftp/\0 # Convert relative paths to their absolute position r ^/syslinux/ /srv/tftp\0 r ^/pxelinux.cfg/ /srv/tftp\0 r ^/winxp_32bit/ /srv/tftp\0 # Add the remote IP address as a folder on the front of all requests. # This can be useful for sending different winnt.sif's to different machines. #r ^ \i/
And edit /etc/default/tftpd-hpa
to set:
# /etc/default/tftpd-hpa TFTP_USERNAME="tftp" TFTP_DIRECTORY="/srv/tftp" TFTP_ADDRESS=":69" #TFTP_OPTIONS="--secure -vvv -m /etc/tftpd-hpa.rules" TFTP_OPTIONS="-vvv -m /etc/tftpd-hpa.rules"
Note that secure mode is disabled - this is deliberate. In secure mode, tftpd-hpa
runs in a chroot
inside the TFTP directory, which prevents it from following symlinks outside the TFTP root.
Next set up PXELinux:
cd /srv/tftp sudo cp /usr/lib/PXELINUX/pxelinux.0 . sudo cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi . sudo mkdir syslinux for i in ldlinux.c32 libutil.c32 menu.c32; do sudo cp /usr/lib/syslinux/modules/bios/$i syslinux/; done mkdir pxelinux.cfg cat <<EOF >pxelinux.cfg/default timeout 0 prompt 1 ui menu.c32 label xp32_netinst kernel startrom.0
Prepare the Windows XP installation files:
cp /mnt/zfs/risinstall/winxp_32bit/i386/ntdetect.com . cp /mnt/zfs/risinstall/winxp_32bit/i386/setupldr.bin ntldr # Decompress startrom.n12 as startrom.0 7z x /mnt/zfs/risinstall/winxp_32bit/i386/startrom.n1_ mv startrom.n12 startrom.0 # Convert SETUPLDR.BIN into NTLDR fixloader.py ntldr
#!/usr/bin/env python3 # -*- Mode: Python; tab-width: 4 -*- # # Fix for setuploader # # Copyright (C) 2005-2006 Gianluigi Tiesi <sherpya@netfarm.it> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # ====================================================================== from sys import argv, exit as sys_exit if __name__ == '__main__': if len(argv) < 2: print('Usage: fixloader.py ntldr') sys_exit() data = open(argv[1], 'rb').read() if data.find(b'setupldr.exe')==-1: print('Wrong file') sys_exit() if data[:2] == b'MZ': print('Loader already fixed') sys_exit() data = b'MZ' + data.split(b'MZ', 1).pop() open(argv[1], 'wb').write(data) print('Loader fixed')
Create a file called winnt.sif
in the TFTP root. The one below is an example.
Replace FILESERVER
with the SMB name of the file server, and RISINSTALL
with the share name.
OriSrc
should point to the i386
directory as it's used if Windows needs extra files after it's been installed.
SetupSourceDevice
is the SMB path in the form of the device, and should point to what is effectively the root directory, one level up from the i386
directory.
[data] floppyless = "1" msdosinitiated = "1" ; Needed for second stage -- this is used as the installation path for Windows itself (if it needs things later) OriSrc = "\\FILESERVER\RISINSTALL\winxp_32bit\i386" OriTyp = "4" LocalSourceOnCD = 1 DisableAdminAccountOnDomainJoin = 1 ; ;;;;;;;;;;;;; ; Copy the [data] section from your nLite i386/WINNT.SIF file into the area below. ; ;;;;;;;;;;;;; AutomaticUpdates="Yes" Autopartition=0 MsDosInitiated=0 UnattendedInstall="Yes" ; ;;;;;;;;;;;;; ; End nLite area ; ;;;;;;;;;;;;; [SetupData] OsLoadOptions = "/fastdetect" ; Needed for first stage SetupSourceDevice="\Device\LanmanRedirector\FILESERVER\RISInstall\winxp_32bit" [RemoteInstall] ; Avoid automatic format/repartition Repartition = No UseWholeDisk = No [UserData] ; Samba will see this as an underscore ComputerName = * ProductID=XXXXX-XXXXX-XXXXX-XXXXX-XXXXX ; ;;;;;;;;;;;;; ; Copy your nLite i386/WINNT.SIF file (except the [data] section) below. ; ;;;;;;;;;;;;;
BINL is used to convert a network card identity (PCI ID) into a device driver name. It requires a server on the local network, and a directory of INF files. The SYS file is retrieved via TFTP.
If you need an Ethernet driver which isn't included with Windows XP, download and unpack it. For this example I'll be using the Marvell Yukon driver.
First we create the BINL support directories and unpack the Windows XP standard driver descriptions:
mkdir -p /mnt/zfs/risinstall/binl/tmp cd /mnt/zfs/risinstall/binl/tmp cabextract /mnt/zfs/risinstall/winxp_32bit/I386/*.IN_ cabextract /mnt/zfs/risinstall/winxp_32bit/I386/DRIVER.CAB
Next we copy the Marvell Yukon INF file into the BINL input directory, and the driver into the Windows i386 directory:
cp /mnt/zfs/risinstall/Drivers/yukon/XP32/*.inf /mnt/zfs/risinstall/binl/tmp cp /mnt/zfs/risinstall/Drivers/yukon/XP32/*.sys /mnt/zfs/risinstall/winxp_32bit/i386
And the same for the Realtek RTL811E drivers:
cp /mnt/zfs/risinstall/Drivers/rtl8111e/WINXP/*.inf /mnt/zfs/risinstall/binl/tmp cp /mnt/zfs/risinstall/Drivers/rtl8111e/WINXP/*.sys /mnt/zfs/risinstall/winxp_32bit/i386
Now run nLite and use it to integrate the network drivers into the installer. If you don't do this, then the network drivers will only be used for the setup process, and will not actually be installed on the system.
Finally we create the BINL cache and start the server:
# Create BINL cache cd /mnt/zfs/risinstall/binl ../ris-linux-0.4/infparser.py tmp # Start BINL server gcc -o binlsrv ../ris-linux-0.4/binlsrv.c ./binlsrv # Alternatively use the Python BINL server ../ris-linux-0.4/binlsrv.py
I've found that the Python BINL server doesn't always find the driver correctly (e.g. on the Intel D525MW), but the C version is quite reliable.
Now the TFTP, SMB and BINL servers should be running.
Configure the target system for PXE network boot, and trigger a netboot. On the Asus Rampage Formula system I used for testing, this is done by enabling the LAN Boot ROM, then hitting F8 for the boot menu, and selecting the Marvell Yukon PXE entry.
If you see NT_STATUS_ACCESS_DENIED
errors from Samba (or STATUS_ACCESS_DENIED
in Wireshark decoded SMB protocol traces), then check whether the file being requested is executable. If so, and the client expects to execute it, then it may need to be chmod +x
'd.
This more or less boils down to installing the applications and drivers you need. I usually put these in a subdirectory of the RISInstall
share directory, then run them over the network.
I've yet to find a good way to pre-install applications automatically. I imagine something could be done with a RunOnce
modification in nLite, but that's something I need to look into.
The main applications you'll want to install are:
nLite can be used to integrate service packs and drivers. Generally this is most useful for network and RAID/AHCI drivers as everything else can usually be loaded after the installation has completed.
Note that some filenames will need to be fixed after nLite has built the image:
mv TXTSETUP.SIF txtsetup.sif
mv IASTOR.SY_ iaStor.sy_
(Intel ICH9R RAID drivers)Other files may need to be renamed; these will be visible when the setup is first started from the nLite'd image directory.
These are starting from a Windows XP SP3 CD.
BUILD
BUILD
Workgroup
(or your system workgroup)
Sometimes it's necessary to have several different winnt.sif
files, to accommodate different deployment images.
The easiest way to achieve this is to modify the TFTP server rules
file to remap requests for winnt.sif
to winnt_\i.sif
. This will select the SIF file based on the IP address of the requesting machine.
Sometimes it's preferable to have multiple images which can be selected from the menu. This can be achieved by patching the loaders, as documented by Jui-Nan Lin:
NTLDR
to XPLDR
:sed -i -e 's/NTLDR/XPLDR/gi' startrom.n12
winxp.0
winnt.sif
to winxp.sif
cabextract /i386/SETUPLDR.EX_
sed -i -e 's/winnt\.sif/winxp\.sif/gi' setupldr.exe
ntdetect
from ntdetect.com
to ntdetect.wxp
:sed -i -e 's/ntdetect\.com/ntdetect\.wxp/gi' setupldr.exe
xpldr
The modified loader is referenced in the PXELinux configuration as winxp.0
. With the above modifications, the load order changes to:
winxp.0
(modified startrom
) → XPLDR
(modified ntldr
) → ntdetect.wxp
, winxp.sif
→ (install)
While this process works, it's imperfect:
sif
file variant.Per KB950722 and this thread on MSFN, this is usually caused by slipstreaming an XP Service Pack into an installation under Windows Server 2003 or Windows 7.
To resolve this, you'll have to recreate your nLite-d install image using Windows XP.
Windows XP images generally require a product key for the specific type of Windows in use. There are two ways to identify the image type.
SETUPP.INI
: The last three digits of the Pid
field identifies the image type.270
: VLK335
: RetailOEM
: OEM000
: can be one of several; the full MPC/CID code will need to be looked up on Lunarsoft's list of valid product IDs.These both assume the image hasn't been monkeyed with: changing the Pid will generally not work to change a VLK installation into a Retail one, per the comments on this MyDigitalLife post.
These files are requested by the text-mode version of the Windows XP setup utility.
All these files are in the i386
directory.
txtsetup.si_ txtsetup.sif biosinfo.in_ biosinfo.inf drvmain.sd_ drvmain.sdb migrate.in_ migrate.inf unsupdrv.in_ unsupdrv.inf halmacpi.dl_ ntkrnlmp.ex_ KDCOM.DL_ BOOTVID.dl_ SETUPREG.HI_ SETUPREG.HIV vgaoem.fo_ c_1252.nl_ c_437.nl_ l_intl.nl_ c_1252.nl_ c_437.nl_ l_intl.nl_ setupdd.sy_ SPDDLANG.SY_ pci.sy_ acpi.sy_ WMILIB.SY_ isapnp.sy_ acpiec.sy_ OPRGHDLR.SY_ ohci1394.sy_ 1394BUS.SY_ pcmcia.sy_ pciide.sy_ PCIIDEX.SY_ intelide.sy_ viaide.sy_ cmdide.sy_ toside.sy_ aliide.sy_ mountmgr.sy_ ftdisk.sy_ partmgr.sy_ fdc.sy_ dmload.sy_ dmio.sy_ sbp2port.sy_ lbrtfdc.sy_ usbehci.sy_ USBPORT.SY_ usbohci.sy_ usbuhci.sy_ usbhub.sy_ USBD.SY_ usbccgp.sy_ hidusb.sy_ HIDCLASS.SY_ HIDPARSE.SY_ serial.sy_ serenum.sy_ usbstor.sy_ vga.sy_ VIDEOPRT.SY_ i8042prt.sy_ kbdhid.sy_ kbdclass.sy_ SCSIPORT.SY_ cpqarray.sy_ atapi.sy_ aha154x.sy_ sparrow.sy_ symc810.sy_ aic78xx.sy_ i2omp.sy_ dac960nt.sy_ ql10wnt.sy_ amsint.sy_ asc.sy_ asc3550.sy_ mraid35x.sy_ ini910u.sy_ ql1240.sy_ aic78u2.sy_ symc8xx.sy_ sym_hi.sy_ sym_u3.sy_ asc3350p.sy_ abp480n5.sy_ cd20xrnt.sy_ ultra.sy_ adpu160m.sy_ dpti2o.sy_ ql1080.sy_ ql1280.sy_ ql12160.sy_ perc2.sy_ hpn.sy_ cbidf2k.sy_ dac2w2k.sy_ dmboot.sy_ cdrom.sy_ CLASSPNP.SY_ disk.sy_ sfloppy.sy_ ramdisk.sy_ ksecdd.sy_ ksecdd.sys fastfat.sy_ ntfs.sy_ ntfs.sys cdfs.sy_ ndis.sy_ ipsec.sy_ tcpip.sy_ TDI.SY_ ipnat.sy_ netbt.sy_ rdbss.sy_ mup.sy_ mrxsmb.sy_
Note that the network driver is also requested from TFTP, after its name has been obtained using BINL.
These are useful for debugging the stage-zero (TFTP bootstrapping) phase.
Source: https://www.syslinux.org/archives/2004-August/003883.html
Making them exclusive to WinXP is a bit tricky, see: https://www.syslinux.org/archives/2004-August/003884.html
rg A a # lower case rg B b # lower case rg C c # lower case rg D d # lower case rg E e # lower case rg F f # lower case rg G g # lower case rg H h # lower case rg I i # lower case rg J j # lower case rg K k # lower case rg L l # lower case rg M m # lower case rg N n # lower case rg O o # lower case rg P p # lower case rg Q q # lower case rg R r # lower case rg S s # lower case rg T t # lower case rg U u # lower case rg V v # lower case rg W w # lower case rg X x # lower case rg Y y # lower case rg Z z # lower case