nand.sh 8.5 KB

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