Overview
So I have a Raspberry Pi 2 B (the latest model at the moment of writing this article – Dec 2015), 128Mb size SD card and some USB flash drive. The goal is to make the Raspberry Pi boot from 128Mb microSD card and continue loading everything else from the USB flash drive.
The problem is in that that the official raspbian distributives does not allow you to use microSD card smaller than a 1Gb to boot the system from (minimum recommended is 4Gb), and that’s what we will be dealing with here.
This article is updated – Jan 2024.
Please read this article for more solutions.
Context
Raspberry Pi can not be booted directly from USB flash drive (actually can, read this), but only from the microSD card, and more interesting, most available Raspbian OS (or Raspberry Pi OS now) images are bigger than 1Gb of size, so it is impossible to boot the Raspberry Pi from the 128Mb microSD card w/o customization.
The described below method will allow you to boot Raspberry Pi OS using the 128Mb microSD card, however you still need some additional storage to complete the OS loading – the USB flash drive, since it still needs more space for everything else needed for the system to be successfully loaded and running.
Bear in mind that the read/write speed of your SD card might be significantly slower/faster than your USB flash drive, which may affect your OS system loading speed.
Prerequisites
Usually the original Raspbian (or Raspberry Pi) OS image contains two partitions, one is /boot
, and another one is /
. In this article I will show you how to derive the /boot
partition only and write it onto the microSD card, so the system will be able to start booting from the microSD card, and then, by editing cmdline.txt
file of the /boot
partition, we will tell the system to continue loading from the other source (USB flash drive or even network storage, i.e. NFS). Before the system will switch to the other source the system will load all required drivers, so the other source will be accessible for the system when it switches to it. /etc/fstab
also needs to be changed so all drives are mounted correctly on each system start.
Usually the /boot partition of the image is not bigger than 50-70Mb, even if the partition itself is bigger (in the latest Raspberry Pi OS it is usually 256Mb), the total files size is less than 128Mb, that’s exactly what we need for this project.
We would need the laptop with any Ubuntu or Debian system installed, or if you use Windows – install Debian or Ubuntu on VirtualBox, or if your Windows is 11 – use WSL (Windows Subsystem for Linux).
We also need 128Mb microSD card and at least 4Gb USB flash drive.
I will be using Windows 11 with WSL in all my code samples below.
Just reminding you that the standard/default login/pass for the Raspberry Pi OS are:
- login: pi
- password: raspberry
Don’t forget to change the password once all is done and you finally see the Raspberry Pi OS welcome or configuration screen 🙂 .
Let’s get started
Prepare your WSL
By default WSL is not able to see (as well as read from or write to) your USB (including microSD card) devices attached physically to your PC/laptop. However there is a solution for that, build your custom linux kernel for WSL which will support USB devices, so then the USB drive can be attached from Windows to WSL and seen by WSL distro in the same way as on original linux OS, as a /dev/sd*
device. The whole process is described here.
Download and analyze the Raspbian OS image
- Log in to your WSL distro (I’m using Ubuntu):
wsl -d Ubuntu
- Download the Raspberry Pi OS image (Bullseye, 32bit legacy) from Raspberry Download source. Basically you can use any prior Raspbian OS, or Raspberry Pi OS except the latest (starting from bookworm) Raspberry Pi OS images, since they have a different options of booting from USB and other devices, read this:
cd /tmp && wget https://downloads.raspberrypi.com/raspios_oldstable_armhf/images/raspios_oldstable_armhf-2023-12-06/2023-12-05-raspios-bullseye-armhf.img.xz
- Extract the image file:
xz -dv 2023-12-05-raspios-bullseye-armhf.img.xz
- Analyze the downloaded image:
sudo apt update && sudo apt install fdisk && \ fdisk -l 2023-12-05-raspios-bullseye-armhf.img
There should be the result like this:
Disk 2023-12-05-raspios-bullseye-armhf.img: 3.99 GiB, 4286578688 bytes, 8372224 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x54aa0fc0 Device Boot Start End Sectors Size Id Type 2023-12-05-raspios-bullseye-armhf.img1 8192 532479 524288 256M c W95 FAT32 (LBA) 2023-12-05-raspios-bullseye-armhf.img2 532480 8372223 7839744 3.7G 83 Linux
From the listing above we can clearly see that each sector is 512 bytes of size, the first 2023-12-05-raspios-bullseye-armhf.img1 image partition starts from sector 8192 and ends by sector 532479, total 524288 sectors, which is 256Mb of size (partition size, not the real files size). The second image partition
2023-12-05-raspios-bullseye-armhf.img2
starts from sector532480
and ends by sector8372223
, total7839744
sectors, which is 3.7Gb of size which we would not be able to write to our microSD card but we can easily write it to any 4Gb USB flash drive. We need the data of the first partition (2023-12-05-raspios-bullseye-armhf.img1) which we will extract from the original image and write onto the microSD card. On the USB flash drive we will write the second partition – 2023-12-05-raspios-bullseye-armhf.img2
Mount first partition
Create a respective mount folders in /mnt
:
cd /mnt && \
sudo mkdir image_boot image_data sdcard usbdrive
Mount first image partition to /mnt/image_boot
folder. Offset is calculated by Sector size
multiplied on sector Start
:
sudo mount -t vfat -o loop,offset=$((8192*512)) /tmp/2023-12-05-raspios-bullseye-armhf.img /mnt/image_boot/
Check the real size of the partition, used by files:
df -h
You should see something like:
Filesystem Size Used Avail Use% Mounted on
none 3.9G 4.0K 3.9G 1% /mnt/wsl
none 3.8T 300G 3.5T 8% /usr/lib/wsl/drivers
/dev/sdc 1007G 19G 938G 2% /
none 3.9G 92K 3.9G 1% /mnt/wslg
none 3.9G 0 3.9G 0% /usr/lib/wsl/lib
rootfs 3.9G 2.1M 3.9G 1% /init
none 3.9G 860K 3.9G 1% /run
none 3.9G 0 3.9G 0% /run/lock
none 3.9G 0 3.9G 0% /run/shm
tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup
none 3.9G 76K 3.9G 1% /mnt/wslg/versions.txt
none 3.9G 76K 3.9G 1% /mnt/wslg/doc
C:\ 3.8T 300G 3.5T 8% /mnt/c
G:\ 15G 6.5G 8.6G 44% /mnt/g
snapfuse 75M 75M 0 100% /snap/core22/1033
snapfuse 128K 128K 0 100% /snap/bare/5
snapfuse 74M 74M 0 100% /snap/core22/864
snapfuse 92M 92M 0 100% /snap/gtk-common-themes/1535
snapfuse 41M 41M 0 100% /snap/snapd/20290
snapfuse 41M 41M 0 100% /snap/snapd/20671
snapfuse 132M 132M 0 100% /snap/ubuntu-desktop-installer/1276
snapfuse 131M 131M 0 100% /snap/ubuntu-desktop-installer/1280
/dev/loop0 255M 51M 205M 20% /mnt/image_boot
Look at /dev/loop0
, which is mounted to /mnt/image_boot
, as you can see, the used space is only 51M from 255M of partition size (205M is available), so our 128Mb (even 64Mb) microSD card should perfectly fit.
Attach microSD card
Insert the microSD card in one of the physical port of your PC/laptop (Windows) and attach it to WSL (as described here), and check whether it is appeared in WSL properly:
lsusb
There should be something like:
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 011: ID 14cd:1212 Super Top microSD card reader (SY-T18)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Then run the following:
ls -al /dev/sd*
You should see new records in this list, which were not there before the microSD card attached to WSL, something like:
brw-rw---- 1 root disk 8, 0 Jan 16 12:38 /dev/sda
brw-rw---- 1 root disk 8, 16 Jan 16 12:38 /dev/sdb
brw-rw---- 1 root disk 8, 32 Jan 16 12:38 /dev/sdc
brw-rw---- 1 root disk 8, 48 Jan 16 20:08 /dev/sdd
The /dev/sdd
– new record (new USB device).
Now check the new USB device by running this command:
sudo lsblk -f
You should see your /dev/sdd
at bottom of the list:
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
loop0 vfat FAT32 bootfs 9C6E-1858 204.6M 20% /mnt/image_boot
sda ext4 1.0
sdb swap 1 200c5d9b-37a9-40e4-8978-29ce5d555db6 [SWAP]
sdc ext4 1.0 193d5217-6469-4205-8067-2e4fe4f76658 935.3G 2% /snap
/mnt/wslg/distro
/
sdd vfat FAT16 7C3E-ED07
Format microSD card
To be able to boot Raspberry Pi from your microSD card, it needs to be properly formatted with the right partition tables and filesystem. The partition table should be W95 FAT32 (LBA)
with id 0c
(or just c
), for this we will use fdisk
utility:
sudo fdisk /dev/sdd
and then type m
(to display all possible commands), d
(if you have already some partitions it needs to be deleted), F
(to show all free unpartitioned size, it should show all space of your disk), o
(to change the disklabel type to dos), n
(to create a new partition, leave all parameters by default, just press enter for all prompts), t
(to change the partition type to the 0c
W95 FAT32 (LBA)
) and finally w
(to write it all to the disk), and then check what you did by typing sudo fdisk -l /dev/sdd
, you should see something like:
Disk /dev/sdd: 121.25 MiB, 127139840 bytes, 248320 sectors
Disk model: Storage Device
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xf749f5de
Device Boot Start End Sectors Size Id Type
/dev/sdd1 2048 248319 246272 120.3M c W95 FAT32 (LBA)
Format just created microSD card partition (/dev/sdd1
) to vfat
(FAT32) filesystem:
sudo mkfs -t vfat /dev/sdd1
We need PARTUUID
of just created partition for later use (in /etc/fstab
), run sudo blkid /dev/sdd1
and write it down somewhere:
/dev/sdd1: SEC_TYPE="msdos" UUID="888A-9013" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="f749f5de-01"
Mount microSD card
Mount microSD card to /mnt/sdcard
folder:
sudo mount /dev/sdd1 /mnt/sdcard
Check that the mounting was successful by typing df -h
, you should see /dev/sdd1
mounted to /mnt/sdcard
in the bottom of the list:
Filesystem Size Used Avail Use% Mounted on
none 3.9G 4.0K 3.9G 1% /mnt/wsl
none 3.8T 300G 3.5T 8% /usr/lib/wsl/drivers
/dev/sdc 1007G 19G 938G 2% /
none 3.9G 92K 3.9G 1% /mnt/wslg
none 3.9G 0 3.9G 0% /usr/lib/wsl/lib
rootfs 3.9G 2.1M 3.9G 1% /init
none 3.9G 864K 3.9G 1% /run
none 3.9G 0 3.9G 0% /run/lock
none 3.9G 0 3.9G 0% /run/shm
tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup
none 3.9G 76K 3.9G 1% /mnt/wslg/versions.txt
none 3.9G 76K 3.9G 1% /mnt/wslg/doc
C:\ 3.8T 300G 3.5T 8% /mnt/c
G:\ 15G 6.5G 8.6G 44% /mnt/g
snapfuse 75M 75M 0 100% /snap/core22/1033
snapfuse 128K 128K 0 100% /snap/bare/5
snapfuse 74M 74M 0 100% /snap/core22/864
snapfuse 92M 92M 0 100% /snap/gtk-common-themes/1535
snapfuse 41M 41M 0 100% /snap/snapd/20290
snapfuse 41M 41M 0 100% /snap/snapd/20671
snapfuse 132M 132M 0 100% /snap/ubuntu-desktop-installer/1276
snapfuse 131M 131M 0 100% /snap/ubuntu-desktop-installer/1280
/dev/loop0 255M 51M 205M 20% /mnt/image_boot
/dev/sdd1 120M 0 120M 0% /mnt/sdcard
Copy first image partition files onto microSD card
Now we should be able to copy the files from first partition of the image onto the microSD card:
sudo rsync -a --info=progress2 /mnt/image_boot/ /mnt/sdcard/
In the end you should see the 100% progress, like this:
52,531,459 100% 131.10MB/s 0:00:00 (xfr#328, to-chk=0/330)
Mount second partition
To be able to mount the second partition, the first one (mounted earlier) shall be unmounted:
sudo umount /dev/loop1
Now we can mount second image partition to /mnt/image_data
folder (pretty much the same way as we mounted the first partition):
sudo mount -t ext4 -o loop,offset=$((532480*512)) /tmp/2023-12-05-raspios-bullseye-armhf.img /mnt/image_data/
Check the real size of the partition, used by files:
df -h
You should see something like:
Filesystem Size Used Avail Use% Mounted on
none 3.9G 4.0K 3.9G 1% /mnt/wsl
none 3.8T 300G 3.5T 8% /usr/lib/wsl/drivers
/dev/sdc 1007G 19G 938G 2% /
none 3.9G 92K 3.9G 1% /mnt/wslg
none 3.9G 0 3.9G 0% /usr/lib/wsl/lib
rootfs 3.9G 2.1M 3.9G 1% /init
none 3.9G 864K 3.9G 1% /run
none 3.9G 0 3.9G 0% /run/lock
none 3.9G 0 3.9G 0% /run/shm
tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup
none 3.9G 76K 3.9G 1% /mnt/wslg/versions.txt
none 3.9G 76K 3.9G 1% /mnt/wslg/doc
C:\ 3.8T 300G 3.5T 8% /mnt/c
G:\ 15G 6.5G 8.6G 44% /mnt/g
snapfuse 75M 75M 0 100% /snap/core22/1033
snapfuse 128K 128K 0 100% /snap/bare/5
snapfuse 74M 74M 0 100% /snap/core22/864
snapfuse 92M 92M 0 100% /snap/gtk-common-themes/1535
snapfuse 41M 41M 0 100% /snap/snapd/20290
snapfuse 41M 41M 0 100% /snap/snapd/20671
snapfuse 132M 132M 0 100% /snap/ubuntu-desktop-installer/1276
snapfuse 131M 131M 0 100% /snap/ubuntu-desktop-installer/1280
/dev/sdd1 120M 51M 70M 43% /mnt/sdcard
/dev/loop0 3.7G 3.1G 384M 90% /mnt/image_data
Look at /dev/loop0
, which is mounted to /mnt/image_data
, as you can see, the used space is 3.1G from 3.7G of partition size, so we need at least 4Gb USB flash drive.
Attach USB flash drive
I will detach the microSD card since I have only one available USB port in my laptop, so first I have to unmount it in WSL:
sudo umount /dev/sdd1
Then detach it in Windows:
usbipd detach -b 1-1
So it should disappear from the list of lsusb
and ls -al /dev/sd*
.
Now insert USB flash drive in one of the physical port of your PC/laptop (Windows) and attach it to WSL (as described here), and check whether it is appeared in WSL similarly as for microSD card.
Format USB flash drive
USB flash drive needs to be properly formatted with the right partition tables and filesystem. The partition table should be 83
Linux
, for this we will use fdisk
utility (my USB flash drive recognized as /dev/sdd
, same as microSD card was):
sudo fdisk /dev/sdd
Do the same steps as for microSD card formatting, except the step with changing the partition type, you don’t have to change it, since by default it will be already 83 Linux
.
If for some reason you were not able to delete some partition in fdisk
, you can do the following trick: exit from fdisk
(type q
), format the disk typing sudo mkfs -t ext4 /dev/sdd
(without the partition number), it will kill all partitions on the disk and format it to ext4
, and after that you should be able to run fdisk
again and be able to do anything you need with it.
Check that formatting went well by typing sudo fdisk -l /dev/sdd
, you should see something like:
Disk /dev/sdd: 14.44 GiB, 15502147584 bytes, 30277632 sectors
Disk model: Storage Device
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xbd589f0b
Device Boot Start End Sectors Size Id Type
/dev/sdd1 2048 30277631 30275584 14.4G 83 Linux
We need PARTUUID
of just created partition for later use (in /etc/fstab
and cmdline.txt
), run sudo blkid /dev/sdd1
and write it down somewhere:
/dev/sdd1: UUID="fbb4fa1c-ac4a-47ad-8618-8be797981605" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="bd589f0b-01"
Format just created USB flash drive partition (/dev/sdd1
) to ext4
filesystem:
sudo mkfs -t ext4 /dev/sdd1
Mount USB flash drive
Mount USB flash drive to /mnt/usbdrive
folder:
sudo mount /dev/sdd1 /mnt/usbdrive
Copy second partition files onto USB flash drive
Now we should be able to copy the files from second partition of the image onto the USB flash drive:
sudo rsync -a --info=progress2 /mnt/image_data/ /mnt/usbdrive/
Be patient, this may take up to 1 hour, depends on your USB flash drive write speed and Raspberry Pi OS image size you’ve chosen. Not days though 🙂 .
Edit /etc/fstab on USB flash drive
Since we changed a bit a boot process and its device list, /etc/fstab
needs to be changed as well. Once all the files are copied onto USB flash drive, edit the /etc/fstab
file.
sudo nano /mnt/usbdrive/etc/fstab
As the device source (left part, the proc
column) you should use PARTUUID=*
. For PARTUUID
value use the value identified by the blkid
command (see above), the first one from the microSD card and the second one for the USB flash drive. So your /etc/fstab
should look like:
proc /proc proc defaults 0 0
PARTUUID=f749f5de-01 /boot vfat defaults 0 2
PARTUUID=bd589f0b-01 / ext4 defaults,noatime 0 1
and then press Ctrl+X
, Shift+Y
and Enter
to save the changes to the file.
In earlier versions of the linux distros you could use /dev/mmcblk0p1
and /dev/sda1
, so your /etc/fstab
will look like:
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/sda1 / ext4 defaults,noatime 0 1
Edit cmdline.txt on microSD card
The system will start booting from microSD card, boot partition of which is recognized as /dev/mmcblk0p1
device (or PARTUUID=f749f5de-01
) in Raspberry Pi, then the system will read the instructions from cmdline.txt
file and continue loading the system files from the device indicated in the root
parameter.
Since the second image partition files are written onto the USB flash drive (so it won’t be a microSD card anymore), we need to change the root
parameter in cmdline.txt
on microSD card accordingly.
Unmount USB flash drive, detach it in Windows, insert microSD card in one of the physical PC/laptop port (if not inserted yet), attach it in Windows, mount it to /mnt/sdcard
in WSL and change the value of the root
parameter to PARTUUID=bd589f0b-01
(in earlier linux distros you could also use /dev/sda1
format if you like, however it is considered less reliable in the latest versions of linux distros), so it will look like (it should still be one line):
console=serial0,115200 console=tty1 root=PARTUUID=bd589f0b-01 rootfstype=ext4 fsck.repair=yes rootwait quiet init=/usr/lib/raspberrypi-sys-mods/firstboot splash plymouth.ignore-serial-consoles
or (for earlier linux distros):
console=serial0,115200 console=tty1 root=/dev/sda1 rootfstype=ext4 fsck.repair=yes rootwait quiet init=/usr/lib/raspberrypi-sys-mods/firstboot splash plymouth.ignore-serial-consoles
and then press Ctrl+X
, Shift+Y
and Enter
to save the changes to the file.
Now you can unmount the SD card:
sudo umount /dev/sdd1
Conclusion
This is basically it. Now you should be able to insert the SD card into the micro SD slot of Raspberry Pi, USB flash drive into the USB port and start your Raspberry Pi.
Don’t forget to connect the display and at least keyboard to your Raspberry Pi on the first start.
Once you set the network settings (and enabled SSH) you should be able to connect to your Raspberry Pi via SSH
, make sure that the Raspberry Pi is connected to your network.
Leave a Reply
You must be logged in to post a comment.