QEMU/SunOS 4.1.4

Motivation

edit

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

edit
  • SunOS 4.1.4 installation CD-ROM image
  • SPARCstation 5 ROM Rev. 2.15 image

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.

Copying the Miniroot Image

edit

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 "(qemu)".

$ 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 -machine 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 -nographic, 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 -monitor 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 -monitor 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 -m 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 -cdrom 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:  <drive type unknown>> 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 sd1 and our target disk is named sd3. 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 /etc/format.dat 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 format.dat 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 ncyl*nhead*nsect=4154160 is the number of 512 byte blocks in the third partition, which comprises the whole usable space, while the size of the disk is (ncyl+acyl)*nhead*nsect=4157200 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 b 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 extract script fails because the source CD-ROM device /dev/rsr0 doesn't exist. In the file /extract 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:

# dd if=/dev/rsd1d bs=4096 skip=1024 count=1750 of=/dev/sd3b
1750+0 records in
1750+0 records out

Reboot the machine with:

# reboot

Installation

edit

Back on the ROM prompt we boot the miniroot:

ok boot disk0:b -w

The -w 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 /dev/sr0 to the hard disk associated with our CD-ROM image:

# cd /dev
# mv sr0 sr0.bak
# ln -s sd1a sr0

SunInstall will recreate device names using the script /dev/MAKEDEV. To exclude/dev/sr0 from the recreation we remove its entry in MAKEDEV:

# mv MAKEDEV MAKEDEV.bak
# sed 's/sr0 //' MAKEDEV.bak > MAKEDEV
# chmod 755 MAKEDEV
# cd /

We are now ready to fire up SunInstall:

# 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 ansi 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 "+" means the entered data is not lost, even if we reboot the machine. After SunInstall has finished its job we can reboot with

# reboot

and should be able to boot our fresh system with:

ok boot disk0

At the login prompt we can enter root and get a shell prompt without password. The system can be stopped with

# halt

and the machine can be shut down with:

ok power-off

Network

edit

Guest Configuration

edit

If you want to address the host system by a host name, assign it to the IP address 10.0.2.2 in /etc/hosts (on the guest):

# cat >> /etc/hosts
10.0.2.2 qemuhost
^D

where ^D 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

# route add default 10.0.2.2 1
add net default: gateway 10.0.2.2

and make it permanent with:

# cat > /etc/defaultrouter
10.0.2.2
^D

Check the routes with:

# netstat -r
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

User Networking

edit

With the default networking back end of QEMU we can utilize the -redir 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 info 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:

# telnet 10.0.2.2

or from the guest to the outside (india.colorado.edu reports the current Coordinated Universal Time):

# telnet 128.138.140.44 13
Trying 128.138.140.44 ...
Connected to 128.138.140.44.
Escape character is '^]'.

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 ping command from the guest that the host is alive:

# ping 10.0.2.2
10.0.2.2 is alive

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

edit

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 /etc/hosts. 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 ~/.rhosts. 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

# usr/openwin/bin/xterm -display 10.0.2.2:0

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 wlan0 is the network device that connects the host to the Internet (often eth0 for a LAN connection). The firewall on the host might need to be disabled to make it work.

Running OpenWindows

edit

With the TAP/TUN network setup, set the following environment variables on the guest:

# setenv DISPLAY 10.0.2.2:1.0
# setenv OPENWINHOME /usr/openwin
# setenv PATH $OPENWINHOME/bin:$PATH
# setenv LD_LIBRARY_PATH $OPENWINHOME/lib
# setenv MANPATH $OPENWINHOME/share/man:/usr/man
# setenv HELPPATH $OPENWINHOME/lib/help

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:

# olwm &

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