RPi – Khởi động từ ổ đĩa USB

Mặc định, RPi đã có hai kiểu boot: SD bootUSB boot. Tuy nhiên, USB boot không được cho phép theo mặc định, vì nó cần một ít chuẩn bị trước khi có thể hoạt động.

Mới đây, raspberrypi.org đã đưa ra giải pháp cho phép khởi động từ các ổ đĩa USB. Tuy nhiên, mọi việc không thực sự dễ dàng như thể cài đặt rồi cắm và chạy, nó còn phụ thuộc vào ổ đĩa USB có phù hợp hay không (về nguồn điện, thời gian khởi động của ổ đĩa, tốc độ đọc ghi, firmware…)

Trong bài là script giúp tự động tạo đĩa usb để có thể khởi động từ đó.

Chuẩn bị

  1. RPi
  2. Micro USB đã cài đặt hoàn chỉnh Raspbian
  3. USB flash/SSD

Thực hành

Khởi động RPi với thẻ Micro SD, sau đó cắm USB flash/SSD vào RPi. Nếu chỉ có duy nhất một ổ đĩa USB được cắm vào RPi thì tên ổ đĩa là /dev/sda. Nếu có nhiều ổ USB cắm vào RPi thì dùng lệnh fdisk -l hay mount để nhận biết tên ổ đĩa.

Cú pháp tạo đĩa khởi động là

usbBoot [deviceName] [partitionSize]

deviceName là tên ổ đĩa USB, có thể là /dev/sda hay /dev/sdb…

Script sẽ tạo 2 phân vùng trên ổ đĩa USB, boot (FAT32) dung lượng 64M và OS (ext4) dung lượng là 100% dung lượng còn lại hay partitionSize (tính bằng %, hay M hay G)

Nếu chỉ chạy lệnh usbBoot thì ổ đĩa USB mặc định là /dev/sda và dung lượng OS partition là 100% phần đĩa còn lại

Script chạy trong khoảng thời gian từ 10 phút đến hơn 30 phút, tùy thuộc tốc độ ghi của ổ đĩa USB và kết thúc với dòng nhắc

Chạy lệnh sudo poweroff để tắt RPi...
Tháo Micro SD card và tắt/mở điện để khởi động RPi từ USB...
#!/bin/bash
#--usbBoot script --------------
#--Tác giả: lnt <lnt@ly-le.info>

if [ "$#" -eq 0 ]; then
    usb='/dev/sda'
    siz='100%'
elif [ "$#" -eq 1 ]; then
    if [[ "$1" =~ \d*[%MG] ]]; then
        siz=$1
        usb='/dev/sda'
    else
        usb=$1
        siz='100%'
    fi
elif [ "$#" -eq 2 ]; then
    if [[ "$1" =~ \d*[%MG] ]]; then
        siz=$1
        usb=$2
    else
        usb=$1
        siz=$2
    fi
else
    echo 'Chuẩn bị USB để khởi động RPi'
    echo "usage: $(basename $0) [device] [partition_size]"
    exit
fi
if [ -z "$(sudo blkid $usb)" ]; then
        echo "Vui lòng cắm $usb vào RPi"
        exit
fi
echo 'Cập nhật OS...'
echo
sudo apt-get update
sudo BRANCH=next rpi-update
echo program_usb_boot_mode=1 | sudo tee -a /boot/config.txt &> /dev/null
echo
echo 'Umount các thư mục/phân vùng liên quan...'
for f in $(mount | grep -Po "(?<=${usb}[1-9] on )[^ ]+" | sort -r); do sudo umount $f; done
echo
echo "Phân chia đĩa ${usb}, P1 64M và P2 $siz..."
echo
sudo parted -s ${usb} mklabel msdos
sudo parted -a optimal -s ${usb} mkpart primary fat32 0% 64M
sudo parted -a optimal -s ${usb} mkpart primary ext4 64M $siz
sudo mkfs.vfat -n BOOT -F 32 ${usb}1
sudo mkfs.ext4 -F ${usb}2
[ ! -d /mnt/target ] && sudo mkdir /mnt/target || sudo umount /mnt/target &> /dev/null
sudo mount ${usb}2 /mnt/target
[ ! -d /mnt/target/boot ] && sudo mkdir /mnt/target/boot || sudo umount /mnt/target/boot &> /dev/null
sudo mount ${usb}1 /mnt/target/boot
echo
echo 'Chép boot/OS vào USB. Có thể mất vài mươi phút...'
echo
sudo rsync -avx --delete / /boot /mnt/target
sudo sed -i "s,root=/dev/mmcblk0p2,root=${usb}2," /mnt/target/boot/cmdline.txt
sudo sed -i "s,/dev/mmcblk0p,${usb},g" /mnt/target/etc/fstab
echo
echo 'Tạo lại ssh host keys...'
cd /mnt/target
sudo mount --bind /dev dev
sudo mount --bind /sys sys
sudo mount --bind /proc proc
cat <<EOF | sudo chroot /mnt/target
    rm /etc/ssh/ssh_host*
    dpkg-reconfigure openssh-server
    wait
EOF
sudo umount dev
sudo umount sys
sudo umount proc
cd ~
#sudo umount /mnt/target/boot
#sudo umount /mnt/target
echo 'Chạy lệnh sudo poweroff để tắt RPi'
echo 'Tháo Micro SD card và tắt/mở điện để khởi động RPi từ USB'
#sudo poweroff

Chú thích

  1. Test nhanh
    Sau 3 câu lệnh

    sudo apt-get update
    sudo BRANCH=next rpi-update
    echo program_usb_boot_mode=1 | sudo tee -a /boot/config.txt &> /dev/null

    thì Micro SD card đang dùng trên RPi đã được bổ sung các file cần thiết để khởi động từ USB, chỉ phải đổi tên các partition
    a.   Trong /boot/cmdline.txt, đổi /dev/mmcblk0p2 thành /dev/sda2
    b.   Trong /etc/fstab, đổi /dev/mmcblk0p1 thành /dev/sda1, /dev/mmcblk0p2 thanh /dev/sda2
    Công việc này có thể làm thủ công hay qua 2 câu lệnh sau:

    sudo sed -i "s,root=/dev/mmcblk0p2,root=/dev/sda2," /boot/cmdline.txt
    sudo sed -i "s,/dev/mmcblk0p,/dev/sda,g" /etc/fstab

    Nếu tháo Micro SD card này (tôi đang dùng thẻ Sandisk 16GB hay Samsung 8GB) gắn vào một đầu đoc thẻ và gắn đầu đọc này vào cổng USB của RPi thì có thể khởi động từ USB (đầu đọc thẻ Trancend 3.0)

  2. Không thể khởi động từ USB?
    raspberrypi.org không cam đoan là có thể khởi động được từ mọi ổ đĩa USB, mọi việc đang trong giai đoạn hoàn thiện. Hãy nối RPi với một màn hình, chúng ta sẽ quan sát quá trình khởi động rõ hơn. Nếu do ổ đĩa USB, đèn data trên RPi và đèn USB sẽ không chớp, quá trình khởi động đã dừng ở một bước nào đó, thông thường ở bước kết nối với ổ đĩa USB. Với ổ đĩa GPT, quá trình khởi động sẽ dừng ở màn hình cầu vòng. Hiện nay chỉ khởi động được với ổ đĩa MBR.
  3. Khởi động từ USB chậm hơn từ Micro SD card?
    Một số người dùng cho biết khởi động từ USB chậm, đó là vì RPi phải quét qua từng ổ đĩa USB để tìm file khởi động bootcode.bin, có thể vẫn để thẻ SD card trống không ở RPi để giảm 5 giây tìm kiếm.
  4. Không thể kết nối qua SSH?
    Cắm USB vào một máy Linux (RPi) và chạy đoạn mã tạo lại SSH như sau (copy và dán vào màn hình SSH)
[ ! -d /mnt/target ] && sudo mkdir /mnt/target || sudo umount /mnt/target &> /dev/null
sudo mount /dev/sda2 /mnt/target/
[ ! -d /mnt/target/boot ] && sudo mkdir /mnt/target/boot || sudo umount /mnt/target/boot &> /dev/null
sudo mount /dev/sda1 /mnt/target/boot
cd /mnt/target
sudo mount --bind /dev dev
sudo mount --bind /sys sys
sudo mount --bind /proc proc
sudo chroot /mnt/target
sudo rm /etc/ssh/ssh_host*
sudo dpkg-reconfigure openssh-server
exit
sudo umount dev
sudo umount sys
sudo umount proc
cd ~
sudo umount /mnt/target/boot 
sudo umount /mnt/target

5. Nếu boot từ HDD, có thể phải cấp nguồn cho RPi với công suất lớn hơn 2.5A (5V) vì HDD có thể cần nguồn lớn khi khởi động. Trong khi đó, nhiều SSD có thể khởi động với nguồn 2.5A
Hãy nghĩ ngay đến dòng điện cung cấp cho RPi nếu không thể khởi động.

6. Để thẻ nhớ đầy đủ phân vùng khởi động trong RPi có thể khiến RPi khởi động từ thẻ nhớ, sau đó theo fstab mà mount sda1 thành /boot và sda2 thành OS. Điều này khiến chúng ta dễ hiểu lầm là RPi được boot từ USB, tuy nhiên cả 2 phân vùng của thẻ nhớ đều được mount như phân vùng data. Chẳng có gì xảy ra cho đến khi chúng ta cài đặt gì đó có ghi vào phân vùng boot (như bật I2C), các thay đổi này được ghi vào sda1 thay vì mmcblk0p1 và không có tác dụng.

 

Leave a Comment

Filed under Software

Leave a Reply