build-efi.sh 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0+
  3. #
  4. # Script to build an EFI thing suitable for booting with QEMU, possibly running
  5. # it also.
  6. # This just an example. It assumes that
  7. # - you build U-Boot in ${ubdir}/<name> where <name> is the U-Boot board config
  8. # - /mnt/x is a directory used for mounting
  9. # - you have access to the 'pure UEFI' builds for QEMU
  10. #
  11. # UEFI binaries for QEMU used for testing this script:
  12. #
  13. # OVMF-pure-efi.i386.fd at
  14. # https://drive.google.com/file/d/1jWzOAZfQqMmS2_dAK2G518GhIgj9r2RY/view?usp=sharing
  15. # OVMF-pure-efi.x64.fd at
  16. # https://drive.google.com/file/d/1c39YI9QtpByGQ4V0UNNQtGqttEzS-eFV/view?usp=sharing
  17. bzimage_fname=/tmp/kernel/arch/x86/boot/bzImage
  18. set -e
  19. usage() {
  20. echo "Usage: $0 [-a | -p] [other opts]" 1>&2
  21. echo 1>&2
  22. echo " -a - Package up the app" 1>&2
  23. echo " -k - Add a kernel" 1>&2
  24. echo " -o - Use old EFI app build (before 32/64 split)" 1>&2
  25. echo " -p - Package up the payload" 1>&2
  26. echo " -P - Create a partition table" 1>&2
  27. echo " -r - Run QEMU with the image" 1>&2
  28. echo " -s - Run QEMU with serial only (no display)" 1>&2
  29. echo " -w - Use word version (32-bit)" 1>&2
  30. exit 1
  31. }
  32. # 32- or 64-bit EFI
  33. bitness=64
  34. # app or payload ?
  35. type=app
  36. # create a partition table and put the filesystem in that (otherwise put the
  37. # filesystem in the raw device)
  38. part=
  39. # run the image with QEMU
  40. run=
  41. # run QEMU without a display (U-Boot must be set to stdout=serial)
  42. serial=
  43. # before the 32/64 split of the app
  44. old=
  45. # package up a kernel as well
  46. kernel=
  47. # Set ubdir to the build directory where you build U-Boot out-of-tree
  48. # We avoid in-tree build because it gets confusing trying different builds
  49. ubdir=/tmp/b/
  50. while getopts "akopPrsw" opt; do
  51. case "${opt}" in
  52. a)
  53. type=app
  54. ;;
  55. p)
  56. type=payload
  57. ;;
  58. k)
  59. kernel=1
  60. ;;
  61. r)
  62. run=1
  63. ;;
  64. s)
  65. serial=1
  66. ;;
  67. w)
  68. bitness=32
  69. ;;
  70. o)
  71. old=1
  72. ;;
  73. P)
  74. part=1
  75. ;;
  76. *)
  77. usage
  78. ;;
  79. esac
  80. done
  81. run_qemu() {
  82. extra=
  83. if [[ "${bitness}" = "64" ]]; then
  84. qemu=qemu-system-x86_64
  85. bios=OVMF-pure-efi.x64.fd
  86. else
  87. qemu=qemu-system-i386
  88. bios=OVMF-pure-efi.i386.fd
  89. fi
  90. if [[ -n "${serial}" ]]; then
  91. extra="-display none -serial mon:stdio"
  92. else
  93. extra="-serial mon:stdio"
  94. fi
  95. echo "Running ${qemu}"
  96. # Use 512MB since U-Boot EFI likes to have 256MB to play with
  97. "${qemu}" -bios "${bios}" \
  98. -m 512 \
  99. -drive id=disk,file="${IMG}",if=none,format=raw \
  100. -nic none -device ahci,id=ahci \
  101. -device ide-hd,drive=disk,bus=ahci.0 ${extra}
  102. }
  103. setup_files() {
  104. echo "Packaging ${BUILD}"
  105. mkdir -p $TMP
  106. cat >$TMP/startup.nsh <<EOF
  107. fs0:u-boot-${type}.efi
  108. EOF
  109. sudo cp ${ubdir}/${BUILD}/u-boot-${type}.efi $TMP
  110. # Can copy in other files here:
  111. #sudo cp ${ubdir}/$BUILD/image.bin $TMP/chromeos.rom
  112. #sudo cp /boot/vmlinuz-5.4.0-77-generic $TMP/vmlinuz
  113. }
  114. # Copy files into the filesystem
  115. copy_files() {
  116. sudo cp $TMP/* $MNT
  117. if [[ -n "${kernel}" ]]; then
  118. sudo cp ${bzimage_fname} $MNT/vmlinuz
  119. fi
  120. }
  121. # Create a filesystem on a raw device and copy in the files
  122. setup_raw() {
  123. mkfs.vfat "${IMG}" >/dev/null
  124. sudo mount -o loop "${IMG}" $MNT
  125. copy_files
  126. sudo umount $MNT
  127. }
  128. # Create a partition table and put the filesystem in the first partition
  129. # then copy in the files
  130. setup_part() {
  131. # Create a gpt partition table with one partition
  132. parted "${IMG}" mklabel gpt 2>/dev/null
  133. # This doesn't work correctly. It creates:
  134. # Number Start End Size File system Name Flags
  135. # 1 1049kB 24.1MB 23.1MB boot msftdata
  136. # Odd if the same is entered interactively it does set the FS type
  137. parted -s -a optimal -- "${IMG}" mkpart boot fat32 1MiB 23MiB
  138. # Map this partition to a loop device
  139. kp="$(sudo kpartx -av ${IMG})"
  140. read boot_dev<<<$(grep -o 'loop.*p.' <<< "${kp}")
  141. test "${boot_dev}"
  142. dev="/dev/mapper/${boot_dev}"
  143. mkfs.vfat "${dev}" >/dev/null
  144. sudo mount -o loop "${dev}" $MNT
  145. copy_files
  146. # Sync here since this makes kpartx more likely to work the first time
  147. sync
  148. sudo umount $MNT
  149. # For some reason this needs a sleep or it sometimes fails, if it was
  150. # run recently (in the last few seconds)
  151. if ! sudo kpartx -d "${IMG}" > /dev/null; then
  152. sleep .5
  153. sudo kpartx -d "${IMG}" > /dev/null || \
  154. echo "Failed to remove ${boot_dev}, use: sudo kpartx -d ${IMG}"
  155. fi
  156. }
  157. TMP="/tmp/efi${bitness}${type}"
  158. MNT=/mnt/x
  159. BUILD="efi-x86_${type}${bitness}"
  160. IMG=try.img
  161. if [[ -n "${old}" && "${bitness}" = "32" ]]; then
  162. BUILD="efi-x86_${type}"
  163. fi
  164. setup_files
  165. qemu-img create "${IMG}" 24M >/dev/null
  166. if [[ -n "${part}" ]]; then
  167. setup_part
  168. else
  169. setup_raw
  170. fi
  171. if [[ -n "${run}" ]]; then
  172. run_qemu
  173. fi