1# Copyright (C) 2023 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15load("@gbl_llvm_prebuilts//:info.bzl", "LLVM_PREBUILTS_C_INCLUDE")
16load("@rules_rust//bindgen:defs.bzl", "rust_bindgen")
17load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
18
19package(
20    default_visibility = ["//visibility:public"],
21)
22
23# Newer version of `rust_bindgen` requires a `cc_library` target that actually produces a static
24# library and instead of only headers. Thus we generate a placeholder source file to meet the
25# requirement.
26genrule(
27    name = "bindgen_noop_cc",
28    outs = ["bindgen_noop_cc.cc"],
29    cmd = "touch $(OUTS)",
30)
31
32cc_library(
33    name = "efi_c_headers",
34    srcs = [":bindgen_noop_cc"],
35    hdrs = [
36        "defs/boot_service.h",
37        "defs/efi.h",
38        "defs/protocols/android_boot_protocol.h",
39        "defs/protocols/block_io_protocol.h",
40        "defs/protocols/device_path_protocol.h",
41        "defs/protocols/loaded_image_protocol.h",
42        "defs/protocols/riscv_efi_boot_protocol.h",
43        "defs/protocols/simple_network_protocol.h",
44        "defs/protocols/simple_text_input_protocol.h",
45        "defs/protocols/simple_text_output_protocol.h",
46        "defs/runtime_service.h",
47        "defs/system_table.h",
48        "defs/types.h",
49    ],
50    includes = ["defs"],
51)
52
53# Side note: function pointers for UEFI interfaces need to specify the "efiapi" ABI. i.e.
54# "unsafe extern "efiapi" fn(...)". bindgen uses "extern "C"" by default. We are currently fine
55# because for x86_64/x86_32/aarch64, we use dedicated rust UEFI compiler which uses EFIAPI ABI by
56# default. For riscv64 which we use ELF compiler, the efiapi calling convention is the same as C
57# calling convention according to the UEFI spec at the time of writing. If we do eventually run
58# into problems, we need to use a newer version of bindgen 0.65.0 or above, which offers
59# "--override-abi" with "efiapi" option.
60rust_bindgen(
61    name = "efi_defs_bindgen",
62    bindgen_flags = [
63        "--ctypes-prefix",
64        "core::ffi",
65        "--use-core",
66        "--with-derive-partialeq",
67        "--with-derive-default",
68        "--with-derive-custom-struct=EfiMemoryDescriptor=AsBytes,FromBytes,FromZeroes",
69        "--allowlist-type",
70        "(Efi.*)",
71        "--raw-line",
72        """
73#![allow(non_camel_case_types)]
74#![allow(non_snake_case)]
75use zerocopy::{AsBytes, FromBytes, FromZeroes};""",
76    ],
77    cc_lib = ":efi_c_headers",
78    # For x86_32, we need to explicitly specify 32bit architecture.
79    clang_flags = select({
80        "@gbl//toolchain:gbl_rust_uefi_x86_32": ["-m32"],
81        "//conditions:default": ["-m64"],
82    }) + [
83        "-I{}".format(LLVM_PREBUILTS_C_INCLUDE),
84        "-nostdinc",
85    ],
86    header = "defs/efi.h",
87)
88
89# Copy the generated source to "src/defs.rs" in the output assembly, so that libefi can include it
90# as a source.
91genrule(
92    name = "efi_defs_genrule",
93    srcs = [":efi_defs_bindgen"],
94    outs = ["src/defs.rs"],
95    cmd = "cat $(location :efi_defs_bindgen) > $@",
96)
97
98rust_library(
99    name = "libefi",
100    srcs = [
101        "src/allocation.rs",
102        "src/defs.rs",  # Generated by :efi_defs_genrule
103        "src/lib.rs",
104        "src/protocol.rs",
105        "src/protocol/android_boot.rs",
106        "src/protocol/block_io.rs",
107        "src/protocol/device_path.rs",
108        "src/protocol/loaded_image.rs",
109        "src/protocol/riscv.rs",
110        "src/protocol/simple_network.rs",
111        "src/protocol/simple_text_input.rs",
112        "src/protocol/simple_text_output.rs",
113    ],
114    crate_name = "efi",
115    data = [":efi_defs_genrule"],
116    deps = ["@zerocopy"],
117)
118
119rust_test(
120    name = "libefi_test",
121    crate = ":libefi",
122)
123