nand.sh 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. # Copyright (C) 2014 OpenWrt.org
  2. #
  3. . /lib/functions.sh
  4. # 'kernel' partition or UBI volume 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' UBI volume 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_remove_ubiblock() {
  101. local ubivol=$1
  102. local ubiblk=ubiblock${ubivol:3}
  103. if [ -e /dev/$ubiblk ]; then
  104. echo "removing $ubiblk"
  105. if ! ubiblock -r /dev/$ubivol; then
  106. echo "cannot remove $ubiblk"
  107. return 1
  108. fi
  109. fi
  110. }
  111. nand_upgrade_prepare_ubi() {
  112. local rootfs_length="$1"
  113. local rootfs_type="$2"
  114. local rootfs_data_max="$(fw_printenv -n rootfs_data_max 2>/dev/null)"
  115. [ -n "$rootfs_data_max" ] && rootfs_data_max=$((rootfs_data_max))
  116. local kernel_length="$3"
  117. local has_env="${4:-0}"
  118. [ -n "$rootfs_length" -o -n "$kernel_length" ] || return 1
  119. local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
  120. if [ ! "$mtdnum" ]; then
  121. echo "cannot find ubi mtd partition $CI_UBIPART"
  122. return 1
  123. fi
  124. local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  125. if [ ! "$ubidev" ]; then
  126. ubiattach -m "$mtdnum"
  127. sync
  128. ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  129. if [ ! "$ubidev" ]; then
  130. ubiformat /dev/mtd$mtdnum -y
  131. ubiattach -m "$mtdnum"
  132. sync
  133. ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  134. if [ ! "$ubidev" ]; then
  135. echo "cannot attach ubi mtd partition $CI_UBIPART"
  136. return 1
  137. fi
  138. if [ "$has_env" -gt 0 ]; then
  139. ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
  140. ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
  141. fi
  142. fi
  143. fi
  144. local kern_ubivol="$( nand_find_volume $ubidev "$CI_KERNPART" )"
  145. local root_ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
  146. local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
  147. [ "$root_ubivol" = "$kern_ubivol" ] && root_ubivol=
  148. # remove ubiblocks
  149. [ "$kern_ubivol" ] && { nand_remove_ubiblock $kern_ubivol || return 1; }
  150. [ "$root_ubivol" ] && { nand_remove_ubiblock $root_ubivol || return 1; }
  151. [ "$data_ubivol" ] && { nand_remove_ubiblock $data_ubivol || return 1; }
  152. # kill volumes
  153. [ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N "$CI_KERNPART" || :
  154. [ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N "$CI_ROOTPART" || :
  155. [ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || :
  156. # create kernel vol
  157. if [ -n "$kernel_length" ]; then
  158. if ! ubimkvol /dev/$ubidev -N "$CI_KERNPART" -s $kernel_length; then
  159. echo "cannot create kernel volume"
  160. return 1;
  161. fi
  162. fi
  163. # create rootfs vol
  164. if [ -n "$rootfs_length" ]; then
  165. local rootfs_size_param
  166. if [ "$rootfs_type" = "ubifs" ]; then
  167. rootfs_size_param="-m"
  168. else
  169. rootfs_size_param="-s $rootfs_length"
  170. fi
  171. if ! ubimkvol /dev/$ubidev -N "$CI_ROOTPART" $rootfs_size_param; then
  172. echo "cannot create rootfs volume"
  173. return 1;
  174. fi
  175. fi
  176. # create rootfs_data vol for non-ubifs rootfs
  177. if [ "$rootfs_type" != "ubifs" ]; then
  178. local rootfs_data_size_param="-m"
  179. if [ -n "$rootfs_data_max" ]; then
  180. rootfs_data_size_param="-s $rootfs_data_max"
  181. fi
  182. if ! ubimkvol /dev/$ubidev -N rootfs_data $rootfs_data_size_param; then
  183. if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
  184. echo "cannot initialize rootfs_data volume"
  185. return 1
  186. fi
  187. fi
  188. fi
  189. sync
  190. return 0
  191. }
  192. nand_do_upgrade_success() {
  193. local conf_tar="/tmp/sysupgrade.tgz"
  194. sync
  195. [ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
  196. echo "sysupgrade successful"
  197. umount -a
  198. reboot -f
  199. }
  200. # Flash the UBI image to MTD partition
  201. nand_upgrade_ubinized() {
  202. local ubi_file="$1"
  203. local mtdnum="$(find_mtd_index "$CI_UBIPART")"
  204. if [ ! "$mtdnum" ]; then
  205. echo "cannot find mtd device $CI_UBIPART"
  206. umount -a
  207. reboot -f
  208. fi
  209. local mtddev="/dev/mtd${mtdnum}"
  210. ubidetach -p "${mtddev}" || :
  211. sync
  212. ubiformat "${mtddev}" -y -f "${ubi_file}"
  213. ubiattach -p "${mtddev}"
  214. nand_do_upgrade_success
  215. }
  216. # Write the UBIFS image to UBI volume
  217. nand_upgrade_ubifs() {
  218. local rootfs_length=$( (cat $1 | wc -c) 2> /dev/null)
  219. nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "" ""
  220. local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  221. local root_ubivol="$(nand_find_volume $ubidev "$CI_ROOTPART")"
  222. ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
  223. nand_do_upgrade_success
  224. }
  225. nand_upgrade_fit() {
  226. local fit_file="$1"
  227. local fit_length="$(wc -c < "$fit_file")"
  228. nand_upgrade_prepare_ubi "" "" "$fit_length" "1"
  229. local fit_ubidev="$(nand_find_ubi "$CI_UBIPART")"
  230. local fit_ubivol="$(nand_find_volume $fit_ubidev "$CI_KERNPART")"
  231. ubiupdatevol /dev/$fit_ubivol -s $fit_length $fit_file
  232. nand_do_upgrade_success
  233. }
  234. nand_upgrade_tar() {
  235. local tar_file="$1"
  236. local board_dir="$(tar tf "$tar_file" | grep -m 1 '^sysupgrade-.*/$')"
  237. board_dir="${board_dir%/}"
  238. local kernel_mtd kernel_length
  239. if [ "$CI_KERNPART" != "none" ]; then
  240. kernel_mtd="$(find_mtd_index "$CI_KERNPART")"
  241. kernel_length=$( (tar xf "$tar_file" "$board_dir/kernel" -O | wc -c) 2> /dev/null)
  242. [ "$kernel_length" = 0 ] && kernel_length=
  243. fi
  244. local rootfs_length=$( (tar xf "$tar_file" "$board_dir/root" -O | wc -c) 2> /dev/null)
  245. [ "$rootfs_length" = 0 ] && rootfs_length=
  246. local rootfs_type
  247. [ "$rootfs_length" ] && rootfs_type="$(identify_tar "$tar_file" "$board_dir/root")"
  248. local ubi_kernel_length
  249. if [ "$kernel_length" ]; then
  250. if [ "$kernel_mtd" ]; then
  251. mtd erase "$CI_KERNPART"
  252. else
  253. ubi_kernel_length="$kernel_length"
  254. fi
  255. fi
  256. local has_env=0
  257. nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$ubi_kernel_length" "$has_env"
  258. local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
  259. if [ "$rootfs_length" ]; then
  260. local root_ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
  261. tar xf "$tar_file" "$board_dir/root" -O | \
  262. ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
  263. fi
  264. if [ "$kernel_length" ]; then
  265. if [ "$kernel_mtd" ]; then
  266. tar xf "$tar_file" "$board_dir/kernel" -O | \
  267. mtd -n write - "$CI_KERNPART"
  268. else
  269. local kern_ubivol="$( nand_find_volume $ubidev "$CI_KERNPART" )"
  270. tar xf "$tar_file" "$board_dir/kernel" -O | \
  271. ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
  272. fi
  273. fi
  274. nand_do_upgrade_success
  275. }
  276. # Recognize type of passed file and start the upgrade process
  277. nand_do_upgrade() {
  278. local file_type=$(identify $1)
  279. [ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART=rootfs
  280. case "$file_type" in
  281. "fit") nand_upgrade_fit $1;;
  282. "ubi") nand_upgrade_ubinized $1;;
  283. "ubifs") nand_upgrade_ubifs $1;;
  284. *) nand_upgrade_tar $1;;
  285. esac
  286. }
  287. # Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
  288. # 3 types of files:
  289. # 1) UBI - should contain an ubinized image, header is checked for the proper
  290. # MAGIC
  291. # 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
  292. # header is checked for the proper MAGIC
  293. # 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
  294. # "CONTROL" file (at this point its content isn't verified)
  295. #
  296. # You usually want to call this function in platform_check_image.
  297. #
  298. # $(1): board name, used in case of passing TAR file
  299. # $(2): file to be checked
  300. nand_do_platform_check() {
  301. local board_name="$1"
  302. local tar_file="$2"
  303. local control_length=$( (tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null)
  304. local file_type="$(identify $2)"
  305. [ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" -a "$file_type" != "fit" ] && {
  306. echo "Invalid sysupgrade file."
  307. return 1
  308. }
  309. return 0
  310. }