major restructuring, prepare for smp
This commit is contained in:
1 parent
b3569a2b90
commit
6bff37746d
229 files changed
+1617
-1489
No files matched your search
@@ -0,0 +1,25 @@
|
||||
# lwip.sys
|
||||
|
||||
`lwip.sys` is the TCP/IP stack provider driver. It owns lwIP, `tcpip_thread`,
|
||||
netif attach, DNS, TCP, UDP, and the provider-side socket implementation.
|
||||
|
||||
The core kernel owns only:
|
||||
|
||||
- `NET_DEVICE` registration and Ethernet frame transport
|
||||
- `NET_STACK_PROVIDER` registration
|
||||
- process-owned socket handles
|
||||
- syscall/user-memory boundaries
|
||||
|
||||
Build notes:
|
||||
|
||||
- Do not use lwIP CMake.
|
||||
- `build.bat` compiles the sources listed in `drivers/lwip/lwip_sources.txt`.
|
||||
- Include directories:
|
||||
- `code/drivers/lwip/include`
|
||||
- `code/third_party/lwip/src/include`
|
||||
|
||||
Load order:
|
||||
|
||||
`drivers.ini` should load `lwip.sys` before NIC drivers so the provider is
|
||||
ready when the NIC registers. The kernel also supports provider-after-device
|
||||
registration, but provider-first keeps boot logs cleaner.
|
||||
@@ -0,0 +1 @@
|
||||
#pragma pack(push, 1)
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#ifndef LWIP_ARCH_CC_H
|
||||
#define LWIP_ARCH_CC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <kernel/ke_debug.h>
|
||||
|
||||
#ifndef LITTLE_ENDIAN
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#endif
|
||||
#ifndef BIG_ENDIAN
|
||||
#define BIG_ENDIAN 4321
|
||||
#endif
|
||||
#ifndef BYTE_ORDER
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
/* MSVC/freestanding kernel-friendly printf format fallbacks. */
|
||||
#define LWIP_NO_INTTYPES_H 1
|
||||
#define X8_F "02x"
|
||||
#define U16_F "hu"
|
||||
#define S16_F "hd"
|
||||
#define X16_F "hx"
|
||||
#define U32_F "lu"
|
||||
#define S32_F "ld"
|
||||
#define X32_F "lx"
|
||||
#define SZT_F "llu"
|
||||
|
||||
#define LWIP_NO_CTYPE_H 1
|
||||
#define LWIP_TIMEVAL_PRIVATE 1
|
||||
#define LWIP_PROVIDE_ERRNO 1
|
||||
|
||||
/* Used by SYS_LIGHTWEIGHT_PROT. Keep it wide enough for saved RFLAGS. */
|
||||
typedef uintptr_t sys_prot_t;
|
||||
|
||||
#define LWIP_PLATFORM_DIAG(x) do { DbgPrint x; } while (0)
|
||||
#define LWIP_PLATFORM_ASSERT(x) do { KePanic("lwIP assert: %s\n", (x)); } while (0)
|
||||
|
||||
unsigned int lwip_port_rand(void);
|
||||
#define LWIP_RAND() ((uint32_t)lwip_port_rand())
|
||||
|
||||
/* Force lwIP's static heap/aligned buffers to be at least 8-byte aligned. */
|
||||
#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) \
|
||||
__declspec(align(8)) uint8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)]
|
||||
|
||||
#define PACK_STRUCT_USE_INCLUDES
|
||||
|
||||
#endif /* LWIP_ARCH_CC_H */
|
||||
@@ -0,0 +1 @@
|
||||
#pragma pack(pop)
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#ifndef LWIP_ARCH_SYS_ARCH_H
|
||||
#define LWIP_ARCH_SYS_ARCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <lwip/opt.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct sys_sem;
|
||||
typedef struct sys_sem* sys_sem_t;
|
||||
#define SYS_SEM_NULL NULL
|
||||
#define sys_sem_valid(sem) ((sem) && (*(sem) != NULL))
|
||||
#define sys_sem_valid_val(sem) ((sem) != NULL)
|
||||
#define sys_sem_set_invalid(sem) do { if ((sem)) { *(sem) = NULL; } } while (0)
|
||||
#define sys_sem_set_invalid_val(sem) do { (sem) = NULL; } while (0)
|
||||
|
||||
struct sys_mutex;
|
||||
typedef struct sys_mutex* sys_mutex_t;
|
||||
#define sys_mutex_valid(mutex) ((mutex) && (*(mutex) != NULL))
|
||||
#define sys_mutex_valid_val(mutex) ((mutex) != NULL)
|
||||
#define sys_mutex_set_invalid(mutex) do { if ((mutex)) { *(mutex) = NULL; } } while (0)
|
||||
|
||||
struct sys_mbox;
|
||||
typedef struct sys_mbox* sys_mbox_t;
|
||||
#define SYS_MBOX_NULL NULL
|
||||
#define sys_mbox_valid(mbox) ((mbox) && (*(mbox) != NULL))
|
||||
#define sys_mbox_valid_val(mbox) ((mbox) != NULL)
|
||||
#define sys_mbox_set_invalid(mbox) do { if ((mbox)) { *(mbox) = NULL; } } while (0)
|
||||
#define sys_mbox_set_invalid_val(mbox) do { (mbox) = NULL; } while (0)
|
||||
|
||||
/*
|
||||
* lwIP only treats sys_thread_t as an opaque handle. Keep it pointer-sized.
|
||||
*
|
||||
* Do NOT make this a by-value incomplete struct. MSVC may compile callers
|
||||
* that see only the incomplete type with a hidden struct-return parameter,
|
||||
* which shifts sys_thread_new(name, thread, arg, ...) so the callee receives
|
||||
* thread == name and arg == thread. The first tcpip_thread then jumps into
|
||||
* the literal string "tcpip" as code.
|
||||
*/
|
||||
typedef void* sys_thread_t;
|
||||
|
||||
void LwipPortSetTimerQuery(uint64_t (*query_ticks_us)(void));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_ARCH_SYS_ARCH_H */
|
||||
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
/*
|
||||
* lwipopts.h - kernel port configuration for lwIP 2.2.1.
|
||||
*
|
||||
* This is intentionally a practical first configuration: IPv4, ARP, ICMP,
|
||||
* UDP, TCP, DHCP, DNS and netconn are enabled; IPv6, PPP,
|
||||
* SNMP, lwIP's POSIX socket API, and app protocols stay off.
|
||||
*/
|
||||
|
||||
#define NO_SYS 0
|
||||
#define SYS_LIGHTWEIGHT_PROT 1
|
||||
#define MEM_ALIGNMENT 8
|
||||
|
||||
/* Keep lwIP memory self-contained. It uses its own heap/pools, not malloc(). */
|
||||
#define MEM_LIBC_MALLOC 0
|
||||
#define MEMP_MEM_MALLOC 0
|
||||
#define MEM_SIZE (256 * 1024)
|
||||
#define MEMP_OVERFLOW_CHECK 0
|
||||
#define MEMP_SANITY_CHECK 0
|
||||
|
||||
#define PBUF_POOL_SIZE 64
|
||||
#define PBUF_POOL_BUFSIZE 1536
|
||||
#define MEMP_NUM_PBUF 32
|
||||
#define MEMP_NUM_NETBUF 32
|
||||
#define MEMP_NUM_NETCONN 32
|
||||
#define MEMP_NUM_TCPIP_MSG_API 64
|
||||
#define MEMP_NUM_TCPIP_MSG_INPKT 64
|
||||
#define MEMP_NUM_SYS_TIMEOUT 32
|
||||
|
||||
#define LWIP_IPV4 1
|
||||
#define LWIP_IPV6 0
|
||||
#define LWIP_ARP 1
|
||||
#define LWIP_ETHERNET 1
|
||||
#define LWIP_ICMP 1
|
||||
#define LWIP_IGMP 0
|
||||
#define LWIP_RAW 1
|
||||
#define LWIP_UDP 1
|
||||
#define LWIP_TCP 1
|
||||
#define LWIP_DHCP 1
|
||||
#define LWIP_AUTOIP 0
|
||||
#define LWIP_DNS 1
|
||||
|
||||
#define TCP_MSS 1460
|
||||
#define TCP_WND (4 * TCP_MSS)
|
||||
#define TCP_SND_BUF (4 * TCP_MSS)
|
||||
#define TCP_SND_QUEUELEN 16
|
||||
#define MEMP_NUM_TCP_PCB 16
|
||||
#define MEMP_NUM_TCP_PCB_LISTEN 8
|
||||
#define MEMP_NUM_TCP_SEG 32
|
||||
#define MEMP_NUM_UDP_PCB 16
|
||||
|
||||
#define LWIP_NETCONN 1
|
||||
#define LWIP_SOCKET 0
|
||||
#define LWIP_COMPAT_SOCKETS 0
|
||||
#define LWIP_POSIX_SOCKETS_IO_NAMES 0
|
||||
#define LWIP_SOCKET_SELECT 0
|
||||
#define LWIP_SO_RCVTIMEO 1
|
||||
#define LWIP_SO_SNDTIMEO 1
|
||||
#define LWIP_SO_RCVBUF 1
|
||||
#define LWIP_SO_REUSE 1
|
||||
#define LWIP_TCP_KEEPALIVE 1
|
||||
|
||||
#define TCPIP_THREAD_NAME "tcpip"
|
||||
#define TCPIP_THREAD_STACKSIZE 0
|
||||
#define TCPIP_THREAD_PRIO 2
|
||||
#define TCPIP_MBOX_SIZE 128
|
||||
#define DEFAULT_THREAD_STACKSIZE 0
|
||||
#define DEFAULT_THREAD_PRIO 1
|
||||
#define DEFAULT_RAW_RECVMBOX_SIZE 32
|
||||
#define DEFAULT_UDP_RECVMBOX_SIZE 64
|
||||
#define DEFAULT_TCP_RECVMBOX_SIZE 64
|
||||
#define DEFAULT_ACCEPTMBOX_SIZE 32
|
||||
|
||||
#define LWIP_NETIF_HOSTNAME 1
|
||||
#define LWIP_NETIF_STATUS_CALLBACK 1
|
||||
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||
#define LWIP_CHECKSUM_CTRL_PER_NETIF 0
|
||||
#define CHECKSUM_GEN_IP 1
|
||||
#define CHECKSUM_GEN_UDP 1
|
||||
#define CHECKSUM_GEN_TCP 1
|
||||
#define CHECKSUM_CHECK_IP 1
|
||||
#define CHECKSUM_CHECK_UDP 1
|
||||
#define CHECKSUM_CHECK_TCP 1
|
||||
|
||||
#define LWIP_TIMERS 1
|
||||
#define LWIP_TCPIP_TIMEOUT 1
|
||||
#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 1
|
||||
|
||||
#define LWIP_STATS 0
|
||||
#define LWIP_DEBUG 0
|
||||
#define LWIP_NOASSERT 0
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#ifndef LWIP_PORT_STDLIB_H
|
||||
#define LWIP_PORT_STDLIB_H
|
||||
|
||||
/*
|
||||
* Minimal freestanding stdlib shim for lwIP.
|
||||
*
|
||||
* lwIP 2.2.1 includes <stdlib.h> in a couple of files only for atoi(). If MSVC
|
||||
* finds the UCRT header, it drags errno.h into the kernel build and then lwIP's
|
||||
* own errno values collide with UCRT's. Put this header first in lwIP's include
|
||||
* path so those sources stay freestanding.
|
||||
*/
|
||||
static __inline int atoi(const char* s) {
|
||||
int sign = 1;
|
||||
int value = 0;
|
||||
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' || *s == '\v' || *s == '\f')
|
||||
++s;
|
||||
|
||||
if (*s == '-') {
|
||||
sign = -1;
|
||||
++s;
|
||||
} else if (*s == '+') {
|
||||
++s;
|
||||
}
|
||||
|
||||
while (*s >= '0' && *s <= '9') {
|
||||
value = value * 10 + (*s - '0');
|
||||
++s;
|
||||
}
|
||||
|
||||
return sign * value;
|
||||
}
|
||||
|
||||
#endif /* LWIP_PORT_STDLIB_H */
|
||||
@@ -0,0 +1,50 @@
|
||||
# Add these lwIP 2.2.1 files to the lwip.sys driver build.
|
||||
# Include directories required:
|
||||
# code/drivers/net/lwip/include
|
||||
# code/third_party/lwip/src/include
|
||||
# Port glue
|
||||
drivers/net/lwip/lwip_sys_arch.c
|
||||
drivers/net/lwip/lwip_stack.c
|
||||
|
||||
# lwIP core
|
||||
third_party/lwip/src/core/init.c
|
||||
third_party/lwip/src/core/def.c
|
||||
third_party/lwip/src/core/dns.c
|
||||
third_party/lwip/src/core/inet_chksum.c
|
||||
third_party/lwip/src/core/ip.c
|
||||
third_party/lwip/src/core/mem.c
|
||||
third_party/lwip/src/core/memp.c
|
||||
third_party/lwip/src/core/netif.c
|
||||
third_party/lwip/src/core/pbuf.c
|
||||
third_party/lwip/src/core/raw.c
|
||||
third_party/lwip/src/core/stats.c
|
||||
third_party/lwip/src/core/sys.c
|
||||
third_party/lwip/src/core/altcp.c
|
||||
third_party/lwip/src/core/altcp_alloc.c
|
||||
third_party/lwip/src/core/altcp_tcp.c
|
||||
third_party/lwip/src/core/tcp.c
|
||||
third_party/lwip/src/core/tcp_in.c
|
||||
third_party/lwip/src/core/tcp_out.c
|
||||
third_party/lwip/src/core/timeouts.c
|
||||
third_party/lwip/src/core/udp.c
|
||||
|
||||
# IPv4
|
||||
third_party/lwip/src/core/ipv4/acd.c
|
||||
third_party/lwip/src/core/ipv4/autoip.c
|
||||
third_party/lwip/src/core/ipv4/dhcp.c
|
||||
third_party/lwip/src/core/ipv4/etharp.c
|
||||
third_party/lwip/src/core/ipv4/icmp.c
|
||||
third_party/lwip/src/core/ipv4/igmp.c
|
||||
third_party/lwip/src/core/ipv4/ip4_frag.c
|
||||
third_party/lwip/src/core/ipv4/ip4.c
|
||||
third_party/lwip/src/core/ipv4/ip4_addr.c
|
||||
|
||||
# netconn/socket API
|
||||
third_party/lwip/src/api/api_lib.c
|
||||
third_party/lwip/src/api/api_msg.c
|
||||
third_party/lwip/src/api/err.c
|
||||
third_party/lwip/src/api/netbuf.c
|
||||
third_party/lwip/src/api/tcpip.c
|
||||
|
||||
# Ethernet netif helper
|
||||
third_party/lwip/src/netif/ethernet.c
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,363 @@
|
||||
// lwip_sys_arch.c - lwIP OS abstraction layer for the kernel.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#include <lwip/opt.h>
|
||||
#include <lwip/sys.h>
|
||||
#include <lwip/err.h>
|
||||
|
||||
#include <kernel/mm_virt.h>
|
||||
#include <kernel/ob_object.h>
|
||||
#include <kernel/ke_debug.h>
|
||||
#include <kernel/ke_sched.h>
|
||||
#include <kernel/ke_thread.h>
|
||||
#include <kernel/ke_semaphore.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
#include <kernel/ke_irql.h>
|
||||
|
||||
#define LWIP_PORT_MBOX_DEFAULT_SIZE 128u
|
||||
|
||||
struct sys_sem {
|
||||
SEMAPHORE* Sem;
|
||||
};
|
||||
|
||||
struct sys_mutex {
|
||||
SEMAPHORE* Sem;
|
||||
};
|
||||
|
||||
struct sys_mbox {
|
||||
SPINLOCK Lock;
|
||||
SEMAPHORE* Items;
|
||||
void** Ring;
|
||||
uint32_t Size;
|
||||
uint32_t Head;
|
||||
uint32_t Tail;
|
||||
uint32_t Count;
|
||||
uint32_t Valid;
|
||||
};
|
||||
|
||||
|
||||
static uint64_t (*gLwipQueryTicksUs)(void) = 0;
|
||||
static uint32_t gRandState = 0x4b4e4554u; /* 'KNET' */
|
||||
|
||||
void LwipPortSetTimerQuery(uint64_t (*query_ticks_us)(void)) {
|
||||
gLwipQueryTicksUs = query_ticks_us;
|
||||
}
|
||||
|
||||
unsigned int lwip_port_rand(void) {
|
||||
/* Tiny deterministic LCG. Good enough for ephemeral port randomisation. */
|
||||
gRandState = gRandState * 1664525u + 1013904223u;
|
||||
return gRandState;
|
||||
}
|
||||
|
||||
void sys_init(void) {
|
||||
}
|
||||
|
||||
u32_t sys_now(void) {
|
||||
if (!gLwipQueryTicksUs)
|
||||
return 0;
|
||||
return (u32_t)(gLwipQueryTicksUs() / 1000u);
|
||||
}
|
||||
|
||||
u32_t sys_jiffies(void) {
|
||||
return sys_now();
|
||||
}
|
||||
|
||||
/*
|
||||
* lwIP's core/sys.c provides sys_msleep() when it is not a macro. Do not
|
||||
* define it here as well, or MSVC links both sys.obj and lwip_sys_arch.obj
|
||||
* with a duplicate sys_msleep symbol.
|
||||
*/
|
||||
|
||||
/*
|
||||
* First bring-up errno storage for lwIP's socket/netdb compatibility layer.
|
||||
* This is global, not per-thread; the kernel socket-object wrapper should
|
||||
* eventually translate lwIP errors to KSTATUS instead of exposing this.
|
||||
*/
|
||||
// fuckass microsoft
|
||||
#ifdef errno
|
||||
#undef errno
|
||||
#endif
|
||||
int errno;
|
||||
int* __cdecl _errno(void) { return &errno; }
|
||||
|
||||
err_t sys_sem_new(sys_sem_t* sem, u8_t count) {
|
||||
if (!sem)
|
||||
return ERR_ARG;
|
||||
|
||||
struct sys_sem* s = (struct sys_sem*)MmAllocatePool(sizeof(*s));
|
||||
if (!s)
|
||||
return ERR_MEM;
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
SEMAPHORE* ksem = 0;
|
||||
if (!KSUCCESS(KeSemaphoreCreate(count ? 1 : 0, 0x7fffffff, &ksem))) {
|
||||
MmFreePool(s);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
s->Sem = ksem;
|
||||
*sem = s;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void sys_sem_signal(sys_sem_t* sem) {
|
||||
if (sem && *sem && (*sem)->Sem)
|
||||
KeSignalSemaphore((*sem)->Sem);
|
||||
}
|
||||
|
||||
u32_t sys_arch_sem_wait(sys_sem_t* sem, u32_t timeout) {
|
||||
if (!sem || !*sem || !(*sem)->Sem)
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
|
||||
u32_t start = sys_now();
|
||||
|
||||
if (timeout == 0) {
|
||||
KSTATUS st = KeWaitSemaphore((*sem)->Sem);
|
||||
return KSUCCESS(st) ? (u32_t)(sys_now() - start) : SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (KSUCCESS(KeTrySemaphore((*sem)->Sem)))
|
||||
return (u32_t)(sys_now() - start);
|
||||
|
||||
if ((u32_t)(sys_now() - start) >= timeout)
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
|
||||
KeYield();
|
||||
}
|
||||
}
|
||||
|
||||
void sys_sem_free(sys_sem_t* sem) {
|
||||
if (!sem || !*sem)
|
||||
return;
|
||||
if ((*sem)->Sem)
|
||||
ObDereferenceObject(&(*sem)->Sem->Header);
|
||||
MmFreePool(*sem);
|
||||
*sem = 0;
|
||||
}
|
||||
|
||||
err_t sys_mutex_new(sys_mutex_t* mutex) {
|
||||
if (!mutex)
|
||||
return ERR_ARG;
|
||||
|
||||
struct sys_mutex* m = (struct sys_mutex*)MmAllocatePool(sizeof(*m));
|
||||
if (!m)
|
||||
return ERR_MEM;
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
SEMAPHORE* sem = 0;
|
||||
if (!KSUCCESS(KeSemaphoreCreate(1, 1, &sem))) {
|
||||
MmFreePool(m);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
m->Sem = sem;
|
||||
*mutex = m;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void sys_mutex_lock(sys_mutex_t* mutex) {
|
||||
if (mutex && *mutex && (*mutex)->Sem)
|
||||
(void)KeWaitSemaphore((*mutex)->Sem);
|
||||
}
|
||||
|
||||
void sys_mutex_unlock(sys_mutex_t* mutex) {
|
||||
if (mutex && *mutex && (*mutex)->Sem)
|
||||
KeSignalSemaphore((*mutex)->Sem);
|
||||
}
|
||||
|
||||
void sys_mutex_free(sys_mutex_t* mutex) {
|
||||
if (!mutex || !*mutex)
|
||||
return;
|
||||
if ((*mutex)->Sem)
|
||||
ObDereferenceObject(&(*mutex)->Sem->Header);
|
||||
MmFreePool(*mutex);
|
||||
*mutex = 0;
|
||||
}
|
||||
|
||||
static err_t LwipMboxTryPost(sys_mbox_t* mbox, void* msg) {
|
||||
if (!mbox || !*mbox || !(*mbox)->Valid)
|
||||
return ERR_ARG;
|
||||
|
||||
struct sys_mbox* m = *mbox;
|
||||
uintptr_t flags = KeAcquireSpinlock(&m->Lock);
|
||||
if (m->Count >= m->Size) {
|
||||
KeReleaseSpinlock(&m->Lock, flags);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
m->Ring[m->Tail] = msg;
|
||||
m->Tail = (m->Tail + 1u) % m->Size;
|
||||
m->Count++;
|
||||
KeReleaseSpinlock(&m->Lock, flags);
|
||||
|
||||
KeSignalSemaphore(m->Items);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t sys_mbox_new(sys_mbox_t* mbox, int size) {
|
||||
if (!mbox)
|
||||
return ERR_ARG;
|
||||
|
||||
uint32_t n = (size > 0) ? (uint32_t)size : LWIP_PORT_MBOX_DEFAULT_SIZE;
|
||||
struct sys_mbox* m = (struct sys_mbox*)MmAllocatePool(sizeof(*m));
|
||||
if (!m)
|
||||
return ERR_MEM;
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
m->Ring = (void**)MmAllocatePool(sizeof(void*) * n);
|
||||
if (!m->Ring) {
|
||||
MmFreePool(m);
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(m->Ring, 0, sizeof(void*) * n);
|
||||
|
||||
SEMAPHORE* items = 0;
|
||||
if (!KSUCCESS(KeSemaphoreCreate(0, (int32_t)n, &items))) {
|
||||
MmFreePool(m->Ring);
|
||||
MmFreePool(m);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
m->Lock = (SPINLOCK)SPINLOCK_INIT;
|
||||
m->Items = items;
|
||||
m->Size = n;
|
||||
m->Valid = 1;
|
||||
*mbox = m;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void sys_mbox_post(sys_mbox_t* mbox, void* msg) {
|
||||
/* lwIP promises this is not called from ISR context. */
|
||||
while (LwipMboxTryPost(mbox, msg) != ERR_OK)
|
||||
KeYield();
|
||||
}
|
||||
|
||||
err_t sys_mbox_trypost(sys_mbox_t* mbox, void* msg) {
|
||||
return LwipMboxTryPost(mbox, msg);
|
||||
}
|
||||
|
||||
err_t sys_mbox_trypost_fromisr(sys_mbox_t* mbox, void* msg) {
|
||||
return LwipMboxTryPost(mbox, msg);
|
||||
}
|
||||
|
||||
static u32_t LwipMboxPopAfterItem(sys_mbox_t* mbox, void** msg, u32_t waited) {
|
||||
struct sys_mbox* m = *mbox;
|
||||
uintptr_t flags = KeAcquireSpinlock(&m->Lock);
|
||||
if (m->Count == 0) {
|
||||
KeReleaseSpinlock(&m->Lock, flags);
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
void* value = m->Ring[m->Head];
|
||||
m->Ring[m->Head] = 0;
|
||||
m->Head = (m->Head + 1u) % m->Size;
|
||||
m->Count--;
|
||||
KeReleaseSpinlock(&m->Lock, flags);
|
||||
|
||||
if (msg)
|
||||
*msg = value;
|
||||
return waited;
|
||||
}
|
||||
|
||||
u32_t sys_arch_mbox_fetch(sys_mbox_t* mbox, void** msg, u32_t timeout) {
|
||||
if (!mbox || !*mbox || !(*mbox)->Valid)
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
|
||||
u32_t start = sys_now();
|
||||
|
||||
if (timeout == 0) {
|
||||
KSTATUS st = KeWaitSemaphore((*mbox)->Items);
|
||||
if (!KSUCCESS(st))
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
return LwipMboxPopAfterItem(mbox, msg, (u32_t)(sys_now() - start));
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (KSUCCESS(KeTrySemaphore((*mbox)->Items)))
|
||||
return LwipMboxPopAfterItem(mbox, msg, (u32_t)(sys_now() - start));
|
||||
|
||||
if ((u32_t)(sys_now() - start) >= timeout)
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
|
||||
KeYield();
|
||||
}
|
||||
}
|
||||
|
||||
u32_t sys_arch_mbox_tryfetch(sys_mbox_t* mbox, void** msg) {
|
||||
if (!mbox || !*mbox || !(*mbox)->Valid)
|
||||
return SYS_MBOX_EMPTY;
|
||||
|
||||
if (!KSUCCESS(KeTrySemaphore((*mbox)->Items)))
|
||||
return SYS_MBOX_EMPTY;
|
||||
|
||||
return LwipMboxPopAfterItem(mbox, msg, 0);
|
||||
}
|
||||
|
||||
void sys_mbox_free(sys_mbox_t* mbox) {
|
||||
if (!mbox || !*mbox)
|
||||
return;
|
||||
|
||||
struct sys_mbox* m = *mbox;
|
||||
m->Valid = 0;
|
||||
if (m->Items)
|
||||
ObDereferenceObject(&m->Items->Header);
|
||||
if (m->Ring)
|
||||
MmFreePool(m->Ring);
|
||||
MmFreePool(m);
|
||||
*mbox = 0;
|
||||
}
|
||||
|
||||
sys_thread_t sys_thread_new(const char* name, lwip_thread_fn thread, void* arg,
|
||||
int stacksize, int prio) {
|
||||
(void)name;
|
||||
(void)stacksize;
|
||||
|
||||
if (!thread)
|
||||
KePanic("lwIP: sys_thread_new called with null entry\n");
|
||||
|
||||
THREAD_PRIORITY kp = PriorityNormal;
|
||||
if (prio >= 2)
|
||||
kp = PriorityHigh;
|
||||
else if (prio <= 0)
|
||||
kp = PriorityLow;
|
||||
|
||||
/*
|
||||
* lwIP thread entries already use the same ABI as kernel worker threads:
|
||||
*
|
||||
* void entry(void* arg)
|
||||
*
|
||||
* Do not bounce through a heap-allocated thunk. The first scaffold used a
|
||||
* tiny { function, argument } heap block and a wrapper, but an early boot
|
||||
* crash showed the wrapper sometimes loaded a bogus function pointer and
|
||||
* jumped into lwIP's .rdata strings. Passing the lwIP entry directly keeps
|
||||
* the initial thread stack simple: KeKernelThreadEntry calls exactly the
|
||||
* function pointer that lwIP supplied, with exactly the argument it supplied.
|
||||
*/
|
||||
THREAD* t = 0;
|
||||
KSTATUS st = KeCreateKernelThread((uintptr_t)thread,
|
||||
(uintptr_t)arg,
|
||||
kp,
|
||||
&t);
|
||||
if (!KSUCCESS(st))
|
||||
KePanic("lwIP: failed to create kernel thread: 0x%x\n", st);
|
||||
|
||||
return (sys_thread_t)t;
|
||||
}
|
||||
|
||||
sys_prot_t sys_arch_protect(void) {
|
||||
uintptr_t flags = __readeflags();
|
||||
_disable();
|
||||
return (sys_prot_t)flags;
|
||||
}
|
||||
|
||||
void sys_arch_unprotect(sys_prot_t pval) {
|
||||
if (((uintptr_t)pval) & 0x200u)
|
||||
_enable();
|
||||
else
|
||||
_disable();
|
||||
}
|
||||
Reference in new issue
Block a user