3 # Install a bog-standard Debian bootable for ODROID XU3/XU4.
5 # Note: You will need u-boot-exynos >= 2016.05~rc3+dfsg1-1,
6 # which at the time of writing is in experimental (it will
7 # probably eventually hit stretch).
9 # Beware: This will ERASE ALL DATA on the target SD card
13 # Copyright 2016 Steinar H. Gunderson <steinar+odroid@gunderson.no>.
14 # Licensed under the GNU GPL, v2 or (at your option) any later version.
23 while getopts "b:s:t:" opt; do
29 # Sorry, jessie won't work; the kernel doesn't support XU3/XU4.
36 echo "Option -$OPTARG requires an argument."
44 if [ ! -b "$DEVICE" ]; then
45 echo "Usage: $0 [-b BOOTPARTITION_SIZE] [-s SUITE] [-t sd|mmc|mmcbootonly] DEVICE [OTHER_DEBOOTSTRAP_ARGS...]"
46 echo "DEVICE is an SD card device, e.g. /dev/sdb."
51 if [ "$TYPE" != "sd" ] && [ "$TYPE" != "mmc" ] && [ "$TYPE" != "mmcbootonly" ]; then
52 echo "Card type must be 'sd', 'mmc' or 'mmcbootonly'."
59 dpkg --add-architecture armhf
61 apt install git parted dosfstools e2fsprogs binfmt-support qemu qemu-user-static debootstrap zerofree u-boot-exynos:armhf
63 # Get first stages of bootloader. (BL1 must be signed by Hardkernel,
64 # and TZSW comes without source anyway, so we can't build these ourselves)
65 # This is the only part that doesn't strictly need root.
66 if [ ! -d u-boot ]; then
67 git clone https://github.com/hardkernel/u-boot -b odroidxu3-v2012.07
70 if [ "$TYPE" != "mmcbootonly" ]; then
71 # Partition the device.
72 parted ${DEVICE} mklabel msdos
73 parted ${DEVICE} mkpart primary fat32 2MB $(( BOOTPART_MB + 2 ))MB
74 parted ${DEVICE} set 1 boot on
75 parted ${DEVICE} mkpart primary ext2 $(( BOOTPART_MB + 2))MB 100%
77 # Figure out if the partitions are of type ${DEVICE}1 or ${DEVICE}p1.
78 if [ -b "${DEVICE}1" ]; then
80 elif [ -b "${DEVICE}p1" ]; then
81 DEVICE_STEM=${DEVICE}p
83 echo "Could not find device files for partitions of ${DEVICE}. Exiting."
88 # Put the different stages of U-Boot into the right place.
89 # The offsets come from /usr/share/doc/u-boot-exynos/README.odroid.gz.
90 if [ "$TYPE" = "sd" ]; then
91 UBOOT_DEVICE=${DEVICE}
93 elif [ "$TYPE" = "mmcbootonly" ]; then
94 UBOOT_DEVICE=${DEVICE}
97 UBOOT_DEVICE=${DEVICE}boot0
100 dd if=u-boot/sd_fuse/hardkernel_1mb_uboot/bl1.bin.hardkernel of=${UBOOT_DEVICE} seek=${UBOOT_OFFSET} conv=sync
101 dd if=u-boot/sd_fuse/hardkernel_1mb_uboot/bl2.bin.hardkernel.1mb_uboot of=${UBOOT_DEVICE} seek=$((UBOOT_OFFSET + 30)) conv=sync
102 dd if=/usr/lib/u-boot/odroid-xu3/u-boot-dtb.bin of=${UBOOT_DEVICE} seek=$((UBOOT_OFFSET + 62)) conv=sync
103 dd if=u-boot/sd_fuse/hardkernel_1mb_uboot/tzsw.bin.hardkernel of=${UBOOT_DEVICE} seek=$((UBOOT_OFFSET + 2110)) conv=sync
105 # Clear out the environment.
106 dd if=/dev/zero of=${DEVICE} seek=2560 count=32 bs=512 conv=sync
108 if [ "$TYPE" = "mmcbootonly" ]; then
109 # The user asked us to only create the MMC boot partition, so exit.
113 # Create a /boot partition. Strictly speaking, almost everything could be loaded
114 # from ext4, but using FAT is somehow traditional and less likely to be broken
115 # at any given time. (It doesn't support symlinks, though, which breaks flash-kernel,
116 # but we don't use that anyway.)
117 BOOT_PART=${DEVICE_STEM}1
118 mkfs.vfat -F 32 ${BOOT_PART}
120 # Put an LVM on the other partition; it's easier to deal with when expanding
121 # partitions or otherwise moving them around.
122 vgchange -a n odroid || true # Could be left around from a previous copy of the partition.
123 pvcreate -ff ${DEVICE_STEM}2
124 vgcreate odroid ${DEVICE_STEM}2
125 lvcreate -l 100%FREE -n root odroid
127 # And the main filesystem.
128 mkfs.ext4 /dev/odroid/root
130 # Mount the filesystem and debootstrap into it.
131 # isc-dhcp-client is, of course, not necessarily required, especially as
132 # systemd-networkd is included and can do networking just fine, but most people
133 # will probably find it very frustrating to install packages without it.
135 mount /dev/odroid/root /mnt/xu4
137 mount ${BOOT_PART} /mnt/xu4/boot
138 debootstrap --include=linux-image-armmp-lpae,grub-efi-arm,lvm2,isc-dhcp-client --foreign --arch armhf ${SUITE} /mnt/xu4 "$@"
140 # Run the second stage debootstrap under qemu (via binfmt_misc).
141 cp /usr/bin/qemu-arm-static /mnt/xu4/usr/bin/
142 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot /mnt/xu4 /debootstrap/debootstrap --second-stage
143 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot /mnt/xu4 dpkg --configure -a
145 # Enable security updates, and apply any that might be waiting.
146 if [ "$SUITE" != "unstable" ] && [ "$SUITE" != "sid" ]; then
147 echo "deb http://security.debian.org $SUITE/updates main" >> /mnt/xu4/etc/apt/sources.list
148 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot /mnt/xu4 apt update
149 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot /mnt/xu4 apt dist-upgrade
152 # Create an fstab (this is normally done by partconf, in d-i).
153 BOOT_UUID=$( blkid -s UUID -o value ${BOOT_PART} )
154 cat <<EOF > /mnt/xu4/etc/fstab
155 # /etc/fstab: static file system information.
157 # Use 'blkid' to print the universally unique identifier for a
158 # device; this may be used with UUID= as a more robust way to name devices
159 # that works even if disks are added and removed. See fstab(5).
161 # <file system> <mount point> <type> <options> <dump> <pass>
162 /dev/odroid/root / ext4 errors=remount-ro 0 1
163 UUID=${BOOT_UUID} /boot vfat defaults 0 2
167 echo odroid > /mnt/xu4/etc/hostname
169 # Work around Debian bug #824391.
170 echo ttySAC2 >> /mnt/xu4/etc/securetty
172 # Install GRUB, chainloaded from U-Boot via UEFI.
173 mount --bind /dev /mnt/xu4/dev
174 mount --bind /proc /mnt/xu4/proc
175 chroot /mnt/xu4 /usr/sbin/grub-install --removable --target=arm-efi --boot-directory=/boot --efi-directory=/boot
177 # Get the device tree in place (we need it to load GRUB).
178 # flash-kernel can do this (if you also have u-boot-tools installed),
179 # but it also includes its own boot script (which has higher priority than
180 # GRUB) and just seems to lock up.
181 cp $( find /mnt/xu4 -name exynos5422-odroidxu4.dtb ) /mnt/xu4/boot/
183 # update-grub does not add “devicetree” statements for the
184 # each kernel (not that it's copied from /usr/lib without
185 # flash-kernel anyway), so we need to explicitly load it
186 # ourselves. See Debian bug #824399.
187 cat <<EOF > /mnt/xu4/etc/grub.d/25_devicetree
191 # Hack added by mkimage.sh when building the root image,
192 # to work around Debian bug #824399.
193 echo "echo 'Loading device tree ...'"
194 echo "devicetree /exynos5422-odroidxu4.dtb"
196 chmod 0755 /mnt/xu4/etc/grub.d/25_devicetree
198 # Work around Debian bug #823552.
199 sed -i 's/\(GRUB_CMDLINE_LINUX_DEFAULT=".*\)"/\1 loglevel=4"/' /mnt/xu4/etc/default/grub
201 # Now we can create the GRUB boot menu.
202 chroot /mnt/xu4 /usr/sbin/update-grub
204 # Set the root password. (It should be okay to have a dumb one as default,
205 # since there's no ssh by default. Yet, it would be nice to have a way
206 # to ask on first boot, or better yet, invoke debian-installer after boot.)
207 echo root:odroid | chroot /mnt/xu4 /usr/sbin/chpasswd
209 # Zero any unused blocks on /boot, for better packing if we are to compress the
210 # filesystem and publish it somewhere. (See below for the root device.)
211 echo 'Please ignore the following error about full disk.'
212 dd if=/dev/zero of=/mnt/xu4/boot/zerofill bs=1M || true
213 rm -f /mnt/xu4/boot/zerofill
215 # All done, clean up.
216 rm /mnt/xu4/usr/bin/qemu-arm-static
222 # The root file system is ext4, so we can use zerofree, which is
223 # supposedly faster than dd-ing a zero file onto it.
224 zerofree -v /dev/odroid/root