Skip to content

Commit 06759a2

Browse files
committed
rust: module: add support for module softdep info
Add support for declaring module softdeps in the generated module info. The module macro may now include something like the following: module! { ... softdeps { pre: keywrap, post: sha512, ... } Signed-off-by: Dan Robertson <[email protected]>
1 parent d8c6b9c commit 06759a2

File tree

1 file changed

+168
-96
lines changed

1 file changed

+168
-96
lines changed

rust/macros/module.rs

Lines changed: 168 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3+
use core::fmt;
34
use proc_macro::{token_stream, Delimiter, Group, TokenStream, TokenTree};
45

56
fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
@@ -110,93 +111,6 @@ fn get_byte_string(it: &mut token_stream::IntoIter, expected_name: &str) -> Stri
110111
byte_string
111112
}
112113

113-
fn __build_modinfo_string_base(
114-
module: &str,
115-
field: &str,
116-
content: &str,
117-
variable: &str,
118-
builtin: bool,
119-
) -> String {
120-
let string = if builtin {
121-
// Built-in modules prefix their modinfo strings by `module.`.
122-
format!(
123-
"{module}.{field}={content}",
124-
module = module,
125-
field = field,
126-
content = content
127-
)
128-
} else {
129-
// Loadable modules' modinfo strings go as-is.
130-
format!("{field}={content}", field = field, content = content)
131-
};
132-
133-
format!(
134-
"
135-
{cfg}
136-
#[link_section = \".modinfo\"]
137-
#[used]
138-
pub static {variable}: [u8; {length}] = *b\"{string}\\0\";
139-
",
140-
cfg = if builtin {
141-
"#[cfg(not(MODULE))]"
142-
} else {
143-
"#[cfg(MODULE)]"
144-
},
145-
variable = variable,
146-
length = string.len() + 1,
147-
string = string,
148-
)
149-
}
150-
151-
fn __build_modinfo_string_variable(module: &str, field: &str) -> String {
152-
format!("__{module}_{field}", module = module, field = field)
153-
}
154-
155-
fn build_modinfo_string_only_builtin(module: &str, field: &str, content: &str) -> String {
156-
__build_modinfo_string_base(
157-
module,
158-
field,
159-
content,
160-
&__build_modinfo_string_variable(module, field),
161-
true,
162-
)
163-
}
164-
165-
fn build_modinfo_string_only_loadable(module: &str, field: &str, content: &str) -> String {
166-
__build_modinfo_string_base(
167-
module,
168-
field,
169-
content,
170-
&__build_modinfo_string_variable(module, field),
171-
false,
172-
)
173-
}
174-
175-
fn build_modinfo_string(module: &str, field: &str, content: &str) -> String {
176-
build_modinfo_string_only_builtin(module, field, content)
177-
+ &build_modinfo_string_only_loadable(module, field, content)
178-
}
179-
180-
fn build_modinfo_string_optional(module: &str, field: &str, content: Option<&str>) -> String {
181-
if let Some(content) = content {
182-
build_modinfo_string(module, field, content)
183-
} else {
184-
"".to_string()
185-
}
186-
}
187-
188-
fn build_modinfo_string_param(module: &str, field: &str, param: &str, content: &str) -> String {
189-
let variable = format!(
190-
"__{module}_{field}_{param}",
191-
module = module,
192-
field = field,
193-
param = param
194-
);
195-
let content = format!("{param}:{content}", param = param, content = content);
196-
__build_modinfo_string_base(module, field, &content, &variable, true)
197-
+ &__build_modinfo_string_base(module, field, &content, &variable, false)
198-
}
199-
200114
fn permissions_are_readonly(perms: &str) -> bool {
201115
let (radix, digits) = if let Some(n) = perms.strip_prefix("0x") {
202116
(16, n)
@@ -298,6 +212,118 @@ fn generated_array_ops_name(vals: &str, max_length: usize) -> String {
298212
)
299213
}
300214

215+
struct ModuleInfoStringBuilder<'a> {
216+
counter: usize,
217+
module: &'a str,
218+
}
219+
220+
impl<'a> ModuleInfoStringBuilder<'a> {
221+
fn new(module_str: &'a str) -> ModuleInfoStringBuilder<'a> {
222+
ModuleInfoStringBuilder {
223+
module: module_str,
224+
counter: 0,
225+
}
226+
}
227+
228+
fn build_modinfo_string_base(
229+
&self,
230+
field: &str,
231+
content: &str,
232+
variable: &str,
233+
builtin: bool,
234+
) -> String {
235+
let string = if builtin {
236+
// Built-in modules prefix their modinfo strings by `module.`.
237+
format!(
238+
"{module}.{field}={content}",
239+
module = self.module,
240+
field = field,
241+
content = content
242+
)
243+
} else {
244+
// Loadable modules' modinfo strings go as-is.
245+
format!("{field}={content}", field = field, content = content)
246+
};
247+
248+
format!(
249+
"
250+
{cfg}
251+
#[link_section = \".modinfo\"]
252+
#[used]
253+
pub static {variable}: [u8; {length}] = *b\"{string}\\0\";
254+
",
255+
cfg = if builtin {
256+
"#[cfg(not(MODULE))]"
257+
} else {
258+
"#[cfg(MODULE)]"
259+
},
260+
variable = variable,
261+
length = string.len() + 1,
262+
string = string,
263+
)
264+
}
265+
266+
fn build_modinfo_string_variable(&mut self, field: &str) -> String {
267+
self.counter += 1;
268+
format!(
269+
"__{module}_{field}{counter}",
270+
module = self.module,
271+
field = field,
272+
counter = self.counter,
273+
)
274+
}
275+
276+
fn build_modinfo_string_only_builtin(&mut self, field: &str, content: &str) -> String {
277+
let str_var = self.build_modinfo_string_variable(field);
278+
self.build_modinfo_string_base(field, content, &str_var, true)
279+
}
280+
281+
fn build_modinfo_string_only_loadable(&mut self, field: &str, content: &str) -> String {
282+
let str_var = self.build_modinfo_string_variable(field);
283+
self.build_modinfo_string_base(field, content, &str_var, false)
284+
}
285+
286+
fn build_modinfo_string(&mut self, field: &str, content: &str) -> String {
287+
self.build_modinfo_string_only_builtin(field, content)
288+
+ &self.build_modinfo_string_only_loadable(field, content)
289+
}
290+
291+
fn build_modinfo_string_optional(&mut self, field: &str, content: Option<&str>) -> String {
292+
if let Some(content) = content {
293+
self.build_modinfo_string(field, content)
294+
} else {
295+
"".to_string()
296+
}
297+
}
298+
299+
fn build_modinfo_string_param(&mut self, field: &str, param: &str, content: &str) -> String {
300+
let variable = format!(
301+
"__{module}_{field}_{param}",
302+
module = self.module,
303+
field = field,
304+
param = param
305+
);
306+
let content = format!("{param}:{content}", param = param, content = content);
307+
self.build_modinfo_string_base(field, &content, &variable, true)
308+
+ &self.build_modinfo_string_base(field, &content, &variable, false)
309+
}
310+
}
311+
312+
#[derive(Debug)]
313+
enum Softdep {
314+
Pre(String),
315+
Post(String),
316+
}
317+
318+
impl fmt::Display for Softdep {
319+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320+
match self {
321+
Softdep::Pre(ref module) => write!(f, "pre: {}", module),
322+
Softdep::Post(ref module) => write!(f, "post: {}", module),
323+
}
324+
}
325+
}
326+
301327
#[derive(Debug, Default)]
302328
struct ModuleInfo {
303329
type_: String,
@@ -307,6 +333,7 @@ struct ModuleInfo {
307333
description: Option<String>,
308334
alias: Option<String>,
309335
params: Option<Group>,
336+
softdeps: Option<Vec<Softdep>>,
310337
}
311338

312339
impl ModuleInfo {
@@ -322,6 +349,7 @@ impl ModuleInfo {
322349
"alias",
323350
"alias_rtnl_link",
324351
"params",
352+
"softdeps",
325353
];
326354
const REQUIRED_KEYS: &[&str] = &["type", "name", "license"];
327355
let mut seen_keys = Vec::new();
@@ -353,6 +381,9 @@ impl ModuleInfo {
353381
info.alias = Some(format!("rtnl-link-{}", expect_byte_string(it)))
354382
}
355383
"params" => info.params = Some(expect_group(it)),
384+
"softdeps" => {
385+
info.softdeps = Some(Self::parse_softdeps(expect_group(it)));
386+
}
356387
_ => panic!(
357388
"Unknown key \"{}\". Valid keys are: {:?}.",
358389
key, EXPECTED_KEYS
@@ -388,17 +419,58 @@ impl ModuleInfo {
388419

389420
info
390421
}
422+
423+
fn parse_softdeps(group: Group) -> Vec<Softdep> {
424+
assert_eq!(group.delimiter(), Delimiter::Brace);
425+
426+
let mut it = group.stream().into_iter();
427+
428+
let mut res = vec![];
429+
430+
while let Some(order) = try_ident(&mut it) {
431+
res.push(Self::parse_softdep(&mut it, &order));
432+
}
433+
434+
expect_end(&mut it);
435+
436+
res
437+
}
438+
439+
fn parse_softdep(it: &mut token_stream::IntoIter, order: &str) -> Softdep {
440+
assert_eq!(expect_punct(it), ':');
441+
let module = expect_ident(it);
442+
let softdep = match &*order {
443+
"pre" => Softdep::Pre(module),
444+
"post" => Softdep::Post(module),
445+
_ => panic!("failed to parse invalid softdep '{}: {}", order, module),
446+
};
447+
assert_eq!(expect_punct(it), ',');
448+
softdep
449+
}
450+
451+
fn encode_softdeps<'a>(&self, str_builder: &mut ModuleInfoStringBuilder<'a>) -> String {
452+
match self.softdeps {
453+
Some(ref softdeps) => softdeps.iter().fold(String::new(), |mut acc, new| {
454+
acc.push_str(&str_builder.build_modinfo_string("softdep", &format!("{}", new)));
455+
acc
456+
}),
457+
None => String::new(),
458+
}
459+
}
391460
}
392461

393462
pub fn module(ts: TokenStream) -> TokenStream {
394463
let mut it = ts.into_iter();
395464

396465
let info = ModuleInfo::parse(&mut it);
466+
let mut str_builder = ModuleInfoStringBuilder::new(&info.name);
397467

398468
let name = info.name.clone();
399469

400470
let mut array_types_to_generate = Vec::new();
401471
let mut params_modinfo = String::new();
472+
let softdeps = info.encode_softdeps(&mut str_builder);
473+
402474
if let Some(params) = info.params {
403475
assert_eq!(params.delimiter(), Delimiter::Brace);
404476

@@ -443,14 +515,12 @@ pub fn module(ts: TokenStream) -> TokenStream {
443515
}
444516
};
445517

446-
params_modinfo.push_str(&build_modinfo_string_param(
447-
&name,
518+
params_modinfo.push_str(&str_builder.build_modinfo_string_param(
448519
"parmtype",
449520
&param_name,
450521
&param_kernel_type,
451522
));
452-
params_modinfo.push_str(&build_modinfo_string_param(
453-
&name,
523+
params_modinfo.push_str(&str_builder.build_modinfo_string_param(
454524
"parm",
455525
&param_name,
456526
&param_description,
@@ -672,16 +742,18 @@ pub fn module(ts: TokenStream) -> TokenStream {
672742
{params_modinfo}
673743
674744
{generated_array_types}
745+
{softdeps}
675746
",
676747
type_ = info.type_,
677748
name = info.name,
678-
author = &build_modinfo_string_optional(&name, "author", info.author.as_deref()),
679-
description = &build_modinfo_string_optional(&name, "description", info.description.as_deref()),
680-
license = &build_modinfo_string(&name, "license", &info.license),
681-
alias = &build_modinfo_string_optional(&name, "alias", info.alias.as_deref()),
682-
file = &build_modinfo_string_only_builtin(&name, "file", &file),
749+
author = &str_builder.build_modinfo_string_optional("author", info.author.as_deref()),
750+
description = &str_builder.build_modinfo_string_optional("description", info.description.as_deref()),
751+
license = &str_builder.build_modinfo_string("license", &info.license),
752+
alias = &str_builder.build_modinfo_string_optional("alias", info.alias.as_deref()),
753+
file = &str_builder.build_modinfo_string_only_builtin("file", &file),
683754
params_modinfo = params_modinfo,
684755
generated_array_types = generated_array_types,
756+
softdeps = softdeps,
685757
initcall_section = ".initcall6.init"
686758
).parse().expect("Error parsing formatted string into token stream.")
687759
}

0 commit comments

Comments
 (0)