PatchworkOS  da8a090
A non-POSIX operating system.
Loading...
Searching...
No Matches
ipi.c
Go to the documentation of this file.
1#include <kernel/cpu/cpu.h>
2#include <kernel/cpu/ipi.h>
3#include <kernel/cpu/irq.h>
4#include <kernel/log/log.h>
5#include <kernel/log/panic.h>
6#include <kernel/sync/lock.h>
8
9#include <errno.h>
10#include <string.h>
11
14
16{
17 memset(ctx->queue, 0, sizeof(ctx->queue));
18 ctx->readIndex = 0;
19 ctx->writeIndex = 0;
20 lock_init(&ctx->lock);
21}
22
24{
25 (void)frame;
26
27 ipi_cpu_ctx_t* ctx = &self->ipi;
28
31 {
32 registeredChip->ack(self);
33 }
35
36 while (true)
37 {
38 LOCK_SCOPE(&ctx->lock);
39
40 if (ctx->readIndex == ctx->writeIndex)
41 {
42 break;
43 }
44
45 ipi_t ipi = ctx->queue[ctx->readIndex];
46 ctx->readIndex = (ctx->readIndex + 1) % IPI_QUEUE_SIZE;
47
48 ipi_func_data_t ipiData = {
49 .self = self,
50 .private = ipi.private,
51 };
52 ipi.func(&ipiData);
53 }
54
57 {
58 registeredChip->eoi(self);
59 }
61}
62
64{
65 if (chip == NULL)
66 {
67 errno = EINVAL;
68 return ERR;
69 }
70
72
73 if (registeredChip != NULL)
74 {
75 errno = EBUSY;
76 return ERR;
77 }
78
79 registeredChip = chip;
80 LOG_INFO("registered IPI chip '%s'\n", chip->name);
81 return 0;
82}
83
85{
86 if (chip == NULL)
87 {
88 return;
89 }
90
92
93 if (registeredChip != chip)
94 {
95 return;
96 }
97
98 LOG_INFO("unregistered IPI chip '%s'\n", chip->name);
100}
101
103{
105 return registeredChip != NULL ? 1 : 0;
106}
107
108static uint64_t ipi_push(cpu_t* cpu, ipi_func_t func, void* private)
109{
110 if (registeredChip == NULL)
111 {
112 errno = ENODEV;
113 return ERR;
114 }
115
117 {
118 errno = ENOSYS;
119 return ERR;
120 }
121
122 ipi_cpu_ctx_t* ctx = &cpu->ipi;
123 LOCK_SCOPE(&ctx->lock);
124
125 uint64_t nextWriteIndex = (ctx->writeIndex + 1) % IPI_QUEUE_SIZE;
126 if (nextWriteIndex == ctx->readIndex)
127 {
128 errno = EBUSY;
129 return ERR;
130 }
131
132 ctx->queue[ctx->writeIndex].func = func;
133 ctx->queue[ctx->writeIndex].private = private;
134 ctx->writeIndex = nextWriteIndex;
135 return 0;
136}
137
139{
140 if (func == NULL)
141 {
142 errno = EINVAL;
143 return ERR;
144 }
145
147
148 switch (flags & IPI_OTHERS)
149 {
150 case IPI_SINGLE:
151 {
152 if (cpu == NULL)
153 {
154 errno = EINVAL;
155 return ERR;
156 }
157
158 if (ipi_push(cpu, func, private) == ERR)
159 {
160 return ERR;
161 }
162
164 }
165 break;
166 case IPI_BROADCAST:
167 {
168 cpu_t* cpu;
169 CPU_FOR_EACH(cpu)
170 {
171 if (ipi_push(cpu, func, private) == ERR)
172 {
173 return ERR;
174 }
175
177 }
178 }
179 break;
180 case IPI_OTHERS:
181 {
182 if (cpu == NULL)
183 {
184 errno = EINVAL;
185 return ERR;
186 }
187
188 cpu_t* iter;
189 CPU_FOR_EACH(iter)
190 {
191 if (iter == cpu)
192 {
193 continue;
194 }
195
196 if (ipi_push(iter, func, private) == ERR)
197 {
198 return ERR;
199 }
200
202 }
203 }
204 break;
205 default:
206 errno = EINVAL;
207 return ERR;
208 }
209
210 return 0;
211}
212
214{
216
218 {
219 return;
220 }
221
222 switch (flags & IPI_OTHERS)
223 {
224 case IPI_SINGLE:
225 {
226 if (cpu == NULL)
227 {
228 return;
229 }
230
232 }
233 break;
234 case IPI_BROADCAST:
235 {
236 cpu_t* cpu;
237 CPU_FOR_EACH(cpu)
238 {
240 }
241 }
242 break;
243 case IPI_OTHERS:
244 {
245 if (cpu == NULL)
246 {
247 return;
248 }
249
250 cpu_t* iter;
251 CPU_FOR_EACH(iter)
252 {
253 if (iter == cpu)
254 {
255 continue;
256 }
257
259 }
260 }
261 break;
262 default:
263 return;
264 }
265}
266
267void ipi_invoke(void)
268{
270}
@ VECTOR_IPI
See IPI for more information.
Definition interrupt.h:127
#define IPI_QUEUE_SIZE
IPI queue size.
Definition ipi.h:83
void ipi_cpu_ctx_init(ipi_cpu_ctx_t *ctx)
Initialize per-CPU IPI context.
Definition ipi.c:15
ipi_flags_t
IPI flags.
Definition ipi.h:104
void ipi_handle_pending(interrupt_frame_t *frame, cpu_t *self)
Handle pending IPIs on the current CPU.
Definition ipi.c:23
void ipi_invoke(void)
Invoke a IPI interrupt on the current CPU.
Definition ipi.c:267
void ipi_wake_up(cpu_t *cpu, ipi_flags_t flags)
Wake up one or more CPUs.
Definition ipi.c:213
void(* ipi_func_t)(ipi_func_data_t *data)
IPI function type.
Definition ipi.h:66
uint64_t ipi_chip_register(ipi_chip_t *chip)
Register an IPI chip.
Definition ipi.c:63
uint64_t ipi_chip_amount(void)
Get the number of registered IPI chips.
Definition ipi.c:102
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
void ipi_chip_unregister(ipi_chip_t *chip)
Unregister the IPI chip.
Definition ipi.c:84
@ IPI_OTHERS
Send the IPI to all CPUs except the specified CPU.
Definition ipi.h:107
@ IPI_SINGLE
Send the IPI to the specified CPU.
Definition ipi.h:105
@ IPI_BROADCAST
Send the IPI to all CPUs, specified CPU ignored.
Definition ipi.h:106
#define IRQ_INVOKE(virt)
Invoke the given virtual IRQ.
Definition irq.h:290
#define CPU_FOR_EACH(cpu)
Macro to iterate over all CPUs.
Definition cpu.h:339
#define LOG_INFO(format,...)
Definition log.h:106
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:86
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
void rwlock_read_acquire(rwlock_t *lock)
Acquires a rwlock for reading, blocking until it is available.
Definition rwlock.c:18
#define RWLOCK_READ_SCOPE(lock)
Acquires a rwlock for reading for the reminder of the current scope.
Definition rwlock.h:29
void rwlock_read_release(rwlock_t *lock)
Releases a rwlock from reading.
Definition rwlock.c:54
#define RWLOCK_CREATE()
Create a rwlock initializer.
Definition rwlock.h:47
#define RWLOCK_WRITE_SCOPE(lock)
Acquires a rwlock for writing for the reminder of the current scope.
Definition rwlock.h:38
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOSYS
Function not implemented.
Definition errno.h:222
#define EBUSY
Device or resource busy.
Definition errno.h:112
#define errno
Error number variable.
Definition errno.h:27
#define ENODEV
No such device.
Definition errno.h:127
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static ipi_chip_t * registeredChip
Definition ipi.c:12
static uint64_t ipi_push(cpu_t *cpu, ipi_func_t func, void *private)
Definition ipi.c:108
static rwlock_t chipLock
Definition ipi.c:13
static const path_flag_t flags[]
Definition path.c:42
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
CPU structure.
Definition cpu.h:122
ipi_cpu_ctx_t ipi
Definition cpu.h:136
Trap Frame Structure.
Definition interrupt.h:143
Inter-Processor Interrupt (IPI) chip structure.
Definition ipi.h:36
const char * name
Definition ipi.h:37
void(* interrupt)(cpu_t *cpu, irq_virt_t virt)
Should interrupt the given CPU with the given virtual IRQ.
Definition ipi.h:46
void(* eoi)(cpu_t *cpu)
Definition ipi.h:48
void(* ack)(cpu_t *cpu)
Definition ipi.h:47
Per-CPU IPI context.
Definition ipi.h:92
uint64_t writeIndex
Definition ipi.h:95
lock_t lock
Definition ipi.h:96
uint64_t readIndex
Definition ipi.h:94
ipi_t queue[IPI_QUEUE_SIZE]
Definition ipi.h:93
IPI function data structure.
Definition ipi.h:58
cpu_t * self
Definition ipi.h:59
IPI structure.
Definition ipi.h:75
void * private
Definition ipi.h:77
ipi_func_t func
Definition ipi.h:76
Read-Write Ticket Lock structure.
Definition rwlock.h:61