1use crate::fs::sysfs::{build_cpu_class_directory, build_kernel_directory, build_power_directory};
6use crate::task::{CurrentTask, Kernel};
7use crate::vfs::pseudo::simple_directory::SimpleDirectoryMutator;
8use crate::vfs::pseudo::simple_file::BytesFile;
9use crate::vfs::pseudo::stub_empty_file::StubEmptyFile;
10use crate::vfs::{
11 CacheConfig, CacheMode, FileSystem, FileSystemHandle, FileSystemOps, FileSystemOptions, FsStr,
12};
13use ebpf_api::BPF_PROG_TYPE_FUSE;
14use starnix_logging::bug_ref;
15use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, Unlocked};
16use starnix_types::vfs::default_statfs;
17use starnix_uapi::errors::Errno;
18use starnix_uapi::file_mode::mode;
19use starnix_uapi::{SYSFS_MAGIC, statfs};
20
21struct SysFs;
22impl FileSystemOps for SysFs {
23 fn statfs(
24 &self,
25 _locked: &mut Locked<FileOpsCore>,
26 _fs: &FileSystem,
27 _current_task: &CurrentTask,
28 ) -> Result<statfs, Errno> {
29 Ok(default_statfs(SYSFS_MAGIC))
30 }
31 fn name(&self) -> &'static FsStr {
32 "sysfs".into()
33 }
34}
35
36impl SysFs {
37 fn new_fs<L>(
38 locked: &mut Locked<L>,
39 kernel: &Kernel,
40 options: FileSystemOptions,
41 ) -> FileSystemHandle
42 where
43 L: LockEqualOrBefore<FileOpsCore>,
44 {
45 let fs = FileSystem::new(
46 locked,
47 kernel,
48 CacheMode::Cached(CacheConfig::default()),
49 SysFs,
50 options,
51 )
52 .expect("sysfs constructed with valid options");
53
54 fn empty_dir(_: &SimpleDirectoryMutator) {}
55
56 let registry = &kernel.device_registry;
57 let root = ®istry.objects.root;
58 fs.create_root(fs.allocate_ino(), root.clone());
59 let dir = SimpleDirectoryMutator::new(fs.clone(), root.clone());
60
61 let dir_mode = 0o755;
62 dir.subdir("fs", dir_mode, |dir| {
63 dir.subdir("selinux", dir_mode, empty_dir);
64 dir.subdir("bpf", dir_mode, empty_dir);
65 dir.subdir("cgroup", dir_mode, empty_dir);
66 dir.subdir("fuse", dir_mode, |dir| {
67 dir.subdir("connections", dir_mode, empty_dir);
68 dir.subdir("features", dir_mode, |dir| {
69 dir.entry(
70 "fuse_bpf",
71 BytesFile::new_node(b"supported\n".to_vec()),
72 mode!(IFREG, 0o444),
73 );
74 });
75 dir.entry(
76 "bpf_prog_type_fuse",
77 BytesFile::new_node(format!("{}\n", BPF_PROG_TYPE_FUSE).into_bytes()),
78 mode!(IFREG, 0o444),
79 );
80 });
81 dir.subdir("pstore", dir_mode, empty_dir);
82 });
83
84 dir.subdir("block", dir_mode, |dir| {
85 dir.subdir("zram0", dir_mode, |dir| {
86 dir.entry(
87 "backing_dev",
88 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
89 mode!(IFREG, 0o444),
90 );
91 dir.entry(
92 "recomp_algorithm",
93 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
94 mode!(IFREG, 0o444),
95 );
96 dir.entry(
97 "recompress",
98 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
99 mode!(IFREG, 0o444),
100 );
101 });
102 });
103
104 dir.subdir("bus", dir_mode, |dir| {
105 dir.subdir("mmc", dir_mode, |dir| {
106 dir.subdir("devices", dir_mode, |dir| {
107 dir.subdir("mmc0:0001", dir_mode, |dir| {
108 dir.subdir("block", dir_mode, |dir| {
109 dir.subdir("mmcblk0", dir_mode, |dir| {
110 dir.entry(
111 "size",
112 StubEmptyFile::new_node(bug_ref!(
113 "https://fxbug.dev/452096300"
114 )),
115 mode!(IFREG, 0o444),
116 );
117 });
118 });
119 });
120 });
121 });
122 dir.subdir("platform", dir_mode, |dir| {
123 dir.subdir("drivers", dir_mode, |dir| {
124 dir.entry(
125 "trusty",
126 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
127 mode!(IFREG, 0o444),
128 );
129 });
130 });
131 });
132
133 dir.subdir("class", dir_mode, |dir| {
134 dir.subdir("backlight", dir_mode, |dir| {
135 dir.subdir("panel0-backlight", dir_mode, |dir| {
136 dir.entry(
137 "brightness",
138 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
139 mode!(IFREG, 0o444),
140 );
141 });
142 });
143 dir.subdir("bdi", dir_mode, |dir| {
144 dir.subdir("0:80", dir_mode, |dir| {
145 dir.entry(
146 "max_ratio",
147 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
148 mode!(IFREG, 0o444),
149 );
150 dir.entry(
151 "read_ahead_kb",
152 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
153 mode!(IFREG, 0o444),
154 );
155 });
156 });
157 dir.subdir("mmc_host", dir_mode, |dir| {
158 dir.subdir("mmc0", dir_mode, |dir| {
159 dir.subdir("mmc0:0001", dir_mode, |dir| {
160 dir.entry(
161 "fwrev",
162 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
163 mode!(IFREG, 0o444),
164 );
165 dir.entry(
166 "hwrev",
167 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
168 mode!(IFREG, 0o444),
169 );
170 dir.entry(
171 "life_time",
172 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
173 mode!(IFREG, 0o444),
174 );
175 dir.entry(
176 "manfid",
177 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
178 mode!(IFREG, 0o444),
179 );
180 dir.entry(
181 "pre_eol_info",
182 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
183 mode!(IFREG, 0o444),
184 );
185 dir.entry(
186 "serial",
187 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
188 mode!(IFREG, 0o444),
189 );
190 });
191 });
192 });
193 dir.subdir("net", dir_mode, |dir| {
194 dir.subdir("eth0", dir_mode, |dir| {
195 dir.entry(
196 "address",
197 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
198 mode!(IFREG, 0o444),
199 );
200 });
201 dir.subdir("sit0", dir_mode, |dir| {
202 dir.entry(
203 "address",
204 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
205 mode!(IFREG, 0o444),
206 );
207 });
208 dir.subdir("wlan0", dir_mode, |dir| {
209 dir.entry(
210 "address",
211 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
212 mode!(IFREG, 0o444),
213 );
214 });
215 });
216 dir.subdir("power_supply", dir_mode, |dir| {
217 dir.subdir("battery", dir_mode, |dir| {
218 dir.entry(
219 "charge_counter",
220 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
221 mode!(IFREG, 0o444),
222 );
223 dir.entry(
224 "charge_full",
225 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
226 mode!(IFREG, 0o444),
227 );
228 dir.entry(
229 "charge_full_design",
230 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
231 mode!(IFREG, 0o444),
232 );
233 dir.entry(
234 "current_now",
235 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
236 mode!(IFREG, 0o444),
237 );
238 dir.entry(
239 "resistance",
240 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
241 mode!(IFREG, 0o444),
242 );
243 dir.entry(
244 "time_to_empty_avg",
245 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
246 mode!(IFREG, 0o444),
247 );
248 dir.entry(
249 "time_to_full_now",
250 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
251 mode!(IFREG, 0o444),
252 );
253 dir.entry(
254 "voltage_now",
255 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
256 mode!(IFREG, 0o444),
257 );
258 });
259 });
260 dir.subdir("powercap", dir_mode, |_dir| {});
261 dir.subdir("udc", dir_mode, |_dir| {});
262 dir.subdir("android_usb", dir_mode, empty_dir);
266 });
267 dir.subdir("dev", dir_mode, |dir| {
268 dir.subdir("char", dir_mode, empty_dir);
269 dir.subdir("block", dir_mode, empty_dir);
270 });
271 dir.subdir("firmware", dir_mode, |dir| {
272 dir.subdir("devicetree", dir_mode, |dir| {
273 dir.subdir("base", dir_mode, |dir| {
274 dir.subdir("chosen", dir_mode, |dir| {
275 dir.subdir("plat", dir_mode, |dir| {
276 if let Some(device_tree) = &kernel.device_tree {
277 if let Some(product_bytes) =
278 device_tree.root_node.find("plat").and_then(|n| {
279 n.get_property("product").map(|p| p.value.clone())
280 })
281 {
282 let product_bytes = if product_bytes.len() >= 4 {
283 product_bytes.to_vec()
284 } else {
285 let mut padded_bytes = vec![0; 4];
286 let start = 4 - product_bytes.len();
287 padded_bytes[start..].copy_from_slice(&product_bytes);
288 padded_bytes
289 };
290 dir.entry(
291 "product",
292 BytesFile::new_node(product_bytes),
293 mode!(IFREG, 0o444),
294 );
295 }
296 }
297 });
298 dir.subdir("config", dir_mode, |dir| {
299 dir.entry(
300 "pcbcfg",
301 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
302 mode!(IFREG, 0o444),
303 );
304 });
305 });
306 });
307 });
308 });
309
310 dir.subdir("kernel", dir_mode, |dir| {
311 build_kernel_directory(kernel, dir);
312 });
313
314 dir.subdir("power", 0o755, |dir| {
315 build_power_directory(kernel, dir);
316 });
317
318 dir.subdir("leds", dir_mode, |dir| {
319 dir.entry(
320 "leds",
321 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
322 mode!(IFREG, 0o444),
323 );
324 });
325
326 dir.subdir("module", dir_mode, |dir| {
327 dir.subdir("dm_bufio", dir_mode, |dir| {
328 dir.subdir("parameters", dir_mode, |dir| {
329 dir.entry(
330 "max_age_seconds",
331 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
332 mode!(IFREG, 0o644),
333 );
334 });
335 });
336 dir.subdir("dm_verity", dir_mode, |dir| {
337 dir.subdir("parameters", dir_mode, |dir| {
338 dir.entry(
339 "prefetch_cluster",
340 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/322893670")),
341 mode!(IFREG, 0o644),
342 );
343 });
344 });
345 });
346
347 dir.subdir("devices", dir_mode, |dir| {
349 dir.subdir("system", dir_mode, |dir| {
350 dir.subdir("cpu", dir_mode, build_cpu_class_directory);
351 });
352 dir.subdir("leds", dir_mode, |_dir| {});
353 dir.subdir("platform", dir_mode, |dir| {
354 dir.subdir("soc", dir_mode, |dir| {
355 dir.subdir("1c40000.qcom,spmi", dir_mode, |dir| {
356 dir.subdir("spmi-0", dir_mode, |dir| {
357 dir.subdir("0-00", dir_mode, |dir| {
358 dir.subdir(
359 "1c40000.qcom,spmi:qcom,pm5100@0:qpnp,qbg@4f00",
360 dir_mode,
361 |dir| {
362 dir.subdir("iio:device3", dir_mode, |dir| {
363 dir.entry(
364 "in_resistance_resistance_id_input",
365 StubEmptyFile::new_node(bug_ref!(
366 "https://fxbug.dev/452096300"
367 )),
368 mode!(IFREG, 0o444),
369 );
370 });
371 },
372 );
373 });
374 });
375 });
376 dir.subdir("5e00000.qcom,mdss_mdp", dir_mode, |dir| {
377 dir.subdir("drm", dir_mode, |dir| {
378 dir.subdir("card0", dir_mode, |dir| {
379 dir.subdir("sde-conn-0-DSI-1", dir_mode, |dir| {
380 dir.entry(
381 "display_power_state",
382 StubEmptyFile::new_node(bug_ref!(
383 "https://fxbug.dev/452096300"
384 )),
385 mode!(IFREG, 0o644),
386 );
387 dir.entry(
388 "panel_power_state",
389 StubEmptyFile::new_node(bug_ref!(
390 "https://fxbug.dev/452096300"
391 )),
392 mode!(IFREG, 0o644),
393 );
394 });
395 });
396 });
397 });
398 });
399 });
400 dir.subdir("soc0", dir_mode, |dir| {
401 dir.entry(
402 "revision",
403 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
404 mode!(IFREG, 0o444),
405 );
406 dir.entry(
407 "serial_number",
408 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
409 mode!(IFREG, 0o444),
410 );
411 });
412 dir.subdir("system", dir_mode, |dir| {
413 dir.subdir("cpu", dir_mode, |dir| {
414 dir.entry(
415 "present",
416 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
417 mode!(IFREG, 0o444),
418 );
419 });
420 });
421 dir.subdir("virtual", dir_mode, |dir| {
422 dir.entry(
423 "country",
424 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
425 mode!(IFREG, 0o444),
426 );
427 dir.subdir("leds", dir_mode, |_dir| {});
428 dir.subdir("power_supply", dir_mode, |dir| {
429 dir.subdir("battery", dir_mode, |dir| {
430 dir.entry(
431 "capacity",
432 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
433 mode!(IFREG, 0o444),
434 );
435 dir.entry(
436 "capacity_level",
437 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
438 mode!(IFREG, 0o444),
439 );
440 dir.entry(
441 "status",
442 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
443 mode!(IFREG, 0o444),
444 );
445 });
446 dir.subdir("bms", dir_mode, |dir| {
447 dir.entry(
448 "capacity",
449 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
450 mode!(IFREG, 0o444),
451 );
452 dir.entry(
453 "capacity_level",
454 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
455 mode!(IFREG, 0o444),
456 );
457 dir.entry(
458 "status",
459 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
460 mode!(IFREG, 0o444),
461 );
462 });
463 dir.subdir("usb", dir_mode, |dir| {
464 dir.entry(
465 "capacity",
466 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
467 mode!(IFREG, 0o444),
468 );
469 dir.entry(
470 "capacity_level",
471 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
472 mode!(IFREG, 0o444),
473 );
474 dir.entry(
475 "status",
476 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
477 mode!(IFREG, 0o444),
478 );
479 });
480 });
481 });
482 });
483
484 fs
485 }
486}
487
488struct SysFsHandle(FileSystemHandle);
489
490pub fn sys_fs(
491 locked: &mut Locked<Unlocked>,
492 current_task: &CurrentTask,
493 _options: FileSystemOptions,
494) -> Result<FileSystemHandle, Errno> {
495 Ok(get_sysfs(locked, current_task.kernel()))
496}
497
498pub fn get_sysfs<L>(locked: &mut Locked<L>, kernel: &Kernel) -> FileSystemHandle
499where
500 L: LockEqualOrBefore<FileOpsCore>,
501{
502 kernel
503 .expando
504 .get_or_init(|| SysFsHandle(SysFs::new_fs(locked, kernel, FileSystemOptions::default())))
505 .0
506 .clone()
507}