1 #include <debug.h>
2 #include <lwip/sys.h>
3
4 #include "lwip_glue.h"
5
6 static LIST_ENTRY ThreadListHead;
7 static KSPIN_LOCK ThreadListLock;
8
9 KEVENT TerminationEvent;
10 NPAGED_LOOKASIDE_LIST MessageLookasideList;
11 NPAGED_LOOKASIDE_LIST QueueEntryLookasideList;
12
13 static LARGE_INTEGER StartTime;
14
15 typedef struct _thread_t
16 {
17 HANDLE Handle;
18 void (* ThreadFunction)(void *arg);
19 void *ThreadContext;
20 LIST_ENTRY ListEntry;
21 } *thread_t;
22
sys_now(void)23 u32_t sys_now(void)
24 {
25 LARGE_INTEGER CurrentTime;
26
27 KeQuerySystemTime(&CurrentTime);
28
29 return (CurrentTime.QuadPart - StartTime.QuadPart) / 10000;
30 }
31
32 void
sys_arch_protect(sys_prot_t * lev)33 sys_arch_protect(sys_prot_t *lev)
34 {
35 /* Preempt the dispatcher */
36 KeRaiseIrql(DISPATCH_LEVEL, lev);
37 }
38
39 void
sys_arch_unprotect(sys_prot_t lev)40 sys_arch_unprotect(sys_prot_t lev)
41 {
42 KeLowerIrql(lev);
43 }
44
45 err_t
sys_sem_new(sys_sem_t * sem,u8_t count)46 sys_sem_new(sys_sem_t *sem, u8_t count)
47 {
48 ASSERT(count == 0 || count == 1);
49
50 /* It seems lwIP uses the semaphore implementation as either a completion event or a lock
51 * so I optimize for this case by using a synchronization event and setting its initial state
52 * to signalled for a lock and non-signalled for a completion event */
53
54 KeInitializeEvent(&sem->Event, SynchronizationEvent, count);
55
56 sem->Valid = 1;
57
58 return ERR_OK;
59 }
60
sys_sem_valid(sys_sem_t * sem)61 int sys_sem_valid(sys_sem_t *sem)
62 {
63 return sem->Valid;
64 }
65
sys_sem_set_invalid(sys_sem_t * sem)66 void sys_sem_set_invalid(sys_sem_t *sem)
67 {
68 sem->Valid = 0;
69 }
70
71 void
sys_sem_free(sys_sem_t * sem)72 sys_sem_free(sys_sem_t* sem)
73 {
74 /* No op (allocated in stack) */
75
76 sys_sem_set_invalid(sem);
77 }
78
79 void
sys_sem_signal(sys_sem_t * sem)80 sys_sem_signal(sys_sem_t* sem)
81 {
82 KeSetEvent(&sem->Event, IO_NO_INCREMENT, FALSE);
83 }
84
85 u32_t
sys_arch_sem_wait(sys_sem_t * sem,u32_t timeout)86 sys_arch_sem_wait(sys_sem_t* sem, u32_t timeout)
87 {
88 LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
89 UINT64 TimeDiff;
90 NTSTATUS Status;
91 PVOID WaitObjects[] = {&sem->Event, &TerminationEvent};
92
93 LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
94
95 KeQuerySystemTime(&PreWaitTime);
96
97 Status = KeWaitForMultipleObjects(2,
98 WaitObjects,
99 WaitAny,
100 Executive,
101 KernelMode,
102 FALSE,
103 timeout != 0 ? &LargeTimeout : NULL,
104 NULL);
105 if (Status == STATUS_WAIT_0)
106 {
107 KeQuerySystemTime(&PostWaitTime);
108 TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
109 TimeDiff /= 10000;
110
111 return TimeDiff;
112 }
113 else if (Status == STATUS_WAIT_1)
114 {
115 /* DON'T remove ourselves from the thread list! */
116 PsTerminateSystemThread(STATUS_SUCCESS);
117
118 /* We should never get here! */
119 ASSERT(FALSE);
120
121 return 0;
122 }
123
124 return SYS_ARCH_TIMEOUT;
125 }
126
127 err_t
sys_mbox_new(sys_mbox_t * mbox,int size)128 sys_mbox_new(sys_mbox_t *mbox, int size)
129 {
130 KeInitializeSpinLock(&mbox->Lock);
131
132 InitializeListHead(&mbox->ListHead);
133
134 KeInitializeEvent(&mbox->Event, NotificationEvent, FALSE);
135
136 mbox->Valid = 1;
137
138 return ERR_OK;
139 }
140
sys_mbox_valid(sys_mbox_t * mbox)141 int sys_mbox_valid(sys_mbox_t *mbox)
142 {
143 return mbox->Valid;
144 }
145
sys_mbox_set_invalid(sys_mbox_t * mbox)146 void sys_mbox_set_invalid(sys_mbox_t *mbox)
147 {
148 mbox->Valid = 0;
149 }
150
151 void
sys_mbox_free(sys_mbox_t * mbox)152 sys_mbox_free(sys_mbox_t *mbox)
153 {
154 ASSERT(IsListEmpty(&mbox->ListHead));
155
156 sys_mbox_set_invalid(mbox);
157 }
158
159 void
sys_mbox_post(sys_mbox_t * mbox,void * msg)160 sys_mbox_post(sys_mbox_t *mbox, void *msg)
161 {
162 PLWIP_MESSAGE_CONTAINER Container;
163
164 Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
165 ASSERT(Container);
166
167 Container->Message = msg;
168
169 ExInterlockedInsertTailList(&mbox->ListHead,
170 &Container->ListEntry,
171 &mbox->Lock);
172
173 KeSetEvent(&mbox->Event, IO_NO_INCREMENT, FALSE);
174 }
175
176 u32_t
sys_arch_mbox_fetch(sys_mbox_t * mbox,void ** msg,u32_t timeout)177 sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
178 {
179 LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
180 UINT64 TimeDiff;
181 NTSTATUS Status;
182 PVOID Message;
183 PLWIP_MESSAGE_CONTAINER Container;
184 PLIST_ENTRY Entry;
185 KIRQL OldIrql;
186 PVOID WaitObjects[] = {&mbox->Event, &TerminationEvent};
187
188 LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
189
190 KeQuerySystemTime(&PreWaitTime);
191
192 Status = KeWaitForMultipleObjects(2,
193 WaitObjects,
194 WaitAny,
195 Executive,
196 KernelMode,
197 FALSE,
198 timeout != 0 ? &LargeTimeout : NULL,
199 NULL);
200
201 if (Status == STATUS_WAIT_0)
202 {
203 KeAcquireSpinLock(&mbox->Lock, &OldIrql);
204 Entry = RemoveHeadList(&mbox->ListHead);
205 ASSERT(Entry);
206 if (IsListEmpty(&mbox->ListHead))
207 KeClearEvent(&mbox->Event);
208 KeReleaseSpinLock(&mbox->Lock, OldIrql);
209
210 Container = CONTAINING_RECORD(Entry, LWIP_MESSAGE_CONTAINER, ListEntry);
211 Message = Container->Message;
212 ExFreePool(Container);
213
214 if (msg)
215 *msg = Message;
216
217 KeQuerySystemTime(&PostWaitTime);
218 TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
219 TimeDiff /= 10000;
220
221 return TimeDiff;
222 }
223 else if (Status == STATUS_WAIT_1)
224 {
225 /* DON'T remove ourselves from the thread list! */
226 PsTerminateSystemThread(STATUS_SUCCESS);
227
228 /* We should never get here! */
229 ASSERT(FALSE);
230
231 return 0;
232 }
233
234 return SYS_ARCH_TIMEOUT;
235 }
236
237 u32_t
sys_arch_mbox_tryfetch(sys_mbox_t * mbox,void ** msg)238 sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
239 {
240 if (sys_arch_mbox_fetch(mbox, msg, 1) != SYS_ARCH_TIMEOUT)
241 return 0;
242 else
243 return SYS_MBOX_EMPTY;
244 }
245
246 err_t
sys_mbox_trypost(sys_mbox_t * mbox,void * msg)247 sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
248 {
249 sys_mbox_post(mbox, msg);
250
251 return ERR_OK;
252 }
253
254 VOID
255 NTAPI
LwipThreadMain(PVOID Context)256 LwipThreadMain(PVOID Context)
257 {
258 thread_t Container = (thread_t)Context;
259 KIRQL OldIrql;
260
261 ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock);
262
263 Container->ThreadFunction(Container->ThreadContext);
264
265 KeAcquireSpinLock(&ThreadListLock, &OldIrql);
266 RemoveEntryList(&Container->ListEntry);
267 KeReleaseSpinLock(&ThreadListLock, OldIrql);
268
269 ExFreePool(Container);
270
271 PsTerminateSystemThread(STATUS_SUCCESS);
272 }
273
274 sys_thread_t
sys_thread_new(const char * name,lwip_thread_fn thread,void * arg,int stacksize,int prio)275 sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
276 {
277 thread_t Container;
278 NTSTATUS Status;
279
280 Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
281 if (!Container)
282 return 0;
283
284 Container->ThreadFunction = thread;
285 Container->ThreadContext = arg;
286
287 Status = PsCreateSystemThread(&Container->Handle,
288 THREAD_ALL_ACCESS,
289 NULL,
290 NULL,
291 NULL,
292 LwipThreadMain,
293 Container);
294
295 if (!NT_SUCCESS(Status))
296 {
297 ExFreePool(Container);
298 return 0;
299 }
300
301 return 0;
302 }
303
304 void
sys_init(void)305 sys_init(void)
306 {
307 KeInitializeSpinLock(&ThreadListLock);
308 InitializeListHead(&ThreadListHead);
309
310 KeQuerySystemTime(&StartTime);
311
312 KeInitializeEvent(&TerminationEvent, NotificationEvent, FALSE);
313
314 ExInitializeNPagedLookasideList(&MessageLookasideList,
315 NULL,
316 NULL,
317 0,
318 sizeof(struct lwip_callback_msg),
319 LWIP_MESSAGE_TAG,
320 0);
321
322 ExInitializeNPagedLookasideList(&QueueEntryLookasideList,
323 NULL,
324 NULL,
325 0,
326 sizeof(QUEUE_ENTRY),
327 LWIP_QUEUE_TAG,
328 0);
329 }
330
331 void
sys_shutdown(void)332 sys_shutdown(void)
333 {
334 PLIST_ENTRY CurrentEntry;
335 thread_t Container;
336
337 /* Set the termination event */
338 KeSetEvent(&TerminationEvent, IO_NO_INCREMENT, FALSE);
339
340 /* Loop through the thread list and wait for each to die */
341 while ((CurrentEntry = ExInterlockedRemoveHeadList(&ThreadListHead, &ThreadListLock)))
342 {
343 Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry);
344
345 if (Container->ThreadFunction)
346 {
347 KeWaitForSingleObject(Container->Handle,
348 Executive,
349 KernelMode,
350 FALSE,
351 NULL);
352
353 ZwClose(Container->Handle);
354 }
355 }
356
357 ExDeleteNPagedLookasideList(&MessageLookasideList);
358 ExDeleteNPagedLookasideList(&QueueEntryLookasideList);
359 }
360