platform.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. # SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
  2. . /lib/functions/bcm4908.sh
  3. RAMFS_COPY_BIN="bcm4908img expr grep ln fdtget fw_printenv fw_setenv readlink tr"
  4. PART_NAME=firmware
  5. BCM4908_FW_FORMAT=
  6. BCM4908_FW_BOARD_ID=
  7. BCM4908_FW_INT_IMG_FORMAT=
  8. # $(1): file to read from
  9. # $(2): offset in bytes
  10. # $(3): length in bytes
  11. get_content() {
  12. dd if="$1" skip=$2 bs=1 count=$3 2>/dev/null
  13. }
  14. # $(1): file to read from
  15. # $(2): offset in bytes
  16. get_hex_u32_le() {
  17. dd if="$1" skip=$2 bs=1 count=4 2>/dev/null | hexdump -v -e '1/4 "%02x"'
  18. }
  19. # $(1): file to read from
  20. # $(2): offset in bytes
  21. get_hex_u32_be() {
  22. dd if="$1" skip=$2 bs=1 count=4 2>/dev/null | hexdump -v -e '1/1 "%02x"'
  23. }
  24. platform_expected_image() {
  25. local machine=$(board_name)
  26. case "$machine" in
  27. asus,gt-ac5300) echo "asus GT-AC5300";;
  28. netgear,r8000p) echo "chk U12H359T00_NETGEAR";;
  29. tplink,archer-c2300-v1) echo "";;
  30. esac
  31. }
  32. platform_identify() {
  33. local magic
  34. local size
  35. magic=$(get_hex_u32_be "$1" 0)
  36. case "$magic" in
  37. d00dfeed)
  38. BCM4908_FW_FORMAT="pkgtb"
  39. return
  40. ;;
  41. 2a23245e)
  42. local header_len=$((0x$(get_hex_u32_be "$1" 4)))
  43. local board_id_len=$(($header_len - 40))
  44. BCM4908_FW_FORMAT="chk"
  45. BCM4908_FW_BOARD_ID=$(dd if="$1" skip=40 bs=1 count=$board_id_len 2>/dev/null | hexdump -v -e '1/1 "%c"')
  46. magic=$(get_hex_u32_be "$1" "$header_len")
  47. [ "$magic" = "d00dfeed" ] && {
  48. BCM4908_FW_INT_IMG_FORMAT="pkgtb"
  49. } || {
  50. BCM4908_FW_INT_IMG_FORMAT="bcm4908img"
  51. }
  52. BCM4908_FW_INT_IMG_EXTRACT_CMD="dd skip=$header_len iflag=skip_bytes"
  53. return
  54. ;;
  55. esac
  56. size=$(wc -c "$1" | cut -d ' ' -f 1)
  57. magic=$(get_content "$1" $((size - 20 - 64 + 8)) 12)
  58. case "$magic" in
  59. GT-AC5300)
  60. local size=$(wc -c "$1" | cut -d ' ' -f 1)
  61. BCM4908_FW_FORMAT="asus"
  62. BCM4908_FW_BOARD_ID=$(get_content "$1" $((size - 20 - 64 + 8)) 12)
  63. BCM4908_FW_INT_IMG_FORMAT="bcm4908img"
  64. return
  65. ;;
  66. esac
  67. # Detecting native format is a bit complex (it may start with CFE or
  68. # JFFS2) so just use bcm4908img instead of bash hacks.
  69. # Make it the last attempt as bcm4908img detects also vendor formats.
  70. bcm4908img info -i "$1" > /dev/null && {
  71. BCM4908_FW_FORMAT="bcm4908img"
  72. return
  73. }
  74. }
  75. #
  76. # pkgtb helpers
  77. #
  78. platform_pkgtb_get_image_name() {
  79. local configuration=$($2 < $1 | fdtget - /configurations default)
  80. [ -z "$configuration" ] && {
  81. echo "Failed to read default configuration from pkgtb" >&2
  82. return
  83. }
  84. local image_name=$($2 < $1 | fdtget - /configurations/$configuration $3)
  85. [ -z "$image_name" ] && {
  86. echo "Failed to read $3 from pkgtb configuration \"$configuration\"" >&2
  87. return
  88. }
  89. echo "$image_name"
  90. }
  91. platform_pkgtb_get_image() {
  92. local cmd="${2:-cat}"
  93. local image_name=$(platform_pkgtb_get_image_name "$1" "$cmd" "$3")
  94. $cmd < $1 | fdtget -p - /images/$image_name | grep -Eq "^data$" && {
  95. $cmd < $1 | fdtget -t r - /images/$image_name data
  96. return
  97. }
  98. $cmd < $1 | fdtget -p - /images/$image_name | grep -Eq "^data-position$" && {
  99. local data_position=$($cmd < $1 | fdtget - /images/$image_name data-position)
  100. local data_size=$($cmd < $1 | fdtget - /images/$image_name data-size)
  101. $cmd < $1 2>/dev/null | dd skip=$data_position count=$data_size iflag=skip_bytes,count_bytes
  102. return
  103. }
  104. $cmd < $1 | fdtget -p - /images/$image_name | grep -Eq "^data-offset" && {
  105. local data_offset=$($cmd < $1 | fdtget - /images/$image_name data-offset)
  106. local totalsize=$(get_hex_u32_be "$1" 4)
  107. local data_position=$(((0x$totalsize + data_offset + 3) & ~3))
  108. local data_size=$($cmd < $1 | fdtget - /images/$image_name data-size)
  109. $cmd < $1 2>/dev/null | dd skip=$data_position count=$data_size iflag=skip_bytes,count_bytes
  110. return
  111. }
  112. }
  113. platform_pkgtb_get_upgrade_index() {
  114. case "$(fw_printenv -l /tmp -n -c /tmp/env.config COMMITTED)" in
  115. 1) echo 2;;
  116. 2) echo 1;;
  117. *) echo 1;;
  118. esac
  119. }
  120. platform_pkgtb_commit() {
  121. local size=$((0x$(get_hex_u32_le /dev/ubi0_1 4)))
  122. local valid1=0
  123. local valid2=0
  124. local seq1
  125. local seq2
  126. local tmp
  127. # Read current values
  128. for valid in $(fw_printenv -l /tmp -n -c /tmp/env.config VALID | tr ',' ' '); do
  129. case "$valid" in
  130. 1) valid0=1;;
  131. 2) valid1=2;;
  132. esac
  133. done
  134. seq0=$(fw_printenv -l /tmp -n -c /tmp/env.config SEQ | cut -d ',' -f 1)
  135. seq1=$(fw_printenv -l /tmp -n -c /tmp/env.config SEQ | cut -d ',' -f 2)
  136. # Calculate values
  137. case "$1" in
  138. 1) valid0=1; seq0=$(((seq1 + 1) % 1000));;
  139. 2) valid1=2; seq1=$(((seq0 + 1) % 1000));;
  140. esac
  141. # Update variables
  142. fw_setenv -l /tmp -c /tmp/env.config COMMITTED "$1"
  143. fw_setenv -l /tmp -c /tmp/env.config VALID "$valid0,$valid1"
  144. fw_setenv -l /tmp -c /tmp/env.config SEQ "$seq0,$seq1"
  145. # Write
  146. tmp=$(cat /tmp/env.head /tmp/env.body | wc -c)
  147. cat /tmp/env.head /tmp/env.body | ubiupdatevol /dev/ubi0_1 -s $tmp -
  148. }
  149. #
  150. # check
  151. #
  152. platform_check_pkgtb() {
  153. local cmd="${2:-cat}"
  154. [ -n "$(platform_pkgtb_get_image_name "$1" "$cmd" "bootfs")" -a -n "$(platform_pkgtb_get_image_name "$1" "$cmd" "rootfs")" ]
  155. }
  156. platform_check_image() {
  157. [ "$#" -gt 1 ] && return 1
  158. local expected_image=$(platform_expected_image)
  159. local error=0
  160. platform_identify "$1"
  161. [ -z "$BCM4908_FW_FORMAT" ] && {
  162. echo "Invalid image type. Please use firmware specific for this device."
  163. notify_firmware_broken
  164. return 1
  165. }
  166. echo "Found $BCM4908_FW_FORMAT firmware for device ${BCM4908_FW_BOARD_ID:----}"
  167. local expected_image="$(platform_expected_image)"
  168. [ -n "$expected_image" -a -n "$BCM4908_FW_BOARD_ID" -a "$BCM4908_FW_FORMAT $BCM4908_FW_BOARD_ID" != "$expected_image" ] && {
  169. echo "Firmware doesn't match device ($expected_image)"
  170. error=1
  171. }
  172. case "$BCM4908_FW_FORMAT" in
  173. "bcm4908img")
  174. bcm4908img info -i "$1" > /dev/null || {
  175. echo "Failed to validate BCM4908 image" >&2
  176. notify_firmware_broken
  177. return 1
  178. }
  179. bcm4908img bootfs -i "$1" ls | grep -q "1-openwrt" || {
  180. # OpenWrt images have 1-openwrt dummy file in the bootfs.
  181. # Don't allow backup if it's missing
  182. notify_firmware_no_backup
  183. }
  184. ;;
  185. "pkgtb")
  186. platform_check_pkgtb "$1" || {
  187. echo "Failed to validate pkgtb firmware" >&2
  188. notify_firmware_broken
  189. return 1
  190. }
  191. ;;
  192. *)
  193. case "$BCM4908_FW_INT_IMG_FORMAT" in
  194. "bcm4908img")
  195. bcm4908img info -i "$1" > /dev/null || {
  196. echo "Failed to validate BCM4908 image" >&2
  197. notify_firmware_broken
  198. return 1
  199. }
  200. bcm4908img bootfs -i "$1" ls | grep -q "1-openwrt" || {
  201. # OpenWrt images have 1-openwrt dummy file in the bootfs.
  202. # Don't allow backup if it's missing
  203. notify_firmware_no_backup
  204. }
  205. ;;
  206. "pkgtb")
  207. platform_check_pkgtb "$1" "$BCM4908_FW_INT_IMG_EXTRACT_CMD" || {
  208. echo "Failed to validate pkgtb firmware" >&2
  209. notify_firmware_broken
  210. return 1
  211. }
  212. ;;
  213. esac
  214. ;;
  215. esac
  216. return $error
  217. }
  218. #
  219. # upgrade
  220. #
  221. platform_pkgtb_clean_rootfs_data() {
  222. local ubidev=$(nand_find_ubi $CI_UBIPART)
  223. local ubivol="$(nand_find_volume $ubidev rootfs_data)"
  224. bcm4908_verify_rootfs_data "$ubivol"
  225. }
  226. platform_do_upgrade_pkgtb() {
  227. local cmd="${2:-cat}"
  228. local size
  229. local idx bootfs_id rootfs_id
  230. bcm4908_pkgtb_setup_env_config
  231. idx=$(platform_pkgtb_get_upgrade_index)
  232. case "$idx" in
  233. 1) bootfs_id=3; rootfs_id=4;;
  234. 2) bootfs_id=5; rootfs_id=6;;
  235. esac
  236. size=$(platform_pkgtb_get_image "$1" "$cmd" "bootfs" | wc -c)
  237. ubirmvol /dev/ubi0 -N bootfs$idx
  238. ubimkvol /dev/ubi0 -n $bootfs_id -N bootfs$idx -t static -s $size
  239. platform_pkgtb_get_image "$1" "$cmd" "bootfs" | ubiupdatevol /dev/ubi0_$bootfs_id -s $size -
  240. size=$(platform_pkgtb_get_image "$1" "$cmd" "rootfs" | wc -c)
  241. ubirmvol /dev/ubi0 -N rootfs$idx
  242. ubimkvol /dev/ubi0 -n $rootfs_id -N rootfs$idx -t dynamic -s $size
  243. platform_pkgtb_get_image "$1" "$cmd" "rootfs" | ubiupdatevol /dev/ubi0_$rootfs_id -s $size -
  244. platform_pkgtb_commit $idx
  245. CI_UBIPART="image"
  246. platform_pkgtb_clean_rootfs_data
  247. nand_do_upgrade_success
  248. }
  249. # $1: cferam index increment value
  250. platform_calc_new_cferam() {
  251. local inc="$1"
  252. local dir="/tmp/sysupgrade-bcm4908"
  253. local mtd=$(find_mtd_part bootfs)
  254. [ -z "$mtd" ] && {
  255. echo "Failed to find bootfs partition" >&2
  256. return
  257. }
  258. rm -fR $dir
  259. mkdir -p $dir
  260. mount -t jffs2 -o ro $mtd $dir || {
  261. echo "Failed to mount bootfs partition $mtd" >&2
  262. rm -fr $dir
  263. return
  264. }
  265. local idx=$(ls $dir/cferam.??? | sed -n 's/.*cferam\.\(\d\d\d\)/\1/p')
  266. [ -z "$idx" ] && {
  267. echo "Failed to find cferam current index" >&2
  268. rm -fr $dir
  269. return
  270. }
  271. umount $dir
  272. rm -fr $dir
  273. idx=$(($(expr $idx + $inc) % 1000))
  274. echo $(printf "cferam.%03d" $idx)
  275. }
  276. platform_do_upgrade_ubi() {
  277. local dir="/tmp/sysupgrade-bcm4908"
  278. local inc=1
  279. # Verify new bootfs size
  280. local mtd_bootfs_size=$(grep "\"bootfs\"" /proc/mtd | sed "s/mtd[0-9]*:[ \t]*\([^ \t]*\).*/\1/")
  281. [ -z "$mtd_bootfs_size" ] && {
  282. echo "Unable to find \"bootfs\" partition size"
  283. return
  284. }
  285. mtd_bootfs_size=$((0x$mtd_bootfs_size))
  286. local img_bootfs_size=$(bcm4908img extract -i "$1" -t bootfs | wc -c)
  287. [ $img_bootfs_size -gt $mtd_bootfs_size ] && {
  288. echo "New bootfs doesn't fit MTD partition."
  289. return
  290. }
  291. # Find cferam name for new firmware
  292. # For UBI we always flash "firmware" so don't increase cferam index if
  293. # there is "fallback". That could result in cferam.999 & cferam.001
  294. [ -n "$(find_mtd_index backup)" -o -n "$(find_mtd_index fallback)" ] && inc=0
  295. local cferam=$(platform_calc_new_cferam $inc)
  296. [ -z "$cferam" ] && exit 1
  297. # Prepare new firmware
  298. bcm4908img bootfs -i "$1" mv cferam.000 $cferam || {
  299. echo "Failed to rename cferam.000 to $cferam" >&2
  300. exit 1
  301. }
  302. # Extract rootfs for further flashing
  303. rm -fr $dir
  304. mkdir -p $dir
  305. bcm4908img extract -i "$1" -t rootfs > $dir/root || {
  306. echo "Failed to extract rootfs" >&2
  307. rm -fr $dir
  308. exit 1
  309. }
  310. # Flash bootfs MTD partition with new one
  311. mtd erase bootfs || {
  312. echo "Failed to erase bootfs" >&2
  313. rm -fr $dir
  314. exit 1
  315. }
  316. bcm4908img extract -i "$1" -t bootfs | mtd write - bootfs || {
  317. echo "Failed to flash bootfs" >&2
  318. rm -fr $dir
  319. exit 1
  320. }
  321. nand_do_upgrade $dir/root
  322. }
  323. platform_do_upgrade() {
  324. platform_identify "$1"
  325. # Try NAND aware UBI upgrade for OpenWrt images
  326. case "$BCM4908_FW_FORMAT" in
  327. "bcm4908img")
  328. bcm4908img bootfs -i "$1" ls | grep -q "1-openwrt" && platform_do_upgrade_ubi "$1"
  329. ;;
  330. "pkgtb")
  331. platform_do_upgrade_pkgtb "$1"
  332. ;;
  333. *)
  334. case "$BCM4908_FW_INT_IMG_FORMAT" in
  335. "bcm4908img")
  336. bcm4908img bootfs -i "$1" ls | grep -q "1-openwrt" && platform_do_upgrade_ubi "$1"
  337. ;;
  338. "pkgtb")
  339. platform_do_upgrade_pkgtb "$1" "$BCM4908_FW_INT_IMG_EXTRACT_CMD"
  340. ;;
  341. *)
  342. echo "NAND aware sysupgrade is unsupported for $BCM4908_FW_FORMAT format"
  343. ;;
  344. esac
  345. ;;
  346. esac
  347. # Above calls exit on success.
  348. # If we got here it isn't OpenWrt image or something went wrong.
  349. [ "$BCM4908_FW_FORMAT" = "pkgtb" -o "$BCM4908_FW_INT_IMG_FORMAT" = "pkgtb" ] && {
  350. echo "Failed to upgrade pkgtb. Fallback to raw flashing is impossible for this format." >&2
  351. exit 1
  352. }
  353. echo "Writing whole image to NAND flash. All erase counters will be lost."
  354. # Find cferam name for new firmware
  355. local cferam=$(platform_calc_new_cferam 1)
  356. [ -z "$cferam" ] && exit 1
  357. # Prepare new firmware
  358. bcm4908img bootfs -i "$1" mv cferam.000 $cferam || {
  359. echo "Failed to rename cferam.000 to $cferam" >&2
  360. exit 1
  361. }
  362. # Jush flash firmware partition as is
  363. [ -n "$(find_mtd_index backup)" ] && PART_NAME=backup
  364. [ -n "$(find_mtd_index fallback)" ] && PART_NAME=fallback
  365. mtd erase $PART_NAME
  366. default_do_upgrade "$1" "bcm4908img extract -t firmware"
  367. }