Running your Raspberry Pi on a conventional (or SSD) hard disk or a USB thumb drive

A Raspberry Pi (mine is an RPI 3) requires a MicroSD card to boot, but once booted it is not required any longer. This is great because while very convenient, a MicroSD card is not as robust and hardy as a regular SSD card or even a regular USB flash device.

One of the things that I therefore do is to run my RPI’s on either SSD or a USB thumb drive. I’ve also run mine with a 1TB external spinning rust disk with external power. The technique illustrated here works on all of these.

My earlier post described the RPI boot process. The picture here shows a simple MicroSD card image for an RPI. The disk is partitioned into two parts, the first partition is a small FAT32 LBA addressable partition and the second is a larger ext4 partition. The FAT32 partition contains the bootloader and the ext4 partition contains the root filesystem.

The thing that these two together is cmdline.txt which defines the root device with a declaration like:

root=/dev/mmcblk0p2 rootfstype=ext4

Since the RPI always mounts the MicroSD card as /dev/mmcblk0 and the partitions are numbered p1, p2, and so on, this indicates that the root partition is the ext4 partition as shown above.

To move this to a different location is a mere matter of adjusting cmdline.txt (and updating /etc/fstab) as shown below.

Here is my RPI with a USB thumb drive running the root (/) filesystem.

As you can see, I have a USB drive which shows up as /dev/sda and the MicroSD card.

amrith@rpi:~$ lsblk
sda 8:0 1 115.7G 0 disk
└─sda1 8:1 1 115.7G 0 part /
mmcblk0 179:0 0 29G 0 disk
└─mmcblk0p1 179:1 0 100M 0 part /boot

amrith@rpi:~$ blkid
/dev/mmcblk0p1: LABEL="BOOT" UUID="E4F6-9E9D" TYPE="vfat" PARTUUID="01deb70e-01"
/dev/sda1: LABEL="root" UUID="7f4e0807-d745-4d6e-af6f-799d23a6450e" TYPE="ext4" PARTUUID="88578723-01"

I have changed cmdline.txt as shown below.

amrith@rpi:~$ more /boot/cmdline.txt
[...] root=/dev/sda1 rootfstype=ext4 [...]

and updated /etc/fstab (on the USB drive) as shown below.

amrith@rpi:~$ more /etc/fstab
# fstab generated by rpi-base element
proc /proc proc defaults 0 0
LABEL=BOOT /boot vfat defaults,ro 0 2
PARTUUID=88578723-01 / ext4 defaults,noatime 0 1

As you can see, I’ve also marked the MicroSD card (which provides /boot) to be readonly; in the unlikely event that I have to modify it, I can remount it without the ‘ro’ option and make any changes.

This is illustrated below

On the left hand side is the MicroSD card. Note that on the MicroSD card, in the FAT32 partition, cmdline.txt is in ‘/’ (there’s no /boot on the MicroSD card). the cmdline.txt points the root partition to /dev/sda1 which is the USB flash drive.

On the right hand side is the USB flash drive, it has an ext4 partition with an /etc/fstab entry which mounts the MicroSD card’s fat32 partition on /boot and mounts itself on /.

This works just as well with any external disk; just make sure that you have adequate power!

Everything you wanted to know about Raspberry Pi (RPI) images

This is a two part blog post that covers a lot of topics about a rather boring aspect of the RPI. I suspect that the vast majority of people using a RPI wouldn’t be interested in most of this stuff. But, there are a small number of people out there (like myself) who will no doubt find this stuff very useful.

This (the first of two) posts covers the booting process of an RPI. You need to have some idea of how this works to make your own images.

I have a RPI 3, some of this stuff may not be accurate for other models.

RPI Booting demystified

I have not been able to find any documentation on the bootloader that runs in the firmware but by trial and error, here is what I’ve found.

The firmware accesses the partition table on the MicroSD card which it assumes is an MS-DOS style partition table. The partition table is at the very beginning of the card and is part of the Master Boot Record (MBR). A good write up about this layout is found here [1].

The bootloader looks (it appears) for an MS-DOS LBA addressable partition. I have found that partition types 0x0C and 0x0E work. In order to boot reliably, I have also found that this must be the first partition on the disk.

RPI’s don’t use bootstrap code on the MicroSD card.

This is very important to if you wish to make your own images; it makes that process a whole lot simpler. The bootloader in firmware looks instead at this small MS-DOS partition to find a kernel, all the drivers it needs, and a pointer to the root file system.

The bootloader parses the cmdline.txt file to find the root partition. Here is a small portion of the cmdline.txt on one of my RPIs.

root=/dev/mmcblk0p2 rootfstype=ext4

The RPI addresses the MicroSD as /dev/mmcblk0 and the partitions on it are (in order) addressed as /dev/mmcblk0p1, /dev/mmcblk0p2, and so on.

The cmdline.txt file identifies the root partition either by providing this name, or by specifying a partition UUID, or a label. In the example above, cmdline.txt points to the second partition on the MicroSD card.

I found exactly one place that appears to document this in some detail, that is here[2].

Troubleshooting the boot process

When you power on the RPI, the red light indicates power. The green light (ACT/D5) indicates SD card access. If the red light comes on but the green one doesn’t it means that the firmware did not find a card it liked. This has been the most common problem described by people online.

If you have the tools to debug it, here are some things that I have found to be helpful.

If you can put this MicroSD card into a machine where you can mount it (and hopefully that machine is Linux based; if it is Windows based, my apologies, I can’t help you).

lsblk will help you identify the device. For example on my machine it is /dev/sdc. Here is the output of lsblk on my machine. The MicroSD card is shown in bold letters.

$ lsblk
sda 8:0 0 150G 0 disk
├─sda1 8:1 0 134G 0 part /
├─sda2 8:2 0 1K 0 part
└─sda5 8:5 0 16G 0 part [SWAP]
sdc 8:32 1 29.7G 0 disk
├─sdc1 8:33 1 100M 0 part
└─sdc2 8:34 1 29.6G 0 part
sr0 11:0 1 1024M 0 rom

And (as root) runnint ‘parted’ on that device gives me

(parted) unit b
(parted) print
Model: SD SL16G (sd/mmc)
Disk /dev/mmcblk0: 15931539456B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number Start End Size Type File system Flags
 1 1048576B 1529000447B 1527951872B primary fat32 lba

As highlighted above, the partition table is ‘msdos’ and the partition is shown as ‘fat32 lba’. Both of these are essential.

Here are some examples of a closer look at the MicroSD card using hexdump.

# sudo dd if=/dev/sdc of=/tmp/head bs=4K count=1
# hexdump -C /tmp/head
00000000 fa b8 00 10 8e d0 bc 00 b0 b8 00 00 8e d8 8e c0 |................|
00000010 fb be 00 7c bf 00 06 b9 00 02 f3 a4 ea 21 06 00 |...|.........!..|
00000020 00 be be 07 38 04 75 0b 83 c6 10 81 fe fe 07 75 |....8.u........u|
00000030 f3 eb 16 b4 02 b0 01 bb 00 7c b2 80 8a 74 01 8b |.........|...t..|
00000040 4c 02 cd 13 ea 00 7c 00 00 eb fe 00 00 00 00 00 |L.....|.........|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001b0 00 00 00 00 00 00 00 00 d4 5c 0b 00 00 00 00 00 |.........\......|
000001c0 01 20 0e 03 d0 ff 00 08 00 00 59 89 2d 00 00 03 |. ........Y.-...|
000001d0 d0 ff 05 03 d0 ff 59 91 2d 00 a7 3a ad 01 00 00 |......Y.-..:....|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

The thing I’ve highlighted is the byte at offset 0x1c2 into the card, here it says 0x0E. That is the code for a Fat16 LBA mapped partition table.

On another RPI, I have the following.

$ sudo dd if=/dev/sdc of=/tmp/header bs=4K count=1
$ hexdump -C /tmp/header
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001b0 00 00 00 00 00 00 00 00 99 56 4c 6b 00 00 80 20 |.........VLk... |
000001c0 21 00 0c eb 17 0c 00 08 00 00 00 20 03 00 00 eb |!.......... ....|
000001d0 17 0c 83 f9 71 05 00 28 03 00 00 d0 3c 00 00 00 |....q..(....<...|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

Both of these work well for me. If you don’t see one of these, look up the number you do see here [3]. If it is not a MS-DOS LBA-mapped partition type, you have a problem.

If you made your own SD card and you have the image file handy, you can inspect it to see what it has as follows.

Here is an image I built for myself.

$ ls -l raspbian.raw
-rw-rw-r-- 1 amrith amrith 2147483648 Jul 16 22:26 raspbian.raw

It is a 2GB Raspbian clone that I use for some of my machines. It contains two partitions, the output below shows offsets and sizes in Bytes because of the ‘unit b’ command.

$ sudo parted ./raspbian.raw unit b print
Model: (file)
Disk /home/amrith/images/raspbian.raw: 2147483648B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number Start End Size Type File system Flags
 1 1048576B 105906175B 104857600B primary fat32 boot, lba
 2 105906176B 2146435071B 2040528896B primary ext4

Armed with that information, you can now do this.

$ sudo losetup --show -o 1048576 -f ./raspbian.raw
$ sudo losetup --show -o 105906176 -f ./raspbian.raw
$ mkdir /tmp/boot
$ mkdir /tmp/root
$ sudo mount /dev/loop0 /tmp/boot
$ sudo mount /dev/loop1 /tmp/root

/tmp/boot and /tmp/root now mount the MS-DOS and ext4 partitions in the image using loopback file systems. This is very useful in debugging. You can, of course, do the exact same thing on a MicroSD card and make corrections to the card if you so desire.

Making your own images

The next installment of this blog post will describe how you can build your own images.