grub-helper 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #!/usr/bin/env bash
  2. # Copyright (C) 2017,2018 Andrew Robbins <contact@andrewrobbins.info>
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ARCH='arch'
  17. CONFIG='config'
  18. FONTS='fonts'
  19. FONT_FILE='font-file'
  20. FONT_PROJECT='font-project'
  21. FORMAT='format'
  22. MODMIN='modules-minimal'
  23. PLATFORM='platform'
  24. PREFIX='prefix'
  25. SIZE='size'
  26. grub_arch() {
  27. project_file_contents "$project" "$CONFIGS" "$ARCH" "$@"
  28. }
  29. grub_font_file() {
  30. project_file_contents "$project" "$CONFIGS" "$FONT_FILE" "$@"
  31. }
  32. grub_font_project() {
  33. project_file_contents "$project" "$CONFIGS" "$FONT_PROJECT" "$@"
  34. }
  35. grub_format() {
  36. project_file_contents "$project" "$CONFIGS" "$FORMAT" "$@"
  37. }
  38. grub_platform() {
  39. project_file_contents "$project" "$CONFIGS" "$PLATFORM" "$@"
  40. }
  41. grub_prefix() {
  42. project_file_contents "$project" "$CONFIGS" "$PREFIX" "$@"
  43. }
  44. grub_size() {
  45. project_file_contents "$project" "$CONFIGS" "$SIZE" "$@"
  46. }
  47. grub_config_path() {
  48. project_file_path "$project" "$CONFIGS" "$CONFIG" "$@"
  49. }
  50. grub_modmin_path() {
  51. project_file_path "$project" "$CONFIGS" "$MODMIN" "$@"
  52. }
  53. grub_bo_search() {
  54. local pattern="$1"
  55. local comparand="$2"
  56. grep -Fbof <(grub_bo_dump "$pattern") <(grub_bo_dump "$comparand") | cut -d: -f1
  57. }
  58. grub_bo_dump() {
  59. local file="$1"
  60. od -An -t x1 -w16 -v "$file" | paste -sd '' | tr -d ' '
  61. }
  62. grub_bo() {
  63. local pattern="$1"
  64. local comparand="$2"
  65. local nibble_offset="$(grub_bo_search "$pattern" "$comparand")"
  66. if [[ -n "$nibble_offset" ]]; then
  67. printf '0x%X\n' $((nibble_offset / 2))
  68. else
  69. return 1
  70. fi
  71. }
  72. grub_blocklist_format() {
  73. local blocklist="$1"
  74. local byte
  75. while read -N 2 byte; do
  76. printf '%s' "\\x$byte"
  77. done <<< "$blocklist"
  78. }
  79. grub_blocklist_generate() {
  80. local -i byte_offset="$1"
  81. printf '%04x' $((byte_offset / 512)) | tac -rs ..
  82. }
  83. grub_copy_modules() {
  84. local grub_module_dir="$sources_path/grub-core"
  85. local keep_dir="$build_path/$(grub_format "$target" "$@")"
  86. mkdir -p "$keep_dir"
  87. cp -a "$grub_module_dir"/*.@(mod|lst) "$keep_dir"
  88. }
  89. grub_build_font() {
  90. local font_file="$(grub_font_file "$FONTS" "$@")"
  91. local font_project="$(grub_font_project "$FONTS" "$@")"
  92. local font_build_dir="$root/$BUILD/$font_project"
  93. local grub_mkfont="$sources_path/grub-mkfont"
  94. mkdir -p "$build_path/$FONTS"
  95. "$grub_mkfont" --output="$build_path/$FONTS/${font_file%.*}.pf2" \
  96. "$font_build_dir/$font_file"
  97. }
  98. grub_build_utils() {
  99. (
  100. local arch="$(grub_arch "$target" "$@")"
  101. local platform="$(grub_platform "$target" "$@")"
  102. cd "$sources_path" || return
  103. if git_project_check "$repository"; then
  104. ./autogen.sh
  105. fi
  106. ./configure --target="$arch" --with-platform="$platform"
  107. make -j"$TASKS"
  108. )
  109. }
  110. grub_build_layout() {
  111. local raw_layout="${1##*/}"
  112. local raw_layout_path="$1"
  113. local keymap_out_path="$build_path/keymaps"
  114. local grub_mklayout="$sources_path/grub-mklayout"
  115. local grub_kbd_layout="$keymap_out_path/$raw_layout.gkb"
  116. if ! [[ -e "$keymap_out_path" ]]; then
  117. mkdir -p "$keymap_out_path"
  118. elif ! [[ -d "$keymap_out_path" ]]; then
  119. printf '\n%s\n' "Error: File $keymap_out_path is not a directory" 1>&2
  120. return 1
  121. fi
  122. "$grub_mklayout" --output="$grub_kbd_layout" --input="$raw_layout_path"
  123. }
  124. grub_build_bootable_image() {
  125. local arch="$(grub_arch "$target" "$@")"
  126. local format="$(grub_format "$target" "$@")"
  127. local prefix="$(grub_prefix "$target" "$@")"
  128. local config_path="$(grub_config_path "$target" "$@")"
  129. local modmin_path="$(grub_modmin_path "$target" "$@")"
  130. local -a modmin=($(< "$modmin_path"))
  131. local grub_mkimage="$sources_path/grub-mkimage"
  132. local grub_module_dir="$sources_path/grub-core"
  133. local grub_bootimg="$grub_module_dir/boot.img"
  134. local grub_coreimg="$build_path/core.img"
  135. "$grub_mkimage" \
  136. --config="$config_path" \
  137. --directory="$grub_module_dir" \
  138. --output="$grub_coreimg" \
  139. --format="$format" \
  140. --prefix="$prefix" \
  141. "${modmin[@]}"
  142. cp -a "$grub_bootimg" "$build_path"
  143. }
  144. grub_build_floppy_image() {
  145. local floppyimg="$build_path/floppy.img"
  146. local format="$(grub_format "$target" "$@")"
  147. local grub_module_dir="$sources_path/grub-core"
  148. local size="$(grub_size "$target" "$@")"
  149. local -a modules
  150. for module in "$grub_module_dir"/*.mod; do
  151. modules+=($module)
  152. done
  153. if ! grub_build_bootable_image "$@"; then
  154. printf '\n%s\n\n' "Error: Failed to build a GRUB image" 1>&2
  155. return 1
  156. fi
  157. # Pre-allocate a floppy-sized image with a FAT12 filesystem
  158. # SeaBIOS requires floppy images to have a "correct" size
  159. if ! [[ -e "$floppyimg" ]]; then
  160. mkfs.fat -C -D 0x00 -F 12 -M 0xF9 -n SEAGRUB --invariant "$floppyimg" "$size"
  161. else
  162. printf '\n%s\n\n' "Error: File $floppyimg already exists!" 1>&2
  163. return 1
  164. fi
  165. grub_floppy_image_mmd "$floppyimg" /boot /boot/grub "/boot/grub/$format"
  166. grub_floppy_image_mcopy "$floppyimg" "/boot/grub/$format" "${modules[@]}"
  167. grub_floppy_image_make_bootable "$floppyimg"
  168. }
  169. grub_build_standalone_image() {
  170. local arch="$(grub_arch "$target" "$@")"
  171. local format="$(grub_format "$target" "$@")"
  172. local prefix="$(grub_prefix "$target" "$@")"
  173. local config_path="$(grub_config_path "$target" "$@")"
  174. local modmin_path="$(grub_modmin_path "$target" "$@")"
  175. local -a modmin=($(< "$modmin_path"))
  176. local grubimg="$build_path/grub2"
  177. local grub_mkimage="$sources_path/grub-mkimage"
  178. local grub_mkstandalone="$sources_path/grub-mkstandalone"
  179. local grub_module_dir="$sources_path/grub-core"
  180. "$grub_mkstandalone" \
  181. --grub-mkimage="$grub_mkimage" \
  182. --fonts='' \
  183. --themes='' \
  184. --locales='' \
  185. --install-modules="${modmin[*]}" \
  186. --directory="$grub_module_dir" \
  187. --format="$format" \
  188. --output="$grubimg" \
  189. /boot/grub/grub.cfg="$config_path"
  190. }
  191. grub_floppy_image_mmd() {
  192. local img="$1"
  193. local -a dirs=("${@:2}")
  194. if [[ -n "$img" ]]; then
  195. mmd -i "$img" "${dirs[@]}"
  196. else
  197. return 1
  198. fi
  199. }
  200. grub_floppy_image_mcopy() {
  201. local img="$1"
  202. local target="$2"
  203. local -a files=("${@:3}")
  204. if [[ -z "$img" ]]; then
  205. return 1
  206. elif [[ -z "${files[@]}" ]]; then
  207. mcopy -i "$img" -pv "::$target"
  208. else
  209. mcopy -i "$img" -pQv "${files[@]}" "::$target"
  210. fi
  211. }
  212. grub_floppy_image_make_bootable() {
  213. local floppyimg="$1"
  214. local bootimg="$build_path/boot.img"
  215. local coreimg="$build_path/core.img"
  216. local oem_name='\x4C\x49\x42\x52\x45\x20\x20\x20'
  217. # write $floppyimg Bios Parameter Block to $bootimg first
  218. dd if="$floppyimg" of="$bootimg" bs=1 skip=11 seek=11 count=51 conv=notrunc
  219. dd if=<(printf "$oem_name") of="$bootimg" bs=1 seek=3 conv=notrunc
  220. dd if=/dev/zero of="$floppyimg" count=1 conv=notrunc
  221. dd if="$bootimg" of="$floppyimg" conv=notrunc
  222. grub_floppy_image_mcopy "$floppyimg" /boot/grub "$bootimg"
  223. grub_floppy_image_mcopy "$floppyimg" /boot/grub "$coreimg"
  224. grub_floppy_image_update_blocklists "$coreimg" "$floppyimg"
  225. rm -f "$bootimg" "$coreimg"
  226. }
  227. grub_floppy_image_update_blocklists() {
  228. local coreimg="$1"
  229. local floppyimg="$2"
  230. local -i coreimg_offset="$(grub_bo "$coreimg" "$floppyimg")"
  231. local -i coreimg_second_sector_offset=$((coreimg_offset + 0x200))
  232. local -i boot_record_blocklist_offset=0x5C
  233. local -i coreimg_blocklist_offset=$((coreimg_offset + 0x1F4))
  234. # blocklists (little endian) describe the $coreimg_offset in sectors
  235. local boot_record_blocklist="$(grub_blocklist_generate "$coreimg_offset")"
  236. local coreimg_blocklist="$(grub_blocklist_generate "$coreimg_second_sector_offset")"
  237. if [[ $coreimg_offset -gt 0 ]]; then
  238. dd if=<(printf "$(grub_blocklist_format "$boot_record_blocklist")") \
  239. of="$floppyimg" \
  240. bs=1 \
  241. seek="$boot_record_blocklist_offset" \
  242. conv=notrunc
  243. dd if=<(printf "$(grub_blocklist_format "$coreimg_blocklist")") \
  244. of="$floppyimg" \
  245. bs=1 \
  246. seek="$coreimg_blocklist_offset" \
  247. conv=notrunc
  248. else
  249. printf 1>&2 '%s\n' "Error: ${coreimg##*/} offset not found"
  250. return 1
  251. fi
  252. }