To start off, I’m going to explain just what is required to be on the SD Card when the raspberry pi boots up. This is a fairly complicated process in actuality, and it took me forever to fully figure it out. From your perspective, however, it’s quite simple. The bare requirements are as follows:
- The first partition in your SD Card is formatted under Fat32.
- The SD Card contains some pre-loaded boot files provided by the raspberry pi foundation.
- A kernel.img file is provided.
Excellent! That’s it. One of the first questions I had when getting setup was what exactly is a kernel.img file and how does that need to be formatted? I’ll get to that in more detail later, for now just realize that it is a raw ELF file dumped into a file with an img extension.
Before starting anything, you’ll need to get the raspberry-pi specific bootloader. Note: you cannot use any old bootloader. So GRUB is out of the question. You have to specifically use the bootloader.bin and startup.elf files provided by the raspberry pi foundation. Assuming you have git installed, let’s snag those files first…
So first, let’s setup our project directory structure. Here is a series of commands you can run to setup the structure.
- mkdir ~/rpi-kernel
- mkdir ~/rpi-kernel/boot
- mkdir ~/rpi-kernel/kernel
- mkdir ~/rpi-kernel/output
- mkdir ~/rpi-kernel/make
Now that we have the directory structure setup, let’s look at the bootloader files and put them inside our ~/rpi-kernel/boot directory. The official firmware project can be accessed from this URL: http://github.com/raspberrypi/firmware/tree/master You can git clone the whole repository if you want, but it’s actually pretty large. So I’ll just list the files you specifically need and you can download those directly into your boot directory.
And that’s it! These are the necessary files required for the little green light to turn on when booting the raspberry pi from your own image.
Now that we have the bare minimum required, let’s look at making a bash script to automatically generate our IMG file. Now, I am not a linux expert – so I apologize if this seems pretty silly. After quite some time, I was able to write my very own script to automatically generate a bootable IMG file, however, the commands I use require root privileges. I don’t know how to do it any other way, but I’m sure it’s possible…
I’ll walk you through the relevant commands. But first, let’s create the actual script file.
- nano ~/rpi-kernel/make/genimage.sh
Okay, now that we have a file let’s start writing it! The first thing your bash script needs is this line: #!/bin/sh. This tells the computer it’s an executable script (I think). To make life easy, we’re going to setup a few variables next.
Yeah, no text. Sorry 🙂 I am a firm believer in typing things out yourself. You’ll thank me later.
All we’re doing here is defining variables that can be used later. For example: $OUTPUT would reference the output name that we’ve set. Note you have to have the dollar-sign in front of the variable name when accessing it. The interesting thing to note here is the variable OUTPUSIZEmb. Yes, we are outputting a 34MB file. This is important because FAT32 requires ~34mb of space to properly generate the file structure. I don’t know exactly why, but it looks like this is the minimum output size we can generate.
Now this looks scary, but it’s not all that bad. You can do the math ahead of time if you want – but I like to have it all configured from variables. Basically we are generating some details about the output file that we must use when creating the file. I probably do this the hard way, but after much testing – it all works. So let’s roll with it.
This next line uses some of the math we calculated above to generate a completely blank IMG file.
Now for a big scary one. Let’s take this one in sections… First, the command is fdisk. This is a utility that allows us to specify some meta-data about the IMG file. Specifically things like how many bytes per sector, how many sectors, whether it’s bootable, etc. Next, you’ll see I have this line > /dev/null 2>&1 This part is just for convenience. It basically says “redirect all the output from this command to a fake console”. That makes it so we don’t have to see the nitty gritty details of what happens when we run the script. Lastly, we do << EOF – this allows us to specify how the IMG file is formatted by sending in command line characters that get processed by the utility. I recommend you do this part by hand first, just to see the output and to better understand the fdisk utility.
This is the last part of our script. I’ll try to explain it in detail…
losetup is a utility that lets you mount a sector of an IMG file. This is important because our IMG file has 4 sectors, and due to the boot table information – those sectors are not aligned to 0x0. This means we have to offset the starting point of our FAT32 partition, which is what the command line args are doing for us. The math that I am using in there is just something I’ve determined ahead of time that will work. Basically our FAT32 file system starts at an offset of 63 sectors. Each sector is 512 bytes. So we offset at 512b * 63s. Then we tell it to virtually mount that partition to the location /dev/loop1. You may need to create this directory if it doesn’t already exist.
mkfs.msdos is a utility that will format the virtual drive we just mounted, and passing in the command line args -F 32, it will format it under FAT32, which is what the raspberry pi requires.
mount is a utility that will let us mount the newly formatted partition of our IMG file as though it were a regular folder on our hard drive. Once we’ve mounted it, we can write files to it by copying them.
chmod 777 this is probably unnecessary. I didn’t even know I still had this in here… I would recommend not doing this.
cp this is the linux command to copy files. So basically we are copying files from our BOOT directory into the IMG file.
umount this is a utility to un-mount the IMG file. PLEASE NOTE: it is umount. NOT UNmount. There is no ‘n’.
And that’s it! If you run this script, hopefully you will have an IMG file that you can then write to an SD card and boot from. In later posts, I’ll explain how to generate the kernel.IMG file. We will be writing it to the /boot/ directory of our project folder, which means it will be automatically written to the SD card when we call this script.