1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/filesystem/sysfs/sysfs.hpp"
4#include "mos/filesystem/sysfs/sysfs_autoinit.hpp"
5#include "mos/mm/mm.hpp"
6#include "mos/mm/paging/paging.hpp"
7#include "mos/mm/physical/pmm.hpp"
8#include "mos/syslog/debug.hpp"
9#include "mos/syslog/syslog.hpp"
10#include "mos/tasks/elf.hpp"
11
12#include <mos/allocator.hpp>
13#include <mos/device/console.hpp>
14#include <mos/filesystem/vfs.hpp>
15#include <mos/interrupt/ipi.hpp>
16#include <mos/ipc/ipc.hpp>
17#include <mos/lib/cmdline.hpp>
18#include <mos/list.hpp>
19#include <mos/misc/cmdline.hpp>
20#include <mos/misc/setup.hpp>
21#include <mos/platform/platform.hpp>
22#include <mos/shared_ptr.hpp>
23#include <mos/syslog/printk.hpp>
24#include <mos/tasks/kthread.hpp>
25#include <mos/tasks/schedule.hpp>
26#include <mos/type_utils.hpp>
27#include <mos_stdio.hpp>
28#include <mos_stdlib.hpp>
29#include <mos_string.hpp>
30
31MMContext mos_kernel_mm;
32
33mos::vector<mos::string> init_args;
34
35static bool init_sysfs_argv(sysfs_file_t *file)
36{
37 for (u32 i = 0; i < init_args.size(); i++)
38 sysfs_printf(file, fmt: "%s ", init_args[i].c_str());
39 sysfs_printf(file, fmt: "\n");
40 return true;
41}
42
43SYSFS_ITEM_RO_STRING(kernel_sysfs_version, MOS_KERNEL_VERSION)
44SYSFS_ITEM_RO_STRING(kernel_sysfs_revision, MOS_KERNEL_REVISION)
45SYSFS_ITEM_RO_STRING(kernel_sysfs_build_date, __DATE__)
46SYSFS_ITEM_RO_STRING(kernel_sysfs_build_time, __TIME__)
47SYSFS_ITEM_RO_STRING(kernel_sysfs_compiler, __VERSION__)
48SYSFS_ITEM_RO_STRING(kernel_sysfs_arch, MOS_ARCH)
49SYSFS_ITEM_RO_STRING(init_sysfs_path, init_args[0].c_str())
50SYSFS_ITEM_RO_PRINTF(initrd_sysfs_info, "pfn: " PFN_FMT "\nnpages: %zu\n", platform_info->initrd_pfn, platform_info->initrd_npages)
51
52static sysfs_item_t kernel_sysfs_items[] = {
53 SYSFS_RO_ITEM("arch", kernel_sysfs_arch), //
54 SYSFS_RO_ITEM("build_date", kernel_sysfs_build_date), //
55 SYSFS_RO_ITEM("build_time", kernel_sysfs_build_time), //
56 SYSFS_RO_ITEM("compiler", kernel_sysfs_compiler), //
57 SYSFS_RO_ITEM("init_argv", init_sysfs_argv), //
58 SYSFS_RO_ITEM("init_path", init_sysfs_path), //
59 SYSFS_RO_ITEM("initrd", initrd_sysfs_info), //
60 SYSFS_RO_ITEM("revision", kernel_sysfs_revision), //
61 SYSFS_RO_ITEM("version", kernel_sysfs_version), //
62};
63
64SYSFS_AUTOREGISTER(kernel, kernel_sysfs_items);
65
66MOS_SETUP("init", setup_init_path)
67{
68 if (arg.empty())
69 {
70 pr_warn("init path not specified");
71 return false;
72 }
73
74 if (init_args.empty())
75 init_args.push_back(value: arg.data());
76 else
77 init_args[0] = arg;
78
79 return true;
80}
81
82MOS_SETUP("init_args", setup_init_args)
83{
84 char *var_arg = strdup(src: arg.data());
85 string_unquote(str: var_arg);
86 for (const auto &cmd : cmdline_parse_vector(inbuf: var_arg, length: strlen(str: var_arg)))
87 init_args.push_back(value: cmd);
88 kfree(ptr: var_arg);
89 return true;
90}
91
92static void setup_sane_environment()
93{
94 platform_startup_early();
95 pmm_init();
96
97 pr_dinfo(vmm, "initializing paging...");
98 mos_kernel_mm.pgd = pgd_create(pml_create_table(MOS_PMLTOP));
99 platform_startup_setup_kernel_mm();
100
101 pr_dinfo(vmm, "mapping kernel space...");
102 mm_map_kernel_pages( //
103 mmctx: platform_info->kernel_mm, //
104 vaddr: (ptr_t) __MOS_KERNEL_CODE_START, //
105 MOS_KERNEL_PFN((ptr_t) __MOS_KERNEL_CODE_START), //
106 ALIGN_UP_TO_PAGE((ptr_t) __MOS_KERNEL_CODE_END - (ptr_t) __MOS_KERNEL_CODE_START) / MOS_PAGE_SIZE, //
107 flags: VM_READ | VM_EXEC | VM_GLOBAL //
108 );
109
110 mm_map_kernel_pages( //
111 mmctx: platform_info->kernel_mm, //
112 vaddr: (ptr_t) __MOS_KERNEL_RODATA_START, //
113 MOS_KERNEL_PFN((ptr_t) __MOS_KERNEL_RODATA_START), //
114 ALIGN_UP_TO_PAGE((ptr_t) __MOS_KERNEL_RODATA_END - (ptr_t) __MOS_KERNEL_RODATA_START) / MOS_PAGE_SIZE, //
115 flags: VM_READ | VM_GLOBAL //
116 );
117
118 mm_map_kernel_pages( //
119 mmctx: platform_info->kernel_mm, //
120 vaddr: (ptr_t) __MOS_KERNEL_RW_START, //
121 MOS_KERNEL_PFN((ptr_t) __MOS_KERNEL_RW_START), //
122 ALIGN_UP_TO_PAGE((ptr_t) __MOS_KERNEL_RW_END - (ptr_t) __MOS_KERNEL_RW_START) / MOS_PAGE_SIZE, //
123 flags: VM_READ | VM_WRITE | VM_GLOBAL //
124 );
125
126 platform_switch_mm(new_mm: platform_info->kernel_mm);
127 slab_init(); // now mos::create<T>, kmalloc<T>, etc. are available
128}
129
130void mos_start_kernel(void)
131{
132 setup_sane_environment();
133 mInfo << "Welcome to MOS!";
134 mInfo << fmt("MOS {}-{} on ({}, {}), compiler {}", MOS_KERNEL_VERSION, MOS_ARCH, MOS_KERNEL_REVISION, __DATE__, __VERSION__);
135
136 if (platform_info->n_cmdlines)
137 {
138 mInfo << "MOS Kernel cmdline";
139 for (u32 i = 0; i < platform_info->n_cmdlines; i++)
140 {
141 const cmdline_option_t *opt = &platform_info->cmdlines[i];
142 if (opt->arg)
143 pr_info2(" %-2d: %-10s = %s", i, opt->name, opt->arg);
144 else
145 pr_info2(" %-2d: %s", i, opt->name);
146 }
147 }
148
149 // power management
150 startup_invoke_autoinit(target: INIT_TARGET_POWER);
151
152 // register builtin filesystems
153 startup_invoke_autoinit(target: INIT_TARGET_PRE_VFS);
154 startup_invoke_autoinit(target: INIT_TARGET_VFS);
155 startup_invoke_autoinit(target: INIT_TARGET_SYSFS);
156
157 platform_startup_late();
158
159 init_args.push_back(MOS_DEFAULT_INIT_PATH);
160 startup_invoke_cmdline_hooks();
161 {
162 const auto ret = vfs_mount(device: "none", path: "/", fs: "tmpfs", NULL);
163 if (ret.isErr())
164 mos_panic("failed to mount rootfs, vfs_mount returns %ld", ret.getErr());
165 }
166 {
167 const auto ret = vfs_mkdir(path: "/initrd");
168 if (ret.isErr())
169 mos_panic("failed to create /initrd, vfs_mkdir returns %ld", ret.getErr());
170 }
171 {
172 const auto ret = vfs_mount(device: "none", path: "/initrd/", fs: "cpiofs", NULL);
173 if (ret.isErr())
174 mos_panic("failed to mount initrd, vfs_mount returns %ld", ret.getErr());
175 }
176 ipc_init();
177 scheduler_init();
178
179 const auto init_con = platform_info->boot_console;
180 if (unlikely(!init_con))
181 mos_panic("failed to get console");
182
183 const stdio_t init_io = { .in = init_con, .out = init_con, .err = init_con };
184 const mos::vector<mos::string> init_envp = {
185 "PATH=/initrd/programs:/initrd/bin:/bin",
186 "HOME=/",
187 "TERM=linux",
188 };
189
190 mInfo << "running '" << init_args[0] << "' as init process.";
191 mInfo << " with arguments:";
192 for (u32 i = 0; i < init_args.size(); i++)
193 mInfo << fmt(" argv[{}] = {}", i, init_args[i].c_str());
194 mInfo << " with environment:";
195 for (u32 i = 0; i < init_envp.size(); i++)
196 mInfo << " " << init_envp[i].c_str();
197
198 const auto init = elf_create_process(path: init_args[0], NULL, argv: init_args, envp: init_envp, ios: &init_io);
199 if (unlikely(!init))
200 mos_panic("failed to create init process");
201
202 const auto m = mm_map_user_pages(mmctx: init->mm, MOS_INITRD_BASE, pfn: platform_info->initrd_pfn, npages: platform_info->initrd_npages, flags: VM_USER_RO, type: VMAP_TYPE_SHARED, content: VMAP_FILE, exact: true);
203 pmm_ref(pfn_start: platform_info->initrd_pfn, npages: platform_info->initrd_npages);
204 pmm_ref(pfn_start: platform_info->initrd_pfn, npages: platform_info->initrd_npages);
205
206 MOS_ASSERT_X(m, "failed to map initrd into init process");
207
208 kthread_init(); // must be called after creating the first init process
209 startup_invoke_autoinit(target: INIT_TARGET_KTHREAD);
210
211 unblock_scheduler();
212
213 mInfo << "\n";
214 enter_scheduler();
215 MOS_UNREACHABLE();
216}
217