x86 (i386) Emulator in C
Why:
- I wanted to trace how an OS runs on CPUs at archtecture / instruction level.
 
What:
- Runs vanilla xv6 (memfs) image from boot.
 - Each instruction is manually implemented and executed sequentially without binary translation or OoOE.
 - Representation of logic is prioritized over the performance. Codes have bunch of comments covering the instructions and the hardware mechanism as well.
 
Done:
- Instructions required for running xv6
 - Real mode
 - Protected mode
 - Paging
 - MP configuration
 - Software/Hardware interrupts
 - Device emulation (disk, keyboard, APIC timer, local APIC, IO APIC, UART etc)
 
To do:
- FPU-related instructions
 - Exception
 - Virtual 8086 mode
 - TLB
 
System requirements:
- Memory: 512MB
 - CPU: scheduler loop will occupy CPU resource. 
nicecommand, cgroups or docker resource setting might help here. 
make
# basic use
./dax86 [binary_file]
# run xv6 (ctrl + c to stop)
./dax86 xv6memfs.img
# verbose run (prints each op)
./dax86 [binary_file] -v
Though dax86 can be built for different targets and run, there's a docker image in case Debian's build-essential package is preferred to the build environment of your host. Mini Debian Jessie is used for the base image.
The command below will build image, run a container with the image and execute shell in interactive mode.
make create-docker
To clean created container and image, run the command below.
make clean-docker
# test all
./test.sh
# test specific one in tests/exec directory
./test.sh [test_name]
# directory test binary (stops at EIP: 0x0)
./dax86 test [binary_file]
- Disassemble Binary
 
# 32 bit all the way 
ndisasm -b 32 [binary_file]
# 32 bit after 0xFF bytes of real mode instructions
ndisasm -b 32 [binary_file] -k 0,0xFF
- View Binary
 
# hex
xxd [bin_file]
# bin
xxd -b [binary_file]
Referenced these publications with many thanks: