Compare commits

..
Author SHA1 Message Date
t3hn3rd cb7144f282 USB Stack & HID Refactor
- New units: usbtypes, usbcore, usbhub, UHCI, OHCI, usb_keyboard,
  usb_mouse
- usbtypes: shared USB descriptors, constants, HC abstraction,
  aligned alloc, unit tests
- usb_keyboard: USB HID boot keyboard driver with HID-to-ASCII
  translation, polling, unit tests
- usb_mouse: USB HID boot mouse driver with delta/scroll/button
  processing, polling, unit tests

HID Layer Restructure:
- keyboard.pas: stripped to abstract API (hook + reportKeyEvent),
  no PS/2 dependency
- mouse.pas: absorbed mousestate.pas, now owns
  position/buttons/scroll/hooks directly
- mousestate.pas: deleted (merged into mouse.pas)
- New ps2_keyboard.pas: PS/2 scan code translation,
  calls keyboard.reportKeyEvent
- New ps2_mouse.pas: PS/2 packet handling, calls
  mouse.setMousePos/fireMouseEvent

LVGL Integration:
- lvgl.pas: updated to use mouse.pas directly (was mousestate),
  improved keyboard input handling with proper key held/release tracking
- vterminal.pas: removed serial debug logging, dropped serial dependency

Kernel:
- kernel.pas: added USB units, USB polling in main loop, unit test
  calls, ps2_keyboard/ps2_mouse init
2026-03-01 21:23:33 +00:00
admin afdc83eaf6 Merge pull request 'Merge feature/hardening into develop' (#11) from feature/hardening into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #11
2026-03-01 02:57:23 +00:00
t3hn3rd 2239d9c848 Rebase: Fixed console -> syslog interface
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2026-03-01 02:46:13 +00:00
t3hn3rd beb4b253ab fix: guard against uint32 underflow in memset/memcpy and strings unit
When size=0 was passed to memset() or memcpy(), the loop bound
`0 to size-1` underflowed to $FFFFFFFF, iterating ~4 billion times
and causing an immediate page fault.

Added `if size = 0 then exit` guards to both memset() and memcpy()
in util.pas.

Also guarded all `for i:=0 to X-1` loops in strings.pas where X
could be 0 on empty string inputs:
- stringToUpper: wrap loop in `if stringSize > 0`
- stringToLower: wrap loop in `if stringSize > 0`
- stringEquals: early exit when both sizes are 0
- stringToInt: early exit when string is empty

Additionally fixed all previously identified bugs in strings.pas:
- hexStringToInt: guard against empty string underflow
- stringConcat: cache stringSize calls to avoid redundant O(n) scans
- stringTrim: clamp length to source string size
- stringSub: bounds check start/size against source length
- stringReplace: complete rewrite - was using stringEquals() for
  substring matching (only matched at string end), dropped prefix
  chars, had dangling assignment overwriting valid result with
  uninitialized pointer, and had unused variable
- stringIndexOf: rewritten to use new stringMatchAt() helper for
  correct substring matching
- stringContains: simplified to delegate to fixed stringIndexOf(),
  also fixing uint32 underflow when sub was empty
- stringToInt: removed always-true `v >= 0` check on uint32
- intToString: implemented (was a stub returning ' ')
- Added stringMatchAt() helper for prefix comparison
- Added comprehensive UnitTest procedure with 77 assertions
  including adversarial empty/nil/boundary inputs
2026-03-01 02:33:28 +00:00
admin 084130da80 Merge pull request 'feat: VESA rendering implementation & LVGL for graphics drawing' (#10) from feature/lvgl into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #10
2026-03-01 02:25:47 +00:00
admin 924305a1ab Merge pull request 'Migration from FPC 2.6.4 to FPC 3.2.2' (#9) from feature/fpc-3.2.2 into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #9
2026-02-26 12:51:09 +00:00
24 changed files with 7281 additions and 1114 deletions

No files matched your search

+1 -1
View File
@@ -4,4 +4,4 @@ echo "======================="
echo " "
echo "Compiling FPC Sources..."
echo " "
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* -Fusrc/driver/bus/* -Fusrc/driver/bus/usb/* -Fusrc/driver/hid/* src/kernel.pas
-96
View File
@@ -1,96 +0,0 @@
// Copyright 2021 Kieron Morris
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
{
Driver->Bus->OHCI - Open Host Controller Interface Driver.
@author(Kieron Morris <[email protected]>)
}
unit OHCI;
interface
uses
tracer,
syslog,
PCI,
drivertypes,
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
type
POHCI_MMR = ^TOHCI_MMR;
TOHCI_MMR = packed record
HcRevision : uint32;
HcControl : uint32;
HcCommandStatus : uint32;
HcIntStatus : uint32;
HcIntEnable : uint32;
HcIntDisable : uint32;
HcHCCA : uint32;
HcPeriodCurrentED : uint32;
HcControlHeadED : uint32;
HcControlCurrentED : uint32;
HcBulkHeadED : uint32;
HcBulkCurrentED : uint32;
HcDoneHead : uint32;
HcFmRemaining : uint32;
HcFmNumber : uint32;
HcPeriodicStart : uint32;
HcLSThreshold : uint32;
HcRhDescriptorA : uint32;
HcRhDescriptorB : uint32;
HcRhStatus : uint32;
end;
function load : boolean;
implementation
function load : boolean;
var
devices : TDeviceArray;
count : uint32;
i : uint32;
block : uint32;
MMR : POHCI_MMR;
begin
tracer.push_trace('OHCI.load');
devices:= PCI.getDeviceInfo($0C, $03, $10, count);
syslog.log('USB-OHCI Driver', 'Found ');
syslog.writeint(count);
syslog.writestringln(' USB Controller(s).');
if count > 0 then begin
for i:=0 to count-1 do begin
syslog.log('USB-OHCI Driver', 'Controller[');
syslog.writeint(i);
syslog.writestring(']: ');
syslog.writehex(devices[i].device_id);
syslog.writestring(' ');
syslog.writehex(devices[i].vendor_id);
syslog.writestring(' ');
syslog.writehexln(devices[i].prog_if);
block:= devices[i].address0 SHR 22;
force_alloc_block(block, 0);
map_page(block, block);
MMR:= POHCI_MMR(devices[i].address0);
end;
end;
load:= true;
end;
end.
-65
View File
@@ -1,65 +0,0 @@
// Copyright 2021 Kieron Morris
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
{
Driver->Bus->UHCI - Universal Host Controller Interface Driver.
@author(Kieron Morris <[email protected]>)
}
unit UHCI;
interface
uses
tracer,
syslog,
PCI,
drivertypes,
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
function load : boolean;
implementation
function load : boolean;
var
devices : TDeviceArray;
count : uint32;
i : uint32;
begin
tracer.push_trace('UHCI.load');
devices:= PCI.getDeviceInfo($0C, $03, $00, count);
syslog.log('USB-UHCI Driver','Found ');
syslog.writeint(count);
syslog.writestringln(' USB Controller(s).');
if count > 0 then begin
for i:=0 to count-1 do begin
syslog.log('USB-UHCI Driver','Controller[');
syslog.writeint(i);
syslog.writestring(']: ');
syslog.writehex(devices[i].device_id);
syslog.writestring(' ');
syslog.writehex(devices[i].vendor_id);
syslog.writestring(' ');
syslog.writehexln(devices[i].prog_if);
end;
end;
load:= true;
end;
end.
@@ -29,7 +29,8 @@ uses
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
drivermanagement,
usbtypes;
function load : boolean;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -30,6 +30,11 @@ uses
vmemorymanager,
util,
drivermanagement,
usbtypes,
usbcore,
usbhub,
usb_keyboard,
usb_mouse,
OHCI, UHCI, EHCI, XHCI;
procedure init;
@@ -40,24 +45,28 @@ function loadXHCI(ptr : void) : boolean;
begin
push_trace('USB.loadXHCI');
loadXHCI:= XHCI.load;
pop_trace;
end;
function loadEHCI(ptr : void) : boolean;
begin
push_trace('USB.loadEHCI');
loadEHCI:= EHCI.load;
pop_trace;
end;
function loadOHCI(ptr : void) : boolean;
begin
push_trace('USB.loadOHCI');
loadOHCI:= OHCI.load;
pop_trace;
end;
function loadUHCI(ptr : void) : boolean;
begin
push_trace('USB.loadUHCI');
loadUHCI:= UHCI.load;
pop_trace;
end;
procedure init;
@@ -71,6 +80,16 @@ begin
push_trace('USB.init');
syslog.logln('USB Driver', 'INIT BEGIN.');
{ Initialize USB core (HC list, etc.) }
usbcore.init;
{ Initialize hub driver (registers class driver for $09) }
usbhub.init;
{ Initialize HID class drivers }
usb_keyboard.init;
usb_mouse.init;
UHCI_ID.Bus:= biPCI;
UHCI_ID.id0:= idANY;
UHCI_ID.id1:= $0000000C;
@@ -29,7 +29,8 @@ uses
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
drivermanagement,
usbtypes;
function load : boolean;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+105 -306
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File renamed without changes.
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+46 -34
View File
@@ -13,7 +13,7 @@ interface
uses
video, videotypes, color, serial, tracer, lmemorymanager,
mousestate, keyboard, TMR_0_ISR, util;
mouse, keyboard, TMR_0_ISR, util;
{ ============================================================
Opaque LVGL pointer types (internal C structs)
@@ -1719,10 +1719,11 @@ var
{ Keyboard ring buffer for LVGL }
kb_buf : array[0..15] of uint32;
kb_head : uint32; { next write slot (ISR side) }
kb_head : uint32; { next write slot (hook side) }
kb_tail : uint32; { next read slot (LVGL poll side) }
last_key : uint32; { last key delivered, for release event }
kb_pending_release : boolean; { true = must send RELEASED before next key }
kb_current_key : uint32; { key currently reported as pressed to LVGL, 0 = none }
kb_key_held : boolean; { true while physical key is down }
kb_held_code : uint32; { the LVGL key code of the held key }
const
KB_BUF_SIZE = 16;
@@ -1805,9 +1806,9 @@ end;
============================================================ }
procedure lvgl_mouse_read_cb(indev: Plv_indev; data: Plv_indev_data); cdecl;
begin
data^.point.x := mousestate.getMouseX;
data^.point.y := mousestate.getMouseY;
if mousestate.getMouseLMB then
data^.point.x := mouse.getMouseX;
data^.point.y := mouse.getMouseY;
if mouse.getMouseLMB then
data^.state := LV_INDEV_STATE_PRESSED
else
data^.state := LV_INDEV_STATE_RELEASED;
@@ -1818,28 +1819,29 @@ end;
Keyboard read callback — LVGL polls this for key state
============================================================ }
procedure lvgl_kb_read_cb(indev: Plv_indev; data: Plv_indev_data); cdecl;
var
next_tail: uint32;
begin
if kb_pending_release then begin
{ Send release for the previous key before consuming the next }
data^.key := last_key;
if (kb_current_key <> 0) and
((not kb_key_held) or (kb_held_code <> kb_current_key) or (kb_tail <> kb_head)) then begin
{ Release current key: physical key released, different key now held, or new keys queued }
data^.key := kb_current_key;
data^.state := LV_INDEV_STATE_RELEASED;
kb_pending_release := false;
{ If more keys are queued, tell LVGL to call us again }
kb_current_key := 0;
data^.continue_reading := (kb_tail <> kb_head);
end else if kb_tail <> kb_head then begin
{ Consume next key from ring buffer — send press }
last_key := kb_buf[kb_tail];
{ Consume next key from ring buffer — press }
kb_current_key := kb_buf[kb_tail];
kb_tail := (kb_tail + 1) mod KB_BUF_SIZE;
data^.key := last_key;
data^.key := kb_current_key;
data^.state := LV_INDEV_STATE_PRESSED;
kb_pending_release := true;
{ Always call again to send the matching release }
data^.continue_reading := true;
data^.continue_reading := false; { one press per timer cycle for proper long-press timing }
end else if (kb_current_key <> 0) and kb_key_held then begin
{ Key still physically held — keep reporting pressed for LVGL long-press repeat }
data^.key := kb_current_key;
data^.state := LV_INDEV_STATE_PRESSED;
data^.continue_reading := false;
end else begin
{ No pending keys — idle release }
data^.key := last_key;
{ Idle — no keys }
data^.key := 0;
data^.state := LV_INDEV_STATE_RELEASED;
data^.continue_reading := false;
end;
@@ -1853,12 +1855,13 @@ var
k: uint32;
next_head: uint32;
begin
{ Ctrl+D toggles debug overlay }
if key_info.CTRL_DOWN and (key_info.key_code = ord('d')) then begin
{ Ctrl+D toggles debug overlay (press only) }
if key_info.is_down_code and key_info.CTRL_DOWN and (key_info.key_code = ord('d')) then begin
uidebug.toggle;
exit;
end;
{ Map Asuro key codes to LVGL key codes }
case key_info.key_code of
$1B: k := LV_KEY_ESC;
$08: k := LV_KEY_BACKSPACE;
@@ -1871,11 +1874,19 @@ begin
else k := uint32(key_info.key_code);
end;
{ Push into ring buffer (drop if full — better than corrupting) }
next_head := (kb_head + 1) mod KB_BUF_SIZE;
if next_head <> kb_tail then begin
kb_buf[kb_head] := k;
kb_head := next_head;
if key_info.is_down_code then begin
{ Key press — push into ring buffer and track held state }
next_head := (kb_head + 1) mod KB_BUF_SIZE;
if next_head <> kb_tail then begin
kb_buf[kb_head] := k;
kb_head := next_head;
end;
kb_key_held := true;
kb_held_code := k;
end else begin
{ Key release — clear held state if it matches }
if kb_key_held and (kb_held_code = k) then
kb_key_held := false;
end;
end;
@@ -1895,10 +1906,11 @@ begin
tracer.push_trace('lvgl.init.enter');
tick_accumulator := 0;
last_key := 0;
kb_head := 0;
kb_tail := 0;
kb_pending_release := false;
kb_current_key := 0;
kb_key_held := false;
kb_held_code := 0;
{ Initialize LVGL core }
lv_init;
@@ -1957,10 +1969,10 @@ begin
lv_tick_inc(elapsed);
{ Process scroll wheel }
scroll_delta := mousestate.getMouseScroll;
scroll_delta := mouse.getMouseScroll;
if scroll_delta <> 0 then begin
mx := mousestate.getMouseX;
my := mousestate.getMouseY;
mx := mouse.getMouseX;
my := mouse.getMouseY;
pt.x := mx;
pt.y := my;
target := lv_indev_search_obj(lv_screen_active, @pt);
Loaded 20 of 24 files, more files were not shown because too many files have changed in this diff. Show more