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