Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
39867fe
Documentation
LICENSES
arch
block
certs
crypto
drivers
fs
include
init
io_uring
ipc
kernel
lib
mm
net
rust
alloc
bindings
kernel
macros
concat_idents.rs
helpers.rs
lib.rs
module.rs
vtable.rs
.gitignore
Makefile
bindgen_parameters
build_error.rs
compiler_builtins.rs
exports.c
helpers.c
samples
scripts
security
sound
tools
usr
virt
.clang-format
.cocciconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
.rustfmt.toml
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
rust
/
macros
/
module.rs
Blame
Blame
Latest commit
History
History
302 lines (260 loc) · 9.17 KB
Breadcrumbs
linux
/
rust
/
macros
/
module.rs
Top
File metadata and controls
Code
Blame
302 lines (260 loc) · 9.17 KB
Raw
// SPDX-License-Identifier: GPL-2.0 use crate::helpers::*; use proc_macro::{token_stream, Delimiter, Literal, TokenStream, TokenTree}; use std::fmt::Write; fn expect_string_array(it: &mut token_stream::IntoIter) -> Vec<String> { let group = expect_group(it); assert_eq!(group.delimiter(), Delimiter::Bracket); let mut values = Vec::new(); let mut it = group.stream().into_iter(); while let Some(val) = try_string(&mut it) { assert!(val.is_ascii(), "Expected ASCII string"); values.push(val); match it.next() { Some(TokenTree::Punct(punct)) => assert_eq!(punct.as_char(), ','), None => break, _ => panic!("Expected ',' or end of array"), } } values } struct ModInfoBuilder<'a> { module: &'a str, counter: usize, buffer: String, } impl<'a> ModInfoBuilder<'a> { fn new(module: &'a str) -> Self { ModInfoBuilder { module, counter: 0, buffer: String::new(), } } fn emit_base(&mut self, field: &str, content: &str, builtin: bool) { let string = if builtin { // Built-in modules prefix their modinfo strings by `module.`. format!( "{module}.{field}={content}\0", module = self.module, field = field, content = content ) } else { // Loadable modules' modinfo strings go as-is. format!("{field}={content}\0", field = field, content = content) }; write!( &mut self.buffer, " {cfg} #[doc(hidden)] #[link_section = \".modinfo\"] #[used] pub static __{module}_{counter}: [u8; {length}] = *{string}; ", cfg = if builtin { "#[cfg(not(MODULE))]" } else { "#[cfg(MODULE)]" }, module = self.module.to_uppercase(), counter = self.counter, length = string.len(), string = Literal::byte_string(string.as_bytes()), ) .unwrap(); self.counter += 1; } fn emit_only_builtin(&mut self, field: &str, content: &str) { self.emit_base(field, content, true) } fn emit_only_loadable(&mut self, field: &str, content: &str) { self.emit_base(field, content, false) } fn emit(&mut self, field: &str, content: &str) { self.emit_only_builtin(field, content); self.emit_only_loadable(field, content); } } #[derive(Debug, Default)] struct ModuleInfo { type_: String, license: String, name: String, author: Option<String>, description: Option<String>, alias: Option<Vec<String>>, } impl ModuleInfo { fn parse(it: &mut token_stream::IntoIter) -> Self { let mut info = ModuleInfo::default(); const EXPECTED_KEYS: &[&str] = &["type", "name", "author", "description", "license", "alias"]; const REQUIRED_KEYS: &[&str] = &["type", "name", "license"]; let mut seen_keys = Vec::new(); loop { let key = match it.next() { Some(TokenTree::Ident(ident)) => ident.to_string(), Some(_) => panic!("Expected Ident or end"), None => break, }; if seen_keys.contains(&key) { panic!( "Duplicated key \"{}\". Keys can only be specified once.", key ); } assert_eq!(expect_punct(it), ':'); match key.as_str() { "type" => info.type_ = expect_ident(it), "name" => info.name = expect_string_ascii(it), "author" => info.author = Some(expect_string(it)), "description" => info.description = Some(expect_string(it)), "license" => info.license = expect_string_ascii(it), "alias" => info.alias = Some(expect_string_array(it)), _ => panic!( "Unknown key \"{}\". Valid keys are: {:?}.", key, EXPECTED_KEYS ), } assert_eq!(expect_punct(it), ','); seen_keys.push(key); } expect_end(it); for key in REQUIRED_KEYS { if !seen_keys.iter().any(|e| e == key) { panic!("Missing required key \"{}\".", key); } } let mut ordered_keys: Vec<&str> = Vec::new(); for key in EXPECTED_KEYS { if seen_keys.iter().any(|e| e == key) { ordered_keys.push(key); } } if seen_keys != ordered_keys { panic!( "Keys are not ordered as expected. Order them like: {:?}.", ordered_keys ); } info } } pub(crate) fn module(ts: TokenStream) -> TokenStream { let mut it = ts.into_iter(); let info = ModuleInfo::parse(&mut it); let mut modinfo = ModInfoBuilder::new(info.name.as_ref()); if let Some(author) = info.author { modinfo.emit("author", &author); } if let Some(description) = info.description { modinfo.emit("description", &description); } modinfo.emit("license", &info.license); if let Some(aliases) = info.alias { for alias in aliases { modinfo.emit("alias", &alias); } } // Built-in modules also export the `file` modinfo string. let file = std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); modinfo.emit_only_builtin("file", &file); format!( " /// The module name. /// /// Used by the printing macros, e.g. [`info!`]. const __LOG_PREFIX: &[u8] = b\"{name}\\0\"; /// The \"Rust loadable module\" mark, for `scripts/is_rust_module.sh`. // // This may be best done another way later on, e.g. as a new modinfo // key or a new section. For the moment, keep it simple. #[cfg(MODULE)] #[doc(hidden)] #[used] static __IS_RUST_MODULE: () = (); static mut __MOD: Option<{type_}> = None; // SAFETY: `__this_module` is constructed by the kernel at load time and will not be // freed until the module is unloaded. #[cfg(MODULE)] static THIS_MODULE: kernel::ThisModule = unsafe {{ kernel::ThisModule::from_ptr(&kernel::bindings::__this_module as *const _ as *mut _) }}; #[cfg(not(MODULE))] static THIS_MODULE: kernel::ThisModule = unsafe {{ kernel::ThisModule::from_ptr(core::ptr::null_mut()) }}; // Loadable modules need to export the `{{init,cleanup}}_module` identifiers. #[cfg(MODULE)] #[doc(hidden)] #[no_mangle] pub extern \"C\" fn init_module() -> core::ffi::c_int {{ __init() }} #[cfg(MODULE)] #[doc(hidden)] #[no_mangle] pub extern \"C\" fn cleanup_module() {{ __exit() }} // Built-in modules are initialized through an initcall pointer // and the identifiers need to be unique. #[cfg(not(MODULE))] #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))] #[doc(hidden)] #[link_section = \"{initcall_section}\"] #[used] pub static __{name}_initcall: extern \"C\" fn() -> core::ffi::c_int = __{name}_init; #[cfg(not(MODULE))] #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] core::arch::global_asm!( r#\".section \"{initcall_section}\", \"a\" __{name}_initcall: .long __{name}_init - . .previous \"# ); #[cfg(not(MODULE))] #[doc(hidden)] #[no_mangle] pub extern \"C\" fn __{name}_init() -> core::ffi::c_int {{ __init() }} #[cfg(not(MODULE))] #[doc(hidden)] #[no_mangle] pub extern \"C\" fn __{name}_exit() {{ __exit() }} fn __init() -> core::ffi::c_int {{ match <{type_} as kernel::Module>::init(&THIS_MODULE) {{ Ok(m) => {{ unsafe {{ __MOD = Some(m); }} return 0; }} Err(e) => {{ return e.to_kernel_errno(); }} }} }} fn __exit() {{ unsafe {{ // Invokes `drop()` on `__MOD`, which should be used for cleanup. __MOD = None; }} }} {modinfo} ", type_ = info.type_, name = info.name, modinfo = modinfo.buffer, initcall_section = ".initcall6.init" ) .parse() .expect("Error parsing formatted string into token stream.") }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
You can’t perform that action at this time.