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
36typedef void (*irq_handler)(u32 irq);
37
38struct Thread;
39struct Console;
40
41enum 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
63MOS_ENUM_OPERATORS(vm_flags)
64
65typedef 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
75typedef enum
76{
77 SWITCH_REGULAR,
78 SWITCH_TO_NEW_USER_THREAD,
79 SWITCH_TO_NEW_KERNEL_THREAD,
80} switch_flags_t;
81
82MOS_ENUM_OPERATORS(switch_flags_t)
83
84struct 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
91typedef struct _platform_regs platform_regs_t;
92
93typedef 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
104typedef struct
105{
106 u8 second;
107 u8 minute;
108 u8 hour;
109 u8 day;
110 u8 month;
111 u16 year;
112} timeval_t;
113
114typedef 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
144extern mos_platform_info_t *const platform_info;
145
146typedef struct _platform_process_options platform_process_options_t;
147typedef struct _platform_thread_options platform_thread_options_t;
148
149// should be defined in platform's linker script
150extern const char __MOS_KERNEL_CODE_START[], __MOS_KERNEL_CODE_END[]; // Kernel text
151extern const char __MOS_KERNEL_RODATA_START[], __MOS_KERNEL_RODATA_END[]; // Kernel rodata
152extern const char __MOS_KERNEL_RW_START[], __MOS_KERNEL_RW_END[]; // Kernel read-write data
153extern const char __MOS_KERNEL_END[]; // Kernel end
154
155extern 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);
161void platform_startup_early();
162void platform_startup_setup_kernel_mm();
163void 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
169void platform_dump_regs(platform_regs_t *regs);
170void platform_dump_stack(platform_regs_t *regs);
171void platform_dump_current_stack();
172void platform_dump_thread_kernel_stack(const Thread *thread);
173
174// Platform Timer/Clock APIs
175// default implementation does nothing
176void 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
182void platform_invalidate_tlb(ptr_t vaddr);
183u32 platform_current_cpu_id(void);
184void platform_cpu_idle(void);
185u64 platform_get_timestamp(void);
186
187typedef char datetime_str_t[32];
188datetime_str_t *platform_get_datetime_str(void);
189
190// Platform Interrupt APIs
191// default implementation does nothing
192void platform_interrupt_enable(void);
193void platform_interrupt_disable(void);
194
195// Platform Page Table APIs
196// no default implementation, platform-specific implementations must be provided
197pfn_t platform_pml1e_get_pfn(const pml1e_t *pml1); // returns the physical address contained in the pmlx entry,
198void platform_pml1e_set_pfn(pml1e_t *pml1, pfn_t pfn); // -- which can be a pfn for either a page or another page table
199bool platform_pml1e_get_present(const pml1e_t *pml1); // returns if an entry in this page table is present
200void platform_pml1e_set_flags(pml1e_t *pml1, vm_flags flags); // set bits in the flags field of the pmlx entry
201vm_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
204pml1_t platform_pml2e_get_pml1(const pml2e_t *pml2);
205void platform_pml2e_set_pml1(pml2e_t *pml2, pml1_t pml1, pfn_t pml1_pfn);
206bool platform_pml2e_get_present(const pml2e_t *pml2);
207void platform_pml2e_set_flags(pml2e_t *pml2, vm_flags flags);
208vm_flags platform_pml2e_get_flags(const pml2e_t *pml2e);
209#if MOS_CONFIG(PML2_HUGE_CAPABLE)
210bool platform_pml2e_is_huge(const pml2e_t *pml2);
211void platform_pml2e_set_huge(pml2e_t *pml2, pfn_t pfn);
212pfn_t platform_pml2e_get_huge_pfn(const pml2e_t *pml2);
213#endif
214#endif
215
216#if MOS_PLATFORM_PAGING_LEVELS >= 3
217pml2_t platform_pml3e_get_pml2(const pml3e_t *pml3e);
218void platform_pml3e_set_pml2(pml3e_t *pml3e, pml2_t pml2, pfn_t pml2_pfn);
219bool platform_pml3e_get_present(const pml3e_t *pml3e);
220void platform_pml3e_set_flags(pml3e_t *pml3e, vm_flags flags);
221vm_flags platform_pml3e_get_flags(const pml3e_t *pml3e);
222#if MOS_CONFIG(PML3_HUGE_CAPABLE)
223bool platform_pml3e_is_huge(const pml3e_t *pml3e);
224void platform_pml3e_set_huge(pml3e_t *pml3e, pfn_t pfn);
225pfn_t platform_pml3e_get_huge_pfn(const pml3e_t *pml3e);
226#endif
227#endif
228
229#if MOS_PLATFORM_PAGING_LEVELS >= 4
230pml3_t platform_pml4e_get_pml3(const pml4e_t *pml4);
231void platform_pml4e_set_pml3(pml4e_t *pml4, pml3_t pml3, pfn_t pml3_pfn);
232bool platform_pml4e_get_present(const pml4e_t *pml4);
233void platform_pml4e_set_flags(pml4e_t *pml4, vm_flags flags);
234vm_flags platform_pml4e_get_flags(const pml4e_t *pml4e);
235#if MOS_CONFIG(PML4_HUGE_CAPABLE)
236bool platform_pml4e_is_huge(const pml4e_t *pml4);
237void platform_pml4e_set_huge(pml4e_t *pml4, pfn_t pfn);
238pfn_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
244platform_regs_t *platform_thread_regs(Thread *thread);
245void platform_context_setup_main_thread(Thread *thread, ptr_t entry, ptr_t sp, int argc, ptr_t argv, ptr_t envp);
246void platform_context_setup_child_thread(Thread *thread, thread_entry_t entry, void *arg);
247void platform_context_clone(Thread *from, Thread *to);
248void platform_context_cleanup(Thread *thread);
249
250// Platform Context Switching APIs
251// no default implementation, platform-specific implementations must be provided
252void platform_switch_mm(const MMContext *new_mm);
253void 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
258u64 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
262void 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
266typedef 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);
269void platform_syscall_setup_restart_context(platform_regs_t *regs, reg_t syscall_nr);
270void platform_syscall_store_retval(platform_regs_t *regs, reg_t result);
271