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