QEMU/SunOS 4.1.4

Motivation
This chapter describes the installation of SunOS 4.1.4 (= Solaris 1.1.2) on an emulated QEMU 1.4.0 SPARC machine. SunOS 4.1.4 is the last purely BSD based Unix operating system by Sun Microsystems. It was superseded by Solaris 2.x (= SunOS 5.x), based on System V Release 4. Programs compiled for SunOS 4.x won't run without binary emulation on Solaris version 2.x. The Unix file utility under Solaris 2.4 will print reports like Sun demand paged SPARC executable for SunOS 4.1.4 binaries and ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped for Solaris 2.4 binaries. If you want to run ancient computer programs of the first kind you might want to try it natively on SunOS 4.1.4.

Prerequisites
In the following the CD image file is named solaris1.1.2.iso and the ROM image file is named ss5.bin. For our installation we create a disk image of 2 GB in size: $ qemu-img create -f qcow2 -o compat=1.1 sunos414.img 2G Formatting 'sunos414.img', fmt=qcow2 size=2147483648 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off For compatibility with QEMU versions prior to 1.1 leave out compat=1.1. If you need more space, replace 2G by a higher value, but keep in mind that the installation program won't provide a predefined disk geometry. You'll have to enter the CHS values yourself during the installation.
 * SunOS 4.1.4 installation CD-ROM image
 * SPARCstation 5 ROM Rev. 2.15 image

Copying the Miniroot Image
We start the emulated machine with the following command. Here and in the following all commands on the host (the system QEMU runs on) will have the shell prompt "$", the ROM prompt will be "ok", the guest prompt (of the system running on the emulated machine) will be "#" and the QEMU monitor prompt will be "<tt>(qemu)</tt>". $ qemu-system-sparc -monitor tcp::4444,server,nowait -bios ss5.bin -m 32 -nographic -hda sunos414.img -hdb solaris1.1.2.iso We omit the <tt>-machine</tt> option, which means QEMU will emulate a SPARCstation 5 (based on the sun4m architecture) as default. The emulated machine provides no usable graphics, so we disable graphical output with <tt>-nographic</tt>, redirecting all output to the terminal from which we started QEMU. Later we will explain how to run X Windows programs on the guest by exporting the display to an X server running on the host. Since there will be no keyboard emulation either, all input will be taken from the terminal as well. You will see the following ROM message: Keyboard not present. Using tty for input and output. The <tt>-monitor</tt> option lets us control QEMU over a telnet connection, in our example over port 4444. For this execute $ telnet localhost 4444 in another console. Alternatively we could omit the <tt>-monitor</tt> option and use the "Ctrl-a c" command to switch between console (in which QEMU runs) and the QEMU monitor prompt. In this case type "Ctrl-a h" to get help. Useful commands are (qemu) stop to pause the emulated machine and (qemu) cont to resume. You will always have full CPU load on the host system while the emulated machine is not paused. This command terminates QEMU immediately: (qemu) q Our emulated machine has 32 MB of RAM, indicated by the <tt>-m</tt> option. That seems to be the minimal amount that won't make QEMU exit with the error: qemu: fatal: Trap 0x29 while interrupts disabled, Error state The maximal amount for a SPARCstation 5 ist 256 MB. Choose 32 MB if you don't want to wait for the ROM memory test, which takes some time. We don't make use of the emulated CD-ROM device via the <tt>-cdrom</tt> option because it doesn't work. Instead, we declare the installation CD to be the second hard drive. The start sequence of the ROM finishes with a failed network boot: Boot device: /iommu/sbus/ledma@5,8400010/le@5,8c00000 File and args: Internal loopback test -- Wrong packet length; expected 36, observed 64 It seems that QEMU version 1.4.0 is not capable of allowing us to boot over network.

We boot with ok boot disk1:d from the fourth partition on the second hard drive (our CD image), which carries the boot block for our architecture.

Make the following choices: What would you like to do? 1 - install SunOS mini-root 2 - exit to single user shell Enter a 1 or 2: 1 Beginning system installation - probing for disks. Which disk do you want to be your miniroot system disk? 1 - sd1: <CD-ROM Disc for SunOS Installation> at esp0 slave 8 2 - sd3: > at esp0 slave 0 3 - exit to single user shell Enter a 1, 2 or 3: 2 selected disk unit "sd3". Do you want to format and/or label disk "sd3"? 1 - yes, run format 2 - no, continue with loading miniroot 3 - no, exit to single user shell Enter a 1, 2, or 3: 1 Notice that the booted system has its own idea about how to order the attached drives. The device we booted from (the second hard disk) is given the name <tt>sd1</tt> and our target disk is named <tt>sd3</tt>. We chose to format the latter. We select the type "SUN2.1G": format> type

AVAILABLE DRIVE TYPES: 0. Quantum ProDrive 80S 1. Quantum ProDrive 105S 2. CDC Wren IV 94171-344 3. SUN0104 4. SUN0207 5. SUN0320 6. SUN0327 7. SUN0424 8. SUN0535 9. SUN0669 10. SUN1.0G 11. SUN1.05 12. SUN1.3G 13. SUN2.1G 14. CD-ROM Disc for SunOS Installation 15. other Specify disk type (enter its number): 13 selecting sd3: <SUN2.1G> [disk formatted, no defect list found] The predefined disk formats are stored in <tt>/etc/format.dat</tt> on the miniroot file system. The path to our miniroot image on the CD-ROM is: EXPORT/EXEC/KVM/SUN4M_SUNOS_4_1_4/MINIROOT_SUN4M In <tt>format.dat</tt> we find for the disk geometry of our disk type: disk_type = "SUN2.1G" \ : ctlr = SCSI : fmt_time = 4 \ : ncyl = 2733 : acyl = 2 : pcyl = 3500 : nhead = 19 : nsect = 80 \ : rpm = 5400 : bpt = 44823 and for the predefined partitionings: partition = "SUN2.1G_PREINSTALL" \ : disk = "SUN2.1G" : ctlr = SCSI \ : a = 0, 62320 : b = 41, 197600 : c = 0, 4154160 : g = 171, 1947120 \ : h = 1452, 1947120

partition = "SUN2.1G_STANDARD" \ : disk = "SUN2.1G" : ctlr = SCSI \ : a = 0, 62320 : b = 41, 197600 : c = 0, 4154160 : g = 171, 3894240 Notice that <tt>ncyl*nhead*nsect=4154160</tt> is the number of 512 byte blocks in the third partition, which comprises the whole usable space, while the size of the disk is <tt>(ncyl+acyl)*nhead*nsect=4157200</tt> blocks, which is approximately 1.98 GB or 2.13e9 Bytes. If you want to install on a disk image without predefined geometry you'll have to enter the figures yourself.

To write the partitioning to the disk and print the partition table do: format> label Ready to label disk, continue? y

format> partition partition> print Current partition table (SUN2.1G_PREINSTALL): partition a - starting cyl     0, # blocks    62320 (41/0/0) partition b - starting cyl    41, # blocks   197600 (130/0/0) partition c - starting cyl     0, # blocks  4154160 (2733/0/0) partition d - starting cyl     0, # blocks        0 (0/0/0) partition e - starting cyl     0, # blocks        0 (0/0/0) partition f - starting cyl     0, # blocks        0 (0/0/0) partition g - starting cyl   171, # blocks  1947120 (1281/0/0) partition h - starting cyl  1452, # blocks  1947120 (1281/0/0)

partition> quit

The size of the swap partition <tt>b</tt> is 100 MB. In SunOS 4.x the size of the swap partition should be at least the size of the RAM because every program has reserved swap space that amounts to its memory size. Change the swap space to your needs and exit the format utility with: format> quit checking writeability of /dev/rsd3b 0+1 records in 1+0 records out Extracting miniroot ... using cdrom partition number 3 fastread: failed to open /dev/rsr0No such device or address ERROR while loading miniroot disk: /dev/rsd3b Extraction of the minroot by the <tt>extract</tt> script fails because the source CD-ROM device <tt>/dev/rsr0</tt> doesn't exist. In the file <tt>/extract</tt> we find the figures (in bytes) to locate the miniroot image: miniskip=4194304 minicount=7168000 and the command to copy it: fastread $cddev $cdpartno $miniskip $minicount > /dev/r${disk}b With this information we can extract the miniroot to the swap partition of our target disk: 1750+0 records in 1750+0 records out Reboot the machine with:
 * 1) dd if=/dev/rsd1d bs=4096 skip=1024 count=1750 of=/dev/sd3b
 * 1) reboot

Installation
Back on the ROM prompt we boot the miniroot: ok boot disk0:b -w The <tt>-w</tt> flag is necessary to make the mounted file system writable as required by the SunInstall program.

The SunInstall program won't let us select a hard disk as installation source. Therefore we link the CD-ROM device <tt>/dev/sr0</tt> to the hard disk associated with our CD-ROM image: SunInstall will recreate device names using the script <tt>/dev/MAKEDEV</tt>. To exclude<tt>/dev/sr0</tt> from the recreation we remove its entry in <tt>MAKEDEV</tt>:
 * 1) cd /dev
 * 2) mv sr0 sr0.bak
 * 3) ln -s sd1a sr0

We are now ready to fire up SunInstall:
 * 1) mv MAKEDEV MAKEDEV.bak
 * 2) sed 's/sr0 //' MAKEDEV.bak > MAKEDEV
 * 3) chmod 755 MAKEDEV
 * 4) cd /
 * 1) suninstall

Welcome to SunInstall

Remember: Always back up your disks before beginning an installation.

SunInstall provides two installation methods: 1. Quick installation

This option provides an automatic installation with a choice of        standard installations, and a minimum number of questions asked.

2. Custom installation

Choose this method if you want more freedom to configure your system. You must use this option if you are installing your system as a server.

Your choice (or Q to quit) >> 2

Select your terminal type: 1) Televideo 925       2) Wyse Model 50 3) Sun Workstation       4) Other

>> 4

Enter the terminal type ( the type must be in /etc/termcap ): >> ansi

Enter the local time zone name (enter ? for help):

>> ? The terminal type <tt>ansi</tt> seems to work well enough. If you encounter problems with the display of the SunInstall menus you can redraw the screen with "Ctrl-l". If you know the name of your time zone, you can enter it directly. With "?" we are led through a menu to select our time zone. After confirming the correct time setting we are led to the form assigning the host information: HOST FORM               [?=help] [DEL=erase one char] [RET=end of input data] - Workstation Information : Name : sunguest Type : x[standalone] [server]  [dataless]

Network Information : Ethernet Interface : [none] x[le0]

Internet Address  : 10.0.2.15 NIS Type          : x[none]  [master]  [slave]  [client]

Misc Information : Reboot after completed       :  [y] x[n]

Are you finished with this form [y/n] ? y   [x/X=select choice] [space=next choice] [^B/^P=backward] [^F/^N=forward] In this example we set the host name to "sunguest" and 10.0.2.15 is the standard address assigned to the guest system by QEMU. The next form lets us assign the disk information: DISK FORM               [?=help] [DEL=erase one char] [RET=end of input data] - Attached Disk Devices : [sd1]   x[sd3]

Disk Label : [default] x[use existing]  [modify existing] Free Hog Disk Partition : [d]  [e]  [f]  [g] x[h] Display Unit           : x[Mbytes]  [Kbytes]  [blocks]  [cylinders]

PARTITION START_CYL BLOCKS   SIZE     MOUNT PT             PRESERVE(Y/N) ==============================================================================    a     0         62320     31       /                          n     b     41        197600    100 c    0         4154160   2126 d    0         0         0 e    0         0         0 f    0         0         0 g    171       1947120   996      /usr                       n     h     1452      1947120   996      /home                      n

Ok to use this partition table [y/n] ? y   [x/X=select choice] [space=next choice] [^B/^P=backward] [^F/^N=forward] Eventually we set the source device and make a choice for a software selection: SOFTWARE FORM           [?=help] [DEL=erase one char] [RET=end of input data] - Software Architecture Operations : x[add new release] [edit existing release]

Media Information : Media Device  :  [st0]  [st1]  [st2]  [st_]  [xt0]  [mt0]  [fd0] x[sr0] Media Location : x[local] [remote]

Choice : x[all] [default]  [required]  [own choice] Executables path : /usr Kernel executables path : /usr/kvm

Ok to use these values to select Software Categories [y/n] ? y   [x/X=select choice] [space=next choice] [^B/^P=backward] [^F/^N=forward] We are then informed about the software packages to be installed and arrive at the final screen from which we can start the installation: MAIN MENU                                                           [?=help] -                  Sun Microsystems System Installation Tool

( + means the data file(s) exist(s) )

+    assign host information

+    assign disk information

+    assign software information

start the installation

exit suninstall

[RET/SPACE=next choice] [x/X=select choice] [^B/^P=backward] [^F/^N=forward] The existence of data files indicated by "<tt>+</tt>" means the entered data is not lost, even if we reboot the machine. After SunInstall has finished its job we can reboot with and should be able to boot our fresh system with: ok boot disk0
 * 1) reboot

At the login prompt we can enter <tt>root</tt> and get a shell prompt without password. The system can be stopped with and the machine can be shut down with: ok power-off
 * 1) halt

Guest Configuration
If you want to address the host system by a host name, assign it to the IP address 10.0.2.2 in <tt>/etc/hosts</tt> (on the guest): 10.0.2.2 qemuhost ^D where <tt>^D</tt> means Ctrl-d. A host name is necessary to use rlogin, rsh and rcp on the guest. For a connection to the outside we set the default route with add net default: gateway 10.0.2.2 and make it permanent with: 10.0.2.2 ^D Check the routes with: Routing tables Destination         Gateway              Flags    Refcnt Use        Interface localhost           localhost            UH       1      288        lo0 default             qemuhost             UG       0      0          le0 arpanet             sunguest             U        2      96         le0
 * 1) cat >> /etc/hosts
 * 1) route add default 10.0.2.2 1
 * 1) cat > /etc/defaultrouter
 * 1) netstat -r

User Networking
With the default networking back end of QEMU we can utilize the <tt>-redir</tt> option to enable connections between host and guest over Telnet (port 23), rlogin to the guest (port 513), or the copying of files between host and guest with rcp (port 514). Telnet can also be used to connect from the guest to the outside world if the host is connected to the Internet. For rlogin and rcp we'll need root access on a Linux host system to define packet filter rules. Start the emulated machine with: $ qemu-system-sparc -monitor tcp::4444,server,nowait -bios ss5.bin -m 32 -nographic -hda sunos414.img \ -redir tcp:4423:10.0.2.15:23 -redir tcp:4513:10.0.2.15:513 -redir tcp:4514:10.0.2.15:514 Use the <tt>info</tt> command of the QEMU monitor to print a table of the forwarded ports: (qemu) info usernet info usernet VLAN 0 (user.0): Protocol[State]   FD  Source Address  Port   Dest. Address Port RecvQ SendQ TCP[HOST_FORWARD] 10               *  4423       10.0.2.15    23     0     0 TCP[HOST_FORWARD]  9               *  4513       10.0.2.15   513     0     0 TCP[HOST_FORWARD]  8               *  4514       10.0.2.15   514     0     0 The ports on the host that are forwarded must be greater than 1023 (as long as you don't run qemu as root). To check on which ports QEMU is listening, do: $ netstat -tulpn | grep qemu tcp       0      0 0.0.0.0:4514            0.0.0.0:*               LISTEN      27021/qemu-system-s tcp       0      0 0.0.0.0:4423            0.0.0.0:*               LISTEN      27021/qemu-system-s tcp       0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN      27021/qemu-system-s tcp       0      0 0.0.0.0:4513            0.0.0.0:*               LISTEN      27021/qemu-system-s

After the guest system is booted we are able to connect from the host to the guest: $ telnet localhost 4423 and from the guest to the host: or from the guest to the outside (india.colorado.edu reports the current Coordinated Universal Time): Trying 128.138.140.44 ... Connected to 128.138.140.44. Escape character is '^]'.
 * 1) telnet 10.0.2.2
 * 1) telnet 128.138.140.44 13

56365 13-03-14 00:33:39 50 0 0 147.2 UTC(NIST) * Connection closed by foreign host. We can even check with the <tt>ping</tt> command from the guest that the host is alive: 10.0.2.2 is alive
 * 1) ping 10.0.2.2

Rlogin and rcp use fixed ports. We define port redirection rules on the host to get a connection to the guest. For this to work, it may be necessary to disable your firewall (or see below for a more accurate setting) before you execute as root: $ iptables -t nat -I OUTPUT -o lo -p tcp --dport 513 -j REDIRECT --to-ports 4513 $ iptables -t nat -I OUTPUT -o lo -p tcp --dport 514 -j REDIRECT --to-ports 4514 Print the rules with: $ iptables -t nat -n -L OUTPUT Chain OUTPUT (policy ACCEPT) target    prot opt source               destination REDIRECT  tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:514 redir ports 4514 REDIRECT  tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:513 redir ports 4513 These rules can be removed with: $ iptables -t nat -D OUTPUT 1 $ iptables -t nat -D OUTPUT 1 Under openSUSE 11.4, disabling the firewall would remove these rules. Therefore we would stop the firewall first and then define the rules. Alternatively we could keep the firewall up and remove only the following single rule: $ iptables -t raw -n -L OUTPUT Chain OUTPUT (policy ACCEPT) target    prot opt source               destination NOTRACK   all  --  0.0.0.0/0            0.0.0.0/0 with the command: $ iptables -t raw -D OUTPUT 1 This rule can be restored with: $ iptables -t raw -A OUTPUT -j NOTRACK

or by stopping the firewall and starting it again. Now we should be able to connect from the host to the guest with: $ rlogin -l root localhost and to copy files as root on the host in both directions: $ rcp file_on_host localhost: $ rcp localhost:file_on_guest. To use rcp as a regular user on the host, we would have to create a user with the same name on the guest.

For reasons unknown to the author a remote shell command like $ rsh localhost uname fails with: socket: protocol failure in circuit setup Rlogin, rsh and rcp from the guest to the host do not work in this setting. Port redirection with $ ssh -L 23:localhost:4423 localhost (as root) works for Telnet, but when redirecting the ports 513 and 514 over SSH, connections can't be established from the host. The error messages are: rlogind: Permission denied. when trying to rlogin to the guest and rcmd: localhost: short read when trying to rcp to the guest.

Using a TAP Device
In the previous section we have seen the shortcomings of QEMU's user networking. Using the tap networking back end allows for a unrestricted connection between host and guest. To create and configure a TUN/TAP interfaces on a Linux host we need root access: $ tunctl -t tap0 -u user_name_on_host $ ifconfig tap0 10.0.2.2 netmask 255.255.255.0 We start qemu with the command: $ qemu-system-sparc -monitor tcp::4444,server,nowait -nographic -bios ss5.bin -m 32 -hda sunos414.img \ -net nic,vlan=0 -net tap,vlan=0,ifname=tap0,script=no,downscript=no From the host we use the address 10.0.2.15 to access the host and from the guest we use the address 10.0.2.2 to access the host. For rlogin & co. on the guest we need to refer to the host system with the host name defined in <tt>/etc/hosts</tt>. We should be able to ping and to connect over Telnet, rlogin, rsh, and rcp without problem if permitted by the host configuration. The root rlogin may be disabled completely on the host and for users we usually need to add the address 10.0.2.2 to <tt>~/.rhosts</tt>. A firewall on the host must be configured (or disabled) to allow for such connections. We can also run X Window programs on the guest by displaying them on the host X server: $ xhost +10.0.2.15 (on the host) will allow access from the guest and starts the terminal emulator for the X Window System on the guest, displayed in an window on the host. We can give the guest access to the Internet by enabling IP forwarding on the host: $ echo 1 > /proc/sys/net/ipv4/ip_forward $ iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE where <tt>wlan0</tt> is the network device that connects the host to the Internet (often <tt>eth0</tt> for a LAN connection). The firewall on the host might need to be disabled to make it work.
 * 1) usr/openwin/bin/xterm -display 10.0.2.2:0

Running OpenWindows
With the TAP/TUN network setup, set the following environment variables on the guest: We export the display to a second X server running inside a window of our host X server: $ Xephyr :1 -ac -screen 1152x900 & Start the window manager on the guest: You should now see the OpenWindows desktop in he Xephyr window. Click with the right mouse button for the application menu. Unfortunately, the help viewer refuses to start with: XView error: NULL pointer passed to xv_set
 * 1) setenv DISPLAY 10.0.2.2:1.0
 * 2) setenv OPENWINHOME /usr/openwin
 * 3) setenv PATH $OPENWINHOME/bin:$PATH
 * 4) setenv LD_LIBRARY_PATH $OPENWINHOME/lib
 * 5) setenv MANPATH $OPENWINHOME/share/man:/usr/man
 * 6) setenv HELPPATH $OPENWINHOME/lib/help
 * 1) olwm &