2007年10月11日 星期四

Diskless Windows with PXE

Diskless Windows with PXE
A step-by-step guide to booting windows 98 without a hard disk, or a windows server (terminal or otherwise) using just a pxe enabled network card and a linux box.
You should be able to get this up and running in under a day, as there are quite a few steps involved, so we will be testing the setup at each stage to help iron out any problems. You will need a linux box, a pc for windows, a copy of windows98 (probably on CD) and a small hard disk (say 2GB) to use for the original windows 98 setup. The basic steps we are going to do are as follows
• Setup bootpd and tftpd on the linux server
• Setup PXE and check the windows pc will sucessfully boot from PXE
• Install a compact safe version of windows, and compress it.
• Transfer the compressed image, and some boot sectors to the linux box.
• Build a new hard disk image on the linux box
• Boot the windows box from the new disk image
Now I made that sound easy huh?
Setup bootpd and tftpd
Most linux distributions come with bootpd and tftpd, so you will have to refer to your distributions documentation as to how to install them (package, rpm or from source) All of the examples in this guide are based on Slackware Linux. We are just going to do the most basic setup possible in order to get this to work.
First up, if you have a server or router on your network that is providing dhcp addresses for all of the network, then you need to ensure that it is configured to not support bootp clients, as we are going to use our linux box for that. I'd allocate a seperate range of addresses just for the bootp clients, which will only need those addresses during the boot process. Once windows is booted, it can get it's real address from a dhcp server or use a static address as normal.
Bootpd uses a configuration file /etc/bootptab. We will set up a dummy entry for our windows pc, and you will need to replace the values with those for your network. For full details of the parameters check out the bootptab man page. We are using a very cut-down configuration, just enough to get it working.
.windows:\
:ht=1:ha=001122334455:\
:hd=/tftpboot:bf="pxelinux.0":\
:sa=10.0.0.5:sm=255.255.255.0:\
:ip=10.0.0.11:
You need to make the following replacements
ha with the MAC address of the windows network card.
hd with the path tftpd will serve the pxe files from
sa with the ip address of the linux box
sm with your networks subnet mask
ip with the ip address you want to give the windows box during the boot process
Now create the directory that tftpd will use for the pxe files. I'd recommend /tftpboot for simplicity at the moment. Create a small text file in the directory, and check you can retrieve it with tftp
root@linuxbox:~# tftp linuxbox
tftp> get /tftpboot/test.txt
Received 615 bytes in 0.0 seconds
tftp> quit
root@linuxbox:~#
If it fails, check the messages log file for any errors.

Setup PXE
You need to grap a copy of H. Peter Anvin's excellent Syslinux (http://syslinux.zytor.com/) that makes all of this possible. Extract memdisk and pxelinux.0 from the download and copy them to /tftpboot. Now create a directory /tftpboot/pxelinux.cfg where the pxe configuration files live. Copy the following basic config into a file called default in the /tftpboot/pxelinux.cfg directory.
DEFAULT net
PROMPT 0

LABEL local
LOCALBOOT 0

LABEL net
KERNEL memdisk
APPEND initrd=win.img
By having local and net sections in the config file means that by changing the default entry we can get the windows box to boot off of its local hard drive, or the network.
We are now going to check that everything is working ok. From windows create a bootable floppy disk. Make sure its bootable. Put it into the linux box, and copy the disk image off 製作windows開機片 floppy BootDisk
dd if=/dev/floppy of=/tftpboot/win.img bs=1024 count=1440 製作win.img開機images
You will probably need to go into the bios setup of the windows box, to enable network booting. You may need to change the boot order to allow network booting first. Check your motherboard manual for details.
Now for the moment of truth ... drumroll please ... Start the windows box.
If everything goes smoothly, you should have seen it start the PXE process, load memdisk and win.img and then give you an A:\ dos command prompt. If you have, then Hoorah, you may proceed. If not, then we need to do a little troubleshooting first.
• You didn't see the PXE stack load, and it try to request an IP address. Re-check your bios and network settings to find out how to get it to network boot.
• The PXE stack loaded, but sat there for ages before failing and booting of the local hard disk. This means it failed to get a bootp response. Check the MAC address in your bootptab file matches the MAC address of the windows network card. Check nothing else on the network is giving out bootp responses.
• The PXE stack loaded, but then complained accessing your tftp server. Check the /var/log/messages log file to see if there is a path of permissions problem. Double check the tftpd server is running. Check the ip address of the server in the bootptab file is correct. You are running bootp and tftp on the same box aren't you as PXE seems to work best when the bootp server is the same box as the tftp server.
Rinse and repeat.
備註:測試PXE開機是否能正常載入win.img
Diskless Windows with PXE - Part 2
Now that we have a working PXE setup its time to move on to install windows. Firstly change the default entry in you pxe config file to local so that pxe will tell the pc to boot off of the local disk.
Setup Windows
We need to install a small version of windows, small enough that once compressed we have enough memory for both the disk image and for windows to run. I'd recommend using an old hard disk for this, preferably one that hasn't had linux on, as the linux boot loaders (lilo, grub) can tamper with the bootsectors, which may cause you problems later on. You only need a small disk, as we are going to install windows in a small FAT16 partion of less that 2 Gigabytes.
I'm going to assume you are happy installing windows from scratch, as I don't intend to walk you through step-by-step instructions of how to do it. These instructions are based on using a FAT16 partition, so when you set up the partion, use fdisk to make sure it it FAT16 and not FAT32. The easiest way I've found to do this, is when fdisk asks if you want to support large disks, Just Say No.
When installing windows, it's best to choose the compact setting so that it only installs the bare minumum. If you want to install lots of other software, I'd recommend installing them to a network drive, either another windows box, or a linux box running samba. I've found that the compact install once compressed will easily fit in under 90Mb, so it may be possible to run with just 128Mb RAM.
There are special configurations, such as win98 lite that are supposed to trim even more fat off, but I've not personally tried them.
Now we need start tweaking the settings so we can compress it easily. Firstly we may as well turn off the swap file, as we won't be needing it when we are running from a ramdisk. Go to Start->Settings->ControlPanel and click on System. Now choose the performance tab, click on the virtual memory button and Disable Virtual Memory 關閉虛擬記憶體
Next up, if you copied any files onto the box such as drivers, you can delete the install files, especially ANYTHING in the temp directory. You should now find you are using less than 200Mb of your C drive.
Time to Compress. We are going to use DriveSpace to compress windows so that we can use a smaller ramdisk, and to make moving windows around MUCH easier.
Go to Start->Programs->Accessories->System Tools->DriveSpace.
Choose to compress your C drive. I'd usually recommend leaving say 20MB of free space on the compressed C drive, as this is enough space for any temporary files windows needs to create. You will probably need to reboot a few times to finish the compression. Usually windows remaps your original hard drive to H: and the compressed drive to C:
If you look at your H:\ drive, you should see most of the files are marked as hidden system files, and the important one is DRVSPACE.000 which is the file containing your compressed filesystem.
In order for windows to happily boot from a ramdisk, we may need to turn off a few filesystem settings.
Go to Start->Settings->Control Panel Click on System. Go to the Performance tab. Click on the FileSystem Button, and go to the TroubleShooting tab.
Booting windows off of a hardisk image, you shouldn't need to tick any of theses, but if windows has problems starting, come back here, and tick all of them to start with. When I intially started with this diskless windows project, I was using 170MB floppy disk images, and needed some of these selected in order to get windows running. Your mileage may vary.
Time to get onto the fun part.
Diskless Windows with PXE - Part 3
Now we have a working PXE system, and windows compressed, we can start on the disk image.
Build a new hard disk image
If you had a small enough hard disk, you could just use dd to copy the entire image onto linux for booting via PXE, but the fun (do I really mean fun?) part is being able to create disk images of any size, so you can match the size of your compressed windows file (drvspace.000)
In order to make bootable disk images, we need to copy a couple of sectors off of your existing windows harddrive. We only need to do this once, as from these two sectors we can build any size disk image.
First up, we need to get the windows harddrive into your linux box, so we can read bits off of it. Once in your linux box (I'll assume you've added it as the secondary master hdc) we need to make a note of some of its geometry settings. Run fdisk /dev/hdc and then press p to view the partition table. You should see your FAT16 partion there in all its glory. Make a note of the number of sectors (and bytes per sector).
The two bits we need off this disk, are the first 384 bytes of the disk, and the first 512 bytes of the first partion (were you've install windows)
dd if=/dev/hdc of=hd.384 bs=384 count=1 匯出備份開機磁區 0-384 byte
If you look at hd.384 in vi it should look a bit like 開機磁區大致內容如下所視
offset 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00000000 fa e9 a2 00 56 51 53 88 d3 80 e2 8f f6 c3 20 74 úé¢.VQS.Ó.â.öà t
00000010 31 bb aa 55 b4 41 cd 13 72 28 81 fb 55 aa 75 22 1»ªU´AÍ.r(.ûUªu"
00000020 f6 c1 01 74 1d 5b 59 1e 66 6a 00 57 51 06 53 6a öÁ.t.[Y.fj.WQ.Sj
00000030 01 6a 10 89 e6 16 1f b8 00 42 cd 13 8d 64 10 1f .j..æ..¸.BÍ..d..
00000040 eb 45 5b 59 53 52 57 51 06 b4 08 cd 13 07 72 39 ëE[YSRWQ.´.Í..r9
00000050 51 c0 e9 06 86 e9 89 cf 59 c1 ea 08 92 40 83 e1 QÀé..é.ÏYÁê..@.á
00000060 3f f7 e1 96 58 5a 39 f2 73 23 f7 f6 39 f8 77 1d ?÷á.XZ9òs#÷ö9øw.
00000070 c0 e4 06 86 e0 92 f6 f1 fe c4 00 e2 89 d1 5a 5b Àä..à.öñþÄ.â.ÑZ[
00000080 86 f0 b8 01 02 cd 13 eb 09 59 5f eb 02 b4 40 5a .ð¸..Í.ë.Y_ë.´@Z
00000090 5b f9 5e c3 5e ac 08 c0 74 09 b4 0e bb 07 00 cd [ù^Ã^.Àt.´.»..Í
000000a0 10 eb f2 f4 eb fd 31 c0 8e d0 bc 00 7c fb fc 8e .ëòôëý1À.м.|ûü.
000000b0 d8 8e c0 bf 00 06 89 e6 b9 00 01 f3 a5 ea c2 06 Ø.À¿...æ¹..ó¥êÂ.
000000c0 00 00 b8 00 12 b3 36 cd 10 be be 07 b9 04 00 84 ..¸..³6Í.¾¾.¹...
000000d0 14 89 f5 78 3f 83 c6 10 e2 f5 e8 b7 ff 4e 6f 20 ..õx?.Æ.âõè•ÿNo
000000e0 70 61 72 74 69 74 69 6f 6e 20 61 63 74 69 76 65 partition active
000000f0 0d 0a 00 84 14 79 1d e8 9a ff 49 6e 76 61 6c 69 .....y.è.ÿInvali

Now to pull of the first 512 bytes of the first partition, we need to calculate where the first partition starts. If your hard drive has 63 sectors (with 512 bytes per sector) then under dos, the first partion starts 63 x 512 bytes in.
dd if=/dev/hdc of=hdp1.512 bs=512 skip=63 count=1 匯出分割區 起始位置 = 63x512 byte
Which under vi should look a bit like
offset 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00000000 eb 3c 90 4d 53 57 49 4e 34 2e 31 00 02 40 01 00 ë<.MSWIN4.1..@..
00000010 02 00 02 00 00 f8 fc 00 3f 00 40 00 3f 00 00 00 .....øü.?.@.?...
00000020 41 e0 3e 00 80 00 29 cf 1b 32 45 20 20 20 20 20 Aà>...)Ï.2E
00000030 20 20 20 20 20 20 46 41 54 31 36 20 20 20 33 c9 FAT16 3É
00000040 8e d1 bc fc 7b 16 07 bd 78 00 c5 76 00 1e 56 16 .Ѽü{..½x.Åv..V.
00000050 55 bf 22 05 89 7e 00 89 4e 02 b1 0b fc f3 a4 06 U¿"..~..N.±.üó¤.
00000060 1f bd 00 7c c6 45 fe 0f 38 4e 24 7d 20 8b c1 99 .½.|ÆEþ.8N$} .Á.
00000070 e8 7e 01 83 eb 3a 66 a1 1c 7c 66 3b 07 8a 57 fc è~..ë:f¡.|f;..Wü
00000080 75 06 80 ca 02 88 56 02 80 c3 10 73 ed 33 c9 fe u..Ê..V..Ã.sí3Éþ
00000090 06 d8 7d 8a 46 10 98 f7 66 16 03 46 1c 13 56 1e .Ø}.F..÷f..F..V.
000000a0 03 46 0e 13 d1 8b 76 11 60 89 46 fc 89 56 fe b8 .F..Ñ.v.`.Fü.Vþ¸
While the disk is in the Linux box we may as well take this easy opportunity to copy all the files off. Make sure you get the hidden files as well (eg. io.sys, msdos.sys etc)
Now to create a new disk image. I usually size the disk image 5MB larger than the files it's going to take, so there is a little free space if needed. But if you are tight on memory, you may need to play with this.
Firstly create an empty file for the image. All of the following code assumes a 100MB disk which is is 512Bytes * 204800 blocks. The disk image geometry will be 100 cylinders, 64 heads, 32 sectors and 512 bytes per sector. This allows the cylinder count to match the size in Megabytes. If you are making a different size, then adjust accordingly.
dd if=/dev/zero of=hd.img bs=512 count=204800 100MB=512Bytes * 204800 blocks
Now mount the disk as a loop device
losetup /dev/loop0 hd.img 掛載hd.img
If you already have something loaded as loop0 you'll need to use a different loop device We need to create a partition table so run
fdisk /dev/loop0 掛載成 loop 分割區
Press x to go to the advanced menu, press c then 100 to set the cylinders. Then h and 64 for the heads, then s and 32 for the sectors. fdisk will probably then tell you its setting the sector offset for dos compatibility, which is what we want.
Now press r to return to the main menu, n to create a new partion. Create it as the first primary partition. Take the defaults offered, and fill the disk. Now press t and 6 to set its type id to 6 (FAT 16) and press a to make the partition active.
Now press w to write the partition to the file. fdisk will complain that it was unable to reread the disk, don't worry. restart fdisk and press p and you should see your lovely partition sitting there. double check the cylinders, heads and sectors for the disk are correct.

root@linuxbox:~# fdisk /dev/loop0

Command (m for help): p

Disk /dev/loop0: 64 heads, 32 sectors, 100 cylinders
Units = cylinders of 2048 * 512 bytes

Device Boot Start End Blocks Id System
/dev/loop0p1 * 1 100 102384 6 FAT16

Command (m for help):
Now we have a disk image with partition table, we don't need to make it ever again. All of the rest of the commands we need to finish off can be scripted as they are not interactive.
remember to unmount the loop device losetup -d /dev/loop0
We could just mount the new partion we have created, and copy the files on , but I've found linux dies if when you try to copy the 90mb drvspace.000 file on. Oops. Think there must be a bug there somewhere. So we need to create a stand-alone partition image, the same size as the one above, which we can copy files to, and then insert that image into the disk image, at the location of partition 1. See I said it was fun. Oh, and it gets better, just wait.
mkdosfs -F 16 -S 512 -R 1 -C hdp1.img 102384
When mkdosfs is creating large images it defaults to 32 sectors and 64 heads, which is why we used the same geometry for the disk image we fdisk'd. Now the partition is made, we don't ever need to re-make it if we just want to update the windows files in the image. Now mount the partition image, copy in the files, unmount it, and inject it into the disk image.
mount -o loop -t msdos hdp1.img /mnt/hd
rm /mnt/hd/*.*
cp win98/*.* /mnt/hd
umount /mnt/hd
dd if=hdp1.img of=hd.img conv=notrunc bs=512 count=204768 seek=32
Now, is when the real fun begins. In order to get this disk image to actually boot, its needs a disk boot sector and a bootable partition boot sector. But these sectors need to contain the geometry for the disk we are creating, not the disk they came from. Hence the following jiggery pokery.
# copy on the disk boot sector
dd if=hd.384 of=hd.img bs=1 count=384 conv=notrunc

# read the partion boot sector off the disk image
dd if=hd.img of=vdp1.old bs=512 skip=32 count=1

# make a copy of the real partition boot sector
cp hdp1.512 vdp1.new

# read bytes 12 to 36 from old image bootsector to the new bootsector
dd if=vdp1.old of=vdp1.new conv=notrunc bs=1 skip=11 seek=11 count=25

# turn sectors into hex and escape the value to a file
echo -e -n "\x20" > vdp1.fix

# inject the value into the new boot sector
dd if=vdp1.fix of=vdp1.new conv=notrunc bs=1 count=1 seek=28

# inject the new boot sector to the start of the partion
dd if=vdp1.new of=hd.img conv=notrunc bs=512 seek=32 count=1
Ok has your head stopped spinning? so copy the image to the tftpboot directory
cp hd.img /tftpboot/win.img
If you want to know what you just did, visit Hale's Boot Sector Disassembly We should now be ready to boot windows. Set the pxe config to use the win.img file, and reboot your windows box. If everything goes according to plan, windows should load just fine.
If you want to save your diskimage from ram back to the linux box, so you can save your changes and make a new disk image, then close all your windows apps and drop into a dos command prompt. Change to the H drive, un-hide the drvspace.000 file, and copy it over the network to the linux server. The easiest way is to have samba installed on the linux server, and mount a drive from windows.
C:\windows>H:
H:\>attrib -s -h -r DRVSPACE.000
H:\>copy DRVSPACE.000 \\linuxbox\root

Troubleshooting
If windows fails to start there are three main areas you may be having a problem.
Firstly does the disk image load completely. If not, then there could be timeout issues or, memory issues. Check your graphics card is not taking more memory than you expected, leaving you with insufficient.
Secondly does the disk image boot. If not, then check the steps when you created it. Retry the image one step at a time. mkdosfs can paste a message into the partition it creates, use it to check that the partition is even trying to load, before fixing its boot sector. Were the boot sectors you copied from the real disk ok? You may need to read Hale's guide and check your sectors by hand with vi
Thirdly windows tries to start but throws a wobbly. Go back to the windows hard disk, and tick all of the troubleshooting checkboxes. Also add the line bootmenu=1 to the bottom of your msdos.sys file, and try booting into safe mode.
Rinse and repeat.
If you are a boot sector guru and spot some error
with how I'm doing this, please let me know.

沒有留言: