starnix_core/fs/sysfs/
fs.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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 = &registry.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            // TODO(https://fxbug.dev/434255839): This provides the directory but doesn't provide the
263            // state or control nodes. We should consider whether the USB stack should set
264            // this path up itself if we choose to implement the corresponding HALs.
265            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        // TODO(https://fxbug.dev/425942145): Correctly implement system filesystem in sysfs
348        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}