My now wife came up with a wonderfully nerdy idea to send out 3.5 inch floppy disks as 'save the date' reminders for our wedding. Feeling that my status as 'nerdiest' in the relationship was threatened I thought...
"Wouldn't it be great if we could put a secret message on the disks. Some kind of program that displays a secret message when you boot up your computer with the disk in the drive".
This instructable is a description of how I wrote a helper script in python and a healthy does of 8086 assembly to regain my 'nerdiest' status.
Step 1: Plan
To make the secret message I originally explored a few ideas:
1. Copy a text and or image file to the disk
2. Find a copy of some floppy disk linux distro and setup an init script to display a message on boot
3. Write to the boot sector of the disk and hope someone is silly enough to put the disk in before turning on their computer
Number 1 would have been relatively easy, but not nearly as fun. 2 seemed doable however I had some difficulty finding a working distro and 3 sounded like oh so much fun.
So, the basic plan was to find some way to make a custom 'boot disk' that when the computer is powered on with the disk in the drive a secret message will appear on the screen. For those of you too impatient to read the instructable, you can find the code to make your own secret message floppy disks here:
Step 2: Dusting Off Old Webpages
After some google searching I found a series of awesome tutorials on linuxgazette.net on 'Writing Your Own Toy OS':
Part 1: http://linuxgazette.net/issue77/krishnakumar.html
Part 2: http://linuxgazette.net/issue79/krishnakumar.html
Part 3: http://linuxgazette.net/issue82/raghu.html
In short, these tutorials detail how to write some assembly code for 8086 type processors (i.e. 386s, 486s, Pentiums, etc...) to do epic things like display a single letter A on screen and more! These actually covered everything I needed to know to display a simple secret message on screen.
Rather than try to duplicate the tutorials I will just highly recommend that you go through at least parts 1 and 2. If you don't have a floppy drive or disks on hand don't worry. I did all of the development and debugging using qemu, a processor emulator, and only burned the resulting image to actual disks when I had worked out most of the bugs.
Step 3: Setting Up Software
If you're lucky enough to be on a *nix system it's likely that Qemu is available through whatever package manager you use. On ubuntu, you can install it by typing:
sudo apt-get install qemu
or by searching for qemu in the software center (*shiver*). It looks like it may soon be renamed to qemu-kvm
On Macs, last time I checked qemu was available through homebrew (possibly also macports, fink, etc.).
On Windows... not sure. If anyone has a good link, please include it in the comments.
Finally, the source is available at: http://wiki.qemu.org/Download
Other software that you will need includes:
1. as86 and ld86 (on ubuntu, available in the bin86 package: sudo apt-get install bin86)
Here is all of it on one line for you ubuntuers:
sudo apt-get install qemu bin86 gcc python make
Step 4: Working Through Tutorial Part 1
Now that your computer has the necessary software, it's time to work through part 1 of the "Writing Your Own Toy OS" tutorial. Now if you're not using a physical floppy drive you'll have to use a slightly modified write.c that writes the image to a file, not to a floppy.
I will include the text of write.c at the bottom of this step and also attach the file.
Finally, test the image (boot) that you made in the tutorial in qemu. When I first made these images, ubuntu sensibly named the qemu binary 'qemu'. Now, it appears that at least in 12.04 qemu is now 'kvm'. So, if you're not using a recent ubuntu the command you will want to run may be slightly different.
On Ubuntu 12.04:
kvm -fda boot.img
On other platforms where qemu is referred to as... qemu (*sigh*)
qemu -fda boot.img
At this point, a window should pop up where the first character (eventually) becomes a white A on a black background.
------------------------ write.c -------------------------
int floppy_desc, file_desc;
file_desc = open("./boot", O_RDONLY);
read(file_desc, boot_buf, 510);
boot_buf = 0x55;
boot_buf = 0xaa;
floppy_desc = open("./boot.img", O_RDWR | O_CREAT);
lseek(floppy_desc, 0, SEEK_CUR);
write(floppy_desc, boot_buf, 512);
Step 5: What You Can Do So Far
So now you can make a boot disk that displays simple characters on screen. The meat of the code is as follows
mov ,#0x41; set the first character to ascii code 0x41 "A"
mov ,#0x1f; set the 'attribute' of the first character
The attribute bits set the color of the character and background. 0x1f or %00011111 sets the background to blue (first 4 bits, 0001) and foreground to white (1111). One word of warning here, when i tested this out on a real machine I discovered that at least the computer I used also had a blink bit (woot!). From the following link, it should be bit 7 or (%10000000 = blink).
You can find more info here:
Feel free to do what I did here, and play around with making all sorts of colored text (make all you design friends cry with yellow text on a white background) and display funny things like 'Feed me' etc...
This seemed very promising however I ran into a limitation where the boot sector on a floppy disk is only 512 bytes. This is fine for short messages, however if you want to do something fancier or more complicated you'll have to move on to part 2.
Step 6: Part 2
I'll let part 2 of "Writing Your Own Toy OS" explain all the nitty gritty of getting the computer to run code that is not on the boot sector. Again, you'll have to make a few changes to write.c if you're not using a physical floppy drive (see attachment).
If all you want to do is display a short message than just change the lines:
.ascii "Handling BIOS interrupts"
Change the 26 to the length of your string + 2 and the text in quotes to your message.
For example, a message like "Hello Human" would be 11 characters long so:
.ascii "Hello Human"
Step 7: Secret Message
The message I ended up displaying was 80x25 characters (standard display size). Rather than writing the assembly directly, I wrote a python script that:
1. reads in a text file
2. reads the ascii code of each character
3. generates the 8086 assembly code for sect2.s to display the characters
The script is terribly ugly, but hopefully with what you've learned from these tutorials, you can change it to your liking. Setting the attr variable at the beginning of the file will change the text attributes (if you don't like the white on pink). Also, if you edit secret.txt you might want to make sure each line has 80 characters so that you fully define what is on screen.
Step 8: Reception
Overall the disks went over quite well. At first, we told no one that they contained anything, hoping that someone would foolishly try to boot it as I probably would :). After a few weeks of suspense (and a few broken disks in the mail) we let people know that the disk was bootable. After that, several people dusted off their old computers, booted up the disks and were quite pleased to find the secret message.
I then proposed a challenge to a few of the more technically inclined invitees and I will pose the same challenge to you. There is a secret within the secret. There is some way to trigger the display of a second secret message (which you can easily find in the code). If you figure out the trigger, please post it in the comments along with a brief description of how you figured it out.
I've attached a zip file containing all the files related to parts 1 and 2 of the 'Writing Your Own Toy OS' tutorial and the final disk image with the 2 secret messages. Happy hunting!