summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init')
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init268
1 files changed, 268 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
new file mode 100755
index 000000000..2065f94ee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
@@ -0,0 +1,268 @@
+#!/bin/bash
+
+# Copyright 2017-2019 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# provide a couple of places in the RO root filesystem
+# that can be made RW with an overlayfs
+
+log() {
+ [ -c /dev/kmsg ] && echo "init: $*" > /dev/kmsg
+ echo "init: $*"
+}
+
+# start with /proc and /tmp mounted
+[ -e /proc/mounts ] || mount -t proc proc /proc
+# FIXME: add size limits to /tmp
+grep -q /tmp /proc/mounts || mount -t tmpfs -o rw,nosuid,nodev tmp /tmp
+grep -q /sys /proc/mounts || mount -t sysfs -o rw,nosuid,nodev,noexec sys /sys
+
+# fix up /srv to be RW
+mkdir -p /tmp/srv
+mount --bind /tmp/srv /srv
+
+if grep -q debug-init /proc/cmdline; then
+ exec > /tmp/init.log 2>&1
+ set -x
+ env
+else
+ # Suppress any stray output but we want to see any errors
+ exec >/dev/null 2>/dev/kmsg
+fi
+
+# list of things that need to be rw at boot
+NV_OVERLAYS="/etc /var /home"
+
+# place to mount the overlay backing store
+OVERLAY_MNT=/tmp/.overlay
+# OVERLAY_SIZE=16384
+# place to mount NV
+RWFS_MNT=/tmp/.rwfs
+# NV overlay storage
+OVERLAY_SYNC=${RWFS_MNT}/.overlay
+
+if grep -q "$RWFS_MNT" /proc/mounts; then
+ # quit - we have already run
+ exit 0
+fi
+mkdir -p "$OVERLAY_MNT"
+# TODO: remount the overlay with a size limit?
+# mount -t tmpfs -o rw,size=${OVERLAY_SIZE} oltmp ${OVERLAY_MNT}
+
+mtd_by_name() {
+ local name="$1"
+ echo "/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)"
+}
+
+mtdnum_by_name() {
+ local name="$1"
+ grep "$name" /proc/mtd | cut -c 4
+}
+
+NV_MTD=rwfs
+
+nvrw() {
+ local p="$1"
+ # Clear the work dir doing overlay mount
+ rm -rf "${OVERLAY_MNT}${p}.work"
+ mkdir -p "${OVERLAY_MNT}${p}" "${OVERLAY_MNT}${p}.work"
+ local mname
+ mname=$(echo "ol${p}" | sed 's,/,,g')
+ local opts="lowerdir=${p},upperdir=${OVERLAY_MNT}${p},workdir=${OVERLAY_MNT}${p}.work,sync"
+ mount -t overlay -o "$opts" "$mname" "$p"
+}
+
+targeted_clean() {
+ log "restore-defaults: targeted_clean"
+ # Do not delete FRU info, ssh/ssl certs, or machine-id
+ (
+ cd "${OVERLAY_SYNC}/etc" || exit
+ find . ! -regex '.*/\(ssl\|dropbear\|machine-id\|fru\).*' -a ! -path '.' \
+ -exec rm -rf {} +
+ )
+ # nothing should be in the workdir, but clear it just in case
+ rm -rf "${OVERLAY_SYNC}/etc.work"
+
+ # clean everything out of /home
+ rm -rf "${OVERLAY_SYNC}/home" "${OVERLAY_SYNC}/home.work"
+
+ # clean everything out of /var
+ rm -rf "${OVERLAY_SYNC}/var" "${OVERLAY_SYNC}/var.work"
+
+ echo "Files remaining: $(find $OVERLAY_SYNC/)"
+ sync
+}
+
+full_clean() {
+ log "restore-defaults: full_clean"
+ local OVL=''
+ for OVL in $NV_OVERLAYS; do
+ rm -rf "${OVERLAY_SYNC}${OVL}" "${OVERLAY_SYNC}${OVL}.work"
+ done
+ sync
+}
+
+jffs2_mount() {
+ mtd_name=$1
+ mnt=$2
+ mount -t jffs2 -o sync,ro mtd:"$mtd_name" "$mnt"
+}
+
+reformat_jffs2_partition() {
+ local mtd_name="$1"
+ local mnt="$2"
+ # unmount the partition to reformat it
+ umount -f "$mnt"
+ flash_erase "$(mtd_by_name "$mtd_name")" 0 0
+ # remount the JFFS2
+ if ! jffs2_mount "$mtd_name" "$mnt"; then
+ log "Failed to mount reformatted NV volume; system unstable"
+ fi
+}
+
+clear_ubenv() {
+ log "Clearing U-Boot environment"
+ flash_erase "$(mtd_by_name u-boot-env)" 0 0
+}
+
+# mount NV filesystem
+mkdir -p "$RWFS_MNT"
+if ! jffs2_mount "$NV_MTD" "$RWFS_MNT"; then
+ log "Failed to mount NV volume; attempting recovery"
+ reformat_jffs2_partition $NV_MTD $RWFS_MNT
+fi
+
+# check for full factory reset: if so, format $NV_MTD_DEV
+RESTORE_FLAG=$RWFS_MNT/.restore_op
+if [ -f "$RESTORE_FLAG" ]; then
+ mount -o remount,rw "$RWFS_MNT"
+ restore_op=$(cat $RESTORE_FLAG) # read from NV
+ modified_on=$(stat -c %y $RESTORE_FLAG) # get last modified time
+ log "restore_op: $restore_op modified on: $modified_on"
+ # To rule out stale file mounted, Write unique, unused value 0x10
+ # (last 2-bits are b00) before removing the file.
+ echo 16 > $RESTORE_FLAG
+ # set default value 0 if RESTORE_FLAG file was empty
+ restore_op=${restore_op:-0}
+ restore_op=$((restore_op & 3)) # mask off 2 bits
+ if [ $restore_op -eq 1 ]; then
+ targeted_clean
+ elif [ $restore_op -eq 2 ]; then
+ full_clean
+ clear_ubenv
+ elif [ $restore_op -eq 3 ]; then
+ log "restore-defaults: reformat"
+ reformat_jffs2_partition $NV_MTD $RWFS_MNT
+ clear_ubenv
+ fi
+ rm -f $RESTORE_FLAG
+ mount -o remount,ro "$RWFS_MNT"
+fi
+
+# Restore the overlay saved in the sync
+rsync -a --delete "${OVERLAY_SYNC}/" "${OVERLAY_MNT}"
+log "Restored overlay from sync location"
+
+for FS in $NV_OVERLAYS; do
+ nvrw "$FS"
+done
+
+# work around bug where /etc/machine-id will be mounted with a temporary file
+# if rootfs is read-only and the file is empty
+MACHINE_ID=/etc/machine-id
+generate_machine_id() {
+ systemd-machine-id-setup
+ cp -pf "$MACHINE_ID" "${MACHINE_ID}_bkup"
+}
+
+if [ ! -s "$MACHINE_ID" ]; then
+ # work around - Bug: Overlay fs fails for machine-id due to
+ # origin mismatch. Clean it up, from overlay fs before re-creating
+ # the same.
+ if [ -e "$OVERLAY_MNT$MACHINE_ID" ]; then
+ umount "/etc"
+ rm -f "$OVERLAY_MNT$MACHINE_ID"
+ nvrw "/etc"
+ # Restore the machine-id from backup, else generate it.
+ if [ -s "${MACHINE_ID}_bkup" ]; then
+ cp -pf "${MACHINE_ID}_bkup" "${MACHINE_ID}"
+ else
+ generate_machine_id
+ fi
+ log "Remounted /etc for machine-id origin mismatch"
+ else
+ generate_machine_id
+ fi
+fi
+
+# mount persistent NV filesystem, where immortal settings live
+SOFS_MNT=/var/sofs
+if ! grep -q sofs /proc/mounts; then
+ mkdir -p $SOFS_MNT
+ SOFS_MTD=sofs
+
+ # mount a JFFS2 on the partition
+ if ! jffs2_mount "$SOFS_MTD" "$SOFS_MNT"; then
+ log "Failed to mount SOFS volume; attempting recovery"
+ reformat_jffs2_partition $SOFS_MTD $SOFS_MNT
+ fi
+fi
+
+log "Finished mounting nv and overlays"
+
+
+# Detect the non-legacy node in cooper city and boot in to special mode.
+
+readonly COOPER_CITY=40 # Board id of cooper city
+
+is_nl_node() {
+ typeset -i nid1=$(gpioget $(gpiofind "FM_NODE_ID_1"))
+ typeset -i nid2=$(gpioget $(gpiofind "FM_NODE_ID_2"))
+ echo $((nid1|nid2))
+}
+
+read_board_id() {
+ local idx=0
+ local result=0
+ local value=0
+ for ((idx=0; idx<6; idx++))
+ do
+ typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N"))
+ value=$((value << idx))
+ result=$((result | value))
+ done
+ echo $result
+}
+
+pfr_write() {
+ [ $# -ne 2 ] && return 1
+ local PFR_BUS=4
+ local PFR_ADDR=0x38
+ local reg=$1
+ local val=$2
+ i2cset -y $PFR_BUS $PFR_ADDR "$reg" "$val" >&/dev/null
+}
+
+board_id=$(read_board_id)
+if [ "$board_id" -eq $COOPER_CITY ]; then
+ if [ "$(is_nl_node)" -ne 0 ]; then
+ systemctl set-default multi-node-nl.target
+ PFR_BMC_CHECKPOINT_REG=0xf
+ PFR_BMC_CHECKPOINT_COMPLETE=0x9
+ pfr_write $PFR_BMC_CHECKPOINT_REG $PFR_BMC_CHECKPOINT_COMPLETE
+ fi
+fi
+
+exec /lib/systemd/systemd