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    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 = &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                    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        // TODO(https://fxbug.dev/425942145): Correctly implement system filesystem in sysfs
373        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}