fix: GUI and kernel fixes, Wikipedia app rewrite, among other things

This commit is contained in:
2026-02-21 11:08:11 +01:00
parent 596be25eaf
commit 9d5e7eac8d
97 changed files with 1844 additions and 662 deletions
+11
View File
@@ -833,6 +833,15 @@ namespace Zenith {
return WinServer::SendEvent(windowId, event);
}
static uint64_t Sys_WinResize(int windowId, int newW, int newH) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
uint64_t outVa = 0;
int r = WinServer::Resize(windowId, proc->pid, proc->pml4Phys, newW, newH,
proc->heapNext, outVa);
return (r == 0) ? outVa : 0;
}
// ---- Dispatch ----
extern "C" int64_t SyscallDispatch(SyscallFrame* frame) {
@@ -986,6 +995,8 @@ namespace Zenith {
return (int64_t)Sys_WinMap((int)frame->arg1);
case SYS_WINSENDEVENT:
return (int64_t)Sys_WinSendEvent((int)frame->arg1, (const WinEvent*)frame->arg2);
case SYS_WINRESIZE:
return (int64_t)Sys_WinResize((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_PROCLIST:
return (int64_t)Sys_ProcList((ProcInfo*)frame->arg1, (int)frame->arg2);
case SYS_KILL:
+1
View File
@@ -74,6 +74,7 @@ namespace Zenith {
static constexpr uint64_t SYS_WINENUM = 58;
static constexpr uint64_t SYS_WINMAP = 59;
static constexpr uint64_t SYS_WINSENDEVENT = 60;
static constexpr uint64_t SYS_WINRESIZE = 64;
// Process management syscalls
static constexpr uint64_t SYS_PROCLIST = 61;
+39
View File
@@ -162,6 +162,45 @@ namespace WinServer {
return 0;
}
int Resize(int windowId, int callerPid, uint64_t ownerPml4, int newW, int newH,
uint64_t& heapNext, uint64_t& outVa) {
if (windowId < 0 || windowId >= MaxWindows) return -1;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid) return -1;
if (newW <= 0 || newH <= 0) return -1;
if (newW == slot.width && newH == slot.height) {
outVa = slot.ownerVa;
return 0;
}
uint64_t bufSize = (uint64_t)newW * newH * 4;
int numPages = (int)((bufSize + 0xFFF) / 0x1000);
if (numPages > MaxPixelPages) return -1;
// Allocate new pages and map into owner's address space
uint64_t userVa = heapNext;
for (int i = 0; i < numPages; i++) {
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) return -1;
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
slot.pixelPhysPages[i] = physAddr;
Memory::VMM::Paging::MapUserIn(ownerPml4, physAddr, userVa + (uint64_t)i * 0x1000);
}
slot.width = newW;
slot.height = newH;
slot.pixelNumPages = numPages;
slot.ownerVa = userVa;
heapNext += (uint64_t)numPages * 0x1000;
// Invalidate desktop mapping so it re-maps on next enumerate
slot.desktopVa = 0;
slot.desktopPid = 0;
outVa = userVa;
return 0;
}
void CleanupProcess(int pid) {
for (int i = 0; i < MaxWindows; i++) {
if (g_slots[i].used && g_slots[i].ownerPid == pid) {
+2
View File
@@ -37,6 +37,8 @@ namespace WinServer {
int Enumerate(Zenith::WinInfo* outArray, int maxCount);
uint64_t Map(int windowId, int callerPid, uint64_t callerPml4, uint64_t& heapNext);
int SendEvent(int windowId, const Zenith::WinEvent* event);
int Resize(int windowId, int callerPid, uint64_t ownerPml4, int newW, int newH,
uint64_t& heapNext, uint64_t& outVa);
void CleanupProcess(int pid);
}
+1 -1
View File
@@ -109,7 +109,7 @@ namespace Drivers::Graphics::IntelGPU {
} else {
// Unknown device ID - accept generically but warn
g_gpuInfo.gen = 7; // Assume gen 7 as a safe default
g_gpuInfo.name = "Unknown Intel GPU";
g_gpuInfo.name = "Intel GPU";
KernelLogStream(WARNING, "IntelGPU") << "Unknown Intel display controller "
<< "(device " << base::hex << (uint64_t)found->DeviceId << ")"
+207 -12
View File
@@ -1,6 +1,6 @@
/*
* HidMouse.cpp
* USB HID Boot Protocol Mouse driver
* USB HID Mouse driver (Report Protocol with descriptor parsing)
* Copyright (c) 2025 Daniel Hammer
*/
@@ -18,6 +18,173 @@ namespace Drivers::USB::HidMouse {
// -------------------------------------------------------------------------
static uint8_t g_SlotId = 0;
static MouseReportFormat g_Format = {};
static bool g_FormatValid = false;
// -------------------------------------------------------------------------
// HID Report Descriptor parsing
// -------------------------------------------------------------------------
// HID item size lookup: bSize field (bits 0-1) → byte count
static uint8_t ItemDataSize(uint8_t bSize) {
static const uint8_t sizes[] = {0, 1, 2, 4};
return sizes[bSize & 0x03];
}
// Read an unsigned value from 1-4 bytes (little-endian)
static uint32_t ReadItemData(const uint8_t* p, uint8_t size) {
switch (size) {
case 1: return p[0];
case 2: return (uint32_t)p[0] | ((uint32_t)p[1] << 8);
case 4: return (uint32_t)p[0] | ((uint32_t)p[1] << 8)
| ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
default: return 0;
}
}
// HID usage page constants
static constexpr uint16_t USAGE_PAGE_GENERIC_DESKTOP = 0x01;
static constexpr uint16_t USAGE_PAGE_BUTTON = 0x09;
// HID usage constants (Generic Desktop)
static constexpr uint16_t USAGE_X = 0x30;
static constexpr uint16_t USAGE_Y = 0x31;
static constexpr uint16_t USAGE_WHEEL = 0x38;
// Maximum local usages we track between Input items
static constexpr int MAX_USAGES = 16;
void ParseReportDescriptor(const uint8_t* desc, uint16_t length) {
g_FormatValid = false;
MouseReportFormat fmt = {};
// Global state
uint16_t usagePage = 0;
uint32_t reportSize = 0; // bits per field
uint32_t reportCount = 0; // number of fields
// Local state (reset after each Main item)
uint16_t usages[MAX_USAGES] = {};
int usageCount = 0;
bool hasUsageRange = false;
// Running bit offset within the report (excluding report ID byte)
uint16_t bitOffset = 0;
uint16_t pos = 0;
while (pos < length) {
uint8_t header = desc[pos];
// Long items (0xFE prefix) — skip
if (header == 0xFE) {
if (pos + 1 >= length) break;
uint8_t dataSize = desc[pos + 1];
pos += 3 + dataSize;
continue;
}
uint8_t bSize = header & 0x03;
uint8_t bType = (header >> 2) & 0x03;
uint8_t bTag = (header >> 4) & 0x0F;
uint8_t dataSize = ItemDataSize(bSize);
if (pos + 1 + dataSize > length) break;
uint32_t data = ReadItemData(&desc[pos + 1], dataSize);
pos += 1 + dataSize;
if (bType == 1) {
// Global items
switch (bTag) {
case 0: usagePage = (uint16_t)data; break; // Usage Page
case 7: reportSize = data; break; // Report Size
case 8: fmt.hasReportId = true; // Report ID
fmt.reportId = (uint8_t)data; break;
case 9: reportCount = data; break; // Report Count
}
} else if (bType == 2) {
// Local items
switch (bTag) {
case 0: // Usage
if (usageCount < MAX_USAGES)
usages[usageCount++] = (uint16_t)data;
break;
case 1: hasUsageRange = true; break; // Usage Minimum
case 2: break; // Usage Maximum
}
} else if (bType == 0) {
// Main items
if (bTag == 8 || bTag == 9) {
// Input (tag 8) or Output (tag 9)
bool isConstant = (data & 0x01);
if (bTag == 8 && !isConstant) {
// Data input fields — map usages to bit offsets
if (usagePage == USAGE_PAGE_BUTTON && hasUsageRange) {
fmt.buttonBitOffset = bitOffset;
fmt.buttonCount = (uint8_t)reportCount;
} else if (usagePage == USAGE_PAGE_GENERIC_DESKTOP) {
for (uint32_t i = 0; i < reportCount && i < (uint32_t)usageCount; i++) {
uint16_t u = usages[i];
uint16_t off = bitOffset + (uint16_t)(i * reportSize);
if (u == USAGE_X) {
fmt.xBitOffset = off;
fmt.xBitSize = (uint8_t)reportSize;
} else if (u == USAGE_Y) {
fmt.yBitOffset = off;
fmt.yBitSize = (uint8_t)reportSize;
} else if (u == USAGE_WHEEL) {
fmt.scrollBitOffset = off;
fmt.scrollBitSize = (uint8_t)reportSize;
}
}
}
}
// Advance bit offset for all input fields (data and constant/padding)
bitOffset += (uint16_t)(reportSize * reportCount);
}
// Reset local state after any Main item
usageCount = 0;
hasUsageRange = false;
}
}
// Validate: we need at least X and Y
if (fmt.xBitSize > 0 && fmt.yBitSize > 0) {
g_Format = fmt;
g_FormatValid = true;
KernelLogStream(INFO, "USB/Mouse")
<< "Report format: buttons=" << (uint64_t)fmt.buttonCount
<< " X@" << (uint64_t)fmt.xBitOffset << ":" << (uint64_t)fmt.xBitSize
<< " Y@" << (uint64_t)fmt.yBitOffset << ":" << (uint64_t)fmt.yBitSize
<< " scroll=" << (uint64_t)fmt.scrollBitSize
<< (fmt.hasReportId ? " (has report ID)" : "");
} else {
KernelLogStream(WARNING, "USB/Mouse") << "Could not parse report descriptor, using boot protocol fallback";
}
}
// -------------------------------------------------------------------------
// Bit-field extraction
// -------------------------------------------------------------------------
static int32_t ExtractSigned(const uint8_t* data, uint16_t bitOffset, uint8_t bitSize) {
int32_t value = 0;
for (uint8_t i = 0; i < bitSize; i++) {
uint16_t byteIdx = (bitOffset + i) / 8;
uint8_t bitIdx = (bitOffset + i) % 8;
if (data[byteIdx] & (1 << bitIdx))
value |= (1 << i);
}
// Sign extend
if (bitSize < 32 && (value & (1 << (bitSize - 1)))) {
value |= ~((1 << bitSize) - 1);
}
return value;
}
// -------------------------------------------------------------------------
// Public API
@@ -25,25 +192,53 @@ namespace Drivers::USB::HidMouse {
void RegisterDevice(uint8_t slotId) {
g_SlotId = slotId;
KernelLogStream(OK, "USB/Mouse") << "Registered HID mouse on slot " << (uint64_t)slotId;
}
void ProcessReport(const uint8_t* data, uint16_t length) {
if (length < 3) return;
// Boot protocol mouse report:
// Byte 0: Buttons (bit 0 = left, bit 1 = right, bit 2 = middle)
// Byte 1: X displacement (signed int8_t)
// Byte 2: Y displacement (signed int8_t)
// Byte 3: Scroll wheel (signed int8_t, optional)
if (!g_FormatValid) {
// Fallback: assume boot protocol format
uint8_t buttons = data[0] & 0x07;
int8_t deltaX = (int8_t)data[1];
int8_t deltaY = (int8_t)data[2];
int8_t scroll = (length >= 4) ? (int8_t)data[3] : 0;
Drivers::PS2::Mouse::InjectMouseReport(buttons, deltaX, deltaY, scroll);
return;
}
uint8_t buttons = data[0] & 0x07;
int8_t deltaX = (int8_t)data[1];
int8_t deltaY = (int8_t)data[2];
int8_t scroll = (length >= 4) ? (int8_t)data[3] : 0;
// Skip report ID byte if present
uint16_t byteOffset = g_Format.hasReportId ? 8 : 0;
Drivers::PS2::Mouse::InjectMouseReport(buttons, deltaX, deltaY, scroll);
// Extract buttons
uint8_t buttons = 0;
for (uint8_t i = 0; i < g_Format.buttonCount && i < 8; i++) {
uint16_t bit = byteOffset + g_Format.buttonBitOffset + i;
if (data[bit / 8] & (1 << (bit % 8)))
buttons |= (1 << i);
}
// Extract X, Y
int32_t rawX = ExtractSigned(data, byteOffset + g_Format.xBitOffset, g_Format.xBitSize);
int32_t rawY = ExtractSigned(data, byteOffset + g_Format.yBitOffset, g_Format.yBitSize);
// Clamp to int8_t range for InjectMouseReport
if (rawX > 127) rawX = 127;
if (rawX < -128) rawX = -128;
if (rawY > 127) rawY = 127;
if (rawY < -128) rawY = -128;
// Extract scroll wheel
int8_t scroll = 0;
if (g_Format.scrollBitSize > 0) {
int32_t rawScroll = ExtractSigned(data, byteOffset + g_Format.scrollBitOffset, g_Format.scrollBitSize);
if (rawScroll > 127) rawScroll = 127;
if (rawScroll < -128) rawScroll = -128;
scroll = (int8_t)rawScroll;
}
Drivers::PS2::Mouse::InjectMouseReport(buttons, (int8_t)rawX, (int8_t)rawY, scroll);
}
}
+20 -2
View File
@@ -1,6 +1,6 @@
/*
* HidMouse.hpp
* USB HID Boot Protocol Mouse driver
* USB HID Mouse driver (Report Protocol with descriptor parsing)
* Copyright (c) 2025 Daniel Hammer
*/
@@ -9,10 +9,28 @@
namespace Drivers::USB::HidMouse {
// Parsed layout of a mouse HID report
struct MouseReportFormat {
bool hasReportId;
uint8_t reportId;
uint8_t buttonBitOffset; // bit offset of first button
uint8_t buttonCount;
uint8_t xBitOffset;
uint8_t xBitSize; // 8 or 16 typically
uint8_t yBitOffset;
uint8_t yBitSize;
uint8_t scrollBitOffset;
uint8_t scrollBitSize; // 0 = no scroll wheel
};
// Register a mouse device by slot ID
void RegisterDevice(uint8_t slotId);
// Process a 3-4 byte boot protocol mouse report
// Parse a HID Report Descriptor to determine the report layout.
// Must be called before ProcessReport for Report Protocol mice.
void ParseReportDescriptor(const uint8_t* desc, uint16_t length);
// Process an incoming mouse report using the parsed format
void ProcessReport(const uint8_t* data, uint16_t length);
};
+28 -2
View File
@@ -339,6 +339,7 @@ namespace Drivers::USB::UsbDevice {
uint16_t offset = 0;
bool foundHid = false;
bool foundEp = false;
uint16_t hidReportDescLen = 0;
while (offset + 2 <= totalLen) {
uint8_t len = cfgBuf[offset];
@@ -360,6 +361,12 @@ namespace Drivers::USB::UsbDevice {
}
}
// HID descriptor (0x21): extract report descriptor length
if (type == DESC_HID && foundHid && !foundEp && len >= 9 && offset + 8 < totalLen) {
hidReportDescLen = (uint16_t)cfgBuf[offset + 7]
| ((uint16_t)cfgBuf[offset + 8] << 8);
}
if (type == DESC_ENDPOINT && foundHid && !foundEp &&
offset + sizeof(EndpointDescriptor) <= totalLen) {
auto* ep = (EndpointDescriptor*)&cfgBuf[offset];
@@ -463,8 +470,9 @@ namespace Drivers::USB::UsbDevice {
// -----------------------------------------------------------------
// Step 10: SET_PROTOCOL -- Boot Protocol for keyboards only
// -----------------------------------------------------------------
// Boot Protocol constrains mice to 3-byte reports (no scroll wheel).
// Keep mice in Report Protocol (the default) so scroll data is included.
// Set Boot Protocol for keyboards only.
// Mice stay in Report Protocol (the default) for scroll wheel support;
// HidMouse parses the HID Report Descriptor to handle variable formats.
if (foundEp && dev->InterfaceProtocol == PROTOCOL_KEYBOARD) {
cc = Xhci::ControlTransfer(slotId, REQTYPE_CLASS_IFACE, REQ_SET_PROTOCOL,
0, 0, 0, nullptr, false);
@@ -474,6 +482,24 @@ namespace Drivers::USB::UsbDevice {
}
}
// -----------------------------------------------------------------
// Step 10b: Fetch HID Report Descriptor for mice
// -----------------------------------------------------------------
if (foundEp && dev->InterfaceProtocol == PROTOCOL_MOUSE && hidReportDescLen > 0) {
uint8_t rdBuf[256] = {};
uint16_t rdLen = hidReportDescLen;
if (rdLen > 256) rdLen = 256;
cc = Xhci::ControlTransfer(slotId, REQTYPE_STD_IFACE_IN, REQ_GET_DESCRIPTOR,
(DESC_HID_REPORT << 8), 0, rdLen,
rdBuf, true);
if (cc == Xhci::CC_SUCCESS || cc == Xhci::CC_SHORT_PACKET) {
HidMouse::ParseReportDescriptor(rdBuf, rdLen);
} else {
KernelLogStream(WARNING, "USB") << "GET_DESCRIPTOR(HID Report) failed, cc=" << (uint64_t)cc;
}
}
// -----------------------------------------------------------------
// Step 11: SET_IDLE(4) -- 16ms idle rate for software typematic
// -----------------------------------------------------------------
+3
View File
@@ -71,6 +71,8 @@ namespace Drivers::USB::UsbDevice {
constexpr uint8_t DESC_CONFIGURATION = 2;
constexpr uint8_t DESC_INTERFACE = 4;
constexpr uint8_t DESC_ENDPOINT = 5;
constexpr uint8_t DESC_HID = 0x21;
constexpr uint8_t DESC_HID_REPORT = 0x22;
// USB class codes
constexpr uint8_t CLASS_HID = 0x03;
@@ -91,6 +93,7 @@ namespace Drivers::USB::UsbDevice {
constexpr uint8_t REQTYPE_DEV_TO_HOST = 0x80;
constexpr uint8_t REQTYPE_HOST_TO_DEV = 0x00;
constexpr uint8_t REQTYPE_CLASS_IFACE = 0x21; // Host-to-device, class, interface
constexpr uint8_t REQTYPE_STD_IFACE_IN = 0x81; // Dev-to-host, standard, interface
// Endpoint direction mask
constexpr uint8_t EP_DIR_IN = 0x80;