A bare metal Hello world in assembly on RISC-V with QEMU

I wanted to create a minimal, Hello world style, program, for RISC-V.

I wanted the program to run on Ubuntu, as well as on MacOS, and I wanted to use QEMU as RISC-V simulator.

QEMU – Ubuntu

For Ubuntu, I installed QEMU by following instructions on the QEMU site, which led to commands, as

git clone https://git.qemu.org/git/qemu.git
cd qemu
git submodule init
git submodule update --recursive
mkdir objdir
cd objdir
../configure --target-list=riscv32-softmmu --prefix=/home/$USER/prog/qemu_riscv

The configure step gave an error, as

ola@ola-VirtualBox:~/mw/qemu/objdir$ ../configure --target-list=riscv32-softmmu --prefix=/home/$USER/prog/qemu_riscv

ERROR: pkg-config binary 'pkg-config' not found

ola@ola-VirtualBox:~/mw/qemu/objdir$ 

I realized that this was due to lack of programs on my newly installed Ubuntu 18.04.3 on Virtualbox.

I installed pkg-config, by doing

sudo apt install pkg-config

after which I got more errors, which led to

sudo apt install libglib2.0-dev 
sudo apt install libpixman-1-dev

which in turn led to a successful configure command.

I could then build, using

make

and install, using

make install

The installation was then tested, as

ola@ola-VirtualBox:~/mw/qemu/objdir$ /home/$USER/prog/qemu_riscv/bin/qemu-system-riscv32 --help | head
QEMU emulator version 4.1.93 (v4.2.0-rc3-dirty)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
usage: qemu-system-riscv32 [options] [disk_image]

'disk_image' is a raw hard disk image for IDE hard disk 0

Standard options:
-h or -help     display this help and exit
-version        display version information and exit
-machine [type=]name[,prop[=value][,...]]
ola@ola-VirtualBox:~/mw/qemu/objdir$ 

QEMU – macOS Catalina

For macOS, I had already done an installation of QEMU on macOS Mojave.

I followed the steps from this experience, but now on macOS Catalina, and changing the configure command from

../configure --target-list=riscv32-softmmu --prefix=/Users/$USER/qemu_riscv

to

../configure --target-list=riscv32-softmmu --prefix=/Users/$USER/prog/qemu_riscv

I also noted that a parallel make

make -j

was successful.

I checked by my installation, by doing.

objdir oladahl$ /Users/$USER/prog/qemu_riscv/bin/qemu-system-riscv32 --help | head
QEMU emulator version 4.1.94 (v4.2.0-rc4-2-g02f9c885ed)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
usage: qemu-system-riscv32 [options] [disk_image]

'disk_image' is a raw hard disk image for IDE hard disk 0

Standard options:
-h or -help     display this help and exit
-version        display version information and exit
-machine [type=]name[,prop[=value][,...]]
objdir oladahl$ 

Toolchain

As the next step, I wanted to install a toolchain.

I decided to use this RISC-V toolchain.

Ubuntu

Following the instructions, I did, on Ubuntu

git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain

followed by

git submodule update --init --recursive

which took some time.

I installed programs, as recommended, by doing

sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev

A configure was then done, for a 32-bit instruction set, using information from the Github site, as

mkdir objdir
cd objdir/
../configure --prefix=/home/$USER/prog/gcc_riscv --with-arch=rv32gc --with-abi=ilp32d

I built the toolchain, at first trying with

make -j

which led to an out-of-memory situation, with prints such as

cc1plus: out of memory allocating 65536 bytes after a total of 2252800 bytes
virtual memory exhausted: Cannot allocate memory
virtual memory exhausted: Cannot allocate memory

cc1plus: out of memory allocating 240809 bytes after a total of 1343488 bytes
virtual memory exhausted: Cannot allocate memory
virtual memory exhausted: Cannot allocate memory
virtual memory exhausted: Cannot allocate memory

I changed to a sequential make

make

which was successful.

I checked that I could start gcc, using

ola@ola-VirtualBox:~/mw/riscv-gnu-toolchain/objdir$ /home/$USER/prog/gcc_riscv/bin/riscv32-unknown-elf-gcc -v
Using built-in specs.
COLLECT_GCC=/home/ola/prog/gcc_riscv/bin/riscv32-unknown-elf-gcc
COLLECT_LTO_WRAPPER=/home/ola/prog/gcc_riscv/libexec/gcc/riscv32-unknown-elf/9.2.0/lto-wrapper
Target: riscv32-unknown-elf
Configured with: /home/ola/mw/riscv-gnu-toolchain/objdir/../riscv-gcc/configure --target=riscv32-unknown-elf --prefix=/home/ola/prog/gcc_riscv --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-sysroot=/home/ola/prog/gcc_riscv/riscv32-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src=../../riscv-gcc --disable-multilib --with-abi=ilp32d --with-arch=rv32gc --with-tune=rocket 'CFLAGS_FOR_TARGET=-Os   -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-Os   -mcmodel=medlow'
Thread model: single
gcc version 9.2.0 (GCC) 
ola@ola-VirtualBox:~/mw/riscv-gnu-toolchain/objdir$ 
macOS Catalina

On macOS Catalina, I installed programs as

brew install gawk gnu-sed gmp mpfr libmpc isl zlib expat

Following the instructions, I cloned the repo, as

git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain

followed by

git submodule update --init --recursive

which took some time.

A configure was done, for a 32-bit instruction set, using information from the Github site, as

mkdir objdir
cd objdir/
../configure --prefix=/Users/$USER/prog/gcc_riscv --with-arch=rv32gc --with-abi=ilp32d

I built the toolchain, using parallel make, as

make -j

which was successful.

I checked that I could start gcc, using

$ /Users/$USER/prog/gcc_riscv/bin/riscv32-unknown-elf-gcc -v
Using built-in specs.
COLLECT_GCC=/Users/oladahl/prog/gcc_riscv/bin/riscv32-unknown-elf-gcc
COLLECT_LTO_WRAPPER=/Users/oladahl/prog/gcc_riscv/libexec/gcc/riscv32-unknown-elf/9.2.0/lto-wrapper
Target: riscv32-unknown-elf
Configured with: /Users/oladahl/mw/riscv-gnu-toolchain/objdir/../riscv-gcc/configure --target=riscv32-unknown-elf --prefix=/Users/oladahl/prog/gcc_riscv --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-sysroot=/Users/oladahl/prog/gcc_riscv/riscv32-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src=../../riscv-gcc --disable-multilib --with-abi=ilp32d --with-arch=rv32gc --with-tune=rocket 'CFLAGS_FOR_TARGET=-Os   -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-Os   -mcmodel=medlow'
Thread model: single
gcc version 9.2.0 (GCC) 
$ 

A program

I decided to write an assembly program, and to use a simulated UART in QEMU as the means for printing.

Looking at the 32-bit instruction set, in the The RISC-V Instruction Set Manual for the Unprivileged ISA, available as one of the RISC-V Specifications, and also using information from this page for the rv8 simulator, I came up with a program as

    .global _start

_start:

    lui t0, 0x10010

    andi t1, t1, 0
    addi t1, t1, 72
    sw t1, 0(t0)

    andi t1, t1, 0
    addi t1, t1, 101
    sw t1, 0(t0)

    andi t1, t1, 0
    addi t1, t1, 108
    sw t1, 0(t0)

    andi t1, t1, 0
    addi t1, t1, 108
    sw t1, 0(t0)

    andi t1, t1, 0
    addi t1, t1, 111
    sw t1, 0(t0)

    andi t1, t1, 0
    addi t1, t1, 10
    sw t1, 0(t0)

finish:
    beq t1, t1, finish

Here, the UART address is indicated by the value 0x10010, which is used in the first instruction as

    lui t0, 0x10010

I found the UART address by first practising building of a hello world program from riscv-probe, where I also learned how to create a linker script.

After this, I looked in the QEMU source code, where I found the file hw/riscv/sifive_u.c, in which the UART address is found in a struct, defined (with values for entries not related to UART0 omitted) as

static const struct MemmapEntry {
     hwaddr base;
     hwaddr size;
} sifive_u_memmap[] = {
...
    [SIFIVE_U_UART0] =    { 0x10010000,     0x1000 },
...
};

Considering that the lui instruction loads its immediate value into the upper 20 bits of the register used in the instruction, we see that the value 0x10010000 can be loaded in to a register, in this case t0, by doing

    lui t0, 0x10010

Using a makefile, as

hello: hello.o link.lds
	riscv32-unknown-elf-ld -T link.lds -o hello hello.o

hello.o: hello.s
	riscv32-unknown-elf-as -o hello.o hello.s

clean:
	rm hello hello.o

where the file link.lds has the same content as the riscv-probe linker script, I could build and run the program, on Ubuntu, as

export PATH=/home/$USER/prog/gcc_riscv/bin/:$PATH
make
/home/$USER/prog/qemu_riscv/bin/qemu-system-riscv32 -machine sifive_u -nographic -kernel hello

with printouts as

$ /home/$USER/prog/qemu_riscv/bin/qemu-system-riscv32 -machine sifive_u -nographic -kernel hello
qemu-system-riscv32: warning: No -bios option specified. Not loading a firmware.
qemu-system-riscv32: warning: This default will change in a future QEMU release. Please use the -bios option to avoid breakages when this happens.
qemu-system-riscv32: warning: See QEMU's deprecation documentation for details.
Hello
Hello
QEMU: Terminated
$ 

On macOS Catalina, I did

export PATH=/Users/$USER/prog/gcc_riscv/bin/:$PATH
make
/Users/$USER/prog/qemu_riscv/bin/qemu-system-riscv32 -machine sifive_u -nographic -kernel hello

with printouts as

$ /Users/$USER/prog/qemu_riscv/bin/qemu-system-riscv32 -machine sifive_u -nographic -kernel hello
qemu-system-riscv32: warning: No -bios option specified. Not loading a firmware.
qemu-system-riscv32: warning: This default will change in a future QEMU release. Please use the -bios option to avoid breakages when this happens.
qemu-system-riscv32: warning: See QEMU's deprecation documentation for details.
Hello
Hello
QEMU: Terminated
$ 

In both cases (Ubuntu and macOS Catalina), I terminated QEMU using Ctrl-A x. Also, I don’t know why the Hello string was printed twice.

Installing RISC-V QEMU on macOS Mojave

In my ongoing book project, I have decided to change architecture, from OpenRISC to RISC-V.

My main motivation (yes, you might want to call it procrastination), is to be more aligned with current topics, and to have access to a broader range of reference material.

As a first step, I wanted to run on my macOS Mojave computer (later on, I should also use Ubuntu).

I downloaded QEMU using Git, as

git clone https://git.qemu.org/git/qemu.git
cd qemu
git submodule init
git submodule update --recursive

Configure was done, as

mkdir objdir
cd objdir
../configure --target-list=riscv32-softmmu --prefix=/Users/$USER/qemu_riscv

This resulted in an error, as

ERROR: pkg-config binary 'pkg-config' not found 

I guessed (based on earlier Mac experiences) that I could have use of brew. From the Homebrew page, I learned how to install brew, as

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

I did this, and then tried to install pkg-config, as

brew install pkg-config

Trying the configure command again, as

../configure --target-list=riscv32-softmmu --prefix=/Users/$USER/qemu_riscv

resulted in the error message

ERROR: glib-2.40 gthread-2.0 is required to compile QEMU

I guessed that brew could help me also here, so I tried

brew install glib

The configure command now gave

ERROR: pixman >= 0.21.8 not present.
       Please install the pixman devel package.

Continuing with brew, as

brew install pixman

resulted in a successful configure command.

I tried building, using

make -j

which finished with errors, as

clang: error: unable to execute command: posix_spawn failed: Resource temporarily unavailable
make: *** [util/drm.o] Error 1
make: *** Waiting for unfinished jobs....
  CC      util/guest-random.o
clang: error: unable to execute command: posix_spawn failed: Resource temporarily unavailable
make: *** [util/qsp.o] Error 1

Using a sequential make, as

make

resulted in a successful build.

I could then install QEMU, by doing

make install

As a sanity check of the installation, I did

Olas-MacBook:objdir ola$ /Users/ola/qemu_riscv/bin/qemu-system-riscv32 --help | head
QEMU emulator version 4.0.90 (v4.1.0-rc0)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
usage: qemu-system-riscv32 [options] [disk_image]

'disk_image' is a raw hard disk image for IDE hard disk 0

Standard options:
-h or -help     display this help and exit
-version        display version information and exit
-machine [type=]name[,prop[=value][,...]]

Installing QEMU on Mac OS X El Capitan

QEMU is an open source computer emulator. Here I describe how I installed QEMU on Mac OS X El Capitan.

My goal was to learn more about building QEMU, and to boot Linux on QEMU, and to check if there were differences in the installation compared to when doing it on Mac OS X Yosemite.

I downloaded and unpacked QEMU 2.5.0 (this was the latest stable release at the date I did the download), by doing

wget http://wiki.qemu-project.org/download/qemu-2.5.0.tar.bz2
tar xvjf qemu-2.5.0.tar.bz2
cd qemu-2.5.0

Then, based on my earlier experiences, I used the configure command

./configure --enable-cocoa --target-list=i386-softmmu,arm-softmmu,x86_64-softmmu --disable-vnc

and it succeeded! Here I took advantage of my previous installation of rudix, and the use of rudix for installing glib, which I did using the command

sudo rudix install glib

This installation of glib prevented an error printout

ERROR: glib-2.22 gthread-2.0 is required to compile QEMU

The next step is building, which I did by simply typing make, but that did not succeed.

There were warnings, but also errors. I searched using google, using the error printout as search terms. This led me to this page with advice, which told me to add make targets, resulting in lines like

region_test_OBJECTS = region-test.$(OBJEXT) utils.$(OBJEXT)

and

scaling_helpers_test_OBJECTS = scaling-helpers-test.$(OBJEXT) utils.$(OBJEXT)

in the file

./pixman/test/Makefile

where the targets utils.$(OBJEXT) were added by me.

The errors went away, resulting in a successful build. Again, I was helped by my earlier experiences, where I learned how to prevent link errors by installing gettext using rudix, as

sudo rudix install gettext

I could then do make install to install my new QEMU.

Now I wanted to boot Linux! I looked at the QEMU Testing page, and decided to download and unpack a Linux image for ARM by doing

wget http://wiki.qemu.org/download/arm-test-0.2.tar.gz
tar zxvf arm-test-0.2.tar.gz

A Linux boot could then be done, by starting QEMU with the downloaded Linux image as argument, as

cd arm-test
qemu-system-arm -machine integratorcp -kernel zImage.integrator -initrd arm_root.img -nographic -append "console=ttyAMA0"

When done, QEMU can be shut down by doing Ctrl-A x.

Installing QEMU on Mac OS X Yosemite

QEMU is an open source computer emulator. Here I describe how I installed QEMU on Mac OS X Yosemite.

My goal was to learn more about building QEMU, and to boot Linux on QEMU.

I downloaded and unpacked QEMU 2.3.0 (this was the latest stable release at the date I did the download), by doing

wget http://wiki.qemu-project.org/download/qemu-2.3.0.tar.bz2
tar xvjf qemu-2.3.0.tar.bz2
cd qemu-2.3.0

Then, based on my earlier experiences, I used the configure command

./configure --enable-cocoa --target-list=i386-softmmu,arm-softmmu,x86_64-softmmu --disable-vnc

This command generated an error, telling me that

ERROR: glib-2.22 gthread-2.0 is required to compile QEMU

I tried my previous approach, where I installed the required glib version using sudo port install. I used the command

sudo port install glib-2.2

which resulted in

Warning: port definitions are more than two weeks old, consider using selfupdate
Error: Port glib-2.2 not found

I followed this advice, and did

sudo port selfupdate

but that led me into new troubles, with error messages telling me that my Xcode Command Line Tools were most likely not installed. I tried to install these tools but without luck

I was about to give up when I stumbled upon rudix. This turned out to be an attractive solution! I read at the rudix page that I should do

sudo python rudix.py install rudix

Then, from the rudix glib page, I learned that I should do

sudo rudix install glib

I did as told, and now the configure command

./configure --enable-cocoa --target-list=i386-softmmu,arm-softmmu,x86_64-softmmu --disable-vnc

succeeded. I followed it up by building, using make, but that did not succeed.

I looked at the build errors, which led me to this page with advice, which told me to add make targets, resulting in lines like

scaling_helpers_test_OBJECTS = scaling-helpers-test.$(OBJEXT) utils.$(OBJEXT)

in the file

./pixman/test/Makefile

where the last target had to be added by me. A similar change, in the same Makefile, was required, and resulted in the modified line

region_test_OBJECTS = region-test.$(OBJEXT) utils.$(OBJEXT)

The errors went away, but a new link error remained. The error printout was

LINK qemu-ga
ld: library not found for -lintl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [qemu-ga] Error 1

I found this page with advice on how to solve it using brew (which was not applicable to my problem).

However, since I now had my rudix package, I chose instead to do

sudo rudix install gettext

This resulted in a successful build, and I could then also do make install to install my new QEMU.

Now I wanted to boot Linux! I looked at the QEMU Testing page, and decided to download and unpack a Linux image by doing

wget http://wiki.qemu.org/download/linux-0.2.img.bz2
bzip2 -d linux-0.2.img.bz2

A Linux boot could then be done, by starting QEMU with the downloaded Linux image as argument, as

qemu-system-i386 -hda linux-0.2.img

A bare-metal x86-cross-compiler on Mountain Lion

I wanted to create a bare-metal program for an Intel-x86 processor. The program is used in a chapter called The Bare Metal in the book Into Embedded.

On an Ubuntu Linux host I could use gcc, together with a linker script, to accomplish the task. I could then run the program using Bochs.

On a Mac Mountain Lion host, the above method did not work out of the box, due to ld not being the GNU linker.

In addition, gcc was not GNU gcc either.

I searched the net and found this interesting page by M3 Operating System Development where it was described how to build an i386 cross-compiler. I thought that this could be a way to create a compiler for bare-metal programs with no OS-dependencies – which was desirable since the bare-metal program was to be evolved into an OS by itself.

Problem arose, however, since the pre-installed gcc on my Mac could not build the i386-cross-gcc.

I searched again, and found this eminent page by Solarian Programmer where it is described how to build a GNU gcc compiler.

I downloaded the gcc 4.7.2 sources from the GNU ftp repository.

Then, following the instructions, however leaving out the choice of building a compiler for Fortran and also changing the gcc version from 4.7.1 to gcc 4.7.2, I was able to build a native GNU gcc compiler.

The newly built native gcc could then be set to the default gcc by issuing the command

export PATH=/usr/gcc-4.7.2/bin:$PATH

Then, returning to the instructions for building an i386-cross-gcc, I started with downloading

binutils-2.23.tar.gz

from the GNU binutils repository.

I created a destination directory for the cross compiler, by doing

sudo mkdir /usr/local/i386elfgcc/

The binutils could then be unpacked, configured, and built, using the commands

tar zxvf binutils-2.23.tar.gz
mkdir build-binutils
cd build-binutils/
../binutils-2.23/configure --target=i386-elf --prefix=/usr/local/i386elfgcc
make
sudo make install

I then built gcc, using inspiration also from this OS development wiki, by issuing the commands

tar xvjf gcc-4.7.2.tar.bz2
mkdir build-gcc
cd build-gcc
../gcc-4.7.2/configure --target=i386-elf --prefix=/usr/local/i386elfgcc --with-gnu-as --with-gnu-ld --disable-libssp --enable-languages=c --without-headers
make all-gcc
sudo make install-gcc

After having added /usr/local/i386elfgcc/bin to the PATH environment variable I was able to compile and link a bare metal program.

The program consists of three C-files, which I could compile using the commands

i386-elf-gcc -Wall -c screen_output.c
i386-elf-gcc -c -Wall -DBUILD_X86_FD_TARGET src/bare_metal.c -o obj/bare_metal_x86_fd_target.o
i386-elf-gcc -c -Wall -DBUILD_X86_FD_TARGET src/console.c -o obj/console_x86_fd_target.o

The program could then be linked, using a command where also startup code, written in assembly and assembled using NASM resulting in the object file start_code.o, as

i386-elf-ld -T arch/x86_fd_target/link.ld --oformat=elf32-i386 -melf_i386 arch/x86_fd_target/start_code.o arch/x86_fd_target/screen_output.o -o prog_x86_fd_target.elf obj/console_x86_fd_target.o obj/bare_metal_x86_fd_target.o

Finally, the file prog_x86_fd_target.elf needs to be converted from ELF format to raw binary format. This can be done using the command

i386-elf-objcopy -O binary prog_x86_fd_target.elf prog_x86_fd_target.bin

As a last step, a binary bootable image for a floppy-disc drive can be created, by concatenating a FAT12 boot sector, a defined number of empty FAT12-sectors, and the binary file created by the i386-elf-objcopy command.

The concatenation is done as

cat arch/x86_fd_target/boot.bin arch/x86_fd_target/b_32_512.bin prog_x86_fd_target.bin > arch/x86_fd_target/a.img

The program can now be run, using Bochs, by giving the command

bochs -f arch/x86_fd_target/bochsrc.txt -q

Installing Bochs

Bochs is an x86-emulator that can be installed on different platforms. Here I describe my experiences of installing Bochs on Linux and on MacOS Mountain Lion.

Ubuntu Linux

Installing Bochs on Ubuntu was simple. I did

sudo apt-get install bochs

Then I located the Bochs configuration file. It was found, and copied to the directory where I intended to run Bochs, as

cp /usr/local/share/doc/bochs/bochsrc-sample.txt bochsrc.txt

My goal was to simulate an x86-computer with a floppy-disc unit. Changes were therefore done, in the file bochsrc.txt. The changes can be seen from the diff-command

diff /usr/local/share/doc/bochs/bochsrc-sample.txt bochsrc.txt

as

387c387
< floppya: 1_44=/dev/fd0, status=inserted
---
> #floppya: 1_44=/dev/fd0, status=inserted
392c392
< #floppya: 1_44=a.img, status=inserted, write_protected=1
---
> floppya: 1_44=arch/x86_fd_target/a.img, status=inserted, write_protected=1
474c474
< ata0-master: type=disk, mode=flat, path="30M.sample"
---
> #ata0-master: type=disk, mode=flat, path="30M.sample"
494,495c494,495
< #boot: floppy
< boot: disk
---
> boot: floppy
> #boot: disk

Then I am ready to run Bochs, using the command

bochs -f arch/x86_fd_target/bochsrc.txt -q

resulting in a simulated PC screen, as

bochs hello

Linux

The Bochs project is found at http://bochs.sourceforge.net.

After reading information about the latest release, I navigated to the releases page. I then downloaded release 2.6 in source format, resulting in download of the file

bochs-2.6.tar.gz

I then unpacked the source and navigated to the newly created bochs source directory, as

tar zxvf bochs-2.6.tar.gz
cd bochs-2.6

Then the configure script shall be run. Since I was not root on the machine, I used a prefix to configure, indicating the directory where I wanted Bochs to be installed. The configure command used was

./configure --prefix=/nobackup/local/prog/bochs

Bochs was then built, using the command

make

and installed using the command

make install

Then I located the Bochs configuration file. It was found, and copied to the directory where I intended to run Bochs, as

cp /nobackup/local/prog/bochs/share/doc/bochs/bochsrc-sample.txt arch/x86_fd_target/bochsrc.txt

My goal was to simulate an x86-computer with a floppy-disc unit. Changes were therefore done, in the file bochsrc.txt. The changes can be seen from the diff-command

diff /nobackup/local/prog/bochs/share/doc/bochs/bochsrc-sample.txt arch/x86_fd_target/bochsrc.txt

as

190c190
< cpu: model=core2_penryn_t9600, count=1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
---
> cpu: count=1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
415c415
< floppya: 1_44=/dev/fd0, status=inserted
---
> #floppya: 1_44=/dev/fd0, status=inserted
420c420
< #floppya: 1_44=a.img, status=inserted, write_protected=1
---
> floppya: 1_44=arch/x86_fd_target/a.img, status=inserted, write_protected=1
502c502
< ata0-master: type=disk, mode=flat, path="30M.sample"
---
> #ata0-master: type=disk, mode=flat, path="30M.sample"
522,523c522,523
< #boot: floppy
< boot: disk
---
> boot: floppy
> #boot: disk
636c636
< debug: action=ignore, pci=report # report BX_DEBUG from module 'pci'
---
> debug: action=ignore, # pci=report # report BX_DEBUG from module 'pci'

I also added the following changes

export PATH=/nobackup/local/prog/bochs/bin:$PATH
export BXSHARE=/nobackup/local/prog/bochs/share/bochs

to my setup script, where I also set up other environment variables.

Then I am ready to run Bochs, using the command

bochs -f arch/x86_fd_target/bochsrc.txt -q

resulting in a simulated PC screen as shown above.

Mac Mountain Lion

I navigated to the releases page. I then downloaded release 2.6 in source format, resulting in download of the file

bochs-2.6.tar.gz

I then unpacked the source and navigated to the newly created bochs source directory, as

tar zxvf bochs-2.6.tar.gz
cd bochs-2.6

The configure command used was

./configure --with-x11

The –with-x11 indicates that X11 shall be used. For this purpose I had installed XQuartz, as described by Apple in this support note.

Bochs was then built, using the command

make

and installed using the command

sudo make install

I used the same configuration file as described above for Ubuntu, and I could then run Bochs using the command

bochs -f arch/x86_fd_target/bochsrc.txt -q

resulting in a simulated PC screen, as shown above.

Installing NASM

NASM is an assembler for x86-based computers. Here I describe my experiences from installing NASM on Linux and on Mac Mountain Lion.

Ubuntu Linux

NASM was installed using the command

sudo apt-get install nasm

Linux

Starting from the NASM site I navigated to the NASM download page.

I downloaded NASM version 2.10.05 in source format, by downloading the file

nasm-2.10.05.tar.bz2

I unpacked the file and navigated to the newly created directory, using the commands

tar xvjf nasm-2.10.05.tar.bz2
cd nasm-2.10.05

As a preparation for building NASM, a configure command shall be issued. Since I was not root for the machine, I used a prefix, indicating the place where I wanted NASM to be installed. The command used was

./configure --prefix=/nobackup/local/prog/nasm

Then I could build and install NASM, using the commands

make
make install

I also added the following changes

export PATH=/nobackup/local/prog/nasm/bin:$PATH

to my setup script, where I also set up other environment variables.

Mac Mountain Lion

Starting from the NASM site I navigated to the NASM download page. From there I continued to the Mac OS download page, from where I downloaded the file

nasm-2.10.05-macosx.zip

Unzipping this file resulted in a directory named nasm-2.10.05 being created.

I now noticed that I already had nasm on my computer, as could be seen from

Olas-MacBook-Air:nasm-2.10.05 oladahl$ nasm -v
NASM version 0.98.40 (Apple Computer, Inc. build 11) compiled on Aug 4 2012

That version was however older than the newly downloaded, as could be seen by doing

Olas-MacBook-Air:nasm-2.10.05 oladahl$ ./nasm -v
NASM version 2.10.05 compiled on Sep 9 2012

I decided to put the downloaded nasm in a directory called prog/nasm inside my home directory. I moved it there using

mkdir -p ~/prog/nasm
mv * ~/prog/nasm

I then added the following changes

export PATH=~/prog/nasm:$PATH

to my setup script, where I also set up other environment variables. After having rerun the setup script I could use the downloaded nasm, after first having verified that it was found using

Olas-MacBook-Air:i1_bare_metal oladahl$ nasm -v
NASM version 2.10.05 compiled on Sep 9 2012

Installing an ARM cross-compiler on Mac Mountain Lion

Here I will describe my installation of an ARM cross compiler, on a MacBook Air with Mac OS Mountain Lion.

After some searching on the net I decided to try the YAGARTO toolchain.

Navigating to the download place for Mac, I downloaded the file

yagarto-bu-2.22_gcc-4.7.1-c-c++_nl-1.20.0_gdb-7.4.1_eabi_intelmac_20120616.dmg

Using this file however led to an error, saying

selected processor does not support requested special purpose register -- `mrs r0,cpsr'

I reverted to an older version, found at YAGARTO’s Sourceforge page. This led to download of the file

yagarto-bu-2.21_gcc-4.6.2-c-c++_nl-1.19.0_gdb-7.3.1_eabi_intelmac_20111119.dmg

Double-clicking on this downloaded file, I was able to install the toolchain.

I then added the following changes

export ARM_GCC_LOCATION=/Users/oladahl/yagarto/yagarto-4.6.2/bin
export PATH=$ARM_GCC_LOCATION:$PATH

to my setup script, where I also set up other environment variables.

Now I can start programming for ARM!

As an example, I can compile, link, and run the example described in Chapter The Bare Metal in the book Into Embedded.

Installing QEMU

QEMU is an open source computer emulator. Here I describe how I installed QEMU on Linux and on Mac Mountain Lion.

My goal was to create a simulator for machines with ARM architecture and for machines with x86 architecture.

Updates to this post

  • July 15, 2013 – changed the section on Ubuntu Linux to cover QEMU 1.5.1 instead of QEMU 1.2.0.

Ubuntu Linux

Starting from the QEMU home page I navigated to the download page. From there I downloaded the file

qemu-1.5.1.tar.bz2

I unpacked the file, and navigated to the directory created during the unpacking, using the commands

tar xvjf qemu-1.5.1.tar.bz2
cd qemu-1.5.1

As a preparation, I needed to update my Ubuntu 13.04 installation. It turned out that the following installations were needed:

sudo apt-get install zlib1g-dev
sudo apt-get install libglib2.0
sudo apt-get install autoconf
sudo apt-get install libtool
sudo apt-get install libsdl-console
sudo apt-get install libsdl-console-dev

I could then configure QEMU, using the command

./configure --target-list=i386-softmmu,arm-softmmu,x86_64-softmmu --disable-vnc --enable-sdl

I could then build and install, using

make
sudo make install

I could then use QEMU, for simulation of an ARM computer, e.g. as

qemu-system-arm -M realview-pb-a8 -nographic -kernel prog_arm_rpb_a8.elf

and simulation of an x86 computer, e.g. as

qemu-system-x86_64 -kernel prog_x86_grub_target.elf

Problems encountered – I had some trouble before realizing which packages to add to Ubuntu in order to get QEMU to build. The first thing that happened was that the configure command failed, with

ERROR: zlib check failed
Make sure to have the zlib libs and headers installed.

which, after some searching, led me to install zlib as

sudo apt-get install zlib1g-dev

Then I got a message I recognized from my installation of QEMU on Mac, saying that

ERROR: glib-2.12 required to compile QEMU

which, again after some searching, led to the installation of glib as

sudo apt-get install libglib2.0

Configure was now happy but make was not. The make command gave an error, as

(cd /home/ola/Downloads/qemu-1.5.1/pixman; autoreconf -v --install)
/bin/sh: autoreconf: command not found
make: *** [/home/ola/Downloads/qemu-1.5.1/pixman/configure] Error 127

Trying the command autoreconf, as

ola@ola-Aspire-S3-391:~/Downloads/qemu-1.5.1$ autoreconf
The program 'autoreconf' can be found in the following packages:
* autoconf

led to the installation of autoconf, as

sudo apt-get install autoconf

An error telling me to install libtool then appeared, as

../../lib/autoconf/general.m4:2678: AC_LINK_IFELSE is expanded from...
configure.ac:552: the top level
configure.ac:75: error: possibly undefined macro: AC_PROG_LIBTOOL
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1
make: *** [/home/ola/Downloads/qemu-1.5.1/pixman/configure] Error 1
make: *** Deleting file `/home/ola/Downloads/qemu-1.5.1/pixman/configure'

which, by help from Erik Rull, led me to the installation of libtool, as

sudo apt-get install libtool

Now everything built, and I could also do an installation of QEMU, as

sudo make install

The ARM simulation worked fine, but there was no screen in the x86 simulation. I guessed that I needed also SDL for this purpose, and after the installation of sdl, as

sudo apt-get install libsdl-console
sudo apt-get install libsdl-console-dev

I could see a console, and the long-awaited “Hello, world”-message from my program.

Linux

I downloaded and unpacked QEMU in the same way as described above for Ubuntu Linux.

Then, since I was not root on the machine, I used the configure command

./configure --prefix=/nobackup/local/prog/qemu --target-list=i386-softmmu,arm-softmmu,x86_64-softmmu --disable-vnc

followed by commands for build and installation, as

make
make install

I also added the following changes

export PATH=/nobackup/local/prog/qemu/bin:$PATH

to my setup script, where I also set up other environment variables.

I could then use QEMU, for simulation of an ARM computer, e.g. as

qemu-system-arm -M realview-pb-a8 -nographic -kernel prog_arm_rpb_a8.bin

Mac Mountain Lion

I downloaded and unpacked QEMU 1.2.0 in the same way as described above for Ubuntu Linux.

Then, based on information from Ruben Schade, I used the configure command

./configure --enable-cocoa --target-list=i386-softmmu,arm-softmmu,x86_64-softmmu --disable-vnc

This command generated an error, telling me that “glib-2.12” was “required to compile QEMU”. I searched for this error, and after having read at this MacPorts-related page, I ended up doing

sudo port install glib-2.12
sudo port selfupdate
sudo port upgrade outdated

which, as a result, made it possible to redo the configure command as decribed above.

I then built QEMU, which succeeded but with several warnings, and installed it, using

make
sudo make install

I could now use QEMU, for simulation of an ARM computer, e.g. as

qemu-system-arm -M realview-pb-a8 -nographic -kernel prog_arm_rpb_a8.bin