1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #pragma once |
4 | |
5 | #include "mos/interrupt/ipi.hpp" |
6 | #include "mos/misc/cmdline.hpp" |
7 | #include "mos/mm/paging/pml_types.hpp" |
8 | #include "mos/mm/physical/pmm.hpp" |
9 | #include "mos/platform/platform_defs.hpp" |
10 | |
11 | #include <mos/allocator.hpp> |
12 | #include <mos/lib/structures/list.hpp> |
13 | #include <mos/lib/sync/spinlock.hpp> |
14 | #include <mos/mm/mm_types.h> |
15 | #include <mos/mos_global.h> |
16 | #include <mos/shared_ptr.hpp> |
17 | #include <mos/tasks/signal_types.h> |
18 | |
19 | // clang-format off |
20 | #if MOS_CONFIG(MOS_SMP) |
21 | #define PER_CPU_DECLARE(type, name) struct name { type percpu_value[MOS_MAX_CPU_COUNT]; } name |
22 | #define PER_CPU_VAR_INIT { .percpu_value = { 0 } } |
23 | #define per_cpu(var) (&(var.percpu_value[platform_current_cpu_id()])) |
24 | #else |
25 | #define PER_CPU_DECLARE(type, name) struct name { type percpu_value[1]; } name |
26 | #define PER_CPU_VAR_INIT { .percpu_value = { 0 } } |
27 | #define per_cpu(var) (&(var.percpu_value[0])) |
28 | #endif |
29 | // clang-format on |
30 | |
31 | #define current_cpu per_cpu(platform_info->cpu) |
32 | #define current_thread (current_cpu->thread) |
33 | #define current_process (current_thread->owner) |
34 | #define current_mm (current_cpu->mm_context) |
35 | |
36 | typedef void (*irq_handler)(u32 irq); |
37 | |
38 | struct Thread; |
39 | struct Console; |
40 | |
41 | enum vm_flags : unsigned int |
42 | { |
43 | VM_NONE = 0, |
44 | VM_READ = MEM_PERM_READ, // 1 << 0 |
45 | VM_WRITE = MEM_PERM_WRITE, // 1 << 1 |
46 | VM_EXEC = MEM_PERM_EXEC, // 1 << 2 |
47 | |
48 | VM_USER = 1 << 3, |
49 | VM_WRITE_THROUGH = 1 << 4, |
50 | VM_CACHE_DISABLED = 1 << 5, |
51 | VM_GLOBAL = 1 << 6, |
52 | |
53 | // composite flags (for convenience) |
54 | VM_RW = VM_READ | VM_WRITE, |
55 | VM_RX = VM_READ | VM_EXEC, |
56 | VM_RWX = VM_READ | VM_WRITE | VM_EXEC, |
57 | VM_USER_RW = VM_USER | VM_RW, |
58 | VM_USER_RX = VM_USER | VM_RX, |
59 | VM_USER_RO = VM_USER | VM_READ, |
60 | VM_USER_RWX = VM_USER | VM_RWX, |
61 | }; |
62 | |
63 | MOS_ENUM_OPERATORS(vm_flags) |
64 | |
65 | typedef enum |
66 | { |
67 | THREAD_STATE_CREATED, ///< created or forked, but not ever started |
68 | THREAD_STATE_READY, ///< thread can be scheduled |
69 | THREAD_STATE_RUNNING, ///< thread is currently running |
70 | THREAD_STATE_BLOCKED, ///< thread is blocked by a wait condition |
71 | THREAD_STATE_NONINTERRUPTIBLE, ///< thread is blocked, and cannot be interrupted |
72 | THREAD_STATE_DEAD, ///< thread is dead, and will be cleaned up soon by the scheduler |
73 | } thread_state_t; |
74 | |
75 | typedef enum |
76 | { |
77 | SWITCH_REGULAR, |
78 | SWITCH_TO_NEW_USER_THREAD, |
79 | SWITCH_TO_NEW_KERNEL_THREAD, |
80 | } switch_flags_t; |
81 | |
82 | MOS_ENUM_OPERATORS(switch_flags_t) |
83 | |
84 | struct MMContext : mos::NamedType<"MMContext" > |
85 | { |
86 | spinlock_t mm_lock; ///< protects [pgd] and the [mmaps] list (the list itself, not the vmap_t objects) |
87 | pgd_t pgd; |
88 | list_head mmaps; |
89 | }; |
90 | |
91 | typedef struct _platform_regs platform_regs_t; |
92 | |
93 | typedef struct |
94 | { |
95 | u32 id; |
96 | Thread *thread; |
97 | ptr_t scheduler_stack; |
98 | MMContext *mm_context; |
99 | platform_regs_t *interrupt_regs; ///< the registers of whatever interrupted this CPU |
100 | platform_cpuinfo_t cpuinfo; |
101 | Thread *idle_thread; ///< idle thread for this CPU |
102 | } cpu_t; |
103 | |
104 | typedef struct |
105 | { |
106 | u8 second; |
107 | u8 minute; |
108 | u8 hour; |
109 | u8 day; |
110 | u8 month; |
111 | u16 year; |
112 | } timeval_t; |
113 | |
114 | typedef struct |
115 | { |
116 | u32 num_cpus; |
117 | u32 boot_cpu_id; |
118 | PER_CPU_DECLARE(cpu_t, cpu); |
119 | |
120 | pfn_t k_basepfn; |
121 | ptr_t k_basevaddr; // virtual address of the kernel base (i.e. the start of the kernel image) |
122 | |
123 | MMContext *kernel_mm; |
124 | |
125 | pfn_t initrd_pfn; |
126 | size_t initrd_npages; |
127 | |
128 | pfn_t max_pfn; |
129 | pmm_region_t pmm_regions[MOS_MAX_MEMREGIONS]; |
130 | size_t num_pmm_regions; |
131 | |
132 | ptr_t direct_map_base; // direct mapping to all physical memory |
133 | |
134 | size_t n_cmdlines; |
135 | cmdline_option_t cmdlines[MOS_MAX_CMDLINE_COUNT]; |
136 | |
137 | platform_arch_info_t arch_info; |
138 | |
139 | Console *boot_console; |
140 | } mos_platform_info_t; |
141 | |
142 | #define MOS_KERNEL_PFN(vaddr) ((ALIGN_DOWN_TO_PAGE((vaddr) - (platform_info->k_basevaddr)) / MOS_PAGE_SIZE) + (platform_info->k_basepfn)) |
143 | |
144 | extern mos_platform_info_t *const platform_info; |
145 | |
146 | typedef struct _platform_process_options platform_process_options_t; |
147 | typedef struct _platform_thread_options platform_thread_options_t; |
148 | |
149 | // should be defined in platform's linker script |
150 | extern const char __MOS_KERNEL_CODE_START[], __MOS_KERNEL_CODE_END[]; // Kernel text |
151 | extern const char __MOS_KERNEL_RODATA_START[], __MOS_KERNEL_RODATA_END[]; // Kernel rodata |
152 | extern const char __MOS_KERNEL_RW_START[], __MOS_KERNEL_RW_END[]; // Kernel read-write data |
153 | extern const char __MOS_KERNEL_END[]; // Kernel end |
154 | |
155 | extern void mos_start_kernel(void); |
156 | |
157 | #define platform_alias(name) __attribute__((alias("platform_default_" #name))) |
158 | |
159 | // Platform Startup APIs |
160 | [[noreturn]] void platform_ap_entry(u64 arg); |
161 | void platform_startup_early(); |
162 | void platform_startup_setup_kernel_mm(); |
163 | void platform_startup_late(); |
164 | |
165 | // Platform Machine APIs |
166 | // default implementation panics |
167 | [[noreturn]] void platform_shutdown(void); |
168 | // default implementations do nothing for 4 functions below |
169 | void platform_dump_regs(platform_regs_t *regs); |
170 | void platform_dump_stack(platform_regs_t *regs); |
171 | void platform_dump_current_stack(); |
172 | void platform_dump_thread_kernel_stack(const Thread *thread); |
173 | |
174 | // Platform Timer/Clock APIs |
175 | // default implementation does nothing |
176 | void platform_get_time(timeval_t *val); |
177 | |
178 | // Platform CPU APIs |
179 | // default implementation loops forever |
180 | [[noreturn]] void platform_halt_cpu(void); |
181 | // default implementation does nothing for 4 functions below |
182 | void platform_invalidate_tlb(ptr_t vaddr); |
183 | u32 platform_current_cpu_id(void); |
184 | void platform_cpu_idle(void); |
185 | u64 platform_get_timestamp(void); |
186 | |
187 | typedef char datetime_str_t[32]; |
188 | datetime_str_t *platform_get_datetime_str(void); |
189 | |
190 | // Platform Interrupt APIs |
191 | // default implementation does nothing |
192 | void platform_interrupt_enable(void); |
193 | void platform_interrupt_disable(void); |
194 | |
195 | // Platform Page Table APIs |
196 | // no default implementation, platform-specific implementations must be provided |
197 | pfn_t platform_pml1e_get_pfn(const pml1e_t *pml1); // returns the physical address contained in the pmlx entry, |
198 | void platform_pml1e_set_pfn(pml1e_t *pml1, pfn_t pfn); // -- which can be a pfn for either a page or another page table |
199 | bool platform_pml1e_get_present(const pml1e_t *pml1); // returns if an entry in this page table is present |
200 | void platform_pml1e_set_flags(pml1e_t *pml1, vm_flags flags); // set bits in the flags field of the pmlx entry |
201 | vm_flags platform_pml1e_get_flags(const pml1e_t *pml1e); // get bits in the flags field of the pmlx entry |
202 | |
203 | #if MOS_PLATFORM_PAGING_LEVELS >= 2 |
204 | pml1_t platform_pml2e_get_pml1(const pml2e_t *pml2); |
205 | void platform_pml2e_set_pml1(pml2e_t *pml2, pml1_t pml1, pfn_t pml1_pfn); |
206 | bool platform_pml2e_get_present(const pml2e_t *pml2); |
207 | void platform_pml2e_set_flags(pml2e_t *pml2, vm_flags flags); |
208 | vm_flags platform_pml2e_get_flags(const pml2e_t *pml2e); |
209 | #if MOS_CONFIG(PML2_HUGE_CAPABLE) |
210 | bool platform_pml2e_is_huge(const pml2e_t *pml2); |
211 | void platform_pml2e_set_huge(pml2e_t *pml2, pfn_t pfn); |
212 | pfn_t platform_pml2e_get_huge_pfn(const pml2e_t *pml2); |
213 | #endif |
214 | #endif |
215 | |
216 | #if MOS_PLATFORM_PAGING_LEVELS >= 3 |
217 | pml2_t platform_pml3e_get_pml2(const pml3e_t *pml3e); |
218 | void platform_pml3e_set_pml2(pml3e_t *pml3e, pml2_t pml2, pfn_t pml2_pfn); |
219 | bool platform_pml3e_get_present(const pml3e_t *pml3e); |
220 | void platform_pml3e_set_flags(pml3e_t *pml3e, vm_flags flags); |
221 | vm_flags platform_pml3e_get_flags(const pml3e_t *pml3e); |
222 | #if MOS_CONFIG(PML3_HUGE_CAPABLE) |
223 | bool platform_pml3e_is_huge(const pml3e_t *pml3e); |
224 | void platform_pml3e_set_huge(pml3e_t *pml3e, pfn_t pfn); |
225 | pfn_t platform_pml3e_get_huge_pfn(const pml3e_t *pml3e); |
226 | #endif |
227 | #endif |
228 | |
229 | #if MOS_PLATFORM_PAGING_LEVELS >= 4 |
230 | pml3_t platform_pml4e_get_pml3(const pml4e_t *pml4); |
231 | void platform_pml4e_set_pml3(pml4e_t *pml4, pml3_t pml3, pfn_t pml3_pfn); |
232 | bool platform_pml4e_get_present(const pml4e_t *pml4); |
233 | void platform_pml4e_set_flags(pml4e_t *pml4, vm_flags flags); |
234 | vm_flags platform_pml4e_get_flags(const pml4e_t *pml4e); |
235 | #if MOS_CONFIG(PML4_HUGE_CAPABLE) |
236 | bool platform_pml4e_is_huge(const pml4e_t *pml4); |
237 | void platform_pml4e_set_huge(pml4e_t *pml4, pfn_t pfn); |
238 | pfn_t platform_pml4e_get_huge_pfn(const pml4e_t *pml4); |
239 | #endif |
240 | #endif |
241 | |
242 | // Platform Thread / Process APIs |
243 | // no default implementation, platform-specific implementations must be provided |
244 | platform_regs_t *platform_thread_regs(Thread *thread); |
245 | void platform_context_setup_main_thread(Thread *thread, ptr_t entry, ptr_t sp, int argc, ptr_t argv, ptr_t envp); |
246 | void platform_context_setup_child_thread(Thread *thread, thread_entry_t entry, void *arg); |
247 | void platform_context_clone(Thread *from, Thread *to); |
248 | void platform_context_cleanup(Thread *thread); |
249 | |
250 | // Platform Context Switching APIs |
251 | // no default implementation, platform-specific implementations must be provided |
252 | void platform_switch_mm(const MMContext *new_mm); |
253 | void platform_switch_to_thread(Thread *current, Thread *new_thread, switch_flags_t switch_flags); |
254 | [[noreturn]] void platform_return_to_userspace(platform_regs_t *regs); |
255 | |
256 | // Platform-Specific syscall APIs |
257 | // default implementation does nothing |
258 | u64 platform_arch_syscall(u64 syscall, u64 arg1, u64 arg2, u64 arg3, u64 arg4); |
259 | |
260 | // Platform-Specific IPI (Inter-Processor Interrupt) APIs |
261 | // default implementation does nothing |
262 | void platform_ipi_send(u8 target_cpu, ipi_type_t type); |
263 | |
264 | // Signal Handler APIs |
265 | // the 4 function below has default implementations that panic if not implemented |
266 | typedef struct _sigreturn_data sigreturn_data_t; |
267 | [[noreturn]] void platform_jump_to_signal_handler(const platform_regs_t *regs, const sigreturn_data_t *sigreturn_data, const sigaction_t *sa); |
268 | [[noreturn]] void platform_restore_from_signal_handler(void *sp); |
269 | void platform_syscall_setup_restart_context(platform_regs_t *regs, reg_t syscall_nr); |
270 | void platform_syscall_store_retval(platform_regs_t *regs, reg_t result); |
271 | |