├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── armv7l-linux-kernel-module.json ├── build.rs ├── hello_world ├── Cargo.toml ├── Makefile └── src │ └── lib.rs ├── kernel-cflags-finder └── Makefile ├── simple_sysctl ├── Cargo.toml ├── Makefile └── src │ └── lib.rs ├── smsc9512 ├── Cargo.toml ├── Makefile └── src │ └── lib.rs ├── src ├── allocator.rs ├── bindgen_helper.h ├── bindings.rs ├── c_types.rs ├── c_wrapper.c ├── kernel.rs ├── kernel_module.rs ├── kernel_result.rs ├── lib.rs ├── panic.rs ├── printk.rs └── sync.rs ├── sync_example ├── Cargo.toml ├── Makefile └── src │ └── lib.rs ├── x86_64-linux-kernel-module.json └── yes_chardev ├── Cargo.toml ├── Makefile └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | kernel-cflags-finder/ 5 | !kernel-cflags-finder/Makefile 6 | .cache.mk 7 | *.ko 8 | *.o 9 | *.order 10 | *.cmd 11 | *.mod.c 12 | Module.symvers 13 | .tmp_versions/ 14 | *.swp 15 | *.ur-safe 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: rust 3 | cache: cargo 4 | rust: nightly 5 | install: 6 | - sudo apt-get install linux-headers-`uname -r` 7 | - cargo install --force cargo-xbuild 8 | - rustup component add --toolchain=nightly rust-src 9 | - rustup component add rustfmt-preview 10 | jobs: 11 | include: 12 | - stage: hello_world 13 | before_script: cd hello_world 14 | script: 15 | - RUST_TARGET_PATH=$(pwd)/.. cargo xbuild --target x86_64-linux-kernel-module 16 | - make 17 | - stage: yes_chardev 18 | before_script: cd yes_chardev 19 | script: 20 | - RUST_TARGET_PATH=$(pwd)/.. cargo xbuild --target x86_64-linux-kernel-module 21 | - make 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linux-kernel-module" 3 | version = "0.1.0" 4 | authors = ["Li Zhuohua "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | # failure = { version = "0.1.3", features = [] } 9 | # libc = { version = "0.2.43", default-features = false } 10 | # spin = "0.4.9" 11 | [build-dependencies] 12 | bindgen = "0.43.0" 13 | cc = "1.0.25" 14 | shlex = "0.1.1" 15 | 16 | [profile.release] 17 | lto = true 18 | panic="abort" 19 | 20 | [profile.dev] 21 | panic="abort" 22 | -------------------------------------------------------------------------------- /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 | 341 | 342 | The following files are from the `fishinabarrel/linux-kernel-module-rust' project 343 | (https://github.com/fishinabarrel/linux-kernel-module-rust/blob/master/Cargo.toml): 344 | - kernel-cflags-finder/Makefile 345 | - src/printk.rs 346 | - src/c_types.rs 347 | 348 | The following is the license of the `fishinabarrel/linux-kernel-module-rust' project. 349 | 350 | Copyright (C) 2019 Alex Gaynor, Geoffrey Thomas, and other project authors 351 | 352 | This program is free software; you can redistribute it and/or modify 353 | it under the terms of the GNU General Public License as published by 354 | the Free Software Foundation; either version 2 of the License, or 355 | (at your option) any later version. 356 | 357 | This program is distributed in the hope that it will be useful, 358 | but WITHOUT ANY WARRANTY; without even the implied warranty of 359 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 360 | GNU General Public License for more details. 361 | 362 | You should have received a copy of the GNU General Public License along 363 | with this program; if not, write to the Free Software Foundation, Inc., 364 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 365 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Writing Linux Kernel Module in Rust 2 | [![Build Status](https://travis-ci.com/lizhuohua/linux-kernel-module-rust.svg?token=gQ3MGp1DXsVespCpQBDg&branch=master)](https://travis-ci.com/lizhuohua/linux-kernel-module-rust) 3 | 4 | Device drivers on Linux-powered embedded or IoT systems execute in kernel 5 | space thus must be fully trusted. Any fault in drivers may significantly 6 | impact the whole system. However, third-party embedded hardware manufacturers 7 | usually ship their proprietary device drivers with their embedded devices. 8 | These out-of-tree device drivers are generally of poor quality because of a 9 | lack of code audit. 10 | 11 | We propose an approach that helps third-party developers to improve the 12 | reliability and safety of device drivers without modifying the kernel: 13 | Rewriting device drivers in a memory-safe programming language called Rust. 14 | Rust's rigorous language model assists the device driver developers to detect 15 | many security issues at compile time. We designed a framework to help 16 | developers to quickly build device drivers in Rust. We also utilized Rust’s 17 | security features to provide several useful infrastructures for developers so 18 | that they can easily handle kernel memory allocation and concurrency 19 | management, at the same time, some common bugs (e.g. use-after-free) can be 20 | alleviated. 21 | 22 | We demonstrate the generality of our framework by implementing a real-world 23 | device driver on Raspberry Pi 3, and our evaluation shows that device drivers 24 | generated by our framework have acceptable binary size for canonical embedded 25 | systems and the runtime overhead is negligible. 26 | 27 | More details about the design and implementation can be found in our paper: 28 | [Securing the Device Drivers of Your Embedded Systems: Framework and 29 | Prototype](https://mssun.me/assets/ares19securing.pdf). 30 | 31 | ## Requirements 32 | 33 | ### Toolchain 34 | 35 | * `x86_64` 36 | 37 | Rust nightly. Tested on `nightly-2018-09-30-x86_64-unknown-linux-gnu`. 38 | 39 | * `ARMv7` (Raspberry Pi) 40 | 41 | Rust nightly. In addition, you need to install the new target: 42 | ```bash 43 | $ rustup target add arm-unknown-linux-gnueabi 44 | ``` 45 | And the `arm-linux-gnueabihf-` cross-compiler. 46 | 47 | ### Linux Kernel Headers 48 | 49 | A pre-built kernel (with configuration and header files) is needed. 50 | 51 | * `x86_64` 52 | 53 | Your Linux distribution should provide a package for this. For example, on Ubuntu, you can try: 54 | ```bash 55 | $ sudo apt-get install linux-headers-`uname -r` 56 | ``` 57 | 58 | * `ARMv7` (Raspberry Pi) 59 | 60 | You need to [compile your own kernel](https://www.raspberrypi.org/documentation/linux/kernel/building.md) in order for `bindgen` to work. 61 | 62 | ## Build 63 | 64 | 1. `cargo-xbuild`, `rust-src` and `rustfmt-preview` 65 | ```bash 66 | $ cargo install cargo-xbuild 67 | $ rustup component add --toolchain=nightly rust-src 68 | $ rustup component add rustfmt-preview 69 | ``` 70 | 2. Select an example 71 | ```bash 72 | $ cd hello_world 73 | ``` 74 | 3. Compile into a static library 75 | * `x86_64` 76 | ```bash 77 | $ RUST_TARGET_PATH=$(pwd)/.. cargo xbuild --target x86_64-linux-kernel-module 78 | ``` 79 | * `ARMv7` (Raspberry Pi) 80 | ```bash 81 | $ RUST_TARGET_PATH=$(pwd)/.. KDIR= cargo xbuild --target armv7l-linux-kernel-module 82 | ``` 83 | 4. Link as a kernel module 84 | * `x86_64` 85 | ```bash 86 | $ make 87 | ``` 88 | * `ARMv7` (Raspberry Pi) 89 | ```bash 90 | $ make TARGET=armv7l-linux-kernel-module KDIR= CROSS=arm-linux-gnueabihf- 91 | ``` 92 | 5. Load and test 93 | 94 | See below. 95 | 6. If you want to clean it up 96 | * `x86_64` 97 | ```bash 98 | $ make clean;cargo clean 99 | ``` 100 | * `ARMv7` (Raspberry Pi) 101 | ```bash 102 | $ make clean TARGET=armv7l-linux-kernel-module KDIR= CROSS=arm-linux-gnueabihf-;cargo clean 103 | ``` 104 | 105 | ## Load and Test 106 | Examples are tested on Ubuntu 18.04 (Linux kernel 4.15.0-46-generic), `smsc95xx` is tested on Raspberry Pi 3 (Linux kernel 4.19.29). 107 | 108 | ### hello_world 109 | The simplest kernel module. It just prints "hello" and "goodbye". 110 | ```bash 111 | $ sudo insmod helloworld.ko # load the module 112 | $ sudo rmmod helloworld # remove the module 113 | $ dmesg # dump kernel messages 114 | ``` 115 | 116 | ### yes_chardev 117 | A simple character device which is similar to the `yes` Unix command. 118 | ```bash 119 | $ sudo insmod yes_chardev.ko 120 | $ cat /proc/devices # find the major number of the device 'yes', for example, 243 121 | $ sudo mknod /dev/yes c 243 0 # make a filesystem node (replace 243 with your own major number) 122 | $ sudo cat /dev/yes # read from the device 123 | $ sudo rmmod yes_chardev 124 | ``` 125 | 126 | ### simple_sysctl 127 | A simple sysctl device driver. 128 | ```bash 129 | $ sudo insmod simple_sysctl.ko 130 | $ cat /proc/sys/rust/example/test # the default value should be 1 131 | $ sudo sh -c "echo 2 > /proc/sys/rust/example/test" # change the value 132 | $ cat /proc/sys/rust/example/test # now the value is 2 133 | $ sudo rmmod simple_sysctl 134 | ``` 135 | There is another way to read/write the sysctl value: 136 | ```bash 137 | $ sysctl rust.example.test # read 138 | $ sudo sysctl -w rust.example.test=2 # write 139 | ``` 140 | 141 | ### sync_example 142 | A simple example to illustrate the use of `Spinlock` and `Mutex`. 143 | ```rust 144 | let mutex_data = sync::Mutex::new(50); 145 | let mut data = mutex_data.lock(); 146 | println!("Data {} is locked by a mutex", *data); 147 | *data = 100; 148 | println!("Now data is {}", *data); 149 | println!("Hello from Rust!"); 150 | ``` 151 | The above code snippet will output like this: 152 | ```bash 153 | [ 424.328154] Mutex is locked! 154 | [ 424.328156] Data 50 is locked by a mutex 155 | [ 424.328158] Now data is 100 156 | [ 424.328158] Hello from Rust! 157 | [ 424.328160] Mutex is dropped! 158 | ``` 159 | 160 | ### smsc95xx 161 | A highly simplified real-world device driver for [LAN9512](https://www.microchip.com/datasheet/LAN9512) USB to Ethernet controller, which is used on Raspberry Pi 3. The implementation resembles the [C version](https://github.com/torvalds/linux/blob/master/drivers/net/usb/smsc95xx.c). 162 | 163 | ## Roadmap 164 | The efforts of writing kernel modules in Rust can be traced back to 2013 (the first commit of [rust.ko](https://github.com/tsgates/rust.ko)), long before Rust's first stable version was released. Here we list some of the objectives that people have already achieved and what we plan to achieve in the future. 165 | - [x] Generate OS-independent machine code by using JSON specification files 166 | - [x] Recompile pre-compiled libraries (core, compiler_builtins, alloc) by using [cargo-xbuild](https://github.com/rust-osdev/cargo-xbuild) 167 | - [x] Generate Rust bindings for kernel headers to reuse existing data structures and functions defined inside the kernel by using [bindgen](https://github.com/rust-lang/rust-bindgen). 168 | - [x] Kernel allocator by using the [GlobalAlloc](https://doc.rust-lang.org/core/alloc/trait.GlobalAlloc.html) trait. 169 | - [x] Kernel synchronizations by reimplementing the synchronization primitives. 170 | - [x] A simple real-world device driver for LAN9512. 171 | - [ ] Minimize the use of unsafe Rust. 172 | - [ ] Find a idiomatic way to define callback functions. 173 | - [ ] Failure recovery. 174 | - [ ] Use static analysis tool to reason about unsafe Rust code. 175 | 176 | ## Acknowledgment 177 | 178 | Thanks to these previous works on writing Linux kernel driver in Rust. Their attempts inspire us a lot. 179 | - `fishinabarrel/linux-kernel-module-rust`: https://github.com/fishinabarrel/linux-kernel-module-rust 180 | - `tsgates/rust.ko`: https://github.com/tsgates/rust.ko 181 | - `kernel-roulette`: https://github.com/souvik1997/kernel-roulette 182 | 183 | ## License 184 | 185 | GPL-2.0 186 | -------------------------------------------------------------------------------- /armv7l-linux-kernel-module.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi-blacklist": [ 3 | "stdcall", 4 | "fastcall", 5 | "vectorcall", 6 | "thiscall", 7 | "win64", 8 | "sysv64" 9 | ], 10 | "arch": "arm", 11 | "data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", 12 | "env": "gnu", 13 | "features": "+strict-align,+v7", 14 | "is-builtin": true, 15 | "linker-flavor": "gcc", 16 | "linker-is-gnu": true, 17 | "llvm-target": "arm-unknown-linux-gnueabi", 18 | "max-atomic-width": 64, 19 | "os": "none", 20 | "panic-strategy": "abort", 21 | "position-independent-executables": true, 22 | "pre-link-args": { 23 | "gcc": [ 24 | "-Wl,--as-needed", 25 | "-Wl,-z,noexecstack" 26 | ] 27 | }, 28 | "relocation-model": "static", 29 | "relro-level": "full", 30 | "target-c-int-width": "32", 31 | "target-endian": "little", 32 | "target-family": "unix", 33 | "target-pointer-width": "32", 34 | "vendor": "unknown" 35 | } 36 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate bindgen; 2 | extern crate cc; 3 | extern crate shlex; 4 | 5 | use std::env; 6 | use std::path::PathBuf; 7 | use std::process::Command; 8 | 9 | const INCLUDED_TYPES: &[&str] = &["file_operations", "ctl_table", "spinlock_t", "mutex", "usb_driver", "usb_device_id", "driver_info"]; 10 | const INCLUDED_FUNCTIONS: &[&str] = &[ 11 | "__register_chrdev", 12 | "__unregister_chrdev", 13 | "_copy_to_user", 14 | "register_sysctl", 15 | "unregister_sysctl_table", 16 | "proc_dointvec_minmax", 17 | "spin_lock", 18 | "usbnet_probe", 19 | "usbnet_disconnect", 20 | "usb_register_driver", 21 | "usb_deregister", 22 | "usbnet_get_endpoints", 23 | "of_get_mac_address", 24 | "skb_pull", 25 | "skb_push", 26 | "skb_trim", 27 | "skb_clone", 28 | "usbnet_skb_return", 29 | "usbnet_read_cmd", 30 | "call_usermodehelper", 31 | "schedule", 32 | //"__purge_module", 33 | //"__rust_delete_module", 34 | ]; 35 | const INCLUDED_VARS: &[&str] = &["__this_module", "THIS_MODULE"]; 36 | 37 | fn main() { 38 | let target = env::var("TARGET").unwrap(); 39 | println!("Target={}", target); 40 | let mut builder = bindgen::Builder::default() 41 | .use_core() 42 | .ctypes_prefix("c_types") 43 | .no_copy(".*") 44 | .derive_default(true) 45 | .rustfmt_bindings(true) 46 | .clang_arg(format!("--target={}", target)); 47 | 48 | let output = String::from_utf8( 49 | Command::new("make") 50 | .arg("-C") 51 | .arg("kernel-cflags-finder") 52 | .arg("-s") 53 | .output() 54 | .unwrap() 55 | .stdout, 56 | ) 57 | .unwrap(); 58 | 59 | Command::new("make") 60 | .arg("-C") 61 | .arg("kernel-cflags-finder") 62 | .arg("clean"); 63 | 64 | println!("get output:{}", output); 65 | // These three arguments are not supported by clang 66 | // output = output.replace("-mapcs", ""); 67 | // output = output.replace("-mno-sched-prolog", ""); 68 | // output = output.replace("-mno-thumb-interwork", ""); 69 | 70 | for arg in shlex::split(&output).unwrap() { 71 | builder = builder.clang_arg(arg.to_string()); 72 | } 73 | 74 | println!("cargo:rerun-if-changed=src/bindgen_helper.h"); 75 | builder = builder.header("src/bindgen_helper.h"); 76 | 77 | for t in INCLUDED_TYPES { 78 | builder = builder.whitelist_type(t); 79 | } 80 | for f in INCLUDED_FUNCTIONS { 81 | builder = builder.whitelist_function(f); 82 | } 83 | for v in INCLUDED_VARS { 84 | builder = builder.whitelist_var(v); 85 | } 86 | let bindings = builder.generate().expect("Unable to generate bindings"); 87 | 88 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 89 | bindings 90 | .write_to_file(out_path.join("bindings.rs")) 91 | .expect("Couldn't write bindings!"); 92 | } 93 | -------------------------------------------------------------------------------- /hello_world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_world" 3 | version = "0.1.0" 4 | authors = ["Li Zhuohua "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["staticlib"] 9 | 10 | [dependencies] 11 | linux-kernel-module = { path = ".." } 12 | 13 | [profile.release] 14 | panic = "abort" 15 | lto = true 16 | 17 | [profile.dev] 18 | panic = "abort" 19 | -------------------------------------------------------------------------------- /hello_world/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := helloworld.o 2 | ifeq ($(RELEASE),1) 3 | BUILD = release 4 | else 5 | BUILD = debug 6 | endif 7 | 8 | ifeq ($(TARGET),armv7l-linux-kernel-module) 9 | helloworld-objs := target/$(TARGET)/$(BUILD)/libhello_world.a 10 | else 11 | helloworld-objs := target/x86_64-linux-kernel-module/$(BUILD)/libhello_world.a 12 | endif 13 | EXTRA_LDFLAGS += --entry=init_module 14 | 15 | ifeq ($(TARGET),armv7l-linux-kernel-module) 16 | CMD_LINE = ARCH=arm CROSS_COMPILE=$(CROSS) 17 | else 18 | KDIR = /lib/modules/$(shell uname -r)/build 19 | CMD_LINE = 20 | endif 21 | 22 | all: 23 | $(MAKE) $(CMD_LINE) -C $(KDIR) M=$(CURDIR) 24 | 25 | clean: 26 | $(MAKE) -C $(KDIR) M=$(CURDIR) clean 27 | -------------------------------------------------------------------------------- /hello_world/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(alloc)] 3 | 4 | extern crate alloc; 5 | use crate::alloc::string::{String, ToString}; 6 | use linux_kernel_module::c_types; 7 | use linux_kernel_module::println; 8 | 9 | struct HelloWorldModule { 10 | message: String, 11 | } 12 | 13 | impl linux_kernel_module::KernelModule for HelloWorldModule { 14 | fn init() -> linux_kernel_module::KernelResult { 15 | println!("Hello from Rust!"); 16 | Ok(HelloWorldModule { 17 | message: "Hello World!".to_string(), 18 | }) 19 | } 20 | } 21 | 22 | impl Drop for HelloWorldModule { 23 | fn drop(&mut self) { 24 | println!("Goodbye from Rust!"); 25 | } 26 | } 27 | 28 | static mut MODULE: Option = None; 29 | 30 | #[no_mangle] 31 | pub extern "C" fn init_module() -> c_types::c_int { 32 | match ::init() { 33 | Ok(m) => { 34 | unsafe { 35 | MODULE = Some(m); 36 | } 37 | return 0; 38 | } 39 | Err(_e) => { 40 | return 1; 41 | } 42 | } 43 | } 44 | 45 | #[no_mangle] 46 | pub extern "C" fn cleanup_module() { 47 | unsafe { 48 | MODULE = None; 49 | } 50 | } 51 | 52 | #[link_section = ".modinfo"] 53 | pub static MODINFO: [u8; 12] = *b"license=GPL\0"; 54 | -------------------------------------------------------------------------------- /kernel-cflags-finder/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Alex Gaynor, Geoffrey Thomas, and other project authors 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License along 14 | # with this program; if not, write to the Free Software Foundation, Inc., 15 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | 17 | ifneq ($(KERNELRELEASE),) 18 | obj-m += dummy.o 19 | clean-files := dummy.c 20 | 21 | # Some systems for installing kernel headers (e.g. Debian's) happen to 22 | # trigger the out-of-tree build code because the kernel headers directly 23 | # actually just recursively invokes another non-arch-specific one. This 24 | # means that they already generate absolute paths for -I by using the 25 | # flags/addtree make functions. Some (e.g. Ubuntu's) do not, and 26 | # generate relative paths. We want absolute paths, but we cannot force 27 | # the out-of-tree build code because it won't work on Debian-style 28 | # kernel headers directory (it will look in the mostly-empty kernel 29 | # headers directory instead of the actual one). So we steal the addtree 30 | # and flags functions from scripts/Kbuild.include, and use them _after_ 31 | # the build system has generated paths - if any remaining paths are 32 | # relative, we make them absolute with respect to CURDIR. (Unlike the 33 | # upstream addtree function, we prefix -I./foo. We also need to fix 34 | # -include ./include/linux/kconfig.h) 35 | our_addtree = $(if $(patsubst -I%,%,$(1)), \ 36 | $(if $(filter-out -I/% -I../%,$(1)),$(patsubst ./%,$(CURDIR)/%,$(patsubst -I%,-I$(CURDIR)/%,$(1))),$(1)),$(1)) 37 | our_flags = $(foreach o,$($(1)),$(call our_addtree,$(o))) 38 | # Clang doesn't support these arguments, just ignoring them seems to be ok 39 | # clang_unsupported = -mapcs -mno-sched-prolog -mno-thumb-interwork 40 | # @echo $(NOSTDINC_FLAGS) $(call our_flags,LINUXINCLUDE) $(filter-out $(clang_unsupported),$(__c_flags)) $(modkern_cflags) 41 | 42 | $(M)/dummy.c: 43 | @echo $(NOSTDINC_FLAGS) $(call our_flags,LINUXINCLUDE) $(__c_flags) $(modkern_cflags) 44 | @touch $@ 45 | 46 | .PHONY: $(M)/dummy.c 47 | else 48 | 49 | ifeq ($(TARGET),armv7l-linux-kernel-module) 50 | CMD_LINE = ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 51 | else 52 | KDIR = /lib/modules/$(shell uname -r)/build 53 | endif 54 | 55 | all: 56 | $(MAKE) CC=clang HOSTCC=clang $(CMD_LINE) -C $(KDIR) M=$(CURDIR) 57 | clean: 58 | $(MAKE) -C $(KDIR) M=$(CURDIR) clean 59 | endif 60 | -------------------------------------------------------------------------------- /simple_sysctl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple_sysctl" 3 | version = "0.1.0" 4 | authors = ["Li Zhuohua "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["staticlib"] 9 | 10 | [dependencies] 11 | linux-kernel-module = { path = ".." } 12 | 13 | [profile.release] 14 | panic = "abort" 15 | lto = true 16 | 17 | [profile.dev] 18 | panic = "abort" 19 | -------------------------------------------------------------------------------- /simple_sysctl/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := simple_sysctl.o 2 | ifeq ($(RELEASE),1) 3 | BUILD = release 4 | else 5 | BUILD = debug 6 | endif 7 | 8 | ifeq ($(TARGET),armv7l-linux-kernel-module) 9 | simple_sysctl-objs := target/$(TARGET)/$(BUILD)/libsimple_sysctl.a 10 | else 11 | simple_sysctl-objs := target/x86_64-linux-kernel-module/$(BUILD)/libsimple_sysctl.a 12 | endif 13 | EXTRA_LDFLAGS += --entry=init_module 14 | 15 | ifeq ($(TARGET),armv7l-linux-kernel-module) 16 | CMD_LINE = ARCH=arm CROSS_COMPILE=$(CROSS) 17 | else 18 | KDIR = /lib/modules/$(shell uname -r)/build 19 | CMD_LINE = 20 | endif 21 | 22 | all: 23 | $(MAKE) $(CMD_LINE) -C $(KDIR) M=$(CURDIR) 24 | 25 | clean: 26 | $(MAKE) -C $(KDIR) M=$(CURDIR) clean 27 | -------------------------------------------------------------------------------- /simple_sysctl/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(alloc)] 3 | 4 | extern crate alloc; 5 | 6 | use crate::alloc::boxed::Box; 7 | use crate::alloc::vec; // import vec! macro 8 | use core::mem; 9 | use linux_kernel_module::bindings; 10 | use linux_kernel_module::c_types; 11 | use linux_kernel_module::println; 12 | 13 | struct Sysctl { 14 | // We must store `table` here, otherwise it will be dropped after `register`. It would be a 15 | // use-after-free 16 | table: Box<[bindings::ctl_table]>, 17 | header: *mut bindings::ctl_table_header, 18 | } 19 | 20 | struct SysctlModule { 21 | sysctl: Sysctl, 22 | } 23 | 24 | extern "C" { 25 | pub fn register_sysctl( 26 | path: *const c_types::c_char, 27 | table: *mut bindings::ctl_table, 28 | ) -> *mut bindings::ctl_table_header; 29 | } 30 | 31 | extern "C" { 32 | pub fn unregister_sysctl_table(table: *mut bindings::ctl_table_header); 33 | } 34 | 35 | extern "C" { 36 | pub fn proc_dointvec_minmax( 37 | arg1: *mut bindings::ctl_table, 38 | arg2: c_types::c_int, 39 | arg3: *mut c_types::c_void, 40 | arg4: *mut usize, 41 | arg5: *mut bindings::loff_t, 42 | ) -> c_types::c_int; 43 | } 44 | 45 | static mut DATA: i32 = 1; 46 | static mut ZERO: i32 = 0; 47 | static mut TWO: i32 = 2; 48 | 49 | impl Sysctl { 50 | fn register(path: &'static str, name: &'static str) -> linux_kernel_module::KernelResult { 51 | let mut tmp = bindings::ctl_table::default(); 52 | tmp.procname = name.as_bytes().as_ptr() as *const i8; 53 | tmp.maxlen = mem::size_of::() as i32; 54 | tmp.mode = 0o644; 55 | tmp.data = unsafe { &mut DATA as *mut i32 as *mut c_types::c_void }; 56 | tmp.proc_handler = Some(proc_dointvec_minmax); 57 | tmp.extra1 = unsafe { &mut ZERO as *mut i32 as *mut c_types::c_void }; 58 | tmp.extra2 = unsafe { &mut TWO as *mut i32 as *mut c_types::c_void }; 59 | let mut table = vec![tmp, unsafe { mem::zeroed() }].into_boxed_slice(); 60 | //println!( 61 | //"procname={}, data={}, maxlen={}, mode={}, proc_handler={:?}, extra1={}, extra2={}, addr of table={:?}, addr of table[0]={:?}", 62 | //unsafe { *table[0].procname }, 63 | //unsafe { *(table[0].data as *mut i32) }, 64 | //table[0].maxlen, 65 | //table[0].mode, 66 | //table[0].proc_handler.unwrap(), 67 | //unsafe { *(table[0].extra1 as *mut i32) }, 68 | //unsafe { *(table[0].extra2 as *mut i32) }, 69 | //table.as_ptr(), 70 | //&table[0] as *const bindings::ctl_table as *const i32, 71 | //); 72 | let header = 73 | unsafe { register_sysctl(path.as_bytes().as_ptr() as *const i8, table.as_mut_ptr()) }; 74 | if header as i32 == 0 { 75 | println!("Error while registring sysctl"); 76 | } 77 | Ok(Sysctl { 78 | table: table, 79 | header: header, 80 | }) 81 | } 82 | } 83 | 84 | impl linux_kernel_module::KernelModule for SysctlModule { 85 | fn init() -> linux_kernel_module::KernelResult { 86 | println!("Hello from Rust!"); 87 | let sysctl = Sysctl::register("rust/example\0", "test\0")?; 88 | Ok(SysctlModule { sysctl: sysctl }) 89 | } 90 | } 91 | 92 | impl Drop for SysctlModule { 93 | fn drop(&mut self) { 94 | println!("Goodbye from Rust!"); 95 | // println!("now header={}", self.sysctl.header as u32); 96 | unsafe { 97 | bindings::unregister_sysctl_table(self.sysctl.header); 98 | } 99 | } 100 | } 101 | 102 | static mut MODULE: Option = None; 103 | 104 | #[no_mangle] 105 | pub extern "C" fn init_module() -> c_types::c_int { 106 | match ::init() { 107 | Ok(m) => { 108 | unsafe { 109 | MODULE = Some(m); 110 | } 111 | return 0; 112 | } 113 | Err(_e) => { 114 | return 1; 115 | } 116 | } 117 | } 118 | 119 | #[no_mangle] 120 | pub extern "C" fn cleanup_module() { 121 | unsafe { 122 | MODULE = None; 123 | } 124 | } 125 | 126 | #[no_mangle] 127 | #[link_section = ".modinfo"] 128 | pub static MODINFO: [u8; 12] = *b"license=GPL\0"; 129 | -------------------------------------------------------------------------------- /smsc9512/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "smsc9512" 3 | version = "0.1.0" 4 | authors = ["Li Zhuohua "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["staticlib"] 9 | 10 | [dependencies] 11 | linux-kernel-module = { path = ".." } 12 | rlibc = "1.0.0" 13 | 14 | [profile.release] 15 | panic = "abort" 16 | lto = true 17 | 18 | [profile.dev] 19 | panic = "abort" 20 | -------------------------------------------------------------------------------- /smsc9512/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := smsc9512.o 2 | ifeq ($(RELEASE),1) 3 | BUILD = release 4 | else 5 | BUILD = debug 6 | endif 7 | 8 | ifeq ($(TARGET),armv7l-linux-kernel-module) 9 | smsc9512-objs := target/$(TARGET)/$(BUILD)/libsmsc9512.a ../src/c_wrapper.o 10 | else 11 | smsc9512-objs := target/x86_64-linux-kernel-module/$(BUILD)/libsmsc9512.a ../src/c_wrapper.o 12 | endif 13 | EXTRA_LDFLAGS += --entry=init_module 14 | 15 | ifeq ($(TARGET),armv7l-linux-kernel-module) 16 | CMD_LINE = ARCH=arm CROSS_COMPILE=$(CROSS) 17 | else 18 | KDIR = /lib/modules/$(shell uname -r)/build 19 | CMD_LINE = 20 | endif 21 | 22 | all: 23 | $(MAKE) $(CMD_LINE) -C $(KDIR) M=$(CURDIR) 24 | 25 | clean: 26 | $(MAKE) -C $(KDIR) M=$(CURDIR) clean 27 | -------------------------------------------------------------------------------- /smsc9512/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(alloc)] 3 | 4 | extern crate alloc; 5 | 6 | use crate::alloc::boxed::Box; 7 | use crate::alloc::vec; // import vec! macro 8 | use core::mem; 9 | use linux_kernel_module::bindings; 10 | use linux_kernel_module::c_types; 11 | use linux_kernel_module::println; 12 | use rlibc; 13 | 14 | const ETH_FRAME_LEN: u32 = 1514; 15 | 16 | struct USBDriver { 17 | _driver_info: Box, 18 | _table: Box<[bindings::usb_device_id]>, 19 | // driver must be stored in a box, why? 20 | driver: Box, 21 | } 22 | 23 | struct Smsc9512Priv { 24 | dev: *mut bindings::usbnet, 25 | } 26 | 27 | unsafe extern "C" fn smsc9512_bind( 28 | dev: *mut bindings::usbnet, 29 | intf: *mut bindings::usb_interface, 30 | ) -> c_types::c_int { 31 | println!("SMSC9512: into smsc9512_bind"); 32 | println!("before constructing pdata"); 33 | let pdata = Box::new(Smsc9512Priv { dev: dev }); 34 | println!("after constructing pdata"); 35 | let ret = bindings::usbnet_get_endpoints(dev, intf); 36 | if ret < 0 { 37 | println!("usbnet_get_endpoints failed: {}", ret); 38 | return ret; 39 | } 40 | (*dev).data[0] = Box::into_raw(pdata) as u32; 41 | 42 | smsc9512_init_mac_address(dev); 43 | 44 | (*(*dev).net).flags |= 1 << 12; // IFF_MULTICAST 45 | (*(*dev).net).hard_header_len += 12; // SMSC95XX_TX_OVERHEAD_CSUM 46 | (*(*dev).net).min_mtu = 68; // ETH_MIN_MTU 47 | (*(*dev).net).max_mtu = 1500; // ETH_DATA_LEN 48 | (*dev).hard_mtu = (*(*dev).net).mtu + (*(*dev).net).hard_header_len as u32; 49 | 50 | 0 51 | } 52 | 53 | fn smsc9512_init_mac_address(dev: *mut bindings::usbnet) { 54 | let mac_addr = unsafe { bindings::of_get_mac_address((*(*dev).udev).dev.of_node) }; 55 | if mac_addr as usize != 0 { 56 | unsafe { 57 | rlibc::memcpy((*(*dev).net).dev_addr, mac_addr as *const u8, 6); 58 | } 59 | println!("MAC got from device tree"); 60 | return; 61 | } 62 | println!("Error in smsc9512_init_mac_address"); 63 | } 64 | 65 | unsafe extern "C" fn smsc9512_unbind( 66 | dev: *mut bindings::usbnet, 67 | _intf: *mut bindings::usb_interface, 68 | ) { 69 | println!("into unbind()"); 70 | let _pdata = Box::from_raw((*dev).data[0] as *mut Smsc9512Priv); 71 | // Smsc9512Priv struct should be freed here 72 | println!("exit unbind()"); 73 | } 74 | 75 | unsafe extern "C" fn smsc9512_rx_fixup( 76 | dev: *mut bindings::usbnet, 77 | skb: *mut bindings::sk_buff, 78 | ) -> c_types::c_int { 79 | if (*skb).len < (*(*dev).net).hard_header_len as u32 { 80 | return 0; 81 | } 82 | 83 | while (*skb).len > 0 { 84 | let mut header: u32 = 0; 85 | rlibc::memcpy( 86 | &mut header as *mut u32 as *mut u8, 87 | (*skb).data, 88 | mem::size_of::(), 89 | ); 90 | bindings::skb_pull(skb, 4 + 2); 91 | let packet = (*skb).data; 92 | 93 | // get the packet length 94 | let size = (header & 0x3FFF0000) >> 16; 95 | let align_count = (4 - ((size + 2) % 4)) % 4; 96 | 97 | if header & 0x00008000 != 0 { 98 | // Error Summary 99 | println!("Error header = 0x{:X}", header); 100 | (*(*dev).net).stats.rx_errors += 1; 101 | (*(*dev).net).stats.rx_dropped += 1; 102 | 103 | if header & 0x00000002 != 0 { 104 | // CRC Error 105 | (*(*dev).net).stats.rx_crc_errors += 1; 106 | } else { 107 | if header & (0x00000080 | 0x00000800) != 0 { 108 | (*(*dev).net).stats.rx_frame_errors += 1; 109 | } 110 | 111 | if (header & 0x00001000 != 0) && (header & 0x00000020) == 0 { 112 | // Length Error 113 | (*(*dev).net).stats.rx_length_errors += 1; 114 | } 115 | } 116 | } else { 117 | if size > (ETH_FRAME_LEN + 12) { 118 | println!("size err header = 0x{:X}", header); 119 | return 0; 120 | } 121 | 122 | // last frame in this batch 123 | if (*skb).len == size { 124 | bindings::skb_trim(skb, (*skb).len - 4); 125 | return 1; 126 | } 127 | 128 | let ax_skb = bindings::skb_clone(skb, 1); 129 | 130 | if ax_skb as u32 == 0 { 131 | println!("Error allocating skb"); 132 | return 0; 133 | } 134 | 135 | (*ax_skb).len = size; 136 | (*ax_skb).data = packet; 137 | skb_set_tail_pointer_wrapper(ax_skb, size as i32); 138 | 139 | bindings::skb_trim(ax_skb, (*ax_skb).len - 4); 140 | bindings::usbnet_skb_return(dev, ax_skb); 141 | } 142 | bindings::skb_pull(skb, size); 143 | 144 | if (*skb).len != 0 { 145 | bindings::skb_pull(skb, align_count); 146 | } 147 | } 148 | 1 149 | } 150 | 151 | extern "C" { 152 | fn skb_set_tail_pointer_wrapper(skb: *const bindings::sk_buff, offset: c_types::c_int); 153 | } 154 | 155 | unsafe extern "C" fn smsc9512_tx_fixup( 156 | _dev: *mut bindings::usbnet, 157 | skb: *mut bindings::sk_buff, 158 | _flags: bindings::gfp_t, 159 | ) -> *mut bindings::sk_buff { 160 | bindings::skb_push(skb, 4); 161 | let tx_cmd_b = (*skb).len - 4; 162 | rlibc::memcpy((*skb).data, &tx_cmd_b as *const u32 as *const u8, 4); 163 | 164 | bindings::skb_push(skb, 4); 165 | let tx_cmd_a = ((*skb).len - 8) | 0x00002000 | 0x00001000; 166 | rlibc::memcpy((*skb).data, &tx_cmd_a as *const u32 as *const u8, 4); 167 | 168 | skb 169 | } 170 | 171 | impl USBDriver { 172 | fn register(name: &'static str) -> linux_kernel_module::KernelResult { 173 | // Construct driver_info structure 174 | println!("before constrcuting driver_info"); 175 | let mut smsc9512_info = Box::new(bindings::driver_info::default()); 176 | println!("after constrcuting driver_info"); 177 | smsc9512_info.description = "smsc9512 USB 2.0 Ethernet\0".as_bytes().as_ptr() as *mut i8; 178 | smsc9512_info.bind = Some(smsc9512_bind); 179 | smsc9512_info.unbind = Some(smsc9512_unbind); 180 | smsc9512_info.rx_fixup = Some(smsc9512_rx_fixup); 181 | smsc9512_info.tx_fixup = Some(smsc9512_tx_fixup); 182 | 183 | // Construct an array of usb_device_id 184 | let mut products = bindings::usb_device_id::default(); 185 | products.match_flags = 3; 186 | products.idVendor = 0x0424; 187 | products.idProduct = 0xec00; 188 | products.driver_info = &(*smsc9512_info) as *const _ as c_types::c_ulong; 189 | println!("driver_info = {:X}", products.driver_info); 190 | println!("before constrcuting table"); 191 | let mut table = vec![products, unsafe { mem::zeroed() }].into_boxed_slice(); 192 | println!( 193 | "usb_device_id = {:X}", 194 | &table[0] as *const _ as c_types::c_ulong 195 | ); 196 | println!("after constrcuting table"); 197 | 198 | // Construct usb_driver structure 199 | println!("before constrcuting usb_driver"); 200 | let mut driver = Box::new(bindings::usb_driver::default()); 201 | println!("after constrcuting usb_driver"); 202 | driver.name = name.as_bytes().as_ptr() as *const i8; 203 | driver.id_table = table.as_mut_ptr(); 204 | driver.probe = Some(bindings::usbnet_probe); 205 | driver.disconnect = Some(bindings::usbnet_disconnect); 206 | 207 | unsafe { 208 | bindings::usb_register_driver( 209 | driver.as_mut(), 210 | &mut bindings::__this_module, 211 | "smsc9512\0".as_bytes().as_ptr() as *const i8, 212 | ); 213 | } 214 | 215 | Ok(USBDriver { 216 | _driver_info: smsc9512_info, 217 | _table: table, 218 | driver: driver, 219 | }) 220 | } 221 | } 222 | 223 | struct USBModule { 224 | usb: USBDriver, 225 | } 226 | 227 | impl linux_kernel_module::KernelModule for USBModule { 228 | fn init() -> linux_kernel_module::KernelResult { 229 | println!("Hello from Rust!"); 230 | let usb = USBDriver::register("smsc9512\0")?; 231 | Ok(USBModule { usb: usb }) 232 | } 233 | } 234 | 235 | impl Drop for USBModule { 236 | fn drop(&mut self) { 237 | println!("Goodbye from Rust!"); 238 | unsafe { 239 | bindings::usb_deregister(self.usb.driver.as_mut()); 240 | } 241 | } 242 | } 243 | 244 | static mut MODULE: Option = None; 245 | 246 | #[no_mangle] 247 | pub extern "C" fn init_module() -> c_types::c_int { 248 | match ::init() { 249 | Ok(m) => { 250 | unsafe { 251 | MODULE = Some(m); 252 | } 253 | return 0; 254 | } 255 | Err(_e) => { 256 | return 1; 257 | } 258 | } 259 | } 260 | 261 | #[no_mangle] 262 | pub extern "C" fn cleanup_module() { 263 | unsafe { 264 | MODULE = None; 265 | } 266 | } 267 | 268 | #[no_mangle] 269 | #[link_section = ".modinfo"] 270 | pub static MODINFO: [u8; 12] = *b"license=GPL\0"; 271 | -------------------------------------------------------------------------------- /src/allocator.rs: -------------------------------------------------------------------------------- 1 | use core::alloc::{GlobalAlloc, Layout}; 2 | 3 | use crate::c_types; 4 | use crate::kernel; 5 | use crate::println; 6 | 7 | pub struct KernelAllocator; 8 | 9 | unsafe impl GlobalAlloc for KernelAllocator { 10 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 11 | return kernel::krealloc( 12 | 0 as *const c_types::c_void, 13 | layout.size(), 14 | kernel::GFP_KERNEL, 15 | ) as *mut u8; 16 | } 17 | 18 | unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { 19 | kernel::kfree(ptr as *const c_types::c_void); 20 | } 21 | } 22 | 23 | #[lang = "oom"] 24 | extern "C" fn oom(_err: Layout) -> ! { 25 | panic!("Out of memory!"); 26 | } 27 | -------------------------------------------------------------------------------- /src/bindgen_helper.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, u16 value, 17 | u16 index, void *data, u16 size); 18 | 19 | void bug_helper(void); 20 | -------------------------------------------------------------------------------- /src/bindings.rs: -------------------------------------------------------------------------------- 1 | #![allow(safe_packed_borrows, non_camel_case_types, non_upper_case_globals, non_snake_case, improper_ctypes)] 2 | 3 | use crate::c_types; 4 | 5 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 6 | -------------------------------------------------------------------------------- /src/c_types.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 Alex Gaynor, Geoffrey Thomas, and other project authors 2 | // 3 | // This program is free software; you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation; either version 2 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License along 14 | // with this program; if not, write to the Free Software Foundation, Inc., 15 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | 17 | #![allow(non_camel_case_types)] 18 | 19 | pub type c_int = i32; 20 | pub type c_char = i8; 21 | // pub type c_long = i64; 22 | pub type c_long = i32; 23 | pub type c_longlong = i64; 24 | pub type c_short = i16; 25 | pub type c_uchar = u8; 26 | pub type c_uint = u32; 27 | // pub type c_ulong = u64; 28 | pub type c_ulong = u32; 29 | pub type c_ulonglong = u64; 30 | pub type c_ushort = u16; 31 | pub type c_schar = i8; 32 | 33 | #[repr(u8)] 34 | pub enum c_void { 35 | #[doc(hidden)] 36 | __nothing_to_see_here, 37 | #[doc(hidden)] 38 | __move_along, 39 | } 40 | -------------------------------------------------------------------------------- /src/c_wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | long copy_to_user_wrapper(void __user *to, const void *from, unsigned long n) { 13 | return _copy_to_user(to, from, n); 14 | } 15 | 16 | void spin_lock_init_wrapper(spinlock_t *lock) { spin_lock_init(lock); } 17 | void spin_lock_wrapper(spinlock_t *lock) { spin_lock(lock); } 18 | void spin_unlock_wrapper(spinlock_t *lock) { spin_unlock(lock); } 19 | 20 | void mutex_init_wrapper(struct mutex *lock) { mutex_init(lock); } 21 | void mutex_lock_wrapper(struct mutex *lock) { mutex_lock(lock); } 22 | void mutex_unlock_wrapper(struct mutex *lock) { mutex_unlock(lock); } 23 | 24 | void skb_set_tail_pointer_wrapper(struct sk_buff *skb, const int offset) { 25 | skb_set_tail_pointer(skb, offset); 26 | } 27 | 28 | int usbnet_read_cmd_wrapper(struct usbnet *dev, u8 cmd, u8 reqtype, u16 value, 29 | u16 index, void *data, u16 size) { 30 | return usbnet_read_cmd(dev, cmd, reqtype, value, index, data, size); 31 | } 32 | 33 | void bug_helper(void) { 34 | schedule(); 35 | } 36 | -------------------------------------------------------------------------------- /src/kernel.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | 3 | use crate::c_types; 4 | 5 | pub type gfp_t = c_types::c_uint; 6 | pub const GFP_KERNEL: gfp_t = 20971712; 7 | 8 | extern "C" { 9 | pub fn krealloc(arg1: *const c_types::c_void, arg2: usize, arg3: gfp_t) 10 | -> *mut c_types::c_void; 11 | } 12 | 13 | extern "C" { 14 | pub fn kfree(arg1: *const c_types::c_void); 15 | } 16 | -------------------------------------------------------------------------------- /src/kernel_module.rs: -------------------------------------------------------------------------------- 1 | use crate::kernel_result::*; 2 | 3 | pub trait KernelModule : Sized { 4 | fn init() -> KernelResult; 5 | } 6 | -------------------------------------------------------------------------------- /src/kernel_result.rs: -------------------------------------------------------------------------------- 1 | pub enum KernelError { 2 | EPERM = 1, // Operation not permitted */ 3 | ENOENT = 2, // No such file or directory */ 4 | ESRCH = 3, // No such process */ 5 | EINTR = 4, // Interrupted system call */ 6 | EIO = 5, // I/O error */ 7 | ENXIO = 6, // No such device or address */ 8 | E2BIG = 7, // Argument list too long */ 9 | ENOEXEC = 8, // Exec format error */ 10 | EBADF = 9, // Bad file number */ 11 | ECHILD = 10, // No child processes */ 12 | EAGAIN = 11, // Try again */ 13 | ENOMEM = 12, // Out of memory */ 14 | EACCES = 13, // Permission denied */ 15 | EFAULT = 14, // Bad address */ 16 | ENOTBLK = 15, // Block device required */ 17 | EBUSY = 16, // Device or resource busy */ 18 | EEXIST = 17, // File exists */ 19 | EXDEV = 18, // Cross-device link */ 20 | ENODEV = 19, // No such device */ 21 | ENOTDIR = 20, // Not a directory */ 22 | EISDIR = 21, // Is a directory */ 23 | EINVAL = 22, // Invalid argument */ 24 | ENFILE = 23, // File table overflow */ 25 | EMFILE = 24, // Too many open files */ 26 | ENOTTY = 25, // Not a typewriter */ 27 | ETXTBSY = 26, // Text file busy */ 28 | EFBIG = 27, // File too large */ 29 | ENOSPC = 28, // No space left on device */ 30 | ESPIPE = 29, // Illegal seek 31 | EROFS = 30, // Read-only file system 32 | EMLINK = 31, // Too many links 33 | EPIPE = 32, // Broken pipe 34 | EDOM = 33, // Math argument out of domain of func 35 | ERANGE = 34, // Math result not representable 36 | } 37 | 38 | pub type KernelResult = Result; 39 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(lang_items, allocator_api)] 3 | 4 | pub mod allocator; 5 | pub mod c_types; 6 | pub mod kernel; 7 | pub mod kernel_module; 8 | pub mod kernel_result; 9 | pub mod printk; 10 | pub mod bindings; 11 | pub mod sync; 12 | pub mod panic; 13 | 14 | pub use self::kernel_module::KernelModule; 15 | pub use self::kernel_result::KernelResult; 16 | pub use self::kernel_result::KernelError; 17 | 18 | #[global_allocator] 19 | static ALLOCATOR: allocator::KernelAllocator = allocator::KernelAllocator; 20 | 21 | #[lang = "eh_personality"] 22 | extern "C" fn eh_personality() {} 23 | 24 | #[no_mangle] 25 | pub extern "C" fn __aeabi_unwind_cpp_pr0() {} 26 | -------------------------------------------------------------------------------- /src/panic.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | use core::panic::PanicInfo; 3 | pub use crate::bindings; 4 | pub use crate::println; 5 | 6 | extern "C" { 7 | fn bug_helper() -> !; 8 | } 9 | 10 | #[panic_handler] 11 | fn panic(_info: &PanicInfo) -> ! { 12 | loop {} 13 | } 14 | -------------------------------------------------------------------------------- /src/printk.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019 Alex Gaynor, Geoffrey Thomas, and other project authors 2 | // 3 | // This program is free software; you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation; either version 2 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License along 14 | // with this program; if not, write to the Free Software Foundation, Inc., 15 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | 17 | use core::{cmp, fmt}; 18 | use crate::c_types; 19 | 20 | extern "C" { 21 | pub fn printk(fmt: *const c_types::c_char, ...) -> c_types::c_int; 22 | } 23 | 24 | const LOG_LINE_MAX: usize = 1024 - 32; 25 | 26 | pub struct LogLineWriter { 27 | data: [u8; LOG_LINE_MAX], 28 | pos: usize, 29 | } 30 | 31 | impl LogLineWriter { 32 | pub fn new() -> LogLineWriter { 33 | LogLineWriter { 34 | data: [0u8; LOG_LINE_MAX], 35 | pos: 0, 36 | } 37 | } 38 | 39 | pub fn as_bytes(&self) -> &[u8] { 40 | return &self.data[..self.pos]; 41 | } 42 | } 43 | 44 | impl fmt::Write for LogLineWriter { 45 | fn write_str(&mut self, s: &str) -> fmt::Result { 46 | let copy_len = cmp::min(LOG_LINE_MAX - self.pos, s.as_bytes().len()); 47 | self.data[self.pos..self.pos + copy_len].copy_from_slice(&s.as_bytes()[..copy_len]); 48 | self.pos += copy_len; 49 | return Ok(()); 50 | } 51 | } 52 | 53 | #[macro_export] 54 | macro_rules! println { 55 | () => {{ 56 | unsafe { 57 | $crate::printk::printk("\n\0".as_bytes().as_ptr() as *const i8); 58 | } 59 | }}; 60 | ($fmt:expr) => {{ 61 | unsafe { 62 | $crate::printk::printk(concat!($fmt, "\n\0").as_bytes().as_ptr() as *const i8); 63 | } 64 | }}; 65 | ($fmt:expr, $($arg:tt)*) => ({ 66 | use ::core::fmt; 67 | let mut writer = $crate::printk::LogLineWriter::new(); 68 | let _ = fmt::write(&mut writer, format_args!(concat!($fmt, "\n\0"), $($arg)*)).unwrap(); 69 | unsafe { 70 | $crate::printk::printk(writer.as_bytes().as_ptr() as *const i8); 71 | } 72 | }); 73 | } 74 | -------------------------------------------------------------------------------- /src/sync.rs: -------------------------------------------------------------------------------- 1 | use core::cell::UnsafeCell; 2 | use core::ops::{Deref, DerefMut, Drop}; 3 | use crate::bindings; 4 | use crate::println; 5 | 6 | extern "C" { 7 | pub fn spin_lock_init_wrapper(lock: *mut bindings::spinlock_t); 8 | pub fn spin_lock_wrapper(lock: *mut bindings::spinlock_t); 9 | pub fn spin_unlock_wrapper(lock: *mut bindings::spinlock_t); 10 | 11 | pub fn mutex_init_wrapper(lock: *mut bindings::mutex); 12 | pub fn mutex_lock_wrapper(lock: *mut bindings::mutex); 13 | pub fn mutex_unlock_wrapper(lock: *mut bindings::mutex); 14 | } 15 | 16 | pub struct Spinlock { 17 | lock: UnsafeCell, 18 | data: UnsafeCell, 19 | } 20 | 21 | pub struct SpinlockGuard<'a, T: ?Sized + 'a> { 22 | lock: &'a mut bindings::spinlock_t, 23 | data: &'a mut T, 24 | } 25 | 26 | unsafe impl Sync for Spinlock {} 27 | unsafe impl Send for Spinlock {} 28 | 29 | impl Spinlock { 30 | pub fn new(user_data: T) -> Spinlock { 31 | let mut lock = bindings::spinlock_t::default(); 32 | unsafe { 33 | spin_lock_init_wrapper(&mut lock); 34 | } 35 | Spinlock { 36 | lock: UnsafeCell::new(lock), 37 | data: UnsafeCell::new(user_data), 38 | } 39 | } 40 | 41 | pub fn lock(&self) -> SpinlockGuard { 42 | unsafe { 43 | spin_lock_wrapper(self.lock.get()); 44 | println!("Spinlock is locked!"); 45 | } 46 | SpinlockGuard { 47 | lock: unsafe { &mut *self.lock.get() }, 48 | data: unsafe { &mut *self.data.get() }, 49 | } 50 | } 51 | } 52 | 53 | impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> { 54 | type Target = T; 55 | fn deref<'b>(&'b self) -> &'b T { 56 | &*self.data 57 | } 58 | } 59 | 60 | impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> { 61 | fn deref_mut<'b>(&'b mut self) -> &'b mut T { 62 | &mut *self.data 63 | } 64 | } 65 | 66 | impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> { 67 | fn drop(&mut self) { 68 | unsafe { spin_unlock_wrapper(self.lock) } 69 | println!("Spinlock is dropped!"); 70 | } 71 | } 72 | 73 | pub struct Mutex { 74 | lock: UnsafeCell, 75 | data: UnsafeCell, 76 | } 77 | 78 | pub struct MutexGuard<'a, T: ?Sized + 'a> { 79 | lock: &'a mut bindings::mutex, 80 | data: &'a mut T, 81 | } 82 | 83 | unsafe impl Sync for Mutex {} 84 | unsafe impl Send for Mutex {} 85 | 86 | impl Mutex { 87 | pub fn new(user_data: T) -> Mutex { 88 | let mut lock = bindings::mutex::default(); 89 | unsafe { 90 | mutex_init_wrapper(&mut lock); 91 | } 92 | Mutex { 93 | lock: UnsafeCell::new(lock), 94 | data: UnsafeCell::new(user_data), 95 | } 96 | } 97 | 98 | pub fn lock(&self) -> MutexGuard { 99 | unsafe { 100 | mutex_lock_wrapper(self.lock.get()); 101 | println!("Mutex is locked!"); 102 | } 103 | MutexGuard { 104 | lock: unsafe { &mut *self.lock.get() }, 105 | data: unsafe { &mut *self.data.get() }, 106 | } 107 | } 108 | } 109 | 110 | impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> { 111 | type Target = T; 112 | fn deref<'b>(&'b self) -> &'b T { 113 | &*self.data 114 | } 115 | } 116 | 117 | impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> { 118 | fn deref_mut<'b>(&'b mut self) -> &'b mut T { 119 | &mut *self.data 120 | } 121 | } 122 | 123 | impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { 124 | fn drop(&mut self) { 125 | unsafe { mutex_unlock_wrapper(self.lock) } 126 | println!("Mutex is dropped!"); 127 | } 128 | } 129 | 130 | pub fn drop(_x: T) { } 131 | -------------------------------------------------------------------------------- /sync_example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sync_example" 3 | version = "0.1.0" 4 | authors = ["Li Zhuohua "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["staticlib"] 9 | 10 | [dependencies] 11 | linux-kernel-module = { path = ".." } 12 | # interrupt = { path = "../interrupt" } 13 | # callback_function = { path = "../callback_function" } 14 | lazy_static = { version = "0.2.11", features = ["spin_no_std"] } 15 | 16 | [profile.release] 17 | panic = "abort" 18 | lto = true 19 | 20 | [profile.dev] 21 | panic = "abort" 22 | -------------------------------------------------------------------------------- /sync_example/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := sync_example.o 2 | ifeq ($(TARGET),armv7l-linux-kernel-module) 3 | sync_example-objs := target/$(TARGET)/debug/libsync_example.a ../src/c_wrapper.o 4 | else 5 | sync_example-objs := target/x86_64-linux-kernel-module/debug/libsync_example.a ../src/c_wrapper.o 6 | endif 7 | EXTRA_LDFLAGS += --entry=init_module 8 | 9 | ifeq ($(TARGET),armv7l-linux-kernel-module) 10 | CMD_LINE = ARCH=arm CROSS_COMPILE=$(CROSS) 11 | else 12 | KDIR = /lib/modules/$(shell uname -r)/build 13 | CMD_LINE = 14 | endif 15 | 16 | all: 17 | $(MAKE) $(CMD_LINE) -C $(KDIR) M=$(CURDIR) 18 | 19 | clean: 20 | $(MAKE) -C $(KDIR) M=$(CURDIR) clean 21 | -------------------------------------------------------------------------------- /sync_example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(alloc)] 3 | #![feature(const_fn)] 4 | #![feature(min_const_fn)] 5 | 6 | // pub mod sync; 7 | 8 | extern crate alloc; 9 | use crate::alloc::string::{String, ToString}; 10 | use lazy_static::*; 11 | use linux_kernel_module::c_types; 12 | use linux_kernel_module::println; 13 | use linux_kernel_module::sync; 14 | use linux_kernel_module::sync::Spinlock; 15 | 16 | struct HelloWorldModule { 17 | message: String, 18 | } 19 | 20 | lazy_static! { 21 | static ref GLOBAL: Spinlock = Spinlock::new(0); 22 | } 23 | 24 | fn global_synchronization_example() { 25 | let mut global = GLOBAL.lock(); 26 | *global = 1; 27 | } 28 | 29 | impl linux_kernel_module::KernelModule for HelloWorldModule { 30 | fn init() -> linux_kernel_module::KernelResult { 31 | global_synchronization_example(); 32 | let spinlock_data = sync::Spinlock::new(100); 33 | println!("Data {} is locked by a spinlock", *spinlock_data.lock()); 34 | let mutex_data = sync::Mutex::new(50); 35 | let mut data = mutex_data.lock(); 36 | println!("Data {} is locked by a mutex", *data); 37 | *data = 100; 38 | println!("Now data is {}", *data); 39 | sync::drop(data); 40 | println!("Hello from Rust!"); 41 | Ok(HelloWorldModule { 42 | message: "Hello World!".to_string(), 43 | }) 44 | } 45 | } 46 | 47 | impl Drop for HelloWorldModule { 48 | fn drop(&mut self) { 49 | println!("My message is {}", self.message); 50 | println!("Goodbye from Rust!"); 51 | } 52 | } 53 | 54 | static mut MODULE: Option = None; 55 | 56 | #[no_mangle] 57 | pub extern "C" fn init_module() -> c_types::c_int { 58 | match ::init() { 59 | Ok(m) => { 60 | unsafe { 61 | MODULE = Some(m); 62 | } 63 | return 0; 64 | } 65 | Err(_e) => { 66 | return 1; 67 | } 68 | } 69 | } 70 | 71 | #[no_mangle] 72 | pub extern "C" fn cleanup_module() { 73 | unsafe { 74 | MODULE = None; 75 | } 76 | } 77 | 78 | #[link_section = ".modinfo"] 79 | pub static MODINFO: [u8; 12] = *b"license=GPL\0"; 80 | -------------------------------------------------------------------------------- /x86_64-linux-kernel-module.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "x86_64", 3 | "cpu": "x86-64", 4 | "code-model": "kernel", 5 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 6 | "disable-redzone": true, 7 | "eliminate-frame-pointer": false, 8 | "env": "gnu", 9 | "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", 10 | "linker-flavor": "gcc", 11 | "linker-is-gnu": true, 12 | "llvm-target": "x86_64-elf", 13 | "max-atomic-width": 64, 14 | "no-compiler-rt": true, 15 | "os": "none", 16 | "panic-strategy": "abort", 17 | "position-independent-executables": true, 18 | "pre-link-args": { 19 | "gcc": [ 20 | "-Wl,--as-needed", 21 | "-Wl,-z,noexecstack", 22 | "-m64" 23 | ] 24 | }, 25 | "relocation-model": "static", 26 | "relro-level": "full", 27 | "target-c-int-width": "32", 28 | "target-endian": "little", 29 | "target-family": "unix", 30 | "target-pointer-width": "64", 31 | "vendor": "unknown", 32 | "needs-plt": true 33 | } 34 | -------------------------------------------------------------------------------- /yes_chardev/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yes_chardev" 3 | version = "0.1.0" 4 | authors = ["Li Zhuohua "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["staticlib"] 9 | 10 | [dependencies] 11 | linux-kernel-module = { path = ".." } 12 | 13 | [profile.release] 14 | panic = "abort" 15 | lto = true 16 | 17 | [profile.dev] 18 | panic = "abort" 19 | -------------------------------------------------------------------------------- /yes_chardev/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := yes_chardev.o 2 | ifeq ($(RELEASE),1) 3 | BUILD = release 4 | else 5 | BUILD = debug 6 | endif 7 | 8 | ifeq ($(TARGET),armv7l-linux-kernel-module) 9 | yes_chardev-objs := target/$(TARGET)/$(BUILD)/libyes_chardev.a ../src/c_wrapper.o 10 | else 11 | yes_chardev-objs := target/x86_64-linux-kernel-module/$(BUILD)/libyes_chardev.a ../src/c_wrapper.o 12 | endif 13 | EXTRA_LDFLAGS += --entry=init_module 14 | 15 | ifeq ($(TARGET),armv7l-linux-kernel-module) 16 | CMD_LINE = ARCH=arm CROSS_COMPILE=$(CROSS) 17 | else 18 | KDIR = /lib/modules/$(shell uname -r)/build 19 | endif 20 | 21 | all: 22 | $(MAKE) $(CMD_LINE) -C $(KDIR) M=$(CURDIR) 23 | 24 | clean: 25 | $(MAKE) -C $(KDIR) M=$(CURDIR) clean 26 | -------------------------------------------------------------------------------- /yes_chardev/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(alloc)] 3 | 4 | extern crate alloc; 5 | 6 | use crate::alloc::boxed::Box; 7 | use linux_kernel_module::bindings; 8 | use linux_kernel_module::c_types; 9 | use linux_kernel_module::println; 10 | 11 | struct CharDevModule { 12 | major: c_types::c_int, 13 | name: &'static str, 14 | fops: Box, 15 | } 16 | 17 | extern "C" { 18 | pub fn __register_chrdev( 19 | major: c_types::c_uint, 20 | baseminor: c_types::c_uint, 21 | count: c_types::c_uint, 22 | name: *const c_types::c_char, 23 | fops: *const bindings::file_operations, 24 | ) -> c_types::c_int; 25 | } 26 | 27 | extern "C" { 28 | pub fn __unregister_chrdev( 29 | major: c_types::c_uint, 30 | baseminor: c_types::c_uint, 31 | count: c_types::c_uint, 32 | name: *const c_types::c_char, 33 | ); 34 | } 35 | 36 | extern "C" { 37 | pub fn copy_to_user_wrapper( 38 | arg1: *mut c_types::c_void, 39 | arg2: *const c_types::c_void, 40 | arg3: c_types::c_ulong, 41 | ) -> c_types::c_ulong; 42 | } 43 | 44 | extern "C" fn my_read( 45 | arg1: *mut bindings::file, 46 | arg2: *mut c_types::c_char, 47 | arg3: usize, 48 | arg4: *mut bindings::loff_t, 49 | ) -> isize { 50 | unsafe { 51 | copy_to_user_wrapper( 52 | arg2 as *mut c_types::c_void, 53 | "y".as_ptr() as *const c_types::c_void, 54 | 1, 55 | ); 56 | } 57 | 1 58 | } 59 | 60 | trait CharDevice: Sized { 61 | fn init(name: &'static str) -> linux_kernel_module::KernelResult; 62 | } 63 | 64 | impl CharDevModule { 65 | fn register(&mut self) -> &mut Self { 66 | self.fops.read = Some(my_read); 67 | self 68 | } 69 | fn build(&mut self) -> i32 { 70 | self.major = unsafe { 71 | __register_chrdev( 72 | 0, 73 | 0, 74 | 256, 75 | self.name.as_bytes().as_ptr() as *const i8, 76 | &*self.fops, 77 | ) 78 | }; 79 | println!("My major number: {}", self.major); 80 | self.major 81 | } 82 | } 83 | 84 | impl CharDevice for CharDevModule { 85 | fn init(name: &'static str) -> linux_kernel_module::KernelResult { 86 | println!("Hello CharDev from Rust!"); 87 | let fops = bindings::file_operations::default(); 88 | Ok(CharDevModule { 89 | fops: Box::new(fops), 90 | major: 0, 91 | name: name, 92 | }) 93 | } 94 | } 95 | 96 | impl Drop for CharDevModule { 97 | fn drop(&mut self) { 98 | println!("Goodbye CharDev from Rust!"); 99 | unsafe { 100 | __unregister_chrdev( 101 | self.major as u32, 102 | 0, 103 | 256, 104 | self.name.as_bytes().as_ptr() as *const i8, 105 | ) 106 | } 107 | } 108 | } 109 | 110 | static mut MODULE: Option = None; 111 | 112 | #[no_mangle] 113 | pub extern "C" fn init_module() -> c_types::c_int { 114 | match ::init("yes\0") { 115 | Ok(mut m) => { 116 | m.register().build(); 117 | unsafe { 118 | MODULE = Some(m); 119 | } 120 | return 0; 121 | } 122 | Err(_e) => { 123 | return 1; 124 | } 125 | } 126 | } 127 | 128 | #[no_mangle] 129 | pub extern "C" fn cleanup_module() { 130 | unsafe { 131 | MODULE = None; 132 | } 133 | } 134 | 135 | #[link_section = ".modinfo"] 136 | pub static MODINFO: [u8; 12] = *b"license=GPL\0"; 137 | --------------------------------------------------------------------------------