Assembly programming can be intimidating for people who have never looked into it any deeper than a glance, but giving that it underpins how the computers we use work it can be helpful having context in regards to what is actually being run by the CPU.
[Photo by: Drew Sadik]
x86 PCs are impressive in that they are fully backwards compatible with the original IBM PC. All the way down to timing circuits and boot process. This is both great in that almost all PCs should be able to run software from 1983, but this backwards compatibility also has a very high cost. The x86 ISA is inframous in it’s edge cases and complexity.
To boot a modern x86 PC, you need to step through the history of x86, this is handled by the bootloader in 99% of cases:
For the case of our demo’s we are going to focus on the first mode. 16 bit “real mode” is the mode that DOS and other vintage operating systems run on. This mode offers no system security that we are used to on our modern systems. When a program is run it has full access to the system and can alter the operating system if it wants to. This allowed a creative virus scene to spring up for DOS (though these viruses were more annoying than actually malicious)
This mode also has a very simple model for interacting with hardware. Because PCs had a wide range of hardware they outsourced a lot of the code to interact with hardware with software interrupts (often handled by the BIOS)
This makes the initial stages of OS development easy, since you only need to know a handful of software interrupts to get most of of the I/O work done.
With that, we can start on our first demo:
So what is happening here? The
mov instruction moves data from one place to another. In this case we are purely setting registers in the CPU and not touching RAM in the code. The
int instruction fires off a software interrupt, in our case the 16th one.
After that, we invoke
hlt to stop the CPU from doing anything else. Since we are done with what we wanted to do.
But hang on, how did we even get to this stage? What did the computer do to get our code running just then?
The BIOS is generally the first thing that gets run on the system, its job is to setup and test that the computer is working correctly, It also writes out information about the system so that operating systems later on can easily detect hardware.
Assuming the BIOS knows what device it wants to boot off, it will load the first sector (512 bytes) from that, into a standardised position of memory, and then hand over control by jumping to that part of memory
In the demo above, the browser made the 512 byte payload, padded it into a 1.4MB floppy disk image, and gave it into a emulator to run.
So what happens when the program you need to run is more than 512 bytes?
Luckily for us the BIOS has us covered with disk I/O as well with int 13h calls that allow easy access to the drives in the system.
This code loads a segment from the next sector of the virtual floppy disk, and then jumps to it! The int 13h API is pretty simple, and gives away some of the low level details of how storage works (though with the invention of flash memory, a lot of these values are emulated to retain compatibility)
There are a lot of BIOS provided services out there, some are more official than others, there is a great reference guide at http://www.ctyme.com/intr/rb-0608.htm (Though I do warn you about the 90’s style porn banner ads at the bottom of these pages)
Hopefully this was a fun intro, You can move onwards and even switch to C (or Rust!) and find more information about the underlying hardware of most of the computers you sit down and use daily on http://wiki.osdev.org/
If you found this post interesting, you might like the other things I’ve done! If not you can always stay up to date with when I push out a new post by following me on Twitter, or using my blog’s RSS if that is more of your thing.
Until next time!