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 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(kernel.fs_cache_config()),
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 dir.subdir("firmware", dir_mode, |dir| {
307 dir.subdir("android", 0o755, |dir| {
308 dir.entry(
309 "compatible",
310 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
311 mode!(IFREG, 0o444),
312 );
313 dir.subdir("vbmeta", 0o755, |dir| {
314 dir.entry(
315 "parts",
316 StubEmptyFile::new_node(bug_ref!(
317 "https://fxbug.dev/452096300"
318 )),
319 mode!(IFREG, 0o444),
320 );
321 });
322 });
323 });
324 dir.subdir("mcu", dir_mode, |dir| {
325 dir.entry(
326 "board_type",
327 BytesFile::new_node(b"starnix\n".to_vec()),
328 mode!(IFREG, 0o444),
329 );
330 });
331 });
332 });
333 });
334
335 dir.subdir("kernel", dir_mode, |dir| {
336 build_kernel_directory(kernel, dir);
337 });
338
339 dir.subdir("power", 0o755, |dir| {
340 build_power_directory(kernel, dir);
341 });
342
343 dir.subdir("leds", dir_mode, |dir| {
344 dir.entry(
345 "leds",
346 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
347 mode!(IFREG, 0o444),
348 );
349 });
350
351 dir.subdir("module", dir_mode, |dir| {
352 dir.subdir("dm_bufio", dir_mode, |dir| {
353 dir.subdir("parameters", dir_mode, |dir| {
354 dir.entry(
355 "max_age_seconds",
356 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
357 mode!(IFREG, 0o644),
358 );
359 });
360 });
361 dir.subdir("dm_verity", dir_mode, |dir| {
362 dir.subdir("parameters", dir_mode, |dir| {
363 dir.entry(
364 "prefetch_cluster",
365 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/322893670")),
366 mode!(IFREG, 0o644),
367 );
368 });
369 });
370 });
371
372 dir.subdir("devices", dir_mode, |dir| {
374 dir.subdir("system", dir_mode, |dir| {
375 dir.subdir("cpu", dir_mode, build_cpu_class_directory);
376 });
377 dir.subdir("leds", dir_mode, |_dir| {});
378 dir.subdir("platform", dir_mode, |dir| {
379 dir.subdir("soc", dir_mode, |dir| {
380 dir.subdir("1c40000.qcom,spmi", dir_mode, |dir| {
381 dir.subdir("spmi-0", dir_mode, |dir| {
382 dir.subdir("0-00", dir_mode, |dir| {
383 dir.subdir(
384 "1c40000.qcom,spmi:qcom,pm5100@0:qpnp,qbg@4f00",
385 dir_mode,
386 |dir| {
387 dir.subdir("iio:device3", dir_mode, |dir| {
388 dir.entry(
389 "in_resistance_resistance_id_input",
390 StubEmptyFile::new_node(bug_ref!(
391 "https://fxbug.dev/452096300"
392 )),
393 mode!(IFREG, 0o444),
394 );
395 });
396 },
397 );
398 });
399 });
400 });
401 dir.subdir("5e00000.qcom,mdss_mdp", dir_mode, |dir| {
402 dir.subdir("drm", dir_mode, |dir| {
403 dir.subdir("card0", dir_mode, |dir| {
404 dir.subdir("sde-conn-0-DSI-1", dir_mode, |dir| {
405 dir.entry(
406 "display_power_state",
407 StubEmptyFile::new_node(bug_ref!(
408 "https://fxbug.dev/452096300"
409 )),
410 mode!(IFREG, 0o644),
411 );
412 dir.entry(
413 "panel_power_state",
414 StubEmptyFile::new_node(bug_ref!(
415 "https://fxbug.dev/452096300"
416 )),
417 mode!(IFREG, 0o644),
418 );
419 });
420 });
421 });
422 });
423 });
424 });
425 dir.subdir("soc0", dir_mode, |dir| {
426 dir.entry(
427 "revision",
428 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
429 mode!(IFREG, 0o444),
430 );
431 dir.entry(
432 "serial_number",
433 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
434 mode!(IFREG, 0o444),
435 );
436 });
437 dir.subdir("system", dir_mode, |dir| {
438 dir.subdir("cpu", dir_mode, |dir| {
439 dir.entry(
440 "present",
441 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
442 mode!(IFREG, 0o444),
443 );
444 });
445 });
446 dir.subdir("virtual", dir_mode, |dir| {
447 dir.entry(
448 "country",
449 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
450 mode!(IFREG, 0o444),
451 );
452 dir.subdir("leds", dir_mode, |_dir| {});
453 dir.subdir("power_supply", dir_mode, |dir| {
454 dir.subdir("battery", dir_mode, |dir| {
455 dir.entry(
456 "capacity",
457 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
458 mode!(IFREG, 0o444),
459 );
460 dir.entry(
461 "capacity_level",
462 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
463 mode!(IFREG, 0o444),
464 );
465 dir.entry(
466 "status",
467 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
468 mode!(IFREG, 0o444),
469 );
470 });
471 dir.subdir("bms", dir_mode, |dir| {
472 dir.entry(
473 "capacity",
474 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
475 mode!(IFREG, 0o444),
476 );
477 dir.entry(
478 "capacity_level",
479 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
480 mode!(IFREG, 0o444),
481 );
482 dir.entry(
483 "status",
484 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
485 mode!(IFREG, 0o444),
486 );
487 });
488 dir.subdir("usb", dir_mode, |dir| {
489 dir.entry(
490 "capacity",
491 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
492 mode!(IFREG, 0o444),
493 );
494 dir.entry(
495 "capacity_level",
496 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
497 mode!(IFREG, 0o444),
498 );
499 dir.entry(
500 "status",
501 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
502 mode!(IFREG, 0o444),
503 );
504 });
505 });
506 });
507 });
508
509 fs
510 }
511}
512
513struct SysFsHandle(FileSystemHandle);
514
515pub fn sys_fs(
516 locked: &mut Locked<Unlocked>,
517 current_task: &CurrentTask,
518 _options: FileSystemOptions,
519) -> Result<FileSystemHandle, Errno> {
520 Ok(get_sysfs(locked, current_task.kernel()))
521}
522
523pub fn get_sysfs<L>(locked: &mut Locked<L>, kernel: &Kernel) -> FileSystemHandle
524where
525 L: LockEqualOrBefore<FileOpsCore>,
526{
527 kernel
528 .expando
529 .get_or_init(|| SysFsHandle(SysFs::new_fs(locked, kernel, FileSystemOptions::default())))
530 .0
531 .clone()
532}