brillo: Add tool for creating EFI images.

Create an EFI partition image containing initial ab boot
application.  Additional configurations to support the 'make_efi_image'
command and pass it a list of efi paths/applications is also included
here.

BUG=29123391
TEST=Manually tested output full-disk-image.img with qemu. Checked for
presence of EFI application and executed it. Passed unit tests for
make_efi_image using the efi_image_unittest.py test suite.

Change-Id: Icea2cf40bf7d0f48e3d66ecb9a9109e46877f75d
diff --git a/brillo_uefi_x86_64/README b/brillo_uefi_x86_64/README
new file mode 100644
index 0000000..30e57df
--- /dev/null
+++ b/brillo_uefi_x86_64/README
@@ -0,0 +1,31 @@
+This sub-directory defines an x86_64 UEFI-compatbile Brillo board target.
+
+-- FILES AND DIRECTORIES
+
+boot_loader/
+
+    Contains the EFI source code files, a Makefile, and EFI binaries needed for
+    the A/B boot loader of the system.  The binaries will be placed on the EFI
+    partition of the final disk image.  Currently, developers using the x86_64
+    UEFI board target must manually install gnu-efi on their workstations in
+    order to build the boot loader binary.  Once this is done, simply run 'make'
+    in the boot_loader/ directory to produce the necessary *.efi binaries.
+
+make_efi_image/
+
+    Contains a bash script (make_efi_image) which creates an image to be put
+    on the EFI partition of the final disk image. The script takes image size
+    in bytes, resulting image output path, and a list of EFI application
+    'host/target' paths as inputs.  The EFI applications will placed on the
+    final image's EFI partition with absolute paths specified by the latter
+    argument. Each 'host/target' element must be of the form
+    "/PATH/TO/HOST_EFI_FILE:/PATH/TO/TARGET_EFI_FILE"
+    NOTE: mtools utility is required on the system in order to create the EFI
+    image.
+
+-- BUILD SYSTEM INTEGRATION NOTES
+
+If EFI_INPUT_FILE_PATHS is non-empty, the build system system will call the
+make_efi_image script, passing EFI_IMAGE_SIZE, $(ANDROID_OUT)/EFI.img, and
+EFI_INPUT_FILE_PATHS arguments. The variables are defined globally in the
+BoardConfig.mk file.
\ No newline at end of file
diff --git a/brillo_uefi_x86_64/make_efi_image/Android.mk b/brillo_uefi_x86_64/make_efi_image/Android.mk
new file mode 100644
index 0000000..e6a5ea1
--- /dev/null
+++ b/brillo_uefi_x86_64/make_efi_image/Android.mk
@@ -0,0 +1,24 @@
+#
+# Copyright 2016 The Android Open Source Project
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := make_efi_image
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE := make_efi_image
+include $(BUILD_PREBUILT)
\ No newline at end of file
diff --git a/brillo_uefi_x86_64/make_efi_image/efi_image_unittest.py b/brillo_uefi_x86_64/make_efi_image/efi_image_unittest.py
new file mode 100755
index 0000000..186ab41
--- /dev/null
+++ b/brillo_uefi_x86_64/make_efi_image/efi_image_unittest.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+
+# Copyright 2016, The Android Open Source Project
+#
+# 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.
+
+
+"""Unit-test for make_efi_image."""
+
+import os
+import subprocess
+import tempfile
+import unittest
+
+class ArgumentTest(unittest.TestCase):
+  """Unit tests for various argument values."""
+
+  def testOutputPathSpaces(self):
+    with tempfile.NamedTemporaryFile(prefix='foo ') as efi_image, \
+      tempfile.NamedTemporaryFile() as efi_app:
+      efi_args = \
+        [ 'make_efi_image', '524288',
+          efi_image.name ,
+          efi_app.name + ':bar/biz/' + efi_app.name.split('/')[-1]]
+
+      self.assertEqual(subprocess.call(efi_args, stdout=open(os.devnull, 'wb'))
+        , 0)
+
+class DirectoryStructureTest(unittest.TestCase):
+  """Unit tests for files output paths."""
+
+  def _Paths(self, dirs):
+    """Helper function to place files into a list of directories.
+
+    This function takes a list of directories and places one file in each to
+    verify they are copied into an EFI image.  Listing the same directory N
+    times will result in N files being placed into it.
+
+    """
+    with tempfile.NamedTemporaryFile() as efi_image:
+      efi_args = ['make_efi_image', '524288', efi_image.name]
+      ifiles = []
+      target_paths = []
+
+      for d in dirs:
+        ifiles.append(tempfile.NamedTemporaryFile())
+        target_paths.append(d + ifiles[-1].name.split('/')[-1])
+        efi_args.append(ifiles[-1].name + ':' + target_paths[-1])
+
+      self.assertEqual(subprocess.call(efi_args, stdout=open(os.devnull, 'wb'))
+        , 0)
+
+      for target in target_paths:
+        self.assertEqual(
+          subprocess.call( ['mdir', '-i', efi_image.name, target],
+            stdout=open(os.devnull, 'wb'))
+          , 0)
+
+  def testOneDir(self):
+    self._Paths([''])
+    self._Paths(['foo/'])
+
+  def testSameDir(self):
+    self._Paths(['', ''])
+    self._Paths(['foo/bar/','foo/bar/'])
+
+  def testManyDir(self):
+    self._Paths(['', 'foo/', 'bar/'])
+    self._Paths(['', 'foo/bar/', 'foo/bar/biz/'])
+
+if __name__ == '__main__':
+  unittest.main()
\ No newline at end of file
diff --git a/brillo_uefi_x86_64/make_efi_image/make_efi_image b/brillo_uefi_x86_64/make_efi_image/make_efi_image
new file mode 100755
index 0000000..533eb65
--- /dev/null
+++ b/brillo_uefi_x86_64/make_efi_image/make_efi_image
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+#
+# Copyright 2016 The Android Open Source Project
+#
+# 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.
+#
+# This script writes an image with EFI applications to be copied over onto
+# an EFI partition.
+#
+# Arguments:
+#   $1:     Size in bytes for the EFI image.
+#   $2:     Output EFI image path.
+#   $3...:  EFI application files host and target paths. Each element is of the
+#           form: /PATH/TO/HOST_EFI_FILE:/PATH/TO/TARGET_EFI_FILE
+#
+# Outputs:
+#   Disk image containing EFI applications to be put in EFI partition located
+#   in the path defined by argument 2.
+#
+
+IMAGE_SIZE=$1
+BLOCK_SIZE=512
+NUM_BLOCKS=$(((IMAGE_SIZE + BLOCK_SIZE - 1) / BLOCK_SIZE))
+FILES=${@:3}
+EFI_IMAGE="$2"
+
+# Create disk image to be put in EFI partition.
+dd if=/dev/zero of="$EFI_IMAGE" bs=$BLOCK_SIZE count=0 seek=$NUM_BLOCKS \
+    &> /dev/null
+mkfs.vfat "$EFI_IMAGE"
+
+# Copy over EFI application files specified by EFI_INPUT_FILES variable.
+# TODO: Need mtools installed on system to accomplish this. See b/27389310
+for app in $FILES; do
+    IFS=":"
+    set $app
+
+    # Create directory structures as necessary.
+    dstruct=''
+    IFS='/' read -a ds <<< "${2}"
+    unset "ds[${#ds[@]}-1]"
+    for d in "${ds[@]}"; do
+        dstruct+=$d
+        mmd -D s -i "$EFI_IMAGE" $dstruct
+        dstruct+=/
+    done
+
+    mcopy -i "$EFI_IMAGE" "${1}" ::"${2}"
+done
\ No newline at end of file