(If this file is unreadable, look at readme.nix.)

      _   _____  __  ___  
     | | | ____|/_ ||__ \ 
   __| | | |__   | |   ) |
  / _` | |___ \  | |  / / 
 | (_| |  ___) | | | / /_ 
  \__,_| |____/  |_||____|

   d512, an extensible "debug"-like OS in 512 bytes
   By Joshua Oreman
   Created for the FASM 512-byte competition
   This code is in the public domain. You can use it however you like.

Introduction
============
d512 is a simple machine monitor for x86 systems. You can read and write
memory, copy memory, and execute blocks of code. It can support up to 3
add-on modules that add more commands. See below to find out how to write
said modules :-)

This runs in "unreal mode", which means 4GB of address space and no segment
registers for you! :-)

Installation
============
If you're on *nix, run ./install.sh. If you're creating a floppy disk
image for Bochs, type in e.g. d512.flp and point Bochs to that
file. If you're writing to a real floppy, make sure you're root and
type in /dev/fd0. Real floppies will take a while.

If you're on Windows, open a DOS box, insert an expendable floppy in
drive A: and run install.bat. It should be quick. Thanks to the
DEBUGOS folks for their abscopy program.

Then fire up bochs or reboot the computer. Preferably, read the rest
of this file first :-)

Commands
========
Here is a list of the available commands. Backspace will not work, so
type well. Don't try anything wacky like writing 0 bytes (it'll
interpret that as 0x10000). There is slim to no error checking. You
will not need to type punctuation (e.g. if this says "> r/0200
00007c00" type "r020000007c00"). All numbers are hex. 'a' through 'f'
must be lowercase. You need to type all the digits, including leading
zeroes. If you type in anything other than '0' through '9', 'a'
through 'f', you'll get weird results. Input will be echoed every byte
(that's two digits).

Without further ado, the basic commands...
> r/LENGTH ADDR
Hex-dumps LENGTH (two bytes) bytes starting at ADDR (four bytes). You
get the full "canonical format" hexdump: offset, hex bytes, ASCII.
LENGTH will be rounded up to the nearest multiple of 16.
> w/LENGTH ADDR
Writes LENGTH (two bytes) bytes starting at ADDR (four bytes). Input
the bytes in hex, with lowercase letters (a..f, not A..F). A space will
be output after every byte to make it look nicer.
> W/LENGTH ADDR
The same as 'w', except the input is ASCII.
> c/LENGTH SRCADDR DSTADDR
Copies LENGTH (two bytes) bytes from SRCADDR (four bytes) to DSTADDR (four
bytes).
> x ADDR
Begins execution at ADDR. Executing data will produce unpredictable results,
to say the least.
*** BIG FAT IMPORTANT NOTE ***: You NEED a 'retn' instruction (0xC3) at the
end of the stream of instructions to be executed.
> q
Reboots the computer.

Yeah, this seems kind of wimpy. There's not much you can do with six commands.
Sure, you could write programs to do other stuff (inb/outb, BIOS calls, etc.),
but then you have to be cumbersome with the 'x' command.

Right?

Not so fast.

At addresses 0x7c46 to 0x7c58, you have 18 NOPs. You can overwrite these with
whatever you want. For example, a CALL FAR 0:0x7e00 (9a 00 7e 00 00). AL will
hold the character typed. You can create additional commands this way.

Which brings us to the next point...

I/O Extensions
==============
A machine monitor isn't too useful without I/O, right? So I've written a little
extension, 512 additional bytes, and tacked it on the end of d512.asm. (It's in
the file d512x.bin). Make sure it's on sector 2 of the floppy (DOS/Windows:
abscopy d512x.bin 1; *nix: dd if=d512x.bin of=/dev/fd0 seek=1). Then type these
commands once you're booted:

> w/0012 00001000
b8 01 02 31 db 8e c3 bb 00 7e b9 02 00 31 d2 cd 13 c3
> x 00001000
> w/0005 00007c50
9a 00 7e 00 00
>

This gives you five new I/O-related commands.
> l/NSECs CYL/HEAD/SEC SEG:OFF
Loads NSEC (one byte) sectors from CYL/HEAD/SEC (two/one/one byte) on drive A:
to SEG:OFF (SEG and OFF two bytes each). Displays the status code in AH after
the BIOS call. This function uses real-mode addresses because it calls the BIOS.
> s/NSECs SEG:OFF CYL/HEAD/SEC
Saves NSEC sectors starting at SEG:OFF to CYL/HEAD/SEC. Sizes are the same as for
'l'.
> iX PORT
Inputs a byte, word, or dword (X is b, w, or d) from PORT (two bytes) and prints
it.
> oX PORT VAL
Outputs a byte, word, or dword VAL to PORT. PORT is two bytes; VAL is the appropriate
size.
> I NNh
Calls an interrupt (BIOS or otherwise). NN is the interrupt number, one byte.
You will be asked for the values of AX, BX, CX, DX, SI, DI, BP, DS, and ES to use
for the call.

You can write your own extensions too. Just patch in a CALL FAR somewhere between
0x7c46 and 0x7c50 and load it from the disk. (Dis)assembler? Editor? Clock? The
possibilities are endless.

Enjoy, and have a lot of fun!

-- Josh
