PatchworkOS  da8a090
A non-POSIX operating system.
Loading...
Searching...
No Matches
cpu.c
Go to the documentation of this file.
1#include <errno.h>
2#include <kernel/cpu/cpu.h>
3
4#include <kernel/cpu/gdt.h>
5#include <kernel/cpu/idt.h>
7#include <kernel/cpu/ipi.h>
8#include <kernel/cpu/simd.h>
10#include <kernel/cpu/tss.h>
11#include <kernel/drivers/perf.h>
12#include <kernel/log/log.h>
13#include <kernel/log/panic.h>
14#include <kernel/mem/vmm.h>
15#include <kernel/sched/sched.h>
16#include <kernel/sync/lock.h>
17#include <kernel/sync/rwlock.h>
18#include <kernel/utils/map.h>
19#include <stdatomic.h>
20#include <stdint.h>
21#include <sys/list.h>
22
25
29
31{
32 cpuid_t id = _cpuAmount++;
34
35 cpu->id = id;
36 _cpus[id] = cpu;
37
40 tss_init(&cpu->tss);
41 gdt_cpu_tss_load(&cpu->tss);
42
43 if (stack_pointer_init_buffer(&cpu->exceptionStack, cpu->exceptionStackBuffer, CONFIG_INTERRUPT_STACK_PAGES) == ERR)
44 {
45 panic(NULL, "Failed to init exception stack for cpu %u\n", cpu->id);
46 }
49
50 if (stack_pointer_init_buffer(&cpu->doubleFaultStack, cpu->doubleFaultStackBuffer, CONFIG_INTERRUPT_STACK_PAGES) ==
51 ERR)
52 {
54 panic(NULL, "Failed to init double fault stack for cpu %u\n", cpu->id);
55 }
58
59 if (stack_pointer_init_buffer(&cpu->nmiStack, cpu->nmiStackBuffer, CONFIG_INTERRUPT_STACK_PAGES) == ERR)
60 {
63 panic(NULL, "Failed to init NMI stack for cpu %u\n", cpu->id);
64 }
66 tss_ist_load(&cpu->tss, TSS_IST_NMI, &cpu->nmiStack);
67
68 if (stack_pointer_init_buffer(&cpu->interruptStack, cpu->interruptStackBuffer, CONFIG_INTERRUPT_STACK_PAGES) == ERR)
69 {
72 panic(NULL, "Failed to init interrupt stack for cpu %u\n", cpu->id);
73 }
76}
77
78void cpu_init(cpu_t* cpu)
79{
82
83 vmm_cpu_ctx_init(&cpu->vmm);
87 wait_init(&cpu->wait);
88 sched_init(&cpu->sched);
89 ipi_cpu_ctx_init(&cpu->ipi);
90
92 for (uint64_t i = 0; i < eventHandlerCount; i++)
93 {
94 cpu_event_t event = {.type = CPU_ONLINE};
95 eventHandlers[i].func(cpu, &event);
96 bitmap_set(&eventHandlers[i].initializedCpus, cpu->id);
97 }
98}
99
101{
102 if (func == NULL)
103 {
104 errno = EINVAL;
105 return ERR;
106 }
107
110 {
111 errno = EBUSY;
112 return ERR;
113 }
114
115 for (uint64_t i = 0; i < eventHandlerCount; i++)
116 {
117 if (eventHandlers[i].func == func)
118 {
119 errno = EEXIST;
120 return ERR;
121 }
122 }
123
125 eventHandler->func = func;
126 BITMAP_DEFINE_INIT(eventHandler->initializedCpus, CPU_MAX);
127 bitmap_clear_range(&eventHandler->initializedCpus, 0, CPU_MAX);
128
129 cpu_t* self = cpu_get_unsafe();
130 if (self != NULL)
131 {
132 cpu_event_t event = {.type = CPU_ONLINE};
133 eventHandler->func(self, &event);
134 bitmap_set(&eventHandler->initializedCpus, self->id);
135 }
136
137 cpu_t* cpu;
138 CPU_FOR_EACH(cpu)
139 {
140 if (cpu == self)
141 {
142 continue;
143 }
144 atomic_store(&cpu->needHandlersCheck, true);
145 }
146
147 return 0;
148}
149
151{
152 if (func == NULL)
153 {
154 return;
155 }
156
158
159 for (uint64_t i = 0; i < eventHandlerCount; i++)
160 {
161 cpu_handler_t* eventHandler = &eventHandlers[i];
162 if (eventHandler->func == func)
163 {
164 eventHandler->func = NULL;
166 memmove(&eventHandlers[i], &eventHandlers[i + 1], (CPU_MAX_EVENT_HANDLERS - i - 1) * sizeof(cpu_func_t));
167 break;
168 }
169 }
170}
171
173{
174 bool expected = true;
175 if (!atomic_compare_exchange_strong(&cpu->needHandlersCheck, &expected, false))
176 {
177 return;
178 }
179
181 for (uint64_t i = 0; i < eventHandlerCount; i++)
182 {
183 cpu_handler_t* eventHandler = &eventHandlers[i];
184 if (!bitmap_is_set(&eventHandler->initializedCpus, cpu->id))
185 {
186 cpu_event_t event = {.type = CPU_ONLINE};
187 eventHandler->func(cpu, &event);
188 bitmap_set(&eventHandler->initializedCpus, cpu->id);
189 }
190 }
191}
192
194{
196 {
197 panic(NULL, "CPU%u exception stack overflow detected", cpu->id);
198 }
200 {
201 panic(NULL, "CPU%u double fault stack overflow detected", cpu->id);
202 }
204 {
205 panic(NULL, "CPU%u NMI stack overflow detected", cpu->id);
206 }
208 {
209 panic(NULL, "CPU%u interrupt stack overflow detected", cpu->id);
210 }
211}
212
214{
215 (void)data;
216
217 while (true)
218 {
219 asm volatile("cli; hlt");
220 }
221
222 __builtin_unreachable();
223}
224
226{
228 {
229 return ERR;
230 }
231 return 0;
232}
static void cpu_halt_ipi_handler(ipi_func_data_t *data)
Definition cpu.c:213
static uint64_t eventHandlerCount
Definition cpu.c:27
static lock_t eventHandlerLock
Definition cpu.c:28
static cpu_handler_t eventHandlers[CPU_MAX_EVENT_HANDLERS]
Definition cpu.c:26
static fd_t data
Definition dwm.c:21
static char * id
Definition dwm.c:20
void gdt_cpu_tss_load(tss_t *tss)
Load a TSS into the GDT and load it using the ltr instruction on the current CPU.
Definition gdt.c:63
void gdt_cpu_load(void)
Load the GDT on the current CPU.
Definition gdt.c:55
void idt_cpu_load(void)
Load the IDT on the current CPU.
Definition idt.c:53
void interrupt_ctx_init(interrupt_ctx_t *ctx)
Initializes the interrupt context.
Definition interrupt.c:16
void ipi_cpu_ctx_init(ipi_cpu_ctx_t *ctx)
Initialize per-CPU IPI context.
Definition ipi.c:15
uint64_t ipi_send(cpu_t *cpu, ipi_flags_t flags, ipi_func_t func, void *private)
Send an IPI to one or more CPUs.
Definition ipi.c:138
@ IPI_OTHERS
Send the IPI to all CPUs except the specified CPU.
Definition ipi.h:107
void simd_cpu_init(void)
Definition simd.c:41
void stack_pointer_deinit_buffer(stack_pointer_t *stack)
Deinitializes a stack pointer structure that was initialized using stack_pointer_init_buffer().
uint64_t stack_pointer_init_buffer(stack_pointer_t *stack, void *buffer, uint64_t pages)
Initializes a stack pointer structure using a provided buffer, does not allocate or map any memory.
void syscalls_cpu_init(void)
Initialize syscalls on the current CPU.
Definition syscall.c:49
void tss_ist_load(tss_t *tss, tss_ist_t ist, stack_pointer_t *stack)
Load a stack into an IST entry.
Definition tss.c:21
#define TSS_IST_NMI
The IST index to use for non-maskable interrupts.
Definition tss.h:50
void tss_init(tss_t *tss)
Initialize a TSS structure.
Definition tss.c:5
#define TSS_IST_INTERRUPT
The IST index to use for other interrupts.
Definition tss.h:55
#define TSS_IST_EXCEPTION
The IST index to use for exceptions.
Definition tss.h:40
#define TSS_IST_DOUBLE_FAULT
The IST index to use for double faults.
Definition tss.h:45
uint64_t cpu_halt_others(void)
Halts all other CPUs.
Definition cpu.c:225
void cpu_stacks_overflow_check(cpu_t *cpu)
Checks for CPU stack overflows.
Definition cpu.c:193
uint64_t cpu_handler_register(cpu_func_t func)
Registers a CPU event handler for all CPUs.
Definition cpu.c:100
static cpu_t * cpu_get_unsafe(void)
Gets the current CPU structure without disabling interrupts.
Definition cpu.h:289
void(* cpu_func_t)(cpu_t *cpu, const cpu_event_t *event)
CPU event function type.
Definition cpu.h:105
void cpu_init(cpu_t *cpu)
Initializes the CPU represented by the cpu_t structure.
Definition cpu.c:78
#define CPU_MAX
Maximum number of CPUs supported.
Definition cpu.h:51
cpu_t * _cpus[CPU_MAX]
Array of pointers to cpu_t structures for each CPU, indexed by CPU ID.
Definition cpu.c:23
#define CPU_STACK_CANARY
CPU stack canary value.
Definition cpu.h:74
void cpu_handlers_check(cpu_t *cpu)
Checks if any handlers have been registered since the last check, and invokes them if so.
Definition cpu.c:172
#define CPU_FOR_EACH(cpu)
Macro to iterate over all CPUs.
Definition cpu.h:339
void cpu_init_early(cpu_t *cpu)
Only initialize the parts of the CPU structure needed for early boot.
Definition cpu.c:30
#define CPU_MAX_EVENT_HANDLERS
Maximum number of CPU event handlers that can be registered.
Definition cpu.h:100
void cpu_handler_unregister(cpu_func_t func)
Unregisters a previously registered CPU event handler.
Definition cpu.c:150
uint16_t _cpuAmount
The number of CPUs currently identified.
Definition cpu.c:24
uint16_t cpuid_t
Type used to identify a CPU.
Definition cpu.h:66
@ CPU_ONLINE
Definition cpu.h:82
void perf_cpu_ctx_init(perf_cpu_ctx_t *ctx)
Initializes a per-CPU performance context, must be called on the CPU that owns the context.
Definition perf.c:113
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:266
void vmm_cpu_ctx_init(vmm_cpu_ctx_t *ctx)
Initializes a per-CPU VMM context and performs per-CPU VMM initialization.
Definition vmm.c:122
void wait_init(wait_t *wait)
Initialize an instance of the waiting subsystem.
Definition wait.c:63
void sched_init(sched_t *sched)
Initialize the scheduler for a CPU.
Definition sched.c:324
#define LOCK_CREATE()
Create a lock initializer.
Definition lock.h:68
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
void timer_cpu_ctx_init(timer_cpu_ctx_t *ctx)
Initialize per-CPU timer context.
Definition timer.c:23
#define CONFIG_INTERRUPT_STACK_PAGES
Interrupt stack configuration.
Definition config.h:14
#define EEXIST
File exists.
Definition errno.h:117
#define EINVAL
Invalid argument.
Definition errno.h:142
#define EBUSY
Device or resource busy.
Definition errno.h:112
#define errno
Error number variable.
Definition errno.h:27
void bitmap_clear_range(bitmap_t *map, uint64_t low, uint64_t high)
Clear a range of bits in the bitmap.
bool bitmap_is_set(bitmap_t *map, uint64_t idx)
Check if a bit is set in the bitmap.
void bitmap_set(bitmap_t *map, uint64_t index)
Set a bit in the bitmap.
Definition bitmap_set.c:3
#define BITMAP_DEFINE_INIT(name, bits)
Initialize a bitmap defined with BITMAP_DEFINE.
Definition bitmap.h:107
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define MSR_CPU_ID
Definition regs.h:13
static void msr_write(uint32_t msr, uint64_t value)
Definition regs.h:71
#define atomic_store(object, desired)
Definition stdatomic.h:289
#define atomic_compare_exchange_strong(object, expected, desired)
Definition stdatomic.h:278
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT16_TYPE__ uint16_t
Definition stdint.h:13
_PUBLIC void * memmove(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
CPU event structure.
Definition cpu.h:90
cpu_event_type_t type
Definition cpu.h:91
cpu_func_t func
Definition cpu.h:109
CPU structure.
Definition cpu.h:122
cpuid_t id
Definition cpu.h:123
interrupt_ctx_t interrupt
Definition cpu.h:130
timer_cpu_ctx_t timer
Definition cpu.h:132
atomic_bool needHandlersCheck
Definition cpu.h:127
vmm_cpu_ctx_t vmm
Definition cpu.h:129
stack_pointer_t exceptionStack
Definition cpu.h:137
tss_t tss
Definition cpu.h:128
wait_t wait
Definition cpu.h:133
perf_cpu_ctx_t perf
Definition cpu.h:131
stack_pointer_t interruptStack
Definition cpu.h:140
sched_t sched
Definition cpu.h:134
ipi_cpu_ctx_t ipi
Definition cpu.h:136
stack_pointer_t nmiStack
Definition cpu.h:139
stack_pointer_t doubleFaultStack
Definition cpu.h:138
IPI function data structure.
Definition ipi.h:58
A simple ticket lock implementation.
Definition lock.h:43
uintptr_t bottom
The bottom of the stack, this address is inclusive.