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