Skip to main content

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("powercap", dir_mode, |_dir| {});
217            dir.subdir("udc", dir_mode, |_dir| {});
218        });
219        dir.subdir("dev", dir_mode, |dir| {
220            dir.subdir("char", dir_mode, empty_dir);
221            dir.subdir("block", dir_mode, empty_dir);
222        });
223        dir.subdir("firmware", dir_mode, |dir| {
224            dir.subdir("devicetree", dir_mode, |dir| {
225                dir.subdir("base", dir_mode, |dir| {
226                    dir.subdir("chosen", dir_mode, |dir| {
227                        dir.subdir("plat", dir_mode, |dir| {
228                            if let Some(device_tree) = &kernel.device_tree {
229                                if let Some(product_bytes) =
230                                    device_tree.root_node.find("plat").and_then(|n| {
231                                        n.get_property("product").map(|p| p.value.clone())
232                                    })
233                                {
234                                    let product_bytes = if product_bytes.len() >= 4 {
235                                        product_bytes.to_vec()
236                                    } else {
237                                        let mut padded_bytes = vec![0; 4];
238                                        let start = 4 - product_bytes.len();
239                                        padded_bytes[start..].copy_from_slice(&product_bytes);
240                                        padded_bytes
241                                    };
242                                    dir.entry(
243                                        "product",
244                                        BytesFile::new_node(product_bytes),
245                                        mode!(IFREG, 0o444),
246                                    );
247                                }
248                            }
249                        });
250                        dir.subdir("config", dir_mode, |dir| {
251                            dir.entry(
252                                "pcbcfg",
253                                StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
254                                mode!(IFREG, 0o444),
255                            );
256                        });
257                    });
258                    dir.subdir("firmware", dir_mode, |dir| {
259                        dir.subdir("android", 0o755, |dir| {
260                            dir.entry(
261                                "compatible",
262                                StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
263                                mode!(IFREG, 0o444),
264                            );
265                            dir.subdir("vbmeta", 0o755, |dir| {
266                                dir.entry(
267                                    "parts",
268                                    StubEmptyFile::new_node(bug_ref!(
269                                        "https://fxbug.dev/452096300"
270                                    )),
271                                    mode!(IFREG, 0o444),
272                                );
273                            });
274                        });
275                    });
276                    dir.subdir("mcu", dir_mode, |dir| {
277                        dir.entry(
278                            "board_type",
279                            BytesFile::new_node(b"starnix".to_vec()),
280                            mode!(IFREG, 0o444),
281                        );
282                    });
283                });
284            });
285        });
286
287        dir.subdir("kernel", dir_mode, |dir| {
288            build_kernel_directory(kernel, dir);
289        });
290
291        dir.subdir("power", 0o755, |dir| {
292            build_power_directory(kernel, dir);
293        });
294
295        dir.subdir("leds", dir_mode, |dir| {
296            dir.entry(
297                "leds",
298                StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
299                mode!(IFREG, 0o444),
300            );
301        });
302
303        dir.subdir("module", dir_mode, |dir| {
304            dir.subdir("dm_bufio", dir_mode, |dir| {
305                dir.subdir("parameters", dir_mode, |dir| {
306                    dir.entry(
307                        "max_age_seconds",
308                        StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
309                        mode!(IFREG, 0o644),
310                    );
311                });
312            });
313            dir.subdir("dm_verity", dir_mode, |dir| {
314                dir.subdir("parameters", dir_mode, |dir| {
315                    dir.entry(
316                        "prefetch_cluster",
317                        StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/322893670")),
318                        mode!(IFREG, 0o644),
319                    );
320                });
321            });
322        });
323
324        // TODO(https://fxbug.dev/425942145): Correctly implement system filesystem in sysfs
325        dir.subdir("devices", dir_mode, |dir| {
326            dir.subdir("system", dir_mode, |dir| {
327                dir.subdir("cpu", dir_mode, build_cpu_class_directory);
328            });
329            dir.subdir("leds", dir_mode, |_dir| {});
330            dir.subdir("platform", dir_mode, |dir| {
331                dir.subdir("soc", dir_mode, |dir| {
332                    dir.subdir("1c40000.qcom,spmi", dir_mode, |dir| {
333                        dir.subdir("spmi-0", dir_mode, |dir| {
334                            dir.subdir("0-00", dir_mode, |dir| {
335                                dir.subdir(
336                                    "1c40000.qcom,spmi:qcom,pm5100@0:qpnp,qbg@4f00",
337                                    dir_mode,
338                                    |dir| {
339                                        dir.subdir("iio:device3", dir_mode, |dir| {
340                                            dir.entry(
341                                                "in_resistance_resistance_id_input",
342                                                StubEmptyFile::new_node(bug_ref!(
343                                                    "https://fxbug.dev/452096300"
344                                                )),
345                                                mode!(IFREG, 0o444),
346                                            );
347                                        });
348                                    },
349                                );
350                            });
351                        });
352                    });
353                    dir.subdir("5e00000.qcom,mdss_mdp", dir_mode, |dir| {
354                        dir.subdir("drm", dir_mode, |dir| {
355                            dir.subdir("card0", dir_mode, |dir| {
356                                dir.subdir("sde-conn-0-DSI-1", dir_mode, |dir| {
357                                    dir.entry(
358                                        "display_power_state",
359                                        StubEmptyFile::new_node(bug_ref!(
360                                            "https://fxbug.dev/452096300"
361                                        )),
362                                        mode!(IFREG, 0o644),
363                                    );
364                                    dir.entry(
365                                        "panel_power_state",
366                                        StubEmptyFile::new_node(bug_ref!(
367                                            "https://fxbug.dev/452096300"
368                                        )),
369                                        mode!(IFREG, 0o644),
370                                    );
371                                });
372                            });
373                        });
374                    });
375                });
376            });
377            dir.subdir("soc0", dir_mode, |dir| {
378                dir.entry(
379                    "revision",
380                    StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
381                    mode!(IFREG, 0o444),
382                );
383                dir.entry(
384                    "serial_number",
385                    StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
386                    mode!(IFREG, 0o444),
387                );
388            });
389            dir.subdir("virtual", dir_mode, |dir| {
390                dir.subdir("leds", dir_mode, |_dir| {});
391                dir.subdir("power_supply", dir_mode, |dir| {
392                    dir.subdir("bms", dir_mode, |dir| {
393                        dir.entry(
394                            "capacity",
395                            StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
396                            mode!(IFREG, 0o444),
397                        );
398                        dir.entry(
399                            "capacity_level",
400                            StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
401                            mode!(IFREG, 0o444),
402                        );
403                        dir.entry(
404                            "status",
405                            StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
406                            mode!(IFREG, 0o444),
407                        );
408                    });
409                });
410            });
411        });
412
413        fs
414    }
415}
416
417struct SysFsHandle(FileSystemHandle);
418
419pub fn sys_fs(
420    locked: &mut Locked<Unlocked>,
421    current_task: &CurrentTask,
422    _options: FileSystemOptions,
423) -> Result<FileSystemHandle, Errno> {
424    Ok(get_sysfs(locked, current_task.kernel()))
425}
426
427pub fn get_sysfs<L>(locked: &mut Locked<L>, kernel: &Kernel) -> FileSystemHandle
428where
429    L: LockEqualOrBefore<FileOpsCore>,
430{
431    kernel
432        .expando
433        .get_or_init(|| SysFsHandle(SysFs::new_fs(locked, kernel, FileSystemOptions::default())))
434        .0
435        .clone()
436}