diff mbox series

[04/13] Kbuild: Rust support

Message ID 20210414184604.23473-5-ojeda@kernel.org (mailing list archive)
State New, archived
Headers show
Series Rust support | expand

Commit Message

Miguel Ojeda April 14, 2021, 6:45 p.m. UTC
From: Miguel Ojeda <ojeda@kernel.org>

This commit includes also the `Kconfig` entries related to Rust,
the Rust configuration printer, the target definition files,
the version detection script and a few other bits.

In the future, we will likely want to generate the target files
on the fly via a script.

With this in place, we will be adding the rest of the bits piece
by piece and enabling their builds.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 .gitignore                        |   2 +
 .rustfmt.toml                     |  12 +++
 Documentation/kbuild/kbuild.rst   |   4 +
 Documentation/process/changes.rst |   9 ++
 Makefile                          | 120 +++++++++++++++++++++++--
 arch/arm64/rust/target.json       |  40 +++++++++
 arch/powerpc/rust/target.json     |  30 +++++++
 arch/x86/rust/target.json         |  42 +++++++++
 init/Kconfig                      |  27 ++++++
 lib/Kconfig.debug                 | 100 +++++++++++++++++++++
 rust/.gitignore                   |   5 ++
 rust/Makefile                     | 141 ++++++++++++++++++++++++++++++
 scripts/Makefile.build            |  19 ++++
 scripts/Makefile.lib              |  12 +++
 scripts/kconfig/confdata.c        |  67 +++++++++++++-
 scripts/rust-version.sh           |  31 +++++++
 16 files changed, 654 insertions(+), 7 deletions(-)
 create mode 100644 .rustfmt.toml
 create mode 100644 arch/arm64/rust/target.json
 create mode 100644 arch/powerpc/rust/target.json
 create mode 100644 arch/x86/rust/target.json
 create mode 100644 rust/.gitignore
 create mode 100644 rust/Makefile
 create mode 100755 scripts/rust-version.sh

Comments

Nick Desaulniers April 14, 2021, 11:19 p.m. UTC | #1
On Wed, Apr 14, 2021 at 11:48 AM <ojeda@kernel.org> wrote:
>
> From: Miguel Ojeda <ojeda@kernel.org>
>
> This commit includes also the `Kconfig` entries related to Rust,
> the Rust configuration printer, the target definition files,
> the version detection script and a few other bits.
>
> In the future, we will likely want to generate the target files
> on the fly via a script.
>
> With this in place, we will be adding the rest of the bits piece
> by piece and enabling their builds.
>
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
> Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
> Co-developed-by: Finn Behrens <me@kloenk.de>
> Signed-off-by: Finn Behrens <me@kloenk.de>
> Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
> Co-developed-by: Michael Ellerman <mpe@ellerman.id.au>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
>  .gitignore                        |   2 +
>  .rustfmt.toml                     |  12 +++
>  Documentation/kbuild/kbuild.rst   |   4 +
>  Documentation/process/changes.rst |   9 ++
>  Makefile                          | 120 +++++++++++++++++++++++--
>  arch/arm64/rust/target.json       |  40 +++++++++
>  arch/powerpc/rust/target.json     |  30 +++++++
>  arch/x86/rust/target.json         |  42 +++++++++
>  init/Kconfig                      |  27 ++++++
>  lib/Kconfig.debug                 | 100 +++++++++++++++++++++
>  rust/.gitignore                   |   5 ++
>  rust/Makefile                     | 141 ++++++++++++++++++++++++++++++
>  scripts/Makefile.build            |  19 ++++
>  scripts/Makefile.lib              |  12 +++
>  scripts/kconfig/confdata.c        |  67 +++++++++++++-
>  scripts/rust-version.sh           |  31 +++++++
>  16 files changed, 654 insertions(+), 7 deletions(-)
>  create mode 100644 .rustfmt.toml
>  create mode 100644 arch/arm64/rust/target.json
>  create mode 100644 arch/powerpc/rust/target.json
>  create mode 100644 arch/x86/rust/target.json
>  create mode 100644 rust/.gitignore
>  create mode 100644 rust/Makefile
>  create mode 100755 scripts/rust-version.sh
>
> diff --git a/.gitignore b/.gitignore
> index 3af66272d6f1..6ba4f516f46c 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -37,6 +37,7 @@
>  *.o
>  *.o.*
>  *.patch
> +*.rmeta
>  *.s
>  *.so
>  *.so.dbg
> @@ -96,6 +97,7 @@ modules.order
>  !.gitattributes
>  !.gitignore
>  !.mailmap
> +!.rustfmt.toml
>
>  #
>  # Generated include files
> diff --git a/.rustfmt.toml b/.rustfmt.toml
> new file mode 100644
> index 000000000000..5893c0e3cbde
> --- /dev/null
> +++ b/.rustfmt.toml
> @@ -0,0 +1,12 @@
> +edition = "2018"
> +format_code_in_doc_comments = true
> +newline_style = "Unix"
> +
> +# Unstable options that help catching some mistakes in formatting and that we may want to enable
> +# when they become stable.
> +#
> +# They are kept here since they are useful to run from time to time.
> +#reorder_impl_items = true
> +#comment_width = 100
> +#wrap_comments = true
> +#normalize_comments = true
> diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst
> index 2d1fc03d346e..1109d18d9377 100644
> --- a/Documentation/kbuild/kbuild.rst
> +++ b/Documentation/kbuild/kbuild.rst
> @@ -57,6 +57,10 @@ CFLAGS_MODULE
>  -------------
>  Additional module specific options to use for $(CC).
>
> +KRUSTCFLAGS
> +-----------
> +Additional options to the Rust compiler (for built-in and modules).
> +
>  LDFLAGS_MODULE
>  --------------
>  Additional options used for $(LD) when linking modules.
> diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst
> index dac17711dc11..4b6ba5458706 100644
> --- a/Documentation/process/changes.rst
> +++ b/Documentation/process/changes.rst
> @@ -31,6 +31,8 @@ you probably needn't concern yourself with pcmciautils.
>  ====================== ===============  ========================================
>  GNU C                  4.9              gcc --version
>  Clang/LLVM (optional)  10.0.1           clang --version
> +rustc (optional)       nightly          rustc --version
> +bindgen (optional)     0.56.0           bindgen --version
>  GNU make               3.81             make --version
>  binutils               2.23             ld -v
>  flex                   2.5.35           flex --version
> @@ -56,6 +58,7 @@ iptables               1.4.2            iptables -V
>  openssl & libcrypto    1.0.0            openssl version
>  bc                     1.06.95          bc --version
>  Sphinx\ [#f1]_        1.3              sphinx-build --version
> +rustdoc (optional)     nightly          rustdoc --version
>  ====================== ===============  ========================================
>
>  .. [#f1] Sphinx is needed only to build the Kernel documentation
> @@ -330,6 +333,12 @@ Sphinx
>  Please see :ref:`sphinx_install` in :ref:`Documentation/doc-guide/sphinx.rst <sphinxdoc>`
>  for details about Sphinx requirements.
>
> +rustdoc
> +-------
> +
> +``rustdoc`` is used to generate Rust documentation. Please see
> +:ref:`Documentation/rust/docs.rst <rust_docs>` for more information.
> +
>  Getting updated software
>  ========================
>
> diff --git a/Makefile b/Makefile
> index 9c75354324ed..62b3bba38635 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -120,6 +120,13 @@ endif
>
>  export KBUILD_CHECKSRC
>
> +# Enable "clippy" (a linter) as part of the Rust compilation.
> +#
> +# Use 'make CLIPPY=1' to enable it.
> +ifeq ("$(origin CLIPPY)", "command line")
> +  KBUILD_CLIPPY := $(CLIPPY)
> +endif

Rather than check the origin (yikes, are we intentionally avoiding env
vars?), can this simply be
ifneq ($(CLIPPY),)
  KBUILD_CLIPPY := $(CLIPPY)
endif

Then you can specify whatever value you want, support command line or
env vars, etc.?

> +
>  # Use make M=dir or set the environment variable KBUILD_EXTMOD to specify the
>  # directory of external module to build. Setting M= takes precedence.
>  ifeq ("$(origin M)", "command line")
> @@ -263,7 +270,7 @@ no-dot-config-targets := $(clean-targets) \
>                          cscope gtags TAGS tags help% %docs check% coccicheck \
>                          $(version_h) headers headers_% archheaders archscripts \
>                          %asm-generic kernelversion %src-pkg dt_binding_check \
> -                        outputmakefile
> +                        outputmakefile rustfmt rustfmtcheck
>  no-sync-config-targets := $(no-dot-config-targets) %install kernelrelease \
>                           image_name
>  single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.s %.symtypes %/
> @@ -444,6 +451,10 @@ OBJDUMP            = $(CROSS_COMPILE)objdump
>  READELF                = $(CROSS_COMPILE)readelf
>  STRIP          = $(CROSS_COMPILE)strip
>  endif
> +RUSTC          = rustc
> +RUSTFMT                = rustfmt
> +CLIPPY_DRIVER  = clippy-driver
> +BINDGEN                = bindgen
>  PAHOLE         = pahole
>  RESOLVE_BTFIDS = $(objtree)/tools/bpf/resolve_btfids/resolve_btfids
>  LEX            = flex
> @@ -467,9 +478,11 @@ CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
>                   -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF)
>  NOSTDINC_FLAGS :=
>  CFLAGS_MODULE   =
> +RUSTCFLAGS_MODULE =
>  AFLAGS_MODULE   =
>  LDFLAGS_MODULE  =
>  CFLAGS_KERNEL  =
> +RUSTCFLAGS_KERNEL =
>  AFLAGS_KERNEL  =
>  LDFLAGS_vmlinux =
>
> @@ -498,15 +511,30 @@ KBUILD_CFLAGS   := -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs \
>                    -Werror=return-type -Wno-format-security \
>                    -std=gnu89
>  KBUILD_CPPFLAGS := -D__KERNEL__
> +KBUILD_RUSTCFLAGS := --emit=dep-info,obj,metadata --edition=2018 \
> +                    -Cpanic=abort -Cembed-bitcode=n -Clto=n -Crpath=n \
> +                    -Cforce-unwind-tables=n -Ccodegen-units=1 \
> +                    -Zbinary_dep_depinfo=y -Zsymbol-mangling-version=v0
>  KBUILD_AFLAGS_KERNEL :=
>  KBUILD_CFLAGS_KERNEL :=
> +KBUILD_RUSTCFLAGS_KERNEL :=
>  KBUILD_AFLAGS_MODULE  := -DMODULE
>  KBUILD_CFLAGS_MODULE  := -DMODULE
> +KBUILD_RUSTCFLAGS_MODULE := --cfg MODULE
>  KBUILD_LDFLAGS_MODULE :=
>  KBUILD_LDFLAGS :=
>  CLANG_FLAGS :=
>
> -export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
> +ifeq ($(KBUILD_CLIPPY),1)
> +       RUSTC_OR_CLIPPY_QUIET := CLIPPY
> +       RUSTC_OR_CLIPPY = $(CLIPPY_DRIVER)
> +else
> +       RUSTC_OR_CLIPPY_QUIET := RUSTC
> +       RUSTC_OR_CLIPPY = $(RUSTC)
> +endif
> +export RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY
> +
> +export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC RUSTC BINDGEN
>  export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
>  export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
>  export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD
> @@ -514,9 +542,10 @@ export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
>
>  export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
>  export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
> +export KBUILD_RUSTCFLAGS RUSTCFLAGS_KERNEL RUSTCFLAGS_MODULE
>  export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
> -export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
> -export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
> +export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_RUSTCFLAGS_MODULE KBUILD_LDFLAGS_MODULE
> +export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTCFLAGS_KERNEL
>
>  # Files to ignore in find ... statements
>
> @@ -712,7 +741,7 @@ $(KCONFIG_CONFIG):
>  quiet_cmd_syncconfig = SYNC    $@
>        cmd_syncconfig = $(MAKE) -f $(srctree)/Makefile syncconfig
>
> -%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h: $(KCONFIG_CONFIG)
> +%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h %/generated/rustc_cfg: $(KCONFIG_CONFIG)
>         +$(call cmd,syncconfig)
>  else # !may-sync-config
>  # External modules and some install targets need include/generated/autoconf.h
> @@ -738,12 +767,43 @@ KBUILD_CFLAGS     += $(call cc-disable-warning, format-truncation)
>  KBUILD_CFLAGS  += $(call cc-disable-warning, format-overflow)
>  KBUILD_CFLAGS  += $(call cc-disable-warning, address-of-packed-member)
>
> +ifdef CONFIG_RUST_DEBUG_ASSERTIONS
> +KBUILD_RUSTCFLAGS += -Cdebug-assertions=y
> +else
> +KBUILD_RUSTCFLAGS += -Cdebug-assertions=n
> +endif
> +
> +ifdef CONFIG_RUST_OVERFLOW_CHECKS
> +KBUILD_RUSTCFLAGS += -Coverflow-checks=y
> +else
> +KBUILD_RUSTCFLAGS += -Coverflow-checks=n
> +endif
> +
>  ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
>  KBUILD_CFLAGS += -O2
> +KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP := 2
>  else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
>  KBUILD_CFLAGS += -O3
> +KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP := 3
>  else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
>  KBUILD_CFLAGS += -Os
> +KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP := z

-Oz in clang typically generates larger kernel code than -Os; LLVM
seems to aggressively emit libcalls even when the setup for a call
would be larger than the inlined call itself.  Is z smaller than s for
the existing rust examples?

> +endif
> +
> +ifdef CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
> +KBUILD_RUSTCFLAGS += -Copt-level=$(KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP)
> +else ifdef CONFIG_RUST_OPT_LEVEL_0
> +KBUILD_RUSTCFLAGS += -Copt-level=0
> +else ifdef CONFIG_RUST_OPT_LEVEL_1
> +KBUILD_RUSTCFLAGS += -Copt-level=1
> +else ifdef CONFIG_RUST_OPT_LEVEL_2
> +KBUILD_RUSTCFLAGS += -Copt-level=2
> +else ifdef CONFIG_RUST_OPT_LEVEL_3
> +KBUILD_RUSTCFLAGS += -Copt-level=3
> +else ifdef CONFIG_RUST_OPT_LEVEL_S
> +KBUILD_RUSTCFLAGS += -Copt-level=s
> +else ifdef CONFIG_RUST_OPT_LEVEL_Z
> +KBUILD_RUSTCFLAGS += -Copt-level=z

This is a mess; who thought it would be a good idea to support
compiling the rust code at a different optimization level than the
rest of the C code in the kernel?  Do we really need that flexibility
for Rust kernel code, or can we drop this feature?

>  endif
>
>  # Tell gcc to never replace conditional load with a non-conditional one
> @@ -793,6 +853,7 @@ endif
>  KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable)
>  ifdef CONFIG_FRAME_POINTER
>  KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
> +KBUILD_RUSTCFLAGS += -Cforce-frame-pointers=y

Don't the target.json files all set `"eliminate-frame-pointer":
false,`?  Is this necessary then?  Also, which targets retain frame
pointers at which optimization levels is quite messy (in C compilers),
as well as your choice of unwinder, which is configurable for certain
architectures.

>  else
>  # Some targets (ARM with Thumb2, for example), can't be built with frame
>  # pointers.  For those, we don't have FUNCTION_TRACER automatically
> @@ -826,6 +887,8 @@ ifdef CONFIG_CC_IS_GCC
>  DEBUG_CFLAGS   += $(call cc-ifversion, -lt, 0500, $(call cc-option, -fno-var-tracking-assignments))
>  endif
>
> +DEBUG_RUSTCFLAGS :=
> +
>  ifdef CONFIG_DEBUG_INFO
>
>  ifdef CONFIG_DEBUG_INFO_SPLIT
> @@ -836,6 +899,11 @@ endif
>
>  ifneq ($(LLVM_IAS),1)
>  KBUILD_AFLAGS  += -Wa,-gdwarf-2
> +ifdef CONFIG_DEBUG_INFO_REDUCED
> +DEBUG_RUSTCFLAGS += -Cdebuginfo=1
> +else
> +DEBUG_RUSTCFLAGS += -Cdebuginfo=2
> +endif
>  endif

This should not be in the `ifneq ($(LLVM_IAS),1)` block, otherwise if
I set `LLVM_IAS=1` when invoking `make` then these wont get set.

>
>  ifndef CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
> @@ -860,6 +928,9 @@ endif # CONFIG_DEBUG_INFO
>  KBUILD_CFLAGS += $(DEBUG_CFLAGS)
>  export DEBUG_CFLAGS
>
> +KBUILD_RUSTCFLAGS += $(DEBUG_RUSTCFLAGS)
> +export DEBUG_RUSTCFLAGS
> +
>  ifdef CONFIG_FUNCTION_TRACER
>  ifdef CONFIG_FTRACE_MCOUNT_USE_CC
>    CC_FLAGS_FTRACE      += -mrecord-mcount
> @@ -990,10 +1061,11 @@ include $(addprefix $(srctree)/, $(include-y))
>  # Do not add $(call cc-option,...) below this line. When you build the kernel
>  # from the clean source tree, the GCC plugins do not exist at this point.
>
> -# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
> +# Add user supplied CPPFLAGS, AFLAGS, CFLAGS and RUSTCFLAGS as the last assignments
>  KBUILD_CPPFLAGS += $(KCPPFLAGS)
>  KBUILD_AFLAGS   += $(KAFLAGS)
>  KBUILD_CFLAGS   += $(KCFLAGS)
> +KBUILD_RUSTCFLAGS += $(KRUSTCFLAGS)

I can't help but read that as Krusty-flags. :P Are ya' ready kids?

>
>  KBUILD_LDFLAGS_MODULE += --build-id=sha1
>  LDFLAGS_vmlinux += --build-id=sha1
> @@ -1138,6 +1210,10 @@ export MODULES_NSDEPS := $(extmod-prefix)modules.nsdeps
>  ifeq ($(KBUILD_EXTMOD),)
>  core-y         += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
>
> +ifdef CONFIG_RUST
> +core-y         += rust/
> +endif
> +
>  vmlinux-dirs   := $(patsubst %/,%,$(filter %/, \
>                      $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
>                      $(libs-y) $(libs-m)))
> @@ -1238,6 +1314,9 @@ archprepare: outputmakefile archheaders archscripts scripts include/config/kerne
>  prepare0: archprepare
>         $(Q)$(MAKE) $(build)=scripts/mod
>         $(Q)$(MAKE) $(build)=.
> +ifdef CONFIG_RUST
> +       $(Q)$(MAKE) $(build)=rust
> +endif
>
>  # All the preparing..
>  prepare: prepare0 prepare-objtool prepare-resolve_btfids
> @@ -1648,6 +1727,13 @@ help:
>         @echo  '  kselftest-merge   - Merge all the config dependencies of'
>         @echo  '                      kselftest to existing .config.'
>         @echo  ''
> +       @echo  'Rust targets:'
> +       @echo  '  rustfmt         - Reformat all the Rust code in the kernel'

Seems like a good way for drive by commits where someone reformatted
the whole kernel.

> +       @echo  '  rustfmtcheck    - Checks if all the Rust code in the kernel'
> +       @echo  '                    is formatted, printing a diff otherwise.'

Might be nice to invoke this somehow from checkpatch.pl somehow for
changes to rust source files. Not necessary in the RFC, but perhaps
one day.

> +       @echo  '  rustdoc         - Generate Rust documentation'
> +       @echo  '                    (requires kernel .config)'
> +       @echo  ''
>         @$(if $(dtstree), \
>                 echo 'Devicetree:'; \
>                 echo '* dtbs             - Build device tree blobs for enabled boards'; \
> @@ -1719,6 +1805,27 @@ PHONY += $(DOC_TARGETS)
>  $(DOC_TARGETS):
>         $(Q)$(MAKE) $(build)=Documentation $@
>
> +
> +# Rust targets
> +# ---------------------------------------------------------------------------
> +
> +# Documentation target
> +#
> +# Using the singular to avoid running afoul of `no-dot-config-targets`.
> +PHONY += rustdoc
> +rustdoc: prepare0
> +       $(Q)$(MAKE) $(build)=rust $@
> +
> +# Formatting targets
> +PHONY += rustfmt rustfmtcheck
> +
> +rustfmt:
> +       find -name '*.rs' | xargs $(RUSTFMT)
> +
> +rustfmtcheck:
> +       find -name '*.rs' | xargs $(RUSTFMT) --check
> +
> +
>  # Misc
>  # ---------------------------------------------------------------------------
>
> @@ -1866,6 +1973,7 @@ clean: $(clean-dirs)
>         $(call cmd,rmfiles)
>         @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
>                 \( -name '*.[aios]' -o -name '*.ko' -o -name '.*.cmd' \
> +               -o -name '*.rmeta' \
>                 -o -name '*.ko.*' \
>                 -o -name '*.dtb' -o -name '*.dtbo' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
>                 -o -name '*.dwo' -o -name '*.lst' \
> diff --git a/arch/arm64/rust/target.json b/arch/arm64/rust/target.json
> new file mode 100644
> index 000000000000..44953e2725c4
> --- /dev/null
> +++ b/arch/arm64/rust/target.json
> @@ -0,0 +1,40 @@
> +{
> +  "arch": "aarch64",
> +  "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
> +  "disable-redzone": true,
> +  "eliminate-frame-pointer": false,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "+strict-align,+neon,+fp-armv8",
> +  "function-sections": false,

^ Depends on your config. This is implied by LTO, and IIRC
CONFIG_LD_DEAD_CODE_ELIMINATION does set this.

> +  "is-builtin": true,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,

Is there more documentation on these values? For example, is LLD a GNU
linker?  I would think not, but perhaps the flag could have been named
better and this is a non-issue.

> +  "llvm-target": "aarch64-unknown-none",

What happens if you use aarch64-linux-gnu, like Clang does?

> +  "max-atomic-width": 128,
> +  "needs-plt": true,

^ do we?

> +  "os": "none",
> +  "panic-strategy": "abort",

^ alternatives?

> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [

^ gcc?

> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"

Is -m64 necessary?

> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "inline-or-call",
> +    "min-llvm-version-for-inline": [
> +      11,
> +      0,
> +      1
> +    ]
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",

The kernel supports both.  Does that mean there would be two different
aarch64 target.json files, each per endianness?  Maybe not critical
for initial support, but something to be aware of.

> +  "target-pointer-width": "64",
> +  "vendor": ""
> +}
> diff --git a/arch/powerpc/rust/target.json b/arch/powerpc/rust/target.json
> new file mode 100644
> index 000000000000..1e53f8308092
> --- /dev/null
> +++ b/arch/powerpc/rust/target.json
> @@ -0,0 +1,30 @@
> +{
> +  "arch": "powerpc64",
> +  "code-mode": "kernel",
> +  "cpu": "ppc64le",
> +  "data-layout": "e-m:e-i64:64-n32:64",

Seems like this target doesn't set "eliminate-frame-pointer." I think
it should one way or another to be explicit?

> +  "env": "gnu",
> +  "features": "-altivec,-vsx,-hard-float",
> +  "function-sections": false,
> +  "is-builtin": true,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "powerpc64le-elf",
> +  "max-atomic-width": 64,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "target-family": "unix",
> +  "target-mcount": "_mcount",
> +  "target-endian": "little",
> +  "target-pointer-width": "64"
> +}
> diff --git a/arch/x86/rust/target.json b/arch/x86/rust/target.json
> new file mode 100644
> index 000000000000..6e1759cd45bf
> --- /dev/null
> +++ b/arch/x86/rust/target.json
> @@ -0,0 +1,42 @@
> +{
> +  "arch": "x86_64",
> +  "code-model": "kernel",
> +  "cpu": "x86-64",
> +  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
> +  "disable-redzone": true,
> +  "eliminate-frame-pointer": false,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float",
> +  "function-sections": false,
> +  "is-builtin": true,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "x86_64-elf",
> +  "max-atomic-width": 64,
> +  "needs-plt": true,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "inline-or-call",
> +    "min-llvm-version-for-inline": [
> +      11,
> +      0,
> +      1
> +    ]
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",
> +  "target-pointer-width": "64",
> +  "vendor": "unknown"
> +}
> diff --git a/init/Kconfig b/init/Kconfig
> index 5f5c776ef192..11475840c29c 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -57,6 +57,15 @@ config LLD_VERSION
>         default $(ld-version) if LD_IS_LLD
>         default 0
>
> +config HAS_RUST
> +       depends on ARM64 || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64
> +       def_bool $(success,$(RUSTC) --version)
> +
> +config RUSTC_VERSION
> +       depends on HAS_RUST
> +       int
> +       default $(shell,$(srctree)/scripts/rust-version.sh $(RUSTC))
> +
>  config CC_CAN_LINK
>         bool
>         default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(m64-flag)) if 64BIT
> @@ -2027,6 +2036,24 @@ config PROFILING
>           Say Y here to enable the extended profiling support mechanisms used
>           by profilers.
>
> +config RUST
> +       bool "Rust support"
> +       depends on HAS_RUST
> +       depends on !COMPILE_TEST
> +       default n
> +       help
> +         Enables Rust support in the kernel.
> +
> +         This allows other Rust-related options, like drivers written in Rust,
> +         to be selected.
> +
> +         It is also required to be able to load external kernel modules
> +         written in Rust.
> +
> +         See Documentation/rust/ for more information.
> +
> +         If unsure, say N.
> +
>  #
>  # Place an empty function call at each tracepoint site. Can be
>  # dynamically changed for a probe function.
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 2779c29d9981..acf4993baddc 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2537,6 +2537,106 @@ config HYPERV_TESTING
>
>  endmenu # "Kernel Testing and Coverage"
>
> +menu "Rust hacking"
> +
> +config RUST_DEBUG_ASSERTIONS
> +       bool "Debug assertions"
> +       default n
> +       depends on RUST
> +       help
> +         Enables rustc's `-Cdebug-assertions` codegen option.
> +
> +         This flag lets you turn `cfg(debug_assertions)` conditional
> +         compilation on or off. This can be used to enable extra debugging
> +         code in development but not in production. For example, it controls
> +         the behavior of the standard library's `debug_assert!` macro.
> +
> +         Note that this will apply to all Rust code, including `core`.
> +
> +         If unsure, say N.
> +
> +config RUST_OVERFLOW_CHECKS
> +       bool "Overflow checks"
> +       default y
> +       depends on RUST
> +       help
> +         Enables rustc's `-Coverflow-checks` codegen option.
> +
> +         This flag allows you to control the behavior of runtime integer
> +         overflow. When overflow-checks are enabled, a panic will occur
> +         on overflow.
> +
> +         Note that this will apply to all Rust code, including `core`.
> +
> +         If unsure, say Y.
> +
> +choice
> +       prompt "Optimization level"
> +       default RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
> +       depends on RUST
> +       help
> +         Controls rustc's `-Copt-level` codegen option.
> +
> +         This flag controls the optimization level.
> +
> +         If unsure, say "Similar as chosen for C".

Yuck. This should be default on and not configurable.

> +
> +config RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
> +       bool "Similar as chosen for C"
> +       help
> +         This choice will pick a similar optimization level as chosen in
> +         the "Compiler optimization level" for C:
> +
> +             -O2 is currently mapped to -Copt-level=2
> +             -O3 is currently mapped to -Copt-level=3
> +             -Os is currently mapped to -Copt-level=z
> +
> +         The mapping may change over time to follow the intended semantics
> +         of the choice for C as sensibly as possible.
> +
> +         This is the default.
> +
> +config RUST_OPT_LEVEL_0
> +       bool "No optimizations (-Copt-level=0)"
> +       help
> +         Not recommended for most purposes. It may come in handy for debugging
> +         suspected optimizer bugs, unexpected undefined behavior, etc.
> +
> +         Note that this level will *not* enable debug assertions nor overflow
> +         checks on its own (like it happens when interacting with rustc
> +         directly). Use the corresponding configuration options to control
> +         that instead, orthogonally.
> +
> +config RUST_OPT_LEVEL_1
> +       bool "Basic optimizations (-Copt-level=1)"
> +       help
> +         Useful for debugging without getting too lost, but without
> +         the overhead and boilerplate of no optimizations at all.
> +
> +config RUST_OPT_LEVEL_2
> +       bool "Some optimizations (-Copt-level=2)"
> +       help
> +         The sensible choice in most cases.
> +
> +config RUST_OPT_LEVEL_3
> +       bool "All optimizations (-Copt-level=3)"
> +       help
> +         Yet more performance (hopefully).
> +
> +config RUST_OPT_LEVEL_S
> +       bool "Optimize for size (-Copt-level=s)"
> +       help
> +         Smaller kernel, ideally without too much performance loss.
> +
> +config RUST_OPT_LEVEL_Z
> +       bool "Optimize for size, no loop vectorization (-Copt-level=z)"
> +       help
> +         Like the previous level, but also turn off loop vectorization.
> +
> +endchoice
> +
> +endmenu # "Rust"
> +
>  source "Documentation/Kconfig"
>
>  endmenu # Kernel hacking
> diff --git a/rust/.gitignore b/rust/.gitignore
> new file mode 100644
> index 000000000000..8875e08ed0b1
> --- /dev/null
> +++ b/rust/.gitignore
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +bindings_generated.rs
> +exports_*_generated.h
> +doc/
> \ No newline at end of file
> diff --git a/rust/Makefile b/rust/Makefile
> new file mode 100644
> index 000000000000..ba4b13e4fc7f
> --- /dev/null
> +++ b/rust/Makefile
> @@ -0,0 +1,141 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +RUSTDOC = rustdoc
> +
> +quiet_cmd_rustdoc = RUSTDOC $<
> +      cmd_rustdoc = \
> +       RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
> +       $(RUSTDOC) $(filter-out --emit=%, $(rustc_flags)) \
> +               $(rustdoc_target_flags) -L $(objtree)/rust/ \
> +               --output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \
> +               -Fmissing-docs @$(objtree)/include/generated/rustc_cfg $<
> +
> +rustdoc: rustdoc-module rustdoc-compiler_builtins rustdoc-kernel
> +
> +rustdoc-module: private rustdoc_target_flags = --crate-type proc-macro \
> +    --extern proc_macro
> +rustdoc-module: $(srctree)/rust/module.rs FORCE
> +       $(call if_changed,rustdoc)
> +
> +rustdoc-compiler_builtins: $(srctree)/rust/compiler_builtins.rs FORCE
> +       $(call if_changed,rustdoc)
> +
> +rustdoc-kernel: private rustdoc_target_flags = --extern alloc \
> +    --extern module=$(objtree)/rust/libmodule.so
> +rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-module \
> +    $(objtree)/rust/libmodule.so $(objtree)/rust/bindings_generated.rs FORCE
> +       $(call if_changed,rustdoc)
> +
> +ifdef CONFIG_CC_IS_CLANG
> +bindgen_c_flags = $(c_flags)
> +else
> +# bindgen relies on libclang to parse C. Ideally, bindgen would support a GCC
> +# plugin backend and/or the Clang driver would be perfectly compatible with GCC.
> +#
> +# For the moment, here we are tweaking the flags on the fly. Some config
> +# options may not work (e.g. `GCC_PLUGIN_RANDSTRUCT` if we end up using one
> +# of those structs). We might want to redo how Clang flags are kept track of
> +# in the general `Makefile` even for GCC builds, similar to what we did with
> +# `TENTATIVE_CLANG_FLAGS`.
> +bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
> +       -mskip-rax-setup -mgeneral-regs-only -msign-return-address=% \
> +       -mindirect-branch=thunk-extern -mindirect-branch-register -mrecord-mcount \
> +       -mabi=lp64 -mstack-protector-guard% -fconserve-stack -falign-jumps=% \
> +       -falign-loops=% -fno-ipa-cp-clone -fno-partial-inlining \
> +       -fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \
> +       -Wno-packed-not-aligned -Wno-format-truncation -Wno-format-overflow \
> +       -Wno-stringop-truncation -Wno-unused-but-set-variable \
> +       -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized \
> +       -Werror=designated-init -Wno-zero-length-bounds \
> +       --param=% --param asan-%
> +
> +# PowerPC
> +bindgen_skip_c_flags += -mtraceback=no -mno-pointers-to-nested-functions \
> +       -mno-string -mno-strict-align
> +
> +bindgen_extra_c_flags = $(TENTATIVE_CLANG_FLAGS) -Wno-address-of-packed-member
> +bindgen_c_flags = $(filter-out $(bindgen_skip_c_flags), $(c_flags)) \
> +       $(bindgen_extra_c_flags)
> +endif
> +
> +bindgen_opaque_types := xregs_state desc_struct arch_lbr_state
> +
> +# To avoid several recompilations in PowerPC, which inserts `-D_TASK_CPU`
> +bindgen_c_flags_final = $(filter-out -D_TASK_CPU=%, $(bindgen_c_flags))
> +
> +quiet_cmd_bindgen = BINDGEN $@
> +      cmd_bindgen = \
> +       $(BINDGEN) $< $(addprefix --opaque-type , $(bindgen_opaque_types)) \
> +               --use-core --with-derive-default --ctypes-prefix c_types \
> +               --size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE
> +
> +$(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h FORCE
> +       $(call if_changed_dep,bindgen)
> +
> +quiet_cmd_exports = EXPORTS $@
> +      cmd_exports = \
> +       $(NM) -p --defined-only $< \
> +               | grep -E ' (T|R|D) ' | cut -d ' ' -f 3 | grep -E '^(__rust_|_R)' \
> +               | xargs -Isymbol \
> +               echo 'EXPORT_SYMBOL_RUST_GPL(symbol);' > $@
> +
> +$(objtree)/rust/exports_core_generated.h: $(objtree)/rust/core.o FORCE
> +       $(call if_changed,exports)
> +
> +$(objtree)/rust/exports_alloc_generated.h: $(objtree)/rust/alloc.o FORCE
> +       $(call if_changed,exports)
> +
> +$(objtree)/rust/exports_kernel_generated.h: $(objtree)/rust/kernel.o FORCE
> +       $(call if_changed,exports)
> +
> +# `-Cpanic=unwind -Cforce-unwind-tables=y` overrides `rustc_flags` in order to
> +# avoid the https://github.com/rust-lang/rust/issues/82320 rustc crash.
> +quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
> +      cmd_rustc_procmacro = \
> +       $(RUSTC_OR_CLIPPY) $(rustc_flags) \
> +               --emit=dep-info,link --extern proc_macro \
> +               -Cpanic=unwind -Cforce-unwind-tables=y \
> +               --crate-type proc-macro --out-dir $(objtree)/rust/ \
> +               --crate-name $(patsubst lib%.so,%,$(notdir $@)) $<; \
> +       mv $(objtree)/rust/$(patsubst lib%.so,%,$(notdir $@)).d $(depfile); \
> +       sed -i '/^\#/d' $(depfile)
> +
> +$(objtree)/rust/libmodule.so: $(srctree)/rust/module.rs FORCE
> +       $(call if_changed_dep,rustc_procmacro)
> +
> +quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
> +      cmd_rustc_library = \
> +       RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
> +       $(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
> +               $(rustc_flags) $(rustc_cross_flags) $(rustc_target_flags) \
> +               --crate-type rlib --out-dir $(objtree)/rust/ -L $(objtree)/rust/ \
> +               --crate-name $(patsubst %.o,%,$(notdir $@)) $<; \
> +       mv $(objtree)/rust/$(patsubst %.o,%,$(notdir $@)).d $(depfile); \
> +       sed -i '/^\#/d' $(depfile) \
> +       $(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@)
> +
> +# `$(rustc_flags)` is passed in case the user added `--sysroot`.
> +rustc_sysroot = $(shell $(RUSTC) $(rustc_flags) --print sysroot)
> +rustc_src = $(rustc_sysroot)/lib/rustlib/src/rust
> +
> +.SECONDEXPANSION:
> +$(objtree)/rust/core.o: private skip_clippy = 1
> +$(objtree)/rust/core.o: $$(rustc_src)/library/core/src/lib.rs FORCE
> +       $(call if_changed_dep,rustc_library)
> +
> +$(objtree)/rust/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
> +$(objtree)/rust/compiler_builtins.o: $(srctree)/rust/compiler_builtins.rs \
> +    $(objtree)/rust/core.o FORCE
> +       $(call if_changed_dep,rustc_library)
> +
> +$(objtree)/rust/alloc.o: private skip_clippy = 1
> +$(objtree)/rust/alloc.o: $$(rustc_src)/library/alloc/src/lib.rs \
> +    $(objtree)/rust/compiler_builtins.o FORCE
> +       $(call if_changed_dep,rustc_library)
> +
> +# ICE on `--extern module`: https://github.com/rust-lang/rust/issues/56935
> +$(objtree)/rust/kernel.o: private rustc_target_flags = --extern alloc \
> +    --extern module=$(objtree)/rust/libmodule.so
> +$(objtree)/rust/kernel.o: $(srctree)/rust/kernel/lib.rs $(objtree)/rust/alloc.o \
> +    $(objtree)/rust/libmodule.so $(objtree)/rust/bindings_generated.rs FORCE
> +       $(call if_changed_dep,rustc_library)
> diff --git a/scripts/Makefile.build b/scripts/Makefile.build
> index 1b6094a13034..3665c49c4dcf 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -26,6 +26,7 @@ EXTRA_CPPFLAGS :=
>  EXTRA_LDFLAGS  :=
>  asflags-y  :=
>  ccflags-y  :=
> +rustcflags-y :=
>  cppflags-y :=
>  ldflags-y  :=
>
> @@ -287,6 +288,24 @@ quiet_cmd_cc_lst_c = MKLST   $@
>  $(obj)/%.lst: $(src)/%.c FORCE
>         $(call if_changed_dep,cc_lst_c)
>
> +# Compile Rust sources (.rs)
> +# ---------------------------------------------------------------------------
> +
> +rustc_cross_flags := --target=$(srctree)/arch/$(SRCARCH)/rust/target.json
> +
> +quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
> +      cmd_rustc_o_rs = \
> +       RUST_MODFILE=$(modfile) \
> +       $(RUSTC_OR_CLIPPY) $(rustc_flags) $(rustc_cross_flags) \
> +               --extern alloc --extern kernel \
> +               --crate-type rlib --out-dir $(obj) -L $(objtree)/rust/ \
> +               --crate-name $(patsubst %.o,%,$(notdir $@)) $<; \
> +       mv $(obj)/$(subst .o,,$(notdir $@)).d $(depfile); \
> +       sed -i '/^\#/d' $(depfile)
> +
> +$(obj)/%.o: $(src)/%.rs FORCE
> +       $(call if_changed_dep,rustc_o_rs)
> +
>  # Compile assembler sources (.S)
>  # ---------------------------------------------------------------------------
>
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 8cd67b1b6d15..bd6cb3562fb4 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -8,6 +8,7 @@ ldflags-y  += $(EXTRA_LDFLAGS)
>  # flags that take effect in current and sub directories
>  KBUILD_AFLAGS += $(subdir-asflags-y)
>  KBUILD_CFLAGS += $(subdir-ccflags-y)
> +KBUILD_RUSTCFLAGS += $(subdir-rustcflags-y)
>
>  # Figure out what we need to build from the various variables
>  # ===========================================================================
> @@ -122,6 +123,10 @@ _c_flags       = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \
>                       $(filter-out $(ccflags-remove-y), \
>                           $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(ccflags-y)) \
>                       $(CFLAGS_$(target-stem).o))
> +_rustc_flags    = $(filter-out $(RUSTCFLAGS_REMOVE_$(target-stem).o), \
> +                     $(filter-out $(rustcflags-remove-y), \
> +                         $(KBUILD_RUSTCFLAGS) $(rustcflags-y)) \
> +                     $(RUSTCFLAGS_$(target-stem).o))
>  _a_flags       = $(filter-out $(AFLAGS_REMOVE_$(target-stem).o), \
>                       $(filter-out $(asflags-remove-y), \
>                           $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(asflags-y)) \
> @@ -191,6 +196,11 @@ modkern_cflags =                                          \
>                 $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \
>                 $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags))
>
> +modkern_rustcflags =                                              \
> +       $(if $(part-of-module),                                   \
> +               $(KBUILD_RUSTCFLAGS_MODULE) $(RUSTCFLAGS_MODULE), \
> +               $(KBUILD_RUSTCFLAGS_KERNEL) $(RUSTCFLAGS_KERNEL))
> +
>  modkern_aflags = $(if $(part-of-module),                               \
>                         $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE),       \
>                         $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL))
> @@ -200,6 +210,8 @@ c_flags        = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
>                  $(_c_flags) $(modkern_cflags)                           \
>                  $(basename_flags) $(modname_flags)
>
> +rustc_flags     = $(_rustc_flags) $(modkern_rustcflags) @$(objtree)/include/generated/rustc_cfg
> +
>  a_flags        = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
>                  $(_a_flags) $(modkern_aflags)
>
> diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
> index 2568dbe16ed6..a83d646ecef5 100644
> --- a/scripts/kconfig/confdata.c
> +++ b/scripts/kconfig/confdata.c
> @@ -637,6 +637,56 @@ static struct conf_printer kconfig_printer_cb =
>         .print_comment = kconfig_print_comment,
>  };
>
> +/*
> + * rustc cfg printer
> + *
> + * This printer is used when generating the resulting rustc configuration
> + * after kconfig invocation and `defconfig` files.
> + */
> +static void rustc_cfg_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
> +{
> +       const char *str;
> +
> +       switch (sym->type) {
> +       case S_INT:
> +       case S_HEX:
> +       case S_BOOLEAN:
> +       case S_TRISTATE:
> +               str = sym_escape_string_value(value);
> +
> +               /*
> +                * We don't care about disabled ones, i.e. no need for
> +                * what otherwise are "comments" in other printers.
> +                */
> +               if (*value == 'n')
> +                       return;
> +
> +               /*
> +                * To have similar functionality to the C macro `IS_ENABLED()`
> +                * we provide an empty `--cfg CONFIG_X` here in both `y`
> +                * and `m` cases.
> +                *
> +                * Then, the common `fprintf()` below will also give us
> +                * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
> +                * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
> +                */
> +               if (*value == 'y' || *value == 'm')
> +                       fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
> +
> +               break;
> +       default:
> +               str = value;
> +               break;
> +       }
> +
> +       fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, str);
> +}
> +
> +static struct conf_printer rustc_cfg_printer_cb =
> +{
> +       .print_symbol = rustc_cfg_print_symbol,
> +};
> +
>  /*
>   * Header printer
>   *
> @@ -1044,7 +1094,7 @@ int conf_write_autoconf(int overwrite)
>         struct symbol *sym;
>         const char *name;
>         const char *autoconf_name = conf_get_autoconfig_name();
> -       FILE *out, *out_h;
> +       FILE *out, *out_h, *out_rustc_cfg;
>         int i;
>
>         if (!overwrite && is_present(autoconf_name))
> @@ -1065,6 +1115,13 @@ int conf_write_autoconf(int overwrite)
>                 return 1;
>         }
>
> +       out_rustc_cfg = fopen(".tmp_rustc_cfg", "w");
> +       if (!out_rustc_cfg) {
> +               fclose(out);
> +               fclose(out_h);
> +               return 1;
> +       }
> +
>         conf_write_heading(out, &kconfig_printer_cb, NULL);
>         conf_write_heading(out_h, &header_printer_cb, NULL);
>
> @@ -1076,9 +1133,11 @@ int conf_write_autoconf(int overwrite)
>                 /* write symbols to auto.conf and autoconf.h */
>                 conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
>                 conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
> +               conf_write_symbol(out_rustc_cfg, sym, &rustc_cfg_printer_cb, NULL);
>         }
>         fclose(out);
>         fclose(out_h);
> +       fclose(out_rustc_cfg);
>
>         name = getenv("KCONFIG_AUTOHEADER");
>         if (!name)
> @@ -1097,6 +1156,12 @@ int conf_write_autoconf(int overwrite)
>         if (rename(".tmpconfig", autoconf_name))
>                 return 1;
>
> +       name = "include/generated/rustc_cfg";
> +       if (make_parent_dir(name))
> +               return 1;
> +       if (rename(".tmp_rustc_cfg", name))
> +               return 1;
> +
>         return 0;
>  }
>
> diff --git a/scripts/rust-version.sh b/scripts/rust-version.sh
> new file mode 100755
> index 000000000000..67b6d31688e2
> --- /dev/null
> +++ b/scripts/rust-version.sh
> @@ -0,0 +1,31 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# rust-version rust-command
> +#
> +# Print the compiler version of `rust-command' in a 5 or 6-digit form
> +# such as `14502' for rustc-1.45.2 etc.
> +#
> +# Returns 0 if not found (so that Kconfig does not complain)
> +compiler="$*"
> +
> +if [ ${#compiler} -eq 0 ]; then
> +       echo "Error: No compiler specified." >&2
> +       printf "Usage:\n\t$0 <rust-command>\n" >&2
> +       exit 1
> +fi
> +
> +if ! command -v $compiler >/dev/null 2>&1; then
> +       echo 0
> +       exit 0
> +fi
> +
> +VERSION=$($compiler --version | cut -f2 -d' ')
> +
> +# Cut suffix if any (e.g. `-dev`)
> +VERSION=$(echo $VERSION | cut -f1 -d'-')
> +
> +MAJOR=$(echo $VERSION | cut -f1 -d'.')
> +MINOR=$(echo $VERSION | cut -f2 -d'.')
> +PATCHLEVEL=$(echo $VERSION | cut -f3 -d'.')
> +printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
> --
> 2.17.1
>
Miguel Ojeda April 15, 2021, 12:43 a.m. UTC | #2
On Thu, Apr 15, 2021 at 1:19 AM Nick Desaulniers
<ndesaulniers@google.com> wrote:
>
> Rather than check the origin (yikes, are we intentionally avoiding env
> vars?), can this simply be
> ifneq ($(CLIPPY),)
>   KBUILD_CLIPPY := $(CLIPPY)
> endif
>
> Then you can specify whatever value you want, support command line or
> env vars, etc.?

I was following the other existing cases like `V`. Masahiro can
probably answer why they are done like this.

> -Oz in clang typically generates larger kernel code than -Os; LLVM
> seems to aggressively emit libcalls even when the setup for a call
> would be larger than the inlined call itself.  Is z smaller than s for
> the existing rust examples?

I will check if the `s`/`z` flags have the exact same semantics as
they do in Clang, but as a quick test (quite late here, sorry!), yes,
it seems `z` is smaller:

      text data bss    dec   hex filename

    126568    8 104 126680 1eed8 drivers/android/rust_binder.o [s]
    122923    8 104 123035 1e09b drivers/android/rust_binder.o [z]

    212351    0   0 212351 33d7f rust/core.o [s]
    207653    0   0 207653 32b25 rust/core.o [z]

> This is a mess; who thought it would be a good idea to support
> compiling the rust code at a different optimization level than the
> rest of the C code in the kernel?  Do we really need that flexibility
> for Rust kernel code, or can we drop this feature?

I did :P

The idea is that, since it seemed to work out of the box when I tried,
it could be nice to keep for debugging and for having another degree
of freedom when testing the compiler/nightlies etc.

Also, it is not intended for users, which is why I put it in the
"hacking" menu -- users should still only modify the usual global
option.

However, it is indeed strange for the kernel and I don't mind dropping
it if people want to see it out (one could still do it manually if
needed...).

(Related: from what I have been told, the kernel does not support
lower levels in C just due to old problems with compilers; but those
may be gone now).

> Don't the target.json files all set `"eliminate-frame-pointer":
> false,`?  Is this necessary then?  Also, which targets retain frame
> pointers at which optimization levels is quite messy (in C compilers),
> as well as your choice of unwinder, which is configurable for certain
> architectures.

For this (and other questions regarding the target definition files
you have below): the situation is quite messy, indeed. Some of these
options can be configured via flags too. Also, the target definition
files are actually unstable in `rustc` because they are too tied to
LLVM. So AFAIK if a command-line flag exists, we should use that. But
I am not sure if the target definition file is supposed to support
removing keys etc.

Anyway, the plan here short-term is to generate the target definition
file on the fly taking into account the options, and keep it working
w.r.t. `rustc` nightlies (this is also why we don't have have big
endian for ppc or 32-bit x86). Longer-term, hopefully `rustc` adds
enough command-line flags to tweak as needed, or stabilizes the target
files somehow, or stabilizes all the target combinations we need (i.e.
as built-in targets in the compiler).

In fact, I will add this to the "unstable features" list.

> Seems like a good way for drive by commits where someone reformatted
> the whole kernel.

We enforce the formatting for all the code at the moment in the CI and
AFAIK `rustfmt` tries to keep formatting stable (as long as one does
not use unstable features), so code should always be formatted.

Having said that, I'm not sure 100% how stable it actually is in
practice over long periods of time -- I guess we will find out soon
enough.

> Might be nice to invoke this somehow from checkpatch.pl somehow for
> changes to rust source files. Not necessary in the RFC, but perhaps
> one day.

We do it in the CI (see above).

> Yuck. This should be default on and not configurable.

See above for the opt-levels.

Cheers,
Miguel
Nick Desaulniers April 15, 2021, 6:03 p.m. UTC | #3
On Wed, Apr 14, 2021 at 5:43 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Thu, Apr 15, 2021 at 1:19 AM Nick Desaulniers
> <ndesaulniers@google.com> wrote:
> >
> > -Oz in clang typically generates larger kernel code than -Os; LLVM
> > seems to aggressively emit libcalls even when the setup for a call
> > would be larger than the inlined call itself.  Is z smaller than s for
> > the existing rust examples?
>
> I will check if the `s`/`z` flags have the exact same semantics as
> they do in Clang, but as a quick test (quite late here, sorry!), yes,
> it seems `z` is smaller:
>
>       text data bss    dec   hex filename
>
>     126568    8 104 126680 1eed8 drivers/android/rust_binder.o [s]
>     122923    8 104 123035 1e09b drivers/android/rust_binder.o [z]
>
>     212351    0   0 212351 33d7f rust/core.o [s]
>     207653    0   0 207653 32b25 rust/core.o [z]

cool, thanks for verifying. LGTM

> > This is a mess; who thought it would be a good idea to support
> > compiling the rust code at a different optimization level than the
> > rest of the C code in the kernel?  Do we really need that flexibility
> > for Rust kernel code, or can we drop this feature?
>
> I did :P
>
> The idea is that, since it seemed to work out of the box when I tried,
> it could be nice to keep for debugging and for having another degree
> of freedom when testing the compiler/nightlies etc.
>
> Also, it is not intended for users, which is why I put it in the
> "hacking" menu -- users should still only modify the usual global
> option.
>
> However, it is indeed strange for the kernel and I don't mind dropping
> it if people want to see it out (one could still do it manually if
> needed...).
>
> (Related: from what I have been told, the kernel does not support
> lower levels in C just due to old problems with compilers; but those
> may be gone now).

IIRC the kernel (or at least x86_64 defconfig) cannot be built at -O0,
which is too bad if developers were myopically focused on build times.
It would have been nice to have something like
CONFIG_CC_OPTIMIZE_FOR_COMPILE_TIME to join
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE and CONFIG_CC_OPTIMIZE_FOR_SIZE,
but maybe it's still possible to support one day.  (¿Por qué no los
tres? Perhaps a false-trichotomy? Sorry, but those 3 are somewhat at
odds for compilation).

Until then, I don't see why we need to permit developers to express
such flexibility for just the Rust code, or have it differ from the
intent of the C code. Does it make sense to set RUST_OPT_LEVEL_3 and
CC_OPTIMIZE_FOR_SIZE? I doubt it. That doesn't seem like a development
feature, but a mistake.  YAGNI.  Instead developers should clarify
what they care about in terms of high level intent; if someone wants
to micromanage optimization level flags in their forks they don't need
a Kconfig to do it (they're either going to hack KBUILD_CFLAGS,
CFLAGS_*.o, or KCFLAGS), and there's probably better mechanisms for
fine-tooth precision of optimizing actually hot code or not via PGO
and AutoFDO.
https://lore.kernel.org/lkml/20210407211704.367039-1-morbo@google.com/
Miguel Ojeda April 16, 2021, 12:23 p.m. UTC | #4
On Thu, Apr 15, 2021 at 8:03 PM Nick Desaulniers
<ndesaulniers@google.com> wrote:
>
> Until then, I don't see why we need to permit developers to express
> such flexibility for just the Rust code, or have it differ from the
> intent of the C code. Does it make sense to set RUST_OPT_LEVEL_3 and
> CC_OPTIMIZE_FOR_SIZE? I doubt it. That doesn't seem like a development
> feature, but a mistake.  YAGNI.  Instead developers should clarify
> what they care about in terms of high level intent; if someone wants
> to micromanage optimization level flags in their forks they don't need
> a Kconfig to do it (they're either going to hack KBUILD_CFLAGS,
> CFLAGS_*.o, or KCFLAGS), and there's probably better mechanisms for
> fine-tooth precision of optimizing actually hot code or not via PGO
> and AutoFDO.

I completely agree when we are talking about higher level optimization
levels. From a user perspective, it does not make much sense to want
slightly different optimizations levels or different size/performance
trade-offs between C and Rust. However, I am thinking from the
debugging side, i.e. mostly low or no optimization; rather than about
micromanaging optimizations for performance.

For instance, last year I used `RUST_OPT_LEVEL_0/1` to quickly rule
out optimizer/codegen/etc. bugs on the Rust side when we had some
memory corruption over Rust data
(https://github.com/Rust-for-Linux/linux/pull/28), which is important
when dealing with compiler nightly versions. It was also nice to be
able to easily follow along when stepping, too.

Having said that, I agree that in those cases one can simply tweak the
flags manually -- so that's why I said it is fine dropping the the
`Kconfig` options. There might be some advantages of having them, such
as making developers aware that those builds should work, to keep them
tested/working, etc.; but we can do that manually too in the CI/docs
too.

Cheers,
Miguel
Peter Zijlstra April 16, 2021, 1:38 p.m. UTC | #5
On Wed, Apr 14, 2021 at 08:45:55PM +0200, ojeda@kernel.org wrote:
> diff --git a/scripts/Makefile.build b/scripts/Makefile.build
> index 1b6094a13034..3665c49c4dcf 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -26,6 +26,7 @@ EXTRA_CPPFLAGS :=
>  EXTRA_LDFLAGS  :=
>  asflags-y  :=
>  ccflags-y  :=
> +rustcflags-y :=
>  cppflags-y :=
>  ldflags-y  :=
>  
> @@ -287,6 +288,24 @@ quiet_cmd_cc_lst_c = MKLST   $@
>  $(obj)/%.lst: $(src)/%.c FORCE
>  	$(call if_changed_dep,cc_lst_c)
>  
> +# Compile Rust sources (.rs)
> +# ---------------------------------------------------------------------------
> +
> +rustc_cross_flags := --target=$(srctree)/arch/$(SRCARCH)/rust/target.json
> +
> +quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
> +      cmd_rustc_o_rs = \
> +	RUST_MODFILE=$(modfile) \
> +	$(RUSTC_OR_CLIPPY) $(rustc_flags) $(rustc_cross_flags) \
> +		--extern alloc --extern kernel \
> +		--crate-type rlib --out-dir $(obj) -L $(objtree)/rust/ \
> +		--crate-name $(patsubst %.o,%,$(notdir $@)) $<; \
> +	mv $(obj)/$(subst .o,,$(notdir $@)).d $(depfile); \
> +	sed -i '/^\#/d' $(depfile)
> +
> +$(obj)/%.o: $(src)/%.rs FORCE
> +	$(call if_changed_dep,rustc_o_rs)
> +
>  # Compile assembler sources (.S)
>  # ---------------------------------------------------------------------------
>  

So if I read all this right, rust compiles to .o and, like any other .o
file is then fed into objtool (for x86_64). Did you have any problems
with objtool? Does it generate correct ORC unwind information?

AFAICT rust has try/throw/catch exception handling (like
C++/Java/others) which is typically implemented with stack unwinding of
its own.

Does all that interact sanely?
Linus Torvalds April 16, 2021, 5:05 p.m. UTC | #6
On Fri, Apr 16, 2021 at 6:38 AM Peter Zijlstra <peterz@infradead.org> wrote:
>
> AFAICT rust has try/throw/catch exception handling (like
> C++/Java/others) which is typically implemented with stack unwinding of
> its own.

I was assuming that the kernel side would never do that.

There's some kind of "catch_unwind()" thing that catches a Rust
"panic!" thing, but I think it's basically useless for the kernel.

Typical Rust error handling should match the regular kernel
IS_ERR/ERR_PTR/PTR_ERR model fairly well, although the syntax is
fairly different (and it's not limited to pointers).

                Linus
Miguel Ojeda April 16, 2021, 5:34 p.m. UTC | #7
On Fri, Apr 16, 2021 at 3:38 PM Peter Zijlstra <peterz@infradead.org> wrote:
>
> So if I read all this right, rust compiles to .o and, like any other .o
> file is then fed into objtool (for x86_64). Did you have any problems
> with objtool? Does it generate correct ORC unwind information?

I opened an issue a while ago to take a closer look at the ORC
unwinder etc., so it is in my radar (thanks for raising it up,
nevertheless!).

Currently, causing a panic in a nested non-inlined function (f -> g ->
h) in one of the samples with the ORC unwinder enabled gives me
something like:

[    0.903456]  rust_begin_unwind+0x9/0x10
[    0.903456]  ? _RNvNtCsbDqzXfLQacH_4core9panicking9panic_fmt+0x29/0x30
[    0.903456]  ? _RNvNtCsbDqzXfLQacH_4core9panicking5panic+0x44/0x50
[    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1h+0x1c/0x20
[    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1g+0x9/0x10
[    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1f+0x9/0x10
[    0.903456]  ?
_RNvXCsbDqzXfLQacH_12rust_minimalNtB2_11RustMinimalNtCsbDqzXfLQacH_6kernel12KernelModule4init+0x73/0x80
[    0.903456]  ? _RNvXsa_NtCsbDqzXfLQacH_4core3fmtbNtB5_5Debug3fmt+0x30/0x30
[    0.903456]  ? __rust_minimal_init+0x11/0x20

But it also shows this one below:

[    0.903456]  ?
_RNvXs5_NtCsbDqzXfLQacH_11rust_binder11range_allocNtB5_15DescriptorStateNtNtCsbDqzXfLQacH_4core3fmt5Debug3fmt+0x60/0x60

So something does not look correct.

> AFAICT rust has try/throw/catch exception handling (like
> C++/Java/others) which is typically implemented with stack unwinding of
> its own.

Rust has optional unwinding for panics, yeah, but we don't enable it.
Instead, we tell the compiler to use its "abort" panic strategy. In
the handler currently we just call `BUG()`, but we will need to do
something less aggressive (e.g. kill the current thread).

But please note that it is not our plan to rely on panics for normal
error conditions. For instance, the allocations currently panic due to
our re-use of `alloc`, but will be fallible eventually (`Result`
etc.).

Cheers,
Miguel
Miguel Ojeda April 16, 2021, 5:47 p.m. UTC | #8
On Fri, Apr 16, 2021 at 7:05 PM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Typical Rust error handling should match the regular kernel
> IS_ERR/ERR_PTR/PTR_ERR model fairly well, although the syntax is
> fairly different (and it's not limited to pointers).

Yeah, exactly. We already have a `KernelResult<T>` type which is a
`Result<T, Error>`, where `Error` is a wrapper for the usual kernel
int errors.

So, for instance, a function that can either fail or return `Data`
would have a declaration like:

    pub fn foo() -> KernelResult<Data>

A caller that needs to handle the error can use pattern matching or
one of the methods in `Result`. And if they only need to bubble the
error up, they can use the ? operator:

    pub fn bar() -> KernelResult<Data> {
        let data = foo()?;

        // `data` is already a `Data` here, not a `KernelResult<Data>`
    }

Cheers,
Miguel
Al Viro April 16, 2021, 6:09 p.m. UTC | #9
On Fri, Apr 16, 2021 at 07:47:32PM +0200, Miguel Ojeda wrote:
> On Fri, Apr 16, 2021 at 7:05 PM Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > Typical Rust error handling should match the regular kernel
> > IS_ERR/ERR_PTR/PTR_ERR model fairly well, although the syntax is
> > fairly different (and it's not limited to pointers).
> 
> Yeah, exactly. We already have a `KernelResult<T>` type which is a
> `Result<T, Error>`, where `Error` is a wrapper for the usual kernel
> int errors.
> 
> So, for instance, a function that can either fail or return `Data`
> would have a declaration like:
> 
>     pub fn foo() -> KernelResult<Data>
> 
> A caller that needs to handle the error can use pattern matching or
> one of the methods in `Result`. And if they only need to bubble the
> error up, they can use the ? operator:
> 
>     pub fn bar() -> KernelResult<Data> {
>         let data = foo()?;
> 
>         // `data` is already a `Data` here, not a `KernelResult<Data>`
>     }

Umm...  A fairly common situation is

foo() returns a pointer to struct foo instance or ERR_PTR()
bar() returns a pointer to struct bar instance of ERR_PTR()

bar()
{
	struct foo *p;
	struct bar *res;
	.... // do some work, grab a mutex, etc.
	p = foo();
	if (IS_ERR(p))
		res = ERR_CAST(p); // (void *)p, internally; conceptually it's
				   // ERR_PTR(PTR_ERR(p));
	else
		res = blah();
	.... // matching cleanup
	return res;
}

How well would ? operator fit that pattern?  _If_ it's just a syntax sugar
along the lines of "if argument matches Err(_), return Err(_)", the types
shouldn't be an issue, but that might need some fun with releasing resources,
etc.  If it's something more elaborate... details, please.
Miguel Ojeda April 16, 2021, 6:57 p.m. UTC | #10
On Fri, Apr 16, 2021 at 8:10 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> How well would ? operator fit that pattern?  _If_ it's just a syntax sugar
> along the lines of "if argument matches Err(_), return Err(_)", the types
> shouldn't be an issue, but that might need some fun with releasing resources,
> etc.  If it's something more elaborate... details, please.

Yes, it is just syntax sugar -- it doesn't introduce any power to the language.

It was introduced because it is a very common pattern when using the
`Result` and `Option` enums. In fact, before it existed, it was just a
simple macro that you could also implement yourself.

For instance, given `Foo` and `Bar` types that need RAII cleanup of
some kind (let's say `kill_foo()` and `kill_bar()`):

    fn foo() -> KernelResult<Foo> {
        if black_box() {
            return Err(EINVAL);
        }

        // something that gets you a `Foo`
        let foo = ...;

        Ok(foo)
    }

    fn bar() -> KernelResult<Bar> {
        let p = foo()?;

        // something that gets you a `Bar`, possibly using the `p`
        let bar = ...;

        Ok(bar)
    }

This reduces to (full example at https://godbolt.org/z/hjTxd3oP1):

    bar:
            push    rbx
            mov     ebx, 1
            call    qword ptr [rip + black_box@GOTPCREL]
            test    al, al
            jne     .LBB2_2
            call    qword ptr [rip + kill_foo@GOTPCREL]
            xor     ebx, ebx
    .LBB2_2:
            mov     eax, ebx
            mov     edx, -1234
            pop     rbx
            ret

You can see `bar()` calls `black_box()`. If it failed, it returns the
EINVAL. Otherwise, it cleans up the `foo` automatically and returns
the successful `bar`.

Cheers,
Miguel
Willy Tarreau April 16, 2021, 8:22 p.m. UTC | #11
On Fri, Apr 16, 2021 at 08:57:07PM +0200, Miguel Ojeda wrote:
> On Fri, Apr 16, 2021 at 8:10 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > How well would ? operator fit that pattern?  _If_ it's just a syntax sugar
> > along the lines of "if argument matches Err(_), return Err(_)", the types
> > shouldn't be an issue, but that might need some fun with releasing resources,
> > etc.  If it's something more elaborate... details, please.
> 
> Yes, it is just syntax sugar -- it doesn't introduce any power to the language.
> 
> It was introduced because it is a very common pattern when using the
> `Result` and `Option` enums. In fact, before it existed, it was just a
> simple macro that you could also implement yourself.
> 
> For instance, given `Foo` and `Bar` types that need RAII cleanup of
> some kind (let's say `kill_foo()` and `kill_bar()`):
> 
>     fn foo() -> KernelResult<Foo> {
>         if black_box() {
>             return Err(EINVAL);
>         }
> 
>         // something that gets you a `Foo`
>         let foo = ...;
> 
>         Ok(foo)
>     }
> 
>     fn bar() -> KernelResult<Bar> {
>         let p = foo()?;
> 
>         // something that gets you a `Bar`, possibly using the `p`
>         let bar = ...;
> 
>         Ok(bar)
>     }
> 
> This reduces to (full example at https://godbolt.org/z/hjTxd3oP1):
> 
>     bar:
>             push    rbx
>             mov     ebx, 1
>             call    qword ptr [rip + black_box@GOTPCREL]
>             test    al, al
>             jne     .LBB2_2
>             call    qword ptr [rip + kill_foo@GOTPCREL]
>             xor     ebx, ebx
>     .LBB2_2:
>             mov     eax, ebx
>             mov     edx, -1234
>             pop     rbx
>             ret
> 
> You can see `bar()` calls `black_box()`. If it failed, it returns the
> EINVAL. Otherwise, it cleans up the `foo` automatically and returns
> the successful `bar`.

So it simply does the equivalent of:

  #define EINVAL -1234

  struct result {
     int status;
     int error;
  };

  extern bool black_box();
  extern void kill_foo();

  struct result bar()
  {
     return (struct error){ !!black_box(), EINVAL };
  }

  struct result foo()
  {
     struct result res = bar();

     if (res.status)
        goto leave;
     /* ... */
     kill_foo();   // only for rust, C doesn't need it
  leave:
     return res;
  }

So it simply returns a pair of values instead of a single one, which
is nothing special but not much conventional in the kernel either given
that ultimately syscalls will usually return a single value anyway. At
some point some code will have to remerge them to provide a composite
result and even take care of ambigous special cases like { true, 0 }
which may or may not indicate an error, and avoiding to consider the
unused error code on success.

For example some code called from mmap() might have to deal with this
this way:

   if (result.status == (void *)-1)
       return -result.error;
   else
       return result.status;

But possibly a lot of code feeding this result struct would be tempted
to do something like this to deal with NULL returns:

   result.status = foo_alloc();
   if (!result.status) {
       result.error = -ENOMEM;
       return result;
   }

And suddenly the error is lost, as a NULL is returned to the upper layers
which does not correspond to an failure status. Conversely, with a unique
result you'd do something like this:

   result = foo_alloc();
   if (!result)
       return -ENOMEM;

So it might possibly be safer to stick to the usually expected return
values instead of introducing composite ones.

I tend to agree that composite results can be better from new projects
started from scratch when all the API follows this principle, but here
there's quite a massive code base that was not designed along these
lines and I easily see how this can become a source of trouble over
time.

Willy
Connor Kuehl April 16, 2021, 8:34 p.m. UTC | #12
On 4/16/21 3:22 PM, Willy Tarreau wrote:
> So it simply does the equivalent of:
> 
>   #define EINVAL -1234
> 
>   struct result {
>      int status;
>      int error;
>   };

Result and Option types are more like a union with a tag that
describes which variant it is.

struct foo_result {
    /* if ok, then access foo_or_err.successful_foo
     *        else, access foo_or_err.error
     */
    bool ok;
    union {
        struct foo successful_foo;
        int error;
    } foo_or_err;
};

> [..]
> 
> So it simply returns a pair of values instead of a single one, which

It will only return 1 value.
Willy Tarreau April 16, 2021, 8:58 p.m. UTC | #13
On Fri, Apr 16, 2021 at 03:34:50PM -0500, Connor Kuehl wrote:
> On 4/16/21 3:22 PM, Willy Tarreau wrote:
> > So it simply does the equivalent of:
> > 
> >   #define EINVAL -1234
> > 
> >   struct result {
> >      int status;
> >      int error;
> >   };
> 
> Result and Option types are more like a union with a tag that
> describes which variant it is.
> 
> struct foo_result {
>     /* if ok, then access foo_or_err.successful_foo
>      *        else, access foo_or_err.error
>      */
>     bool ok;
>     union {
>         struct foo successful_foo;
>         int error;
>     } foo_or_err;
> };

OK.

> > [..]
> > 
> > So it simply returns a pair of values instead of a single one, which
> 
> It will only return 1 value.

No, two:
  - ok in %rax (seems like it's "!ok" technically speaking since it
    returns 1 on !ok and 0 on ok)
  - foo_or_err in %rdx

However then I'm bothered because Miguel's example showed that regardless
of OK, EINVAL was always returned in foo_or_err, so maybe it's just
because his example was not well chosen but it wasn't very visible from
the source:

     bar:
             push    rbx
             mov     ebx, 1
             call    qword ptr [rip + black_box@GOTPCREL]
             test    al, al
             jne     .LBB2_2
             call    qword ptr [rip + kill_foo@GOTPCREL]
             xor     ebx, ebx
     .LBB2_2:
             mov     eax, ebx
             mov     edx, -1234
             pop     rbx
             ret

Willy
Miguel Ojeda April 16, 2021, 9:19 p.m. UTC | #14
On Fri, Apr 16, 2021 at 10:22 PM Willy Tarreau <w@1wt.eu> wrote:
>
> So it simply does the equivalent of:
>
>   struct result {
>      int status;
>      int error;
>   };

Not exactly, it is more like a tagged union, as Connor mentioned.

However, and this is the critical bit: it is a compile-time error to
access the inactive variants (in safe code). In C, it is on you to
keep track which one is the current one.

>      kill_foo();   // only for rust, C doesn't need it

Please note that `kill_foo()` is not needed in Rust -- it was an
example of possible cleanup (since Al mentioned resources/cleanup)
using RAII.

Cheers,
Miguel
Miguel Ojeda April 16, 2021, 9:39 p.m. UTC | #15
On Fri, Apr 16, 2021 at 10:58 PM Willy Tarreau <w@1wt.eu> wrote:
>
> No, two:
>   - ok in %rax (seems like it's "!ok" technically speaking since it
>     returns 1 on !ok and 0 on ok)
>   - foo_or_err in %rdx

Yes, but that is the implementation -- conceptually you only have one
or the other, and Rust won't allow you to use the wrong one.

> However then I'm bothered because Miguel's example showed that regardless
> of OK, EINVAL was always returned in foo_or_err, so maybe it's just
> because his example was not well chosen but it wasn't very visible from
> the source:

That is the optimizer being fancy since the error can be put
unconditionally in `rdx`.

If you compile:

    pub fn it_is_ok() -> KernelResult<Bar> {
        Ok(Bar)
    }

you will see it just clears `rax`.

Cheers,
Miguel
Al Viro April 16, 2021, 10:45 p.m. UTC | #16
On Sat, Apr 17, 2021 at 12:04:16AM +0200, Willy Tarreau wrote:

> Yep but I kept it just to have comparable output code since in C
> you'd simply use "goto leave" and not have this function call to
> do the cleanup.

... or use any number of other technics; the real question was how
much of cleanups would be skipped by that syntax sugar.

IME anything that interacts with flow control should be as explicit
and unambiguous as possible.  _Especially_ concerning how large
a scope are we leaving.

There's a bunch of disciplines that make use of that kind of tools
and do it more or less safely, but they need to be well-specified
and very well understood.  And some tools (C++-style exceptions,
for example) simply need to be taken out and shot, but that's
a separate story^Wflamewar...
Miguel Ojeda April 16, 2021, 11:46 p.m. UTC | #17
On Sat, Apr 17, 2021 at 12:04 AM Willy Tarreau <w@1wt.eu> wrote:
>
> But my point remains that the point of extreme care is at the interface
> with the rest of the kernel because there is a change of semantics
> there.
>
> Sure but as I said most often (due to API or ABI inheritance), both
> are already exclusive and stored as ranges. Returning 1..4095 for
> errno or a pointer including NULL for a success doesn't shock me at
> all.

At the point of the interface we definitely need to take care of
converting properly, but for Rust-to-Rust code (i.e. the ones using
`Result` etc.), that would not be a concern.

Just to ensure I understood your concern, for instance, in this case
you mentioned:

   result.status = foo_alloc();
   if (!result.status) {
       result.error = -ENOMEM;
       return result;
   }

Is your concern is that the caller would mix up the `status` with the
`error`, basically bubbling up the `status` as an `int` and forgetting
about the `error`, and then someone else later understanding that
`int` as a non-error because it is non-negative?

If yes: in C, yes, that could be a concern (if done with raw `int`s).
In Rust, if you get an `Err(ENOMEM)` from somebody, you cannot easily
conflate it with another type and return it by mistake because it is
more strictly typed than C.

Cheers,
Miguel
Willy Tarreau April 17, 2021, 4:24 a.m. UTC | #18
On Sat, Apr 17, 2021 at 01:46:35AM +0200, Miguel Ojeda wrote:
> On Sat, Apr 17, 2021 at 12:04 AM Willy Tarreau <w@1wt.eu> wrote:
> >
> > But my point remains that the point of extreme care is at the interface
> > with the rest of the kernel because there is a change of semantics
> > there.
> >
> > Sure but as I said most often (due to API or ABI inheritance), both
> > are already exclusive and stored as ranges. Returning 1..4095 for
> > errno or a pointer including NULL for a success doesn't shock me at
> > all.
> 
> At the point of the interface we definitely need to take care of
> converting properly, but for Rust-to-Rust code (i.e. the ones using
> `Result` etc.), that would not be a concern.

Sure.

> Just to ensure I understood your concern, for instance, in this case
> you mentioned:
> 
>    result.status = foo_alloc();
>    if (!result.status) {
>        result.error = -ENOMEM;
>        return result;
>    }

Yes I mentioned this when it was my understanding that the composite
result returned was made both of a pointer and an error code, but Connor
explained that it was in fact more of a selector and a union.

> Is your concern is that the caller would mix up the `status` with the
> `error`, basically bubbling up the `status` as an `int` and forgetting
> about the `error`, and then someone else later understanding that
> `int` as a non-error because it is non-negative?

My concern was to know what field to look at to reliably detect an error
from the C side after a sequence doing C -> Rust -> C when the inner C
code uses NULL to mark an error and the upper C code uses NULL as a valid
value and needs to look at an error code instead to rebuild a result. But
if it's more:
     
     if (result.ok)
        return result.pointer;
     else
        return (void *)-result.error;
    
then it shouldn't be an issue.

Willy
Miguel Ojeda April 17, 2021, 3:38 p.m. UTC | #19
On Sat, Apr 17, 2021 at 6:24 AM Willy Tarreau <w@1wt.eu> wrote:
>
> My concern was to know what field to look at to reliably detect an error
> from the C side after a sequence doing C -> Rust -> C when the inner C
> code uses NULL to mark an error and the upper C code uses NULL as a valid
> value and needs to look at an error code instead to rebuild a result. But

I see, thanks for clarifying. I don't think we want to change anything
on either of the C sides (at least for the foreseeable future). So the
Rust code in-between must respect whatever conventions both C sides
already use, even if they happen to be different on each side.

Thus the C side will not know there was a `Result` inside the Rust
side and so it does not need to worry about which field to look at.

Cheers,
Miguel
Masahiro Yamada April 17, 2021, 7:35 p.m. UTC | #20
On Thu, Apr 15, 2021 at 9:43 AM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Thu, Apr 15, 2021 at 1:19 AM Nick Desaulniers
> <ndesaulniers@google.com> wrote:
> >
> > Rather than check the origin (yikes, are we intentionally avoiding env
> > vars?), can this simply be
> > ifneq ($(CLIPPY),)
> >   KBUILD_CLIPPY := $(CLIPPY)
> > endif
> >
> > Then you can specify whatever value you want, support command line or
> > env vars, etc.?
>
> I was following the other existing cases like `V`. Masahiro can
> probably answer why they are done like this.

You are asking about this code:

ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif


You can pass V=1 from the Make command line,
but not from the environment.


KBUILD_VERBOSE is intended as an environment variable,
but you can use it from the Make command line.


Work:
 - make V=1
 - make KBUILD_VERBOSE=1
 - KBUILD_VERBOSE=1 make

Not work:
 - V=1 make



The behavior is like that before I became the maintainer.
In my best guess, the reason is,
V=1 is a useful shorthand of KBUILD_VERBOSE=1,
but it is too short. It should not accidentally
pick up an unintended environment variable.
David Sterba April 19, 2021, 7:58 p.m. UTC | #21
On Fri, Apr 16, 2021 at 07:34:51PM +0200, Miguel Ojeda wrote:
> On Fri, Apr 16, 2021 at 3:38 PM Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > So if I read all this right, rust compiles to .o and, like any other .o
> > file is then fed into objtool (for x86_64). Did you have any problems
> > with objtool? Does it generate correct ORC unwind information?
> 
> I opened an issue a while ago to take a closer look at the ORC
> unwinder etc., so it is in my radar (thanks for raising it up,
> nevertheless!).
> 
> Currently, causing a panic in a nested non-inlined function (f -> g ->
> h) in one of the samples with the ORC unwinder enabled gives me
> something like:
> 
> [    0.903456]  rust_begin_unwind+0x9/0x10
> [    0.903456]  ? _RNvNtCsbDqzXfLQacH_4core9panicking9panic_fmt+0x29/0x30
> [    0.903456]  ? _RNvNtCsbDqzXfLQacH_4core9panicking5panic+0x44/0x50
> [    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1h+0x1c/0x20
> [    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1g+0x9/0x10
> [    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1f+0x9/0x10
> [    0.903456]  ?
> _RNvXCsbDqzXfLQacH_12rust_minimalNtB2_11RustMinimalNtCsbDqzXfLQacH_6kernel12KernelModule4init+0x73/0x80
> [    0.903456]  ? _RNvXsa_NtCsbDqzXfLQacH_4core3fmtbNtB5_5Debug3fmt+0x30/0x30
> [    0.903456]  ? __rust_minimal_init+0x11/0x20

Are there plans to unmangle the symbols when printing stacks? c++filt
says:

  rust_begin_unwind+0x9/0x10
  ? core[8787f43e282added]::panicking::panic_fmt+0x29/0x30
  ? core[8787f43e282added]::panicking::panic+0x44/0x50
  ? rust_minimal[8787f43e282added]::h+0x1c/0x20
  ? rust_minimal[8787f43e282added]::g+0x9/0x10
  ? rust_minimal[8787f43e282added]::f+0x9/0x10
  ? <rust_minimal[8787f43e282added]::RustMinimal as kernel[8787f43e282added]::KernelModule>::init+0x73/0x80
  ? <bool as core[8787f43e282added]::fmt::Debug>::fmt+0x30/0x30
  ? __rust_minimal_init+0x11/0x20

for simple functions it's barely parseable but the following is hardly
readable

> _RNvXs5_NtCsbDqzXfLQacH_11rust_binder11range_allocNtB5_15DescriptorStateNtNtCsbDqzXfLQacH_4core3fmt5Debug3fmt+0x60/0x60

translates to

  <rust_binder[8787f43e282added]::range_alloc::DescriptorState as core[8787f43e282added]::fmt::Debug>::fmt
Matthew Wilcox April 19, 2021, 8:17 p.m. UTC | #22
On Mon, Apr 19, 2021 at 09:58:51PM +0200, David Sterba wrote:
> On Fri, Apr 16, 2021 at 07:34:51PM +0200, Miguel Ojeda wrote:
> > something like:
> > 
> > [    0.903456]  rust_begin_unwind+0x9/0x10
> > [    0.903456]  ? _RNvNtCsbDqzXfLQacH_4core9panicking9panic_fmt+0x29/0x30
> > [    0.903456]  ? _RNvNtCsbDqzXfLQacH_4core9panicking5panic+0x44/0x50
> > [    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1h+0x1c/0x20
> > [    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1g+0x9/0x10
> > [    0.903456]  ? _RNvCsbDqzXfLQacH_12rust_minimal1f+0x9/0x10
> > [    0.903456]  ?
> > _RNvXCsbDqzXfLQacH_12rust_minimalNtB2_11RustMinimalNtCsbDqzXfLQacH_6kernel12KernelModule4init+0x73/0x80
> > [    0.903456]  ? _RNvXsa_NtCsbDqzXfLQacH_4core3fmtbNtB5_5Debug3fmt+0x30/0x30
> > [    0.903456]  ? __rust_minimal_init+0x11/0x20
> 
> Are there plans to unmangle the symbols when printing stacks? c++filt
> says:
> 
>   rust_begin_unwind+0x9/0x10
>   ? core[8787f43e282added]::panicking::panic_fmt+0x29/0x30
>   ? core[8787f43e282added]::panicking::panic+0x44/0x50
>   ? rust_minimal[8787f43e282added]::h+0x1c/0x20
>   ? rust_minimal[8787f43e282added]::g+0x9/0x10
>   ? rust_minimal[8787f43e282added]::f+0x9/0x10
>   ? <rust_minimal[8787f43e282added]::RustMinimal as kernel[8787f43e282added]::KernelModule>::init+0x73/0x80
>   ? <bool as core[8787f43e282added]::fmt::Debug>::fmt+0x30/0x30
>   ? __rust_minimal_init+0x11/0x20
> 
> for simple functions it's barely parseable but the following is hardly
> readable
> 
> > _RNvXs5_NtCsbDqzXfLQacH_11rust_binder11range_allocNtB5_15DescriptorStateNtNtCsbDqzXfLQacH_4core3fmt5Debug3fmt+0x60/0x60
> 
> translates to
> 
>   <rust_binder[8787f43e282added]::range_alloc::DescriptorState as core[8787f43e282added]::fmt::Debug>::fmt

Yes, I agree, we need a better story for name mangling.
My proposal is that we store a pretty name which matches the source
(eg rust_binder::range_alloc) and a sha1 of the mangled symbol
(40 bytes of uninteresting hex).  Symbol resolution is performed against
the sha1.  Printing is of the pretty name.  It should be obvious from
the stack trace which variant of a function is being called, no?
Miguel Ojeda April 19, 2021, 8:54 p.m. UTC | #23
Hi David,

On Mon, Apr 19, 2021 at 10:01 PM David Sterba <dsterba@suse.cz> wrote:
>
> for simple functions it's barely parseable but the following is hardly
> readable
>
> translates to
>
>   <rust_binder[8787f43e282added]::range_alloc::DescriptorState as core[8787f43e282added]::fmt::Debug>::fmt

Some details can be omitted without much problem, e.g. try the `-i`
option of `c++filt`:

    <rust_binder::range_alloc::DescriptorState as core::fmt::Debug>::fmt

Cheers,
Miguel
Miguel Ojeda April 19, 2021, 9:03 p.m. UTC | #24
On Mon, Apr 19, 2021 at 10:18 PM Matthew Wilcox <willy@infradead.org> wrote:
>
> Yes, I agree, we need a better story for name mangling.
> My proposal is that we store a pretty name which matches the source
> (eg rust_binder::range_alloc) and a sha1 of the mangled symbol
> (40 bytes of uninteresting hex).  Symbol resolution is performed against
> the sha1.  Printing is of the pretty name.  It should be obvious from
> the stack trace which variant of a function is being called, no?

If the pretty name is only `rust_binder::range_alloc`, that would not
be enough, since (in this case) that is a module name (i.e. the
namespace of the `DescriptorState` type). The function being called
here is `fmt` (the one outside the `<>`), which is a method of the
`Debug` trait.

We could perhaps reduce this down to:

    rust_binder::range_alloc::DescriptorState::fmt

without much ambiguity (in most cases).

Cheers,
Miguel
diff mbox series

Patch

diff --git a/.gitignore b/.gitignore
index 3af66272d6f1..6ba4f516f46c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ 
 *.o
 *.o.*
 *.patch
+*.rmeta
 *.s
 *.so
 *.so.dbg
@@ -96,6 +97,7 @@  modules.order
 !.gitattributes
 !.gitignore
 !.mailmap
+!.rustfmt.toml
 
 #
 # Generated include files
diff --git a/.rustfmt.toml b/.rustfmt.toml
new file mode 100644
index 000000000000..5893c0e3cbde
--- /dev/null
+++ b/.rustfmt.toml
@@ -0,0 +1,12 @@ 
+edition = "2018"
+format_code_in_doc_comments = true
+newline_style = "Unix"
+
+# Unstable options that help catching some mistakes in formatting and that we may want to enable
+# when they become stable.
+#
+# They are kept here since they are useful to run from time to time.
+#reorder_impl_items = true
+#comment_width = 100
+#wrap_comments = true
+#normalize_comments = true
diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst
index 2d1fc03d346e..1109d18d9377 100644
--- a/Documentation/kbuild/kbuild.rst
+++ b/Documentation/kbuild/kbuild.rst
@@ -57,6 +57,10 @@  CFLAGS_MODULE
 -------------
 Additional module specific options to use for $(CC).
 
+KRUSTCFLAGS
+-----------
+Additional options to the Rust compiler (for built-in and modules).
+
 LDFLAGS_MODULE
 --------------
 Additional options used for $(LD) when linking modules.
diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst
index dac17711dc11..4b6ba5458706 100644
--- a/Documentation/process/changes.rst
+++ b/Documentation/process/changes.rst
@@ -31,6 +31,8 @@  you probably needn't concern yourself with pcmciautils.
 ====================== ===============  ========================================
 GNU C                  4.9              gcc --version
 Clang/LLVM (optional)  10.0.1           clang --version
+rustc (optional)       nightly          rustc --version
+bindgen (optional)     0.56.0           bindgen --version
 GNU make               3.81             make --version
 binutils               2.23             ld -v
 flex                   2.5.35           flex --version
@@ -56,6 +58,7 @@  iptables               1.4.2            iptables -V
 openssl & libcrypto    1.0.0            openssl version
 bc                     1.06.95          bc --version
 Sphinx\ [#f1]_	       1.3		sphinx-build --version
+rustdoc (optional)     nightly          rustdoc --version
 ====================== ===============  ========================================
 
 .. [#f1] Sphinx is needed only to build the Kernel documentation
@@ -330,6 +333,12 @@  Sphinx
 Please see :ref:`sphinx_install` in :ref:`Documentation/doc-guide/sphinx.rst <sphinxdoc>`
 for details about Sphinx requirements.
 
+rustdoc
+-------
+
+``rustdoc`` is used to generate Rust documentation. Please see
+:ref:`Documentation/rust/docs.rst <rust_docs>` for more information.
+
 Getting updated software
 ========================
 
diff --git a/Makefile b/Makefile
index 9c75354324ed..62b3bba38635 100644
--- a/Makefile
+++ b/Makefile
@@ -120,6 +120,13 @@  endif
 
 export KBUILD_CHECKSRC
 
+# Enable "clippy" (a linter) as part of the Rust compilation.
+#
+# Use 'make CLIPPY=1' to enable it.
+ifeq ("$(origin CLIPPY)", "command line")
+  KBUILD_CLIPPY := $(CLIPPY)
+endif
+
 # Use make M=dir or set the environment variable KBUILD_EXTMOD to specify the
 # directory of external module to build. Setting M= takes precedence.
 ifeq ("$(origin M)", "command line")
@@ -263,7 +270,7 @@  no-dot-config-targets := $(clean-targets) \
 			 cscope gtags TAGS tags help% %docs check% coccicheck \
 			 $(version_h) headers headers_% archheaders archscripts \
 			 %asm-generic kernelversion %src-pkg dt_binding_check \
-			 outputmakefile
+			 outputmakefile rustfmt rustfmtcheck
 no-sync-config-targets := $(no-dot-config-targets) %install kernelrelease \
 			  image_name
 single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.s %.symtypes %/
@@ -444,6 +451,10 @@  OBJDUMP		= $(CROSS_COMPILE)objdump
 READELF		= $(CROSS_COMPILE)readelf
 STRIP		= $(CROSS_COMPILE)strip
 endif
+RUSTC		= rustc
+RUSTFMT		= rustfmt
+CLIPPY_DRIVER	= clippy-driver
+BINDGEN		= bindgen
 PAHOLE		= pahole
 RESOLVE_BTFIDS	= $(objtree)/tools/bpf/resolve_btfids/resolve_btfids
 LEX		= flex
@@ -467,9 +478,11 @@  CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
 		  -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF)
 NOSTDINC_FLAGS :=
 CFLAGS_MODULE   =
+RUSTCFLAGS_MODULE =
 AFLAGS_MODULE   =
 LDFLAGS_MODULE  =
 CFLAGS_KERNEL	=
+RUSTCFLAGS_KERNEL =
 AFLAGS_KERNEL	=
 LDFLAGS_vmlinux =
 
@@ -498,15 +511,30 @@  KBUILD_CFLAGS   := -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs \
 		   -Werror=return-type -Wno-format-security \
 		   -std=gnu89
 KBUILD_CPPFLAGS := -D__KERNEL__
+KBUILD_RUSTCFLAGS := --emit=dep-info,obj,metadata --edition=2018 \
+		     -Cpanic=abort -Cembed-bitcode=n -Clto=n -Crpath=n \
+		     -Cforce-unwind-tables=n -Ccodegen-units=1 \
+		     -Zbinary_dep_depinfo=y -Zsymbol-mangling-version=v0
 KBUILD_AFLAGS_KERNEL :=
 KBUILD_CFLAGS_KERNEL :=
+KBUILD_RUSTCFLAGS_KERNEL :=
 KBUILD_AFLAGS_MODULE  := -DMODULE
 KBUILD_CFLAGS_MODULE  := -DMODULE
+KBUILD_RUSTCFLAGS_MODULE := --cfg MODULE
 KBUILD_LDFLAGS_MODULE :=
 KBUILD_LDFLAGS :=
 CLANG_FLAGS :=
 
-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
+ifeq ($(KBUILD_CLIPPY),1)
+	RUSTC_OR_CLIPPY_QUIET := CLIPPY
+	RUSTC_OR_CLIPPY = $(CLIPPY_DRIVER)
+else
+	RUSTC_OR_CLIPPY_QUIET := RUSTC
+	RUSTC_OR_CLIPPY = $(RUSTC)
+endif
+export RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY
+
+export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC RUSTC BINDGEN
 export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
 export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
 export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD
@@ -514,9 +542,10 @@  export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
 
 export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
 export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
+export KBUILD_RUSTCFLAGS RUSTCFLAGS_KERNEL RUSTCFLAGS_MODULE
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
-export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
-export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
+export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_RUSTCFLAGS_MODULE KBUILD_LDFLAGS_MODULE
+export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTCFLAGS_KERNEL
 
 # Files to ignore in find ... statements
 
@@ -712,7 +741,7 @@  $(KCONFIG_CONFIG):
 quiet_cmd_syncconfig = SYNC    $@
       cmd_syncconfig = $(MAKE) -f $(srctree)/Makefile syncconfig
 
-%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h: $(KCONFIG_CONFIG)
+%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h %/generated/rustc_cfg: $(KCONFIG_CONFIG)
 	+$(call cmd,syncconfig)
 else # !may-sync-config
 # External modules and some install targets need include/generated/autoconf.h
@@ -738,12 +767,43 @@  KBUILD_CFLAGS	+= $(call cc-disable-warning, format-truncation)
 KBUILD_CFLAGS	+= $(call cc-disable-warning, format-overflow)
 KBUILD_CFLAGS	+= $(call cc-disable-warning, address-of-packed-member)
 
+ifdef CONFIG_RUST_DEBUG_ASSERTIONS
+KBUILD_RUSTCFLAGS += -Cdebug-assertions=y
+else
+KBUILD_RUSTCFLAGS += -Cdebug-assertions=n
+endif
+
+ifdef CONFIG_RUST_OVERFLOW_CHECKS
+KBUILD_RUSTCFLAGS += -Coverflow-checks=y
+else
+KBUILD_RUSTCFLAGS += -Coverflow-checks=n
+endif
+
 ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
 KBUILD_CFLAGS += -O2
+KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP := 2
 else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
 KBUILD_CFLAGS += -O3
+KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP := 3
 else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
 KBUILD_CFLAGS += -Os
+KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP := z
+endif
+
+ifdef CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
+KBUILD_RUSTCFLAGS += -Copt-level=$(KBUILD_RUSTCFLAGS_OPT_LEVEL_MAP)
+else ifdef CONFIG_RUST_OPT_LEVEL_0
+KBUILD_RUSTCFLAGS += -Copt-level=0
+else ifdef CONFIG_RUST_OPT_LEVEL_1
+KBUILD_RUSTCFLAGS += -Copt-level=1
+else ifdef CONFIG_RUST_OPT_LEVEL_2
+KBUILD_RUSTCFLAGS += -Copt-level=2
+else ifdef CONFIG_RUST_OPT_LEVEL_3
+KBUILD_RUSTCFLAGS += -Copt-level=3
+else ifdef CONFIG_RUST_OPT_LEVEL_S
+KBUILD_RUSTCFLAGS += -Copt-level=s
+else ifdef CONFIG_RUST_OPT_LEVEL_Z
+KBUILD_RUSTCFLAGS += -Copt-level=z
 endif
 
 # Tell gcc to never replace conditional load with a non-conditional one
@@ -793,6 +853,7 @@  endif
 KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable)
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS	+= -fno-omit-frame-pointer -fno-optimize-sibling-calls
+KBUILD_RUSTCFLAGS += -Cforce-frame-pointers=y
 else
 # Some targets (ARM with Thumb2, for example), can't be built with frame
 # pointers.  For those, we don't have FUNCTION_TRACER automatically
@@ -826,6 +887,8 @@  ifdef CONFIG_CC_IS_GCC
 DEBUG_CFLAGS	+= $(call cc-ifversion, -lt, 0500, $(call cc-option, -fno-var-tracking-assignments))
 endif
 
+DEBUG_RUSTCFLAGS :=
+
 ifdef CONFIG_DEBUG_INFO
 
 ifdef CONFIG_DEBUG_INFO_SPLIT
@@ -836,6 +899,11 @@  endif
 
 ifneq ($(LLVM_IAS),1)
 KBUILD_AFLAGS	+= -Wa,-gdwarf-2
+ifdef CONFIG_DEBUG_INFO_REDUCED
+DEBUG_RUSTCFLAGS += -Cdebuginfo=1
+else
+DEBUG_RUSTCFLAGS += -Cdebuginfo=2
+endif
 endif
 
 ifndef CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
@@ -860,6 +928,9 @@  endif # CONFIG_DEBUG_INFO
 KBUILD_CFLAGS += $(DEBUG_CFLAGS)
 export DEBUG_CFLAGS
 
+KBUILD_RUSTCFLAGS += $(DEBUG_RUSTCFLAGS)
+export DEBUG_RUSTCFLAGS
+
 ifdef CONFIG_FUNCTION_TRACER
 ifdef CONFIG_FTRACE_MCOUNT_USE_CC
   CC_FLAGS_FTRACE	+= -mrecord-mcount
@@ -990,10 +1061,11 @@  include $(addprefix $(srctree)/, $(include-y))
 # Do not add $(call cc-option,...) below this line. When you build the kernel
 # from the clean source tree, the GCC plugins do not exist at this point.
 
-# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
+# Add user supplied CPPFLAGS, AFLAGS, CFLAGS and RUSTCFLAGS as the last assignments
 KBUILD_CPPFLAGS += $(KCPPFLAGS)
 KBUILD_AFLAGS   += $(KAFLAGS)
 KBUILD_CFLAGS   += $(KCFLAGS)
+KBUILD_RUSTCFLAGS += $(KRUSTCFLAGS)
 
 KBUILD_LDFLAGS_MODULE += --build-id=sha1
 LDFLAGS_vmlinux += --build-id=sha1
@@ -1138,6 +1210,10 @@  export MODULES_NSDEPS := $(extmod-prefix)modules.nsdeps
 ifeq ($(KBUILD_EXTMOD),)
 core-y		+= kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
 
+ifdef CONFIG_RUST
+core-y		+= rust/
+endif
+
 vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, \
 		     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
 		     $(libs-y) $(libs-m)))
@@ -1238,6 +1314,9 @@  archprepare: outputmakefile archheaders archscripts scripts include/config/kerne
 prepare0: archprepare
 	$(Q)$(MAKE) $(build)=scripts/mod
 	$(Q)$(MAKE) $(build)=.
+ifdef CONFIG_RUST
+	$(Q)$(MAKE) $(build)=rust
+endif
 
 # All the preparing..
 prepare: prepare0 prepare-objtool prepare-resolve_btfids
@@ -1648,6 +1727,13 @@  help:
 	@echo  '  kselftest-merge   - Merge all the config dependencies of'
 	@echo  '		      kselftest to existing .config.'
 	@echo  ''
+	@echo  'Rust targets:'
+	@echo  '  rustfmt	  - Reformat all the Rust code in the kernel'
+	@echo  '  rustfmtcheck	  - Checks if all the Rust code in the kernel'
+	@echo  '		    is formatted, printing a diff otherwise.'
+	@echo  '  rustdoc	  - Generate Rust documentation'
+	@echo  '		    (requires kernel .config)'
+	@echo  ''
 	@$(if $(dtstree), \
 		echo 'Devicetree:'; \
 		echo '* dtbs             - Build device tree blobs for enabled boards'; \
@@ -1719,6 +1805,27 @@  PHONY += $(DOC_TARGETS)
 $(DOC_TARGETS):
 	$(Q)$(MAKE) $(build)=Documentation $@
 
+
+# Rust targets
+# ---------------------------------------------------------------------------
+
+# Documentation target
+#
+# Using the singular to avoid running afoul of `no-dot-config-targets`.
+PHONY += rustdoc
+rustdoc: prepare0
+	$(Q)$(MAKE) $(build)=rust $@
+
+# Formatting targets
+PHONY += rustfmt rustfmtcheck
+
+rustfmt:
+	find -name '*.rs' | xargs $(RUSTFMT)
+
+rustfmtcheck:
+	find -name '*.rs' | xargs $(RUSTFMT) --check
+
+
 # Misc
 # ---------------------------------------------------------------------------
 
@@ -1866,6 +1973,7 @@  clean: $(clean-dirs)
 	$(call cmd,rmfiles)
 	@find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
 		\( -name '*.[aios]' -o -name '*.ko' -o -name '.*.cmd' \
+		-o -name '*.rmeta' \
 		-o -name '*.ko.*' \
 		-o -name '*.dtb' -o -name '*.dtbo' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
 		-o -name '*.dwo' -o -name '*.lst' \
diff --git a/arch/arm64/rust/target.json b/arch/arm64/rust/target.json
new file mode 100644
index 000000000000..44953e2725c4
--- /dev/null
+++ b/arch/arm64/rust/target.json
@@ -0,0 +1,40 @@ 
+{
+  "arch": "aarch64",
+  "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
+  "disable-redzone": true,
+  "eliminate-frame-pointer": false,
+  "emit-debug-gdb-scripts": false,
+  "env": "gnu",
+  "features": "+strict-align,+neon,+fp-armv8",
+  "function-sections": false,
+  "is-builtin": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "aarch64-unknown-none",
+  "max-atomic-width": 128,
+  "needs-plt": true,
+  "os": "none",
+  "panic-strategy": "abort",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relocation-model": "static",
+  "relro-level": "full",
+  "stack-probes": {
+    "kind": "inline-or-call",
+    "min-llvm-version-for-inline": [
+      11,
+      0,
+      1
+    ]
+  },
+  "target-c-int-width": "32",
+  "target-endian": "little",
+  "target-pointer-width": "64",
+  "vendor": ""
+}
diff --git a/arch/powerpc/rust/target.json b/arch/powerpc/rust/target.json
new file mode 100644
index 000000000000..1e53f8308092
--- /dev/null
+++ b/arch/powerpc/rust/target.json
@@ -0,0 +1,30 @@ 
+{
+  "arch": "powerpc64",
+  "code-mode": "kernel",
+  "cpu": "ppc64le",
+  "data-layout": "e-m:e-i64:64-n32:64",
+  "env": "gnu",
+  "features": "-altivec,-vsx,-hard-float",
+  "function-sections": false,
+  "is-builtin": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "powerpc64le-elf",
+  "max-atomic-width": 64,
+  "os": "none",
+  "panic-strategy": "abort",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relocation-model": "static",
+  "relro-level": "full",
+  "target-family": "unix",
+  "target-mcount": "_mcount",
+  "target-endian": "little",
+  "target-pointer-width": "64"
+}
diff --git a/arch/x86/rust/target.json b/arch/x86/rust/target.json
new file mode 100644
index 000000000000..6e1759cd45bf
--- /dev/null
+++ b/arch/x86/rust/target.json
@@ -0,0 +1,42 @@ 
+{
+  "arch": "x86_64",
+  "code-model": "kernel",
+  "cpu": "x86-64",
+  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
+  "disable-redzone": true,
+  "eliminate-frame-pointer": false,
+  "emit-debug-gdb-scripts": false,
+  "env": "gnu",
+  "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float",
+  "function-sections": false,
+  "is-builtin": true,
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-elf",
+  "max-atomic-width": 64,
+  "needs-plt": true,
+  "os": "none",
+  "panic-strategy": "abort",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-Wl,--as-needed",
+      "-Wl,-z,noexecstack",
+      "-m64"
+    ]
+  },
+  "relocation-model": "static",
+  "relro-level": "full",
+  "stack-probes": {
+    "kind": "inline-or-call",
+    "min-llvm-version-for-inline": [
+      11,
+      0,
+      1
+    ]
+  },
+  "target-c-int-width": "32",
+  "target-endian": "little",
+  "target-pointer-width": "64",
+  "vendor": "unknown"
+}
diff --git a/init/Kconfig b/init/Kconfig
index 5f5c776ef192..11475840c29c 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -57,6 +57,15 @@  config LLD_VERSION
 	default $(ld-version) if LD_IS_LLD
 	default 0
 
+config HAS_RUST
+	depends on ARM64 || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64
+	def_bool $(success,$(RUSTC) --version)
+
+config RUSTC_VERSION
+	depends on HAS_RUST
+	int
+	default $(shell,$(srctree)/scripts/rust-version.sh $(RUSTC))
+
 config CC_CAN_LINK
 	bool
 	default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(m64-flag)) if 64BIT
@@ -2027,6 +2036,24 @@  config PROFILING
 	  Say Y here to enable the extended profiling support mechanisms used
 	  by profilers.
 
+config RUST
+	bool "Rust support"
+	depends on HAS_RUST
+	depends on !COMPILE_TEST
+	default n
+	help
+	  Enables Rust support in the kernel.
+
+	  This allows other Rust-related options, like drivers written in Rust,
+	  to be selected.
+
+	  It is also required to be able to load external kernel modules
+	  written in Rust.
+
+	  See Documentation/rust/ for more information.
+
+	  If unsure, say N.
+
 #
 # Place an empty function call at each tracepoint site. Can be
 # dynamically changed for a probe function.
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2779c29d9981..acf4993baddc 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2537,6 +2537,106 @@  config HYPERV_TESTING
 
 endmenu # "Kernel Testing and Coverage"
 
+menu "Rust hacking"
+
+config RUST_DEBUG_ASSERTIONS
+	bool "Debug assertions"
+	default n
+	depends on RUST
+	help
+	  Enables rustc's `-Cdebug-assertions` codegen option.
+
+	  This flag lets you turn `cfg(debug_assertions)` conditional
+	  compilation on or off. This can be used to enable extra debugging
+	  code in development but not in production. For example, it controls
+	  the behavior of the standard library's `debug_assert!` macro.
+
+	  Note that this will apply to all Rust code, including `core`.
+
+	  If unsure, say N.
+
+config RUST_OVERFLOW_CHECKS
+	bool "Overflow checks"
+	default y
+	depends on RUST
+	help
+	  Enables rustc's `-Coverflow-checks` codegen option.
+
+	  This flag allows you to control the behavior of runtime integer
+	  overflow. When overflow-checks are enabled, a panic will occur
+	  on overflow.
+
+	  Note that this will apply to all Rust code, including `core`.
+
+	  If unsure, say Y.
+
+choice
+	prompt "Optimization level"
+	default RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
+	depends on RUST
+	help
+	  Controls rustc's `-Copt-level` codegen option.
+
+	  This flag controls the optimization level.
+
+	  If unsure, say "Similar as chosen for C".
+
+config RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
+	bool "Similar as chosen for C"
+	help
+	  This choice will pick a similar optimization level as chosen in
+	  the "Compiler optimization level" for C:
+
+	      -O2 is currently mapped to -Copt-level=2
+	      -O3 is currently mapped to -Copt-level=3
+	      -Os is currently mapped to -Copt-level=z
+
+	  The mapping may change over time to follow the intended semantics
+	  of the choice for C as sensibly as possible.
+
+	  This is the default.
+
+config RUST_OPT_LEVEL_0
+	bool "No optimizations (-Copt-level=0)"
+	help
+	  Not recommended for most purposes. It may come in handy for debugging
+	  suspected optimizer bugs, unexpected undefined behavior, etc.
+
+	  Note that this level will *not* enable debug assertions nor overflow
+	  checks on its own (like it happens when interacting with rustc
+	  directly). Use the corresponding configuration options to control
+	  that instead, orthogonally.
+
+config RUST_OPT_LEVEL_1
+	bool "Basic optimizations (-Copt-level=1)"
+	help
+	  Useful for debugging without getting too lost, but without
+	  the overhead and boilerplate of no optimizations at all.
+
+config RUST_OPT_LEVEL_2
+	bool "Some optimizations (-Copt-level=2)"
+	help
+	  The sensible choice in most cases.
+
+config RUST_OPT_LEVEL_3
+	bool "All optimizations (-Copt-level=3)"
+	help
+	  Yet more performance (hopefully).
+
+config RUST_OPT_LEVEL_S
+	bool "Optimize for size (-Copt-level=s)"
+	help
+	  Smaller kernel, ideally without too much performance loss.
+
+config RUST_OPT_LEVEL_Z
+	bool "Optimize for size, no loop vectorization (-Copt-level=z)"
+	help
+	  Like the previous level, but also turn off loop vectorization.
+
+endchoice
+
+endmenu # "Rust"
+
 source "Documentation/Kconfig"
 
 endmenu # Kernel hacking
diff --git a/rust/.gitignore b/rust/.gitignore
new file mode 100644
index 000000000000..8875e08ed0b1
--- /dev/null
+++ b/rust/.gitignore
@@ -0,0 +1,5 @@ 
+# SPDX-License-Identifier: GPL-2.0
+
+bindings_generated.rs
+exports_*_generated.h
+doc/
\ No newline at end of file
diff --git a/rust/Makefile b/rust/Makefile
new file mode 100644
index 000000000000..ba4b13e4fc7f
--- /dev/null
+++ b/rust/Makefile
@@ -0,0 +1,141 @@ 
+# SPDX-License-Identifier: GPL-2.0
+
+RUSTDOC = rustdoc
+
+quiet_cmd_rustdoc = RUSTDOC $<
+      cmd_rustdoc = \
+	RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
+	$(RUSTDOC) $(filter-out --emit=%, $(rustc_flags)) \
+		$(rustdoc_target_flags) -L $(objtree)/rust/ \
+		--output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \
+		-Fmissing-docs @$(objtree)/include/generated/rustc_cfg $<
+
+rustdoc: rustdoc-module rustdoc-compiler_builtins rustdoc-kernel
+
+rustdoc-module: private rustdoc_target_flags = --crate-type proc-macro \
+    --extern proc_macro
+rustdoc-module: $(srctree)/rust/module.rs FORCE
+	$(call if_changed,rustdoc)
+
+rustdoc-compiler_builtins: $(srctree)/rust/compiler_builtins.rs FORCE
+	$(call if_changed,rustdoc)
+
+rustdoc-kernel: private rustdoc_target_flags = --extern alloc \
+    --extern module=$(objtree)/rust/libmodule.so
+rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-module \
+    $(objtree)/rust/libmodule.so $(objtree)/rust/bindings_generated.rs FORCE
+	$(call if_changed,rustdoc)
+
+ifdef CONFIG_CC_IS_CLANG
+bindgen_c_flags = $(c_flags)
+else
+# bindgen relies on libclang to parse C. Ideally, bindgen would support a GCC
+# plugin backend and/or the Clang driver would be perfectly compatible with GCC.
+#
+# For the moment, here we are tweaking the flags on the fly. Some config
+# options may not work (e.g. `GCC_PLUGIN_RANDSTRUCT` if we end up using one
+# of those structs). We might want to redo how Clang flags are kept track of
+# in the general `Makefile` even for GCC builds, similar to what we did with
+# `TENTATIVE_CLANG_FLAGS`.
+bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
+	-mskip-rax-setup -mgeneral-regs-only -msign-return-address=% \
+	-mindirect-branch=thunk-extern -mindirect-branch-register -mrecord-mcount \
+	-mabi=lp64 -mstack-protector-guard% -fconserve-stack -falign-jumps=% \
+	-falign-loops=% -fno-ipa-cp-clone -fno-partial-inlining \
+	-fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \
+	-Wno-packed-not-aligned -Wno-format-truncation -Wno-format-overflow \
+	-Wno-stringop-truncation -Wno-unused-but-set-variable \
+	-Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized \
+	-Werror=designated-init -Wno-zero-length-bounds \
+	--param=% --param asan-%
+
+# PowerPC
+bindgen_skip_c_flags += -mtraceback=no -mno-pointers-to-nested-functions \
+	-mno-string -mno-strict-align
+
+bindgen_extra_c_flags = $(TENTATIVE_CLANG_FLAGS) -Wno-address-of-packed-member
+bindgen_c_flags = $(filter-out $(bindgen_skip_c_flags), $(c_flags)) \
+	$(bindgen_extra_c_flags)
+endif
+
+bindgen_opaque_types := xregs_state desc_struct arch_lbr_state
+
+# To avoid several recompilations in PowerPC, which inserts `-D_TASK_CPU`
+bindgen_c_flags_final = $(filter-out -D_TASK_CPU=%, $(bindgen_c_flags))
+
+quiet_cmd_bindgen = BINDGEN $@
+      cmd_bindgen = \
+	$(BINDGEN) $< $(addprefix --opaque-type , $(bindgen_opaque_types)) \
+		--use-core --with-derive-default --ctypes-prefix c_types \
+		--size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE
+
+$(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h FORCE
+	$(call if_changed_dep,bindgen)
+
+quiet_cmd_exports = EXPORTS $@
+      cmd_exports = \
+	$(NM) -p --defined-only $< \
+		| grep -E ' (T|R|D) ' | cut -d ' ' -f 3 | grep -E '^(__rust_|_R)' \
+		| xargs -Isymbol \
+		echo 'EXPORT_SYMBOL_RUST_GPL(symbol);' > $@
+
+$(objtree)/rust/exports_core_generated.h: $(objtree)/rust/core.o FORCE
+	$(call if_changed,exports)
+
+$(objtree)/rust/exports_alloc_generated.h: $(objtree)/rust/alloc.o FORCE
+	$(call if_changed,exports)
+
+$(objtree)/rust/exports_kernel_generated.h: $(objtree)/rust/kernel.o FORCE
+	$(call if_changed,exports)
+
+# `-Cpanic=unwind -Cforce-unwind-tables=y` overrides `rustc_flags` in order to
+# avoid the https://github.com/rust-lang/rust/issues/82320 rustc crash.
+quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
+      cmd_rustc_procmacro = \
+	$(RUSTC_OR_CLIPPY) $(rustc_flags) \
+		--emit=dep-info,link --extern proc_macro \
+		-Cpanic=unwind -Cforce-unwind-tables=y \
+		--crate-type proc-macro --out-dir $(objtree)/rust/ \
+		--crate-name $(patsubst lib%.so,%,$(notdir $@)) $<; \
+	mv $(objtree)/rust/$(patsubst lib%.so,%,$(notdir $@)).d $(depfile); \
+	sed -i '/^\#/d' $(depfile)
+
+$(objtree)/rust/libmodule.so: $(srctree)/rust/module.rs FORCE
+	$(call if_changed_dep,rustc_procmacro)
+
+quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
+      cmd_rustc_library = \
+	RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
+	$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
+		$(rustc_flags) $(rustc_cross_flags) $(rustc_target_flags) \
+		--crate-type rlib --out-dir $(objtree)/rust/ -L $(objtree)/rust/ \
+		--crate-name $(patsubst %.o,%,$(notdir $@)) $<; \
+	mv $(objtree)/rust/$(patsubst %.o,%,$(notdir $@)).d $(depfile); \
+	sed -i '/^\#/d' $(depfile) \
+	$(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@)
+
+# `$(rustc_flags)` is passed in case the user added `--sysroot`.
+rustc_sysroot = $(shell $(RUSTC) $(rustc_flags) --print sysroot)
+rustc_src = $(rustc_sysroot)/lib/rustlib/src/rust
+
+.SECONDEXPANSION:
+$(objtree)/rust/core.o: private skip_clippy = 1
+$(objtree)/rust/core.o: $$(rustc_src)/library/core/src/lib.rs FORCE
+	$(call if_changed_dep,rustc_library)
+
+$(objtree)/rust/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
+$(objtree)/rust/compiler_builtins.o: $(srctree)/rust/compiler_builtins.rs \
+    $(objtree)/rust/core.o FORCE
+	$(call if_changed_dep,rustc_library)
+
+$(objtree)/rust/alloc.o: private skip_clippy = 1
+$(objtree)/rust/alloc.o: $$(rustc_src)/library/alloc/src/lib.rs \
+    $(objtree)/rust/compiler_builtins.o FORCE
+	$(call if_changed_dep,rustc_library)
+
+# ICE on `--extern module`: https://github.com/rust-lang/rust/issues/56935
+$(objtree)/rust/kernel.o: private rustc_target_flags = --extern alloc \
+    --extern module=$(objtree)/rust/libmodule.so
+$(objtree)/rust/kernel.o: $(srctree)/rust/kernel/lib.rs $(objtree)/rust/alloc.o \
+    $(objtree)/rust/libmodule.so $(objtree)/rust/bindings_generated.rs FORCE
+	$(call if_changed_dep,rustc_library)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 1b6094a13034..3665c49c4dcf 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -26,6 +26,7 @@  EXTRA_CPPFLAGS :=
 EXTRA_LDFLAGS  :=
 asflags-y  :=
 ccflags-y  :=
+rustcflags-y :=
 cppflags-y :=
 ldflags-y  :=
 
@@ -287,6 +288,24 @@  quiet_cmd_cc_lst_c = MKLST   $@
 $(obj)/%.lst: $(src)/%.c FORCE
 	$(call if_changed_dep,cc_lst_c)
 
+# Compile Rust sources (.rs)
+# ---------------------------------------------------------------------------
+
+rustc_cross_flags := --target=$(srctree)/arch/$(SRCARCH)/rust/target.json
+
+quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
+      cmd_rustc_o_rs = \
+	RUST_MODFILE=$(modfile) \
+	$(RUSTC_OR_CLIPPY) $(rustc_flags) $(rustc_cross_flags) \
+		--extern alloc --extern kernel \
+		--crate-type rlib --out-dir $(obj) -L $(objtree)/rust/ \
+		--crate-name $(patsubst %.o,%,$(notdir $@)) $<; \
+	mv $(obj)/$(subst .o,,$(notdir $@)).d $(depfile); \
+	sed -i '/^\#/d' $(depfile)
+
+$(obj)/%.o: $(src)/%.rs FORCE
+	$(call if_changed_dep,rustc_o_rs)
+
 # Compile assembler sources (.S)
 # ---------------------------------------------------------------------------
 
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 8cd67b1b6d15..bd6cb3562fb4 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -8,6 +8,7 @@  ldflags-y  += $(EXTRA_LDFLAGS)
 # flags that take effect in current and sub directories
 KBUILD_AFLAGS += $(subdir-asflags-y)
 KBUILD_CFLAGS += $(subdir-ccflags-y)
+KBUILD_RUSTCFLAGS += $(subdir-rustcflags-y)
 
 # Figure out what we need to build from the various variables
 # ===========================================================================
@@ -122,6 +123,10 @@  _c_flags       = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \
                      $(filter-out $(ccflags-remove-y), \
                          $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(ccflags-y)) \
                      $(CFLAGS_$(target-stem).o))
+_rustc_flags    = $(filter-out $(RUSTCFLAGS_REMOVE_$(target-stem).o), \
+                     $(filter-out $(rustcflags-remove-y), \
+                         $(KBUILD_RUSTCFLAGS) $(rustcflags-y)) \
+                     $(RUSTCFLAGS_$(target-stem).o))
 _a_flags       = $(filter-out $(AFLAGS_REMOVE_$(target-stem).o), \
                      $(filter-out $(asflags-remove-y), \
                          $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(asflags-y)) \
@@ -191,6 +196,11 @@  modkern_cflags =                                          \
 		$(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \
 		$(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags))
 
+modkern_rustcflags =                                              \
+	$(if $(part-of-module),                                   \
+		$(KBUILD_RUSTCFLAGS_MODULE) $(RUSTCFLAGS_MODULE), \
+		$(KBUILD_RUSTCFLAGS_KERNEL) $(RUSTCFLAGS_KERNEL))
+
 modkern_aflags = $(if $(part-of-module),				\
 			$(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE),	\
 			$(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL))
@@ -200,6 +210,8 @@  c_flags        = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
 		 $(_c_flags) $(modkern_cflags)                           \
 		 $(basename_flags) $(modname_flags)
 
+rustc_flags     = $(_rustc_flags) $(modkern_rustcflags) @$(objtree)/include/generated/rustc_cfg
+
 a_flags        = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
 		 $(_a_flags) $(modkern_aflags)
 
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 2568dbe16ed6..a83d646ecef5 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -637,6 +637,56 @@  static struct conf_printer kconfig_printer_cb =
 	.print_comment = kconfig_print_comment,
 };
 
+/*
+ * rustc cfg printer
+ *
+ * This printer is used when generating the resulting rustc configuration
+ * after kconfig invocation and `defconfig` files.
+ */
+static void rustc_cfg_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+	const char *str;
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		str = sym_escape_string_value(value);
+
+		/*
+		 * We don't care about disabled ones, i.e. no need for
+		 * what otherwise are "comments" in other printers.
+		 */
+		if (*value == 'n')
+			return;
+
+		/*
+		 * To have similar functionality to the C macro `IS_ENABLED()`
+		 * we provide an empty `--cfg CONFIG_X` here in both `y`
+		 * and `m` cases.
+		 *
+		 * Then, the common `fprintf()` below will also give us
+		 * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
+		 * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
+		 */
+		if (*value == 'y' || *value == 'm')
+			fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
+
+		break;
+	default:
+		str = value;
+		break;
+	}
+
+	fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, str);
+}
+
+static struct conf_printer rustc_cfg_printer_cb =
+{
+	.print_symbol = rustc_cfg_print_symbol,
+};
+
 /*
  * Header printer
  *
@@ -1044,7 +1094,7 @@  int conf_write_autoconf(int overwrite)
 	struct symbol *sym;
 	const char *name;
 	const char *autoconf_name = conf_get_autoconfig_name();
-	FILE *out, *out_h;
+	FILE *out, *out_h, *out_rustc_cfg;
 	int i;
 
 	if (!overwrite && is_present(autoconf_name))
@@ -1065,6 +1115,13 @@  int conf_write_autoconf(int overwrite)
 		return 1;
 	}
 
+	out_rustc_cfg = fopen(".tmp_rustc_cfg", "w");
+	if (!out_rustc_cfg) {
+		fclose(out);
+		fclose(out_h);
+		return 1;
+	}
+
 	conf_write_heading(out, &kconfig_printer_cb, NULL);
 	conf_write_heading(out_h, &header_printer_cb, NULL);
 
@@ -1076,9 +1133,11 @@  int conf_write_autoconf(int overwrite)
 		/* write symbols to auto.conf and autoconf.h */
 		conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
 		conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
+		conf_write_symbol(out_rustc_cfg, sym, &rustc_cfg_printer_cb, NULL);
 	}
 	fclose(out);
 	fclose(out_h);
+	fclose(out_rustc_cfg);
 
 	name = getenv("KCONFIG_AUTOHEADER");
 	if (!name)
@@ -1097,6 +1156,12 @@  int conf_write_autoconf(int overwrite)
 	if (rename(".tmpconfig", autoconf_name))
 		return 1;
 
+	name = "include/generated/rustc_cfg";
+	if (make_parent_dir(name))
+		return 1;
+	if (rename(".tmp_rustc_cfg", name))
+		return 1;
+
 	return 0;
 }
 
diff --git a/scripts/rust-version.sh b/scripts/rust-version.sh
new file mode 100755
index 000000000000..67b6d31688e2
--- /dev/null
+++ b/scripts/rust-version.sh
@@ -0,0 +1,31 @@ 
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# rust-version rust-command
+#
+# Print the compiler version of `rust-command' in a 5 or 6-digit form
+# such as `14502' for rustc-1.45.2 etc.
+#
+# Returns 0 if not found (so that Kconfig does not complain)
+compiler="$*"
+
+if [ ${#compiler} -eq 0 ]; then
+	echo "Error: No compiler specified." >&2
+	printf "Usage:\n\t$0 <rust-command>\n" >&2
+	exit 1
+fi
+
+if ! command -v $compiler >/dev/null 2>&1; then
+	echo 0
+	exit 0
+fi
+
+VERSION=$($compiler --version | cut -f2 -d' ')
+
+# Cut suffix if any (e.g. `-dev`)
+VERSION=$(echo $VERSION | cut -f1 -d'-')
+
+MAJOR=$(echo $VERSION | cut -f1 -d'.')
+MINOR=$(echo $VERSION | cut -f2 -d'.')
+PATCHLEVEL=$(echo $VERSION | cut -f3 -d'.')
+printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL