Create excelsior-bootloader package

- Takes u-boot, ATF, and optee and generates fip image
- Includes signed bl2.img
- Service to keep fip.bin, bl2.img, and u-boot-env.bin up to date
- Generate u-boot-env.bin

Change-Id: I1cc87e3e2c2c4140b8fe4dca79ec068cae232bc7
diff --git a/boot.txt b/boot.txt
new file mode 100644
index 0000000..c51acd5
--- /dev/null
+++ b/boot.txt
@@ -0,0 +1,3 @@
+setexpr boot_partition ${rootfs_partition} - 1
+ext2load mmc ${mmcdev}:${boot_partition} ${kerneladdr} boot.img
+bootm ${kerneladdr}
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..82be084
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+excelsior-bootloader (1-1) mendel-day; urgency=medium
+
+  * Initial release.
+
+ -- Coral Team <coral-support@google.com>  Wed, 19 Feb 2020 16:26:57 -0800
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..a777cd1
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,14 @@
+Source: excelsior-bootloader
+Section: misc
+Priority: optional
+Maintainer: Coral Team <coral-support@google.com>
+Build-Depends: debhelper (>=10), optee-os, python, tf-a, u-boot, u-boot-mkimage
+Standards-Version: 3.9.8
+Homepage: https://coral.ai
+
+Package: excelsior-bootloader
+Architecture: any
+Depends: ${misc:Depends}
+Description: Bootloaders for Excelsior
+ Bootloaders, boot configuration for
+ Coral MT8516 (Excelsior)
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..dacc16a
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,7 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: excelsior-bootloader
+Source: https://excelsior.googlesource.com/excelsior-bootloader
+
+Files: *
+Copyright: Copyright 2020 Google, LLC <coral-support@google.com>
+License: Apache-2.0
diff --git a/debian/excelsior-bootloader.install b/debian/excelsior-bootloader.install
new file mode 100644
index 0000000..3c29d34
--- /dev/null
+++ b/debian/excelsior-bootloader.install
@@ -0,0 +1 @@
+usr /
diff --git a/debian/excelsior-bootloader.service b/debian/excelsior-bootloader.service
new file mode 100644
index 0000000..2b7b3c6
--- /dev/null
+++ b/debian/excelsior-bootloader.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Excelsior bootloader install service
+
+[Service]
+ExecStart=/usr/sbin/install-bootloader.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..3f6bcdc
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,27 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+#
+# output every command that modifies files on the build system.
+# export DH_VERBOSE = 1
+PACKAGENAME=excelsior-bootloader
+DESTDIR=$(shell pwd)/debian/$(PACKAGENAME)
+
+%:
+	dh $@ --with=systemd
+
+override_dh_auto_build:
+	/usr/bin/fiptool create --soc-fw /usr/share/tf-a/bl31.bin --tos-fw /usr/share/optee-os/tee.bin --nt-fw /usr/share/u-boot/u-boot.bin fip.bin
+	./ubootenv.py -i /usr/share/u-boot/u-boot-initial-env -s 4096 -o u-boot-env.bin
+	/usr/bin/mkimage -A arm -T script -O linux -d boot.txt boot.scr
+
+
+override_dh_auto_install:
+	install -d $(DESTDIR)/boot
+	install -p -m 755 ./fip.bin $(DESTDIR)/boot/fip.bin
+	install -p -m 755 ./u-boot-env.bin $(DESTDIR)/boot/u-boot-env.bin
+	install -p -m 755 ./boot.scr $(DESTDIR)/boot/boot.scr
+	install -p -m 755 ./mt8167-coral/bl2.img $(DESTDIR)/boot/bl2.img
+
+override_dh_installinit:
+override_dh_strip:
+	true
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/mt8167-coral/bl2.img b/mt8167-coral/bl2.img
new file mode 100644
index 0000000..4de34c7
--- /dev/null
+++ b/mt8167-coral/bl2.img
Binary files differ
diff --git a/ubootenv.py b/ubootenv.py
new file mode 100755
index 0000000..5d6675f
--- /dev/null
+++ b/ubootenv.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# Copyright (C) 2019 Fabien Parent <fparent@baylibre.com>
+
+import random
+import zlib
+import struct
+import argparse
+import sys
+
+class UBootEnv:
+    def __init__(self, env_size):
+        self.env = [];
+        self.env_size = env_size
+
+    def __init__(self, env_size, env_file):
+        self.env = [];
+        self.env_size = env_size
+        with open(env_file, "r") as env:
+            self.env = env.readlines()
+
+    def add(self, name, value):
+        self.env.append("{}={}".format(name, value))
+
+    def update(self, name, value):
+        new_env = []
+        for line in self.env:
+            if line.startswith(name + '='):
+                new_env.append("{}={}".format(name, value))
+            else:
+                new_env.append(line)
+        self.env = new_env
+
+    def write_binary(self, filename = "u-boot-env.bin"):
+        with open(filename, "w+b") as out:
+            out.seek(4)
+
+            # Write environment
+            for line in self.env:
+                if line == '\n':
+                    continue
+                data = line.rstrip("\n").encode() + b'\0'
+                out.write(data)
+
+            while out.tell() < self.env_size:
+                out.write(chr(0x00))
+
+            # Compute CRC
+            out.seek(4)
+            crc = zlib.crc32(out.read(self.env_size - 4)) & 0xffffffff
+
+            # Write CRC
+            out.seek(0)
+            out.write(struct.pack("I", crc))
+
+    def gen_mac_addr(self, oui, num_iface):
+        for i in range(num_iface):
+            macaddr =  "{}:{:02X}:{:02X}:{:02X}".format(
+                            oui,
+                            random.randint(0, 255),
+                            random.randint(0, 255),
+                            random.randint(0, 255))
+            varname = "eth{}addr".format(i)
+            if i == 0:
+                varname = "ethaddr"
+            self.add(varname, macaddr)
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-i', '--input', default = "u-boot-initial-env",
+                        help = 'Path to U-boot environment file')
+    parser.add_argument('-s', '--size', default = 4096, type = int,
+                        help = 'Size of the U-boot environment file')
+    parser.add_argument('-o', '--output', default = "u-boot-env.bin",
+                         help = 'Path to U-boot binary environment')
+    parser.add_argument('--oui',
+                        help = 'OUI to use when generating MAC addresses')
+    parser.add_argument('--num-ethaddr', default = 0, type = int,
+                        help = "Number of ethaddr to add to the environment")
+    args = parser.parse_args()
+
+    print("Initial environment: {}".format(args.input))
+    print("Binary output environment: {}".format(args.output))
+    print("OUI: {}".format(args.oui))
+    print("Size: {}".format(args.size))
+
+    if args.num_ethaddr > 0 and args.oui == None:
+        sys.stderr.write("\nerror: --oui must be specified when --num-ethaddr is set\n")
+        parser.print_help(sys.stderr)
+        sys.exit(1)
+
+    env = UBootEnv(args.size, args.input)
+    if args.num_ethaddr > 0:
+        env.gen_mac_addr(args.oui, args.num_ethaddr)
+    env.write_binary(args.output)
diff --git a/usr/sbin/install-bootloader.sh b/usr/sbin/install-bootloader.sh
new file mode 100755
index 0000000..cb14d8b
--- /dev/null
+++ b/usr/sbin/install-bootloader.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+# $1 -- Filesystem path
+# $2 -- Block device
+function check_emmc_matches {
+  local CURRENT=$(mktemp)
+  local SIZE=$(stat -c%s $1)
+  dd if=/dev/$2 of=${CURRENT} \
+    count=${SIZE} \
+    bs=512 \
+    iflag=count_bytes
+  diff ${CURRENT} $1
+  local DIFF_RETURN_CODE=$?
+  rm ${CURRENT}
+  echo ${DIFF_RETURN_CODE}
+}
+
+# $1 -- Filesystem path
+# $2 -- Block device
+function write_emmc {
+  for i in `seq 1 5`
+  do
+    dd if=$1 of=/dev/$2 bs=512
+    local EMMC_MATCHES=$(check_emmc_matches $1 $2)
+    if [[ ${EMMC_MATCHES} -eq 0 ]]; then
+      UPDATE_SUCCESS=true
+      break
+    fi
+  done
+  echo ${UPDATE_SUCCESS}
+}
+
+BL2_MATCHES=$(check_emmc_matches /boot/bl2.img mmcblk0boot0)
+FIP_BIN_MATCHES=$(check_emmc_matches /boot/fip.bin mmcblk0p1)
+U_BOOT_ENV_MATCHES=$(check_emmc_matches /boot/u-boot-env.bin mmcblk0boot1)
+
+if [[ ${BL2_MATCHES} -ne 0 ]]; then
+  MMCBLK_RO_PATH=/sys/block/mmcblk0boot0/force_ro
+
+  # Get the read-only setting for the bootloader
+  MMCBLK_RO=$(cat ${MMCBLK_RO_PATH})
+
+  # Disable read-only on bootloader block device
+  echo 0 > ${MMCBLK_RO_PATH}
+
+  UPDATE_SUCCESS=$(write_emmc /boot/bl2.img mmcblk0boot0)
+
+  # Restore whatever the setting was before
+  echo ${MMCBLK_RO} > ${MMCBLK_RO_PATH}
+
+  if [[ "${UPDATE_SUCCESS}" != true ]]; then
+    echo "Failed to update bl2! Rebooting is unsafe!"
+    exit 1
+  fi
+fi
+
+if [[ ${FIP_BIN_MATCHS} -ne 0 ]]; then
+  UPDATE_SUCCESS=$(write_emmc /boot/fip.bin mmcblk0p1)
+  if [[ "${UPDATE_SUCCESS}" != true ]]; then
+    echo "Failed to update fip.bin! Rebooting is unsafe!"
+    exit 1
+  fi
+fi
+
+if [[ ${U_BOOT_ENV_MATCHS} -ne 0 ]]; then
+  UPDATE_SUCCESS=$(write_emmc /boot/u-boot-env.bin mmcblk0boot1)
+  if [[ "${UPDATE_SUCCESS}" != true ]]; then
+    echo "Failed to update u-boot-env.bin! Rebooting is unsafe!"
+    exit 1
+  fi
+fi