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