genimage.sh 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #!/bin/bash
  2. #
  3. # This file is subject to the terms and conditions of the GNU General Public
  4. # License. See the file "COPYING" in the main directory of this archive
  5. # for more details.
  6. #
  7. # Copyright (C) 2017 by Changbin Du <changbin.du@intel.com>
  8. #
  9. # Adapted from code in arch/x86/boot/Makefile by H. Peter Anvin and others
  10. #
  11. # "make fdimage/fdimage144/fdimage288/hdimage/isoimage"
  12. # script for x86 architecture
  13. #
  14. # Arguments:
  15. # $1 - fdimage format
  16. # $2 - target image file
  17. # $3 - kernel bzImage file
  18. # $4 - mtools configuration file
  19. # $5 - kernel cmdline
  20. # $6+ - initrd image file(s)
  21. #
  22. # This script requires:
  23. # bash
  24. # syslinux
  25. # genisoimage
  26. # mtools (for fdimage* and hdimage)
  27. # edk2/OVMF (for hdimage)
  28. #
  29. # Otherwise try to stick to POSIX shell commands...
  30. #
  31. # Use "make V=1" to debug this script
  32. case "${KBUILD_VERBOSE}" in
  33. *1*)
  34. set -x
  35. ;;
  36. esac
  37. # Exit the top-level shell with an error
  38. topshell=$$
  39. trap 'exit 1' USR1
  40. die() {
  41. echo "" 1>&2
  42. echo " *** $*" 1>&2
  43. echo "" 1>&2
  44. kill -USR1 $topshell
  45. }
  46. # Verify the existence and readability of a file
  47. verify() {
  48. if [ ! -f "$1" -o ! -r "$1" ]; then
  49. die "Missing file: $1"
  50. fi
  51. }
  52. diskfmt="$1"
  53. FIMAGE="$2"
  54. FBZIMAGE="$3"
  55. MTOOLSRC="$4"
  56. KCMDLINE="$5"
  57. shift 5 # Remaining arguments = initrd files
  58. export MTOOLSRC
  59. # common options for dd
  60. dd='dd iflag=fullblock'
  61. # Make sure the files actually exist
  62. verify "$FBZIMAGE"
  63. declare -a FDINITRDS
  64. irdpfx=' initrd='
  65. initrdopts_syslinux=''
  66. initrdopts_efi=''
  67. for f in "$@"; do
  68. if [ -f "$f" -a -r "$f" ]; then
  69. FDINITRDS=("${FDINITRDS[@]}" "$f")
  70. fname="$(basename "$f")"
  71. initrdopts_syslinux="${initrdopts_syslinux}${irdpfx}${fname}"
  72. irdpfx=,
  73. initrdopts_efi="${initrdopts_efi} initrd=${fname}"
  74. fi
  75. done
  76. # Read a $3-byte littleendian unsigned value at offset $2 from file $1
  77. le() {
  78. local n=0
  79. local m=1
  80. for b in $(od -A n -v -j $2 -N $3 -t u1 "$1"); do
  81. n=$((n + b*m))
  82. m=$((m * 256))
  83. done
  84. echo $n
  85. }
  86. # Get the EFI architecture name such that boot{name}.efi is the default
  87. # boot file name. Returns false with no output if the file is not an
  88. # EFI image or otherwise unknown.
  89. efiarch() {
  90. [ -f "$1" ] || return
  91. [ $(le "$1" 0 2) -eq 23117 ] || return # MZ magic
  92. peoffs=$(le "$1" 60 4) # PE header offset
  93. [ $peoffs -ge 64 ] || return
  94. [ $(le "$1" $peoffs 4) -eq 17744 ] || return # PE magic
  95. case $(le "$1" $((peoffs+4+20)) 2) in # PE type
  96. 267) ;; # PE32
  97. 523) ;; # PE32+
  98. *) return 1 ;; # Invalid
  99. esac
  100. [ $(le "$1" $((peoffs+4+20+68)) 2) -eq 10 ] || return # EFI app
  101. case $(le "$1" $((peoffs+4)) 2) in # Machine type
  102. 332) echo i386 ;;
  103. 450) echo arm ;;
  104. 512) echo ia64 ;;
  105. 20530) echo riscv32 ;;
  106. 20580) echo riscv64 ;;
  107. 20776) echo riscv128 ;;
  108. 34404) echo x64 ;;
  109. 43620) echo aa64 ;;
  110. esac
  111. }
  112. # Get the combined sizes in bytes of the files given, counting sparse
  113. # files as full length, and padding each file to cluster size
  114. cluster=16384
  115. filesizes() {
  116. local t=0
  117. local s
  118. for s in $(ls -lnL "$@" 2>/dev/null | awk '/^-/{ print $5; }'); do
  119. t=$((t + ((s+cluster-1)/cluster)*cluster))
  120. done
  121. echo $t
  122. }
  123. # Expand directory names which should be in /usr/share into a list
  124. # of possible alternatives
  125. sharedirs() {
  126. local dir file
  127. for dir in /usr/share /usr/lib64 /usr/lib; do
  128. for file; do
  129. echo "$dir/$file"
  130. echo "$dir/${file^^}"
  131. done
  132. done
  133. }
  134. efidirs() {
  135. local dir file
  136. for dir in /usr/share /boot /usr/lib64 /usr/lib; do
  137. for file; do
  138. echo "$dir/$file"
  139. echo "$dir/${file^^}"
  140. done
  141. done
  142. }
  143. findsyslinux() {
  144. local f="$(find -L $(sharedirs syslinux isolinux) \
  145. -name "$1" -readable -type f -print -quit 2>/dev/null)"
  146. if [ ! -f "$f" ]; then
  147. die "Need a $1 file, please install syslinux/isolinux."
  148. fi
  149. echo "$f"
  150. return 0
  151. }
  152. findovmf() {
  153. local arch="$1"
  154. shift
  155. local -a names=(-false)
  156. local name f
  157. for name; do
  158. names=("${names[@]}" -or -iname "$name")
  159. done
  160. for f in $(find -L $(efidirs edk2 ovmf) \
  161. \( "${names[@]}" \) -readable -type f \
  162. -print 2>/dev/null); do
  163. if [ "$(efiarch "$f")" = "$arch" ]; then
  164. echo "$f"
  165. return 0
  166. fi
  167. done
  168. die "Need a $1 file for $arch, please install EDK2/OVMF."
  169. }
  170. do_mcopy() {
  171. if [ ${#FDINITRDS[@]} -gt 0 ]; then
  172. mcopy "${FDINITRDS[@]}" "$1"
  173. fi
  174. if [ -n "$efishell" ]; then
  175. mmd "$1"EFI "$1"EFI/Boot
  176. mcopy "$efishell" "$1"EFI/Boot/boot${kefiarch}.efi
  177. fi
  178. if [ -n "$kefiarch" ]; then
  179. echo linux "$KCMDLINE$initrdopts_efi" | \
  180. mcopy - "$1"startup.nsh
  181. fi
  182. echo default linux "$KCMDLINE$initrdopts_syslinux" | \
  183. mcopy - "$1"syslinux.cfg
  184. mcopy "$FBZIMAGE" "$1"linux
  185. }
  186. genbzdisk() {
  187. verify "$MTOOLSRC"
  188. mformat -v 'LINUX_BOOT' a:
  189. syslinux "$FIMAGE"
  190. do_mcopy a:
  191. }
  192. genfdimage144() {
  193. verify "$MTOOLSRC"
  194. $dd if=/dev/zero of="$FIMAGE" bs=1024 count=1440 2>/dev/null
  195. mformat -v 'LINUX_BOOT' v:
  196. syslinux "$FIMAGE"
  197. do_mcopy v:
  198. }
  199. genfdimage288() {
  200. verify "$MTOOLSRC"
  201. $dd if=/dev/zero of="$FIMAGE" bs=1024 count=2880 2>/dev/null
  202. mformat -v 'LINUX_BOOT' w:
  203. syslinux "$FIMAGE"
  204. do_mcopy w:
  205. }
  206. genhdimage() {
  207. verify "$MTOOLSRC"
  208. mbr="$(findsyslinux mbr.bin)"
  209. kefiarch="$(efiarch "$FBZIMAGE")"
  210. if [ -n "$kefiarch" ]; then
  211. # The efishell provides command line handling
  212. efishell="$(findovmf $kefiarch shell.efi shell${kefiarch}.efi)"
  213. ptype='-T 0xef' # EFI system partition, no GPT
  214. fi
  215. sizes=$(filesizes "$FBZIMAGE" "${FDINITRDS[@]}" "$efishell")
  216. # Allow 1% + 2 MiB for filesystem and partition table overhead,
  217. # syslinux, and config files; this is probably excessive...
  218. megs=$(((sizes + sizes/100 + 2*1024*1024 - 1)/(1024*1024)))
  219. $dd if=/dev/zero of="$FIMAGE" bs=$((1024*1024)) count=$megs 2>/dev/null
  220. mpartition -I -c -s 32 -h 64 $ptype -b 64 -a p:
  221. $dd if="$mbr" of="$FIMAGE" bs=440 count=1 conv=notrunc 2>/dev/null
  222. mformat -v 'LINUX_BOOT' -s 32 -h 64 -c $((cluster/512)) -t $megs h:
  223. syslinux --offset $((64*512)) "$FIMAGE"
  224. do_mcopy h:
  225. }
  226. geniso() {
  227. tmp_dir="$(dirname "$FIMAGE")/isoimage"
  228. rm -rf "$tmp_dir"
  229. mkdir "$tmp_dir"
  230. isolinux=$(findsyslinux isolinux.bin)
  231. ldlinux=$(findsyslinux ldlinux.c32)
  232. cp "$isolinux" "$ldlinux" "$tmp_dir"
  233. cp "$FBZIMAGE" "$tmp_dir"/linux
  234. echo default linux "$KCMDLINE" > "$tmp_dir"/isolinux.cfg
  235. if [ ${#FDINITRDS[@]} -gt 0 ]; then
  236. cp "${FDINITRDS[@]}" "$tmp_dir"/
  237. fi
  238. genisoimage -J -r -appid 'LINUX_BOOT' -input-charset=utf-8 \
  239. -quiet -o "$FIMAGE" -b isolinux.bin \
  240. -c boot.cat -no-emul-boot -boot-load-size 4 \
  241. -boot-info-table "$tmp_dir"
  242. isohybrid "$FIMAGE" 2>/dev/null || true
  243. rm -rf "$tmp_dir"
  244. }
  245. rm -f "$FIMAGE"
  246. case "$diskfmt" in
  247. bzdisk) genbzdisk;;
  248. fdimage144) genfdimage144;;
  249. fdimage288) genfdimage288;;
  250. hdimage) genhdimage;;
  251. isoimage) geniso;;
  252. *) die "Unknown image format: $diskfmt";;
  253. esac