1#!/bin/sh 2 3bios_reset_if_needed() { 4 resetval=$(fw_printenv -n rwreset 2>/dev/nell) 5 if [ "$resetval" = "0" ] || [ "$resetval" = "1" ]; then 6 varstore="/media/hostfw/reset-gpio-val" 7 if [ -f "$varstore" ]; then 8 if [ "$resetval" != "$(cat $varstore)" ]; then 9 if busctl call org.open_power.Software.Host.Updater /xyz/openbmc_project/software xyz.openbmc_project.Common.FactoryReset Reset; then 10 echo "$resetval" > "$varstore" 11 fi 12 fi 13 else 14 echo "$resetval" > "$varstore" 15 fi 16 fi 17} 18 19mmc_get_primary_label() { 20 # Get root device /dev/mmcblkpX 21 rootmatch=" on / " 22 root="$(mount | grep "${rootmatch}")" 23 # shellcheck disable=SC2295 24 root="${root%${rootmatch}*}" 25 26 # Find the device label 27 if [ "$(readlink -f /dev/disk/by-partlabel/rofs-a)" = "${root}" ]; then 28 echo "a" 29 elif [ "$(readlink -f /dev/disk/by-partlabel/rofs-b)" = "${root}" ]; then 30 echo "b" 31 else 32 echo "" 33 fi 34} 35 36mmc_init() { 37 base_dir="/media/hostfw" 38 ro_dir="${base_dir}/running-ro" 39 running_dir="${base_dir}/running" 40 prsv_dir="${base_dir}/prsv" 41 staging_dir="${base_dir}/staging" 42 nvram_dir="${base_dir}/nvram" 43 44 if [ ! -d "${ro_dir}" ]; then 45 mkdir -p "${ro_dir}" 46 fi 47 if [ ! -d "${running_dir}" ]; then 48 mkdir -p ${running_dir} 49 fi 50 if [ ! -d "${prsv_dir}" ]; then 51 mkdir -p "${prsv_dir}" 52 fi 53 if [ ! -d "${staging_dir}" ]; then 54 mkdir -p "${staging_dir}" 55 fi 56 if [ ! -d "${nvram_dir}" ]; then 57 mkdir -p "${nvram_dir}" 58 fi 59 60 # Mount the image that corresponds to the boot label as read-only to be used 61 # to populate the running directory. 62 boot_label="$(mmc_get_primary_label)" 63 if ! grep -q "${ro_dir}" /proc/mounts; then 64 mount ${base_dir}/hostfw-"${boot_label}" ${ro_dir} -o ro 65 fi 66 67 # Determine if the running dir contains the running version 68 running_label="" 69 running_label_file="${running_dir}/partlabel" 70 if [ -f "${running_label_file}" ]; then 71 running_label=$(cat ${running_label_file}) 72 fi 73 if [ "${running_label}" != "${boot_label}" ]; then 74 # Copy off the preserved partitions 75 # A line in the pnor.toc (81e00994.lid) looks like this: 76 # partition05=SECBOOT,0x00381000,0x003a5000,00,ECC,PRESERVED 77 rm -f ${prsv_dir}/* 78 if [ -f "${ro_dir}/81e00994.lid" ]; then 79 prsvs=$(grep PRESERVED "${ro_dir}/81e00994.lid") 80 for prsv in ${prsvs}; do 81 prsv=${prsv##partition*=} 82 prsv=$(echo "${prsv}" | cut -d "," -f 1) 83 if [ -L "${running_dir}/${prsv}" ]; then 84 # Preserve the symlink target file 85 prsv="$(readlink "${running_dir}/${prsv}")" 86 if [ -f "${running_dir}/${prsv}" ] && [ -f "${ro_dir}/${prsv}" ]; then 87 runsize="$(stat -c '%s' "${running_dir}/${prsv}")" 88 rosize="$(stat -c '%s' "${ro_dir}/${prsv}")" 89 if [ "$runsize" != "$rosize" ]; then 90 # Partition size may have changed or became corrupted 91 # So it will not be copied to the preserved directory 92 # Log PEL to indicate such 93 busctl call xyz.openbmc_project.Logging \ 94 /xyz/openbmc_project/logging \ 95 xyz.openbmc_project.Logging.Create Create "ssa{ss}" \ 96 xyz.openbmc_project.Software.Version.Error.HostFile \ 97 xyz.openbmc_project.Logging.Entry.Level.Error 3 "FILE_NAME" \ 98 "${prsv}" "CURRENT_FILE_SIZE" "${runsize}" "EXPECTED_FILE_SIZE" \ 99 "${rosize}" 100 # Initiate dump 101 busctl call xyz.openbmc_project.Dump.Manager \ 102 /xyz/openbmc_project/dump/bmc xyz.openbmc_project.Dump.Create \ 103 CreateDump "a{sv}" 0 104 else 105 cp -p ${running_dir}/"${prsv}" ${prsv_dir} 106 fi 107 fi 108 fi 109 done 110 fi 111 112 # Copy lid contents of running image to running dir 113 rm -f ${running_dir}/* 114 cp -p ${ro_dir}/*.lid ${running_dir}/ 115 116 # Restore the preserved partitions. Ignore error, there may be none. 117 cp -p ${prsv_dir}/* ${running_dir}/ 2>/dev/null || true 118 rm -f "${prsv_dir:?}/"* 119 120 # Clean up the staging dir in case of a failed update 121 rm -rf "${staging_dir:?}/"* 122 123 # Save the label 124 echo "${boot_label}" > "${running_label_file}" 125 126 fi 127 128 # Mount alternate dir 129 if [ "${boot_label}" = "a" ]; then 130 alternate_label="b" 131 else 132 alternate_label="a" 133 fi 134 alternate_dir="${base_dir}/alternate" 135 if [ ! -d "${alternate_dir}" ]; then 136 mkdir -p ${alternate_dir} 137 fi 138 if ! grep -q "${alternate_dir}" /proc/mounts; then 139 mount ${base_dir}/hostfw-${alternate_label} ${alternate_dir} -o ro 140 fi 141} 142 143mmc_patch() { 144 # Patching is disabled if field mode is set 145 if [ "$(fw_printenv fieldmode 2>/dev/null)" = "fieldmode=true" ]; then 146 return 0 147 fi 148 149 boot_label="$(mmc_get_primary_label)" 150 if [ "${boot_label}" = "a" ]; then 151 alternate_label="b" 152 else 153 alternate_label="a" 154 fi 155 156 # Create patch directories 157 patch_dir="/media/hostfw/patch-" 158 running_patch_dir="${patch_dir}${boot_label}" 159 if [ ! -d "${running_patch_dir}" ]; then 160 mkdir -p "${running_patch_dir}" 161 fi 162 alternate_patch_dir="${patch_dir}${alternate_label}" 163 if [ ! -d "${alternate_patch_dir}" ]; then 164 mkdir -p "${alternate_patch_dir}" 165 fi 166 167 # Create patch symlinks 168 symlink_base="/usr/local/share" 169 if [ ! -d "${symlink_base}" ]; then 170 mkdir -p "${symlink_base}" 171 fi 172 hostfw_symlink_base="${symlink_base}/hostfw" 173 if [ ! -d "${hostfw_symlink_base}" ]; then 174 mkdir -p "${hostfw_symlink_base}" 175 fi 176 177 if [ "$(readlink -f "${symlink_base}/pnor")" != "${running_patch_dir}" ]; then 178 ln -s "${running_patch_dir}" "${symlink_base}/pnor" 179 fi 180 if [ "$(readlink -f "${hostfw_symlink_base}/running")" != "${running_patch_dir}" ]; then 181 ln -s "${running_patch_dir}" "${hostfw_symlink_base}/running" 182 fi 183 if [ "$(readlink -f "${hostfw_symlink_base}/alternate")" != "${alternate_patch_dir}" ]; then 184 ln -s "${alternate_patch_dir}" "${hostfw_symlink_base}/alternate" 185 fi 186} 187 188case "$1" in 189 bios-reset-if-needed) 190 bios_reset_if_needed 191 ;; 192 mmc-init) 193 mmc_init 194 ;; 195 mmc-patch) 196 mmc_patch 197 ;; 198 *) 199 echo "Invalid argument: $1" >&2 200 exit 1 201 ;; 202esac 203