mips64emul documentation: Experimenting with mips64emul

Back to the index

## Experimenting with mips64emul

- Hello world
- Experimental devices
- Experiments with other kernels and guest OSes

### Hello world:

You might want to use the emulator to develop programs on your own, not just run precompiled kernels such as NetBSD. To get started, I recommend that you do two things:

- Build and install a cross-compiler for MIPS.
- Compile this hello world program, and run it in the emulator.

The emulator can be run in a mode where it doesn't emulate a real machine. In this "bare" machine mode, only a few simple devices are emulated, such as putchar device, and a simple framebuffer (for outputing pixels in a simple manner).

    /*  Hello world for mips64emul  */

    /*  Note: The cast to a signed int causes the address to be sign-extended
        correctly to 0xffffffffb00000xx when compiled in 64-bit mode  */
    #define	PUTCHAR_ADDRESS		((signed int)0xb0000000)
    #define	HALT_ADDRESS		((signed int)0xb0000010)

    void printchar(char ch)
    {
    	*((volatile unsigned char *) PUTCHAR_ADDRESS) = ch;
    }

    void halt(void)
    {
    	*((volatile unsigned char *) HALT_ADDRESS) = 0;
    }

    void printstr(char *s)
    {
    	while (*s)
    		printchar(*s++);
    }

    void f(void)
    {
    	printstr("Hello world\n");
    	halt();
    }

This hello world program is available here as well: hello_mips.c

I recommend that you build a GCC cross compiler for the mips64-unknown-elf target, and install it. Other compilers could work too, but GCC is good because of its portability. Then try to compile the hello world program:

    	$ mips64-unknown-elf-gcc -O2 hello_mips.c -mips4 -mabi=64 -c
    	$ mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f hello_mips.o -o hello_mips --oformat=elf64-bigmips
    	$ file hello_mips
    	hello_mips: ELF 64-bit MSB mips-4 executable, MIPS R3000_BE, version 1 (SYSV), statically linked, not stripped
    	$ ./mips64emul -q -E testmips hello_mips
    	Hello world

    	$ mips64-unknown-elf-gcc -O2 hello_mips.c -c
    	$ mips64-unknown-elf-ld -Ttext 0x80030000 -e f hello_mips.o -o hello_mips
    	$ file hello_mips
    	hello_mips: ELF 32-bit MSB mips-3 executable, MIPS R3000_BE, version 1 (SYSV), statically linked, not stripped
    	$ ./mips64emul -q -E testmips hello_mips
    	Hello world

As you can see above, a GCC configured for mips64-unknown-elf can produce both 64-bit and 32-bit binaries. If you don't want to run the entire Hello World program, but want to single-step through the execution to learn more about how MIPS programs run, then add -V to the command line:

    	$ ./mips64emul -V -E testmips hello_mips
    	..
    	mips64emul> r
    	cpu0:    pc = a800000000030078
    	cpu0:    hi = 0000000000000000    lo = 0000000000000000
    	cpu0:    zr = 0000000000000000    at = 0000000000000000
    	cpu0:    v0 = 0000000000000000    v1 = 0000000000000000
    	..
    	cpu0:    gp = a8000000000780c0    sp = ffffffffa0007f00
    	cpu0:    fp = 0000000000000000    ra = 0000000000000000
    	mips64emul> s 15
    	<f>
    	a800000000030078: 67bdfff0      daddiu  sp,sp,-16
    	a80000000003007c: 3c04a800      lui     a0,0xa800
    	a800000000030080: 3c010003      lui     at,0x3
    	a800000000030084: 64840000      daddiu  a0,a0,0
    	a800000000030088: 642100b8      daddiu  at,at,184
    	a80000000003008c: 0004203c      dsll32  a0,a0,0
    	a800000000030090: 0081202d      daddu   a0,a0,at
    	a800000000030094: ffbf0000      sd      ra,0(sp)           [0xffffffffa0007ef0, data=0x0000000000000000]
    	a800000000030098: 0c00c00a      jal     0xa800000000030028 <printstr>
    	a80000000003009c: 00000000 (d)  nop
    	  <printstr("Hello world\n",0,0,0,..)>
    	<printstr>
    	a800000000030028: 67bdfff0      daddiu  sp,sp,-16
    	a80000000003002c: ffb00000      sd      s0,0(sp)           [0xffffffffa0007ee0, data=0x0000000000000000]
    	a800000000030030: ffbf0008      sd      ra,8(sp)           [0xffffffffa0007ee8, data=0xa8000000000300a0]
    	a800000000030034: 90820000      lbu     v0,0(a0)           [0xa8000000000300b8 = $LC0, data=0x48]
    	a800000000030038: 00021600      sll     v0,v0,24
    	mips64emul> print v0
    	v0 = 0x0000000048000000
    	mips64emul> _

The syntax of the single-step debugger shouldn't be too hard to grasp. Type 's' to single-step one instruction. Just pressing enter after that will repeat the 's' command. Type 'quit' to quit.

Hopefully this is enough to get you inspired. :-)

#### Hello World for mips64emul's PPC mode

mips64emul also has an experimental PowerPC emulation mode (which is only enabled if --enable-ppc is supplied as a configure option). hello_ppc.c is similar to hello_mips.c, but should be compiled and run as follows:

    	$ ppc-unknown-elf-gcc -O2 hello_ppc.c -c
    	$ ppc-unknown-elf-ld -e f hello_ppc.o -o hello_ppc
    	$ file hello_ppc
    	hello_ppc: ELF 32-bit MSB executable, PowerPC or cisco 4500,
    	  version 1 (SYSV), statically linked, not stripped
    	$ ./mips64emul -q -E testppc hello_ppc
    	Hello world

[ 2005-02-18: I haven't yet been able to build a GCC for ppc64 (only the binutils toolchain), because the gcc sources seem to include Linux header files that aren't present on my FreeBSD system. 32-bit PPC works ok, though. ]

### Experimental devices:

The "bare" MIPS machine has the following experimental devices:

cons: This is a simple console device, for writing characters to the controlling terminal. Source code: devices/dev_cons.c Default physical address: 0x10000000 |  |
Offset: | Effect:
0x0000 | Read: getchar() (non-blocking) Write: putchar(ch)
0x0010 | Read or write: halt() (Useful for exiting the emulator.)
mp: This device controls the behaviour of CPUs in an emulated multi-processor system. Source code: devices/dev_mp.c Default physical address: 0x11000000 |  |
Offset: | Effect:
0x0000 | Read: whoami(). Returns the id of the CPU doing the read.
0x0010 | Read: ncpus(). Returns the number of CPUs in the system.
0x0020 | Write: startupcpu(i). Starts CPU i. It begins execution at the address set by a write to startupaddr (see below).
0x0030 | Write: startupaddr(addr). Sets the starting address for CPUs.
0x0040 | Write: pause_addr(addr). Sets the pause address. (TODO: This is not used anymore?)
0x0050 | Write: pause_cpu(i). Stops all CPUs except CPU i.
0x0060 | Write: unpause_cpu(i). Unpauses all CPUs except CPU i.
0x0070 | Write: startupstack(addr). Sets the startup stack address. (CPUs started with startupcpu() above will have their stack pointer set to this value.)
0x0080 | Read: hardware_random(). This produces a "random" number.
0x0090 | Read: memory(). Returns the number of bytes of RAM in the system.
fb: A simple linear framebuffer, for graphics output. 640 x 480 pixels, 3 bytes per pixel (red, green, blue, 8 bits each). Source code: devices/dev_fb.c Default physical address: 0x12000000 |  |
Offset: | Effect:
... | Read: read pixel values. Write: write pixel values.

While these devices may resemble real-world hardware, they are intentionally made simpler to use. (An exception is the framebuffer; some machines actually have simple linear framebuffers like this.)

If the physical address is 0x10000000, then for MIPS that means that it can be accessed at virtual address 0xffffffffb0000000. (Actually it can be accessed at 0xffffffff90000000 too, but devices should usually be accessed in a non-cached manner.)

(When using the bare PPC test machine, "testppc", the addresses are 0x10000000, 0x11000000 etc., so no need to add any virtual displacement.)

The mp device is agnostic when it comes to word-length. For example, when reading offset 0x0000 of the mp device, you may use any kind of read (an 8-bit read will work just as well as a 64-bit read, although the value will be truncated to 8 bits in the first case).

The cons device should be accessed using 8-bit reads and writes. Doing a getchar() (ie reading from offset 0x0000) returns 0x00 if no character was available.

On MIPS, the cons device is hardwired to interrupt 2 (the lowest hardware interrupt). Whenever a character is available, the interrupt is asserted. When there are no more available characters, the interrupt is deasserted. (Remember that the interrupt has to be enabled in the status register of the system coprocessor.)

### Experiments with other kernels and guest OSes:

Operating system kernels and other test programs can be downloaded from various places. Here are links to some of the kernels that I usually experiment with.

NOTE: This is not a list of kernels that work in the emulator. It is a list of kernels that I experiment with.

For more information about which of these that actually work, read the section in the Introduction chapter that lists guest operating systems. If a system is not listed there, it probably doesn't work in mips64emul.

- DECstation:
  - NetBSD/pmax:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/pmax/binary/kernel/netbsd-INSTALL.gz
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/pmax/binary/kernel/netbsd-INSTALL.symbols.gz
    gunzip the files, and run the emulator with -E dec -e 3max -q -N -XY2 for a graphical framebuffer console. Remove -XY2 and -N to use serial (stdin/stdout) console. Read this section about how to install NetBSD/pmax onto a harddisk image.

  - OpenBSD/pmax:
    ftp://ftp.se.openbsd.org/pub/OpenBSD/2.8/pmax/bsd
    This is an old OpenBSD kernel in a.out format. Try -E dec -e 3max.
    Read this section about how to install OpenBSD/pmax onto a harddisk image. It's a bit more complicated than installing NetBSD/pmax, but might work.

  - Linux for DECstation:
    Here is a Debian package containing a Linux 2.4.26 kernel for DECstation which supports framebuffer!
    http://ftp.debian.org/debian/pool/main/k/kernel-patch-2.4.26-mips/
    kernel-image-2.4.26-r3k-kn02_2.4.26-0.040505.1_mipsel.deb
    Run the following commands to extract the kernel:

        	ar x kernel-image-2.4.26-r3k-kn02_2.4.26-0.040505.1_mipsel.deb data.tar.gz
        	tar xfzv data.tar.gz ./boot/vmlinux-2.4.26-r3k-kn02
        	mv boot/vmlinux-* .; rmdir boot

    To try with the framebuffer: -E dec -e 3max -X vmlinux-2.4.26-r3k-kn02
    To try with serial console: -E dec -e 3max -o 'console=ttyS3' vmlinux-2.4.26-r3k-kn02
    Read this section about how to run a Debian Linux install kernel.
    Here are some older kernels (these don't support framebuffer, I think): http://www.xs4all.nl/~vhouten/mipsel/kernels.html
    Note: Make sure you add -CR4400 to the command line for R4000 kernels, as Linux doesn't autodetect CPU type at runtime.

  - Sprite:
    The Unix Heritage Society (TUHS, www.tuhs.org) has a copy of a harddisk image for a DECstation 5000/200: ftp://ftp.es.embnet.org/misc/TUHS/sprite/ds5000.bt (MD5 (ds5000.bt) = ec84eeeb20fe77b758370d5e312e4a5e)
    Read this section for more information about running this harddisk image in the emulator.

  - Mach:
    Important! Run ./configure --caches; make
    Download http://lost-contact.mit.edu/afs/athena/user/d/a/daveg/Info/Links/Mach/src/release/pmax.tar.Z
    tar xfvz pmax.tar.Z pmax_mach/special/mach.boot.MK83.STD+ANY
    ./mips64emul -E dec -e 3max -X pmax_mach/special/mach.boot.MK83.STD+ANY

- SGI:
  - NetBSD/sgimips:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/sgimips/binary/kernel/netbsd-INSTALL32_IP3x.gz
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/sgimips/binary/kernel/netbsd-INSTALL32_IP3x.symbols.gz
    gunzip, and try running with -E sgi -e ip32.
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/sgimips/binary/kernel/netbsd-INSTALL32_IP2x.gz
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/sgimips/binary/kernel/netbsd-INSTALL32_IP2x.symbols.gz
    gunzip, and try running with -E sgi -e ip22 (or -e ip24 or -e ip20).

  - Linux/SGI:
    Some kernels are available here: http://www.linux-mips.org/~glaurung/
    Try running with -E sgi -e ip32 -X for a graphical framebuffer, or -E sgi -e ip32 -o 'console=ttyS0' for serial console.
    Adding -b (bintrans) might work sometimes.
    (You need to add -CR5000 if you're trying to run a kernel compiled for R5000, because Linux doesn't autodetect CPU at runtime.)
    Also: http://www.tal.org/~milang/o2/patches/vmlinux.ip32-2.6.10rc3-misc
    Try -E sgi -e ip32 -b -X -CR5000 vmlinux.ip32-2.6.10rc3-misc.
    And also some IP27 kernels: http://www.total-knowledge.com/progs/mips/kernels/vmlinux.ip27-20040428 and http://www.total-knowledge.com/progs/mips/kernels/vmlinux.ip27-20040528.bz2 (but unfortunately these lack symbols).
    Try the IP27 kernels with -E sgi -e ip27 -t.

  - OpenBSD/sgi:
    Snapshots can be found at ftp://ftp.OpenBSD.org/pub/OpenBSD/snapshots/sgi/.
    Try ./mips64emul -b -E sgi -e ip32 bsd.rd

  - FreeBSD/MIPS: I don't think public binary snapshots are available yet.

  - arcdiag:
    The NetBSD people have also made available an "arcdiag" for SGI-IP22:
    ftp://ftp.netbsd.org/pub/NetBSD/arch/sgimips/arcdiag.ip22
    Try running ./mips64emul -E sgi -e ip22 arcdiag.ip22.

- ARC:
  - NetBSD/arc:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/arc/binary/kernel/netbsd-RAMDISK.gz
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/arc/binary/kernel/netbsd-RAMDISK.symbols.gz
    gunzip, and try with -E arc -e rd94.
    (You may also try other ARC models.)
    Read this section about how to install NetBSD/arc onto a harddisk image.

  - OpenBSD/arc:
    ftp://ftp.se.openbsd.org/pub/OpenBSD/2.3/arc/bsd.rd.elf
    Try running with -X -E arc -e pica or -X -E arc -e tyne.
    Read this section about how to install OpenBSD/arc onto a harddisk image.

  - Linux:
    ftp://ftp.linux-mips.org/pub/linux/mips/mipsel-linux/boot/vmlinux-m700-2.1.131.gz
    gunzip, and run with -v -J -X -N -E arc -e m700 (Olivetti M700)

  - Pandora:
    ftp://ftp.linux-mips.org/pub/linux/mips/ancient/milo/milo-0.27.1.tar.gz
    A generic test/diagnostics program for ARC-based machines.
    Run with -E arc -e r94 milo-0.27.1/pandora

  - arcdiag:
    Precompiled binary:ftp://ftp.netbsd.org/pub/NetBSD/arch/arc/arcdiag
    (alternative: http://www.sensi.org/~alec/mips/arcdiag)
    A generic test/diagnostics program for ARC-based machines.
    Run with -E arc -e pica arcdiag (or some other ARC mode).
    Example arcdiag output (from real machines):
    http://mail-index.netbsd.org/port-arc/2000/10/18/0001.html (Olivetti M700-10)
    http://www.sensi.org/~alec/mips/arcdiag.txt (PICA-61)
    http://mail-index.netbsd.org/port-arc/2000/10/14/0000.html (Deskstation Tyne)
    http://mail-index.netbsd.org/port-arc/2004/02/01/0001.html (NEC RISCserver 4200)
    http://mirror.aarnet.edu.au/pub/NetBSD/misc/chs/arcdiag.out (NEC-R96)

- Playstation 2:
  - NetBSD/playstation2:
    NetBSD/playstation2 snapshot kernels are available here: (RAMDISK and GENERIC)
    ftp://ftp.NetBSD.org/pub/NetBSD/arch/playstation2/snapshot/20020327/installation/netbsd.gz
    ftp://ftp.NetBSD.org/pub/NetBSD/arch/playstation2/snapshot/20020327/binary/kernel/netbsd-GENERIC.gz
    Try running with -X -E playstation2 (-X is required, for the framebuffer).

  - Linux:
    A Linux kernel (2.2.21-pre1-xr7) is available from http://playstation2-linux.com/projects/xrhino-kernel/
    Try running with -X -E playstation2 (-X is required, for the framebuffer).

The following work even less than the ones listed above:

- Cobalt:
  - NetBSD/cobalt:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-1.6.2/cobalt/binary/kernel/netbsd-GENERIC.gz
    gunzip, and run with -E cobalt

  - Linux:
    http://people.debian.org/~pm/mips-cobalt/nfsroot/vmlinux_raq-2800.gz
    gunzip, and run with -E cobalt

- Sony NeWS:
  - NetBSD/newsmips:
    A NetBSD/newsmips kernel and corresponding symbols are available here:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/newsmips/binary/kernel/netbsd-INSTALL.gz
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/newsmips/binary/kernel/netbsd-INSTALL.symbols.gz
    Try running with -E sonynews.
    There's also a boot floppy available, but the emulator currently doesn't support booting from it:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-1.6/newsmips/installation/floppy/boot.fs

- HPCmips:
  - NetBSD/hpcmips:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/hpcmips/binary/kernel/netbsd-GENERIC.gz
    Try ./mips64emul -X -b -E hpc -e e105 netbsd-GENERIC

  - Linux for BE300: http://www.linux4.be/2004/linux4be20040908.zip
    Try ./mips64emul -X -b -E hpc -e be300 vmlinux

- MeshCube:
  - Linux:
    A Linux kernel is available from http://www.meshcube.org/feed/stable/kernel-image-mtx_2.4.24-3_mipsel.ipk
    (This is a Debian package, you can use ar and tar to extract kernel.img from it.)
    Try running with -E meshcube 0x80800000:kernel.img.

- NetGear WG602:
  - Linux:
    A Linux kernel is available from ftp://downloads.netgear.com/files/wg602_v1715.zip
    (Unzip wg602_v1715.zip to get WG602_V1715.img.)
    Try running with -E netgear 0xbfc80000:0x40:WG602_V1715.img.
    (It takes some time to decompress the kernel, so be patient.)

- Linksys WRT54G:
  - Linux:
    OpenWRT is a Linux distribution for the WRT54G.
    BatBox is another distribution.
    Download http://pjf.dotgeek.org/downloads/openwrt/openwrt-g-code.bin (or a similar .bin file).
    From offset 60 and forward in the bin file, there is a gzip file.
    $ dd if=openwrt-g-code.bin of=piggy.gz bs=60 iseek=1 oseek=0
    $ gunzip piggy.gz
    $ ./mips64emul -E linksys -t 0x80001000:piggy
    There's also a .bin file available from linksys: ftp://ftp.linksys.com/pub/network/WRT54G_1.30.7_US_code.bin

The following don't work at all, actually, because the PPC and SPARC modes are just skeletons so far. (To enable PPC and/or SPARC support, add --enable-ppc and --enable-sparc to the configure command line, respectively.)

- Walnut (evbppc):
  - NetBSD/evbppc:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/evbppc/binary/kernel/netbsd-INSTALL_WALNUT.gz
    gunzip, and try the following:
    $ ./mips64emul -E walnut -v -t netbsd-INSTALL_WALNUT

- Artesyn's PM/PPC board (pmppc):
  - NetBSD/pmppc:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/pmppc/binary/kernel/netbsd-INSTALL.gz
    gunzip, and try the following:
    $ ./mips64emul -E pmppc -v -t netbsd-INSTALL

- Motorola Sandpoint (sandpoint):
  - NetBSD/sandpoint:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/sandpoint/binary/kernel/netbsd-INSTALL.gz
    gunzip, and try the following:
    $ ./mips64emul -E sandpoint -v -t netbsd-INSTALL

- SPARC64:
  - NetBSD/sparc64:
    ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.0/sparc64/binary/kernel/netbsd-INSTALL.gz
    gunzip, and try the following:
    $ ./mips64emul -E ultra1 -v -i netbsd-INSTALL

  - OpenBSD/sparc64:
    ftp://ftp.openbsd.org/pub/OpenBSD/3.6/sparc64/bsd.rd
    rename to bsd.rd.gz, gunzip, and try the following:
    $ ./mips64emul -E ultra1 -v -i bsd.rd