[zircon] [gn] Build multiboot trampoline loader

This is in data_deps of the x86 kernel.

Bug: BLD-325
Test: gn gen && ninja
Change-Id: I55a81934b6be86bc200afb2a4bdf3aca562c6727
diff --git a/zircon/kernel/target/pc/BUILD.gn b/zircon/kernel/target/pc/BUILD.gn
index fd5335b..6985ea5 100644
--- a/zircon/kernel/target/pc/BUILD.gn
+++ b/zircon/kernel/target/pc/BUILD.gn
@@ -7,4 +7,9 @@
     "$zx/kernel/dev/intel_rng",
     "$zx/kernel/platform/pc",
   ]
+
+  # Also build the Multiboot trampoline to support legacy boot loaders.
+  data_deps = [
+    "multiboot",
+  ]
 }
diff --git a/zircon/kernel/target/pc/multiboot/BUILD.gn b/zircon/kernel/target/pc/multiboot/BUILD.gn
new file mode 100644
index 0000000..afe121b
--- /dev/null
+++ b/zircon/kernel/target/pc/multiboot/BUILD.gn
@@ -0,0 +1,97 @@
+# Copyright 2019 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.
+
+import("$zx/public/gn/toolchain/environment.gni")
+import("$zx/public/gn/toolchain/environment_redirect.gni")
+
+# The Multiboot trampoline gets its own toolchain to build x86-32 code.
+if (current_toolchain == default_toolchain) {
+  # Define the special toolchain itself only in the default toolchain.
+  environment("multiboot") {
+    cpu = "x64"
+    configs += standard_fuchsia_configs + [ ":multiboot_config" ]
+    globals = {
+      is_kernel = true
+    }
+    strip = "--strip-sections"
+  }
+} else if (toolchain.environment == "multiboot") {
+  # This is the top config for all code in the multiboot_toolchain.
+  config("multiboot_config") {
+    configs = [
+      "$zx/kernel:headers",
+      "$zx/kernel:standalone",
+      "$zx/kernel:warnings",
+      "$zx/kernel/arch/x86:kernel",
+      "$zx/public/gn/config:no_sanitizers",
+    ]
+    compiler_flags = [
+      "-m32",
+      "-mregparm=3",
+      "-fno-pic",
+    ]
+    asmflags = compiler_flags
+    cflags = compiler_flags
+    ldflags = compiler_flags
+    if (is_gcc) {
+      ldflags += [ "-no-pie" ]
+    } else {
+      ldflags += [ "-Wl,--no-pie" ]
+    }
+  }
+
+  # We could make a Multiboot image meant to be loaded without ELF headers
+  # and do `objcopy -O binary` here.  But there's no reason to, and having
+  # an ELF binary to look at is nicer.  To remove the ELF headers instead,
+  # the linker script would need to remove `+ SIZEOF_HEADERS` and then the
+  # multiboot header would be first thing in the raw binary.  The toolchain
+  # implicitly strips executables, so `multiboot.bin` is a lean, fully
+  # stripped ELF/Multiboot image.
+  executable("multiboot") {
+    output_extension = "bin"
+    output_dir = root_build_dir
+    output_path = rebase_path("$output_dir/$target_name.$output_extension",
+                              root_build_dir)
+    metadata = {
+      images = []
+      foreach(name,
+              [
+                "multiboot-kernel",
+                "qemu-kernel",
+              ]) {
+        images += [
+          {
+            name = name
+            type = "kernel"
+            path = output_path
+          },
+        ]
+      }
+    }
+    sources = [
+      "multiboot-main.c",
+      "multiboot-start.S",
+      "paging.c",
+      "trampoline.c",
+      "util.c",
+    ]
+    deps = [
+      "$zx/kernel/arch/x86/page_tables:headers",
+      "$zx/kernel/platform/pc:headers",
+      "$zx/system/ulib/libzbi",
+    ]
+    ldflags = [ "-Wl,-T," + rebase_path("multiboot.ld", root_build_dir) ]
+    inputs = [
+      "multiboot.ld",
+    ]
+  }
+} else {
+  # In any other toolchain, just redirect to the proper toolchain.
+  environment_redirect("multiboot") {
+    environment_label = ":multiboot"
+    deps = [
+      ":multiboot",
+    ]
+  }
+}