third_party/efistub: init

Adds the EFI stub from systemd-boot, built using our new EFI toolchain.
This allows us to bundle kernels, command lines and other data into
single EFI payloads and also sign them later.

A rules to build these unified EFI payloads is coming later.

Change-Id: I789e893ff88541f3dc9e7400ccd2565ae414e554
Reviewed-on: https://review.monogon.dev/c/monogon/+/335
Reviewed-by: Sergiusz Bazanski <serge@monogon.tech>
diff --git a/WORKSPACE b/WORKSPACE
index 5462219..fcf5197 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -216,6 +216,15 @@
     version = "3.0.14",
 )
 
+load("//third_party/efistub:external.bzl", "efistub_external")
+
+efistub_external(
+    name = "efistub",
+    # Developed in the systemd monorepo, pinned to master as there have been a bunch of critical fixes for the
+    # EFI stub since 249.
+    version = "3542da2442d8b29661b47c42ad7e5fa9bc8562ec",
+)
+
 register_toolchains("//:host_python")
 
 # python dependencies. Currently we don't use Python, but some of our deps (ie. gvisor) do expect @pydeps// to exist, even
diff --git a/third_party/efistub/BUILD.bazel b/third_party/efistub/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/efistub/BUILD.bazel
diff --git a/third_party/efistub/efistub.bzl b/third_party/efistub/efistub.bzl
new file mode 100644
index 0000000..4eec74d
--- /dev/null
+++ b/third_party/efistub/efistub.bzl
@@ -0,0 +1,20 @@
+cc_binary(
+    name = "efistub",
+    srcs = [("src/boot/efi/%s" % v) for v in [
+        "assert.c",
+        "cpio.c",
+        "disk.c",
+        "graphics.c",
+        "linux.c",
+        "measure.c",
+        "pe.c",
+        "secure-boot.c",
+        "splash.c",
+        "stub.c",
+        "util.c",
+    ]] + glob(["src/boot/efi/*.h", "src/fundamental/*.c", "src/fundamental/*.h"]),
+    includes = ["src/fundamental"],
+    copts = ["-std=gnu99", "-DSD_BOOT", "-DGIT_VERSION=\\\"0.0.0-mngn\\\""],
+    deps = ["@gnuefi//:gnuefi"],
+    visibility = ["//visibility:public"],
+)
diff --git a/third_party/efistub/external.bzl b/third_party/efistub/external.bzl
new file mode 100644
index 0000000..f5fc095
--- /dev/null
+++ b/third_party/efistub/external.bzl
@@ -0,0 +1,19 @@
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def efistub_external(name, version):
+    sums = {
+        "3542da2442d8b29661b47c42ad7e5fa9bc8562ec": "021c135bee39ca7346d1f09923be7c044a3d35866ff411a7c9626702ff4c9523",
+    }
+
+    http_archive(
+        name = name,
+        build_file = "@//third_party/efistub:efistub.bzl",
+        sha256 = sums[version],
+        strip_prefix = "systemd-%s" % version,
+        patch_args = ["-p1"],
+        patches = [
+            "//third_party/efistub/patches:use-sysv-for-kernel.patch",
+            "//third_party/efistub/patches:remove-wrong-cmdline-assertion.patch",
+        ],
+        urls = ["https://github.com/systemd/systemd/archive/%s.zip" % version],
+    )
diff --git a/third_party/efistub/patches/BUILD b/third_party/efistub/patches/BUILD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/efistub/patches/BUILD
diff --git a/third_party/efistub/patches/remove-wrong-cmdline-assertion.patch b/third_party/efistub/patches/remove-wrong-cmdline-assertion.patch
new file mode 100644
index 0000000..216c5e9
--- /dev/null
+++ b/third_party/efistub/patches/remove-wrong-cmdline-assertion.patch
@@ -0,0 +1,26 @@
+From 8f0fa4ec981e6c22013949f551ef1b2d7b7dc0e3 Mon Sep 17 00:00:00 2001
+From: Lorenz Brun <lorenz@monogon.tech>
+Date: Wed, 29 Sep 2021 19:10:17 +0200
+Subject: [PATCH] Remove wrong assertion that a cmdline exists
+
+All uses of cmdline are gated behind an if statement, it is perfectly
+acceptable for cmdline to not be passed.
+---
+ src/boot/efi/linux.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
+index 0d58f39ff6..ad82ade019 100644
+--- a/src/boot/efi/linux.c
++++ b/src/boot/efi/linux.c
+@@ -40,7 +40,6 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
+         EFI_STATUS err;
+ 
+         assert(image);
+-        assert(cmdline);
+ 
+         image_params = (const struct boot_params *) linux_addr;
+ 
+-- 
+2.25.1
+
diff --git a/third_party/efistub/patches/use-sysv-for-kernel.patch b/third_party/efistub/patches/use-sysv-for-kernel.patch
new file mode 100644
index 0000000..4a69bbe
--- /dev/null
+++ b/third_party/efistub/patches/use-sysv-for-kernel.patch
@@ -0,0 +1,35 @@
+From d725d3cd472434c52e3c4bebbd7b242329d7a1b4 Mon Sep 17 00:00:00 2001
+From: Lorenz Brun <lorenz@monogon.tech>
+Date: Tue, 28 Sep 2021 05:21:10 +0200
+Subject: [PATCH] Use the SysV ABI calling into the kernel
+
+The original code expected to be compiled into a PE binary but
+internally still using the SysV ABI. Lots of trampolines are used to
+make that work as everything outside is using the MSVC ABI.
+The kernel also exposes the MSVC ABI using trampolines, but only for
+direct PE entrypoints. The EFI handover jump target does not do ABI
+conversion and thus matches the kernel's internal ABI, which is SysV.
+
+This means this call needs to be annotated as otherwise we'd call into
+the Kernel's EFI code using the MSVC ABI which is expecting SysV.
+Sigh.
+---
+ src/boot/efi/linux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
+index 5232a3ba40..0d58f39ff6 100644
+--- a/src/boot/efi/linux.c
++++ b/src/boot/efi/linux.c
+@@ -12,7 +12,7 @@
+ #define __regparm0__
+ #endif
+ 
+-typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
++typedef __attribute__((sysv_abi)) VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
+ 
+ static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
+         handover_f handover;
+-- 
+2.25.1
+