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:
maksw committed 2026-05-22 18:54:53 +02:00
1 parent 18b4dd0f61
commit df13b8056c
365 files changed
+143263 -1362

No files matched your search

+175 -12
View File
@@ -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;
}
// ---------------------------------------------------------------------------