add lwIP TCP/IP stack as a runtime driver, native socket syscalls, SysGetMemoryStatus replacing CatchAllDebugBucket, fix timeGetTime to return milliseconds, fix SysSleep to interpret argument as milliseconds, SysGetTick now returns microseconds, harden all syscalls against bad user pointers with CopyFromUser/CopyToUser/MmProbeUser throughout, add networking test apps, port-forward 8080 in runa.bat, split LWIP_DRIVER_CFLAGS, add settings.ini to deploy, remove ethernet.c stub
This commit is contained in:
1 parent
18b4dd0f61
commit
df13b8056c
365 files changed
+143263
-1362
No files matched your search
@@ -1,620 +0,0 @@
|
||||
// ethernet.c - tiny pre-lwIP Ethernet/ARP/IPv4/ICMP shim.
|
||||
//
|
||||
// Goals:
|
||||
// * prove NIC RX/TX works before lwIP is integrated;
|
||||
// * reply to ARP for a configured static IPv4 address;
|
||||
// * reply to ICMP echo requests for that address;
|
||||
// * provide a tiny NetPingIpv4() smoke-test path;
|
||||
// * auto-configure QEMU's default user-mode network only when the MAC looks
|
||||
// like the QEMU OUI (52:54:00), so real hardware is not assigned a bogus IP.
|
||||
//
|
||||
// This is not intended to grow into a full stack. When lwIP arrives, keep the
|
||||
// NET_DEVICE send/receive boundary and replace this protocol code with lwIP's
|
||||
// netif input path.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ke_debug.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ethernet.h>
|
||||
|
||||
#define NET_MAX_ETH_STATES 8
|
||||
#define NET_ARP_CACHE_SIZE 8
|
||||
|
||||
#define ETH_ADDR_LEN NET_ETHERNET_ADDRESS_LENGTH
|
||||
#define ETH_HDR_LEN NET_ETHERNET_HEADER_LENGTH
|
||||
#define ETH_TYPE_IPV4 0x0800u
|
||||
#define ETH_TYPE_ARP 0x0806u
|
||||
|
||||
#define ARP_HTYPE_ETHERNET 0x0001u
|
||||
#define ARP_PTYPE_IPV4 0x0800u
|
||||
#define ARP_OPER_REQUEST 0x0001u
|
||||
#define ARP_OPER_REPLY 0x0002u
|
||||
#define ARP_PACKET_LEN 28u
|
||||
|
||||
#define IPV4_PROTO_ICMP 1u
|
||||
#define ICMP_ECHO_REPLY 0u
|
||||
#define ICMP_ECHO_REQUEST 8u
|
||||
|
||||
#define NET_ETH_MAX_FRAME NET_ETHERNET_MAX_FRAME
|
||||
#define NET_LOG_LIMIT 16u
|
||||
|
||||
static const uint8_t gBroadcastMac[ETH_ADDR_LEN] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
typedef struct NET_ARP_ENTRY {
|
||||
bool Valid;
|
||||
uint32_t Ip;
|
||||
uint8_t HardwareAddress[ETH_ADDR_LEN];
|
||||
} NET_ARP_ENTRY;
|
||||
|
||||
typedef struct NET_ETH_STATE {
|
||||
bool Present;
|
||||
bool Ipv4Configured;
|
||||
bool GatewayResolved;
|
||||
uint32_t Address;
|
||||
uint32_t Netmask;
|
||||
uint32_t Gateway;
|
||||
uint8_t GatewayHardwareAddress[ETH_ADDR_LEN];
|
||||
NET_ARP_ENTRY ArpCache[NET_ARP_CACHE_SIZE];
|
||||
uint32_t ArpNextReplace;
|
||||
bool PendingPing;
|
||||
uint32_t PendingPingTarget;
|
||||
uint32_t PendingPingNextHop;
|
||||
uint32_t RxFrames;
|
||||
uint32_t TxFrames;
|
||||
uint16_t IcmpEchoSequence;
|
||||
uint32_t ArpFrames;
|
||||
uint32_t Ipv4Frames;
|
||||
uint32_t IcmpFrames;
|
||||
} NET_ETH_STATE;
|
||||
|
||||
static NET_ETH_STATE gEthStates[NET_MAX_ETH_STATES];
|
||||
static SPINLOCK gEthLock = SPINLOCK_INIT;
|
||||
|
||||
static uint16_t NetLoadBe16(const uint8_t* p) {
|
||||
return (uint16_t)(((uint16_t)p[0] << 8) | p[1]);
|
||||
}
|
||||
|
||||
static uint32_t NetLoadBe32(const uint8_t* p) {
|
||||
return ((uint32_t)p[0] << 24) |
|
||||
((uint32_t)p[1] << 16) |
|
||||
((uint32_t)p[2] << 8) |
|
||||
(uint32_t)p[3];
|
||||
}
|
||||
|
||||
static void NetStoreBe16(uint8_t* p, uint16_t v) {
|
||||
p[0] = (uint8_t)(v >> 8);
|
||||
p[1] = (uint8_t)v;
|
||||
}
|
||||
|
||||
static void NetStoreBe32(uint8_t* p, uint32_t v) {
|
||||
p[0] = (uint8_t)(v >> 24);
|
||||
p[1] = (uint8_t)(v >> 16);
|
||||
p[2] = (uint8_t)(v >> 8);
|
||||
p[3] = (uint8_t)v;
|
||||
}
|
||||
|
||||
static void NetPrintIpv4(uint32_t ip) {
|
||||
DbgPrint("%u.%u.%u.%u",
|
||||
(unsigned)((ip >> 24) & 0xFFu),
|
||||
(unsigned)((ip >> 16) & 0xFFu),
|
||||
(unsigned)((ip >> 8) & 0xFFu),
|
||||
(unsigned)(ip & 0xFFu));
|
||||
}
|
||||
|
||||
static void NetPrintMac(const uint8_t* mac) {
|
||||
DbgPrint("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
static bool NetHasEthernetAddress(const NET_DEVICE* device) {
|
||||
return device && device->HardwareAddressLength == ETH_ADDR_LEN;
|
||||
}
|
||||
|
||||
static bool NetIsQemuMac(const NET_DEVICE* device) {
|
||||
return NetHasEthernetAddress(device) &&
|
||||
device->HardwareAddress[0] == 0x52 &&
|
||||
device->HardwareAddress[1] == 0x54 &&
|
||||
device->HardwareAddress[2] == 0x00;
|
||||
}
|
||||
|
||||
static bool NetIsBroadcastMac(const uint8_t* mac) {
|
||||
return mac && memcmp(mac, gBroadcastMac, ETH_ADDR_LEN) == 0;
|
||||
}
|
||||
|
||||
static bool NetIsMulticastMac(const uint8_t* mac) {
|
||||
return mac && (mac[0] & 0x01u) != 0;
|
||||
}
|
||||
|
||||
static bool NetEthernetFrameIsForDevice(const NET_DEVICE* device, const uint8_t* frame) {
|
||||
if (!NetHasEthernetAddress(device) || !frame)
|
||||
return false;
|
||||
return memcmp(frame, device->HardwareAddress, ETH_ADDR_LEN) == 0 ||
|
||||
NetIsBroadcastMac(frame) ||
|
||||
NetIsMulticastMac(frame);
|
||||
}
|
||||
|
||||
static bool NetIpv4SameSubnet(uint32_t a, uint32_t b, uint32_t mask) {
|
||||
return ((a ^ b) & mask) == 0;
|
||||
}
|
||||
|
||||
static NET_ETH_STATE* NetGetEthState(NET_DEVICE* device) {
|
||||
if (!device || device->Index >= NET_MAX_ETH_STATES)
|
||||
return (NET_ETH_STATE*)0;
|
||||
return &gEthStates[device->Index];
|
||||
}
|
||||
|
||||
static uint16_t NetChecksum(const uint8_t* data, size_t length) {
|
||||
uint32_t sum = 0;
|
||||
|
||||
while (length >= 2) {
|
||||
sum += NetLoadBe16(data);
|
||||
data += 2;
|
||||
length -= 2;
|
||||
}
|
||||
|
||||
if (length)
|
||||
sum += (uint16_t)((uint16_t)data[0] << 8);
|
||||
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xFFFFu) + (sum >> 16);
|
||||
|
||||
return (uint16_t)~sum;
|
||||
}
|
||||
|
||||
static void NetBuildEthernetHeader(uint8_t* frame,
|
||||
const uint8_t* dst,
|
||||
const uint8_t* src,
|
||||
uint16_t etherType) {
|
||||
memcpy(frame, dst, ETH_ADDR_LEN);
|
||||
memcpy(frame + ETH_ADDR_LEN, src, ETH_ADDR_LEN);
|
||||
NetStoreBe16(frame + 12, etherType);
|
||||
}
|
||||
|
||||
static bool NetArpLookup(NET_ETH_STATE* state, uint32_t ip, uint8_t* macOut) {
|
||||
if (!state)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < NET_ARP_CACHE_SIZE; ++i) {
|
||||
if (state->ArpCache[i].Valid && state->ArpCache[i].Ip == ip) {
|
||||
if (macOut)
|
||||
memcpy(macOut, state->ArpCache[i].HardwareAddress, ETH_ADDR_LEN);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void NetArpRemember(NET_ETH_STATE* state, uint32_t ip, const uint8_t* mac) {
|
||||
if (!state || !mac || ip == 0)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < NET_ARP_CACHE_SIZE; ++i) {
|
||||
if (state->ArpCache[i].Valid && state->ArpCache[i].Ip == ip) {
|
||||
memcpy(state->ArpCache[i].HardwareAddress, mac, ETH_ADDR_LEN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned slot = state->ArpNextReplace % NET_ARP_CACHE_SIZE;
|
||||
state->ArpNextReplace = (state->ArpNextReplace + 1) % NET_ARP_CACHE_SIZE;
|
||||
state->ArpCache[slot].Valid = true;
|
||||
state->ArpCache[slot].Ip = ip;
|
||||
memcpy(state->ArpCache[slot].HardwareAddress, mac, ETH_ADDR_LEN);
|
||||
}
|
||||
|
||||
static KSTATUS NetSendArp(NET_DEVICE* device,
|
||||
uint16_t operation,
|
||||
const uint8_t* targetMac,
|
||||
uint32_t targetIp) {
|
||||
NET_ETH_STATE* state = NetGetEthState(device);
|
||||
if (!state || !state->Ipv4Configured)
|
||||
return STATUS_NOT_FOUND;
|
||||
if (!NetHasEthernetAddress(device))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (operation == ARP_OPER_REPLY && !targetMac)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
uint8_t frame[ETH_HDR_LEN + ARP_PACKET_LEN];
|
||||
const uint8_t* ethDst = (operation == ARP_OPER_REQUEST) ? gBroadcastMac : targetMac;
|
||||
NetBuildEthernetHeader(frame, ethDst, device->HardwareAddress, ETH_TYPE_ARP);
|
||||
|
||||
uint8_t* arp = frame + ETH_HDR_LEN;
|
||||
NetStoreBe16(arp + 0, ARP_HTYPE_ETHERNET);
|
||||
NetStoreBe16(arp + 2, ARP_PTYPE_IPV4);
|
||||
arp[4] = ETH_ADDR_LEN;
|
||||
arp[5] = 4;
|
||||
NetStoreBe16(arp + 6, operation);
|
||||
memcpy(arp + 8, device->HardwareAddress, ETH_ADDR_LEN);
|
||||
NetStoreBe32(arp + 14, state->Address);
|
||||
|
||||
if (operation == ARP_OPER_REQUEST)
|
||||
memset(arp + 18, 0, ETH_ADDR_LEN);
|
||||
else
|
||||
memcpy(arp + 18, targetMac, ETH_ADDR_LEN);
|
||||
NetStoreBe32(arp + 24, targetIp);
|
||||
|
||||
KSTATUS st = NetSendFrame(device->Index, frame, sizeof(frame));
|
||||
if (KSUCCESS(st))
|
||||
state->TxFrames++;
|
||||
return st;
|
||||
}
|
||||
|
||||
static void NetSendArpRequest(NET_DEVICE* device, uint32_t targetIp) {
|
||||
DbgPrint("NET: %s tx ARP who-has ", device->Name);
|
||||
NetPrintIpv4(targetIp);
|
||||
DbgPrint("\n");
|
||||
|
||||
KSTATUS st = NetSendArp(device, ARP_OPER_REQUEST, gBroadcastMac, targetIp);
|
||||
if (!KSUCCESS(st))
|
||||
DbgPrint("NET: %s ARP probe failed: 0x%x\n", device->Name, st);
|
||||
}
|
||||
|
||||
static KSTATUS NetSendIcmpEchoRequestResolved(NET_DEVICE* device,
|
||||
NET_ETH_STATE* state,
|
||||
uint32_t targetIp,
|
||||
const uint8_t* nextHopMac) {
|
||||
if (!device || !state || !state->Ipv4Configured || !nextHopMac)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
enum {
|
||||
IPV4_HEADER_LEN = 20,
|
||||
ICMP_HEADER_LEN = 8,
|
||||
ICMP_PAYLOAD_LEN = 32,
|
||||
ICMP_TOTAL_LEN = ICMP_HEADER_LEN + ICMP_PAYLOAD_LEN,
|
||||
IPV4_TOTAL_LEN = IPV4_HEADER_LEN + ICMP_TOTAL_LEN,
|
||||
FRAME_LEN = ETH_HDR_LEN + IPV4_TOTAL_LEN
|
||||
};
|
||||
|
||||
uint8_t frame[FRAME_LEN];
|
||||
NetBuildEthernetHeader(frame,
|
||||
nextHopMac,
|
||||
device->HardwareAddress,
|
||||
ETH_TYPE_IPV4);
|
||||
|
||||
uint8_t* ip = frame + ETH_HDR_LEN;
|
||||
memset(ip, 0, IPV4_TOTAL_LEN);
|
||||
ip[0] = 0x45; // IPv4, 20-byte header.
|
||||
ip[1] = 0; // DSCP/ECN.
|
||||
NetStoreBe16(ip + 2, IPV4_TOTAL_LEN);
|
||||
NetStoreBe16(ip + 4, state->IcmpEchoSequence);
|
||||
NetStoreBe16(ip + 6, 0x4000); // Don't fragment.
|
||||
ip[8] = 64; // TTL.
|
||||
ip[9] = IPV4_PROTO_ICMP;
|
||||
NetStoreBe32(ip + 12, state->Address);
|
||||
NetStoreBe32(ip + 16, targetIp);
|
||||
NetStoreBe16(ip + 10, NetChecksum(ip, IPV4_HEADER_LEN));
|
||||
|
||||
uint8_t* icmp = ip + IPV4_HEADER_LEN;
|
||||
icmp[0] = ICMP_ECHO_REQUEST;
|
||||
icmp[1] = 0;
|
||||
NetStoreBe16(icmp + 4, 0x4b4e); // temporary pre-lwIP ping ID: 'KN'.
|
||||
NetStoreBe16(icmp + 6, state->IcmpEchoSequence);
|
||||
for (unsigned i = 0; i < ICMP_PAYLOAD_LEN; ++i)
|
||||
icmp[ICMP_HEADER_LEN + i] = (uint8_t)('A' + (i % 26));
|
||||
NetStoreBe16(icmp + 2, NetChecksum(icmp, ICMP_TOTAL_LEN));
|
||||
|
||||
DbgPrint("NET: %s tx ICMP echo request to ", device->Name);
|
||||
NetPrintIpv4(targetIp);
|
||||
DbgPrint(" seq=%u\n", (unsigned)state->IcmpEchoSequence);
|
||||
|
||||
KSTATUS st = NetSendFrame(device->Index, frame, FRAME_LEN);
|
||||
if (KSUCCESS(st)) {
|
||||
state->TxFrames++;
|
||||
state->IcmpEchoSequence++;
|
||||
} else {
|
||||
DbgPrint("NET: %s ICMP echo request failed: 0x%x\n", device->Name, st);
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static KSTATUS NetPingIpv4OnDevice(NET_DEVICE* device,
|
||||
NET_ETH_STATE* state,
|
||||
uint32_t targetIp) {
|
||||
if (!device || !state || !state->Ipv4Configured || targetIp == 0)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
uint32_t nextHop = targetIp;
|
||||
if (!NetIpv4SameSubnet(state->Address, targetIp, state->Netmask)) {
|
||||
if (state->Gateway == 0)
|
||||
return STATUS_NOT_FOUND;
|
||||
nextHop = state->Gateway;
|
||||
}
|
||||
|
||||
uint8_t nextHopMac[ETH_ADDR_LEN];
|
||||
if (NetArpLookup(state, nextHop, nextHopMac))
|
||||
return NetSendIcmpEchoRequestResolved(device, state, targetIp, nextHopMac);
|
||||
|
||||
state->PendingPing = true;
|
||||
state->PendingPingTarget = targetIp;
|
||||
state->PendingPingNextHop = nextHop;
|
||||
|
||||
DbgPrint("NET: %s ping ", device->Name);
|
||||
NetPrintIpv4(targetIp);
|
||||
DbgPrint(" waiting for ARP ");
|
||||
NetPrintIpv4(nextHop);
|
||||
DbgPrint("\n");
|
||||
|
||||
NetSendArpRequest(device, nextHop);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
static void NetHandleArp(NET_DEVICE* device, NET_ETH_STATE* state,
|
||||
const uint8_t* frame, size_t length) {
|
||||
if (length < ETH_HDR_LEN + ARP_PACKET_LEN)
|
||||
return;
|
||||
|
||||
const uint8_t* arp = frame + ETH_HDR_LEN;
|
||||
if (NetLoadBe16(arp + 0) != ARP_HTYPE_ETHERNET ||
|
||||
NetLoadBe16(arp + 2) != ARP_PTYPE_IPV4 ||
|
||||
arp[4] != ETH_ADDR_LEN || arp[5] != 4)
|
||||
return;
|
||||
|
||||
uint16_t op = NetLoadBe16(arp + 6);
|
||||
const uint8_t* senderMac = arp + 8;
|
||||
uint32_t senderIp = NetLoadBe32(arp + 14);
|
||||
uint32_t targetIp = NetLoadBe32(arp + 24);
|
||||
state->ArpFrames++;
|
||||
|
||||
if (state->ArpFrames <= NET_LOG_LIMIT) {
|
||||
DbgPrint("NET: %s rx ARP %s ",
|
||||
device->Name,
|
||||
op == ARP_OPER_REQUEST ? "request" :
|
||||
op == ARP_OPER_REPLY ? "reply" : "op");
|
||||
NetPrintIpv4(senderIp);
|
||||
DbgPrint(" ");
|
||||
NetPrintMac(senderMac);
|
||||
DbgPrint(" -> ");
|
||||
NetPrintIpv4(targetIp);
|
||||
DbgPrint("\n");
|
||||
}
|
||||
|
||||
if ((op == ARP_OPER_REQUEST || op == ARP_OPER_REPLY) && senderIp != 0)
|
||||
NetArpRemember(state, senderIp, senderMac);
|
||||
|
||||
if (op == ARP_OPER_REPLY && state->Ipv4Configured && senderIp == state->Gateway) {
|
||||
memcpy(state->GatewayHardwareAddress, senderMac, ETH_ADDR_LEN);
|
||||
state->GatewayResolved = true;
|
||||
DbgPrint("NET: %s gateway resolved ", device->Name);
|
||||
NetPrintIpv4(senderIp);
|
||||
DbgPrint(" = ");
|
||||
NetPrintMac(senderMac);
|
||||
DbgPrint("\n");
|
||||
}
|
||||
|
||||
if (op == ARP_OPER_REPLY && state->PendingPing && senderIp == state->PendingPingNextHop) {
|
||||
uint32_t pingTarget = state->PendingPingTarget;
|
||||
state->PendingPing = false;
|
||||
(void)NetSendIcmpEchoRequestResolved(device, state, pingTarget, senderMac);
|
||||
}
|
||||
|
||||
if (op == ARP_OPER_REQUEST && state->Ipv4Configured && targetIp == state->Address) {
|
||||
KSTATUS st = NetSendArp(device, ARP_OPER_REPLY, senderMac, senderIp);
|
||||
if (KSUCCESS(st)) {
|
||||
DbgPrint("NET: %s tx ARP reply for ", device->Name);
|
||||
NetPrintIpv4(state->Address);
|
||||
DbgPrint("\n");
|
||||
} else {
|
||||
DbgPrint("NET: %s ARP reply failed: 0x%x\n", device->Name, st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void NetHandleIcmpEcho(NET_DEVICE* device, NET_ETH_STATE* state,
|
||||
const uint8_t* frame, size_t length,
|
||||
const uint8_t* ip, size_t ipHeaderLength,
|
||||
size_t totalLength) {
|
||||
(void)length;
|
||||
|
||||
if (totalLength < ipHeaderLength + 8)
|
||||
return;
|
||||
|
||||
const uint8_t* icmp = ip + ipHeaderLength;
|
||||
size_t icmpLength = totalLength - ipHeaderLength;
|
||||
if (NetChecksum(icmp, icmpLength) != 0)
|
||||
return;
|
||||
if (icmp[0] != ICMP_ECHO_REQUEST || icmp[1] != 0)
|
||||
return;
|
||||
|
||||
if (ETH_HDR_LEN + totalLength > NET_ETH_MAX_FRAME)
|
||||
return;
|
||||
|
||||
uint8_t out[NET_ETH_MAX_FRAME];
|
||||
NetBuildEthernetHeader(out, frame + 6, device->HardwareAddress, ETH_TYPE_IPV4);
|
||||
memcpy(out + ETH_HDR_LEN, ip, totalLength);
|
||||
|
||||
uint8_t* outIp = out + ETH_HDR_LEN;
|
||||
uint8_t* outIcmp = outIp + ipHeaderLength;
|
||||
|
||||
// Swap IPv4 endpoints and rebuild the IPv4 header checksum.
|
||||
memcpy(outIp + 12, ip + 16, 4);
|
||||
memcpy(outIp + 16, ip + 12, 4);
|
||||
outIp[8] = 64;
|
||||
outIp[10] = 0;
|
||||
outIp[11] = 0;
|
||||
NetStoreBe16(outIp + 10, NetChecksum(outIp, ipHeaderLength));
|
||||
|
||||
// Convert echo request to echo reply and rebuild the ICMP checksum.
|
||||
outIcmp[0] = ICMP_ECHO_REPLY;
|
||||
outIcmp[2] = 0;
|
||||
outIcmp[3] = 0;
|
||||
NetStoreBe16(outIcmp + 2, NetChecksum(outIcmp, icmpLength));
|
||||
|
||||
KSTATUS st = NetSendFrame(device->Index, out, ETH_HDR_LEN + totalLength);
|
||||
if (KSUCCESS(st)) {
|
||||
state->TxFrames++;
|
||||
if (state->IcmpFrames <= NET_LOG_LIMIT) {
|
||||
DbgPrint("NET: %s tx ICMP echo reply to ", device->Name);
|
||||
NetPrintIpv4(NetLoadBe32(ip + 12));
|
||||
DbgPrint("\n");
|
||||
}
|
||||
} else {
|
||||
DbgPrint("NET: %s ICMP reply failed: 0x%x\n", device->Name, st);
|
||||
}
|
||||
}
|
||||
|
||||
static void NetHandleIpv4(NET_DEVICE* device, NET_ETH_STATE* state,
|
||||
const uint8_t* frame, size_t length) {
|
||||
if (!state->Ipv4Configured || length < ETH_HDR_LEN + 20)
|
||||
return;
|
||||
|
||||
const uint8_t* ip = frame + ETH_HDR_LEN;
|
||||
uint8_t version = (uint8_t)(ip[0] >> 4);
|
||||
size_t ipHeaderLength = (size_t)(ip[0] & 0x0Fu) * 4u;
|
||||
if (version != 4 || ipHeaderLength < 20 || length < ETH_HDR_LEN + ipHeaderLength)
|
||||
return;
|
||||
|
||||
size_t totalLength = NetLoadBe16(ip + 2);
|
||||
if (totalLength < ipHeaderLength || length < ETH_HDR_LEN + totalLength)
|
||||
return;
|
||||
|
||||
if (NetChecksum(ip, ipHeaderLength) != 0)
|
||||
return;
|
||||
|
||||
uint16_t fragment = NetLoadBe16(ip + 6);
|
||||
if (fragment & 0x3FFFu)
|
||||
return;
|
||||
|
||||
uint32_t dstIp = NetLoadBe32(ip + 16);
|
||||
if (dstIp != state->Address)
|
||||
return;
|
||||
|
||||
state->Ipv4Frames++;
|
||||
if (ip[9] == IPV4_PROTO_ICMP) {
|
||||
if (totalLength < ipHeaderLength + 8)
|
||||
return;
|
||||
|
||||
const uint8_t* icmp = ip + ipHeaderLength;
|
||||
size_t icmpLength = totalLength - ipHeaderLength;
|
||||
if (NetChecksum(icmp, icmpLength) != 0)
|
||||
return;
|
||||
|
||||
state->IcmpFrames++;
|
||||
|
||||
if (icmp[0] == ICMP_ECHO_REPLY && icmp[1] == 0) {
|
||||
DbgPrint("NET: %s rx ICMP echo reply from ", device->Name);
|
||||
NetPrintIpv4(NetLoadBe32(ip + 12));
|
||||
DbgPrint(" seq=%u\n", (unsigned)NetLoadBe16(icmp + 6));
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->IcmpFrames <= NET_LOG_LIMIT) {
|
||||
DbgPrint("NET: %s rx ICMP type=%u code=%u from ",
|
||||
device->Name,
|
||||
(unsigned)icmp[0],
|
||||
(unsigned)icmp[1]);
|
||||
NetPrintIpv4(NetLoadBe32(ip + 12));
|
||||
DbgPrint("\n");
|
||||
}
|
||||
|
||||
NetHandleIcmpEcho(device, state, frame, length, ip, ipHeaderLength, totalLength);
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS NetConfigureIpv4Static(uint32_t deviceIndex,
|
||||
uint32_t address,
|
||||
uint32_t netmask,
|
||||
uint32_t gateway) {
|
||||
if (deviceIndex >= NET_MAX_ETH_STATES || address == 0)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
NET_DEVICE* device = NetGetDevice(deviceIndex);
|
||||
if (!device)
|
||||
return STATUS_NOT_FOUND;
|
||||
if (!NetHasEthernetAddress(device))
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gEthLock);
|
||||
NET_ETH_STATE* state = &gEthStates[deviceIndex];
|
||||
state->Ipv4Configured = true;
|
||||
state->GatewayResolved = false;
|
||||
state->PendingPing = false;
|
||||
state->IcmpEchoSequence = 1;
|
||||
state->Address = address;
|
||||
state->Netmask = netmask;
|
||||
state->Gateway = gateway;
|
||||
state->ArpNextReplace = 0;
|
||||
memset(state->GatewayHardwareAddress, 0, sizeof(state->GatewayHardwareAddress));
|
||||
memset(state->ArpCache, 0, sizeof(state->ArpCache));
|
||||
KeReleaseSpinlock(&gEthLock, flags);
|
||||
|
||||
DbgPrint("NET: eth%u IPv4 ", deviceIndex);
|
||||
NetPrintIpv4(address);
|
||||
DbgPrint(" mask ");
|
||||
NetPrintIpv4(netmask);
|
||||
DbgPrint(" gw ");
|
||||
NetPrintIpv4(gateway);
|
||||
DbgPrint("\n");
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS NetPingIpv4(uint32_t deviceIndex, uint32_t targetIp) {
|
||||
NET_DEVICE* device = NetGetDevice(deviceIndex);
|
||||
if (!device || deviceIndex >= NET_MAX_ETH_STATES)
|
||||
return STATUS_NOT_FOUND;
|
||||
|
||||
NET_ETH_STATE* state = &gEthStates[deviceIndex];
|
||||
if (!state->Present || !state->Ipv4Configured)
|
||||
return STATUS_NOT_FOUND;
|
||||
|
||||
return NetPingIpv4OnDevice(device, state, targetIp);
|
||||
}
|
||||
|
||||
void NetEthernetAttachDevice(NET_DEVICE* device) {
|
||||
if (!device || device->Index >= NET_MAX_ETH_STATES)
|
||||
return;
|
||||
if (!NetHasEthernetAddress(device)) {
|
||||
DbgPrint("NET: %s has unsupported hardware address length %u; Ethernet shim disabled\n",
|
||||
device->Name, (unsigned)device->HardwareAddressLength);
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gEthLock);
|
||||
NET_ETH_STATE* state = &gEthStates[device->Index];
|
||||
memset(state, 0, sizeof(*state));
|
||||
state->Present = true;
|
||||
KeReleaseSpinlock(&gEthLock, flags);
|
||||
|
||||
if (NetIsQemuMac(device)) {
|
||||
NetConfigureIpv4Static(device->Index,
|
||||
NET_IPV4_ADDR(10, 0, 2, 15),
|
||||
NET_IPV4_ADDR(255, 255, 255, 0),
|
||||
NET_IPV4_ADDR(10, 0, 2, 2));
|
||||
state = &gEthStates[device->Index];
|
||||
(void)NetPingIpv4OnDevice(device, state, state->Gateway);
|
||||
} else {
|
||||
DbgPrint("NET: %s has no IPv4 address yet; ARP/ICMP replies disabled\n",
|
||||
device->Name);
|
||||
}
|
||||
}
|
||||
|
||||
void NetEthernetReceive(NET_DEVICE* device, const void* frame, size_t length) {
|
||||
NET_ETH_STATE* state = NetGetEthState(device);
|
||||
if (!state || !state->Present || !frame || length < ETH_HDR_LEN)
|
||||
return;
|
||||
|
||||
const uint8_t* b = (const uint8_t*)frame;
|
||||
if (!NetEthernetFrameIsForDevice(device, b))
|
||||
return;
|
||||
|
||||
uint16_t etherType = NetLoadBe16(b + 12);
|
||||
state->RxFrames++;
|
||||
|
||||
switch (etherType) {
|
||||
case ETH_TYPE_ARP:
|
||||
NetHandleArp(device, state, b, length);
|
||||
break;
|
||||
case ETH_TYPE_IPV4:
|
||||
NetHandleIpv4(device, state, b, length);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
// ethernet.h - tiny pre-lwIP Ethernet/ARP/ICMP shim.
|
||||
//
|
||||
// This is deliberately small: it gives NIC drivers something useful to feed
|
||||
// while lwIP is not wired up yet. Keep the public surface generic so the lwIP
|
||||
// netif glue can reuse NetSendFrame() and bypass this file later.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
#include <net_device.h>
|
||||
|
||||
#define NET_IPV4_ADDR(a, b, c, d) \
|
||||
((((uint32_t)(a) & 0xFFu) << 24) | \
|
||||
(((uint32_t)(b) & 0xFFu) << 16) | \
|
||||
(((uint32_t)(c) & 0xFFu) << 8) | \
|
||||
((uint32_t)(d) & 0xFFu))
|
||||
|
||||
__declspec(dllexport) KSTATUS NetConfigureIpv4Static(uint32_t deviceIndex,
|
||||
uint32_t address,
|
||||
uint32_t netmask,
|
||||
uint32_t gateway);
|
||||
__declspec(dllexport) KSTATUS NetPingIpv4(uint32_t deviceIndex, uint32_t targetIp);
|
||||
|
||||
void NetEthernetAttachDevice(NET_DEVICE* device);
|
||||
void NetEthernetReceive(NET_DEVICE* device, const void* frame, size_t length);
|
||||
+31
-16
@@ -257,16 +257,26 @@ void KiCheckForUserApcDelivery(KTRAP_FRAME* frame) {
|
||||
newRsp &= ~(uintptr_t)0xFULL;
|
||||
newRsp -= 8; // make injected dispatcher entry look like a normal call target
|
||||
|
||||
SYS_USER_APC_FRAME_K* userFrame = (SYS_USER_APC_FRAME_K*)newRsp;
|
||||
userFrame->Magic = SYS_USER_APC_FRAME_MAGIC;
|
||||
userFrame->OriginalRip = frame->Rip;
|
||||
userFrame->OriginalRsp = frame->Rsp;
|
||||
userFrame->OriginalRflags = frame->Rflags;
|
||||
userFrame->OriginalRax = STATUS_USER_APC;
|
||||
userFrame->Routine = (uint64_t)(uintptr_t)apc->Routine;
|
||||
userFrame->NormalContext = (uint64_t)(uintptr_t)apc->NormalContext;
|
||||
userFrame->SystemArgument1 = (uint64_t)(uintptr_t)apc->SystemArgument1;
|
||||
userFrame->SystemArgument2 = (uint64_t)(uintptr_t)apc->SystemArgument2;
|
||||
SYS_USER_APC_FRAME_K userFrame;
|
||||
memset(&userFrame, 0, sizeof(userFrame));
|
||||
userFrame.Magic = SYS_USER_APC_FRAME_MAGIC;
|
||||
userFrame.OriginalRip = frame->Rip;
|
||||
userFrame.OriginalRsp = frame->Rsp;
|
||||
userFrame.OriginalRflags = frame->Rflags;
|
||||
userFrame.OriginalRax = STATUS_USER_APC;
|
||||
userFrame.Routine = (uint64_t)(uintptr_t)apc->Routine;
|
||||
userFrame.NormalContext = (uint64_t)(uintptr_t)apc->NormalContext;
|
||||
userFrame.SystemArgument1 = (uint64_t)(uintptr_t)apc->SystemArgument1;
|
||||
userFrame.SystemArgument2 = (uint64_t)(uintptr_t)apc->SystemArgument2;
|
||||
|
||||
KSTATUS s = CopyToUser((void*)newRsp, &userFrame, sizeof(userFrame));
|
||||
if (!KSUCCESS(s)) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&thread->UserApcLock);
|
||||
ListInsertTail(&thread->UserApcQueue, &apc->Link);
|
||||
thread->UserApcPending = 1;
|
||||
KeReleaseSpinlock(&thread->UserApcLock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
frame->Rip = thread->UserApcDispatcher;
|
||||
frame->Rsp = newRsp;
|
||||
@@ -313,7 +323,12 @@ void KiRundownApcState(THREAD* thread) {
|
||||
}
|
||||
|
||||
__declspec(dllexport) uint64_t KeUserApcReturn(const SYS_USER_APC_FRAME_K* userFrame) {
|
||||
if (!userFrame || userFrame->Magic != SYS_USER_APC_FRAME_MAGIC)
|
||||
SYS_USER_APC_FRAME_K frameCopy;
|
||||
KSTATUS s = CopyFromUser(&frameCopy, userFrame, sizeof(frameCopy));
|
||||
if (!KSUCCESS(s))
|
||||
return s;
|
||||
|
||||
if (frameCopy.Magic != SYS_USER_APC_FRAME_MAGIC)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
THREAD* thread = KeGetCurrentThread();
|
||||
@@ -324,12 +339,12 @@ __declspec(dllexport) uint64_t KeUserApcReturn(const SYS_USER_APC_FRAME_K* userF
|
||||
if (!frame || !KeTrapFrameFromUser(frame) || frame->Kind != KTRAP_KIND_SYSCALL)
|
||||
return STATUS_FAILURE;
|
||||
|
||||
frame->Rip = userFrame->OriginalRip;
|
||||
frame->Rsp = userFrame->OriginalRsp;
|
||||
frame->Rflags = userFrame->OriginalRflags;
|
||||
frame->Rax = userFrame->OriginalRax;
|
||||
frame->Rip = frameCopy.OriginalRip;
|
||||
frame->Rsp = frameCopy.OriginalRsp;
|
||||
frame->Rflags = frameCopy.OriginalRflags;
|
||||
frame->Rax = frameCopy.OriginalRax;
|
||||
|
||||
thread->UserApcDeliveryActive = 0;
|
||||
thread->UserApcDeliverable = 0;
|
||||
return userFrame->OriginalRax;
|
||||
return frameCopy.OriginalRax;
|
||||
}
|
||||
@@ -20,4 +20,3 @@ __declspec(dllexport) KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialSta
|
||||
__declspec(dllexport) void KeSignalEvent(EVENT* event);
|
||||
__declspec(dllexport) void KeClearEvent(EVENT* event);
|
||||
__declspec(dllexport) KSTATUS KeWaitForEvent(EVENT* event, uint8_t alertable);
|
||||
__declspec(dllexport) KSTATUS KeWaitForEvent(EVENT* event, uint8_t alertable);
|
||||
@@ -0,0 +1,94 @@
|
||||
// ke_settings.c - small system/settings.ini reader.
|
||||
//
|
||||
// This intentionally exposes generic string settings only. Subsystems and
|
||||
// drivers own the policy for interpreting their sections.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ke_settings.h>
|
||||
#include <io_file.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ini_parser.h>
|
||||
|
||||
#define KE_SETTINGS_MAX_FILE_BYTES (64u * 1024u)
|
||||
|
||||
typedef struct KE_FIND_SETTING_CTX {
|
||||
const char* Section;
|
||||
const char* Key;
|
||||
char* Buffer;
|
||||
size_t BufferSize;
|
||||
KSTATUS Status;
|
||||
} KE_FIND_SETTING_CTX;
|
||||
|
||||
static void KeFindSettingCallback(const char* section, const char* key,
|
||||
const char* value, void* userdata) {
|
||||
KE_FIND_SETTING_CTX* ctx = (KE_FIND_SETTING_CTX*)userdata;
|
||||
if (!ctx || ctx->Status != STATUS_NOT_FOUND)
|
||||
return;
|
||||
if (!section || !key || !value)
|
||||
return;
|
||||
if (strcmp(section, ctx->Section) != 0 || strcmp(key, ctx->Key) != 0)
|
||||
return;
|
||||
|
||||
size_t len = strlen(value);
|
||||
if (len + 1 > ctx->BufferSize) {
|
||||
if (ctx->BufferSize)
|
||||
ctx->Buffer[0] = '\0';
|
||||
ctx->Status = STATUS_BUFFER_TOO_SMALL;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(ctx->Buffer, value, len + 1);
|
||||
ctx->Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS KeGetSettingString(const char* section,
|
||||
const char* key,
|
||||
char* buffer,
|
||||
size_t bufferSize) {
|
||||
if (!section || !*section || !key || !*key || !buffer || bufferSize == 0)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
FILE_OBJECT* file = NULL;
|
||||
KSTATUS st = IoOpenFile(KE_SETTINGS_PATH, &file);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
uint64_t fileSize64 = IoGetFileSize(file);
|
||||
if (fileSize64 >= KE_SETTINGS_MAX_FILE_BYTES) {
|
||||
IoCloseFile(file);
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
size_t fileSize = (size_t)fileSize64;
|
||||
char* text = (char*)MmAllocatePool(fileSize + 1);
|
||||
if (!text) {
|
||||
IoCloseFile(file);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
size_t got = 0;
|
||||
st = IoReadFile(file, text, fileSize, &got);
|
||||
IoCloseFile(file);
|
||||
if (!KSUCCESS(st)) {
|
||||
MmFreePool(text);
|
||||
return st;
|
||||
}
|
||||
|
||||
text[got] = '\0';
|
||||
|
||||
KE_FIND_SETTING_CTX ctx;
|
||||
ctx.Section = section;
|
||||
ctx.Key = key;
|
||||
ctx.Buffer = buffer;
|
||||
ctx.BufferSize = bufferSize;
|
||||
ctx.Status = STATUS_NOT_FOUND;
|
||||
|
||||
IniParse(text, KeFindSettingCallback, &ctx);
|
||||
MmFreePool(text);
|
||||
return ctx.Status;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
#define KE_SETTINGS_PATH "system\\settings.ini"
|
||||
|
||||
__declspec(dllexport) KSTATUS KeGetSettingString(const char* section,
|
||||
const char* key,
|
||||
char* buffer,
|
||||
size_t bufferSize);
|
||||
+1118
-197
File diff suppressed because it is too large.
Load diff
+11
-11
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <hal_api.h>
|
||||
|
||||
// Set the HAL API pointer for syscalls
|
||||
void KeSyscallInit(const HAL_API* hal, uint64_t (*CatchAllDebugBucket)(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5));
|
||||
|
||||
// Syscall dispatcher, called from assembly entry point
|
||||
uint64_t KeSyscallDispatch(uint64_t nr, uint64_t a0, uint64_t a1,
|
||||
uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5);
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <hal_api.h>
|
||||
|
||||
// Set the HAL API pointer for syscalls
|
||||
void KeSyscallInit(const HAL_API* hal);
|
||||
|
||||
// Syscall dispatcher, called from assembly entry point
|
||||
uint64_t KeSyscallDispatch(uint64_t nr, uint64_t a0, uint64_t a1,
|
||||
uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5);
|
||||
+2
-76
@@ -13,7 +13,7 @@
|
||||
#include <ke_irq.h>
|
||||
#include <ke_dpc.h>
|
||||
#include <ke_syscall.h>
|
||||
#include <ethernet.h>
|
||||
#include <net_device.h>
|
||||
#include <ke_debug.h>
|
||||
#include <ke_util.h>
|
||||
#include <ldr_image.h>
|
||||
@@ -420,80 +420,6 @@ void SystemInitThread(void* arg) {
|
||||
MmFreePool(args);
|
||||
}
|
||||
|
||||
// for debug! for science!
|
||||
uint64_t KeCatchAllDebugBucket(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||
if (a0 == 0) {
|
||||
DbgPrint(
|
||||
"Memory Status:\n"
|
||||
" -> Free (PMM): %.2f MB\n"
|
||||
" -> Kernel Pool: %.2f MB\n"
|
||||
" -> User Heap: %.2f MB\n",
|
||||
(float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f),
|
||||
(float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f),
|
||||
(float)MmGetUserHeapUsage() / (1024.0f * 1024.0f)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a0 == 1) {
|
||||
uint32_t deviceIndex = (uint32_t)a1;
|
||||
uint32_t targetIp;
|
||||
|
||||
// Usage from shell debug mode:
|
||||
// 1,0,10,0,2,2 ping 10.0.2.2 on eth0
|
||||
// 1,0,167772674,0,0,0 ping packed IPv4 0x0A000202 on eth0
|
||||
// 1,0,0,0,0,0 ping the default QEMU gateway 10.0.2.2
|
||||
if (a2 == 0 && a3 == 0 && a4 == 0 && a5 == 0) {
|
||||
targetIp = NET_IPV4_ADDR(10, 0, 2, 2);
|
||||
} else if (a3 == 0 && a4 == 0 && a5 == 0 && a2 > 0xFFu) {
|
||||
targetIp = (uint32_t)a2;
|
||||
} else {
|
||||
if (a2 > 0xFFu || a3 > 0xFFu || a4 > 0xFFu || a5 > 0xFFu) {
|
||||
DbgPrint("DebugBucket[1]: invalid IPv4 octet(s): %llu.%llu.%llu.%llu\n",
|
||||
a2, a3, a4, a5);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
targetIp = NET_IPV4_ADDR((uint8_t)a2, (uint8_t)a3,
|
||||
(uint8_t)a4, (uint8_t)a5);
|
||||
}
|
||||
|
||||
DbgPrint("DebugBucket[1]: ping eth%u %u.%u.%u.%u\n",
|
||||
deviceIndex,
|
||||
(targetIp >> 24) & 0xFFu,
|
||||
(targetIp >> 16) & 0xFFu,
|
||||
(targetIp >> 8) & 0xFFu,
|
||||
targetIp & 0xFFu);
|
||||
|
||||
KSTATUS status = NetPingIpv4(deviceIndex, targetIp);
|
||||
DbgPrint("DebugBucket[1]: NetPingIpv4 returned 0x%X\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (a0 == 2) {
|
||||
LIST_ENTRY* listHead = KeGetProcessList();
|
||||
LIST_ENTRY* current;
|
||||
|
||||
DbgPrint("\nPID | Name | Threads | ExitCode\n");
|
||||
DbgPrint("---------------------------------------------\n");
|
||||
|
||||
for (current = listHead->Fwd; current != listHead; current = current->Fwd) {
|
||||
// Translate the list entry back to the PROCESS structure
|
||||
PROCESS* proc = CONTAINING_RECORD(current, PROCESS, GlobalLink);
|
||||
|
||||
DbgPrint("%-5u | %-16s | %-7u | %d\n",
|
||||
proc->ProcessId,
|
||||
proc->Name,
|
||||
proc->ThreadCount,
|
||||
proc->ExitCode);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
DbgPrint("DebugBucket: unknown command %llu\n", a0);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main Kernel Entry
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -557,7 +483,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
||||
|
||||
HalRegisterScheduler(KeSchedulerTick);
|
||||
|
||||
KeSyscallInit(hal, KeCatchAllDebugBucket);
|
||||
KeSyscallInit(hal);
|
||||
|
||||
//
|
||||
// Dynamic Linking & Driver Execution
|
||||
|
||||
+175
-12
@@ -41,6 +41,12 @@ static PHYSICAL_ADDRESS gPml4Phys = 0;
|
||||
#define PDT_IDX(va) (((va) >> 21) & 0x1FF)
|
||||
#define PT_IDX(va) (((va) >> 12) & 0x1FF)
|
||||
|
||||
#define PAGE_PS (1ULL << 7)
|
||||
#define PAGE_FLAGS_MASK (0xFFFULL | PAGE_NX)
|
||||
#define PAGE_FRAME_4K_MASK 0x000FFFFFFFFFF000ULL
|
||||
#define PAGE_FRAME_2M_MASK 0x000FFFFFFFE00000ULL
|
||||
#define PAGE_FRAME_1G_MASK 0x000FFFFFC0000000ULL
|
||||
|
||||
// Ensure a page-table entry at 'parentPhys[index]' points to a child table.
|
||||
// Allocates and zeros a new frame if the entry is not present.
|
||||
// Returns the physical address of the child table, or 0 on OOM.
|
||||
@@ -49,7 +55,7 @@ static PHYSICAL_ADDRESS KiEnsureTable(PHYSICAL_ADDRESS parentPhys,
|
||||
uint64_t* entry = KiPtePtr(parentPhys, index);
|
||||
if (*entry & PAGE_PRESENT) {
|
||||
*entry |= extraFlags;
|
||||
return* entry & ~0xFFFULL;
|
||||
return *entry & PAGE_FRAME_4K_MASK;
|
||||
}
|
||||
PHYSICAL_ADDRESS childPhys = MmAllocateFrame();
|
||||
if (!childPhys) return 0;
|
||||
@@ -80,11 +86,11 @@ __declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, u
|
||||
__declspec(dllexport) KSTATUS MmUnmapPage(uintptr_t virt) {
|
||||
uint64_t* e4 = KiPtePtr(gPml4Phys, PML4_IDX(virt));
|
||||
if (!(*e4 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
uint64_t* e3 = KiPtePtr(*e4 & ~0xFFFULL, PDPT_IDX(virt));
|
||||
uint64_t* e3 = KiPtePtr(*e4 & PAGE_FRAME_4K_MASK, PDPT_IDX(virt));
|
||||
if (!(*e3 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
uint64_t* e2 = KiPtePtr(*e3 & ~0xFFFULL, PDT_IDX(virt));
|
||||
uint64_t* e2 = KiPtePtr(*e3 & PAGE_FRAME_4K_MASK, PDT_IDX(virt));
|
||||
if (!(*e2 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
uint64_t* pte = KiPtePtr(*e2 & ~0xFFFULL, PT_IDX(virt));
|
||||
uint64_t* pte = KiPtePtr(*e2 & PAGE_FRAME_4K_MASK, PT_IDX(virt));
|
||||
*pte = 0;
|
||||
__invlpg((void *)virt);
|
||||
return STATUS_SUCCESS;
|
||||
@@ -100,15 +106,15 @@ __declspec(dllexport) KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint
|
||||
for (uintptr_t va = base; va < end; va += PAGE_SIZE) {
|
||||
uint64_t* e4 = KiPtePtr(gPml4Phys, PML4_IDX(va));
|
||||
if (!(*e4 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
uint64_t* e3 = KiPtePtr(*e4 & ~0xFFFULL, PDPT_IDX(va));
|
||||
uint64_t* e3 = KiPtePtr(*e4 & PAGE_FRAME_4K_MASK, PDPT_IDX(va));
|
||||
if (!(*e3 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
uint64_t* e2 = KiPtePtr(*e3 & ~0xFFFULL, PDT_IDX(va));
|
||||
uint64_t* e2 = KiPtePtr(*e3 & PAGE_FRAME_4K_MASK, PDT_IDX(va));
|
||||
if (!(*e2 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
uint64_t* pte = KiPtePtr(*e2 & ~0xFFFULL, PT_IDX(va));
|
||||
uint64_t* pte = KiPtePtr(*e2 & PAGE_FRAME_4K_MASK, PT_IDX(va));
|
||||
if (!(*pte & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
|
||||
// Preserve the physical address, replace everything else.
|
||||
PHYSICAL_ADDRESS phys = *pte & ~0xFFFULL & ~PAGE_NX;
|
||||
PHYSICAL_ADDRESS phys = *pte & PAGE_FRAME_4K_MASK;
|
||||
*pte = phys | flags;
|
||||
__invlpg((void *)va);
|
||||
}
|
||||
@@ -127,7 +133,7 @@ __declspec(dllexport) PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt) {
|
||||
uint64_t* pml4 = KiPhysToVirt(gPml4Phys);
|
||||
if (!(pml4[pml4_idx] & PAGE_PRESENT)) return 0;
|
||||
|
||||
uint64_t* pdpt = KiPhysToVirt(pml4[pml4_idx] & ~0xFFFULL);
|
||||
uint64_t* pdpt = KiPhysToVirt(pml4[pml4_idx] & PAGE_FRAME_4K_MASK);
|
||||
if (!(pdpt[pdpt_idx] & PAGE_PRESENT)) return 0;
|
||||
|
||||
// Check for 1GB huge pages (bit 7 - PS)
|
||||
@@ -135,7 +141,7 @@ __declspec(dllexport) PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt) {
|
||||
return (pdpt[pdpt_idx] & 0x000FFFFFC0000000ULL) + (virt & 0x3FFFFFFF);
|
||||
}
|
||||
|
||||
uint64_t* pd = KiPhysToVirt(pdpt[pdpt_idx] & ~0xFFFULL);
|
||||
uint64_t* pd = KiPhysToVirt(pdpt[pdpt_idx] & PAGE_FRAME_4K_MASK);
|
||||
if (!(pd[pd_idx] & PAGE_PRESENT)) return 0;
|
||||
|
||||
// Check for 2MB huge pages (bit 7 - PS)
|
||||
@@ -143,11 +149,168 @@ __declspec(dllexport) PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt) {
|
||||
return (pd[pd_idx] & 0x000FFFFFFFE00000ULL) + (virt & 0x1FFFFF);
|
||||
}
|
||||
|
||||
uint64_t* pt = KiPhysToVirt(pd[pd_idx] & ~0xFFFULL);
|
||||
uint64_t* pt = KiPhysToVirt(pd[pd_idx] & PAGE_FRAME_4K_MASK);
|
||||
if (!(pt[pt_idx] & PAGE_PRESENT)) return 0;
|
||||
|
||||
// Extract the physical frame and add the offset within the page
|
||||
return (pt[pt_idx] & ~0xFFFULL) + (virt & 0xFFF);
|
||||
return (pt[pt_idx] & PAGE_FRAME_4K_MASK) + (virt & 0xFFF);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page query and user/kernel copy boundary helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS MmQueryPage(uintptr_t virt,
|
||||
PHYSICAL_ADDRESS* physOut,
|
||||
uint64_t* flagsOut) {
|
||||
if (!gPml4Phys) return STATUS_NOT_FOUND;
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)KiPhysToVirt(gPml4Phys);
|
||||
uint64_t e4 = pml4[PML4_IDX(virt)];
|
||||
if (!(e4 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
|
||||
uint64_t effectiveWrite = e4 & PAGE_WRITE;
|
||||
uint64_t effectiveUser = e4 & PAGE_USER;
|
||||
uint64_t effectiveNx = e4 & PAGE_NX;
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)KiPhysToVirt(e4 & PAGE_FRAME_4K_MASK);
|
||||
uint64_t e3 = pdpt[PDPT_IDX(virt)];
|
||||
if (!(e3 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
effectiveWrite &= e3 & PAGE_WRITE;
|
||||
effectiveUser &= e3 & PAGE_USER;
|
||||
effectiveNx |= e3 & PAGE_NX;
|
||||
|
||||
if (e3 & PAGE_PS) {
|
||||
if (physOut)
|
||||
*physOut = (e3 & PAGE_FRAME_1G_MASK) + (virt & 0x3FFFFFFFULL);
|
||||
if (flagsOut) {
|
||||
uint64_t flags = (e3 & PAGE_FLAGS_MASK) | effectiveNx;
|
||||
if (!effectiveWrite) flags &= ~PAGE_WRITE;
|
||||
if (!effectiveUser) flags &= ~PAGE_USER;
|
||||
*flagsOut = flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uint64_t* pd = (uint64_t*)KiPhysToVirt(e3 & PAGE_FRAME_4K_MASK);
|
||||
uint64_t e2 = pd[PDT_IDX(virt)];
|
||||
if (!(e2 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
effectiveWrite &= e2 & PAGE_WRITE;
|
||||
effectiveUser &= e2 & PAGE_USER;
|
||||
effectiveNx |= e2 & PAGE_NX;
|
||||
|
||||
if (e2 & PAGE_PS) {
|
||||
if (physOut)
|
||||
*physOut = (e2 & PAGE_FRAME_2M_MASK) + (virt & 0x1FFFFFULL);
|
||||
if (flagsOut) {
|
||||
uint64_t flags = (e2 & PAGE_FLAGS_MASK) | effectiveNx;
|
||||
if (!effectiveWrite) flags &= ~PAGE_WRITE;
|
||||
if (!effectiveUser) flags &= ~PAGE_USER;
|
||||
*flagsOut = flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uint64_t* pt = (uint64_t*)KiPhysToVirt(e2 & PAGE_FRAME_4K_MASK);
|
||||
uint64_t e1 = pt[PT_IDX(virt)];
|
||||
if (!(e1 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
|
||||
effectiveWrite &= e1 & PAGE_WRITE;
|
||||
effectiveUser &= e1 & PAGE_USER;
|
||||
effectiveNx |= e1 & PAGE_NX;
|
||||
|
||||
if (physOut)
|
||||
*physOut = (e1 & PAGE_FRAME_4K_MASK) + (virt & 0xFFFULL);
|
||||
if (flagsOut) {
|
||||
uint64_t flags = (e1 & PAGE_FLAGS_MASK) | effectiveNx;
|
||||
if (!effectiveWrite) flags &= ~PAGE_WRITE;
|
||||
if (!effectiveUser) flags &= ~PAGE_USER;
|
||||
*flagsOut = flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int KiUserRangeValid(uintptr_t addr, size_t size) {
|
||||
if (size == 0) return 1;
|
||||
if (addr < USER_BASE) return 0;
|
||||
if (addr >= USER_LIMIT) return 0;
|
||||
if (size > (size_t)(USER_LIMIT - addr)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static KSTATUS KiProbeUserRange(uintptr_t addr, size_t size, uint64_t requiredFlags) {
|
||||
if (!KiUserRangeValid(addr, size))
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
if (size == 0)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
uintptr_t va = addr & PAGE_MASK;
|
||||
uintptr_t last = (addr + size - 1) & PAGE_MASK;
|
||||
|
||||
for (;;) {
|
||||
uint64_t flags = 0;
|
||||
KSTATUS s = MmQueryPage(va, (PHYSICAL_ADDRESS*)0, &flags);
|
||||
if (!KSUCCESS(s))
|
||||
return STATUS_ACCESS_DENIED;
|
||||
if ((flags & requiredFlags) != requiredFlags)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
if (va == last)
|
||||
break;
|
||||
va += PAGE_SIZE;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS MmProbeUserRead(const void* ptr, size_t size) {
|
||||
return KiProbeUserRange((uintptr_t)ptr, size, PAGE_PRESENT | PAGE_USER);
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS MmProbeUserWrite(void* ptr, size_t size) {
|
||||
return KiProbeUserRange((uintptr_t)ptr, size, PAGE_PRESENT | PAGE_USER | PAGE_WRITE);
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS CopyFromUser(void* kernelDst, const void* userSrc, size_t size) {
|
||||
if (!kernelDst && size) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS s = MmProbeUserRead(userSrc, size);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
if (size) memcpy(kernelDst, userSrc, size);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS CopyToUser(void* userDst, const void* kernelSrc, size_t size) {
|
||||
if (!kernelSrc && size) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS s = MmProbeUserWrite(userDst, size);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
if (size) memcpy(userDst, kernelSrc, size);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS CopyStringFromUser(char* kernelDst,
|
||||
size_t kernelDstSize,
|
||||
const char* userSrc) {
|
||||
if (!kernelDst || kernelDstSize == 0 || !userSrc)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
for (size_t i = 0; i < kernelDstSize; i++) {
|
||||
KSTATUS s = MmProbeUserRead(userSrc + i, 1);
|
||||
if (!KSUCCESS(s)) {
|
||||
kernelDst[0] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
char ch = userSrc[i];
|
||||
kernelDst[i] = ch;
|
||||
if (ch == '\0')
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
kernelDst[kernelDstSize - 1] = '\0';
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -53,6 +53,31 @@ __declspec(dllexport) KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint
|
||||
// Returns 0 if the address is not mapped.
|
||||
__declspec(dllexport) PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt);
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// User/kernel copy boundary helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
// MmQueryPage returns the physical address and effective PAGE_* bits for a
|
||||
// mapped virtual address. The reported PAGE_USER/PAGE_WRITE bits account for
|
||||
// every page-table level, not just the leaf entry.
|
||||
__declspec(dllexport) KSTATUS MmQueryPage(uintptr_t virt, PHYSICAL_ADDRESS* physOut, uint64_t* flagsOut);
|
||||
|
||||
// Probe a user virtual range without copying it. These functions only accept
|
||||
// lower-half user mappings with PAGE_USER set; MmProbeUserWrite additionally
|
||||
// requires PAGE_WRITE.
|
||||
__declspec(dllexport) KSTATUS MmProbeUserRead(const void* ptr, size_t size);
|
||||
__declspec(dllexport) KSTATUS MmProbeUserWrite(void* ptr, size_t size);
|
||||
|
||||
// Copy through the syscall trust boundary. Kernel subsystems should receive
|
||||
// kernel-owned buffers, not raw user pointers, unless explicitly documented.
|
||||
__declspec(dllexport) KSTATUS CopyFromUser(void* kernelDst, const void* userSrc, size_t size);
|
||||
__declspec(dllexport) KSTATUS CopyToUser(void* userDst, const void* kernelSrc, size_t size);
|
||||
|
||||
// Bounded NUL-terminated string import from user memory. Always NUL-terminates
|
||||
// kernelDst when kernelDstSize is non-zero. Returns STATUS_BUFFER_TOO_SMALL if
|
||||
// no NUL byte was found within kernelDstSize bytes.
|
||||
__declspec(dllexport) KSTATUS CopyStringFromUser(char* kernelDst, size_t kernelDstSize, const char* userSrc);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Kernel pool - ring 0 only, never PAGE_USER.
|
||||
// Best-fit free-list allocator, thread-safe via spinlock.
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
// net_abi.h - native networking ABI shared by the kernel socket facade
|
||||
// and network stack provider drivers.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define SYS_AF_INET 2u
|
||||
#define SYS_SOCK_STREAM 1u
|
||||
#define SYS_SOCK_DGRAM 2u
|
||||
#define SYS_SOCK_RAW 3u
|
||||
#define SYS_IPPROTO_ICMP 1u
|
||||
#define SYS_IPPROTO_TCP 6u
|
||||
#define SYS_IPPROTO_UDP 17u
|
||||
|
||||
#define SYS_SHUTDOWN_READ 0u
|
||||
#define SYS_SHUTDOWN_WRITE 1u
|
||||
#define SYS_SHUTDOWN_BOTH 2u
|
||||
|
||||
#define SYS_SOCKET_ADDRESS_IPV4_SIZE 16u
|
||||
#define SYS_RESOLVE_HOST_NAME_MAX 255u
|
||||
|
||||
#define SYS_SOCKET_OPT_RECV_TIMEOUT_MS 1u
|
||||
#define SYS_SOCKET_OPT_SEND_TIMEOUT_MS 2u
|
||||
#define SYS_SOCKET_OPT_NONBLOCKING 3u
|
||||
|
||||
#define SYS_POLL_READ 0x0001u
|
||||
#define SYS_POLL_WRITE 0x0002u
|
||||
#define SYS_POLL_ERROR 0x0004u
|
||||
#define SYS_POLL_HANGUP 0x0008u
|
||||
#define SYS_POLL_INVALID 0x0010u
|
||||
#define SYS_POLL_TIMEOUT_INFINITE 0xFFFFFFFFu
|
||||
|
||||
typedef struct SYS_SOCKET_ADDRESS_IPV4_K {
|
||||
uint16_t Family; // SYS_AF_INET
|
||||
uint16_t Port; // host byte order
|
||||
uint8_t Address[4]; // dotted-quad bytes, e.g. {10,0,2,2}
|
||||
uint8_t Reserved[8];
|
||||
} SYS_SOCKET_ADDRESS_IPV4_K;
|
||||
|
||||
typedef struct SYS_POLLFD_K {
|
||||
uint32_t Handle;
|
||||
uint32_t Events;
|
||||
uint32_t ReturnedEvents;
|
||||
} SYS_POLLFD_K;
|
||||
+20
-23
@@ -1,15 +1,14 @@
|
||||
// net_device.c - minimal network-device registry and RX handoff.
|
||||
// net_device.c - minimal network-device registry and stack-provider RX handoff.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <net_device.h>
|
||||
#include <ethernet.h>
|
||||
#include <net_stack.h>
|
||||
#include <ke_debug.h>
|
||||
#include <ke_spinlock.h>
|
||||
|
||||
#define NET_MAX_DEVICES 8u
|
||||
#define NET_RX_LOG_LIMIT 16u
|
||||
|
||||
static NET_DEVICE* gNetDevices[NET_MAX_DEVICES];
|
||||
static uint32_t gNetDeviceCount = 0;
|
||||
@@ -19,8 +18,6 @@ static void NetMakeDefaultName(NET_DEVICE* device, uint32_t index) {
|
||||
if (!device || device->Name[0])
|
||||
return;
|
||||
|
||||
// The registry is currently capped at eight devices, so ethN is enough and
|
||||
// keeps the name stable for early boot diagnostics.
|
||||
device->Name[0] = 'e';
|
||||
device->Name[1] = 't';
|
||||
device->Name[2] = 'h';
|
||||
@@ -81,7 +78,15 @@ __declspec(dllexport) KSTATUS NetRegisterDevice(NET_DEVICE* device) {
|
||||
NetLogHardwareAddress(device);
|
||||
DbgPrint(" mtu=%u\n", device->Mtu);
|
||||
|
||||
NetEthernetAttachDevice(device);
|
||||
const NET_STACK_PROVIDER* provider = NetGetStackProvider();
|
||||
if (provider && provider->AttachDevice) {
|
||||
KSTATUS attach = provider->AttachDevice(device);
|
||||
if (!KSUCCESS(attach)) {
|
||||
DbgPrint("NET: provider %s attach for %s failed: 0x%x\n",
|
||||
provider->Name, device->Name, attach);
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -140,8 +145,6 @@ __declspec(dllexport) KSTATUS NetSendFrame(uint32_t index,
|
||||
__declspec(dllexport) void NetReceiveFrame(NET_DEVICE* device,
|
||||
const void* frame,
|
||||
size_t length) {
|
||||
static volatile uint32_t sLoggedFrames = 0;
|
||||
|
||||
if (!device || !frame || length < NET_ETHERNET_HEADER_LENGTH) {
|
||||
if (device) {
|
||||
uintptr_t dropFlags = KeAcquireSpinlock(&gNetLock);
|
||||
@@ -156,20 +159,14 @@ __declspec(dllexport) void NetReceiveFrame(NET_DEVICE* device,
|
||||
device->Stats.RxBytes += length;
|
||||
KeReleaseSpinlock(&gNetLock, flags);
|
||||
|
||||
// Temporary observability until lwIP is attached. Avoid spamming the
|
||||
// console on busy LANs. Log before protocol handling so RX/TX ordering is
|
||||
// easier to read when an interrupt fires during a send path.
|
||||
if (sLoggedFrames < NET_RX_LOG_LIMIT) {
|
||||
const uint8_t* b = (const uint8_t*)frame;
|
||||
uint16_t etherType = ((uint16_t)b[12] << 8) | b[13];
|
||||
DbgPrint("NET: %s rx len=%u ethertype=0x%04x dst=%02x:%02x:%02x:%02x:%02x:%02x src=%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
device->Name,
|
||||
(unsigned)length,
|
||||
etherType,
|
||||
b[0], b[1], b[2], b[3], b[4], b[5],
|
||||
b[6], b[7], b[8], b[9], b[10], b[11]);
|
||||
sLoggedFrames++;
|
||||
}
|
||||
const NET_STACK_PROVIDER* provider = NetGetStackProvider();
|
||||
KSTATUS rxStatus = STATUS_NOT_SUPPORTED;
|
||||
if (provider && provider->ReceiveFrame)
|
||||
rxStatus = provider->ReceiveFrame(device, frame, length);
|
||||
|
||||
NetEthernetReceive(device, frame, length);
|
||||
if (!KSUCCESS(rxStatus)) {
|
||||
uintptr_t dropFlags = KeAcquireSpinlock(&gNetLock);
|
||||
device->Stats.RxDrops++;
|
||||
KeReleaseSpinlock(&gNetLock, dropFlags);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
// net_device.h - tiny kernel network-device registry.
|
||||
// net_device.h - kernel network-device registry.
|
||||
//
|
||||
// This layer is intentionally below the future socket/IP stack. NIC drivers
|
||||
// register a NET_DEVICE and feed complete Ethernet frames into NetReceiveFrame().
|
||||
// Protocol code can later subscribe above this layer or bind a real stack.
|
||||
// NIC drivers register NET_DEVICE objects here and feed complete Ethernet
|
||||
// frames into NetReceiveFrame(). Protocol ownership belongs to whichever
|
||||
// network stack driver registered through net_stack.h.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// net_socket.c - process-owned socket objects with provider-neutral dispatch.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <net_socket.h>
|
||||
#include <net_stack.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
#define NET_SOCKET_IO_MAX_BYTES (1024u * 1024u)
|
||||
#define NET_SOCKET_UDP_MAX_BYTES 65507u
|
||||
#define NET_SOCKET_RAW_MAX_BYTES 65535u
|
||||
|
||||
static void NetSocketDestroy(OBJECT* object) {
|
||||
SOCKET_OBJECT* socket = (SOCKET_OBJECT*)object;
|
||||
if (socket->Provider && socket->ProviderSocket) {
|
||||
socket->Provider->SocketClose(socket->ProviderSocket);
|
||||
socket->ProviderSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static KSTATUS NetSocketAllocate(const NET_STACK_PROVIDER* provider,
|
||||
void* providerSocket,
|
||||
uint32_t domain,
|
||||
uint32_t type,
|
||||
uint32_t protocol,
|
||||
SOCKET_OBJECT** out) {
|
||||
if (!provider || !providerSocket || !out)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
SOCKET_OBJECT* socket = (SOCKET_OBJECT*)ObAllocateObject(ObjectTypeSocket, sizeof(SOCKET_OBJECT));
|
||||
if (!socket)
|
||||
return STATUS_NO_MEMORY;
|
||||
|
||||
socket->Header.Destroy = NetSocketDestroy;
|
||||
socket->Provider = provider;
|
||||
socket->ProviderSocket = providerSocket;
|
||||
socket->Domain = domain;
|
||||
socket->Type = type;
|
||||
socket->Protocol = protocol;
|
||||
*out = socket;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static KSTATUS NetSocketGetProviderSocket(SOCKET_OBJECT* socket,
|
||||
const NET_STACK_PROVIDER** providerOut,
|
||||
void** providerSocketOut) {
|
||||
if (!socket || !providerOut || !providerSocketOut)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (!socket->Provider || !socket->ProviderSocket)
|
||||
return STATUS_OBJECT_DEAD;
|
||||
|
||||
*providerOut = socket->Provider;
|
||||
*providerSocketOut = socket->ProviderSocket;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketCreate(uint32_t domain, uint32_t type, uint32_t protocol, SOCKET_OBJECT** out) {
|
||||
if (!out)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
*out = NULL;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NetGetStackProvider();
|
||||
if (!provider)
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = provider->SocketCreate(domain, type, protocol, &providerSocket);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
if (!providerSocket)
|
||||
return STATUS_FAILURE;
|
||||
|
||||
st = NetSocketAllocate(provider, providerSocket, domain, type, protocol, out);
|
||||
if (!KSUCCESS(st))
|
||||
provider->SocketClose(providerSocket);
|
||||
return st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketBind(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Bind(providerSocket, address, addressSize) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketListen(SOCKET_OBJECT* socket, uint32_t backlog) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Listen(providerSocket, backlog) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketAccept(SOCKET_OBJECT* socket, SOCKET_OBJECT** acceptedOut, SYS_SOCKET_ADDRESS_IPV4_K* remoteOut) {
|
||||
if (!acceptedOut)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
*acceptedOut = NULL;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
void* acceptedProviderSocket = NULL;
|
||||
st = provider->Accept(providerSocket, &acceptedProviderSocket, remoteOut);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
if (!acceptedProviderSocket)
|
||||
return STATUS_FAILURE;
|
||||
|
||||
st = NetSocketAllocate(provider,
|
||||
acceptedProviderSocket,
|
||||
socket->Domain,
|
||||
socket->Type,
|
||||
socket->Protocol,
|
||||
acceptedOut);
|
||||
if (!KSUCCESS(st))
|
||||
provider->SocketClose(acceptedProviderSocket);
|
||||
return st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketConnect(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Connect(providerSocket, address, addressSize) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketSend(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut) {
|
||||
if (sentOut)
|
||||
*sentOut = 0;
|
||||
if (!buffer && length)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (length > NET_SOCKET_IO_MAX_BYTES)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Send(providerSocket, buffer, length, flags, sentOut) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketReceive(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut) {
|
||||
if (receivedOut)
|
||||
*receivedOut = 0;
|
||||
if (!buffer && length)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (length > NET_SOCKET_IO_MAX_BYTES)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Receive(providerSocket, buffer, length, flags, receivedOut) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketSendTo(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags,
|
||||
const SYS_SOCKET_ADDRESS_IPV4_K* remote, size_t remoteSize, size_t* sentOut) {
|
||||
if (sentOut)
|
||||
*sentOut = 0;
|
||||
if (!buffer && length)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (socket && socket->Type == SYS_SOCK_DGRAM && length > NET_SOCKET_UDP_MAX_BYTES)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (socket && socket->Type == SYS_SOCK_RAW && length > NET_SOCKET_RAW_MAX_BYTES)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (socket && socket->Type != SYS_SOCK_DGRAM && socket->Type != SYS_SOCK_RAW)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->SendTo(providerSocket, buffer, length, flags, remote, remoteSize, sentOut) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketReceiveFrom(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags,
|
||||
SYS_SOCKET_ADDRESS_IPV4_K* remoteOut, size_t* receivedOut) {
|
||||
if (receivedOut)
|
||||
*receivedOut = 0;
|
||||
if (!buffer && length)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (socket && socket->Type == SYS_SOCK_DGRAM && length > NET_SOCKET_UDP_MAX_BYTES)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (socket && socket->Type == SYS_SOCK_RAW && length > NET_SOCKET_RAW_MAX_BYTES)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (socket && socket->Type != SYS_SOCK_DGRAM && socket->Type != SYS_SOCK_RAW)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->ReceiveFrom(providerSocket, buffer, length, flags, remoteOut, receivedOut) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketShutdown(SOCKET_OBJECT* socket, uint32_t how) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Shutdown(providerSocket, how) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketSetOption(SOCKET_OBJECT* socket, uint32_t option, const void* value, size_t valueSize) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->SetOption(providerSocket, option, value, valueSize) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketGetOption(SOCKET_OBJECT* socket, uint32_t option, void* value, size_t valueSize, size_t* actualSizeOut) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->GetOption(providerSocket, option, value, valueSize, actualSizeOut) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetSocketPoll(SOCKET_OBJECT* socket, uint32_t events, uint32_t* returnedEventsOut) {
|
||||
if (!returnedEventsOut)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
*returnedEventsOut = 0;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Poll(providerSocket, events, returnedEventsOut) : st;
|
||||
}
|
||||
|
||||
KSTATUS NetResolveHostIpv4(const char* name, SYS_SOCKET_ADDRESS_IPV4_K* addressOut) {
|
||||
if (!name || !addressOut)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
const NET_STACK_PROVIDER* provider = NetGetStackProvider();
|
||||
if (!provider)
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
|
||||
return provider->ResolveHostIpv4(name, addressOut);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
// net_socket.h - process-owned, provider-neutral kernel socket objects.
|
||||
//
|
||||
// The native networking ABI lives in net_abi.h. Protocol implementation lives
|
||||
// in a network stack driver registered through net_stack.h.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
#include <ob_object.h>
|
||||
#include <net_abi.h>
|
||||
|
||||
struct NET_STACK_PROVIDER;
|
||||
|
||||
typedef struct SOCKET_OBJECT {
|
||||
OBJECT Header; // must be first
|
||||
|
||||
const struct NET_STACK_PROVIDER* Provider;
|
||||
void* ProviderSocket;
|
||||
|
||||
uint32_t Domain;
|
||||
uint32_t Type;
|
||||
uint32_t Protocol;
|
||||
} SOCKET_OBJECT;
|
||||
|
||||
KSTATUS NetSocketCreate(uint32_t domain, uint32_t type, uint32_t protocol, SOCKET_OBJECT** out);
|
||||
KSTATUS NetSocketBind(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize);
|
||||
KSTATUS NetSocketListen(SOCKET_OBJECT* socket, uint32_t backlog);
|
||||
KSTATUS NetSocketAccept(SOCKET_OBJECT* socket, SOCKET_OBJECT** acceptedOut, SYS_SOCKET_ADDRESS_IPV4_K* remoteOut);
|
||||
KSTATUS NetSocketConnect(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize);
|
||||
KSTATUS NetSocketSend(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut);
|
||||
KSTATUS NetSocketReceive(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut);
|
||||
KSTATUS NetSocketSendTo(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags, const SYS_SOCKET_ADDRESS_IPV4_K* remote, size_t remoteSize, size_t* sentOut);
|
||||
KSTATUS NetSocketReceiveFrom(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags, SYS_SOCKET_ADDRESS_IPV4_K* remoteOut, size_t* receivedOut);
|
||||
KSTATUS NetSocketShutdown(SOCKET_OBJECT* socket, uint32_t how);
|
||||
KSTATUS NetSocketSetOption(SOCKET_OBJECT* socket, uint32_t option, const void* value, size_t valueSize);
|
||||
KSTATUS NetSocketGetOption(SOCKET_OBJECT* socket, uint32_t option, void* value, size_t valueSize, size_t* actualSizeOut);
|
||||
KSTATUS NetSocketPoll(SOCKET_OBJECT* socket, uint32_t events, uint32_t* returnedEventsOut);
|
||||
KSTATUS NetResolveHostIpv4(const char* name, SYS_SOCKET_ADDRESS_IPV4_K* addressOut);
|
||||
@@ -0,0 +1,65 @@
|
||||
// net_stack.c - single network stack provider registry.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <net_stack.h>
|
||||
#include <net_device.h>
|
||||
#include <ke_debug.h>
|
||||
#include <ke_spinlock.h>
|
||||
|
||||
static const NET_STACK_PROVIDER* gNetStackProvider = 0;
|
||||
static SPINLOCK gNetStackLock = SPINLOCK_INIT;
|
||||
|
||||
static KSTATUS NetValidateStackProvider(const NET_STACK_PROVIDER* p) {
|
||||
if (!p || p->Version != NET_STACK_PROVIDER_VERSION || !p->Name)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if (!p->AttachDevice || !p->ReceiveFrame || !p->SocketCreate || !p->SocketClose ||
|
||||
!p->Bind || !p->Listen || !p->Accept || !p->Connect ||
|
||||
!p->Send || !p->Receive || !p->SendTo || !p->ReceiveFrom ||
|
||||
!p->Shutdown || !p->SetOption || !p->GetOption || !p->Poll ||
|
||||
!p->ResolveHostIpv4) {
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS NetRegisterStackProvider(const NET_STACK_PROVIDER* provider) {
|
||||
KSTATUS st = NetValidateStackProvider(provider);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNetStackLock);
|
||||
if (gNetStackProvider) {
|
||||
KeReleaseSpinlock(&gNetStackLock, flags);
|
||||
return STATUS_ALREADY_EXISTS;
|
||||
}
|
||||
gNetStackProvider = provider;
|
||||
KeReleaseSpinlock(&gNetStackLock, flags);
|
||||
|
||||
DbgPrint("NET: registered stack provider %s\n", provider->Name);
|
||||
|
||||
// Stack drivers usually load before NIC drivers, but support the other
|
||||
// order so driver.ini remains simple while the loader is still flat.
|
||||
uint32_t count = NetGetDeviceCount();
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
NET_DEVICE* dev = NetGetDevice(i);
|
||||
if (!dev)
|
||||
continue;
|
||||
KSTATUS attach = provider->AttachDevice(dev);
|
||||
if (!KSUCCESS(attach)) {
|
||||
DbgPrint("NET: provider %s attach for %s failed: 0x%x\n",
|
||||
provider->Name, dev->Name, attach);
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) const NET_STACK_PROVIDER* NetGetStackProvider(void) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNetStackLock);
|
||||
const NET_STACK_PROVIDER* p = gNetStackProvider;
|
||||
KeReleaseSpinlock(&gNetStackLock, flags);
|
||||
return p;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
// net_stack.h - provider interface between kernel socket facade and network stack drivers.
|
||||
//
|
||||
// The kernel owns process handles, user-memory copying, NET_DEVICE registration,
|
||||
// and SOCKET_OBJECT lifetime. A stack driver owns protocol implementation.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
#include <net_device.h>
|
||||
#include <net_abi.h>
|
||||
|
||||
#define NET_STACK_PROVIDER_VERSION 1u
|
||||
|
||||
typedef struct NET_STACK_PROVIDER NET_STACK_PROVIDER;
|
||||
|
||||
struct NET_STACK_PROVIDER {
|
||||
uint32_t Version;
|
||||
const char* Name;
|
||||
|
||||
KSTATUS (*AttachDevice)(NET_DEVICE* device);
|
||||
KSTATUS (*ReceiveFrame)(NET_DEVICE* device, const void* frame, size_t length);
|
||||
|
||||
KSTATUS (*SocketCreate)(uint32_t domain, uint32_t type, uint32_t protocol, void** outSocket);
|
||||
void (*SocketClose)(void* socket);
|
||||
|
||||
KSTATUS (*Bind)(void* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize);
|
||||
KSTATUS (*Listen)(void* socket, uint32_t backlog);
|
||||
KSTATUS (*Accept)(void* socket, void** acceptedOut, SYS_SOCKET_ADDRESS_IPV4_K* remoteOut);
|
||||
KSTATUS (*Connect)(void* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize);
|
||||
|
||||
KSTATUS (*Send)(void* socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut);
|
||||
KSTATUS (*Receive)(void* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut);
|
||||
KSTATUS (*SendTo)(void* socket, const void* buffer, size_t length, uint32_t flags,
|
||||
const SYS_SOCKET_ADDRESS_IPV4_K* remote, size_t remoteSize, size_t* sentOut);
|
||||
KSTATUS (*ReceiveFrom)(void* socket, void* buffer, size_t length, uint32_t flags,
|
||||
SYS_SOCKET_ADDRESS_IPV4_K* remoteOut, size_t* receivedOut);
|
||||
|
||||
KSTATUS (*Shutdown)(void* socket, uint32_t how);
|
||||
KSTATUS (*SetOption)(void* socket, uint32_t option, const void* value, size_t valueSize);
|
||||
KSTATUS (*GetOption)(void* socket, uint32_t option, void* value, size_t valueSize, size_t* actualSizeOut);
|
||||
KSTATUS (*Poll)(void* socket, uint32_t events, uint32_t* returnedEventsOut);
|
||||
|
||||
KSTATUS (*ResolveHostIpv4)(const char* name, SYS_SOCKET_ADDRESS_IPV4_K* addressOut);
|
||||
};
|
||||
|
||||
__declspec(dllexport) KSTATUS NetRegisterStackProvider(const NET_STACK_PROVIDER* provider);
|
||||
__declspec(dllexport) const NET_STACK_PROVIDER* NetGetStackProvider(void);
|
||||
+35
-35
@@ -1,35 +1,35 @@
|
||||
// ob_object.c - executive object manager
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ob_object.h>
|
||||
#include <mm_virt.h>
|
||||
|
||||
OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size) {
|
||||
if (size < sizeof(OBJECT)) size = sizeof(OBJECT);
|
||||
|
||||
OBJECT* obj = (OBJECT *)MmAllocatePool(size);
|
||||
if (!obj) return (OBJECT *)0;
|
||||
|
||||
memset(obj, 0, size);
|
||||
obj->Type = type;
|
||||
obj->RefCount = 1;
|
||||
obj->Destroy = (void *)0; // caller fills this in
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ObReferenceObject(OBJECT* object) {
|
||||
if (!object) return;
|
||||
_InterlockedIncrement(&object->RefCount);
|
||||
}
|
||||
|
||||
void ObDereferenceObject(OBJECT* object) {
|
||||
if (!object) return;
|
||||
long prev = _InterlockedDecrement(&object->RefCount);
|
||||
if (prev == 0) {
|
||||
// Reference count hit zero - run the destructor then free.
|
||||
if (object->Destroy) {
|
||||
object->Destroy(object);
|
||||
}
|
||||
MmFreePool(object);
|
||||
}
|
||||
}
|
||||
// ob_object.c - executive object manager
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ob_object.h>
|
||||
#include <mm_virt.h>
|
||||
|
||||
__declspec(dllexport) OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size) {
|
||||
if (size < sizeof(OBJECT)) size = sizeof(OBJECT);
|
||||
|
||||
OBJECT* obj = (OBJECT *)MmAllocatePool(size);
|
||||
if (!obj) return (OBJECT *)0;
|
||||
|
||||
memset(obj, 0, size);
|
||||
obj->Type = type;
|
||||
obj->RefCount = 1;
|
||||
obj->Destroy = (void *)0; // caller fills this in
|
||||
return obj;
|
||||
}
|
||||
|
||||
__declspec(dllexport) void ObReferenceObject(OBJECT* object) {
|
||||
if (!object) return;
|
||||
_InterlockedIncrement(&object->RefCount);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void ObDereferenceObject(OBJECT* object) {
|
||||
if (!object) return;
|
||||
long prev = _InterlockedDecrement(&object->RefCount);
|
||||
if (prev == 0) {
|
||||
// Reference count hit zero - run the destructor then free.
|
||||
if (object->Destroy) {
|
||||
object->Destroy(object);
|
||||
}
|
||||
MmFreePool(object);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ typedef enum OBJECT_TYPE {
|
||||
ObjectTypeFile = 7,
|
||||
ObjectTypeDir = 8,
|
||||
ObjectTypeAsyncIo = 9,
|
||||
ObjectTypeSocket = 10,
|
||||
} OBJECT_TYPE;
|
||||
|
||||
typedef struct OBJECT {
|
||||
@@ -25,11 +26,11 @@ typedef struct OBJECT {
|
||||
} OBJECT;
|
||||
|
||||
// Increment the reference count. Call whenever ownership is shared.
|
||||
void ObReferenceObject(OBJECT* object);
|
||||
__declspec(dllexport) void ObReferenceObject(OBJECT* object);
|
||||
|
||||
// Decrement. Calls Destroy() and frees the object when count reaches zero.
|
||||
void ObDereferenceObject(OBJECT* object);
|
||||
__declspec(dllexport) void ObDereferenceObject(OBJECT* object);
|
||||
|
||||
// Allocate a zeroed object of the given size from kernel pool.
|
||||
// Caller must fill Type and Destroy before publishing the pointer.
|
||||
OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size);
|
||||
__declspec(dllexport) OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size);
|
||||
@@ -81,6 +81,20 @@
|
||||
#define SYS_GET_TICK 72
|
||||
#define SYS_DEBUG_PRINT 73
|
||||
#define SYS_QUERY_TRAP_FRAME 74
|
||||
#define SYS_CATCHALLDEBUGBUCKET 75
|
||||
#define SYS_SOCKET 75
|
||||
#define SYS_BIND 76
|
||||
#define SYS_LISTEN 77
|
||||
#define SYS_ACCEPT 78
|
||||
#define SYS_CONNECT 79
|
||||
#define SYS_SEND 80
|
||||
#define SYS_RECV 81
|
||||
#define SYS_SHUTDOWN 82
|
||||
#define SYS_SEND_TO 83
|
||||
#define SYS_RECV_FROM 84
|
||||
#define SYS_RESOLVE_HOST 85
|
||||
#define SYS_SET_SOCKET_OPTION 86
|
||||
#define SYS_GET_SOCKET_OPTION 87
|
||||
#define SYS_POLL 88
|
||||
#define SYS_GET_MEMORY_STATUS 89
|
||||
|
||||
#define SYS_MAX 76
|
||||
#define SYS_MAX 90
|
||||
Reference in new issue
Block a user