Set up and enable the Bazel developer environment

Change-Id: Ibc5f40bc0ebb013a17d518f034ad03b385fc577e
Reviewed-on: https://fuchsia-review.googlesource.com/c/drivers/wlan/intel/iwlwifi/+/638695
Fuchsia-Auto-Submit: Renato Mangini Dias <mangini@google.com>
Reviewed-by: Sakthi Vignesh Radhakrishnan <rsakthi@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/.bazelrc b/.bazelrc
new file mode 100644
index 0000000..9085af9
--- /dev/null
+++ b/.bazelrc
@@ -0,0 +1,8 @@
+build:fuchsia_x64 --crosstool_top=@fuchsia_crosstool//:toolchain
+build:fuchsia_x64 --cpu=x86_64
+build:fuchsia_x64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
+
+build:fuchsia_arm64 --crosstool_top=@fuchsia_crosstool//:toolchain
+build:fuchsia_arm64 --cpu=aarch64
+build:fuchsia_arm64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
+
diff --git a/.gitignore b/.gitignore
index 9694afe..63d1bec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,11 +17,21 @@
 #   Test logs
 #
 bazel-*
-bazel
+
+# fuchsia sdk downloaded manually by the user (see README.md)
+sdk
+
+# compiledb information for IDE integration
+**/.cache/clangd
+compile_commands.json
+
+# symlinks created by scripts/bootstrap.sh
+tools/bazel
+tools/ffx
 
 # Files created by IntelliJ IDE.
 .idea
 iwlwifi.iml
 
 # Files created by VSCode.
-.vscode
\ No newline at end of file
+.vscode
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..61c63b7
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "sdk-integration"]
+	path = sdk-integration
+	url = https://fuchsia.googlesource.com/sdk-integration
+[submodule "third_party/mako"]
+	path = third_party/mako
+	url = https://fuchsia.googlesource.com/third_party/mako
diff --git a/README.md b/README.md
index 8b90b74..6861b5e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,104 @@
-Fuchsia Open Source Template Repository
-=======================================
+# Intel Wifi driver
 
-This repository is a template that we will use when creating new open source
-repositories for Fuchsia.
+This repository contains instructions and source code to build, package and run
+the Intel Wifi driver for Fuchsia using the Fuchsia Bazel SDK.
+
+## Prepare your environment
+
+### Create the SDK and emulator images
+
+You will need the SDK with the driver development tools and libraries.
+Currently this is produced manually in the Fuchsia tree. You can reproduce
+them with one build for qemu.x64 with the SDK archives:
+
+``` bash
+fx --dir=out/qemu set core.qemu-x64 --args=build_sdk_archives=true \
+  --args='dev_bootfs_labels=["//products/kernel_cmdline:devmgr.enable-ephemeral--true"]'
+
+fx build :default sdk sdk:ddk
+```
+
+And a different build is currently required for creating the product bundle:
+
+``` bash
+fx --dir=out/qemupbm set core.qemu-x64 \
+  --args='dev_bootfs_labels=["//products/kernel_cmdline:devmgr.enable-ephemeral--true"]'
+
+fx build :default sdk
+```
+
+
+## Bootstrap your development environment
+
+> **This is not yet a complete nor maintained Bazel integration, and it is not
+> guaranteed to work beyond the samples in this repository**. It is also not the
+> final developer experience and should not be mirrored in another repository as
+> it will change quite often until it settles.
+
+
+```
+scripts/bootstrap.sh \
+  --sdk-local ~/fuchsia/out/qemu
+  --product-bundle-local ~/fuchsia/out/qemupbm
+```
+
+Adjust the paths above accordingly.
+
+Repeat the step above whenever you want to use a new version of the SDK/DDK and
+emulator images. It is harmless to execute it repeatedly.
+
+
+### Start an emulator
+
+```
+tools/ffx emu start --net tap -H
+```
+
+Let the emulator know where are the system packages for on-demand loading:
+
+```
+tools/ffx repository add-from-pm sdk/amber-files 
+tools/ffx target repository register --alias fuchsia.com --repository devhost
+```
+
+TODO(fxbug.dev/92055): the emulator should register the sdk packages
+automatically. Manual add-from-pm and target repository register should not be
+needed.
+
+
+## Build and package the driver
+
+1. Build the driver:
+
+  ```
+  tools/bazel build --config=fuchsia_x64 third_party/iwlwifi:core
+  ```
+
+  This command will build the driver and make it available as a package on a local Fuchsia repository.
+
+2. Register the package repository
+
+  ```
+  tools/ffx repository add-from-pm -r iwlwifi_driver_repo bazel-out/x86_64-fastbuild/bin/third_party/iwlwifi/iwlwifi_driver_repo
+  tools/ffx target repository register -r iwlwifi_driver_repo
+  ```
+
+  TODO(fxbug.dev/92052): ffx does not play nice with the repository created by
+  Bazel, probably because Bazel removes the write permission so that external
+  players don't break the hermeciticy of the build. As a consequence, ffx
+  requires 'add-from-pm' and 'target repository register' every time a new
+  package is published.
+
+3. (optional) watch the device log in a separate window
+
+  ```
+  tools/ffx log
+  ```
+
+4. Load the driver
+
+  Now you are ready to register the driver.
+
+  ```
+  tools/ffx driver register fuchsia-pkg://iwlwifi_driver_repo/iwlwifi#lib/libcore.so
+  ```
diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel
new file mode 100644
index 0000000..7a9b345
--- /dev/null
+++ b/WORKSPACE.bazel
@@ -0,0 +1,37 @@
+# Copyright 2021 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+local_repository(
+    name = "fuchsia_sdk",
+    path = "bazel-rules",
+)
+
+load("@fuchsia_sdk//build_defs:fuchsia_setup.bzl", "fuchsia_setup")
+fuchsia_setup(
+    with_toolchain = True,
+)
+
+# Setup the rules imported from workstation. Eventually we should use only one set of rules.
+local_repository(
+    name = "rules_fuchsia",
+    path = "sdk-integration/bazel_rules_fuchsia",
+)
+
+load("@rules_fuchsia//fuchsia:deps.bzl", "rules_fuchsia_deps")
+rules_fuchsia_deps()
+
+
+load(
+    "@rules_fuchsia//fuchsia:deps.bzl",
+    "fuchsia_sdk_repository",
+)
+fuchsia_sdk_repository(
+    name = "fuchsia_sdk_from_workstation",
+    sha256 = {
+        "linux": "ffe0d1c48ddc300383f5b645ee0bd79229feccfd5f6c205e112fec2cf976be86",
+        "mac": "4c93c6a530354747d3de18804d420b2ed455f6dc943421b1497200331d5ab4cc",
+    },
+    cipd_tag = "version:6.20211029.2.1",
+)
+register_toolchains("@fuchsia_sdk_from_workstation//:fuchsia_toolchain_sdk")
diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh
index b9417ee..9cb6d94 100755
--- a/scripts/bootstrap.sh
+++ b/scripts/bootstrap.sh
@@ -9,7 +9,7 @@
 # This script is used to fetch the prebuilt that is needed by driver build.
 
 readonly REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/..
-readonly BAZELISK_TOOL="${REPO_ROOT}/bazel"
+readonly BAZELISK_TOOL="${REPO_ROOT}/tools/bazel"
 
 function get_os {
   uname -s | tr '[:upper:]' '[:lower:]'
@@ -28,17 +28,161 @@
   echo "$ARCH"
 }
 
+create_symlink() {
+  local TOOL
+  TOOL="$1"
+  SYMLINK="$2"
+  mkdir -p "$(dirname "${SYMLINK}")"
+  ln -f -s "${TOOL}" "${SYMLINK}"
+}
+
 create_bazel_symlink() {
   local BAZELISK_BIN="${REPO_ROOT}/vendor/bazelisk/bazelisk-$(get_os)-$(get_arch)"
   if [[ ! -x "${BAZELISK_BIN}" ]]; then
      >&2 echo "Bazel wrapper not supported in this OS/architecture. Could not find executable: ${BAZELISK_BIN}"
      exit 1
   fi
-  ln -f -s "${BAZELISK_BIN}" "${BAZELISK_TOOL}"
+  create_symlink "$BAZELISK_BIN" "$BAZELISK_TOOL"
+}
+
+create_tools_symlinks() {
+  create_symlink "${REPO_ROOT}/bazel-iwlwifi/external/fuchsia_sdk/tools/x64/ffx" ${REPO_ROOT}/tools/ffx
+}
+
+# TODO: this is probably not needed when the DDK becomes part of the core SDK.
+update_sdk_from_archive() {
+  SDK_ARCHIVE="$1"
+  if [[ ! -f "$SDK_ARCHIVE" ]]; then
+    echo "ERROR: sdk archive cannot be found: $SDK_ARCHIVE"
+    exit 1
+  fi
+  mkdir -p sdk
+  echo "Extracting SDK from archive..."
+  tar xzf "$SDK_ARCHIVE" -C sdk
+  echo "Done extracting SDK from archive."
+}
+
+
+# TODO: this is probably not needed when the DDK becomes part of the core SDK.
+update_sdk_from_local_build() {
+  SDK_OUT="$1"
+  PBM_OUT="$2"
+  if [[ ! -d "$SDK_OUT" ]]; then
+    echo "ERROR: cannot find a directory in $SDK_OUT"
+    exit 1
+  fi
+  if [[ ! -d "$PBM_OUT" ]]; then
+    echo "ERROR: cannot find a directory in $PBM_OUT"
+    exit 1
+  fi
+
+  PBM_FILES=(
+      $PBM_OUT/./gen/build/images/virtual_device.json
+      $PBM_OUT/./gen/build/images/emulator_flags.json.template
+      $PBM_OUT/./gen/build/images/product_bundle.json
+      $PBM_OUT/./obj/build/images/fuchsia/fuchsia/fvm.blk
+      $PBM_OUT/./multiboot.bin
+      $PBM_OUT/./fuchsia.zbi
+      $SDK_OUT/./amber-files
+  )
+  SDK_ARCHIVE="${SDK_OUT}/sdk/archive/core.tar.gz"
+  DDK_ARCHIVE="${SDK_OUT}/sdk/archive/ddk.tar.gz"
+  if [[ ! -f "$SDK_ARCHIVE" ]]; then
+    echo "ERROR: cannot find the core SDK archive, make sure your 'fx set' has"
+    echo "       '--args=build_sdk_archives=true' and that you build"
+    echo "       'fx build :default sdk sdk:ddk': $SDK_ARCHIVE"
+    exit 1
+  fi
+  if [[ ! -f "$DDK_ARCHIVE" ]]; then
+    echo "ERROR: cannot find the DDK archive, make sure your 'fx set' has"
+    echo "       '--args=build_sdk_archives=true' and that you build"
+    echo "       'fx build :default sdk sdk:ddk': $DDK_ARCHIVE"
+    exit 1
+  fi
+
+  for f in "${PBM_FILES[@]}"; do
+    if [[ ! -e "$f" ]]; then
+      echo "ERROR: cannot find file needed to run the emulator. Make sure your"
+      echo "       'fx set' does NOT have '--args=build_sdk_archives=true'"
+      echo "       and that you build with 'fx build :default sdk': $f"
+      exit 1
+    fi
+  done
+
+  LOCAL_SDK_OUT=./sdk
+  if [[ -d "$LOCAL_SDK_OUT" ]]; then
+    echo "Removing old SDK in $LOCAL_SDK_OUT"
+    rm -Rf "${LOCAL_SDK_OUT}"
+  fi
+  echo "Syncing SDK from local build..."
+  mkdir "${LOCAL_SDK_OUT}"
+  tar xzf "${SDK_OUT}/sdk/archive/core.tar.gz" -C "${LOCAL_SDK_OUT}"
+  tar xzf "${SDK_OUT}/sdk/archive/ddk.tar.gz" -C "${LOCAL_SDK_OUT}" --transform='s/meta\/manifest.json/meta\/ddk_manifest.json/'
+  rsync -aR "${PBM_FILES[@]}" "${LOCAL_SDK_OUT}"
+}
+
+generate_rules_fuchsia() {
+  echo "Generating Fuchsia Bazel rules..."
+  if [[ ! -d "${REPO_ROOT}/sdk" ]]; then
+    echo "Warning! Cannot find directory 'sdk', please use argument --sdk-archive or --sdk-local and --product-bundle-local"
+    echo "Bazel rules will not be generated for the Fuchsia SDK. Please run bootstrap.sh again with the proper argument."
+    return
+    # TODO(mangini) exit on error here. Disabling error for now to avoid
+    # triggering CI/CQ, since we cannot run this in CI/CQ until the DDK is
+    # published in an accessible place.
+    # exit 1
+  fi
+  pushd "${REPO_ROOT}/sdk-integration/bazel_rules_generator/" > /dev/null || exit
+  ./generate.py \
+    --directory "${REPO_ROOT}/sdk" \
+    --output "${REPO_ROOT}/bazel-rules"
+  popd > /dev/null || exit
+  echo "Done generating Fuchsia Bazel rules."
+}
+
+
+syntax() {
+    echo "   $(basename $0)"
+    echo "      assume that there is a directory 'sdk' with an SDK, DDK and"
+    echo "      product bundle files for the emulator"
+    echo
+    echo "   $(basename $0) --sdk-archive SDK_TARGZ"
+    echo "      load an SDK and the emulator product bundle files from the"
+    echo "      given tar.gz archive."
+    echo
+    echo "   $(basename $0) --sdk-local FUCHSIA_OUT_SDK --product-bundle-local FUCHSIA_OUT_PRODUCT_BUNDLE"
+    echo "      copy the SDK from a build directory of a local Fuchsia tree,"
+    echo "      and copy the product bundle files for the emulator from another"
+    echo "      build directory."
+}
+
+
+update_git_submodules() {
+  echo "Updating git submodules"
+  git submodule update --init --recursive
 }
 
 main() {
+
+  update_git_submodules
+
+  if [[ $# -gt 0 ]]; then
+    if [[ "$1" == "--sdk-archive" && $# -eq 2 ]]; then
+      update_sdk_from_archive "$2"
+    elif [[ $# -eq 4 && "$1" == "--sdk-local" && "$3" == "--product-bundle-local" ]]; then
+      update_sdk_from_local_build $2 $4
+    elif [[ $# -eq 4 && "$3" == "--sdk-local" && "$1" == "--product-bundle-local" ]]; then
+      update_sdk_from_local_build $4 $2
+    else
+      echo "Invalid syntax."
+      syntax
+      exit 1
+    fi
+  fi
+
   create_bazel_symlink
+  create_tools_symlinks
+  generate_rules_fuchsia
 }
 
 main "$@"
diff --git a/scripts/build.sh b/scripts/build.sh
index 24179cd..d80dc10 100755
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -10,11 +10,20 @@
 # can pass.
 
 readonly REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/..
-readonly BAZELISK_TOOL="${REPO_ROOT}/bazel"
+readonly BAZELISK_TOOL="${REPO_ROOT}/tools/bazel"
 
 main() {
-  "$BAZELISK_TOOL" --version
-  echo "Everything build and all tests passed."
+  if [[ -d "${REPO_ROOT}/sdk" ]]; then
+    "$BAZELISK_TOOL" build --config=fuchsia_x64 third_party/iwlwifi:core
+    echo "Everything build and all tests passed."
+  else
+    # TODO(mangini): handle this appropriately when the DDK is published by
+    # infra in an accessible way. We need to keep this fallback state to avoid
+    # triggering CI/CQ since the build bot cannot build the driver until it has
+    # access to a valid DDK.
+    "$BAZELISK_TOOL" --version
+    echo "Not building now since the DDK is not available. Please re-run scripts/bootstrap.sh with the appropriate flag to generate the Blaze build rules."
+  fi
 }
 
 main "$@"
diff --git a/sdk-integration b/sdk-integration
new file mode 160000
index 0000000..bfda1ec
--- /dev/null
+++ b/sdk-integration
@@ -0,0 +1 @@
+Subproject commit bfda1ec54b53eb776ef977f815722e4e2ecf75c8
diff --git a/third_party/iwlwifi/BUILD.bazel b/third_party/iwlwifi/BUILD.bazel
index 16895c1..3d258ba 100644
--- a/third_party/iwlwifi/BUILD.bazel
+++ b/third_party/iwlwifi/BUILD.bazel
@@ -45,3 +45,4 @@
 #        "//zircon/system/public",
     ],
 )
+
diff --git a/third_party/iwlwifi/platform/BUILD.bazel b/third_party/iwlwifi/platform/BUILD.bazel
index 14b6185..bffbd52 100644
--- a/third_party/iwlwifi/platform/BUILD.bazel
+++ b/third_party/iwlwifi/platform/BUILD.bazel
@@ -1,13 +1,23 @@
 
 package(default_visibility = ["//visibility:public"])
 
-#driver_bind_rules(
-#    name = "iwlwifi_driver_bind",
-#    rules = "iwlwifi.bind",
-#    output_header = "iwlwifi_bind.h",
+load("@fuchsia_sdk//build_defs:driver_bind_rules.bzl", "driver_header_bind_rules", "driver_bytecode_bind_rules")
 
-#    deps = ["@fuchsia_sdk//bind/fuchsia_usb"],
-#)
+driver_header_bind_rules(
+    name = "iwlwifi_driver_bind_header",
+    rules = "iwlwifi.bind",
+    output = "iwlwifi_bind.h",
+
+    deps = ["@fuchsia_sdk//bind/fuchsia_usb"],
+)
+
+driver_bytecode_bind_rules(
+    name = "iwlwifi_driver_bind_bytecode",
+    rules = "iwlwifi.bind",
+    output = "iwlwifi_bind.bc",
+
+    deps = ["@fuchsia_sdk//bind/fuchsia_usb"],
+)
 
 cc_library(
     name = "driver_inspector",
diff --git a/third_party/mako b/third_party/mako
new file mode 160000
index 0000000..c374704
--- /dev/null
+++ b/third_party/mako
@@ -0,0 +1 @@
+Subproject commit c37470481fccb86c2ede492cbbbabba2b6c238a1