├── .gitignore ├── 00_Introduction_to_Rust_Module_in_Linux ├── 01-Kernel_compiling.md ├── 02-How_rust_is_integrated_into_kernel.md ├── 03-Rust_build_processes_in_kernel.md ├── 04-How_rust_code_utilises_kernel_interfaces.md ├── 05-The_first_hello_world_module.md ├── 06-The_module_macro.md ├── 07_module_init_and_exit.md ├── 08_how_is_module_loaded_into_kernel.md ├── 09_how_is_rust_module_loaded_into_kernel.md ├── 10-parameters_in_rust_module.md ├── dependency_graph.drawio ├── dependency_graph.png └── my_macro │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Makefile │ └── src │ ├── lib │ └── lib.rs │ └── main.rs ├── 00_preface └── README.md ├── 01_Introduction_to_Linux_and_Device_Drivers └── README.md ├── 02_getting_start_with_driver_development └── README.md ├── LICENSE ├── README.md ├── eg_01_hello_world ├── Makefile ├── README.md └── main.rs └── eg_02_module_parameters ├── Makefile └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | 34 | # Others 35 | *.cmd 36 | *.symvers 37 | *.mod.c 38 | *.order 39 | .tmp_versions 40 | *.swp 41 | target 42 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/01-Kernel_compiling.md: -------------------------------------------------------------------------------- 1 | # Compile Rust Compatible Kernel 2 | ## Prerequisites 3 | 4 | ### Install nightly Rust 5 | 6 | For now, rust for Linux is still in development that means the project continuously takes advantages from latest rust compiler. So, a proper Rust compiler version is necessary to prevent from potential BUGs. 7 | 8 | ``` 9 | rustup override set $(scripts/min-tool-version.sh rustc) 10 | ``` 11 | 12 | ### Install bindgen 13 | 14 | `bindgen` is used to generate rust code from C side. 15 | 16 | ``` 17 | cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen 18 | ``` 19 | 20 | ### Install standard library source 21 | 22 | The Rust standard library source is required because the build system will cross-compile `core` and `alloc`. 23 | 24 | ``` 25 | rustup component add rust-src 26 | ``` 27 | 28 | ### Install libclang 29 | 30 | `libclang` (part of LLVM) is used by `bindgen` to understand the C code in the kernel, which means you will need a recent LLVM installed 31 | 32 | Download pre-build binaries from here. Beware to choose appropriate architecture. 33 | 34 | [https://github.com/llvm/llvm-project/releases](https://github.com/llvm/llvm-project/releases) 35 | 36 | ## Building Kernel 37 | 38 | ### Configure kernel. 39 | 40 | A new option is added to enable/disable Rust abilities in Kernel in `General setup`. 41 | 42 | ``` 43 | General setup ---> 44 | Rust support 45 | ``` 46 | 47 | It is notable that is option is only shown if a `rustc` build system id detected. 48 | 49 | ### Building kernel 50 | 51 | `GCC` is good for building Kernel. However, due to current experimental state, building Kernel with `Clang` or a complete `LLVM` toolchain is much better. 52 | 53 | 54 | If `libclang` is not installed in a standard location, e.g. `/lib`, you have to locate it manually via `LIBCLANG_PATH` environment: 55 | 56 | ``` 57 | LIBCLANG_PATH=/path/to/libclang make -j LLVM=1 bzImage 58 | ``` 59 | 60 | 61 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/02-How_rust_is_integrated_into_kernel.md: -------------------------------------------------------------------------------- 1 | # How Rust is integrated into Kernel. 2 | 3 | There is one question lingered in my head that how the [Kbuild] system builds 4 | rust's core and other stuffs. 5 | 6 | This post aims to solve this puzzle. 7 | 8 | # Basics of Kernel's Kbuild system. 9 | 10 | Before we dive into the chunks of Makefils, it is worthy to learn some basics 11 | of how kernel's Kbuild system works. 12 | 13 | There is one valuable documentation worthy to read from Kernel's source tree: 14 | [Linux Kernel Makefiles]. I highly suggest you to follow this documentation 15 | first before we going into the hall of puzzle. 16 | 17 | However, for readers who has no patience to read that, I will try my best to 18 | depict every detail. 19 | 20 | ## What is Kbuild 21 | 22 | Kbuild is the abbreviation of "the Linux Kernel Build System", which manages the 23 | process of build kernel image and in-tree/out-tree modules. 24 | 25 | Kbuild is a giant monster. Luckily, for most kernel hackers and driver deveopers, 26 | it is unnecessary to understand Kbuild thoroughly but a small set of rules and 27 | functions. 28 | 29 | Kbuild is made upon makefiles. It adopts make's principals and extents its 30 | abilities to a intact "system". For Linux Kernel, most codes are written in C 31 | and assembly. But there still are complex rules to compile and link these pieces 32 | together. What makes things worse is that other than C and assembly, some 33 | foreign programming languages exists, such as Python, Perl and Rust. 34 | 35 | Kbuild gathers information from every corner for source tree, and then makes 36 | decision on that to build kernel image. 37 | 38 | ## Prerequisites of Kbuild's makefile 39 | 40 | ### Config 41 | 42 | Kbuild's Makefiles have five parts: 43 | 44 | ``` 45 | makefile the top Makefile. 46 | .config the kernel configuration file. 47 | arch/$(SRCARCH)/Makefile the arch Makefile. 48 | scripts/Makefile.* common rules etc. for all kbuild Makefiles. 49 | kbuild Makefiles exist in every subdirectory 50 | ``` 51 | 52 | The `.config` file contains configuration switches which tell Kbuild what to 53 | build and what to be built as modules. Kernel users usually generate `.config` 54 | file by `make menuconfig` command which pops a interactive menu for making 55 | choice. As you wish, switch to enable or disable Rust support in kernel is 56 | contained in this file as well. 57 | 58 | ```makefile 59 | CONFIG_RUST=y 60 | ``` 61 | 62 | For users who has not installed `rustc` yet, `make menuconfig` menu has no 63 | option named `RUST` at all. This is due to that `make menuconfig` will first 64 | check the existence of `rustc` compile and then determine whether to show this 65 | option or not. This logical can be found in `init/Kconfig` 66 | 67 | ```makefile 68 | config HAS_RUST 69 | depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV 70 | def_bool $(success,$(RUSTC) --version) 71 | ``` 72 | 73 | And this: 74 | 75 | ```makefile 76 | config RUST 77 | bool "Rust support" 78 | depends on HAS_RUST 79 | depends on !COMPILE_TEST 80 | default n 81 | help 82 | Enables Rust support in the kernel. 83 | ``` 84 | 85 | ### Target 86 | 87 | When building starts, top Makefile recursively descends into subdirectories of 88 | the source tree, and finds targets named as `obj-y`. For rust, it looks like: 89 | 90 | ```makefile 91 | obj-$(CONFIG_RUST) += core.o compiler_builtins.o helpers.o 92 | obj-$(CONFIG_RUST) += alloc.o kernel.o 93 | obj-$(CONFIG_RUST) += exports.o 94 | ``` 95 | 96 | Note `CONFIG_RUST` variable here, it will be set according to `.config` file. 97 | When Rust support is enabled, `CONFIG_RUST` variable has value of `y` and 98 | results `obj-$(CONFIG_RUST)` to be `obj-y`. So, when Rust support is enable, 99 | these targets are: 100 | 101 | ```makefile 102 | obj-y += core.o compiler_builtins.o helpers.o 103 | obj-y += alloc.o kernel.o 104 | obj-y += exports.o 105 | ``` 106 | 107 | `obj-y` is a list of object files which will be finally linked into vmlinux 108 | image. 109 | 110 | ### Actual building command 111 | 112 | `core.o` is an object files and usually it is generated from `core.c` due to 113 | make's implicit rule. However, for `core.o` it is built from Rust source file 114 | instead of C files, so an explicit rule need to be specific. 115 | 116 | ```makefile 117 | .SECONDEXPANSION: 118 | $(objtree)/rust/core.o: private skip_clippy = 1 119 | $(objtree)/rust/core.o: $$(RUST_LIB_SRC)/core/src/lib.rs FORCE 120 | $(call if_changed_dep,rustc_library) 121 | ``` 122 | 123 | This rule is simple that says `$(objtree)/rust/core.o` depends on 124 | `$$(RUST_LIB_SRC)/core/src/lib.rs` and `FORCE` to update whenever this rule 125 | is run. 126 | 127 | `$(call if_changed_dep,rustc_library)` is a macro. `rustc_library` is run when 128 | files and dependences are changed. 129 | 130 | In the same Makefile, we can find: 131 | 132 | ```makefile 133 | quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@ 134 | cmd_rustc_library = \ 135 | RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \ 136 | $(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \ 137 | $(rustc_flags) $(rustc_cross_flags) $(rustc_target_flags) \ 138 | --crate-type rlib --out-dir $(objtree)/rust/ -L $(objtree)/rust/ \ 139 | --crate-name $(patsubst %.o,%,$(notdir $@)) $<; \ 140 | mv $(objtree)/rust/$(patsubst %.o,%,$(notdir $@)).d $(depfile); \ 141 | sed -i '/^\#/d' $(depfile) \ 142 | $(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) 143 | ``` 144 | 145 | The `quiet_cmd_` and `cmd_` are special variables which is 146 | consumed by Kbuild's "command change detection". Simply, in kernel's Makfile, 147 | we have the following form: 148 | 149 | ```makefile 150 | quiet_cmd_ = ... 151 | cmd_ = ... 152 | 153 | : FORCE 154 | $(call if_changed,) 155 | ``` 156 | 157 | The `if_changed` macro has several variants, and one of them is `if_changed_dep` 158 | what we have met before. All of these macros are defined in 159 | `scripts/Kbuild.include`. 160 | 161 | Conclude from above, we can deduce that to build `core.o` the command string 162 | in variable `cmd_rustc_library` should be evaluated. 163 | 164 | ### Non-builtin targets 165 | 166 | Wait, you say that a file named `bindings_generated.rs` is need and where is it? 167 | 168 | The `bindings_generated.rs` is a file which is automatically generated by 169 | `bindgen`. 170 | 171 | `bindgen` is tool for automatically generating Rust FFI(Foreign Function 172 | Interface) bindings to C and C++ libraries. For our examples here, 173 | `bindings_generated.rs` is generated before any `obj-y` object is built. 174 | 175 | In Kbuild, `extra-y` is used for such purpose. `extra-y` is a twin sister of 176 | `obj-y`. Targets in `extra-y` are built prior to targets in `obj-y`, and are not 177 | finally linked into vmlinux. 178 | 179 | ```makefile 180 | $(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h FORCE 181 | $(call if_changed_dep,bindgen) 182 | ``` 183 | 184 | Other than the list name and building sequence, the remaining procedures are 185 | identical. 186 | 187 | 188 | [Kbuild]: https://www.kernel.org/doc/html/latest/kbuild/kbuild.html 189 | [Linux Kernel Makefiles]: https://www.kernel.org/doc/html/latest/kbuild/makefiles.html 190 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/03-Rust_build_processes_in_kernel.md: -------------------------------------------------------------------------------- 1 | # Rust Build Processes in Kernel 2 | 3 | This documentation try to steps over phases of building Rust support in Kernel 4 | and linking rust files into Kernel image. 5 | 6 | ## Dependency Graph 7 | 8 | ![Dependency Graph](./dependency_graph.png) 9 | 10 | 11 | ## FFI (Foreign Function Interface) 12 | 13 | FFI bridges Rust and C (Some C++) libraries. It provides a neat interface for 14 | rust users to invoke c functions in a library. 15 | 16 | ## Bindgen 17 | 18 | However, directly write FFI interface is time consuming and not long lasting. It 19 | is better to use tools to automatically generate these bindings. For this 20 | purpose, [bindgen] comes in. 21 | 22 | bindgen automatically generates FFI bindings to C libraries, and give Ruster the 23 | abilities to invoke C functions directly in Rust code. It is super convenient 24 | and usable. For readers who have not been familiar with [bindgen], it is good 25 | to take a quick survey. 26 | 27 | One thing need to be noted in precedence is that [bindgen] can be both used as a 28 | library and command line tool. For Rust in Kernel, command line tool is used. 29 | 30 | Basically, [bindgen] takes a series of C header files in which signatures of 31 | functions are given, then [bindgen] analysis these function signatures and 32 | generates wrapper Rust functions on that. 33 | 34 | [bindgen] relays on [libclang] for parsing C codes. That is why we have to 35 | install [libclang] before compiling Rust subsystem in Kernel. 36 | 37 | Makefile rule for generating Rust binding files is listed as below: 38 | 39 | ``` 40 | quiet_cmd_bindgen = BINDGEN $@ 41 | cmd_bindgen = \ 42 | $(BINDGEN) $< $(addprefix --opaque-type , $(bindgen_opaque_types)) \ 43 | --use-core --with-derive-default --ctypes-prefix c_types \ 44 | --size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE 45 | 46 | $(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h FORCE 47 | $(call if_changed_dep,bindgen) 48 | ``` 49 | 50 | Options after two dashed `--` will be passed to clang for header searching and 51 | etc. 52 | 53 | ## Objects generated from C 54 | 55 | Some object files are generated directly from C source files in Rust directory. 56 | These files are generated implicitly by Makefile's implicit rule in that if 57 | `foo.o` file cannot be found in any target, make will find and compile source 58 | file named `foo.c` by default. 59 | 60 | In Rust in Kernel, `exports.o` and `helpers.o` are such type of generation. 61 | They are compiled from `exports.c` and `helpers.c` respectively via make's 62 | implicit rule. 63 | 64 | ## Objects generated from Rust 65 | 66 | Object files other than those generated from C source are compiled from Rust 67 | souce files. Currently, these object files are: `core.o`, `compiler_builtins.o`, 68 | `alloc.o`, `kernel.o`, `build_error.o`. Two files, `core.o` and `alloc.o` are 69 | compiled from Rust's source code, i.e. core and alloc components, and 70 | `compiler_builtins.o` is special for clang's codegen to mute some types of 71 | link error. 72 | 73 | These objects are directly linked into kernel's vmlinux image via Kbuild's 74 | `obj-$(CONFIG_RUST)` directives. 75 | 76 | It is important to note that these the size of these objects finally contributes 77 | to the total size of vmlinux image. So, for some space critical scenarios (for 78 | example, embedded devices), reduces the size of these object files is important. 79 | 80 | ## Extra Targets 81 | 82 | Extra targets are those needed for building vmlinux, but not combined into built-in.a. 83 | 84 | Usually, extra targets are head objects or vmlinux linker scripts. 85 | 86 | `exports_core_generated.h`, `libmacros.so`, `bindings_generated.rs`, 87 | `exports_alloc_generated.h`, `exports_kernel_generated.h`. 88 | 89 | # Build Kernel Module 90 | 91 | Like build normal C kernel modules, rust modules utilise symbols exported by 92 | kernel source. For rust, it is symbols that are exported by rust subsystem. 93 | 94 | [bindgen]: https://github.com/rust-lang/rust-bindgen 95 | [libclang]: https://clang.llvm.org/docs/Tooling.html#libclang 96 | 97 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/04-How_rust_code_utilises_kernel_interfaces.md: -------------------------------------------------------------------------------- 1 | # How rust code utilises Kernel's interfaces instead of standard library 2 | 3 | ## What is the difference between and kernel interfaces 4 | 5 | For normal userspace applications, Rust uses its standard library `libstd` which 6 | in turn utilises standard system calls or system interfaces provided by a 7 | specific OS. However, for circumstances that has no operation system backup, 8 | these standard interfaces is not accessible. Programming in Kernel is one of 9 | such situations in which Rust must be feed with a set of low leveled API for its 10 | functionality. Rust's `libcore` is a tiny, dependency-free library, on which 11 | `libstd` is built, which provides primitive blocks of all Rust code. `libcore` 12 | library links to no upstream libraries, no system libraries, and no libc at all. 13 | 14 | Currently, in Kernel, `libcore` for Rust is compiled from official's libcore 15 | source code. That is why we have to run `rustup component add rust-src` before 16 | any compilation. 17 | 18 | Other than `libcore`, `alloc` crate provides supports of basic data structures 19 | and memory allocation management. Rust benefits itself from this library for 20 | allocating memory directly from Kernel's `kalloc` interfaces. The familiar 21 | types, such as `rc`, `slice`, are exported from this `alloc` library. Rust's 22 | `libstd` re-exports these types in it to make `libstd` a concrete library. 23 | 24 | ## Build `libcore` and `alloc` in Kernel. 25 | 26 | For `core.o` and `alloc.o` targets: 27 | 28 | ``` 29 | .SECONDEXPANSION: 30 | $(objtree)/rust/core.o: private skip_clippy = 1 31 | $(objtree)/rust/core.o: $$(RUST_LIB_SRC)/core/src/lib.rs FORCE 32 | $(call if_changed_dep,rustc_library) 33 | ``` 34 | 35 | ``` 36 | $(objtree)/rust/alloc.o: private skip_clippy = 1 37 | $(objtree)/rust/alloc.o: $$(RUST_LIB_SRC)/alloc/src/lib.rs \ 38 | $(objtree)/rust/compiler_builtins.o FORCE 39 | $(call if_changed_dep,rustc_library) 40 | ``` 41 | 42 | The `$$(RUST_LIB_SRC)` is the location where Rust's lib source files residents. 43 | It was detected via these two commands: 44 | 45 | ``` 46 | rustc_sysroot = $(shell $(RUSTC) $(rustc_flags) --print sysroot) 47 | RUST_LIB_SRC ?= $(rustc_sysroot)/lib/rustlib/src/rust/library 48 | ``` 49 | 50 | ## compiler_builtins for Kernel 51 | 52 | Before we talk about compiler builtins, some basic knowledges of compiling Rust 53 | into object file are requisite. 54 | 55 | Rust is a front end of `llvm` and it depends on `llvm` for code generation. The 56 | front end is responsible for lexical analysis and parsing. It generates IR 57 | (Intermediate representation) and pass IR to `llvm` which converts IR to binary 58 | files for target architecture. So, basically and currently, architectures 59 | supported by Rust in kernel is largely constrained by the architectures 60 | supported by `llvm`. 61 | 62 | There is another term, `intrinsic function`, in `llvm` context. An intrinsic 63 | function is a function built in to the compiler. The compiler knows how to 64 | best implement the functionality in the most optimized way for these functions 65 | and replaces with a set of machine instruction for a particular backend. 66 | Simply, intrinsics are basic elementary functions for code generation in llvm 67 | for a specific architecture. 68 | 69 | `compiler-rt` is library that provides a set of intrinsic functions required 70 | by llvm's code generation and other runtime components. Rust provides 71 | `compiler_builtins` as a port of `compiler-rt`, and it provides necessary 72 | intrinsics for llvm as well. 73 | 74 | However, Rust's core library provides some floating-point functionalities which 75 | are useless for Linux kernel. But, due to Rust in kernel utilises the whole 76 | `libcore` and doesn't strip off these functions. Some floating-point relevant 77 | intrinsics are still need for code generation, even they are meaningless. 78 | 79 | That is why `compiler_builtins.rs` comes in. Rust in kernel uses this source 80 | file as a replacement of `compiler_builtins` to Rust's standard library. 81 | Useless intrinsics to kernel are defined int this file and implemented as 82 | `panic` which means any invocation of such a intrinsics will cause a kernel 83 | panic. 84 | 85 | Obviously, this implementation is crude, but is the fastest way. 86 | 87 | ## How Rust uses our libcore instead of libstd. 88 | 89 | It is all about `--extern` flag and symbols. 90 | 91 | `--extern` flag of `rustc` command specifies the location of an exteranl 92 | library. Indirect dependencies are located using the `-L` flag. `--extern` 93 | flag just makes rust compiler to link libraries that complement the missing 94 | symbols during linkage phase. During the runtime, symbol findings are 95 | automatically done by kernel itself. 96 | 97 | This flag also applies to buding out-tree modules. However, different from 98 | building Rust support in kernel itself, building an out-tree module needs to 99 | link `kernel` only. `kernel` in trun depends on `alloc` and `core` libraries 100 | we have discuessed before. 101 | 102 | 103 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/05-The_first_hello_world_module.md: -------------------------------------------------------------------------------- 1 | # Hello World Module 2 | 3 | We have learned enough for understanding the mechanism of how Rust works in 4 | the Linux Kernel. It is time to write our first hello world module which is 5 | powered by Rust. 6 | 7 | ## Code snippet 8 | 9 | The code is not very long, and is very concise. I paste the holistic Rust part 10 | in below: 11 | 12 | ```rust 13 | #![no_std] 14 | #![feature(allocator_api, global_asm)] 15 | 16 | use kernel::prelude::*; 17 | 18 | module! { 19 | type: HelloWorld, 20 | name: b"hello_world", 21 | author: b"d0u9", 22 | description: b"A simple hello world example", 23 | license: b"GPL v2", 24 | } 25 | 26 | struct HelloWorld; 27 | 28 | impl KernelModule for HelloWorld { 29 | fn init() -> Result { 30 | pr_info!("Hello world from rust!\n"); 31 | 32 | Ok(HelloWorld) 33 | } 34 | } 35 | 36 | impl Drop for HelloWorld { 37 | fn drop(&mut self) { 38 | pr_info!("Bye world from rust!\n"); 39 | } 40 | } 41 | ``` 42 | 43 | You can find the entire project in [eg_01_hello_world] directory in this repo. 44 | I omit the Makefile for building this module out of source tree. The Makefile 45 | is identical to its C counterpart. The Kbuild system takes care of every thing. 46 | 47 | To build this project, run this command: 48 | 49 | ``` 50 | LIBCLANG_PATH=/path/to/libclang make KERNELDIR=/rust/linux/kernel LLVM=1 modules 51 | ``` 52 | 53 | Again, the Linux Kernel must be compiled by clang and llvm beforehand instead of 54 | GCC for our Rust example. GCC maybe works, but not tested in my circumstance. 55 | 56 | `LIBCLANG_PATH` is an environment which points the `libclang` library. We have 57 | talked `libclang` in previous chapter. Its duty is making code generation for 58 | our target host. 59 | 60 | ## Notes on code 61 | 62 | If you are a rustacean, you will be very familiar with this code. However, for 63 | guys who has been a rustacean not very long, like me, I will pin some key points 64 | out to help people understanding this code. 65 | 66 | The first one worthy to mention is `#![no_std]` attribute which prevents Rust 67 | from using standard library. Standard library is of course not accessible from 68 | Kernel space. We have spent a lot words before to talk about this topic. 69 | `libcore` is a replacement (It seems word replacement is not very accurate) of 70 | `libstd` for Rust in situations that no standard library is available. 71 | `#![no_std]` attribute tells Rust compiler that this source file contains 72 | nothing from standard library and doesn't need it at all. It is very suitable 73 | for situations as development rust in the Kernel. 74 | 75 | `#![feature(allocator_api, global_asm)]` is a Rust's attribute used to enable 76 | unstable or experimental compiler features. A list of unstable features can 77 | be found here: https://doc.rust-lang.org/unstable-book/index.html 78 | 79 | `use kernel::prelude::*;` tells that use our own kernel crate. 80 | 81 | `module! {}` is a Rust's [Function-like macro]. We will expand this topic later. 82 | 83 | `struct HelloWorld;` is the body of our kernel module. 84 | 85 | `impl KernelModule for HelloWorld`: implement `KernelModule` trait on our own 86 | `HelloWorld` structure. This trait is the entrypoint of our kernel module. 87 | `KernelModule` trait contains an `init()` method which will be invoked during 88 | the loading process of our module. It behaves like C's `module_init()` function. 89 | 90 | `impl Drop for HelloWorld`: implement `Drop` trait on our own `HelloWorld` 91 | structure. `Drop` trait is a Rust's standard trait. Types with `Drop` trait 92 | implemented will be deconstructed when its lifetime ended via calling `drop()` 93 | method of `Drop` trait. `Drop` trait here almost an identical to C's 94 | `module_exit()` function. 95 | 96 | [eg_01_hello_world]: ../eg_01_hello_world 97 | [Function-like macro]: https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros 98 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/06-The_module_macro.md: -------------------------------------------------------------------------------- 1 | # The module macro 2 | 3 | Every (almost?) Rust driver starts by a macro `module! { }`. This is a 4 | [Function-like macro] that are invoked like a function call but suffixed with 5 | the macro invocation operator `!`. 6 | 7 | It is noticeable that macros in Rust is not identical to macros in C. For macros 8 | in C language, it works almost in a string substitution style. C's macros 9 | expands strings recursively. However, for Rust's macros, they are categorised 10 | into two types: declarative macros with `macro_rules!` and three kinds of 11 | procedural macros. For declarative macros, they are [hygienic macros]. For 12 | procedural macros, they are [not hygiene]. All in all, Rust's macros are 13 | string substitution. For our `module! {}` macro, a function-like macro, it is 14 | a procedural macro. 15 | 16 | ## A simple example of Rust function-like macro 17 | 18 | Due to the differences to traditional macros, it is good to illustrate the basic 19 | process of implementing Rust's function-like macro by an example. And, rust for 20 | kernel uses bare `rustc` compiler instead of `cargo`, it is a little bit complex 21 | to build and run such an example without `cargo`'s help. I will first build the 22 | example by `cargo` and then build it directly by `rustc`. 23 | 24 | ### With the help of Cargo 25 | 26 | Create a cargo package: 27 | 28 | ```bash 29 | cargo init my_macro 30 | ``` 31 | 32 | Append lines below to your `Cargo.toml` file: 33 | 34 | ```toml 35 | [[bin]] 36 | name = "my_bin" 37 | path = "src/main.rs" 38 | 39 | [lib] 40 | name = "my_macros" 41 | path = "src/lib/lib.rs" 42 | proc-macro = true 43 | ``` 44 | 45 | The line `proc-macro = true` is very important to our example. It says that 46 | our library has `proc-macro` macros. 47 | 48 | Crate `src/main.rs` source file: 49 | 50 | ```rust 51 | extern crate my_macros; 52 | use my_macros::answer_fn; 53 | 54 | answer_fn!(); 55 | 56 | fn main() { 57 | print!("This is my answer: {}\n", answer()); 58 | } 59 | ``` 60 | 61 | Create `src/lib/lib.rs` file: 62 | 63 | ```rust 64 | extern crate proc_macro; 65 | use proc_macro::TokenStream; 66 | 67 | #[proc_macro] 68 | pub fn answer_fn(_item: TokenStream) -> TokenStream { 69 | println!("This line is printed in macro"); 70 | " 71 | fn answer() -> u32 { 72 | let k = 1234; 73 | print!(\"The answer is: {}\n\", k); 74 | k 75 | } 76 | ".parse().unwrap() 77 | } 78 | ``` 79 | 80 | Run our example: 81 | 82 | ```bash 83 | Cargo run 84 | ``` 85 | 86 | The output is: 87 | 88 | ``` 89 | Compiling my_macro v0.1.0 (/tmp/my_macro) 90 | This line is printed in macro 91 | Finished dev [unoptimized + debuginfo] target(s) in 0.19s 92 | Running `target/debug/my_bin` 93 | The answer is: 1234 94 | This is my answer: 1234 95 | ``` 96 | 97 | Are you confused by the line `This line is printed in macro`? Would it be 98 | printed after the line `Running xxxx`? That is the key of macro. 99 | 100 | ### Use `rustc` directly 101 | 102 | For Rust in Kernel, we use bare `rustc` compiler instead of redundant `cargo` 103 | tool. 104 | 105 | For our example before, to compile it in an executable, compose a `Makefile`: 106 | 107 | ```makefile 108 | BUILD_DIR ?= $(shell mkdir -p build; echo build) 109 | BIN := my_bin 110 | BIN_SRC := src/main.rs 111 | MACRO_LIB := my_macros 112 | MACRO_LIB_FILE := $(addprefix lib,$(addsuffix .so,$(MACRO_LIB))) 113 | MACRO_SRC := src/lib/lib.rs 114 | MACRO_FLAGS := --emit=obj,link \ 115 | --extern proc_macro \ 116 | --crate-type proc-macro \ 117 | --crate-name $(MACRO_LIB) \ 118 | --out-dir $(BUILD_DIR) 119 | 120 | $(BUILD_DIR)/$(BIN): $(BIN_SRC) $(MACRO_LIB_FILE) 121 | rustc -o $@ --extern $(MACRO_LIB) -L $(BUILD_DIR) $< 122 | 123 | $(MACRO_LIB_FILE): $(MACRO_SRC) 124 | rustc $(MACRO_FLAGS) $^ 125 | 126 | .PHONY: clean 127 | clean: 128 | rm -fr $(BUILD_DIR) 129 | ``` 130 | 131 | The Makefile makes compiling procedure more clearly than cargo which has an 132 | simple one-shot operation. The compiling process contains two phases: 1) build 133 | macro_proc library; 2) build our executable binary. 134 | 135 | The proc_macro is special, that all proc_macros are compiled into a dynamic 136 | libraries and then is feed to rustc compiler. The string "This line is printed 137 | in macro" is printed in our macro_proc function during the compiling time. This 138 | means macro_proc functions are invoked by compiler other than our code. 139 | 140 | ## Real module macro 141 | 142 | We have understanded what is a Rust's procedural macro and how it is expaned 143 | by an example. It is time to play around with real module macro. 144 | 145 | For writing kernel modules in C, it always starts with two functions(they are 146 | actually C macros), `module_init()` and `module_exit()`, and some auxiliary 147 | macros, e.g. `MODULE_LICENSE()`, `MODULE_AUTHOR()`, `MODULE_DESCRIPTION()`. 148 | 149 | For kernel modules in Rust, a macro named `module!{ }` is used to describe 150 | the behavior what our module will have. 151 | 152 | ```rust 153 | module! { 154 | type: RustModuleParameters, 155 | name: b"rust_module_parameters", 156 | author: b"Rust for Linux Contributors", 157 | description: b"Rust module parameters sample", 158 | license: b"GPL v2", 159 | params: { 160 | my_bool: bool { 161 | default: true, 162 | permissions: 0, 163 | description: b"Example of bool", 164 | }, 165 | my_i32: i32 { 166 | default: 42, 167 | permissions: 0o644, 168 | description: b"Example of i32", 169 | }, 170 | }, 171 | } 172 | ``` 173 | 174 | This macro will be expanded during compiling time. For curious readers who 175 | wonder what is the results of output, it is convenient to use rustc's 176 | `--pretty=expanded` option to inspect. `--pretty=expanded` is an option that is 177 | only available when `-Zunstable-options` is also enabled. 178 | 179 | The generated content after macro expansion looks like: 180 | 181 | ```rust 182 | /// The module name. 183 | /// 184 | /// Used by the printing macros, e.g. [`info!`]. 185 | const __LOG_PREFIX: &[u8] = b"test_module\0"; 186 | static mut __MOD: Option = None; 187 | #[cfg(MODULE)] 188 | static THIS_MODULE: kernel::ThisModule = 189 | unsafe { kernel::ThisModule::from_ptr(&kernel::bindings::__this_module as *const _ as *mut _) }; 190 | #[cfg(MODULE)] 191 | #[no_mangle] 192 | pub extern "C" fn init_module() -> kernel::c_types::c_int { 193 | __init() 194 | } 195 | #[cfg(MODULE)] 196 | #[no_mangle] 197 | pub extern "C" fn cleanup_module() { 198 | __exit() 199 | } 200 | fn __init() -> kernel::c_types::c_int { 201 | match ::init() { 202 | Ok(m) => { 203 | unsafe { 204 | __MOD = Some(m); 205 | } 206 | return 0; 207 | } 208 | Err(e) => { 209 | return e.to_kernel_errno(); 210 | } 211 | } 212 | } 213 | fn __exit() { 214 | unsafe { 215 | __MOD = None; 216 | } 217 | } 218 | #[cfg(MODULE)] 219 | #[link_section = ".modinfo"] 220 | #[used] 221 | pub static __test_module_author: [u8; 35] = *b"author=Rust for Linux Contributors\0"; 222 | #[cfg(MODULE)] 223 | #[link_section = ".modinfo"] 224 | #[used] 225 | pub static __test_module_description: [u8; 42] = *b"description=Rust module parameters sample\0"; 226 | #[cfg(MODULE)] 227 | #[link_section = ".modinfo"] 228 | #[used] 229 | pub static __test_module_license: [u8; 15] = *b"license=GPL v2\0"; 230 | #[cfg(MODULE)] 231 | #[link_section = ".modinfo"] 232 | #[used] 233 | pub static __test_module_parmtype_my_bool: [u8; 22] = *b"parmtype=my_bool:bool\0"; 234 | #[cfg(MODULE)] 235 | #[link_section = ".modinfo"] 236 | #[used] 237 | pub static __test_module_parm_my_bool: [u8; 29] = *b"parm=my_bool:Example of bool\0"; 238 | static mut __test_module_my_bool_value: bool = true; 239 | struct __test_module_my_bool; 240 | impl __test_module_my_bool { 241 | fn read(&self) -> &::Value { 242 | unsafe { ::value(&__test_module_my_bool_value) } 243 | } 244 | } 245 | const my_bool: __test_module_my_bool = __test_module_my_bool; 246 | #[repr(transparent)] 247 | struct __test_module_my_bool_RacyKernelParam(kernel::bindings::kernel_param); 248 | unsafe impl Sync for __test_module_my_bool_RacyKernelParam {} 249 | #[cfg(MODULE)] 250 | const __test_module_my_bool_name: *const kernel::c_types::c_char = 251 | b"my_bool\0" as *const _ as *const kernel::c_types::c_char; 252 | #[link_section = "__param"] 253 | #[used] 254 | static __test_module_my_bool_struct: __test_module_my_bool_RacyKernelParam = 255 | __test_module_my_bool_RacyKernelParam(kernel::bindings::kernel_param { 256 | name: __test_module_my_bool_name, 257 | 258 | #[cfg(MODULE)] 259 | mod_: unsafe { &kernel::bindings::__this_module as *const _ as *mut _ }, 260 | ops: unsafe { &kernel::module_param::PARAM_OPS_BOOL } 261 | as *const kernel::bindings::kernel_param_ops, 262 | perm: 0, 263 | level: -1, 264 | flags: 0, 265 | __bindgen_anon_1: kernel::bindings::kernel_param__bindgen_ty_1 { 266 | arg: unsafe { &__test_module_my_bool_value } as *const _ 267 | as *mut kernel::c_types::c_void, 268 | }, 269 | }); 270 | #[cfg(MODULE)] 271 | #[link_section = ".modinfo"] 272 | #[used] 273 | pub static __test_module_parmtype_my_i32: [u8; 20] = *b"parmtype=my_i32:i32\0"; 274 | #[cfg(MODULE)] 275 | #[link_section = ".modinfo"] 276 | #[used] 277 | pub static __test_module_parm_my_i32: [u8; 27] = *b"parm=my_i32:Example of i32\0"; 278 | static mut __test_module_my_i32_value: i32 = 267390960; 279 | struct __test_module_my_i32; 280 | impl __test_module_my_i32 { 281 | fn read<'lck>( 282 | &self, 283 | lock: &'lck kernel::KParamGuard, 284 | ) -> &'lck ::Value { 285 | unsafe { ::value(&__test_module_my_i32_value) } 286 | } 287 | } 288 | const my_i32: __test_module_my_i32 = __test_module_my_i32; 289 | #[repr(transparent)] 290 | struct __test_module_my_i32_RacyKernelParam(kernel::bindings::kernel_param); 291 | unsafe impl Sync for __test_module_my_i32_RacyKernelParam {} 292 | #[cfg(MODULE)] 293 | const __test_module_my_i32_name: *const kernel::c_types::c_char = 294 | b"my_i32\0" as *const _ as *const kernel::c_types::c_char; 295 | #[link_section = "__param"] 296 | #[used] 297 | static __test_module_my_i32_struct: __test_module_my_i32_RacyKernelParam = 298 | __test_module_my_i32_RacyKernelParam(kernel::bindings::kernel_param { 299 | name: __test_module_my_i32_name, 300 | 301 | #[cfg(MODULE)] 302 | mod_: unsafe { &kernel::bindings::__this_module as *const _ as *mut _ }, 303 | ops: unsafe { &kernel::module_param::PARAM_OPS_I32 } 304 | as *const kernel::bindings::kernel_param_ops, 305 | perm: 0o644, 306 | level: -1, 307 | flags: 0, 308 | __bindgen_anon_1: kernel::bindings::kernel_param__bindgen_ty_1 { 309 | arg: unsafe { &__test_module_my_i32_value } as *const _ as *mut kernel::c_types::c_void, 310 | }, 311 | }); 312 | ``` 313 | 314 | This is a very long code. I will detail this in next article. 315 | 316 | [Function-like macro]: https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros 317 | [hygienic macros]: https://en.wikipedia.org/wiki/Hygienic_macro 318 | [not hygiene]: https://doc.rust-lang.org/reference/procedural-macros.html#procedural-macro-hygiene 319 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/07_module_init_and_exit.md: -------------------------------------------------------------------------------- 1 | # Module Init and Exit 2 | 3 | ## An exmaple of C module 4 | 5 | For C module, it has a skeleton like: 6 | 7 | ```C 8 | #include 9 | #include 10 | 11 | static u32 uint_param = 1; 12 | module_param(uint_param, uint, S_IRUGO); 13 | 14 | struct example_module { 15 | u32 version; 16 | }; 17 | static struct example_module module_struct; 18 | 19 | static int __init m_init(void) 20 | { 21 | module_struct.version = uint_param; 22 | pr_info("Hello World! uint_param=%u\n", module_struct.version); 23 | pr_info("Address of module parameter uint_param: %px\n", &uint_param); 24 | return 0; 25 | } 26 | 27 | static void __exit m_exit(void) 28 | { 29 | pr_info("Bye World!\n"); 30 | } 31 | 32 | module_init(m_init); 33 | module_exit(m_exit); 34 | 35 | MODULE_LICENSE("GPL"); 36 | MODULE_AUTHOR("Douglas Su"); 37 | MODULE_DESCRIPTION("An example module"); 38 | ``` 39 | 40 | ## Rewrite C module in Rust 41 | 42 | Our C module has a structure named `exmaple_module`, which describes our module. 43 | Single field, `version`, in `struct exmaple_module` has a type of `int` and 44 | records the current version of our module. To rewrite this part in Rust, we 45 | declare a Rust structure with an int `version` member which is identical to 46 | C's counterpart: 47 | 48 | ```rust 49 | struct ExampleModule { 50 | version: u32, 51 | } 52 | ``` 53 | 54 | Next, we need to mimic the ability of `module_init()` function. This is 55 | implemented via a member function `init()`: 56 | 57 | ```rust 58 | impl KernelModule for ExampleModule { 59 | fn init() -> Result { 60 | let lock = THIS_MODULE.kernel_param_lock(); 61 | let module = ExampleModule { version: *uint_param.read(&lock) }; 62 | 63 | pr_info!("Hello World! uint_prarm={}\n", module.version); 64 | Ok(module) 65 | } 66 | } 67 | ``` 68 | 69 | `module_exit()` is replaced by `Drop` trait: 70 | 71 | ```rust 72 | impl Drop for ExampleModule { 73 | fn drop(&mut self) { 74 | pr_info!("Bye World\n"); 75 | } 76 | } 77 | ``` 78 | 79 | ## Author, Description, License and etc. 80 | 81 | All of these macros listed below are now members of `module!{ }` macro: 82 | 83 | ```c 84 | MODULE_LICENSE("GPL"); 85 | MODULE_AUTHOR("Douglas Su"); 86 | MODULE_DESCRIPTION("An example module"); 87 | ``` 88 | 89 | In Rust: 90 | 91 | ```rust 92 | module! { 93 | type: ExampleModule, 94 | name: b"example_module", 95 | author: b"Douglas Su", 96 | description: b"An example module", 97 | license: b"GPL v2", 98 | params: { 99 | uint_param: u32 { 100 | default: 1, 101 | permissions: 0o644, 102 | description: b"uint parameter", 103 | }, 104 | }, 105 | } 106 | ``` 107 | 108 | ## Make our `struct ExampleModule` be the module entry point 109 | 110 | Just assign structure name to type field in `module!{ }` macro. 111 | 112 | ```rust 113 | module! { 114 | type: ExampleModule, 115 | ... 116 | } 117 | ``` 118 | 119 | ## The whole rust code 120 | 121 | ```rust 122 | #![no_std] 123 | #![feature(allocator_api, global_asm)] 124 | 125 | use kernel::prelude::*; 126 | 127 | module! { 128 | type: ExampleModule, 129 | name: b"example_module", 130 | author: b"Douglas Su", 131 | description: b"An example module", 132 | license: b"GPL v2", 133 | params: { 134 | uint_param: u32 { 135 | default: 1, 136 | permissions: 0o644, 137 | description: b"uint parameter", 138 | }, 139 | }, 140 | } 141 | 142 | struct ExampleModule { 143 | version: u32, 144 | } 145 | 146 | impl KernelModule for ExampleModule { 147 | fn init() -> Result { 148 | let lock = THIS_MODULE.kernel_param_lock(); 149 | let module = ExampleModule { version: *uint_param.read(&lock) }; 150 | 151 | pr_info!("Hello World! uint_prarm={}\n", module.version); 152 | Ok(module) 153 | } 154 | } 155 | 156 | impl Drop for ExampleModule { 157 | fn drop(&mut self) { 158 | pr_info!("Bye World\n"); 159 | } 160 | } 161 | ``` 162 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/08_how_is_module_loaded_into_kernel.md: -------------------------------------------------------------------------------- 1 | # How is module loaded into kernel 2 | 3 | ## Procedures to load and execute a .ko file 4 | 5 | Module file for Linux kernel is an `ELF` file. `ELF` is an abbreviation of 6 | Executable Linkable Format. It is the standard format which is used by 7 | executable binary file and dynamic library file as well as kernel module file. 8 | Actually, loading an kernel module file into kernel almost the same as load an 9 | dynamic library file in user space. 10 | 11 | The whole process can be divided into several steps: 12 | 13 | 1. Copy file from user space to kernel space; 14 | 2. Verification. 15 | 3. Parsing file; 16 | 4. Relocating symbols; 17 | 5. Set module parameters; 18 | 6. Execution. 19 | 20 | ## Copy file from user space to kernel space 21 | 22 | Loading from user space is implemented via a specific system call [init_module]. 23 | This system call takes three paramters: 1. The buffer in which ko file fills; 2. 24 | The size of buffer; 3, a parameter string. 25 | 26 | This system call is defined in file [kernel/module.c], and it is defined as: 27 | 28 | ```c 29 | SYSCALL_DEFINE3(init_module, void __user *, umod, 30 | unsigned long, len, const char __user *, uargs) 31 | ``` 32 | 33 | This function does nothing but checks invoker's capability and copies content 34 | from user space to kernel space. User who invokes this system call must have the 35 | capability of `CAP_SYS_MODULE`. 36 | 37 | Then, calls `load_module()` function which does the heavy duties. 38 | 39 | ## Module verification 40 | 41 | `load_module()` function is defined in [kernel/module.c] as well. It is a long 42 | function that does the actual work to load and run a kernel module. At the 43 | very beginning of this function, some verifications are taken to make sure that 44 | the module will be loaded is valid and matches our kernel version. 45 | 46 | ```c 47 | /* 48 | * Do the signature check (if any) first. All that 49 | * the signature check needs is info->len, it does 50 | * not need any of the section info. That can be 51 | * set up later. This will minimize the chances 52 | * of a corrupt module causing problems before 53 | * we even get to the signature check. 54 | * 55 | * The check will also adjust info->len by stripping 56 | * off the sig length at the end of the module, making 57 | * checks against info->len more correct. 58 | */ 59 | err = module_sig_check(info, flags); 60 | if (err) 61 | goto free_copy; 62 | 63 | /* 64 | * Do basic sanity checks against the ELF header and 65 | * sections. 66 | */ 67 | err = elf_validity_check(info); 68 | if (err) { 69 | pr_err("Module has invalid ELF structures\n"); 70 | goto free_copy; 71 | } 72 | ``` 73 | 74 | ## Parsing module file 75 | 76 | The parsing procedure breaks module elf file into data structures. For module 77 | elf file, there are four sections worthy to mention. 78 | 79 | 1. `.modinfo` section; 80 | 2. `__param` section; 81 | 3. `.rela__param` section; 82 | 4. `.symtab` section. 83 | 84 | The `.modinfo` sections contains basic information about this module. For 85 | example, module description, module parameters, module author, etc. 86 | 87 | The `__param` section contains module parameter structures which will be 88 | initialized after relocating. 89 | 90 | The `.rela_param` section contains relocation information for kernel parameters. 91 | 92 | The `.symtab` section contains symbol table with information about functions and 93 | global variables that are defined and referenced in the program. 94 | 95 | To see what sections are contained in an ELF file, use `readelf` command: 96 | 97 | ``` 98 | readelf -S test_module.ko 99 | ``` 100 | 101 | The function `setup_load_info()` defined in [kernel/module.c] reads module file 102 | and fill some fields of `struct load_info *info` according to module file. The 103 | field `hdr` is special for that this field points to the buffer in which module 104 | file residents. This field is assigned in `copy_module_from_user()` function: 105 | 106 | ```c 107 | info->hdr = __vmalloc(info->len, GFP_KERNEL | __GFP_NOWARN); 108 | if (!info->hdr) 109 | return -ENOMEM; 110 | 111 | if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) { 112 | err = -EFAULT; 113 | goto out; 114 | } 115 | ``` 116 | 117 | For X86_64, `info->hdr` has the type of `Elf64_Ehdr`, defined in 118 | [include/uapi/linux/elf.h]. For folks who familiar with ELF file format, it is 119 | easy to find that `Elf64_Ehdr` structure actually describes the [ELF] header. 120 | 121 | The parsing process is tedious and rigmarole, and most operations are not 122 | relevant to our topic. But for a better understand of reading module info and 123 | setting up module parameter, I will detail some interested procedures. 124 | 125 | ### Get module info 126 | 127 | Module informations include module name, license, author, parameter type, 128 | parameter description, etc. These informations are packed in `.modinfo` section 129 | in ELF file(module file). 130 | 131 | To read `.modinfo` section, first we need to find the index of section. Use 132 | function `find_sec()` to get the index of a specific section with section name: 133 | 134 | ``` 135 | info->index.info = find_sec(info, ".modinfo"); 136 | ``` 137 | 138 | Then obtain a specific field in `.modinfo` section by invoking `get_modinfo()`: 139 | 140 | ``` 141 | info->name = get_modinfo(info, "name"); 142 | ``` 143 | 144 | For users who curious about the content of `.modinfo` section, use `readelf` 145 | command to inspect: 146 | 147 | ``` 148 | readelf -x .modinfo test_module.ko 149 | 150 | Hex dump of section '.modinfo': 151 | 0x00000000 7061726d 74797065 3d75696e 745f7061 parmtype=uint_pa 152 | 0x00000010 72616d3a 75696e74 006c6963 656e7365 ram:uint.license 153 | 0x00000020 3d47504c 00617574 686f723d 446f7567 =GPL.author=Doug 154 | 0x00000030 6c617320 53750064 65736372 69707469 las Su.descripti 155 | 0x00000040 6f6e3d41 6e206578 616d706c 65206d6f on=An example mo 156 | 0x00000050 64756c65 00766572 6d616769 633d352e dule.vermagic=5. 157 | 0x00000060 31322e30 2d726334 2b20534d 50206d6f 12.0-rc4+ SMP mo 158 | 0x00000070 645f756e 6c6f6164 20006e61 6d653d74 d_unload .name=t 159 | 0x00000080 6573745f 6d6f6475 6c650072 6574706f est_module.retpo 160 | 0x00000090 6c696e65 3d590064 6570656e 64733d00 line=Y.depends=. 161 | ``` 162 | 163 | Also, use `-p` option instead of `-x` option to get result in string. 164 | 165 | ``` 166 | readelf -p .modinfo test_module.ko 167 | 168 | String dump of section '.modinfo': 169 | [ 0] parmtype=uint_param:uint 170 | [ 19] license=GPL 171 | [ 25] author=Douglas Su 172 | [ 37] description=An example module 173 | [ 55] vermagic=5.12.0-rc4+ SMP mod_unload 174 | [ 7a] name=test_module 175 | [ 8b] retpoline=Y 176 | [ 97] depends= 177 | ``` 178 | 179 | `get_modinfo()` function parses these `\0` separated strings, and get target 180 | value string by key. 181 | 182 | ### Get `__param` section 183 | 184 | `struct module` is the data structure that describes the module currently 185 | processing. some fields are points to elf sections. For example, `mod->kp` filed 186 | points to the `__param` section in ELF file. 187 | 188 | `__param` section in ELF is an empty table which will be filled during 189 | relocating. So, Reading to this sections from ELF file by `readelf` returns 190 | almost nothing: 191 | 192 | ``` 193 | readelf -x __param test_module.ko 194 | 195 | Hex dump of section '__param': 196 | NOTE: This section has relocations against it, but these have NOT been applied to this dump. 197 | 0x00000000 00000000 00000000 00000000 00000000 ................ 198 | 0x00000010 00000000 00000000 2401ff00 00000000 ........$....... 199 | 0x00000020 00000000 00000000 ........ 200 | 201 | ``` 202 | 203 | ## Parameter parsing and rewriting. 204 | 205 | ### Define module parameter 206 | 207 | To define an `u32` type module parameter: 208 | 209 | ```c 210 | static u32 uint_param = 1; 211 | module_param(uint_param, uint, S_IRUGO); 212 | ``` 213 | 214 | The first line syas we defined a global variable of type `u32` and initialized 215 | its value to `1`. 216 | 217 | The second line is a macro to declare a module paramter. The macro defined as 218 | below recursively. 219 | 220 | ```c 221 | // file: include/linux/moduleparam.h 222 | 223 | #define module_param(name, type, perm) \ 224 | module_param_named(name, name, type, perm) 225 | 226 | #define module_param_named(name, value, type, perm) \ 227 | param_check_##type(name, &(value)); \ 228 | module_param_cb(name, ¶m_ops_##type, &value, perm); \ 229 | __MODULE_PARM_TYPE(name, #type) 230 | 231 | #define param_check_uint(name, p) __param_check(name, p, unsigned int) 232 | 233 | #define __param_check(name, p, type) \ 234 | static inline type __always_unused *__check_##name(void) { return(p); } 235 | 236 | #define module_param_cb(name, ops, arg, perm) \ 237 | __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0) 238 | 239 | #define __module_param_call(prefix, name, ops, arg, perm, level, flags) \ 240 | static const char __param_str_##name[] = prefix #name; \ 241 | static struct kernel_param __moduleparam_const __param_##name \ 242 | __used __section("__param") \ 243 | __aligned(__alignof__(struct kernel_param)) \ 244 | = { __param_str_##name, THIS_MODULE, ops, \ 245 | VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } } 246 | 247 | #define __MODULE_INFO(tag, name, info) \ 248 | static const char __UNIQUE_ID(name)[] \ 249 | __used __section(".modinfo") __aligned(1) \ 250 | = __MODULE_INFO_PREFIX __stringify(tag) "=" info 251 | 252 | #define __MODULE_PARM_TYPE(name, _type) \ 253 | __MODULE_INFO(parmtype, name##type, #name ":" _type) 254 | ``` 255 | 256 | 257 | For our example, `module_param(uint_param, uint, S_IRUGO)`, it is finally 258 | expanded as (I have removed some GCC attributes which are unnecessary for us 259 | to understand the mechanisim): 260 | 261 | ```c 262 | static const char __param_str_uint_param[] = "uint_param"; 263 | 264 | static struct kernel_param const __param_uint_param __attribute__((__section__("__param"))) = { 265 | __param_str_uint_param, 266 | (&__this_module), 267 | ¶m_ops_uint, 268 | S_IRUGO, 269 | -1, 270 | 0, 271 | { &uint_param } 272 | }; 273 | 274 | static const char __UNIQUE_ID_uint_paramtye[] __attribute__((__section__(".modinfo"))) = "parmtype" "=" "uint_param" ":" "uint"; 275 | ``` 276 | 277 | This macro is expanded into three variable definitions. 278 | 279 | The first variable, `__param_str_uint_param` is an array of chars in which our 280 | parameter name is written in. For C language, this char array is placed in 281 | `rodata` section of ELF file. 282 | 283 | ``` 284 | readelf -s test_module.ko 285 | 286 | Symbol table '.symtab' contains 34 entries: 287 | Num: Value Size Type Bind Vis Ndx Name 288 | 3: 0000000000000000 11 OBJECT LOCAL DEFAULT 7 __param_str_uint_param 289 | 4: 0000000000000000 40 OBJECT LOCAL DEFAULT 8 __param_uint_param 290 | 5: 0000000000000000 25 OBJECT LOCAL DEFAULT 10 __UNIQUE_ID_uint_paramtyp 291 | ``` 292 | 293 | ``` 294 | readelf -S test_module.ko 295 | There are 24 section headers, starting at offset 0xc38: 296 | 297 | Section Headers: 298 | [Nr] Name Type Address Offset 299 | Size EntSize Flags Link Info Align 300 | [ 7] .rodata PROGBITS 0000000000000000 0000005c 301 | 000000000000000b 0000000000000000 A 0 0 1 302 | [ 8] __param PROGBITS 0000000000000000 00000068 303 | 0000000000000028 0000000000000000 A 0 0 8 304 | [ 9] .rela__param RELA 0000000000000000 00000530 305 | 0000000000000060 0000000000000018 I 21 8 8 306 | [10] .modinfo PROGBITS 0000000000000000 00000090 307 | 00000000000000a0 0000000000000000 A 0 0 1 308 | ``` 309 | 310 | As you can see from the dump information above, symbol `__param_str_uint_param` 311 | points to section 7 which is `.rodata` section. 312 | 313 | The second variable, `__param_uint_param`, has a type of `kernel_param` which 314 | is defined as: 315 | 316 | ```c 317 | struct kernel_param { 318 | const char *name; 319 | struct module *mod; 320 | const struct kernel_param_ops *ops; 321 | const u16 perm; 322 | s8 level; 323 | u8 flags; 324 | union { 325 | void *arg; 326 | const struct kparam_string *str; 327 | const struct kparam_array *arr; 328 | }; 329 | }; 330 | ``` 331 | 332 | The `name` field is a pointer to `const char` which is initialized to 333 | `__param_str_uint_param`; The `perm` field is assigned as `S_IRUGO`; The `arg` 334 | pointer in union is initialized to the address of our `uint_param` global 335 | variable; The `ops` filed has type of `struct kernel_param_ops` in which three 336 | pointers to functions are included. 337 | 338 | ```c 339 | struct kernel_param_ops { 340 | unsigned int flags; 341 | int (*set)(const char *val, const struct kernel_param *kp); 342 | int (*get)(char *buffer, const struct kernel_param *kp); 343 | void (*free)(void *arg); 344 | }; 345 | ``` 346 | 347 | The `set` and `get` functions are used to set and get our variable values. 348 | For our module parameter, the `ops` filed points to a pre-defined function 349 | in kernel, `param_ops_uint`. 350 | 351 | ```c 352 | // file: kernel/params.c 353 | #define STANDARD_PARAM_DEF(name, type, format, strtolfn) \ 354 | int param_set_##name(const char *val, const struct kernel_param *kp) \ 355 | { \ 356 | return strtolfn(val, 0, (type *)kp->arg); \ 357 | } \ 358 | int param_get_##name(char *buffer, const struct kernel_param *kp) \ 359 | { \ 360 | return scnprintf(buffer, PAGE_SIZE, format "\n", \ 361 | *((type *)kp->arg)); \ 362 | } \ 363 | const struct kernel_param_ops param_ops_##name = { \ 364 | .set = param_set_##name, \ 365 | .get = param_get_##name, \ 366 | }; \ 367 | EXPORT_SYMBOL(param_set_##name); \ 368 | EXPORT_SYMBOL(param_get_##name); \ 369 | EXPORT_SYMBOL(param_ops_##name) 370 | 371 | STANDARD_PARAM_DEF(uint, unsigned int, "%u", kstrtouint); 372 | ``` 373 | 374 | Expanded to: 375 | 376 | ```c 377 | int param_set_uint(const char *val, const struct kernel_param *kp) 378 | { 379 | return strtolfn(val, 0, (type *)kp->arg); 380 | } 381 | 382 | int param_get_uint(char *buffer, const struct kernel_param *kp) 383 | { 384 | return scnprintf(buffer, PAGE_SIZE, format "\n", 385 | *((type *)kp->arg)); 386 | } 387 | const struct kernel_param_ops param_ops_uint = { 388 | .set = param_set_uint, 389 | .get = param_get_uint, 390 | }; 391 | EXPORT_SYMBOL(param_set_uint); 392 | EXPORT_SYMBOL(param_get_uint); 393 | EXPORT_SYMBOL(param_ops_uint); 394 | ``` 395 | 396 | Also, the `__param_uint_param` variable is decorated with 397 | `__attribute__((__section__("__param")))` attribute which tells GCC or clang to 398 | put this variable in `__param` section. However, due to the relocating, the 399 | final `__param` section in ELF file doesn't contain these structures. They 400 | are placed in `.rela__param` section, and are copied to `__param` section during 401 | relocating process. 402 | 403 | For people who is not familiar with relocating, I suggest to read the chapter 7 404 | of book "Computer Systems: A programmer's Perspective". 405 | 406 | The third variable `__UNIQUE_ID_uint_paramtye` is also a array of chars in 407 | which a special string "parmtype=uint_param:uint" is written in. This variable 408 | is linked into `modiinfo` section and be used by tools such as `modinfo` to 409 | fetch information about this module. 410 | 411 | ### Apply relocation 412 | 413 | `apply_relocate()` function is responsible for applying relocation to our 414 | kernel module. We primarily focus on relocation of `__param` section in ELF 415 | file. This sections contains data structures which describes the parameters 416 | a kernel have. 417 | 418 | Hex data dumped below are what content in `__param` section before and after 419 | relocation is taken in action. These data is directly printed in kernel log 420 | by hacking kernel. 421 | 422 | ``` 423 | before: (____ptrval____): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 424 | before: (____ptrval____): 00 00 00 00 00 00 00 00 24 01 ff 00 00 00 00 00 ........$....... 425 | before: (____ptrval____): 00 00 00 00 00 00 00 00 ........ 426 | ``` 427 | 428 | ``` 429 | after: (____ptrval____): 00 50 33 c0 ff ff ff ff 40 60 33 c0 ff ff ff ff .P3.....@`3..... 430 | after: (____ptrval____): 60 c2 80 85 ff ff ff ff 24 01 ff 00 00 00 00 00 `.......$....... 431 | after: (____ptrval____): 00 60 33 c0 ff ff ff ff .`3..... 432 | ``` 433 | 434 | For our example, `__param` section only contains single `struct kernel_param` 435 | data structure describes `static u32 uint_param` parameter. The last field of 436 | `struct kernel_param` an union type. Our `static u32 uint_param` parameter 437 | fits in the void `*arg` type option. 438 | ```c 439 | union { 440 | void *arg; 441 | const struct kparam_string *str; 442 | const struct kparam_array *arr; 443 | }; 444 | ``` 445 | 446 | It has the value `0xffffffc0336000`, i.e. the address of kernel parameter. This 447 | is verified by looking the kernel log that we print this address by `pr_info()` 448 | function in our code. 449 | 450 | ``` 451 | Hello World! uint_param=1 452 | Address of module parameter uint_param: ffffffffc0336000 453 | ``` 454 | 455 | Also, it is not hard to find the address of `param_set_uint()` by decoding this 456 | binary according to `struct kernel_param_ops`. The address `0xffffffff8200c260` 457 | points the `struct kernel_param_ops` structure. Grep this address in kernel's 458 | symbol table file (System.map file in the root of your kernel source, it will 459 | be generated after successfully compiling kernel module). 460 | 461 | ``` 462 | grep param_ops_uint System.map 463 | 464 | ffffffff8200c260 D param_ops_uint 465 | ``` 466 | 467 | Note: You may find that the address printed in kernel log and obtained from 468 | System.map file are mismatched. This is due to `KASLR` (Kernel address space 469 | layout randomization), and you can disable `KASLR` by appending `nokaslr` 470 | kernel parameter. For QEMU users, add this in your `-append` option. 471 | 472 | ### Parsing parameters passed in via `init_module()` system call 473 | 474 | First copy parameter string from user space to kernel: 475 | 476 | ```c 477 | mod->args = strndup_user(uargs, ~0UL >> 1); 478 | if (IS_ERR(mod->args)) { 479 | err = PTR_ERR(mod->args); 480 | goto free_arch_cleanup; 481 | } 482 | ``` 483 | 484 | Then parsing it in function `parse_args()`: 485 | 486 | ```c 487 | after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, 488 | -32768, 32767, mod, 489 | unknown_module_param_cb); 490 | ``` 491 | 492 | In turn, it calls `parse_one()` function for parsing single parameter: 493 | 494 | ```c 495 | ret = parse_one(param, val, doing, params, num, 496 | min_level, max_level, arg, unknown); 497 | ``` 498 | 499 | For each parameter passed in, first compare the parameter name against paramters 500 | in `__param` (Note: params[] is an array of type `struct kernel_param` which 501 | is read directly from `__param` section after relocation). Then, after some 502 | checks, set the variable value by calling `set()` function on it. 503 | 504 | For our `uint` type parameter, this is done via `strtolfn()` function actually. 505 | 506 | ```c 507 | if (parameq(param, params[i].name)) { 508 | ... 509 | if (param_check_unsafe(¶ms[i])) 510 | err = params[i].ops->set(val, ¶ms[i]); 511 | ... 512 | } 513 | ``` 514 | 515 | ## `init` and `exit` function 516 | 517 | Modules' entry and exit function are defined via macro `module_init()` and 518 | macro `module_exit()`. 519 | 520 | For example: 521 | 522 | ``` 523 | module_init(m_init); 524 | module_exit(m_exit); 525 | ``` 526 | 527 | `m_init()` and `m_exit()` are two functions defined by user. Function declared 528 | in `module_init()`, i.e. `m_init()` in our example, is an entry point function 529 | which acts like `main()` function of our module and be called firstly when 530 | module is loaded. Function declared in `module_exit()` macro, `m_exit()` in our 531 | example, acts like a deconstructive usually in which some clean up works were 532 | taken. 533 | 534 | These two macros are expanded to: 535 | 536 | ```c 537 | static inline \ 538 | initcall_t __inittest(void) 539 | { 540 | return m_init; 541 | } 542 | int init_module(void) __attribute__((alias("m_init")));; 543 | 544 | static inline 545 | exitcall_t __exittest(void) 546 | { 547 | return m_exit; 548 | } 549 | void cleanup_module(void) __attribute__((alias("m_exit")));; 550 | ``` 551 | 552 | I have removed GCC's attributes to make codes more concise. 553 | 554 | `initcall_t` and `exitcall_t` are types defined as: 555 | 556 | ```c 557 | typedef int (*initcall_t)(void); 558 | typedef void (*exitcall_t)(void); 559 | ``` 560 | 561 | `__inittest()` and `__exittest()` functions are test functions which verify 562 | the if the functions passed in macro matches the signature. 563 | 564 | The next two lines: 565 | 566 | ```c 567 | int init_module(void) __attribute__((alias("m_init")));; 568 | void cleanup_module(void) __attribute__((alias("m_exit")));; 569 | ``` 570 | 571 | A special [alias attribute] `__attribute__((alias()));` is used. This attribute 572 | defines `m_init` to be a weak alias for `init_module` and `m_exit` to be a weak 573 | alias for `cleanup_module` symbol. 574 | 575 | ## `init` and `exit` fields in `struct module` 576 | 577 | `struct module` contains two pointers, `int (*init)(void)` and 578 | `void (*exit)(void)`, which point to initialization and exit functions 579 | respectively. 580 | 581 | These two pointers are initialized in function `layout_and_allocate()` as: 582 | 583 | ```c 584 | /* Module has been copied to its final place now: return it. */ 585 | mod = (void *)info->sechdrs[info->index.mod].sh_addr; 586 | ``` 587 | 588 | The `info->sechdrs[]` is an array of ELF section headers. The section index 589 | we referenced here is `info->index.mod` which is assigned in `setup_load_info()` 590 | function: 591 | 592 | ```c 593 | info->index.mod = find_sec(info, ".gnu.linkonce.this_module"); 594 | if (!info->index.mod) { 595 | pr_warn("%s: No module found in object\n", 596 | info->name ?: "(missing .modinfo section or name field)"); 597 | return -ENOEXEC; 598 | } 599 | ``` 600 | 601 | Conclude from all above, `struct module` is initialized directly from 602 | `.gnu.linkonce.this_module` section in ELF file. 603 | 604 | To dig into this question more, we have to ask where is 605 | `.gnu.linkonce.this_module` section defined. 606 | 607 | This part is very tricky, for that `.gnu.linkonce.this_module` is not 608 | defined in kernel object files but instead defined in a post process program. 609 | 610 | You may find a line: 611 | 612 | ``` 613 | MODPOST /home/doug/ldd_root/nfs_dir/eg_test_c/Module.symvers 614 | ``` 615 | 616 | In building logs. That says we have made some post process for our module 617 | objects. It includes there several steps: 618 | 619 | ``` 620 | make -f ./scripts/Makefile.modpost 621 | sed 's/\.ko$/\.o/' /home/doug/ldd_root/nfs_dir/eg_test_c/modules.order \ 622 | | scripts/mod/modpost -o /home/doug/ldd_root/nfs_dir/eg_test_c/Module.symvers -e -i Module.symvers -T - 623 | ``` 624 | 625 | You can find a function named `add_header()` in modpost's source code in 626 | `scripts/mod/modpost.c`. 627 | 628 | This function generates C source file by writing strings into a buffer. This 629 | buffer later be written into a file suffixed `.mod.c` in function 630 | `write_if_changed()`. This generated C source file will be compiled into object 631 | and linked together with our module's object files to make a new `.ko` file. 632 | 633 | We can find lines below in generated `.mod.c` file: 634 | 635 | ```c 636 | __visible struct module __this_module 637 | __section(".gnu.linkonce.this_module") = { 638 | .name = KBUILD_MODNAME, 639 | .init = init_module, 640 | #ifdef CONFIG_MODULE_UNLOAD 641 | .exit = cleanup_module, 642 | #endif 643 | .arch = MODULE_ARCH_INIT, 644 | }; 645 | ``` 646 | 647 | This structure attributed with `__section(".gnu.linkonce.this_module")` and 648 | will be put in `.gnu.linkonce.this_module` section finally in object file. 649 | 650 | `.init` and `.exit` fields are initialized to `init_module` and `cleanup_module`. 651 | These two symbols defined in our module source via macro `module_init()` and 652 | `module_exit()` which we have mentioned before. 653 | 654 | During the final linkage stage, all these object pieces are linked together into 655 | `.ko` file. 656 | 657 | During module loading process, `struct module` is read out from this ELF section 658 | directly, and our puzzle is resolved. 659 | 660 | 661 | [init_module]: https://man7.org/linux/man-pages/man2/init_module.2.html] 662 | [kernel/module.c]: https://github.com/torvalds/linux/blob/master/kernel/module.c 663 | [include/uapi/linux/elf.h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h 664 | [ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format 665 | [alias attribute]: https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html 666 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/09_how_is_rust_module_loaded_into_kernel.md: -------------------------------------------------------------------------------- 1 | # How is rust module loaded into Kernel 2 | 3 | We have talked the Loading process of Linux module file. For rust, the process 4 | is same because modules compiled from either Rust or C are all ELF dynamic 5 | linked files. The should have same ABI (Application Binary Interface) which 6 | is compatible with Kernel's dynamic linker. 7 | 8 | The `module!{ }` macro we have talked in previous section is responsible for 9 | bootstrapping Rust kernel modules. It reads fields defined in it and expands 10 | them to definitions of variables, functions and structures. 11 | 12 | For a simple rust module: 13 | 14 | ```rust 15 | #![no_std] 16 | #![feature(allocator_api, global_asm)] 17 | 18 | use kernel::prelude::*; 19 | 20 | module! { 21 | type: ExampleModule, 22 | name: b"example_module", 23 | author: b"Douglas Su", 24 | description: b"An example module", 25 | license: b"GPL v2", 26 | params: { 27 | uint_param: u32 { 28 | default: 1, 29 | permissions: 0o644, 30 | description: b"uint parameter", 31 | }, 32 | }, 33 | } 34 | 35 | struct ExampleModule { 36 | version: u32, 37 | } 38 | 39 | impl KernelModule for ExampleModule { 40 | fn init() -> Result { 41 | let lock = THIS_MODULE.kernel_param_lock(); 42 | let module = ExampleModule { version: *uint_param.read(&lock) }; 43 | pr_info!("Hello World! uint_prarm={}\n", module.version); 44 | pr_info!("The address of module parameter uint_param: {:p}\n", uint_param.read(&lock)); 45 | Ok(module) 46 | } 47 | } 48 | 49 | impl Drop for ExampleModule { 50 | fn drop(&mut self) { 51 | pr_info!("Bye World\n"); 52 | } 53 | } 54 | ``` 55 | 56 | These piece of code will be expanded to code below during compiling time by 57 | Rust's macro processor. 58 | 59 | ```rust 60 | const __LOG_PREFIX: &[u8] = b"example_module\0"; 61 | static mut __MOD: Option = None; 62 | 63 | #[cfg(MODULE)] 64 | static THIS_MODULE: kernel::ThisModule = 65 | unsafe { kernel::ThisModule::from_ptr(&kernel::bindings::__this_module as *const _ as *mut _) }; 66 | 67 | #[cfg(MODULE)] 68 | #[no_mangle] 69 | pub extern "C" fn init_module() -> kernel::c_types::c_int { 70 | __init() 71 | } 72 | 73 | #[cfg(MODULE)] 74 | #[no_mangle] 75 | pub extern "C" fn cleanup_module() { 76 | __exit() 77 | } 78 | 79 | fn __init() -> kernel::c_types::c_int { 80 | match ::init() { 81 | Ok(m) => { 82 | unsafe { 83 | __MOD = Some(m); 84 | } 85 | return 0; 86 | } 87 | Err(e) => { 88 | return e.to_kernel_errno(); 89 | } 90 | } 91 | } 92 | fn __exit() { 93 | unsafe { 94 | __MOD = None; 95 | } 96 | } 97 | 98 | #[cfg(MODULE)] 99 | #[link_section = ".modinfo"] 100 | #[used] 101 | pub static __example_module_author: [u8; 18] = *b"author=Douglas Su\0"; 102 | 103 | #[cfg(MODULE)] 104 | #[link_section = ".modinfo"] 105 | #[used] 106 | pub static __example_module_description: [u8; 30] = *b"description=An example module\0"; 107 | 108 | #[cfg(MODULE)] 109 | #[link_section = ".modinfo"] 110 | #[used] 111 | pub static __example_module_license: [u8; 15] = *b"license=GPL v2\0"; 112 | 113 | #[cfg(MODULE)] 114 | #[link_section = ".modinfo"] 115 | #[used] 116 | pub static __example_module_parmtype_uint_param: [u8; 24] = *b"parmtype=uint_param:u32\0"; 117 | 118 | #[cfg(MODULE)] 119 | #[link_section = ".modinfo"] 120 | #[used] 121 | pub static __example_module_parm_uint_param: [u8; 31] = *b"parm=uint_param:uint parameter\0"; 122 | static mut __example_module_uint_param_value: u32 = 1; 123 | struct __example_module_uint_param; 124 | impl __example_module_uint_param { 125 | fn read<'lck>( 126 | &self, 127 | lock: &'lck kernel::KParamGuard, 128 | ) -> &'lck ::Value { 129 | unsafe { 130 | ::value(&__example_module_uint_param_value) 131 | } 132 | } 133 | } 134 | const uint_param: __example_module_uint_param = __example_module_uint_param; 135 | 136 | #[repr(transparent)] 137 | struct __example_module_uint_param_RacyKernelParam(kernel::bindings::kernel_param); 138 | unsafe impl Sync for __example_module_uint_param_RacyKernelParam {} 139 | 140 | #[cfg(MODULE)] 141 | const __example_module_uint_param_name: *const kernel::c_types::c_char = 142 | b"uint_param\0" as *const _ as *const kernel::c_types::c_char; 143 | 144 | #[link_section = "__param"] 145 | #[used] 146 | static __example_module_uint_param_struct: __example_module_uint_param_RacyKernelParam = 147 | __example_module_uint_param_RacyKernelParam(kernel::bindings::kernel_param { 148 | name: __example_module_uint_param_name, 149 | 150 | #[cfg(MODULE)] 151 | mod_: unsafe { &kernel::bindings::__this_module as *const _ as *mut _ }, 152 | ops: unsafe { &kernel::module_param::PARAM_OPS_U32 } 153 | as *const kernel::bindings::kernel_param_ops, 154 | perm: 0o644, 155 | level: -1, 156 | flags: 0, 157 | __bindgen_anon_1: kernel::bindings::kernel_param__bindgen_ty_1 { 158 | arg: unsafe { &__example_module_uint_param_value } as *const _ 159 | as *mut kernel::c_types::c_void, 160 | }, 161 | }); 162 | 163 | struct ExampleModule { 164 | version: u32, 165 | } 166 | 167 | impl KernelModule for ExampleModule { 168 | fn init() -> Result { 169 | Ok(module) 170 | } 171 | } 172 | 173 | impl Drop for ExampleModule { 174 | fn drop(&mut self) { }; 175 | } 176 | } 177 | 178 | ``` 179 | 180 | ## How Rust module source is compiled into object 181 | 182 | It is intuitive that object is compiled from C source file, and GNU make command 183 | takes this as an implicit rule. However, for Rust code, Kbuild doesn't know 184 | how to handle it and doesn't know that rust source can be compiled into object. 185 | 186 | To make Kbuild understand Rust, below lines are added in `scripts/Makefile.build`: 187 | 188 | 189 | ```makefile 190 | rustc_cross_flags := --target=$(realpath $(KBUILD_RUSTC_TARGET)) 191 | 192 | quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ 193 | cmd_rustc_o_rs = \ 194 | RUST_MODFILE=$(modfile) \ 195 | $(RUSTC_OR_CLIPPY) $(rustc_flags) $(rustc_cross_flags) \ 196 | --extern alloc --extern kernel \ 197 | --crate-type rlib --out-dir $(obj) -L $(objtree)/rust/ \ 198 | --crate-name $(patsubst %.o,%,$(notdir $@)) $<; \ 199 | mv $(obj)/$(subst .o,,$(notdir $@)).d $(depfile); \ 200 | sed -i '/^\#/d' $(depfile) 201 | 202 | $(obj)/%.o: $(src)/%.rs FORCE 203 | $(call if_changed_dep,rustc_o_rs) 204 | ``` 205 | 206 | ## `init_module` and `cleanup_module` symbols 207 | 208 | From the discussions in previous chapter, two important symbols `init_module` 209 | and `cleanup_module` must be defined, and they will be referenced my 210 | `struct module` which later be used to do initialization and cleanup works of 211 | our module. 212 | 213 | Other than than the symbol name, the ABI also plays an important role. Functions 214 | export `init_module` and `cleanup_module` symbols must obey the ABI of standard 215 | C. For Rust code, this is implemented by decorating functions with `extern "C"`. 216 | 217 | Functions marked as `extern "C"` will be compile by using standard C ABI and 218 | in turn be invoked directly by C code. Usually, `#[no_mangle]` annotation is 219 | needed to tell the Rust compiler not to mangle the name of this function. 220 | Mangling is when a compiler changes the name we’ve given a function to a 221 | different name that contains more information for other parts of the compilation 222 | process to consume but is less human readable. 223 | 224 | For example, we a function in Rust: 225 | 226 | ```rust 227 | #[no_mangle] 228 | fn my_add(a: i32, b: i32) -> i32 { a + b } 229 | ``` 230 | 231 | If it is decorated with `#[no_mangle]` annotation, function symbol generated 232 | will be something like: 233 | 234 | ``` 235 | 0000000100001680 T _my_add 236 | ``` 237 | 238 | However, by default, Rust will mangle symbols it generated, and produce 239 | something like this: 240 | 241 | ``` 242 | 0000000100001680 t __ZN2z16my_add17hb64f7e7eb99a7564E 243 | ``` 244 | 245 | Back to our Rust code. After macro expansion, two functions are generated, and 246 | be annotated with `#[no_mangle]`. 247 | 248 | ```rust 249 | #[cfg(MODULE)] 250 | #[no_mangle] 251 | pub extern "C" fn init_module() -> kernel::c_types::c_int { 252 | __init() 253 | } 254 | 255 | #[cfg(MODULE)] 256 | #[no_mangle] 257 | pub extern "C" fn cleanup_module() { 258 | __exit() 259 | } 260 | ``` 261 | 262 | After compiling this Rust into object, `init_module` and `cleanup_module` 263 | symbols is defined as strong symbols which will be used in `postmod`. When the 264 | module file is loaded, kernel's module loader will find these two functions and 265 | use them to init/cleanup module. 266 | 267 | Two functions, `__init()` and `__exit()`, are invoked in `init_module()` 268 | and `cleanup_module()` respectively. `__init()` function in turn calls 269 | our modulel structure's member fucntion `ExampleModule::init()`, in which 270 | `struct ExampleModule` is initialized. 271 | 272 | The `__exit()` function desn't nothing. That is because the `Drop` trait has 273 | been implemented for our `struct ExampleModule`, and the `drop()` function will 274 | be automaticall invoked when instace of `struct ExampleModule` goes out of its 275 | scope. 276 | 277 | ## Build `modinfo` section 278 | 279 | We have talked that in module's ELF file, a special section, `.modinfo`, is used 280 | to store information about this module. It includes the name, paramter type, 281 | parameter name, license, author, etc. 282 | 283 | For rust module, we have to obey this rule. The expanded rust code has self 284 | expained: 285 | 286 | ```rust 287 | #[cfg(MODULE)] 288 | #[link_section = ".modinfo"] 289 | #[used] 290 | pub static __example_module_author: [u8; 18] = *b"author=Douglas Su\0"; 291 | 292 | #[cfg(MODULE)] 293 | #[link_section = ".modinfo"] 294 | #[used] 295 | pub static __example_module_description: [u8; 30] = *b"description=An example module\0"; 296 | 297 | #[cfg(MODULE)] 298 | #[link_section = ".modinfo"] 299 | #[used] 300 | pub static __example_module_license: [u8; 15] = *b"license=GPL v2\0"; 301 | 302 | #[cfg(MODULE)] 303 | #[link_section = ".modinfo"] 304 | #[used] 305 | pub static __example_module_parmtype_uint_param: [u8; 24] = *b"parmtype=uint_param:u32\0"; 306 | 307 | #[cfg(MODULE)] 308 | #[link_section = ".modinfo"] 309 | #[used] 310 | pub static __example_module_parm_uint_param: [u8; 31] = *b"parm=uint_param:uint parameter\0"; 311 | ``` 312 | 313 | A special directive `#[link_section()]` tells Rust compiler which section the 314 | data or code it annotated will be placed in. For our example, the section 315 | is `.modinfo`. 316 | 317 | ## Kernel module 318 | 319 | Module parameter is defined in `module!{ }` macro: 320 | 321 | ```rust 322 | module! { 323 | ... 324 | params: { 325 | uint_param: u32 { 326 | default: 1, 327 | permissions: 0o644, 328 | description: b"uint parameter", 329 | }, 330 | }, 331 | } 332 | ``` 333 | 334 | After macro expansion: 335 | 336 | ```rust 337 | static mut __example_module_uint_param_value: u32 = 1; 338 | 339 | struct __example_module_uint_param; 340 | 341 | impl __example_module_uint_param { 342 | fn read<'lck>( 343 | &self, 344 | lock: &'lck kernel::KParamGuard, 345 | ) -> &'lck ::Value { 346 | unsafe { 347 | ::value(&__example_module_uint_param_value) 348 | } 349 | } 350 | } 351 | 352 | const uint_param: __example_module_uint_param = __example_module_uint_param; 353 | ``` 354 | 355 | The actual variable in which our value is stored is mangled to 356 | `__example_module_uint_param_value`. Then, a new structure 357 | `struct __example_module_uint_param;` is defined and implemented a member 358 | function, say `read()`, on it. The function takes the parameter lock as its 359 | variable to prevent from concurrent acesses to our variable. 360 | 361 | We re-defined a new variable which has the same name as our parameter variable, 362 | i.e. `uint_param`, but has the type of `__example_module_uint_param`. Later, 363 | module programmer can use this variable as: 364 | 365 | ```rust 366 | let lock = THIS_MODULE.kernel_param_lock(); 367 | pr_info!("uint_param = {:p}\n", uint_param.read(&lock)); 368 | ``` 369 | 370 | ## Build `__param` section 371 | 372 | Previous chapter introduces `__param` section in ELF file and how module loader 373 | process this section during loading time. 374 | 375 | For Rust code, we have to build this section consistent with its C counterpart. 376 | The `module!{ }` macro takes care of this, and you can find codes generated 377 | from this macro like this: 378 | 379 | ```rust 380 | #[repr(transparent)] 381 | struct __example_module_uint_param_RacyKernelParam(kernel::bindings::kernel_param); 382 | unsafe impl Sync for __example_module_uint_param_RacyKernelParam {} 383 | 384 | #[cfg(MODULE)] 385 | const __example_module_uint_param_name: *const kernel::c_types::c_char = 386 | b"uint_param\0" as *const _ as *const kernel::c_types::c_char; 387 | 388 | #[link_section = "__param"] 389 | #[used] 390 | static __example_module_uint_param_struct: __example_module_uint_param_RacyKernelParam = 391 | __example_module_uint_param_RacyKernelParam(kernel::bindings::kernel_param { 392 | name: __example_module_uint_param_name, 393 | 394 | #[cfg(MODULE)] 395 | mod_: unsafe { &kernel::bindings::__this_module as *const _ as *mut _ }, 396 | ops: unsafe { &kernel::module_param::PARAM_OPS_U32 } 397 | as *const kernel::bindings::kernel_param_ops, 398 | perm: 0o644, 399 | level: -1, 400 | flags: 0, 401 | __bindgen_anon_1: kernel::bindings::kernel_param__bindgen_ty_1 { 402 | arg: unsafe { &__example_module_uint_param_value } as *const _ 403 | as *mut kernel::c_types::c_void, 404 | }, 405 | }); 406 | ``` 407 | 408 | `struct __example_module_uint_param_RacyKernelParam` is a wrapper of 409 | `kernel::bindings::kernel_param`. `kernel_param` in kernel describes single 410 | parameter in module. We have detailed this in previous chapter, and for 411 | convenience I paste it here again: 412 | 413 | ```c 414 | struct kernel_param { 415 | const char *name; 416 | struct module *mod; 417 | const struct kernel_param_ops *ops; 418 | const u16 perm; 419 | s8 level; 420 | u8 flags; 421 | union { 422 | void *arg; 423 | const struct kparam_string *str; 424 | const struct kparam_array *arr; 425 | }; 426 | }; 427 | ``` 428 | 429 | The Rust part is a mimic of C structure which initialized each field with 430 | Rust code, either in FFI or rust variable. The structure then is compiled into 431 | `__param` section due the the `#[link_section = "__param"]` annotation. 432 | 433 | However, the `ops` field is a little bit special. It is assigned 434 | `&kernel::module_param::PARAM_OPS_U32`. 435 | 436 | This variable is defined via a macro `make_param_ops!()`, and expanded during 437 | kernel compiling time. For `PARAM_OPS_U32`, it is define as: 438 | 439 | ```rust 440 | make_param_ops!( 441 | /// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h) 442 | /// for [`u32`]. 443 | PARAM_OPS_U32, 444 | u32 445 | ); 446 | ``` 447 | 448 | 449 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/10-parameters_in_rust_module.md: -------------------------------------------------------------------------------- 1 | # Parameters in Rust Module 2 | 3 | ## `make_param_ops!( )` macro 4 | 5 | This macro is defined in file: `rust/kernel/module_param.rs`: 6 | 7 | ```rust 8 | macro_rules! make_param_ops { 9 | ($ops:ident, $ty:ty) => { 10 | $crate::make_param_ops!( 11 | #[doc=""] 12 | $ops, 13 | $ty 14 | ); 15 | }; 16 | ($(#[$meta:meta])* $ops:ident, $ty:ty) => { 17 | $(#[$meta])* 18 | /// 19 | /// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h) 20 | /// struct generated by [`make_param_ops`]. 21 | pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops { 22 | flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED { 23 | $crate::bindings::KERNEL_PARAM_OPS_FL_NOARG 24 | } else { 25 | 0 26 | }, 27 | set: Some(<$ty as $crate::module_param::ModuleParam>::set_param), 28 | get: Some(<$ty as $crate::module_param::ModuleParam>::get_param), 29 | free: Some(<$ty as $crate::module_param::ModuleParam>::free), 30 | }; 31 | }; 32 | } 33 | ``` 34 | 35 | This is a declarative macro in Rust. 36 | 37 | ## Declarative macro 38 | 39 | Previously, we introduced procedual macro which is used to define `module!{ }`. 40 | 41 | Parameters definition is kernel are benenifits from declarative macro. The 42 | declarative macro is simpler than procedual macro. Basically, it is has a 43 | profile like `match` expression: 44 | 45 | ```rust 46 | macro_rules! make_param_ops { 47 | ($ops:ident, $ty:ty) => { 48 | ... 49 | }; 50 | ($(#[$meta:meta])* $ops:ident, $ty:ty) => { 51 | ... 52 | }; 53 | } 54 | ``` 55 | 56 | Declarative macro starts with the keyword `macro_rules!` and follows the name 57 | of macro, i.e. `make_param_ops`. The code block in macro definition is similar 58 | to `match` expression that to match arms are defined. However, instead of 59 | matching values of variables, the match arm for macro definition matches 60 | token it receives. 61 | 62 | The first arm `($ops:ident, $ty:ty) => { }` matches two tokens in its paramters 63 | (using word parameter seem not very precise). The first must be an indetifier, 64 | and the second must be a type. 65 | 66 | The second arm `($(#[$meta:meta])* $ops:ident, $ty:ty) => { }` matches three 67 | tokens in its paramters: a meta item, an indetifier and a type. 68 | 69 | Macro takes these indetifiers, types, or other token types, like statement, item, 70 | expression, and then create new rust code based on these tokens. 71 | 72 | ## `make_param_ops!( )` macro expansion 73 | 74 | To define module paramter with type u32: 75 | 76 | ```rust 77 | make_param_ops!( 78 | PARAM_OPS_U32, // Name for the static 79 | u32 // A type which implements [`ModuleParam`]. 80 | ); 81 | ``` 82 | 83 | Psses two tokens to `make_param_ops!()` macro, and matches the first match arm: 84 | 85 | ```rust 86 | ($ops:ident, $ty:ty) => { 87 | $crate::make_param_ops!( 88 | #[doc=""] 89 | $ops, 90 | $ty 91 | ); 92 | }; 93 | ``` 94 | 95 | In this code block, `make_param_ops!( )` is invoked again and passed in three 96 | tokens: `#[doc=""]`, `$ops`, `$ty`. The later two are parameters received from 97 | macro invocation. Then this macro is recursively expaned to: 98 | 99 | ```rust 100 | make_param_ops!( 101 | #[doc=""], 102 | PARAM_OPS_U32, // Name for the static 103 | u32 // A type which implements [`ModuleParam`]. 104 | ); 105 | ``` 106 | 107 | This time, the second match arm is selected and the marco is expaned to: 108 | 109 | ```rust 110 | pub static PARAM_OPS_U32: crate::bindings::kernel_param_ops = crate::bindings::kernel_param_ops { 111 | flags: if ::NOARG_ALLOWED { 112 | crate::bindings::KERNEL_PARAM_OPS_FL_NOARG 113 | } else { 114 | 0 115 | }, 116 | set: Some(::set_param), 117 | get: Some(::get_param), 118 | free: Some(::free), 119 | }; 120 | ``` 121 | 122 | This structure is assgined to `ops` field of `kernel_param`: 123 | 124 | ```rust 125 | #[link_section = "__param"] 126 | #[used] 127 | static __example_module_uint_param_struct: __example_module_uint_param_RacyKernelParam = 128 | __example_module_uint_param_RacyKernelParam(kernel::bindings::kernel_param { 129 | name: __example_module_uint_param_name, 130 | 131 | #[cfg(MODULE)] 132 | mod_: unsafe { &kernel::bindings::__this_module as *const _ as *mut _ }, 133 | ops: unsafe { &kernel::module_param::PARAM_OPS_U32 } 134 | as *const kernel::bindings::kernel_param_ops, 135 | perm: 0o644, 136 | level: -1, 137 | flags: 0, 138 | __bindgen_anon_1: kernel::bindings::kernel_param__bindgen_ty_1 { 139 | arg: unsafe { &__example_module_uint_param_value } as *const _ 140 | as *mut kernel::c_types::c_void, 141 | }, 142 | }); 143 | ``` 144 | 145 | And finially be placed in `__param` section. 146 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/dependency_graph.drawio: -------------------------------------------------------------------------------- 1 | 7Vttb5swEP41+biI8BbycUvTTtM2TeqHtftSOeCCO4ORMQnZr58J5tVZytYsdpcpUoKPs4HnHu7OZ2diLePihoI0+kQCiCemERQT62pimgvb5d+lYFcJ3LlZCUKKgko0awW36AcUQkNIcxTArKfICMEMpX2hT5IE+qwnA5SSbV/tkeD+VVMQQklw6wMsS7+igEWV1HOMVv4eojCqrzwzxJkY1MpCkEUgINuOyFpNrCUlhFVHcbGEuMSuxqXqd/2Ls82NUZiwMR2S6Mn/Bt7N3fgz+LChxh0k+I1ti5tju/qJYcABEE1CWURCkgC8aqXvKMmTAJbDGrzV6nwkJOXCGRc+QcZ2wpogZ4SLIhZjcZbfMd3ddRv35WBTp25eFWLwqrUTLfmRBQoZyakPjzxnTR1AQ8iO6TmVYglC5woC0RtIYshviCtQiAFDmz5LgCBb2Oi19uAHwiS/YR7HUmoeQzfzeFpZR4y7ATgXV/IJhVMi2axvkW2EGLxNwR6RLfeaffQfEcZLggnd97VWbvk5hu4GUgaLo3iIs5Yp6C2csVk7q23r2ma1v4o6bs02/haEC7UEbzl93z13coKbY/2PVgS31bqfs0WH0daZa2UeR23wNqamZm+PXuHBPBAe4hRhSB/WOeIpbJK9pljhKY8VSrzRn7PWGutV9HL6lkTbCOIU0tdE1oaYyshqzy8jdNojSV6DrwnJbe8y8s7R5tHKOo773zr65jW2FCAAxsR/ReHBclWHB0fCEKMkL/hYNM8Y//kOaVJWUq8xWk9p9jJoTwDhzO1DaKtPB1XPfs7kJNyxaaRePtyVGA6LlAOucxo5JLn6NNIx1ZL8XGnkfGye4mpF8vkBN76OSZBjOM1eyPMT8Nn2dHPazoXk3d5IPi+0orMn0XmNkgAlYfYQwgRSwGCgQzLijJnuu+fk9WJ0PtcgWlVVppF6NI2Bl5DBbBaKzpPZyQtrAzTripSvHLzh1OIAeGdOi83nwKvzMPXgSZMK5eDJ8zIBWrmyy38y6us7J1O/nFtfTMZvXyLQHUD1dQFTnjYN3t4Y+JRk+mDo2iNyTMs5I4b2hewpsASAzyaZolCiSZJZb53711dGRptHsy1njtq3RzvzaLbnQ826YoFY5dvmjmje1/bgx61xysaua6luL41c4slXVPZd31IKdh2FlKCEZZ2Rv5SCTn1mNoid9mAL70BfirV9fX5Q3UFLr+ZRXrAfQM7pqsmsxoVcaVamvPA1O1Qq7CV28uYgDbI77/lNQKeqDZRINJvhK/K2/yiwVj8B -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/dependency_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/d0u9/Linux-Device-Driver-Rust/a54f81028e434f4a659cc883948fdf158f6d6474/00_Introduction_to_Rust_Module_in_Linux/dependency_graph.png -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/my_macro/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "my_macro" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/my_macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "my_macro" 3 | version = "0.1.0" 4 | authors = ["d0u9 "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | 11 | [[bin]] 12 | name = "my_bin" 13 | path = "src/main.rs" 14 | 15 | [lib] 16 | name = "my_macros" 17 | path = "src/lib/lib.rs" 18 | proc-macro = true 19 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/my_macro/Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR ?= $(shell mkdir -p build; echo build) 2 | BIN := my_bin 3 | BIN_SRC := src/main.rs 4 | MACRO_LIB := my_macros 5 | MACRO_LIB_FILE := $(addprefix lib,$(addsuffix .so,$(MACRO_LIB))) 6 | MACRO_SRC := src/lib/lib.rs 7 | MACRO_FLAGS := --emit=obj,link \ 8 | --extern proc_macro \ 9 | --crate-type proc-macro \ 10 | --crate-name $(MACRO_LIB) \ 11 | --out-dir $(BUILD_DIR) 12 | 13 | $(BUILD_DIR)/$(BIN): $(BIN_SRC) $(MACRO_LIB_FILE) 14 | rustc -o $@ --extern $(MACRO_LIB) -L $(BUILD_DIR) $< 15 | 16 | $(MACRO_LIB_FILE): $(MACRO_SRC) 17 | rustc $(MACRO_FLAGS) $^ 18 | 19 | .PHONY: clean 20 | clean: 21 | rm -fr $(BUILD_DIR) 22 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/my_macro/src/lib/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | use proc_macro::TokenStream; 3 | 4 | #[proc_macro] 5 | pub fn answer_fn(_item: TokenStream) -> TokenStream { 6 | println!("This line is printed in macro"); 7 | " 8 | fn answer() -> u32 { 9 | let k = 1234; 10 | print!(\"The answer is: {}\n\", k); 11 | k 12 | } 13 | ".parse().unwrap() 14 | } 15 | 16 | -------------------------------------------------------------------------------- /00_Introduction_to_Rust_Module_in_Linux/my_macro/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate my_macros; 2 | use my_macros::answer_fn; 3 | 4 | answer_fn!(); 5 | 6 | fn main() { 7 | print!("This is my answer: {}\n", answer()); 8 | } 9 | -------------------------------------------------------------------------------- /00_preface/README.md: -------------------------------------------------------------------------------- 1 | - [00_dir_tree.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/00_preface/00_dir_tree.md) 2 | -------------------------------------------------------------------------------- /01_Introduction_to_Linux_and_Device_Drivers/README.md: -------------------------------------------------------------------------------- 1 | - [00_opening](https://github.com/d0u9/Linux-Device-Driver/blob/draft/01_Introduction_to_Linux_and_Device_Drivers/00_opening.md) 2 | - [01_the_linux_kernel.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/01_Introduction_to_Linux_and_Device_Drivers/01_the_linux_kernel.md) 3 | - [02_role_of_device_driver](https://github.com/d0u9/Linux-Device-Driver/blob/draft/01_Introduction_to_Linux_and_Device_Drivers/02_role_of_device_driver.md) 4 | - [03_license.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/01_Introduction_to_Linux_and_Device_Drivers/03_license.md) 5 | - [04_overview_of_this_book.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/01_Introduction_to_Linux_and_Device_Drivers/04_overview_of_this_book.md) 6 | -------------------------------------------------------------------------------- /02_getting_start_with_driver_development/README.md: -------------------------------------------------------------------------------- 1 | - [00_opening.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/00_opening.md) 2 | - [01_development_with_qemu.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/01_development_with_qemu.md) 3 | - [02_compile_Linux_Kernel.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/02_compile_Linux_Kernel.md) 4 | - [03_build_initramfs.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/03_build_initramfs.md) 5 | - [04_nfs_support.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/04_nfs_support.md) 6 | - [05_telnet_server.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/05_telnet_server.md) 7 | - [06_hello_world_module.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/06_hello_world_module.md) 8 | - [07_compiling.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/07_compiling.md) 9 | - [08_loading_module.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/08_loading_module.md) 10 | - [09_review_hello_world.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/09_review_hello_world.md) 11 | - [10_kernel_modules_vs_applications.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/10_kernel_modules_vs_applications.md) 12 | - [11_kernel_symbol_table.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/11_kernel_symbol_table.md) 13 | - [12_initialization_and_shutdown.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/12_initialization_and_shutdown.md) 14 | - [99_finial.md](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/99_finial.md) 15 | - [QEMU_LDD.patch](https://github.com/d0u9/Linux-Device-Driver/blob/draft/02_getting_start_with_driver_development/QEMU_LDD.patch) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux-Device-Driver-Rust 2 | 3 | This is a twain Repo of [Linux-Device-Driver]. 4 | 5 | [Linux-Device-Driver] is a long time work in which I rewrite all examples in 6 | the book LDD3 (Linux Device Driver, the 3rd edition). 7 | 8 | [Linux-Device-Driver]: https://github.com/d0u9/Linux-Device-Driver 9 | -------------------------------------------------------------------------------- /eg_01_hello_world/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | 3 | # In kbuild context 4 | hello_world-objs := main.o 5 | obj-m := hello_world.o 6 | 7 | else 8 | # In normal make context 9 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 10 | PWD := $(shell pwd) 11 | 12 | .PHONY: modules 13 | modules: 14 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 15 | 16 | .PHONY: clean 17 | clean: 18 | $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 19 | 20 | endif 21 | -------------------------------------------------------------------------------- /eg_01_hello_world/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | LIBCLANG_PATH=/path/to/libclang make KERNELDIR=/rust/linux/kernel LLVM=1 modules 3 | ``` 4 | 5 | -------------------------------------------------------------------------------- /eg_01_hello_world/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | use kernel::prelude::*; 4 | use kernel::{str::CStr, ThisModule}; 5 | 6 | module! { 7 | type: HelloWorld, 8 | name: b"hello_world", 9 | author: b"Douglas Su", 10 | description: b"A simple hello world example", 11 | license: b"GPL v2", 12 | } 13 | 14 | struct HelloWorld; 15 | 16 | impl kernel::Module for HelloWorld { 17 | fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result { 18 | pr_info!("Hello world from rust!\n"); 19 | 20 | Ok(HelloWorld) 21 | } 22 | } 23 | 24 | impl Drop for HelloWorld { 25 | fn drop(&mut self) { 26 | pr_info!("Bye world from rust!\n"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /eg_02_module_parameters/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | 3 | # In kbuild context 4 | hello_world-objs := main.o 5 | obj-m := hello_world.o 6 | 7 | else 8 | # In normal make context 9 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 10 | PWD := $(shell pwd) 11 | 12 | .PHONY: modules 13 | modules: 14 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 15 | 16 | .PHONY: clean 17 | clean: 18 | $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 19 | 20 | endif 21 | -------------------------------------------------------------------------------- /eg_02_module_parameters/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(allocator_api, global_asm)] 3 | 4 | use kernel::prelude::*; 5 | 6 | module! { 7 | type: ModuleParameter, 8 | name: b"hello_world", 9 | author: b"d0u9", 10 | description: b"A simple hello world example", 11 | license: b"GPL v2", 12 | params: { 13 | howmany: i32 { 14 | default: 3, 15 | permissions: 0o644, 16 | description: b"How many times string will be printed", 17 | }, 18 | whom: str { 19 | default: b"Mom", 20 | permissions: 0o644, 21 | description: b"What string to be printed", 22 | }, 23 | }, 24 | } 25 | 26 | struct ModuleParameter; 27 | 28 | impl KernelModule for ModuleParameter { 29 | fn init() -> Result { 30 | pr_info!("Hello world from rust!\n"); 31 | 32 | let lock = THIS_MODULE.kernel_param_lock(); 33 | for i in 0..*howmany.read(&lock) { 34 | pr_info!("{} Hello, {}\n", i, core::str::from_utf8(whom.read(&lock))?); 35 | } 36 | 37 | Ok(ModuleParameter) 38 | } 39 | } 40 | 41 | impl Drop for ModuleParameter { 42 | fn drop(&mut self) { 43 | pr_info!("Bye world from rust!\n"); 44 | } 45 | } 46 | --------------------------------------------------------------------------------