nand.sh 7.7 KB

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