Add mirror u-boot option to obmc-flash-bmc

The mirror u-boot function copies the currently booted BMC chip's u-boot
partition to the alternate chip, if the two don't match. This is to make
sure we always have a good u-boot in the alternate flash.

Also add service file for the mirror u-boot option.

Resolves openbmc/openbmc#2876

Change-Id: Ida09a167de21f3ccb588a096509d88ad88450c93
Signed-off-by: Eddie James <eajames@us.ibm.com>
diff --git a/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager.bb b/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager.bb
index db80ece..43e363b 100644
--- a/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager.bb
+++ b/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager.bb
@@ -80,6 +80,7 @@
     reboot-guard-enable.service \
     reboot-guard-disable.service \
     obmc-flash-bmc-cleanup.service \
+    obmc-flash-bmc-mirroruboot.service \
     "
 
 # Name of the mtd device where the ubi volumes should be created
diff --git a/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager/obmc-flash-bmc b/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager/obmc-flash-bmc
index 26b83e6..4c69713 100644
--- a/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager/obmc-flash-bmc
+++ b/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager/obmc-flash-bmc
@@ -1,6 +1,33 @@
 #!/bin/bash
 set -eo pipefail
 
+# Check if BMC is currently booted from the alternate chip; returns "1" if true
+check_if_alt() {
+  res=0
+  wdiof_cardreset_bit=5
+  wdiof_cardreset=$((1 << $wdiof_cardreset_bit))
+
+  # Read the systemd watchdog config to see which device we should use
+  line=$(cat /etc/systemd/system.conf | grep "WatchdogDevice")
+  if [ ! -z ${line} ]; then
+    watchdog_device=${line##WatchdogDevice=/dev/}
+
+    # Check for legacy symlink to /dev/watchdog0
+    if [ ${watchdog_device} == "watchdog" ]; then
+      watchdog_device="watchdog0"
+    fi
+
+    # Check the bootstatus to see if we've been reset
+    path="/sys/class/watchdog/${watchdog_device}/bootstatus"
+    if [ -f ${path} ]; then
+      bootstatus=$(cat ${path})
+      res=$((($bootstatus & $wdiof_cardreset) >> $wdiof_cardreset_bit))
+    fi
+  fi
+
+  echo "${res}"
+}
+
 # Get the root mtd device number (mtdX) from "/dev/ubiblockX_Y on /"
 findrootmtd() {
   rootmatch=" on / "
@@ -384,6 +411,49 @@
   fi
 }
 
+# Copy contents of one MTD device to another
+mtd_copy() {
+  in=$1
+  out=$2
+
+  # Must erase MTD first to prevent corruption
+  flash_eraseall "${out}"
+  dd if="${in}" of="${out}"
+}
+
+mirroruboot() {
+  bmc="$(findmtd "u-boot")"
+  bmcdev="/dev/${bmc}"
+  alt="$(findmtd "alt-u-boot")"
+  altdev="/dev/${alt}"
+
+  checksum_bmc="$(md5sum "${bmcdev}")"
+  checksum_bmc="${checksum_bmc% *}"
+  checksum_alt="$(md5sum "${altdev}")"
+  checksum_alt="${checksum_alt% *}"
+
+  if [[ "${checksum_bmc}" != "${checksum_alt}" ]]; then
+    bmcenv="$(findmtd "u-boot-env")"
+    bmcenvdev="/dev/${bmcenv}"
+    altenv="$(findmtd "alt-u-boot-env")"
+    altenvdev="/dev/${altenv}"
+    is_alt="$(check_if_alt)"
+
+    if [[ "${is_alt}" == "1" ]]; then
+      echo "Mirroring U-boot; alt to bmc"
+      mtd_copy "${altdev}" "${bmcdev}"
+      mtd_copy "${altenvdev}" "${bmcenvdev}"
+    else
+      echo "Mirroring U-boot; bmc to alt"
+      mtd_copy "${bmcdev}" "${altdev}"
+      mtd_copy "${bmcenvdev}" "${altenvdev}"
+    fi
+
+    copy_ubiblock_to_alt
+    copy_root_to_alt
+  fi
+}
+
 case "$1" in
   mtduboot)
     reqmtd="$2"
@@ -443,6 +513,9 @@
   rebootguarddisable)
     rebootguarddisable
     ;;
+  mirroruboot)
+    mirroruboot
+    ;;
   *)
     echo "Invalid argument"
     exit 1
diff --git a/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager/obmc-flash-bmc-mirroruboot.service b/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager/obmc-flash-bmc-mirroruboot.service
new file mode 100644
index 0000000..361dd61
--- /dev/null
+++ b/meta-phosphor/common/recipes-phosphor/flash/phosphor-software-manager/obmc-flash-bmc-mirroruboot.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Copy uboot from the currently booted bmc chip to the alternate chip
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/env obmc-flash-bmc mirroruboot
+SyslogIdentifier=obmc-flash-bmc