mmc: Setup hostfw directories

The BMC updater will take care of writing the new hostfw image
to flash since it's delivered in the single tarball file, but
when the BMC starts up, need to setup the directories so that
the contents of the host FW are visible to consumers like pldm.

The first service is to setup the patch directory. This is
similar to UBI. The path that mboxd expects (pnor) will point to
a directory in the hostfw partition. Then create a similar
symlink (hostfw) for pldm to use. Eventually pldm will replace
mboxd.

The second service is an init setup. We need to make the 2 hostfw
versions visible. The secondary (non-running) will just be a
read-only mount of the non-running image. The primary (running)
version needs to be read-write. The mboxd code currently
handles 3 directories: ro, rw, prsv. This was deemed too complex
for pldm to replicate, so it was decided to have a single rw
directory, then pldm would determine if it allowed a write or not.
To handle the preserved files (that are not updated on an update),
need to copy them off to a tmp space, then set up the primary
directory with the contents of the running image, then restore the
preserved files. Currently only the PNOR contents are preserved,
at a later point the pldm files will be preserved and a different
list like the pnor.toc file will be added.

Finally, like the vpnor util does, if the version has changed on,
remove the patch files. Just that we need to do this when the init
service starts because the symlinks will not change at runtime
(the host fw version is tied to the bmc version).

Change-Id: I32b456bd363671404f573cb941a0f2f374a3eab2
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
diff --git a/mmc/Makefile.am.include b/mmc/Makefile.am.include
index 78c3150..9c9aab7 100644
--- a/mmc/Makefile.am.include
+++ b/mmc/Makefile.am.include
@@ -1,3 +1,12 @@
 openpower_update_manager_SOURCES += \
 	%reldir%/activation_mmc.cpp \
 	%reldir%/item_updater_mmc.cpp
+
+dist_bin_SCRIPTS += \
+	%reldir%/obmc-flash-bios
+
+if HAVE_SYSTEMD
+systemdsystemunit_DATA += \
+	%reldir%/obmc-flash-bios-init.service \
+	%reldir%/obmc-flash-bios-patch.service
+endif
diff --git a/mmc/obmc-flash-bios b/mmc/obmc-flash-bios
new file mode 100644
index 0000000..0a496ec
--- /dev/null
+++ b/mmc/obmc-flash-bios
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+mmc_init() {
+  base_dir="/media/hostfw"
+  running_dir="${base_dir}/running"
+  prsv_dir="${base_dir}/prsv"
+
+  if [ ! -d "${running_dir}" ]; then
+    mkdir -p ${running_dir}
+  fi
+  if [ ! -d "${prsv_dir}" ]; then
+    mkdir -p "${prsv_dir}"
+  fi
+
+  # Determine if the running dir contains the running version
+  boot_label="$(fw_printenv -n bootside)"
+  running_label=""
+  running_label_file="${running_dir}/partlabel"
+  if [ -f "${running_label_file}" ]; then
+    running_label=$(cat ${running_label_file})
+  fi
+  if [ "${running_label}" != "${boot_label}" ]; then
+    # Copy off the preserved partitions
+    # A line in the pnor.toc looks like this:
+    # partition05=SECBOOT,0x00381000,0x003a5000,00,ECC,PRESERVED
+    rm -f ${prsv_dir}/*
+    if [ -f ${running_dir}/pnor.toc ]; then
+      prsvs=$(grep PRESERVED ${running_dir}/pnor.toc)
+      for prsv in ${prsvs}; do
+        prsv=${prsv##partition*=}
+        prsv=$(echo ${prsv} | cut -d "," -f 1)
+        cp -p ${running_dir}/${prsv} ${prsv_dir}
+      done
+    fi
+
+    # Copy contents of running image to running dir
+    tmp_dir="/tmp/hostfw"
+    mkdir -p "${tmp_dir}"
+    mount ${base_dir}/hostfw-${boot_label} ${tmp_dir} -o ro
+    rm -f ${running_dir}/*
+    cp -p ${tmp_dir}/* ${running_dir}/
+    umount ${tmp_dir}
+    rm -rf ${tmp_dir}
+
+    # Restore the preserved partitions
+    cp -p ${prsv_dir}/* ${running_dir}/ || true
+    rm -f ${prsv_dir}/*
+
+    # Save the label
+    echo "${boot_label}" > "${running_label_file}"
+
+    # Remove patches
+    rm -f ${base_dir}/patch/*
+  fi
+
+  # Mount alternate dir
+  if [ "${boot_label}" = "a" ]; then
+    alternate_label="b"
+  else
+    alternate_label="a"
+  fi
+  alternate_dir="${base_dir}/alternate"
+  if [ ! -d "${alternate_dir}" ]; then
+    mkdir -p ${alternate_dir}
+  fi
+  mount ${base_dir}/hostfw-${alternate_label} ${alternate_dir} -o ro
+}
+
+mmc_patch() {
+  # Patching is disabled if field mode is set
+  if [[ "$(fw_printenv fieldmode 2>/dev/null)" == "fieldmode=true" ]]; then
+    return 0
+  fi
+
+  target="/media/hostfw/patch"
+  if [ ! -d "${target}" ]; then
+    mkdir -p "${target}"
+  fi
+
+  patchdir="/usr/local/share"
+  if [ ! -d "${patchdir}" ]; then
+    mkdir -p "${patchdir}"
+  fi
+
+  ln -s "${target}" "${patchdir}/hostfw"
+  ln -s "${target}" "${patchdir}/pnor"
+}
+
+case "$1" in
+  mmc-init)
+    mmc_init
+    ;;
+  mmc-patch)
+    mmc_patch
+    ;;
+  *)
+    echo "Invalid argument"
+    exit 1
+    ;;
+esac
diff --git a/mmc/obmc-flash-bios-init.service b/mmc/obmc-flash-bios-init.service
new file mode 100644
index 0000000..191a859
--- /dev/null
+++ b/mmc/obmc-flash-bios-init.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Setup Host FW directories
+Before=pldmd.service
+After=xyz.openbmc_project.Software.BMC.Updater.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/obmc-flash-bios mmc-init
+
+[Install]
+WantedBy=xyz.openbmc_project.Software.BMC.Updater.service
diff --git a/mmc/obmc-flash-bios-patch.service b/mmc/obmc-flash-bios-patch.service
new file mode 100644
index 0000000..226c019
--- /dev/null
+++ b/mmc/obmc-flash-bios-patch.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Create patch directory for Host FW
+Before=pldmd.service
+Wants=usr-local.mount
+After=usr-local.mount
+After=xyz.openbmc_project.Software.BMC.Updater.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/obmc-flash-bios mmc-patch
+
+[Install]
+WantedBy=xyz.openbmc_project.Software.BMC.Updater.service