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
34typedef void (*irq_handler)(u32 irq);
35
36typedef struct _thread thread_t;
37typedef struct _console console_t;
38
39typedef 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
60typedef 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
70typedef enum
71{
72 SWITCH_REGULAR,
73 SWITCH_TO_NEW_USER_THREAD,
74 SWITCH_TO_NEW_KERNEL_THREAD,
75} switch_flags_t;
76
77MOS_ENUM_OPERATORS(switch_flags_t)
78
79typedef 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
86typedef struct _platform_regs platform_regs_t;
87
88typedef 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
99typedef struct
100{
101 u8 second;
102 u8 minute;
103 u8 hour;
104 u8 day;
105 u8 month;
106 u16 year;
107} timeval_t;
108
109typedef 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
139extern mos_platform_info_t *const platform_info;
140
141typedef struct _platform_process_options platform_process_options_t;
142typedef struct _platform_thread_options platform_thread_options_t;
143
144__BEGIN_DECLS
145
146// should be defined in platform's linker script
147extern const char __MOS_KERNEL_CODE_START[], __MOS_KERNEL_CODE_END[]; // Kernel text
148extern const char __MOS_KERNEL_RODATA_START[], __MOS_KERNEL_RODATA_END[]; // Kernel rodata
149extern const char __MOS_KERNEL_RW_START[], __MOS_KERNEL_RW_END[]; // Kernel read-write data
150extern const char __MOS_KERNEL_END[]; // Kernel end
151
152extern void mos_start_kernel(void);
153
154#define platform_alias(name) __attribute__((alias("platform_default_" #name)))
155
156// Platform Startup APIs
157void platform_ap_entry(u64 arg);
158void platform_startup_early();
159void platform_startup_setup_kernel_mm();
160void 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
166void platform_dump_regs(platform_regs_t *regs);
167void platform_dump_stack(platform_regs_t *regs);
168void platform_dump_current_stack();
169void platform_dump_thread_kernel_stack(const thread_t *thread);
170
171// Platform Timer/Clock APIs
172// default implementation does nothing
173void 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
179void platform_invalidate_tlb(ptr_t vaddr);
180u32 platform_current_cpu_id(void);
181void platform_cpu_idle(void);
182u64 platform_get_timestamp(void);
183
184typedef char datetime_str_t[32];
185datetime_str_t *platform_get_datetime_str(void);
186
187// Platform Interrupt APIs
188// default implementation does nothing
189void platform_interrupt_enable(void);
190void platform_interrupt_disable(void);
191
192// Platform Page Table APIs
193// no default implementation, platform-specific implementations must be provided
194pfn_t platform_pml1e_get_pfn(const pml1e_t *pml1); // returns the physical address contained in the pmlx entry,
195void platform_pml1e_set_pfn(pml1e_t *pml1, pfn_t pfn); // -- which can be a pfn for either a page or another page table
196bool platform_pml1e_get_present(const pml1e_t *pml1); // returns if an entry in this page table is present
197void platform_pml1e_set_flags(pml1e_t *pml1, vm_flags flags); // set bits in the flags field of the pmlx entry
198vm_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
201pml1_t platform_pml2e_get_pml1(const pml2e_t *pml2);
202void platform_pml2e_set_pml1(pml2e_t *pml2, pml1_t pml1, pfn_t pml1_pfn);
203bool platform_pml2e_get_present(const pml2e_t *pml2);
204void platform_pml2e_set_flags(pml2e_t *pml2, vm_flags flags);
205vm_flags platform_pml2e_get_flags(const pml2e_t *pml2e);
206#if MOS_CONFIG(PML2_HUGE_CAPABLE)
207bool platform_pml2e_is_huge(const pml2e_t *pml2);
208void platform_pml2e_set_huge(pml2e_t *pml2, pfn_t pfn);
209pfn_t platform_pml2e_get_huge_pfn(const pml2e_t *pml2);
210#endif
211#endif
212
213#if MOS_PLATFORM_PAGING_LEVELS >= 3
214pml2_t platform_pml3e_get_pml2(const pml3e_t *pml3);
215void platform_pml3e_set_pml2(pml3e_t *pml3, pml2_t pml2, pfn_t pml2_pfn);
216bool platform_pml3e_get_present(const pml3e_t *pml3);
217void platform_pml3e_set_flags(pml3e_t *pml3, vm_flags flags);
218vm_flags platform_pml3e_get_flags(const pml3e_t *pml3e);
219#if MOS_CONFIG(PML3_HUGE_CAPABLE)
220bool platform_pml3e_is_huge(const pml3e_t *pml3);
221void platform_pml3e_set_huge(pml3e_t *pml3, pfn_t pfn);
222pfn_t platform_pml3e_get_huge_pfn(const pml3e_t *pml3);
223#endif
224#endif
225
226#if MOS_PLATFORM_PAGING_LEVELS >= 4
227pml3_t platform_pml4e_get_pml3(const pml4e_t *pml4);
228void platform_pml4e_set_pml3(pml4e_t *pml4, pml3_t pml3, pfn_t pml3_pfn);
229bool platform_pml4e_get_present(const pml4e_t *pml4);
230void platform_pml4e_set_flags(pml4e_t *pml4, vm_flags flags);
231vm_flags platform_pml4e_get_flags(const pml4e_t *pml4e);
232#if MOS_CONFIG(PML4_HUGE_CAPABLE)
233bool platform_pml4e_is_huge(const pml4e_t *pml4);
234void platform_pml4e_set_huge(pml4e_t *pml4, pfn_t pfn);
235pfn_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
241platform_regs_t *platform_thread_regs(const thread_t *thread);
242void platform_context_setup_main_thread(thread_t *thread, ptr_t entry, ptr_t sp, int argc, ptr_t argv, ptr_t envp);
243void platform_context_setup_child_thread(thread_t *thread, thread_entry_t entry, void *arg);
244void platform_context_clone(const thread_t *from, thread_t *to);
245void platform_context_cleanup(thread_t *thread);
246
247// Platform Context Switching APIs
248// no default implementation, platform-specific implementations must be provided
249void platform_switch_mm(const mm_context_t *new_mm);
250void 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
255u64 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
259void 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
263typedef 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);
266void platform_syscall_setup_restart_context(platform_regs_t *regs, reg_t syscall_nr);
267void platform_syscall_store_retval(platform_regs_t *regs, reg_t result);
268
269__END_DECLS
270