hikey: Add wrapper script to build uefi

Booloader sources are located under device/linaro/bootloader

Change-Id: I8b35f9a292f5037eac2e0a281f5345921a313b93
Signed-off-by: Vishal Bhoj <vishal.bhoj@linaro.org>
diff --git a/bootloader/Makefile b/bootloader/Makefile
new file mode 100644
index 0000000..4d0f031
--- /dev/null
+++ b/bootloader/Makefile
@@ -0,0 +1,29 @@
+AARCH64_TOOLCHAIN=GCC49
+EDK2_DIR=$(ANDROID_BUILD_TOP)/device/linaro/bootloader/edk2
+UEFI_TOOLS_DIR=$(ANDROID_BUILD_TOP)/device/linaro/hikey/uefi-tools
+ATF_DIR=$(ANDROID_BUILD_TOP)/device/linaro/bootloader/arm-trusted-firmware
+PRODUCT_OUT?=out/target/product/hikey
+DIST_DIR?=$(ANDROID_BUILD_TOP)/out/dist
+
+all: $(DIST_DIR)/fip.bin $(DIST_DIR)/l-loader.bin
+
+$(DIST_DIR)/fip.bin:
+	cd $(EDK2_DIR) && \
+	rm -rf Conf/tools_def.txt Conf/BuildEnv.sh  Conf/build_rule.txt Conf/target.txt  Conf/tools_def.txt && \
+	export CROSS_COMPILE_32=arm-linux-androideabi- && \
+	export CROSS_COMPILE_64=aarch64-linux-android- && \
+	rm -rf OpenPlatformPkg && \
+	ln -sf  $(EDK2_DIR)/../OpenPlatformPkg OpenPlatformPkg && \
+	rm -rf $(EDK2_DIR)/Build/  && \
+	mkdir -p $(EDK2_DIR)/Build/ && \
+	mkdir -p $(DIST_DIR) && \
+	mkdir -p $(ANDROID_BUILD_TOP)/$(PRODUCT_OUT)/obj/uefi && \
+	ln -sf $(ANDROID_BUILD_TOP)/$(PRODUCT_OUT)/obj/uefi $(EDK2_DIR)/Build/HiKey && \
+	$(UEFI_TOOLS_DIR)/uefi-build.sh -b RELEASE -D EDK2_OUT_DIR=$(ANDROID_BUILD_TOP)/$(PRODUCT_OUT)/obj/uefi -a $(ATF_DIR) hikey && \
+	cp $(EDK2_DIR)/Build/HiKey/RELEASE_GCC49/FV/fip.bin $(DIST_DIR)/
+
+$(DIST_DIR)/l-loader.bin: $(DIST_DIR)/fip.bin
+	cd $(ANDROID_BUILD_TOP)/device/linaro/hikey/l-loader && \
+	ln -sf $(EDK2_DIR)/Build/HiKey/RELEASE_GCC49/FV//bl1.bin && \
+	make CROSS_COMPILE=arm-linux-androideabi- l-loader.bin && \
+	mv l-loader.bin $(DIST_DIR)/
diff --git a/bootloader/README.md b/bootloader/README.md
new file mode 100644
index 0000000..1271cfd
--- /dev/null
+++ b/bootloader/README.md
@@ -0,0 +1,10 @@
+Bootloader is build with ArmTF and UEFI from sources located at:
+  device/linaro/bootloader
+To build fip.bin and l-loader.bin do:
+  $ cd device/linaro/hikey/bootloader
+  $ make
+Results will be in out/dist
+
+We can also generate ptable (needs root privilege) with below commands:
+  $ cd device/linaro/hikey/l-loader/
+  $ make ptable.img
diff --git a/l-loader/.gitignore b/l-loader/.gitignore
new file mode 100644
index 0000000..b282a0e
--- /dev/null
+++ b/l-loader/.gitignore
@@ -0,0 +1,3 @@
+/*.o
+/*.img
+/*.bin
diff --git a/l-loader/COPYING b/l-loader/COPYING
new file mode 100644
index 0000000..4ad3f20
--- /dev/null
+++ b/l-loader/COPYING
@@ -0,0 +1,25 @@
+Copyright (c) 2014-2016, Linaro Ltd. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/l-loader/Makefile b/l-loader/Makefile
new file mode 100644
index 0000000..93afcd1
--- /dev/null
+++ b/l-loader/Makefile
@@ -0,0 +1,27 @@
+CROSS_COMPILE?=arm-linux-gnueabihf-
+CC=$(CROSS_COMPILE)gcc
+CFLAGS=-march=armv7-a
+LD=$(CROSS_COMPILE)ld
+OBJCOPY=$(CROSS_COMPILE)objcopy
+BL1=bl1.bin
+PTABLE_LST:=aosp-4g aosp-8g linux-4g linux-8g
+
+all: l-loader.bin ptable.img
+
+%.o: %.S $(DEPS)
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+l-loader.bin: start.o $(BL1)
+	$(LD) -Bstatic -Tl-loader.lds -Ttext 0xf9800800 start.o -o loader
+	$(OBJCOPY) -O binary loader temp
+	python gen_loader.py -o $@ --img_loader=temp --img_bl1=$(BL1)
+	rm -f loader temp
+
+ptable.img:
+	for ptable in $(PTABLE_LST); do \
+		sudo PTABLE=$${ptable} bash -x generate_ptable.sh;\
+		python gen_loader.py -o ptable-$${ptable}.img --img_prm_ptable=prm_ptable.img;\
+	done
+
+clean:
+	rm -f *.o *.img l-loader.bin
diff --git a/l-loader/README.md b/l-loader/README.md
new file mode 100644
index 0000000..e5dcd99
--- /dev/null
+++ b/l-loader/README.md
@@ -0,0 +1,6 @@
+# l-loader
+
+Used to switch from aarch32 to aarch64 and boot. First image to be flashed
+when in recovery mode.
+
+HiKey specific.
diff --git a/l-loader/gen_loader.py b/l-loader/gen_loader.py
new file mode 100755
index 0000000..2d763ca
--- /dev/null
+++ b/l-loader/gen_loader.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env python
+
+import os
+import os.path
+import sys, getopt
+import binascii
+import struct
+import string
+
+class generator(object):
+    #
+    # struct l_loader_head {
+    #      unsigned int	first_instr;
+    #      unsigned char	magic[16];	@ BOOTMAGICNUMBER!
+    #      unsigned int	l_loader_start;
+    #      unsigned int	l_loader_end;
+    # };
+    file_header = [0, 0, 0, 0, 0, 0, 0]
+
+    #
+    # struct entry_head {
+    #       unsigned char   magic[8];           @ ENTY
+    #       unsigned char   name[8];            @ loader/bl1
+    #       unsigned int    start_lba;
+    #       unsigned int    count_lba;
+    #       unsigned int    flag;               @ boot partition or not
+    # };
+
+    s1_entry_name = ['loader', 'bl1']
+    s2_entry_name = ['primary', 'second']
+
+    block_size = 512
+
+    stage = 0
+
+    # set in self.add()
+    idx = 0
+
+    # set in self.parse()
+    ptable_lba = 0
+    stable_lba = 0
+
+    # file pointer
+    p_entry = 0
+    p_file = 0
+
+    def __init__(self, out_img):
+        try:
+            self.fp = open(out_img, "wb+")
+        except IOError, e:
+            print "*** file open error:", e
+            sys.exit(3)
+        else:
+            self.entry_hd = [[0 for col in range(7)] for row in range(5)]
+
+    def __del__(self):
+        self.fp.close()
+
+    # parse partition from the primary ptable
+    def parse(self, fname):
+        try:
+            fptable = open(fname, "rb")
+        except IOError, e:
+            print "*** file open error:", e
+            sys.exit(3)
+        else:
+            # skip the first block in primary partition table
+            # that is MBR protection information
+            fptable.read(self.block_size)
+            # check whether it's a primary paritition table
+            data = struct.unpack("8s", fptable.read(8))
+            efi_magic = 'EFI PART'
+            if cmp("EFI PART", data[0]):
+                print "It's not partition table image."
+                fptable.close()
+                sys.exit(4)
+            # skip 16 bytes
+            fptable.read(16)
+            # get lba of both primary partition table and secondary partition table
+            data = struct.unpack("QQQQ", fptable.read(32))
+            self.ptable_lba = data[0] - 1
+            self.stable_lba = data[3] + 1
+            # skip 24 bytes
+            fptable.read(24)
+            data = struct.unpack("i", fptable.read(4))
+            pentries = data[0]
+            # skip the reset in this block
+            fptable.read(self.block_size - 84)
+
+            for i in range(1, pentries):
+                # name is encoded as UTF-16
+                d0,lba,d2,name = struct.unpack("32sQ16s72s", fptable.read(128))
+                plainname = unicode(name, "utf-16")
+                if (not cmp(plainname[0:7], 'l-loader'[0:7])):
+                    print 'bl1_lba: ', lba
+                    self.bl1_lba = lba
+                    sys.exit(1)
+
+            fptable.close()
+
+    def add(self, lba, fname):
+        try:
+            fsize = os.path.getsize(fname)
+        except IOError, e:
+            print "*** file open error:", e
+            sys.exit(4)
+        else:
+            blocks = (fsize + self.block_size - 1) / self.block_size
+            if (self.stage == 1):
+                # Boot Area1 in eMMC
+                bootp = 1
+                if self.idx == 0:
+                    self.p_entry = 28
+            elif (self.stage == 2):
+                # User Data Area in eMMC
+                bootp = 0
+                # create an empty block only for stage2
+                # This empty block is used to store entry head
+                print 'p_file: ', self.p_file, 'p_entry: ', self.p_entry
+                if self.idx == 0:
+                    self.fp.seek(self.p_file)
+                    for i in range (0, self.block_size):
+                        zero = struct.pack('x')
+                        self.fp.write(zero)
+                    self.p_file += self.block_size
+                    self.p_entry = 0
+            else:
+                print "wrong stage ", stage, "is specified"
+                sys.exit(4)
+            # Maybe the file size isn't aligned. So pad it.
+            if (self.idx == 0) and (self.stage == 1):
+                if fsize > 2048:
+                    print 'loader size exceeds 2KB. file size: ', fsize
+                    sys.exit(4)
+                else:
+                    left_bytes = 2048 - fsize
+            else:
+                left_bytes = fsize % self.block_size
+                if left_bytes:
+                    left_bytes = self.block_size - left_bytes
+            print 'lba: ', lba, 'blocks: ', blocks, 'bootp: ', bootp, 'fname: ', fname
+            # write images
+            fimg = open(fname, "rb")
+            for i in range (0, blocks):
+                buf = fimg.read(self.block_size)
+                self.fp.seek(self.p_file)
+                self.fp.write(buf)
+                # p_file is the file pointer of the new binary file
+                # At last, it means the total block size of the new binary file
+                self.p_file += self.block_size
+
+            if (self.idx == 0) and (self.stage == 1):
+                self.p_file = 2048
+            print 'p_file: ', self.p_file, 'last block is ', fsize % self.block_size, 'bytes', '  tell: ', self.fp.tell(), 'left_bytes: ', left_bytes
+            if left_bytes:
+                for i in range (0, left_bytes):
+                    zero = struct.pack('x')
+                    self.fp.write(zero)
+                print 'p_file: ', self.p_file, '  pad to: ', self.fp.tell()
+
+            # write entry information at the header
+            if self.stage == 1:
+                byte = struct.pack('8s8siii', 'ENTRYHDR', self.s1_entry_name[self.idx], lba, blocks, bootp)
+            elif self.stage == 2:
+                byte = struct.pack('8s8siii', 'ENTRYHDR', self.s2_entry_name[self.idx], lba, blocks, bootp)
+            self.fp.seek(self.p_entry)
+            self.fp.write(byte)
+            self.p_entry += 28
+            self.idx += 1
+
+            fimg.close()
+
+    def hex2(self, data):
+        return data > 0 and hex(data) or hex(data & 0xffffffff)
+
+    def end(self):
+        if self.stage == 1:
+            self.fp.seek(20)
+            start,end = struct.unpack("ii", self.fp.read(8))
+            print "start: ", self.hex2(start), 'end: ', self.hex2(end)
+            end = start + self.p_file
+            print "start: ", self.hex2(start), 'end: ', self.hex2(end)
+            self.fp.seek(24)
+            byte = struct.pack('i', end)
+            self.fp.write(byte)
+        self.fp.close()
+
+    def create_stage1(self, img_loader, img_bl1, output_img):
+        print '+-----------------------------------------------------------+'
+        print ' Input Images:'
+        print '     loader:                       ', img_loader
+        print '     bl1:                          ', img_bl1
+        print ' Ouput Image:                      ', output_img
+        print '+-----------------------------------------------------------+\n'
+
+        self.stage = 1
+
+        # The first 2KB is reserved
+        # The next 2KB is for loader image
+        self.add(4, img_loader)    # img_loader doesn't exist in partition table
+        print 'self.idx: ', self.idx
+        # bl1.bin starts from 4KB
+        self.add(8, img_bl1)      # img_bl1 doesn't exist in partition table
+
+    def create_stage2(self, img_prm_ptable, img_sec_ptable, output_img):
+        print '+-----------------------------------------------------------+'
+        print ' Input Images:'
+        print '     primary partition table:      ', img_prm_ptable
+        print '     secondary partition table:    ', img_sec_ptable
+        print ' Ouput Image:                      ', output_img
+        print '+-----------------------------------------------------------+\n'
+
+        self.stage = 2
+        self.parse(img_prm_ptable)
+        self.add(self.ptable_lba, img_prm_ptable)
+        if (cmp(img_sec_ptable, 'secondary partition table')):
+            # Doesn't match. It means that secondary ptable is specified.
+            self.add(self.stable_lba, img_sec_ptable)
+        else:
+            print 'Don\'t need secondary partition table'
+
+def main(argv):
+    stage1 = 0
+    stage2 = 0
+    img_prm_ptable = "primary partition table"
+    img_sec_ptable = "secondary partition table"
+    try:
+        opts, args = getopt.getopt(argv,"ho:",["img_loader=","img_bl1=","img_prm_ptable=","img_sec_ptable="])
+    except getopt.GetoptError:
+        print 'gen_loader.py -o <l-loader.bin> --img_loader <l-loader> --img_bl1 <bl1.bin> --img_prm_ptable <prm_ptable.img> --img_sec_ptable <sec_ptable.img>'
+        sys.exit(2)
+    for opt, arg in opts:
+        if opt == '-h':
+            print 'gen_loader.py -o <l-loader.bin> --img_loader <l-loader> --img_bl1 <bl1.bin> --img_prm_ptable <prm_ptable.img> --img_sec_ptable <sec_ptable.img>'
+            sys.exit(1)
+        elif opt == '-o':
+            output_img = arg
+        elif opt in ("--img_loader"):
+            img_loader = arg
+            stage1 = 1
+        elif opt in ("--img_bl1"):
+            img_bl1 = arg
+            stage1 = 1
+        elif opt in ("--img_prm_ptable"):
+            img_prm_ptable = arg
+            stage2 = 1
+        elif opt in ("--img_sec_ptable"):
+            img_sec_ptable = arg
+
+    loader = generator(output_img)
+    loader.idx = 0
+
+    if (stage1 == 1) and (stage2 == 1):
+        print 'There are only loader & BL1 in stage1.'
+        print 'And there are primary partition table, secondary partition table and FIP in stage2.'
+        sys.exit(1)
+    elif (stage1 == 0) and (stage2 == 0):
+        print 'No input images are specified.'
+        sys.exit(1)
+    elif stage1 == 1:
+        loader.create_stage1(img_loader, img_bl1, output_img)
+    elif stage2 == 1:
+        loader.create_stage2(img_prm_ptable, img_sec_ptable, output_img)
+
+    loader.end()
+
+if __name__ == "__main__":
+    main(sys.argv[1:])
diff --git a/l-loader/generate_ptable.sh b/l-loader/generate_ptable.sh
new file mode 100755
index 0000000..3bc232e
--- /dev/null
+++ b/l-loader/generate_ptable.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Generate partition table for HiKey eMMC
+#
+# tiny: for testing purpose.
+# aosp: 10 entries (same as linux with userdata).
+# linux: 9 entries (same as aosp without userdata).
+
+PTABLE=${PTABLE:-aosp}
+SECTOR_SIZE=512
+TEMP_FILE=$(mktemp /tmp/${PTABLE}.XXXXXX)
+
+case ${PTABLE} in
+  tiny)
+    SECTOR_NUMBER=81920
+    ;;
+  aosp-4g|linux-4g)
+    SECTOR_NUMBER=7471104
+    ;;
+  aosp-8g|linux-8g)
+    SECTOR_NUMBER=15269888
+    ;;
+esac
+
+BK_PTABLE_LBA=$(expr ${SECTOR_NUMBER} - 33)
+echo ${BK_PTABLE_LBA}
+
+# get the partition table
+case ${PTABLE} in
+  tiny)
+    dd if=/dev/zero of=${TEMP_FILE} bs=${SECTOR_SIZE} count=${SECTOR_NUMBER}
+    sgdisk -U -R -v ${TEMP_FILE}
+    sgdisk -n 1:2048:4095 -t 1:0700 -u 1:F9F21F01-A8D4-5F0E-9746-594869AEC3E4 -c 1:"vrl" -p ${TEMP_FILE}
+    sgdisk -n 2:4096:6143 -t 2:0700 -u 2:F9F21F02-A8D4-5F04-9746-594869AEC3E4 -c 2:"vrl_backup" -p ${TEMP_FILE}
+    ;;
+  aosp*)
+    dd if=/dev/zero of=${TEMP_FILE} bs=${SECTOR_SIZE} count=${SECTOR_NUMBER}
+    sgdisk -U 2CB85345-6A91-4043-8203-723F0D28FBE8 -v ${TEMP_FILE}
+    #[1: vrl: 1M-2M]
+    sgdisk -n 1:0:+1M -t 1:0700 -u 1:496847AB-56A1-4CD5-A1AD-47F4ACF055C9 -c 1:"vrl" ${TEMP_FILE}
+    #[2: vrl_backup: 2M-3M]
+    sgdisk -n 2:0:+1M -t 2:0700 -u 2:61A36FC1-8EFB-4899-84D8-B61642EFA723 -c 2:"vrl_backup" ${TEMP_FILE}
+    #[3: mcuimage: 3M-4M]
+    sgdisk -n 3:0:+1M -t 3:0700 -u 3:65007411-962D-4781-9B2C-51DD7DF22CC3 -c 3:"mcuimage" ${TEMP_FILE}
+    #[4: fastboot: 4M-12M]
+    sgdisk -n 4:0:+8M -t 4:EF02 -u 4:496847AB-56A1-4CD5-A1AD-47F4ACF055C9 -c 4:"fastboot" ${TEMP_FILE}
+    #[5: nvme: 12M-14M]
+    sgdisk -n 5:0:+2M -t 5:0700 -u 5:00354BCD-BBCB-4CB3-B5AE-CDEFCB5DAC43 -c 5:"nvme" ${TEMP_FILE}
+    #[6: boot: 14M-78M]
+    sgdisk -n 6:0:+64M -t 6:EF00 -u 6:5C0F213C-17E1-4149-88C8-8B50FB4EC70E -c 6:"boot" ${TEMP_FILE}
+    #[7: reserved: 78M-334M]
+    sgdisk -n 7:0:+256M -t 7:0700 -u 7:BED8EBDC-298E-4A7A-B1F1-2500D98453B7 -c 7:"reserved" ${TEMP_FILE}
+    #[8: cache: 334M-590M]
+    sgdisk -n 8:0:+256M -t 8:8301 -u 8:A092C620-D178-4CA7-B540-C4E26BD6D2E2 -c 8:"cache" ${TEMP_FILE}
+    #[9: system: 590M-2126M]
+    sgdisk -n 9:0:+1536M -t 9:8300 -u 9:FC56E345-2E8E-49AE-B2F8-5B9D263FE377 -c 9:"system" ${TEMP_FILE}
+    #[10: userdata: 2126M-End]
+    sgdisk -n -E -t 10:8300 -u 10:064111F6-463B-4CE1-876B-13F3684CE164 -c 10:"userdata" -p ${TEMP_FILE}
+    ;;
+  linux*)
+    dd if=/dev/zero of=${TEMP_FILE} bs=${SECTOR_SIZE} count=${SECTOR_NUMBER}
+    sgdisk -U 2CB85345-6A91-4043-8203-723F0D28FBE8 -v ${TEMP_FILE}
+    #[1: vrl: 1M-2M]
+    sgdisk -n 1:0:+1M -t 1:0700 -u 1:496847AB-56A1-4CD5-A1AD-47F4ACF055C9 -c 1:"vrl" ${TEMP_FILE}
+    #[2: vrl_backup: 2M-3M]
+    sgdisk -n 2:0:+1M -t 2:0700 -u 2:61A36FC1-8EFB-4899-84D8-B61642EFA723 -c 2:"vrl_backup" ${TEMP_FILE}
+    #[3: mcuimage: 3M-4M]
+    sgdisk -n 3:0:+1M -t 3:0700 -u 3:65007411-962D-4781-9B2C-51DD7DF22CC3 -c 3:"mcuimage" ${TEMP_FILE}
+    #[4: fastboot: 4M-12M]
+    sgdisk -n 4:0:+8M -t 4:EF02 -u 4:496847AB-56A1-4CD5-A1AD-47F4ACF055C9 -c 4:"fastboot" ${TEMP_FILE}
+    #[5: nvme: 12M-14M]
+    sgdisk -n 5:0:+2M -t 5:0700 -u 5:00354BCD-BBCB-4CB3-B5AE-CDEFCB5DAC43 -c 5:"nvme" ${TEMP_FILE}
+    #[6: boot: 14M-78M]
+    sgdisk -n 6:0:+64M -t 6:EF00 -u 6:5C0F213C-17E1-4149-88C8-8B50FB4EC70E -c 6:"boot" ${TEMP_FILE}
+    #[7: reserved: 78M-334M]
+    sgdisk -n 7:0:+256M -t 7:0700 -u 7:BED8EBDC-298E-4A7A-B1F1-2500D98453B7 -c 7:"reserved" ${TEMP_FILE}
+    #[8: cache: 334M-590M]
+    sgdisk -n 8:0:+256M -t 8:8301 -u 8:A092C620-D178-4CA7-B540-C4E26BD6D2E2 -c 8:"cache" ${TEMP_FILE}
+    #[9: system: 590M-End]
+    sgdisk -n -E -t 9:8300 -u 9:FC56E345-2E8E-49AE-B2F8-5B9D263FE377 -c 9:"system" ${TEMP_FILE}
+    ;;
+esac
+
+# get the main and the backup parts of the partition table
+dd if=${TEMP_FILE} of=prm_ptable.img bs=${SECTOR_SIZE} count=34
+dd if=${TEMP_FILE} of=sec_ptable.img skip=${BK_PTABLE_LBA} bs=${SECTOR_SIZE} count=33
+
+rm -f ${TEMP_FILE}
diff --git a/l-loader/l-loader.lds b/l-loader/l-loader.lds
new file mode 100644
index 0000000..41eb16f
--- /dev/null
+++ b/l-loader/l-loader.lds
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+	. = 0xf9800800;
+	LLOADER_START = .;
+
+	.text :
+	{
+		*(.text)
+		*(.rodata)
+	}
+
+	.data ALIGN(4):
+	{
+		*(.data)
+	}
+
+	. = ALIGN(4);
+
+	.bss ALIGN(4):
+	{
+		*(.bss)
+	}
+
+	LLOADER_BL1_BIN = 0xf9801000;
+}
diff --git a/l-loader/start.S b/l-loader/start.S
new file mode 100644
index 0000000..a0d838a
--- /dev/null
+++ b/l-loader/start.S
@@ -0,0 +1,100 @@
+	.text
+
+/*
+ * The head of l-loader is defined in below.
+ * struct l_loader_head {
+ *	unsigned int	first_instr;
+ *	unsigned char	magic[16];	@ BOOTMAGICNUMBER!
+ *	unsigned int	l_loader_start;
+ *	unsigned int	l_loader_end;
+ * };
+ */
+
+#define CPU0_CTRL_OFFSET		0x100
+#define CPU7_CTRL_OFFSET		0x800
+#define CPU0_RVBARADDR_OFFSET		0x158
+#define CPU7_RVBARADDR_OFFSET		0x858
+
+#define CPU_CTRL_AARCH64_MODE		(1 << 7)
+
+#define SC_PERIPH_CLKEN3		0x230
+#define SC_PERIPH_RSTDIS3		0x334
+	.global	_start
+_start:
+	b	reset
+@ Android magic number: "BOOTMAGICNUMBER!"
+android_magic:
+	.word	0x544f4f42
+	.word	0x4947414d
+	.word	0x4d554e43
+	.word	0x21524542
+	.word	LLOADER_START		@ LLOADER_START in RAM
+	.word	0			@ LLOADER_END in RAM
+
+entries:
+	@ 5 entries with 7 words
+	.space	140
+
+	.align	7
+
+reset:
+	ldr	r8, =(0xf9800000 + 0x700)
+	str	r0, [r8]		@ download mode (1:usb,2:uart,0:boot)
+
+	ldr	r4, =0xf6504000		@ ACPU_CTRL register base
+	@ set RVBAR for cpu0
+	ldr	r5, =CPU0_RVBARADDR_OFFSET
+	ldr	r6, =LLOADER_BL1_BIN
+	mov	r6, r6, lsr #2
+	str	r6, [r4, r5]
+1:
+	ldr	r0, [r4, r5]
+	cmp	r0, r6
+	bne	1b
+
+	mov	r5, #CPU0_CTRL_OFFSET
+	mov	r6, #CPU7_CTRL_OFFSET
+2:
+	ldr	r0, [r4, r5]		@ Load ACPU_SC_CPUx_CTRL
+	orr	r0, r0, #CPU_CTRL_AARCH64_MODE
+	str	r0, [r4, r5]		@ Save to ACPU_SC_CPUx_CTRL
+	ldr	r0, [r4, r5]
+
+	add	r5, r5, #0x100		@ Iterate ACPU_SC_CPUx_CTRL
+	cmp	r5, r6
+	ble	2b
+
+	/*
+	 * Prepare UART2 & UART3 without baud rate initialization.
+	 * So always output on UART0 in l-loader.
+	 */
+	ldr	r4, =0xf70100e0		@ UART2_RXD IOMG register
+	mov	r0, #0
+	str	r0, [r4]
+	str	r0, [r4, #4]		@ UART2_TXD IOMG register
+	ldr	r0, [r4]
+
+	ldr	r4, =0xf7010188		@ UART3_RXD IOMG register
+	mov	r0, #1
+	str	r0, [r4]
+	str	r0, [r4, #4]		@ UART3_TXD IOMG register
+	ldr	r1, [r4]
+
+	ldr	r4, =0xf7030000		@ PERI_CTRL register base
+	@ By default, CLK_TXCO is the parent of CLK_UART3 in SC_CLK_SEL0
+
+	ldr	r5, =SC_PERIPH_RSTDIS3	@ unreset
+	ldr	r6, =SC_PERIPH_CLKEN3	@ enable PCLK
+	mov	r0, #(3 << 6)		@ bit'6' & bit'7' (UART2 & UART3)
+	str	r0, [r4, r5]
+	str	r0, [r4, r6]
+
+	@ execute warm reset to switch aarch64
+	mov	r2, #3
+	mcr	p15, 0, r2, c12, c0, 2
+	wfi
+panic:
+	b	panic
+
+str_aarch64:
+	.asciz	"\nSwitch to aarch64 mode. CPU0 executes at 0x"
diff --git a/uefi-tools/atf-build.sh b/uefi-tools/atf-build.sh
new file mode 100755
index 0000000..0c4c09c
--- /dev/null
+++ b/uefi-tools/atf-build.sh
@@ -0,0 +1,222 @@
+#!/bin/bash
+#
+# Builds ARM Trusted Firmware, and generates FIPs with UEFI and optionally
+# Trusted OS for the supported platforms.
+# Not intended to be called directly, invoked from uefi-build.sh.
+#
+# Board configuration is extracted from
+# parse-platforms.py and platforms.config.
+#
+
+TOOLS_DIR="`dirname $0`"
+. "$TOOLS_DIR"/common-functions
+OUTPUT_DIR="$PWD"/uefi-build
+
+ATF_BUILDVER=1
+
+function usage
+{
+	echo "usage:"
+	echo "atf-build.sh -e <EDK2 source directory> -t <UEFI build profile/toolchain> <platform>"
+	echo
+}
+
+function check_atf_buildver
+{
+	MAJOR=`grep "^VERSION_MAJOR" Makefile | sed 's/.*:= *\([0-9]*\).*/\1/'`
+	[ $? -ne 0 ] && return 1
+	MINOR=`grep "^VERSION_MINOR" Makefile | sed 's/.*:= *\([0-9]*\).*/\1/'`
+	[ $? -ne 0 ] && return 1
+
+	if [ "$MAJOR" -eq 1 -a "$MINOR" -ge 2 ]; then
+		ATF_BUILDVER=2
+	fi
+}
+
+function build_platform
+{
+	if [ X"$EDK2_DIR" = X"" ];then
+		echo "EDK2_DIR not set!" >&2
+		return 1
+	fi
+
+	check_atf_buildver || return 1
+
+	BUILD_ATF="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o build_atf`"
+	if [ X"$BUILD_ATF" = X"" ]; then
+		echo "Platform '$1' is not configured to build ARM Trusted Firmware."
+		return 0
+	fi
+
+	ATF_PLATFORM="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o atf_platform`"
+	if [ X"$ATF_PLATFORM" = X"" ]; then
+		ATF_PLATFORM=$1
+	fi
+
+	#
+	# Read platform configuration
+	#
+	PLATFORM_NAME="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o longname`"
+	PLATFORM_ARCH="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o arch`"
+	PLATFORM_IMAGE_DIR="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o uefi_image_dir`"
+	PLATFORM_BUILDFLAGS="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o atf_buildflags`"
+
+	if [ $VERBOSE -eq 1 ]; then
+		echo "PLATFORM_NAME=$PLATFORM_NAME"
+		echo "PLATFORM_ARCH=$PLATFORM_ARCH"
+		echo "PLATFORM_IMAGE_DIR=$PLATFORM_IMAGE_DIR"
+		echo "PLATFORM_BUILDFLAGS=$PLATFORM_BUILDFLAGS"
+	fi
+
+	unset BL30 BL31 BL32 BL33
+	BL30="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o scp_bin`"
+	if [ $ATF_BUILDVER -gt 1 ]; then
+		unset SCP_BL2
+		SCP_BL2="$EDK2_DIR/$BL30"
+	fi
+	BL31="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o el3_bin`"
+	BL33="$EDK2_DIR/Build/$PLATFORM_IMAGE_DIR/$BUILD_PROFILE/FV/`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o uefi_bin`"
+
+	#
+	# Set up cross compilation variables (if applicable)
+	#
+	set_cross_compile
+	CROSS_COMPILE="$TEMP_CROSS_COMPILE"
+	echo "Building ARM Trusted Firmware for $PLATFORM_NAME - $BUILD_PROFILE"
+	echo "CROSS_COMPILE=\"$TEMP_CROSS_COMPILE\""
+
+	if [ X"$BL30" != X"" ]; then
+		BL30="${EDK2_DIR}"/"${BL30}"
+	fi
+	if [ X"$BL31" != X"" ]; then
+		BL31="${EDK2_DIR}"/"${BL31}"
+	fi
+
+	#
+	# BL32 requires more attention
+	# If TOS_DIR is not set, we assume user does not want a Trusted OS,
+	# even if the source directory and/or binary for it exists
+	#
+	if [ X"$TOS_DIR" != X"" ]; then
+		SPD="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o atf_spd`"
+
+		TOS_BIN="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o tos_bin`"
+		if [ X"$TOS_BIN" != X"" ]; then
+			BL32=$EDK2_DIR/Build/$PLATFORM_IMAGE_DIR/$BUILD_PROFILE/FV/$TOS_BIN
+		fi
+
+		if [ X"$SPD" != X"" ] && [ X"$BL32" != X"" ]; then
+			#
+			# Since SPD cannot be exported or undefined,
+			# we parametrise it here
+			#
+			SPD_OPTION="SPD=$SPD"
+		else
+			echo "WARNING:	Proceeding without Trusted OS!"
+			echo "		Please specify both ATF_SPD and TOS_BIN"
+			echo "		if you wish to use a Trusted OS!"
+		fi
+	fi
+
+	#
+	# Debug extraction handling
+	#
+	case "$BUILD_ATF" in
+	debug*)
+		DEBUG=1
+		BUILD_TYPE="debug"
+		;;
+	*)
+		DEBUG=0
+		BUILD_TYPE="release"
+		;;
+	esac
+
+	export BL30 BL31 BL32 BL33
+
+	echo "BL30=$BL30"
+	if [ $ATF_BUILDVER -gt 1 ]; then
+		export SCP_BL2
+		echo "SCP_BL2=$BL30"
+	fi
+	echo "BL31=$BL31"
+	echo "BL32=$BL32"
+	echo "BL33=$BL33"
+	echo "$SPD_OPTION"
+	echo "BUILD_TYPE=$BUILD_TYPE"
+
+	#
+	# If a build was done with BL32, and followed by another without,
+	# the BL32 component remains in fip.bin, so we delete the build dir
+	# contents before calling make
+	#
+	rm -rf build/"$ATF_PLATFORM/$BUILD_TYPE"/*
+
+	#
+	# Build ARM Trusted Firmware and create FIP
+	#
+	if [ $VERBOSE -eq 1 ]; then
+		echo "Calling ARM Trusted Firmware build:"
+		echo "CROSS_COMPILE="$CROSS_COMPILE" make -j$NUM_THREADS PLAT="$ATF_PLATFORM" $SPD_OPTION DEBUG=$DEBUG ${PLATFORM_BUILDFLAGS} all fip"
+	fi
+	CROSS_COMPILE="$CROSS_COMPILE" make -j$NUM_THREADS PLAT="$ATF_PLATFORM" $SPD_OPTION DEBUG=$DEBUG ${PLATFORM_BUILDFLAGS} all fip
+	if [ $? -eq 0 ]; then
+		#
+		# Copy resulting images to UEFI image dir
+		#
+		if [ $VERBOSE -eq 1 ]; then
+			echo "Copying bl1.bin and fip.bin to "$EDK2_DIR/Build/$PLATFORM_IMAGE_DIR/$BUILD_PROFILE/FV/""
+		fi
+		cp -a build/"$ATF_PLATFORM/$BUILD_TYPE"/{bl1,fip}.bin "$EDK2_DIR/Build/$PLATFORM_IMAGE_DIR/$BUILD_PROFILE/FV/"
+	else
+		return 1
+	fi
+}
+
+# Check to see if we are in a trusted firmware directory
+# refuse to continue if we aren't
+if [ ! -d bl32 ]
+then
+	echo "ERROR: we aren't in the arm-trusted-firmware directory."
+	usage
+	exit 1
+fi
+
+build=
+
+if [ $# = 0 ]
+then
+	usage
+	exit 1
+else
+	while [ "$1" != "" ]; do
+		case $1 in
+			"-e" )
+				shift
+				EDK2_DIR="$1"
+				;;
+			"/h" | "/?" | "-?" | "-h" | "--help" )
+				usage
+				exit
+				;;
+			"-t" )
+				shift
+				BUILD_PROFILE="$1"
+				;;
+			* )
+				build="$1"
+				;;
+		esac
+		shift
+	done
+fi
+
+if [ X"$build" = X"" ]; then
+	echo "No platform specified!" >&2
+	echo
+	usage
+	exit 1
+fi
+
+build_platform $build
+exit $?
diff --git a/uefi-tools/common-functions b/uefi-tools/common-functions
new file mode 100644
index 0000000..08f4fbf
--- /dev/null
+++ b/uefi-tools/common-functions
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+RESULT_BUF=`echo -e ------------------------------------------------------------`
+RESULT_PASS_COUNT=0
+RESULT_FAIL_COUNT=0
+
+TOOLS_DIR="`dirname $0`"
+
+function result_log
+{
+	if [ $1 -eq 0 ]; then
+		RESULT_BUF="`printf \"%s\n%55s\tpass\" \"$RESULT_BUF\" \"$2\"`"
+		RESULT_PASS_COUNT=$(($RESULT_PASS_COUNT + 1))
+	else
+		RESULT_BUF="`printf \"%s\n%55s\tfail\" \"$RESULT_BUF\" \"$2\"`"
+		RESULT_FAIL_COUNT=$(($RESULT_FAIL_COUNT + 1))
+	fi
+}
+
+function result_print
+{
+	printf "%s" "$RESULT_BUF"
+	echo -e "\n------------------------------------------------------------"
+	printf "pass\t$RESULT_PASS_COUNT\n"
+	printf "fail\t$RESULT_FAIL_COUNT\n"
+
+	exit $RESULT_FAIL_COUNT
+}
+
+function get_build_arch
+{
+	case `uname -m` in
+	    arm*)
+	        BUILD_ARCH=ARM;;
+	    aarch64*)
+	        BUILD_ARCH=AARCH64;;
+	    *)
+	        BUILD_ARCH=other;;
+	esac
+}
+
+function set_cross_compile
+{
+	get_build_arch
+
+	echo "Target: $PLATFORM_ARCH"
+	echo "Build: $BUILD_ARCH"
+	if [ "$PLATFORM_ARCH" = "$BUILD_ARCH" ]; then
+	    TEMP_CROSS_COMPILE=
+	elif [ "$PLATFORM_ARCH" == "AARCH64" ]; then
+	    if [ X"$CROSS_COMPILE_64" != X"" ]; then
+	        TEMP_CROSS_COMPILE="$CROSS_COMPILE_64"
+	    else
+	        TEMP_CROSS_COMPILE=aarch64-linux-gnu-
+	    fi
+	elif [ "$PLATFORM_ARCH" == "ARM" ]; then
+	    if [ X"$CROSS_COMPILE_32" != X"" ]; then
+	        TEMP_CROSS_COMPILE="$CROSS_COMPILE_32"
+	    else
+	        TEMP_CROSS_COMPILE=arm-linux-gnueabihf-
+	    fi
+	else
+	    echo "Unsupported target architecture '$PLATFORM_ARCH'!" >&2
+	fi
+}
+
+function get_gcc_version
+{
+	gcc_version=$($1 -dumpversion)
+	case $gcc_version in
+		4.6*|4.7*|4.8*|4.9*)
+			echo GCC$(echo ${gcc_version} | awk -F. '{print $1$2}')
+			;;
+		*)
+			echo "Unknown toolchain version '$gcc_version'" >&2
+			echo "Attempting to build using GCC49 profile." >&2
+			echo GCC49
+			;;
+	esac
+}
+
+function get_clang_version
+{
+	clang_version=`$1 --version | head -1 | sed 's/^.*version\s*\([0-9]*\).\([0-9]*\).*/\1\2/g'`
+	echo "CLANG$clang_version"
+}
diff --git a/uefi-tools/opteed-build.sh b/uefi-tools/opteed-build.sh
new file mode 100755
index 0000000..3c759eb
--- /dev/null
+++ b/uefi-tools/opteed-build.sh
@@ -0,0 +1,158 @@
+#!/bin/bash
+#
+# Builds OP-TEE Trusted OS.
+# Not intended to be called directly, invoked from tos-build.sh.
+#
+# Board configuration is extracted from
+# parse-platforms.py and platforms.config.
+#
+
+TOOLS_DIR="`dirname $0`"
+. "$TOOLS_DIR"/common-functions
+
+export CFG_TEE_CORE_LOG_LEVEL=2  # 0=none 1=err 2=info 3=debug 4=flow
+
+function usage
+{
+	echo "usage:"
+	echo "opteed-build.sh -e <EDK2 source directory> -t <UEFI build profile/toolchain> <platform>"
+	echo
+}
+
+function build_platform
+{
+	unset CFG_ARM64_core PLATFORM PLATFORM_FLAVOR DEBUG
+	TOS_PLATFORM="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o tos_platform`"
+	if [ X"$TOS_PLATFORM" = X"" ]; then
+		TOS_PLATFORM="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o atf_platform`"
+		if [ X"$TOS_PLATFORM" = X"" ]; then
+			TOS_PLATFORM=$1
+		fi
+	fi
+	TOS_PLATFORM_FLAVOR="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o tos_platform_flavor`"
+
+	#
+	# Read platform configuration
+	#
+	PLATFORM_ARCH="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o arch`"
+	PLATFORM_IMAGE_DIR="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o uefi_image_dir`"
+	PLATFORM_BUILDFLAGS="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o tos_buildflags`"
+
+	if [ $VERBOSE -eq 1 ]; then
+		echo "PLATFORM_ARCH=$PLATFORM_ARCH"
+		echo "PLATFORM_IMAGE_DIR=$PLATFORM_IMAGE_DIR"
+		echo "PLATFORM_BUILDFLAGS=$PLATFORM_BUILDFLAGS"
+	fi
+
+	#
+	# Set up cross compilation variables (if applicable)
+	#
+	# OP-TEE requires both 64- and 32-bit compilers for a 64-bit build
+	# For details, visit
+	# https://github.com/OP-TEE/optee_os/blob/master/documentation/build_system.md#cross_compile-cross-compiler-selection
+	#
+	set_cross_compile
+	if [ "$PLATFORM_ARCH" = "AARCH64" ]; then
+		export CFG_ARM64_core=y
+		export CROSS_COMPILE_core="$TEMP_CROSS_COMPILE"
+		export CROSS_COMPILE_ta_arm64="$TEMP_CROSS_COMPILE"
+		PLATFORM_ARCH="ARM"
+		set_cross_compile
+		PLATFORM_ARCH="AARCH64"
+		echo "CFG_ARM64_core=$CFG_ARM64_core"
+		echo "CROSS_COMPILE_ta_arm64=$CROSS_COMPILE_ta_arm64"
+	else
+		export CFG_ARM64_core=n
+	fi
+	export CROSS_COMPILE="$TEMP_CROSS_COMPILE"
+	echo "CROSS_COMPILE=$CROSS_COMPILE"
+	echo "CROSS_COMPILE_core=$CROSS_COMPILE_core"
+
+	#
+	# Set up build variables
+	#
+	BUILD_TOS="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o build_tos`"
+	case "$BUILD_TOS" in
+	debug*)
+		export DEBUG=1
+		echo "PROFILE=DEBUG"
+		;;
+	*)
+		export DEBUG=0
+		echo "PROFILE=RELEASE"
+		;;
+	esac
+
+	export PLATFORM=$TOS_PLATFORM
+	export PLATFORM_FLAVOR=$TOS_PLATFORM_FLAVOR
+	echo "PLATFORM=$PLATFORM"
+	echo "PLATFORM_FLAVOR=$PLATFORM_FLAVOR"
+	echo "CFG_TEE_CORE_LOG_LEVEL=$CFG_TEE_CORE_LOG_LEVEL"
+
+	#
+	# Build OP-TEE
+	#
+	if [ $VERBOSE -eq 1 ]; then
+		echo "Calling OP-TEE build:"
+	fi
+	make -j$NUM_THREADS ${PLATFORM_BUILDFLAGS}
+	if [ $? -eq 0 ]; then
+		#
+		# Copy resulting images to UEFI image dir
+		#
+		if [ $VERBOSE -eq 1 ]; then
+			echo "Copying tee.bin to "$EDK2_DIR/Build/$PLATFORM_IMAGE_DIR/$BUILD_PROFILE/FV/""
+		fi
+		cp -a out/arm-plat-"$TOS_PLATFORM"/core/tee.bin "$EDK2_DIR/Build/$PLATFORM_IMAGE_DIR/$BUILD_PROFILE/FV/"
+	else
+		return 1
+	fi
+}
+
+# Check to see if we are in a trusted OS directory
+# refuse to continue if we aren't
+if [ ! -f documentation/optee_design.md ]
+then
+	echo "ERROR: we aren't in the optee_os directory."
+	usage
+	exit 1
+fi
+
+build=
+
+if [ $# = 0 ]
+then
+	usage
+	exit 1
+else
+	while [ "$1" != "" ]; do
+		case $1 in
+			"-e" )
+				shift
+				EDK2_DIR="$1"
+				;;
+			"/h" | "/?" | "-?" | "-h" | "--help" )
+				usage
+				exit
+				;;
+			"-t" )
+				shift
+				BUILD_PROFILE="$1"
+				;;
+			* )
+				build="$1"
+				;;
+		esac
+		shift
+	done
+fi
+
+if [ X"$build" = X"" ]; then
+	echo "No platform specified!" >&2
+	echo
+	usage
+	exit 1
+fi
+
+build_platform $build
+exit $?
diff --git a/uefi-tools/parse-platforms.py b/uefi-tools/parse-platforms.py
new file mode 100755
index 0000000..af44038
--- /dev/null
+++ b/uefi-tools/parse-platforms.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+
+import sys, os, argparse, ConfigParser
+
+default_filename='platforms.config'
+
+def list_platforms():
+    for p in platforms: print p
+
+def shortlist_platforms():
+    for p in platforms: print p,
+
+def get_images():
+    if args.platform:
+        try:
+            value = config.get(args.platform, "EXTRA_FILES")
+            print value,
+        except:
+            pass
+        try:
+            value = config.get(args.platform, "BUILD_ATF")
+            if value == "yes":
+                print "bl1.bin fip.bin"
+                return True
+        except:
+            try:
+                value = config.get(args.platform, "UEFI_BIN")
+                print value
+                return True
+            except:
+                print "No images found!"
+    else:
+        print "No platform specified!"
+
+    return False
+
+def get_option():
+    if args.platform:
+        if args.option:
+            try:
+                value = config.get(args.platform, args.option)
+                if value:
+                    print value
+                    return True
+            except:
+                return True   # Option not found, return True, and no output
+        else:
+            print "No option specified!"
+    else:
+        print "No platform specified!"
+    return False
+
+parser = argparse.ArgumentParser(description='Parses platform configuration for Linaro UEFI build scripts.')
+parser.add_argument('-c', '--config-file', help='Specify a non-default platform config file.', required=False)
+parser.add_argument('-p', '--platform', help='Read configuration for PLATFORM only.', required=False)
+parser.add_argument('command', action="store", help='Action to perform')
+parser.add_argument('-o', '--option', help='Option to retreive')
+
+args = parser.parse_args()
+if args.config_file:
+    config_filename = args.config_file
+else:
+    config_filename = os.path.dirname(os.path.realpath(sys.argv[0])) + '/' + default_filename
+
+config = ConfigParser.ConfigParser()
+config.read(config_filename)
+
+platforms = config.sections()
+
+commands = {"shortlist": shortlist_platforms,
+            "list": list_platforms,
+            "images": get_images,
+            "get": get_option}
+
+try:
+    retval = commands[args.command]()
+except:
+    print ("Unrecognized command '%s'" % args.command)
+
+if retval != True:
+    sys.exit(1)
diff --git a/uefi-tools/platforms.config b/uefi-tools/platforms.config
new file mode 100644
index 0000000..adaf6c0
--- /dev/null
+++ b/uefi-tools/platforms.config
@@ -0,0 +1,245 @@
+# Platform build configurations for Linaro EDK2 builds
+# ====================================================
+# The configuration file format is extremely simplistic:
+# - Each platform has a short name.
+# - A platform entry starts by the short name held in square brackets, '[]'
+# - Within each entry, all options are described in a NAME=VALUE scheme,
+#   with the name being whatever comes before the first '=' on the line,
+#   and the value being everything that comes after it.
+#
+# Mandatory options:
+# - LONGNAME		A more descriptive name of the platform.
+# - DSC			Pointer to the EDK2 build description file. (The
+#			pandaboard is excused, all other ports must have this.)
+# - ARCH		String describing the architecture to build for.
+#			Currently supported are AARCH32 and AARCH64.
+# - UEFI_BIN		Name of executable image produced.
+# - UEFI_IMAGE_DIR	Build output directory name, relative to 'Build'.
+#
+# Options for Trusted OS
+# Note that OP-TEE (https://github.com/OP-TEE/optee_os) is the only currently
+# supported Trusted OS
+# - BUILD_TOS		Set to "yes" if the build should automatically build
+#   			Trusted OS, mainly for ARM Trusted Firmware.
+#			If this is set, you must also set ATF_SPD!
+#			Else we will not know which specific Trusted OS to
+#			build.
+#			Set to "debug" to create a debug build.
+# - TOS_PLATFORM	Platform name for Trusted OS build, if
+#   			different from ARM Trusted Firmware platform
+#			or UEFI platform name.
+# - TOS_PLATFORM_FLAVOR	If a core platform has multiple flavors, specify which
+#			flavor here.
+#
+# Options for ARM Trusted Firmware platforms
+# - BUILD_ATF		Set to "yes" if the build should automatically build
+#   			ARM Trusted Firmware and a fip containing UEFI image.
+#			Set to "debug" to create a debug build.
+# - ATF_PLATFORM	Platform name for ARM Trusted Firmware build, if
+#   			different from UEFI platform name.
+# - SCP_BIN		SCP image to pass to ARM Trusted Firmware.
+# - TOS_BIN		Trusted OS image to pass to ARM Trusted Firmware.
+#			The path is relative to
+#			$EDK2_DIR/Build/$PLATFORM_IMAGE_DIR/$BUILD_PROFILE/FV/.
+#			To actually build the Trusted OS, you must also set
+#			ATF_SPD.
+# - ATF_SPD		Name of Secure Payload Dispatcher
+#			To actually build the Trusted OS, you must also set
+#			TOS_BIN.
+#
+# Optional options:
+# - BUILDFLAGS		Any special flags you want to pass to the build command.
+# - ATF_BUILDFLAGS	Any special flags you want to pass to the ARM Trusted
+#			Firmware build command.
+# - TOS_BUILDFLAGS	Any special flags you want to pass to the Trusted OS
+#			build command.
+# - EXTRA_FILES		Any additional files to be copied to output dir.
+# - PREBUILD_CMDS	Any commands you want to execute before the build step.
+# - POSTBUILD_CMDS	Any commands you want to execute after the build step.
+# - PACKAGES_PATH	Additional directories to search for packages under.
+#
+# Special options:
+# - BUILDCMD		Command to call instead of the normal build command.
+#			Only for pandaboard, not to be used for new ports.
+#
+
+[juno]
+LONGNAME=aarch64 Juno
+DSC=OpenPlatformPkg/Platforms/ARM/Juno/ArmJuno.dsc
+BUILDFLAGS=
+ARCH=AARCH64
+BUILD_ATF=yes
+UEFI_BIN=BL33_AP_UEFI.fd
+UEFI_IMAGE_DIR=ArmJuno
+SCP_BIN=OpenPlatformPkg/Platforms/ARM/Juno/Binary/bl30.bin
+EXTRA_FILES=../../../../OpenPlatformPkg/Platforms/ARM/Juno/Binary/bl0.bin ../../../../OpenPlatformPkg/Platforms/ARM/Juno/Binary/Copying.txt
+
+# ARM FVP BASE AEMv8-A model
+[fvp_full]
+LONGNAME=aarch64 FVP RTSM with full perhiperhal set
+DSC=OpenPlatformPkg/Platforms/ARM/VExpress/ArmVExpress-FVP-AArch64.dsc
+BUILDFLAGS=-D EDK2_OUT_DIR=Build/ArmVExpress-FVP-AArch64-Full -D EDK2_ENABLE_SMSC_91X=1 -D EDK2_ENABLE_PL111=1
+ARCH=AARCH64
+UEFI_BIN=FVP_AARCH64_EFI.fd
+UEFI_IMAGE_DIR=ArmVExpress-FVP-AArch64-Full
+
+[fvp]
+LONGNAME=aarch64 FVP RTSM
+DSC=OpenPlatformPkg/Platforms/ARM/VExpress/ArmVExpress-FVP-AArch64.dsc
+BUILDFLAGS=-D EDK2_ENABLE_SMSC_91X=1
+ARCH=AARCH64
+BUILD_ATF=yes
+UEFI_BIN=FVP_AARCH64_EFI.fd
+UEFI_IMAGE_DIR=ArmVExpress-FVP-AArch64
+
+[tc2]
+LONGNAME=Versatile Express TC2
+BUILDFLAGS=-D ARM_BIGLITTLE_TC2=1
+DSC=OpenPlatformPkg/Platforms/ARM/VExpress/ArmVExpress-CTA15-A7.dsc
+ARCH=ARM
+UEFI_BIN=ARM_VEXPRESS_CTA15A7_EFI.fd
+UEFI_IMAGE_DIR=ArmVExpress-CTA15-A7
+
+[panda]
+LONGNAME=TI Pandaboard
+BUILDCMD=./PandaBoardPkg/build.sh
+BUILDFLAGS=
+ARCH=ARM
+UEFI_BIN=MLO
+UEFI_IMAGE_DIR=PandaBoard
+
+[beagle]
+LONGNAME=BeagleBoard
+BUILDFLAGS=
+DSC=BeagleBoardPkg/BeagleBoardPkg.dsc
+ARCH=ARM
+
+[d01]
+LONGNAME=HiSilicon D01 Cortex-A15 16-cores
+BUILDFLAGS=-D EDK2_ARMVE_STANDALONE=1
+DSC=HisiPkg/D01BoardPkg/D01BoardPkg.dsc
+ARCH=ARM
+UEFI_BIN=D01.fd
+UEFI_IMAGE_DIR=D01
+
+[d01-intelbds]
+LONGNAME=HiSilicon D01 Cortex-A15 16-cores Intel Bds
+BUILDFLAGS=-D EDK2_ARMVE_STANDALONE=1 -D INTEL_BDS -D NO_LINUX_LOADER -D EDK2_OUT_DIR=Build/D01-IntelBds
+DSC=HisiPkg/D01BoardPkg/D01BoardPkg.dsc
+ARCH=ARM
+UEFI_BIN=D01.fd
+UEFI_IMAGE_DIR=D01
+
+[bbb]
+LONGNAME=Texas Instruments BeagleBone Black
+BUILDFLAGS=
+DSC=TexasInstrumentsPkg/BeagleBoneBlackPkg/BeagleBoneBlackPkg.dsc
+ARCH=ARM
+UEFI_BIN=BEAGLEBONEBLACK_EFI.fd
+UEFI_IMAGE_DIR=BeagleBoneBlack
+
+[qemu]
+LONGNAME=QEMU ARM Emulator
+BUILDFLAGS=-D INTEL_BDS
+DSC=ArmVirtPkg/ArmVirtQemu.dsc
+ARCH=ARM
+UEFI_BIN=QEMU_EFI.fd
+UEFI_IMAGE_DIR=ArmVirtQemu-ARM
+
+[qemu64]
+LONGNAME=QEMU AArch64 Emulator
+BUILDFLAGS=-D INTEL_BDS
+DSC=ArmVirtPkg/ArmVirtQemu.dsc
+ARCH=AARCH64
+UEFI_BIN=QEMU_EFI.fd
+UEFI_IMAGE_DIR=ArmVirtQemu-AARCH64
+
+[mustang]
+LONGNAME=APM XGene Mustang
+BUILDFLAGS=
+DSC=ArmPlatformPkg/APMXGenePkg/APMXGene-Mustang.dsc
+ARCH=AARCH64
+UEFI_BIN=APMXGENE-MUSTANG.fd SEC_APMXGENE-MUSTANG.fd
+UEFI_IMAGE_DIR=APMXGene-Mustang
+
+[overdrive]
+LONGNAME=AMD Overdrive
+BUILDFLAGS=-D INTEL_BDS
+DSC=OpenPlatformPkg/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc
+ARCH=AARCH64
+PACKAGES_PATH=OpenPlatformPkg/Platforms/AMD/Styx/Binary
+UEFI_BIN=STYX_ROM.fd
+UEFI_IMAGE_DIR=Overdrive
+
+[cello]
+LONGNAME=LeMaker Cello
+BUILDFLAGS=-D INTEL_BDS
+DSC=OpenPlatformPkg/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc
+ARCH=AARCH64
+PACKAGES_PATH=OpenPlatformPkg/Platforms/AMD/Styx/Binary
+UEFI_BIN=STYX_ROM.fd
+UEFI_IMAGE_DIR=Cello
+
+[hikey]
+LONGNAME=CircuitCo HiKey
+DSC=OpenPlatformPkg/Platforms/Hisilicon/HiKey/HiKey.dsc
+ARCH=AARCH64
+UEFI_BIN=BL33_AP_UEFI.fd
+UEFI_IMAGE_DIR=HiKey
+BUILD_ATF=yes
+ATF_SPD=opteed
+TOS_BIN=tee.bin
+BUILD_TOS=yes
+SCP_BIN=OpenPlatformPkg/Platforms/Hisilicon/HiKey/Binary/mcuimage.bin
+# Uncomment this to use UART0 as the EDK2 console
+#BUILDFLAGS=-DSERIAL_BASE=0xF8015000
+# Uncomment this to use UART0 as the ARM Trusted Firmware console
+#ATF_BUILDFLAGS=CONSOLE_BASE=PL011_UART0_BASE CRASH_CONSOLE_BASE=PL011_UART0_BASE
+# Uncomment this to use UART0 as the OP-TEE Trusted OS console
+#TOS_BUILDFLAGS=CFG_CONSOLE_UART=0
+
+[xen64]
+LONGNAME=AArch64 Xen guest
+BUILDFLAGS=
+DSC=ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationXen.dsc
+ARCH=AARCH64
+UEFI_BIN=XEN_EFI.fd
+UEFI_IMAGE_DIR=ArmVirtualizationXen-AARCH64
+
+[aarch64-shell]
+LONGNAME=AArch64 EFI Shell
+BUILDFLAGS=-D INCLUDE_TFTP_COMMAND
+DSC=ShellPkg/ShellPkg.dsc
+ARCH=AARCH64
+
+[aarch64-shell-minimal]
+LONGNAME=AArch64 EFI Shell (Minimal)
+BUILDFLAGS=-D NO_SHELL_PROFILES
+DSC=ShellPkg/ShellPkg.dsc
+ARCH=AARCH64
+
+[arm-shell]
+LONGNAME=ARM EFI Shell
+BUILDFLAGS=-D INCLUDE_TFTP_COMMAND
+DSC=ShellPkg/ShellPkg.dsc
+ARCH=ARM
+
+[arm-shell-minimal]
+LONGNAME=ARM EFI Shell (Minimal)
+BUILDFLAGS=-D NO_SHELL_PROFILES
+DSC=ShellPkg/ShellPkg.dsc
+ARCH=ARM
+
+[d02]
+LONGNAME=Hisilicon D02
+DSC=OpenPlatformPkg/Platforms/Hisilicon/D02/Pv660D02.dsc
+ARCH=AARCH64
+UEFI_BIN=PV660D02.fd
+UEFI_IMAGE_DIR=Pv660D02
+
+[d03]
+LONGNAME=Hisilicon D03
+DSC=OpenPlatformPkg/Platforms/Hisilicon/D03/D03.dsc
+ARCH=AARCH64
+UEFI_BIN=D03.fd
+UEFI_IMAGE_DIR=D03
diff --git a/uefi-tools/tos-build.sh b/uefi-tools/tos-build.sh
new file mode 100755
index 0000000..9dc4b2d
--- /dev/null
+++ b/uefi-tools/tos-build.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+#
+# Builds Trusted OS, mainly for ARM Trusted Firmware.
+# Calls $ATF_SPD-build.sh for the actual build of a specific Trusted OS.
+# Not intended to be called directly, invoked from uefi-build.sh.
+#
+# Board configuration is extracted from
+# parse-platforms.py and platforms.config.
+#
+
+TOOLS_DIR="`dirname $0`"
+. "$TOOLS_DIR"/common-functions
+
+function usage
+{
+	echo "usage:"
+	echo "tos-build.sh -e <EDK2 source directory> -t <UEFI build profile/toolchain> <platform>"
+	echo
+}
+
+function build_platform
+{
+	if [ X"$EDK2_DIR" = X"" ];then
+		echo "EDK2_DIR not set!" >&2
+		return 1
+	fi
+
+	if [ X"`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o build_tos`" = X"" ]; then
+		echo "Platform '$1' is not configured to build Trusted OS."
+		return 0
+	fi
+
+	#
+	# Build Trusted OS
+	#
+	ATF_SPD="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $1 get -o atf_spd`"
+	if [ -f $TOOLS_DIR/$ATF_SPD-build.sh ]; then
+		echo "Building $ATF_SPD Trusted OS"
+		if [ $VERBOSE -eq 1 ]; then
+			echo "$TOOLS_DIR/$ATF_SPD-build.sh -e "$EDK2_DIR" -t "$BUILD_PROFILE" $build"
+		fi
+		$TOOLS_DIR/$ATF_SPD-build.sh -e "$EDK2_DIR" -t "$BUILD_PROFILE" $build
+		return $?
+	else
+		echo "ERROR: missing Trusted OS build script."
+		echo "       Or build script not named $ATF_SPD-build.sh"
+		return 1
+	fi
+}
+
+build=
+
+if [ $# = 0 ]
+then
+	usage
+	exit 1
+else
+	while [ "$1" != "" ]; do
+		case $1 in
+			"-e" )
+				shift
+				EDK2_DIR="$1"
+				;;
+			"/h" | "/?" | "-?" | "-h" | "--help" )
+				usage
+				exit
+				;;
+			"-t" )
+				shift
+				BUILD_PROFILE="$1"
+				;;
+			* )
+				build="$1"
+				;;
+		esac
+		shift
+	done
+fi
+
+if [ X"$build" = X"" ]; then
+	echo "No platform specified!" >&2
+	echo
+	usage
+	exit 1
+fi
+
+build_platform $build
+exit $?
diff --git a/uefi-tools/uefi-build.sh b/uefi-tools/uefi-build.sh
new file mode 100755
index 0000000..0fa50ed
--- /dev/null
+++ b/uefi-tools/uefi-build.sh
@@ -0,0 +1,331 @@
+#!/bin/bash
+
+#
+# Board Configuration Section
+# ===========================
+#
+# Board configuration moved to parse-platforms.py and platforms.config.
+#
+# No need to edit below unless you are changing script functionality.
+#
+
+unset WORKSPACE EDK_TOOLS_DIR MAKEFLAGS
+
+TOOLS_DIR="`dirname $0`"
+. "$TOOLS_DIR"/common-functions
+PLATFORM_CONFIG=""
+VERBOSE=0
+ATF_DIR=
+TOS_DIR=
+TOOLCHAIN=
+OPENSSL_CONFIGURED=FALSE
+
+# Number of threads to use for build
+export NUM_THREADS=$((`getconf _NPROCESSORS_ONLN` + 1))
+
+function build_platform
+{
+	PLATFORM_NAME="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o longname`"
+	PLATFORM_PREBUILD_CMDS="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o prebuild_cmds`"
+	PLATFORM_BUILDFLAGS="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o buildflags`"
+	PLATFORM_BUILDFLAGS="$PLATFORM_BUILDFLAGS ${EXTRA_OPTIONS[@]}"
+	PLATFORM_BUILDCMD="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o buildcmd`"
+	PLATFORM_DSC="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o dsc`"
+	PLATFORM_ARCH="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o arch`"
+	PLATFORM_PACKAGES_PATH="$PWD"
+
+	TEMP_PACKAGES_PATH="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o packages_path`"
+	if [ -n "$TEMP_PACKAGES_PATH" ]; then
+		IFS=:
+		for path in "$TEMP_PACKAGES_PATH"; do
+			case "$path" in
+				/*)
+					PLATFORM_PACKAGES_PATH="$PLATFORM_PACKAGES_PATH:$path"
+				;;
+				*)
+					PLATFORM_PACKAGES_PATH="$PLATFORM_PACKAGES_PATH:$PWD/$path"
+				;;
+		        esac
+		done
+		unset IFS
+	fi
+	if [ $VERBOSE -eq 1 ]; then
+		echo "Setting build parallellism to $NUM_THREADS processes\n"
+		echo "PLATFORM_NAME=$PLATFORM_NAME"
+		echo "PLATFORM_PREBUILD_CMDS=$PLATFORM_PREBUILD_CMDS"
+		echo "PLATFORM_BUILDFLAGS=$PLATFORM_BUILDFLAGS"
+		echo "PLATFORM_BUILDCMD=$PLATFORM_BUILDCMD"
+		echo "PLATFORM_DSC=$PLATFORM_DSC"
+		echo "PLATFORM_ARCH=$PLATFORM_ARCH"
+		echo "PLATFORM_PACKAGES_PATH=$PLATFORM_PACKAGES_PATH"
+	fi
+
+	set_cross_compile
+	CROSS_COMPILE="$TEMP_CROSS_COMPILE"
+
+	echo "Building $PLATFORM_NAME - $PLATFORM_ARCH"
+	echo "CROSS_COMPILE=\"$TEMP_CROSS_COMPILE\""
+	echo "$board"_BUILDFLAGS="'$PLATFORM_BUILDFLAGS'"
+
+	if [ "$TARGETS" == "" ]; then
+		TARGETS=( RELEASE )
+	fi
+
+	case $TOOLCHAIN in
+		"gcc")
+			export TOOLCHAIN=`get_gcc_version "$CROSS_COMPILE"gcc`
+			;;
+		"clang")
+			export TOOLCHAIN=`get_clang_version clang`
+			;;
+	esac
+	echo "TOOLCHAIN is ${TOOLCHAIN}"
+
+	export ${TOOLCHAIN}_${PLATFORM_ARCH}_PREFIX=$CROSS_COMPILE
+	echo "Toolchain prefix: ${TOOLCHAIN}_${PLATFORM_ARCH}_PREFIX=$CROSS_COMPILE"
+
+	export PACKAGES_PATH="$PLATFORM_PACKAGES_PATH"
+	for target in "${TARGETS[@]}" ; do
+		if [ X"$PLATFORM_PREBUILD_CMDS" != X"" ]; then
+			echo "Run pre build commands"
+			eval ${PLATFORM_PREBUILD_CMDS}
+		fi
+		if [ X"$PLATFORM_BUILDCMD" == X"" ]; then
+			echo  ${TOOLCHAIN}_${PLATFORM_ARCH}_PREFIX=$CROSS_COMPILE build -n $NUM_THREADS -a "$PLATFORM_ARCH" -t ${TOOLCHAIN} -p "$PLATFORM_DSC" -b "$target" \
+				${PLATFORM_BUILDFLAGS}
+			build -n $NUM_THREADS -a "$PLATFORM_ARCH" -t ${TOOLCHAIN} -p "$PLATFORM_DSC" -b "$target" \
+				${PLATFORM_BUILDFLAGS}
+		else
+			${PLATFORM_BUILDCMD} -b "$target" ${PLATFORM_BUILDFLAGS}
+		fi
+		RESULT=$?
+		if [ $RESULT -eq 0 ]; then
+			if [ X"$TOS_DIR" != X"" ]; then
+				pushd $TOS_DIR >/dev/null
+				if [ $VERBOSE -eq 1 ]; then
+					echo "$TOOLS_DIR/tos-build.sh -e "$EDK2_DIR" -t "$target"_${TOOLCHAIN} $board"
+				fi
+				$TOOLS_DIR/tos-build.sh -e "$EDK2_DIR" -t "$target"_${TOOLCHAIN} $board
+				RESULT=$?
+				popd >/dev/null
+			fi
+		fi
+		if [ $RESULT -eq 0 ]; then
+			if [ X"$ATF_DIR" != X"" ]; then
+				pushd $ATF_DIR >/dev/null
+				if [ $VERBOSE -eq 1 ]; then
+					echo "$TOOLS_DIR/atf-build.sh -e "$EDK2_DIR" -t "$target"_${TOOLCHAIN} $board"
+				fi
+				$TOOLS_DIR/atf-build.sh -e "$EDK2_DIR" -t "$target"_${TOOLCHAIN} $board
+				RESULT=$?
+				popd >/dev/null
+			fi
+		fi
+		result_log $RESULT "$PLATFORM_NAME $target"
+	done
+	unset PACKAGES_PATH
+}
+
+
+function uefishell
+{
+	BUILD_ARCH=`uname -m`
+	case $BUILD_ARCH in
+		arm*)
+			ARCH=ARM
+			;;
+		aarch64)
+			ARCH=AARCH64
+			;;
+		*)
+			unset ARCH
+			;;
+	esac
+	export ARCH
+	if [ $VERBOSE -eq 1 ]; then
+		echo "Building BaseTools"
+	fi
+	export EDK_TOOLS_PATH=`pwd`/BaseTools
+	. edksetup.sh BaseTools
+	make -C $EDK_TOOLS_PATH
+	if [ $? -ne 0 ]; then
+		echo " !!! UEFI BaseTools failed to build !!! " >&2
+		exit 1
+	fi
+}
+
+
+function usage
+{
+	echo "usage:"
+	echo -n "uefi-build.sh [-b DEBUG | RELEASE] [ all "
+	for board in "${boards[@]}" ; do
+	    echo -n "| $board "
+	done
+	echo "]"
+	printf "%8s\tbuild %s\n" "all" "all supported platforms"
+	for board in "${boards[@]}" ; do
+		PLATFORM_NAME="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o longname`"
+		printf "%8s\tbuild %s\n" "$board" "${PLATFORM_NAME}"
+	done
+}
+
+#
+# Since we do a command line validation on whether specified platforms exist or
+# not, do a first pass of command line to see if there is an explicit config
+# file there to read valid platforms from.
+#
+commandline=( "$@" )
+i=0
+for arg;
+do
+	if [ $arg == "-c" ]; then
+		FILE_ARG=${commandline[i + 1]}
+		if [ ! -f "$FILE_ARG" ]; then
+			echo "ERROR: configuration file '$FILE_ARG' not found" >&2
+			exit 1
+		fi
+		case "$FILE_ARG" in
+			/*)
+				PLATFORM_CONFIG="-c \"$FILE_ARG\""
+			;;
+			*)
+				PLATFORM_CONFIG="-c `readlink -f \"$FILE_ARG\"`"
+			;;
+		esac
+		echo "Platform config file: '$FILE_ARG'"
+		export PLATFORM_CONFIG
+	fi
+	i=$(($i + 1))
+done
+
+builds=()
+boards=()
+boardlist="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG shortlist`"
+for board in $boardlist; do
+    boards=(${boards[@]} $board)
+done
+
+NUM_TARGETS=0
+
+while [ "$1" != "" ]; do
+	case $1 in
+		all )
+			builds=(${boards[@]})
+			NUM_TARGETS=$(($NUM_TARGETS + 1))
+			;;
+		"/h" | "/?" | "-?" | "-h" | "--help" )
+			usage
+			exit
+			;;
+		"-v" )
+			VERBOSE=1
+			;;
+		"-a" )
+			shift
+			ATF_DIR="$1"
+			;;
+		"-c" )
+			# Already parsed above - skip this + option
+			shift
+			;;
+		"-s" )
+			shift
+			export TOS_DIR="$1"
+			;;
+		"-b" | "--build" )
+			shift
+			echo "Adding Build profile: $1"
+			TARGETS=( ${TARGETS[@]} $1 )
+			;;
+		"-D" )
+			shift
+			echo "Adding option: -D $1"
+			EXTRA_OPTIONS=( ${EXTRA_OPTIONS[@]} "-D" $1 )
+			;;
+		"-T" )
+			shift
+			echo "Setting toolchain to '$1'"
+			TOOLCHAIN="$1"
+			;;
+		"-1" )
+			NUM_THREADS=1
+			;;
+		* )
+			MATCH=0
+			for board in "${boards[@]}" ; do
+				if [ "$1" == $board ]; then
+					MATCH=1
+					builds=(${builds[@]} "$board")
+					break
+				fi
+			done
+
+			if [ $MATCH -eq 0 ]; then
+				echo "unknown arg $1"
+				usage
+				exit 1
+			fi
+			NUM_TARGETS=$(($NUM_TARGETS + 1))
+			;;
+	esac
+	shift
+done
+
+# If there were no args, use a menu to select a single board / all boards to build
+if [ $NUM_TARGETS -eq 0 ]
+then
+	read -p "$(
+			f=0
+			for board in "${boards[@]}" ; do
+					echo "$((++f)): $board"
+			done
+			echo $((++f)): all
+
+			echo -ne '> '
+	)" selection
+
+	if [ "$selection" -eq $((${#boards[@]} + 1)) ]; then
+		builds=(${boards[@]})
+	else
+		builds="${boards[$((selection-1))]}"
+	fi
+fi
+
+# Check to see if we are in a UEFI repository
+# refuse to continue if we aren't
+if [ ! -e BaseTools ]
+then
+	echo "ERROR: we aren't in the UEFI directory."
+	echo "       I can tell because I can't see the BaseTools directory"
+	exit 1
+fi
+
+EDK2_DIR="$PWD"
+export VERBOSE
+
+if [[ "${EXTRA_OPTIONS[@]}" != *"FIRMWARE_VER"* ]]; then
+	if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
+		FIRMWARE_VER=`git rev-parse --short HEAD`
+		if ! git diff-index --quiet HEAD --; then
+			FIRMWARE_VER="${FIRMWARE_VER}-dirty"
+		fi
+		EXTRA_OPTIONS=( ${EXTRA_OPTIONS[@]} "-D" FIRMWARE_VER=$FIRMWARE_VER )
+		if [ $VERBOSE -eq 1 ]; then
+			echo "FIRMWARE_VER=$FIRMWARE_VER"
+			echo "EXTRA_OPTIONS=$EXTRA_OPTIONS"
+		fi
+	fi
+fi
+
+uefishell
+
+if [ X"$TOOLCHAIN" = X"" ]; then
+	TOOLCHAIN=gcc
+fi
+
+for board in "${builds[@]}" ; do
+	build_platform
+done
+
+result_print
diff --git a/uefi-tools/uefi-build.sh.bash_completion b/uefi-tools/uefi-build.sh.bash_completion
new file mode 100644
index 0000000..f0a5305
--- /dev/null
+++ b/uefi-tools/uefi-build.sh.bash_completion
@@ -0,0 +1,24 @@
+# bash completion for uefi-build.sh
+# copy this file to /etc/bash_completion.d/uefi-build.s
+
+have uefi-build.sh &&
+_uefi-build.sh()
+{
+    local cur prev
+
+    COMPREPLY=()
+    _get_comp_words_by_ref -n = cur
+
+    _expand || return 0
+
+    COMPREPLY=( $( compgen -W '--help -b --build RELEASE DEBUG a5 a9 tc1 tc2 panda origen arndale rtsm_a9x4 rtsm_a15x1 rtsm_a15mpcore rtsm_aarch64 beagle all' -- "$cur" ) )
+} &&
+complete -F _uefi-build.sh uefi-build.sh
+
+# Local variables:
+# mode: shell-script
+# sh-basic-offset: 4
+# sh-indent-comment: t
+# indent-tabs-mode: nil
+# End:
+# ex: ts=4 sw=4 et filetype=sh