nand.sh 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #!/bin/sh
  2. # Copyright (C) 2014 OpenWrt.org
  3. #
  4. . /lib/functions.sh
  5. # 'kernel' partition on NAND contains the kernel
  6. CI_KERNPART="${CI_KERNPART:-kernel}"
  7. # 'ubi' partition on NAND contains UBI
  8. CI_UBIPART="${CI_UBIPART:-ubi}"
  9. # 'rootfs' partition on NAND contains the rootfs
  10. CI_ROOTPART="${CI_ROOTPART:-rootfs}"
  11. ubi_mknod() {
  12. local dir="$1"
  13. local dev="/dev/$(basename $dir)"
  14. [ -e "$dev" ] && return 0
  15. local devid="$(cat $dir/dev)"
  16. local major="${devid%%:*}"
  17. local minor="${devid##*:}"
  18. mknod "$dev" c $major $minor
  19. }
  20. nand_find_volume() {
  21. local ubidevdir ubivoldir
  22. ubidevdir="/sys/devices/virtual/ubi/$1"
  23. [ ! -d "$ubidevdir" ] && return 1
  24. for ubivoldir in $ubidevdir/${1}_*; do
  25. [ ! -d "$ubivoldir" ] && continue
  26. if [ "$( cat $ubivoldir/name )" = "$2" ]; then
  27. basename $ubivoldir
  28. ubi_mknod "$ubivoldir"
  29. return 0
  30. fi
  31. done
  32. }
  33. nand_find_ubi() {
  34. local ubidevdir ubidev mtdnum
  35. mtdnum="$( find_mtd_index $1 )"
  36. [ ! "$mtdnum" ] && return 1
  37. for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
  38. [ ! -d "$ubidevdir" ] && continue
  39. cmtdnum="$( cat $ubidevdir/mtd_num )"
  40. [ ! "$mtdnum" ] && continue
  41. if [ "$mtdnum" = "$cmtdnum" ]; then
  42. ubidev=$( basename $ubidevdir )
  43. ubi_mknod "$ubidevdir"
  44. echo $ubidev
  45. return 0
  46. fi
  47. done
  48. }
  49. nand_get_magic_long() {
  50. dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
  51. }
  52. get_magic_long_tar() {
  53. ( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
  54. }
  55. identify_magic() {
  56. local magic=$1
  57. case "$magic" in
  58. "55424923")
  59. echo "ubi"
  60. ;;
  61. "31181006")
  62. echo "ubifs"
  63. ;;
  64. "68737173")
  65. echo "squashfs"
  66. ;;
  67. "d00dfeed")
  68. echo "fit"
  69. ;;
  70. "4349"*)
  71. echo "combined"
  72. ;;
  73. *)
  74. echo "unknown $magic"
  75. ;;
  76. esac
  77. }
  78. identify() {
  79. identify_magic $(nand_get_magic_long "$1" "${2:-0}")
  80. }
  81. identify_tar() {
  82. identify_magic $(get_magic_long_tar "$1" "$2")
  83. }
  84. nand_restore_config() {
  85. sync
  86. local ubidev=$( nand_find_ubi $CI_UBIPART )
  87. local ubivol="$( nand_find_volume $ubidev rootfs_data )"
  88. [ ! "$ubivol" ] &&
  89. ubivol="$( nand_find_volume $ubidev $CI_ROOTPART )"
  90. mkdir /tmp/new_root
  91. if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
  92. echo "mounting ubifs $ubivol failed"
  93. rmdir /tmp/new_root
  94. return 1
  95. fi
  96. mv "$1" "/tmp/new_root/sysupgrade.tgz"
  97. umount /tmp/new_root
  98. sync
  99. rmdir /tmp/new_root
  100. }
  101. nand_upgrade_prepare_ubi() {
  102. local rootfs_length="$1"
  103. local rootfs_type="$2"
  104. local has_kernel="${3:-0}"
  105. local has_env="${4:-0}"
  106. local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
  107. if [ ! "$mtdnum" ]; then
  108. echo "cannot find ubi mtd partition $CI_UBIPART"
  109. return 1
  110. fi
  111. local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  112. if [ ! "$ubidev" ]; then
  113. ubiattach -m "$mtdnum"
  114. sync
  115. ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  116. fi
  117. if [ ! "$ubidev" ]; then
  118. ubiformat /dev/mtd$mtdnum -y
  119. ubiattach -m "$mtdnum"
  120. sync
  121. ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  122. [ "$has_env" -gt 0 ] && {
  123. ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
  124. ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
  125. }
  126. fi
  127. local kern_ubivol="$( nand_find_volume $ubidev $CI_KERNPART )"
  128. local root_ubivol="$( nand_find_volume $ubidev $CI_ROOTPART )"
  129. local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
  130. # remove ubiblock device of rootfs
  131. local root_ubiblk="ubiblock${root_ubivol:3}"
  132. if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then
  133. echo "removing $root_ubiblk"
  134. if ! ubiblock -r /dev/$root_ubivol; then
  135. echo "cannot remove $root_ubiblk"
  136. return 1;
  137. fi
  138. fi
  139. # kill volumes
  140. [ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N $CI_KERNPART || true
  141. [ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N $CI_ROOTPART || true
  142. [ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
  143. # update kernel
  144. if [ "$has_kernel" = "1" ]; then
  145. if ! ubimkvol /dev/$ubidev -N $CI_KERNPART -s $kernel_length; then
  146. echo "cannot create kernel volume"
  147. return 1;
  148. fi
  149. fi
  150. # update rootfs
  151. local root_size_param
  152. if [ "$rootfs_type" = "ubifs" ]; then
  153. root_size_param="-m"
  154. else
  155. root_size_param="-s $rootfs_length"
  156. fi
  157. if ! ubimkvol /dev/$ubidev -N $CI_ROOTPART $root_size_param; then
  158. echo "cannot create rootfs volume"
  159. return 1;
  160. fi
  161. # create rootfs_data for non-ubifs rootfs
  162. if [ "$rootfs_type" != "ubifs" ]; then
  163. if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
  164. echo "cannot initialize rootfs_data volume"
  165. return 1
  166. fi
  167. fi
  168. sync
  169. return 0
  170. }
  171. nand_do_upgrade_success() {
  172. local conf_tar="/tmp/sysupgrade.tgz"
  173. sync
  174. [ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
  175. echo "sysupgrade successful"
  176. umount -a
  177. reboot -f
  178. }
  179. # Flash the UBI image to MTD partition
  180. nand_upgrade_ubinized() {
  181. local ubi_file="$1"
  182. local mtdnum="$(find_mtd_index "$CI_UBIPART")"
  183. [ ! "$mtdnum" ] && {
  184. CI_UBIPART="rootfs"
  185. mtdnum="$(find_mtd_index "$CI_UBIPART")"
  186. }
  187. if [ ! "$mtdnum" ]; then
  188. echo "cannot find mtd device $CI_UBIPART"
  189. umount -a
  190. reboot -f
  191. fi
  192. local mtddev="/dev/mtd${mtdnum}"
  193. ubidetach -p "${mtddev}" || true
  194. sync
  195. ubiformat "${mtddev}" -y -f "${ubi_file}"
  196. ubiattach -p "${mtddev}"
  197. nand_do_upgrade_success
  198. }
  199. # Write the UBIFS image to UBI volume
  200. nand_upgrade_ubifs() {
  201. local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
  202. nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
  203. local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  204. local root_ubivol="$(nand_find_volume $ubidev $CI_ROOTPART)"
  205. ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
  206. nand_do_upgrade_success
  207. }
  208. nand_upgrade_tar() {
  209. local tar_file="$1"
  210. local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
  211. local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
  212. board_dir=${board_dir%/}
  213. local kernel_length=`(tar xf $tar_file ${board_dir}/kernel -O | wc -c) 2> /dev/null`
  214. local rootfs_length=`(tar xf $tar_file ${board_dir}/root -O | wc -c) 2> /dev/null`
  215. local rootfs_type="$(identify_tar "$tar_file" ${board_dir}/root)"
  216. local has_kernel=1
  217. local has_env=0
  218. [ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
  219. tar xf $tar_file ${board_dir}/kernel -O | mtd write - $CI_KERNPART
  220. }
  221. [ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
  222. nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
  223. local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  224. [ "$has_kernel" = "1" ] && {
  225. local kern_ubivol="$(nand_find_volume $ubidev $CI_KERNPART)"
  226. tar xf $tar_file ${board_dir}/kernel -O | \
  227. ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
  228. }
  229. local root_ubivol="$(nand_find_volume $ubidev $CI_ROOTPART)"
  230. tar xf $tar_file ${board_dir}/root -O | \
  231. ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
  232. nand_do_upgrade_success
  233. }
  234. # Recognize type of passed file and start the upgrade process
  235. nand_do_upgrade() {
  236. if [ -n "$IS_PRE_UPGRADE" ]; then
  237. # Previously, nand_do_upgrade was called from the platform_pre_upgrade
  238. # hook; this piece of code handles scripts that haven't been
  239. # updated. All scripts should gradually move to call nand_do_upgrade
  240. # from platform_do_upgrade instead.
  241. export do_upgrade="nand_do_upgrade '$1'"
  242. return
  243. fi
  244. local file_type=$(identify $1)
  245. if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
  246. platform_nand_pre_upgrade "$1"
  247. fi
  248. [ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
  249. case "$file_type" in
  250. "ubi") nand_upgrade_ubinized $1;;
  251. "ubifs") nand_upgrade_ubifs $1;;
  252. *) nand_upgrade_tar $1;;
  253. esac
  254. }
  255. # Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
  256. # 3 types of files:
  257. # 1) UBI - should contain an ubinized image, header is checked for the proper
  258. # MAGIC
  259. # 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
  260. # header is checked for the proper MAGIC
  261. # 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
  262. # "CONTROL" file (at this point its content isn't verified)
  263. #
  264. # You usually want to call this function in platform_check_image.
  265. #
  266. # $(1): board name, used in case of passing TAR file
  267. # $(2): file to be checked
  268. nand_do_platform_check() {
  269. local board_name="$1"
  270. local tar_file="$2"
  271. local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
  272. local file_type="$(identify $2)"
  273. [ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && {
  274. echo "Invalid sysupgrade file."
  275. return 1
  276. }
  277. return 0
  278. }