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