Windows XP network install

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:

  • PXE:
    • Use DHCP to get an IP address, the name of the TFTP server (next-server) and the name of the boot file.
    • Get the boot file (pxelinux.0) from the TFTP server using TFTP and chain it
  • pxelinux.0:
    • Get ldlinux.c32 using TFTP and start it
    • Get the configuration file via TFTP
      • First try using the MAC address (e.g. pxelinux.cfg/00-11-22-33-44-55-66)
      • If that fails, convert the IP address to hex (e.g. 10.0.240.239 becomes 0A00F0E6) then request e.g. pxelinux.cfg/0A00F0E6.
      • Remove a character from the end of the name and try again. Repeat until either there is success, or the name is null.
      • Finally, request pxelinux.cfg/default
    • The configuration file may specify a user interface (e.g. menu.c32) which will be downloaded at this stage
    • The user selects the Windows XP Netinstall option from the menu (or types it)
      • Syslinux gets startrom.0 (the renamed startrom.n12) via TFTP and chainloads it.
  • startrom.0 – Windows XP stage-0 boot:
    • Request ntldr, BOOTFONT.BIN (optional), ntdetect.com and winnt.sif
    • Read configuration from winnt.sif.
      • Use the SetupSourceDevice in the [SetupData] section to obtain the TFTP and SMB relative path from root.
    • Request around 120 bootstrap files from the TFTP server
      • These are listed in the appendix, and are all in the i386 directory.
  • The Windows XP loading screen appears
    • It takes a few minutes for Windows to load.
    • Windows XP Setup requests the rest of the files it needs using SMB, from the SetupSourceDevice path in winnt.sif.
  • Machine reboots from the hard disk to run the graphical setup wizard.
    • Files are again downloaded over SMB.
    • The 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
fixloader.py
#!/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.

Post-installation steps

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:

  • 7-Zip, surprisingly the latest version (as of April 2024) still supports Windows XP
  • Firefox – you'll need to search around and find the last Windows XP-compatible version.
    • You may not want to install this: it's not a stellar idea to use a massively outdated Windows XP system to browse the Internet…

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.

Useful changes to make with nLite

These are starting from a Windows XP SP3 CD.

  • Hotfixes, add-ons and update packs
  • Drivers – as needed.
    • Generally I integrate the drivers for whichever boards I'm using; this is usually the ASUS Rampage Formula and Intel D525MW.
    • As a minimum, include the AHCI drivers for your SATA controller, and the network drivers.
  • Remove components – disabled
  • Unattended
    • General tab:
      • Product Key: set to your product key
      • Misc
        • Skip OOBE (skips post-install setup)
      • System restore service
        • Turn Off
    • Users tab:
      • Set default Administrator password if desired
      • Add users if desired
    • Owner and Network ID tab: (this skips the user registration page in Setup)
      • Full name: BUILD
      • Organization: BUILD
      • Workgroup: Workgroup (or your system workgroup)
    • Regional: (this skips the region settings page)
      • Language: English UK
      • Use language type
      • Timezone: GMT London
    • Desktop themes tab:
      • Options:
        • Default theme: Windows Classic
        • Colour scheme: Windows Classic style
      • Classic Start Menu: checked
    • Automatic updates:
      • Download and install
      • Elevate non-admins: checked
    • RunOnce tab:
      • TBD. Could use this to install drivers and applications after installation.
  • Options
    • High compression enabled (saves disk space and speeds up installation over the network)
  • Tweaks
    • Boot and Shutdown-Logon Page-Classic
    • Desktop-Internet Explorer icon-Hide
    • Desktop-My Computer icon-Show
    • Desktop-My Documents icon-Show
    • Desktop-My Network Places icon-Show
    • Desktop-Recycle Bin icon-Show
    • Explorer-Add 'Command Prompt' to folder context menu
    • Explorer-Advanced Search: preconfigure options
    • Explorer-Associate additional file types with Notepad
    • Explorer-Classic Control Panel
    • Explorer-Disable Accessibility keyboard shortcuts
    • Explorer-Disable Autorun
    • Explorer-Disable Search Assistant
    • Explorer-Display the contents of system folders
    • Explorer-Launch folder windows in a separate process
    • Explorer-Show extensions of known file-types
    • Explorer-Show hidden files and folders
    • Explorer-Show protected operating system files
    • Explorer-Show the full path in the Address Bar
    • Internet Explorer-Disable Internet Explorer link creation
    • Internet Explorer-Disable Market Place bookmark
    • Internet Explorer-Disable Media Player 6.4 created bookmarks
    • Internet Explorer-Disable Outlook Express link creation
    • Internet Explorer-Disable Password-Caching
    • Internet Explorer-Disable sound when popup is blocked
    • Internet Explorer-Enable Google URL-Search
    • Network-Disable Simple File Sharing
    • Privacy-Disable Driver Update Internet prompt
    • Privacy-Disable Error Reporting
    • Privacy-Remove Alexa
    • Security-Disable Web Open With prompt
    • Start Menu-Do not use Personalized Menus
    • Taskbar-Disable Windows Tour popup

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:

  • Modify the name of the loader from NTLDR to XPLDR:
    • sed -i -e 's/NTLDR/XPLDR/gi' startrom.n12
    • Move the modified pxe loader to tftpd root, and call it winxp.0
  • Modify the name of the response file from winnt.sif to winxp.sif
    • Extract the setuploader, using cabextract: cabextract /i386/SETUPLDR.EX_
    • sed -i -e 's/winnt\.sif/winxp\.sif/gi' setupldr.exe
  • Modify the name of ntdetect from ntdetect.com to ntdetect.wxp:
    • sed -i -e 's/ntdetect\.com/ntdetect\.wxp/gi' setupldr.exe
    • Move the modified setuploader to tftpd root, and call it 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:

  • There are three almost-identical files on the TFTP share, for each different sif file variant.
  • The new filename must be the same length as the old one, which limits the options available.

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: VLK
    • 335: Retail
    • OEM: OEM
    • 000: can be one of several; the full MPC/CID code will need to be looked up on Lunarsoft's list of valid product IDs.
      • The Lunarsoft list also explains how to decode a product ID as shown in the System Properties (Windows key + Break, or right click My Computer, select Properties).
  • Setup appearance: The “Enter Product Key” screen (during the first part of Setup) changes depending on the edition:
    • OEM: Shows a green Certificate of Authenticity, and asks for the key from it.
    • Retail: Shows a yellow Product Key sticker, and asks for the key from it.
    • VLK: Shows no stickers, and requests a Volume License product key.
    • Screenshots are available here: http://www.thetechguide.com/misc/winxp.html

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
Find me on Mastodon
  • Last modified: 2024/04/17 12:49
  • by philpem