#!/bin/sh
# Aboot stage 0 boot
#
# Copies kernel from swi and kexecs it

USER_KERNEL_PARAMS="kernel-params"
ABOOT_KERNEL_PARAMS="/tmp/append"
TEMP_FILE="/tmp/.kparam-temp"
unset HUGEPAGES

set_kernel_params() {
   DONE=false
   until $DONE; do
      read || DONE=true
      l=$REPLY
      if [ "${l}" == "" -o "${l:0:1}" == "#" ]; then
         continue
      fi

      delete=0
      params=$l
      cmd=$(echo $l | cut -f 1 -d " ")
      if [ "${cmd}" == "-" -o "${cmd:0:1}" == "-" ]; then
         delete=1
	 params=${l#*-}
      fi
      for arg in ${params}
      do
         if [ ${delete} -eq 1 ]; then
	    grep -v "$arg=\|$arg$" "${ABOOT_KERNEL_PARAMS}"  > "${TEMP_FILE}"
	    mv "${TEMP_FILE}" "${ABOOT_KERNEL_PARAMS}"
         else
            echo ${arg} >> "${ABOOT_KERNEL_PARAMS}"
         fi
      done
   done
   echo "Notice: Custom kernel parameters are being applied from $1."
}

# pci_config_match - function to match pci config offset value
#    input: dev (bus/dev/function, 00:01.0)
#           off (offset within config space)
#           pattern (pattern to match in output of config_match)
#    output : returns 0 on success (pattern match)
#             returns 1 on failure (no match)
pci_config_match() {
   dev=$1
   off=$2
   pattern=$3
   pci_devs="/sys/bus/pci/devices"
   out=config_match
   dd if=$pci_devs/0000:$dev/config of=$out bs=1 count=4 skip=$off >& /dev/null || return 1
   hexdump $out | grep "$pattern" >& /dev/null && return 0
   return 1
}

writeconfig() {
   variables="$1"
   for n in ${variables}; do
      eval v="\$$n"
      if [ "$v" ]; then
         echo "$n=$v"
      fi
   done
}

parseconfig POST_LEVEL PASSWORD </etc/boot-config
CONSOLESPEED=$(stty speed)
ifget

kernel=linux-i386

rm -f /tmp/${kernel} /tmp/initrd-${arch}
if [ -d "${swipath}" ]; then
    cp ${swipath}/${kernel} ${swipath}/initrd-${arch} /tmp/
else
    unzip -oq ${swipath} ${kernel} initrd-${arch} -d /tmp
fi

echo "${append}" >/tmp/append
writebootconfig >>/tmp/append

# Fix blockdev regex for internal and front panel USB ports on raven boards
if grep -q 'platform=raven' /etc/cmdline; then
   # On systems with no internal flash, we mount external USB on /mnt/flash.
   # In above case, /etc/cmdline will NOT have regex for usb1. see sysinit
   if grep -q 'block_usb1' /etc/cmdline; then # Have internal flash and USB
      sed -i -e '/block_[flash|usb1]/d' /etc/cmdline
      echo 'block_flash=pci0000:00/0000:00:12.[02]/usb.*$' >>/etc/cmdline
      echo 'block_usb1=pci0000:00/0000:00:13.[02]/usb.*$' >>/etc/cmdline
   else # Mount external USB on flash
      sed -i -e '/block_flash/d' /etc/cmdline
      echo 'block_flash=pci0000:00/0000:00:13.[02]/usb.*$' >>/etc/cmdline
   fi
fi

cat /etc/cmdline | sed "/^\(${bootconfigvars// /\|}\|crashkernel\|loglevel\|ignore_loglevel\)\(\$\|=\)/d;/^\$/d" >>/tmp/append

# Calculate dmamem kernel parameter
pci_config_match "00:00.0" 0 "1022 9601" && DMAMEM=54M-NO_IOMMU # Raven

if grep -q 'platform=crow' /etc/cmdline; then
   DMAMEM=110M-NO_IOMMU
   grep -q 'sid=Lakeport' /etc/cmdline && DMAMEM=256M-NO_IOMMU
   grep -q 'sid=Orinda' /etc/cmdline && DMAMEM=272M-NO_IOMMU
   grep -q 'sid=Piedmont' /etc/cmdline && DMAMEM=256M-NO_IOMMU
   grep -q 'sid=PiedmontG' /etc/cmdline && DMAMEM=256M-NO_IOMMU
fi

if grep -q 'platform=magpie' /etc/cmdline; then
   DMAMEM=136M-NO_IOMMU
   grep -q 'sid=HoplandS' /etc/cmdline && DMAMEM=272M-NO_IOMMU
   grep -q 'sid=HoplandT' /etc/cmdline && DMAMEM=272M-NO_IOMMU
   grep -q 'sid=Nice' /etc/cmdline && DMAMEM=272M-NO_IOMMU
   grep -q 'sid=Graton' /etc/cmdline && DMAMEM=272M-NO_IOMMU
   grep -q 'sid=KnoxvilleStat' /etc/cmdline && DMAMEM=272M-NO_IOMMU
   grep -q 'sid=Talmage' /etc/cmdline && DMAMEM=272M-NO_IOMMU
   grep -q 'sid=Wheatland' /etc/cmdline && DMAMEM=272M-NO_IOMMU
fi

grep -q 'platform=mendocino' /etc/cmdline && DMAMEM=40M-NO_IOMMU # Mendocino
grep -q 'platform=veos' /etc/cmdline && DMAMEM=0M # Virtual EOS
grep -q 'platform=grackle' /etc/cmdline && DMAMEM=128M-NO_IOMMU # Grackle
grep -q 'platform=island' /etc/cmdline && DMAMEM=128M-NO_IOMMU # Island
grep -q 'platform=newport' /etc/cmdline && DMAMEM=128M-NO_IOMMU # Newport
grep -q 'platform=dropbear' /etc/cmdline && DMAMEM=0M # Dropbear
grep -q 'platform=raspberryisland' /etc/cmdline && DMAMEM=128M-NO_IOMMU # Raspberry

if grep -q 'Aboot=Aboot-norcal5' /etc/cmdline; then
   DMAMEM=128M-NO_IOMMU
fi

# BUG80839: set dmesg buf size based on RAM in switch
# This is how we set dmesg buffer size by RAM:
#   RAM    dmesg buffer size
#   -----  ------------------
#   2GB    1MB
#   4GB    2MB
#   8GB    4MB
#  >8GB    8MB
dmesg_buf_size() {
    # /proc/meminfo lists total memory in kB
    tot_mem=`head /proc/meminfo | grep MemTot | tr ' ' '\n' | grep '^[1-9]'`
    tot_mem=$((tot_mem/1024))
    if [ ${tot_mem} -gt 8192 ]; then
       dmesg_len="8M"
    elif [ ${tot_mem} -gt 4096 ]; then
       dmesg_len="4M"
    elif [ ${tot_mem} -gt 2048 ]; then
       dmesg_len="2M"
    else
       dmesg_len="1M"
    fi
    echo $dmesg_len
}

dmesg_buf=$(dmesg_buf_size)
#
# Append log_buf_len *before* we read kernel-params. User may wish to
# specifiy larger log_buf_len or even remove log_buf_len argument (by
# specifying "-log_buf_len" in kernel-params)
#
echo "log_buf_len=${dmesg_buf}" >> /tmp/append

# Configure systemd output
echo "systemd.show_status=0" >> /tmp/append
echo "systemd.default_standard_output=tty" >> /tmp/append

if [ -f "/mnt/flash/${USER_KERNEL_PARAMS}" ]; then
   set_kernel_params "/mnt/flash" <"/mnt/flash/${USER_KERNEL_PARAMS}"
elif [ -f "/tmp/${USER_KERNEL_PARAMS}" ]; then
   set_kernel_params "/tmp" <"/tmp/${USER_KERNEL_PARAMS}"
fi

# override dmamem parameter from USER_KERNEL_PARAMS (if any)
if [ "$DMAMEM" ]; then
   echo "dmamem=$DMAMEM" >> /tmp/append
fi

if [ "$HUGEPAGES" ]; then
   echo "hugepages=$HUGEPAGES" >> /tmp/append
fi
# Fixup block_drive regex to support Linux 3.x, which adds /ataX/ before hostX
sed -i 's#block_drive=pci0000:00/0000:00:11\.0/host\./target\.:0:0/\.\*\$#block_drive=pci0000:00/0000:00:11.0/.*host./target.:0:0/.*$#' /tmp/append

# reassign pci pref mem
if [ -f /tmp/kernel ]; then
   mv /tmp/kernel /tmp/${kernel}
fi

# reassign pci pref mem
reassign_prefmem=0
grep -q 'platform=eaglepeak' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=oldfaithful' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=greatfountain' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=oak' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=crow' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=magpie' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=blackbird' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=rook' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=montara' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=dawson' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=sprucefish' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=sprucefishS' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=woodpecker' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=narwhal' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=penguin' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=belvedere' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=lorikeet' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=surfbird' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=hermosa' /etc/cmdline && reassign_prefmem=1
grep -q 'platform=puffin' /etc/cmdline && reassign_prefmem=1

if [ $reassign_prefmem -eq 1 ]; then
   echo "reassign_prefmem" >> /tmp/append
fi

if [ -f /tmp/bootconf ]; then
   . /tmp/bootconf
fi

# BUG69923: On Crow and Raven ma1 loses its MAC mailbox after kexec from EOS.
# We update MAC reg to hold a copy of MAC mailbox, by bringing up ma1 to indirectly call __tg3_set_mac_addr().
[ "${NETDEV}" ] || NETDEV=ma1

if [ -d "/sys/class/net/${NETDEV}" ]; then
   ip link set ${NETDEV} up 2> /dev/null || true

   # Additionally, pass the MAC address to the new kernel as a command line
   # parameter. This makes it possible to restore the MAC address in the new
   # kernel without requiring driver modifications.
   echo "hwaddr_${NETDEV}=$(cat /sys/class/net/${NETDEV}/address)" >> /tmp/append

   # When we have ipv6 activity, it appears that a driver is
   # (potentially network driver) doing dma into memory even before memory is
   # initialized in EosKernel. This leads to unexpected "corruption" or
   # "Bad page state" warnings in EosKernel. So lets bring down the
   # interface before going into EosKernel
   ip link set ${NETDEV} down 2> /dev/null || true
fi

# run eMMC at 50Mhz on new/old units running EOS with 3.18 kernel
if grep -q 'Aboot=Aboot-norcal4\|Aboot=Aboot-norcal6-6' /etc/cmdline; then
   # SDHCI_QUIRK2_BROKEN_HS200
   echo "sdhci.append_quirks2=0x40" >> /tmp/append
fi

# BUG157642: disable interrupts for i801_smbus driver on Sequoia products
# BUG262701: Force sata to 1.5gpbs
if grep -q 'platform=oak' /etc/cmdline; then
   echo 'i2c-i801.disable_features=0x10' >>/tmp/append
   echo libata.force=1.5 >> /tmp/append
fi

# BUG283868: Enable IOMMU on AMD in the kernel config 
# but disable it by command line parameter 
# Old AMD systems with an Aboot older than version 6.2 (pre-woodpecker) have an
# issue (the IOMMU device is not seen in Linux because the IVRS tables are missing)
# which prevents us from enabling the IOMMU so we disable the IOMMU on
# those systems
if grep -q 'platform=magpie' /etc/cmdline ||
   grep -q 'platform=crow' /etc/cmdline ||
   grep -q 'platform=raven' /etc/cmdline ||
   grep -q 'platform=grackle' /etc/cmdline ||
   grep -q 'platform=island' /etc/cmdline ||
   grep -q 'platform=newport' /etc/cmdline ||
   grep -q 'platform=raspberryisland' /etc/cmdline ||
   grep -q 'platform=mendocino' /etc/cmdline ; then
   echo "amd_iommu=off" >> /tmp/append
else
   echo "amd_iommu_dump=1" >> /tmp/append
fi

# BUG179955: remove noxsave from kernel command line for eos-trunk
sed -i "s/\<noxsave\>//g" /tmp/append

# Tell the stage 1 of Aboot that a password is set for Aboot in the TPM
if [ -f /lib/aboot-utils/secureboot ]; then
   . /lib/aboot-utils/secureboot
   passwd=$( get_tpm_password || : )
   if [ -n "${passwd}" ]; then
      echo 'tpmpwd' >> /tmp/append
   fi

   if securebootctl secureboot -display 2>&1 | grep -qs "enabled"; then
      echo 'sbenabled' >> /tmp/append
   fi
fi

# acpi=on is no longer a valid kernel argument and acpi=off is no longer the default
sed -i "/acpi=on/d" /tmp/append
if grep -q 'Aboot 2\.' /etc/issue; then
   echo "acpi=off" >> /tmp/append
fi

# BUG346109: WoodacrePlus DUT randomly rebooting on Delhi
# Using any C-states but C1 results in instability on WoodacrePlus,
# so revert to pre-Delhi behavior, i.e prevent CPU from going into
# deeper C-states.
if grep -q 'Aboot=Aboot-norcal3' /etc/cmdline; then
   echo 'processor.max_cstate=1' >> /tmp/append
   echo 'intel_idle.max_cstate=1' >> /tmp/append
fi

# BUG524262: Aboot10 - CPU softlockup in cpuidle_enter.
if grep -q 'Aboot=Aboot-norcal10\|Aboot=Aboot-norcal11' /etc/cmdline; then
   echo 'processor.max_cstate=1' >> /tmp/append
fi

# BUG588209: Disable low power mode for NVME drives
echo 'nvme_core.default_ps_max_latency_us=0' >> /tmp/append

# Extend the PCR 8 with kernel parameters
if [ "$(grep 'secureboot' /etc/features 2> /dev/null | sed 's/[^0-9]//g')" -ge "16" ] 2> /dev/null; then
   measureKernelParams
fi
 
kexec --load --initrd=/tmp/initrd-${arch} --append="$(tr '\n' ' ' </tmp/append)" /tmp/${kernel}
[ -z "${testonly}" ] || exit 0

# BUG210500: unmount all filesystems in /mnt before kexec
# note: at this point, images are already in /tmp
for mpt in $(cut -d ' ' -f 2 < /proc/mounts); do
   case "$mpt" in
      /mnt/*) umount "$mpt" ;;
   esac
done

kexec --exec
