At long last I have finally succeeded in loading a program off of an external device and executing it.

I mentioned in my last post that I was having trouble reading multiple blocks from the SD card. As it turns out, this was because I was resetting the bit count to 0 instead of 7. Since the SD card transmits MSB first, it was reading bit 0 and then moving on the the next byte, which screwed everything up. Changing it to 7 means that it reads the first byte properly. The reason it worked the first time was because I reset it properly during an actualy reset, but not after it is done reading. Anyway, onto the file system.

File System

I chose to use FAT32 since it is simple. I have experience working with ext2 from my previous project, but FAT is simpler and is the preferred choice for SD cards anyway. Additionally, FAT32 has 512b sectors which maps to the 512b sd card blocks.

The first sector is the boot sector. The boot sector is identified by the signature in the last two bytes, which is 0x55 0xAA. The first 3 bytes of the boot sector are cpu instructions, usually a jump, which is followed by a bunch of information about the drive, and then the rest of the code that the first instruction jumps too.

Since I am not booting from the SD card, I don’t care about any of the code that is on there. The things that we do care about are the number of reserved sectors, the number of file allocation tables, and the number of sectors per file allocation table. If we add up the number of reserved sectors with the number of FAT sectors, we get the offset of the data region. The start of the data region will be the root directory.

Here you can see the result of reading the boot sector: read_boot_sector_2.png

In the root directory there are a series of directory listings. Since we are using VFAT, each entry has 2 or more directory entries: 1 or more VFAT entry and 1 DOS entry. the VFAT entries store the longer file name and the DOS entry stores the actual location and information about the file.

Here is the result of reading the directory entry:

read_directory_entry_2.png

The file location that we read from the directory entry is the cluster number in the data region. Cluster size is given in the boot sector, which we earlier read as 8. We know that the first two clusters don’t exist, so we take the cluster number, subtract two from it, then multiply by 8 to get the sector offset. We can then add that to the data region offset we calculated earlier to get the sector that the file is in.

We assume that the first file we come across is the file that we want, and then parse it as if it is an o65 file. I may write a post about how o65 files work but until then here is the official spec.

First we print the header of the file, which is shown here:

parsed_o65_2.png

Here you can see the text and data segments as well as where they were orignally linked. the o65 format allows for relocation by giving a table of every address that would have to be changed, but we can ignore that for now by just copying the code and data to where it wanted to be originally.

Next we print out the code, so we can verify it is what we want, then copy it to the locations specified earlier. Then we print it out again to make sure it was copied correctly. Finally, we call the copied code as if it were a function and then print the return value.

executed_o65_2.png

It says the return value is 0x41, which seems correct, given the code literally returns 0x41 and does nothing else.

int main() {
    return 0x41;
}

and there it is! We compiled a program, wrote it to the SD card, read it off the the SD card and then executed it!

If you want to check it out, here is a link to my gitlab.