Compare commits

...
5 Commits
Author SHA1 Message Date
t3hn3rd e5548c878b Rebase: Changes made to conform with rebase on develop
continuous-integration/drone/push Build is passing
2026-03-07 13:32:10 +00:00
t3hn3rd 33985afea1 fix: show live GPU/resolution info in System Information
- desktop: Resolution/Graphics fields now read from video frontbuffer
  and gpu.activeDriverName instead of static multiboot/hardcoded values
- gpu: markAvailable sets ActiveName when no driver is active yet, so
  the initial VBE boot driver is reported before any setMode call
- kernel: whitespace cleanup
2026-03-07 10:38:14 +00:00
t3hn3rd a3b766464b feature: GPU driver framework with BGA, V86 monitor, and runtime resolution switching
- GPU Framework (gpu.pas): Priority-ordered GPU driver registry with
  mode-change callback system. Drivers register with a priority (lower =
  tried first). After successful setMode, fires registered callbacks in
  order (video → LVGL → desktop) for fully decoupled resolution updates.

- BGA Driver (bga.pas): Bochs Graphics Adapter via drivermanagement PCI
  auto-detection (class=$03 subclass=$00 wildcard). Programs display via
  I/O ports $01CE/$01CF, reads framebuffer from PCI BARs with VMware SVGA
  fallback. Supports arbitrary resolutions (1920x1080, 2560x1440, etc).

- SETRES Command (setres.pas): Runtime resolution switching — just calls
  gpu.setMode; video reinit, LVGL buffer realloc, and desktop relayout
  all fire automatically via GPU mode-change callbacks.

- VESA/VBE: Registered as GPU fallback driver (priority 50), uses V86
  INT 10h for VBE mode switching.

- TSS: Fix SS0 from $08 (code segment) to $10 (data segment); add
  set_esp0/get_esp0 helpers for V86 ring-0 stack management.

- VMM: Add map_page_user() for identity-mapping first 4MB with User bit
  (required for V86 IVT/BDA/video ROM access).

- Desktop: relayout procedure + GPU callback registration for automatic
  dock/watermark repositioning on resolution change.

- V86 Monitor (v86.pas): Full Virtual 8086 mode monitor for executing
  real-mode BIOS interrupts from protected mode. Naked GPF handler with
  instruction emulation (INT, IRET, CLI, STI, PUSHF/POPF, IN/OUT, HLT,
  0x66 prefix for 32-bit variants). Thunk-based entry via IRET into VM86.

- Kernel init order: gpu.init → video.init → vesa.init → bga.init;
  drivermanagement.init moved earlier (before video) so PCI scan detects
  BGA before first use.
2026-03-07 10:38:13 +00:00
admin 262d064b6d Merge pull request 'Fix: PS/2 mouse ISR blocking; convert USB polling & GFX refresh to processes; remove dead scheduler' (#48) from feature/ps2-mouse-fix into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #48
2026-03-07 00:40:20 +00:00
t3hn3rd 738e5828f6 Fix PS/2 mouse ISR blocking; convert USB polling & GFX refresh to processes; remove dead scheduler
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
PS/2 Mouse:
- Fix ISR spin-blocking by reading port $60 directly with inb() instead
  of calling mouse_read(), which uses mouse_wait_long (100k iterations)
  and would stall the interrupt handler waiting for the next packet byte.

Timer (PIT):
- Increase PIT frequency from ~1024 Hz to ~8 kHz (divisor 1193 -> 149)
  for more granular timer ticks.

Graphics Refresh:
- Replace timer-hook-driven rendering (driver/timers/graphicsrefresh)
  with a dedicated 'gfxd' process that runs a continuous render loop,
  keeping the vCPU active to avoid NEM/Hyper-V pause-loop descheduling.
- Move uidebug from driver/video/ to prog/.
- Update FPS calculation to account for 8 kHz tick rate.

USB Hotplug:
- Replace timer-hook-driven polling (driver/timers/usbhotplug) with a
  dedicated 'usbd' daemon process that sleeps 1s between poll cycles.
- Add bounds check in usbcore.usb_check_hotplug for empty HC list.

Cleanup:
- Remove old scheduler unit (superseded by processmanager/contextswitcher).
- Remove tss unit and tss.init() call from kernel.
- Remove unused syslog import from contextswitcher.
- Reduce BASE_QUANTUM from 8 to 5.
2026-03-07 00:29:38 +00:00
23 changed files with 1834 additions and 377 deletions

No files matched your search

+1 -4
View File
@@ -29,14 +29,11 @@ unit contextswitcher;
interface
uses
idt, isrmanager, processmanager, proctypes, util, syslog, tracer;
idt, isrmanager, processmanager, proctypes, util, tracer;
{ Initialise: overwrite IDT gate 32 with our custom ISR. }
procedure init;
{ No idle ESP variable needed — idle is now a formal process (PID 0)
with its SavedESP managed like any other process. }
implementation
{ -----------------------------------------------------------------------
+4 -1
View File
@@ -957,11 +957,14 @@ end;
procedure usb_check_hotplug;
var
i : uint32;
count: uint32;
hc : PUSBHCDriver;
port : uint8;
begin
if HCList = nil then exit;
for i := 0 to LL_Size(HCList) - 1 do begin
count := LL_Size(HCList);
if count = 0 then exit;
for i := 0 to count - 1 do begin
hc := PUSBHCDriver(LL_Get(HCList, i));
if (hc <> nil) and hc^.PortChangePending then begin
hc^.PortChangePending := false;
+5 -1
View File
@@ -119,8 +119,12 @@ var
x32, y32 : sint32;
r : pchar;
begin
{ mouse_wait(0) checks OBF with a short timeout (100 iterations).
When it returns true, data is ready — read it directly with inb($60).
Do NOT call mouse_read here: it uses mouse_wait_long (100k iterations)
and would spin-block the ISR if the next packet byte hasn't arrived yet. }
while mouse_wait(0) do begin
b := mouse_read;
b := inb($60);
if Cycle = 0 then begin
if (b AND $08) = $08 then begin
Mouse_Byte[Cycle] := b;
+3 -3
View File
@@ -13,7 +13,7 @@
// limitations under the License.
{
Driver->Timer->TMR_0_ISR - 1024hz Timer Driver.
Driver->Timer->TMR_0_ISR - 8khz Timer Driver.
@author(Kieron Morris <[email protected]>)
}
@@ -37,7 +37,7 @@ var
Hooks : Array[1..MAX_HOOKS] of pp_hook_method;
Registered : boolean = false;
procedure Main; //IRQ0, 1024.19hz aprox
procedure Main; //IRQ0, ~8001hz
var
i : integer;
@@ -54,7 +54,7 @@ procedure register();
begin
if not registered then begin
asm
mov ax, 1193
mov ax, 149
out $40, al
mov al, ah
out $40, al
-54
View File
@@ -1,54 +0,0 @@
{
Driver->Timer->GraphicsRefresh - Timer-driven graphics refresh at ~120FPS.
Hooks into the 1024Hz timer (TMR_0_ISR) and calls the desktop, uidebug,
LVGL and video flush routines every ~9 ticks (1024/9 ≈ 113.8 FPS).
@author(Kieron Morris <[email protected]>)
}
unit graphicsrefresh;
interface
procedure init;
implementation
uses
util,
TMR_0_ISR,
desktop,
uidebug,
lvgl,
video,
windows,
syslog;
const
{ 1024 / 4 ≈ 256 FPS }
TICKS_PER_FRAME = 4;
var
TickCounter : uint32;
procedure on_tick(data : void);
begin
TickCounter := TickCounter + 1;
if TickCounter >= TICKS_PER_FRAME then begin
TickCounter := 0;
windows.reapOrphanedWindows;
desktop.update;
uidebug.update;
lvgl_handler;
video.Flush;
end;
end;
procedure init;
begin
TickCounter := 0;
TMR_0_ISR.hook(uint32(@on_tick));
syslog.logln('GFXREFRESH', 'Hooked into 1024Hz timer (~120 FPS).');
end;
end.
-46
View File
@@ -1,46 +0,0 @@
{
Driver->Timer->USBHotplug - Timer-driven USB hotplug polling at ~1Hz.
Hooks into the 1024Hz timer (TMR_0_ISR) and calls
usbcore.usb_check_hotplug every 1024 ticks (approximately once per second).
@author(Kieron Morris <[email protected]>)
}
unit usbhotplug;
interface
procedure init;
implementation
uses
util,
TMR_0_ISR,
usbcore,
syslog;
const
{ 1024 ticks at 1024Hz ≈ 1 second }
TICKS_PER_POLL = 1024;
var
TickCounter : uint32;
procedure on_tick(data : void);
begin
TickCounter := TickCounter + 1;
if TickCounter >= TICKS_PER_POLL then begin
TickCounter := 0;
usbcore.usb_check_hotplug;
end;
end;
procedure init;
begin
TickCounter := 0;
TMR_0_ISR.hook(uint32(@on_tick));
syslog.logln('USBHOTPLUG', 'Hooked into 1024Hz timer (~1Hz polling).');
end;
end.
File diff suppressed because it is too large. Load diff
+52 -6
View File
@@ -15,7 +15,7 @@ unit desktop;
interface
uses
lvgl, video, RTC, strings, util, tracer, multiboot, cpu, serial, windows, asuro;
lvgl, video, gpu, RTC, strings, util, tracer, multiboot, cpu, serial, windows, asuro;
type
TProgLaunchProc = procedure;
@@ -25,6 +25,7 @@ procedure registerProgram(name: pchar; launcher: TProgLaunchProc);
procedure init;
procedure update;
procedure relayout;
implementation
@@ -36,7 +37,7 @@ const
DOCK_ITEM_H = 36;
SEARCH_W = 220;
SEARCH_RADIUS = 18;
SEARCH_RADIUS = 16;
RESULTS_W = SEARCH_W;
RESULTS_ROW_H = 36;
@@ -299,12 +300,12 @@ begin
addInfoRow(content, cw, 'CPU Clock', clk_str);
mem_str := stringConcat(intToString(((multibootinfo^.mem_upper + 1000) div 1024) + 1), ' MB');
addInfoRow(content, cw, 'Memory', mem_str);
res_str := stringConcat(intToString(multibootinfo^.framebuffer_width), 'x');
res_str := stringConcat(res_str, intToString(multibootinfo^.framebuffer_height));
res_str := stringConcat(intToString(video.frontBufferWidth), 'x');
res_str := stringConcat(res_str, intToString(video.frontBufferHeight));
res_str := stringConcat(res_str, 'x');
res_str := stringConcat(res_str, intToString(multibootinfo^.framebuffer_bpp));
res_str := stringConcat(res_str, intToString(video.frontBufferBpp));
addInfoRow(content, cw, 'Resolution', res_str);
addInfoRow(content, cw, 'Graphics', 'VESA VBE');
addInfoRow(content, cw, 'Graphics', gpu.activeDriverName);
addSeparator(content, cw);
@@ -677,6 +678,14 @@ begin
lv_obj_set_pos(results_panel, lv_obj_get_x(results_panel), anim_current_y);
end;
{ ============================================================
Mode-change callback — fired by GPU framework after setMode
============================================================ }
procedure desktopModeChanged(const info : TGPUModeInfo);
begin
relayout;
end;
{ ============================================================
Init — create the desktop UI
============================================================ }
@@ -819,6 +828,43 @@ begin
{ ---- Register built-in programs ---- }
registerProgram('System Information', @openSysInfo);
{ Register for resolution-change notifications from GPU framework }
gpu.registerModeChangeCallback(@desktopModeChanged);
tracer.pop_trace;
end;
{ ============================================================
Relayout — reposition all desktop UI after resolution change
============================================================ }
procedure relayout;
var
scr_w, scr_h : sint32;
dock_w : sint32;
dock_x : sint32;
dock_y : sint32;
begin
tracer.push_trace('desktop.relayout');
scr_w := sint32(video.frontBufferWidth);
scr_h := sint32(video.frontBufferHeight);
{ Close any open search/results first }
clearAndClose;
{ Reposition dock }
dock_w := scr_w - (DOCK_HPAD * 2);
dock_x := DOCK_HPAD;
dock_y := scr_h - DOCK_HEIGHT - DOCK_MARGIN;
lv_obj_set_size(dock, dock_w, DOCK_HEIGHT);
lv_obj_set_pos(dock, dock_x, dock_y);
{ Watermark stays centered (LV_ALIGN_CENTER is relative to parent) }
lv_obj_align(desktop_label, LV_ALIGN_CENTER, 0, -30);
{ Force layout recalculation }
lv_obj_update_layout(lv_screen_active);
tracer.pop_trace;
end;
File diff suppressed because it is too large. Load diff
+46 -1
View File
@@ -13,7 +13,7 @@ interface
uses
video, videotypes, color, serial, tracer, lmemorymanager,
mouse, keyboard, TMR_0_ISR, util;
mouse, keyboard, TMR_0_ISR, util, syslog, gpu;
{ ============================================================
Opaque LVGL pointer types (internal C structs)
@@ -1670,6 +1670,7 @@ function lvgl_get_display: Plv_display;
procedure lvgl_set_mouse_cursor(cursor: Plv_obj);
function lvgl_get_ticks: uint32;
function lvgl_get_kb_group: Plv_group;
procedure lvgl_update_resolution(screen_w, screen_h: uint32);
{ Color helper (Pascal wrapper for inline C function) }
function lv_color_make(r, g, b: uint8): lv_color_t;
@@ -1909,6 +1910,14 @@ begin
tick_accumulator := tick_accumulator + 1;
end;
{ ============================================================
GPU mode-change callback — updates LVGL display resolution
============================================================ }
procedure lvglModeChanged(const info : TGPUModeInfo);
begin
lvgl_update_resolution(info.Width, info.Height);
end;
{ ============================================================
High-level init
============================================================ }
@@ -1962,9 +1971,45 @@ begin
{ Hook 1024Hz timer for accurate LVGL tick }
TMR_0_ISR.hook(uint32(@lvgl_timer_tick));
{ Register for GPU mode-change notifications so LVGL resolution updates automatically }
gpu.registerModeChangeCallback(@lvglModeChanged);
tracer.push_trace('lvgl.init.exit');
end;
procedure lvgl_update_resolution(screen_w, screen_h: uint32);
var
new_buf : pointer;
new_size : uint32;
begin
tracer.push_trace('lvgl.update_resolution.enter');
{ Allocate new render buffer for the new width }
new_size := screen_w * LV_BUF_LINES * SizeOf(lv_color_t);
new_buf := pointer(kalloc(new_size));
if new_buf <> nil then begin
{ Free old render buffer }
if lv_buf1 <> nil then
kfree(lv_buf1);
lv_buf1 := new_buf;
lv_buf1_size := new_size;
{ Update LVGL display resolution and buffers }
lv_display_set_resolution(disp, sint32(screen_w), sint32(screen_h));
lv_display_set_buffers(disp, lv_buf1, nil,
lv_buf1_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
syslog.logln('LVGL', 'Resolution updated successfully.');
end else begin
syslog.logln('LVGL', 'Failed to allocate new render buffer.');
end;
tracer.push_trace('lvgl.update_resolution.exit');
end;
function lvgl_handler: uint32;
var
elapsed: uint32;
File diff suppressed because it is too large. Load diff
+59 -1
View File
@@ -22,7 +22,7 @@ unit video;
interface
uses
lmemorymanager, tracer, color, videotypes, hashmap, util, texture;
lmemorymanager, tracer, color, videotypes, hashmap, util, texture, gpu;
procedure init();
procedure DrawPixel(X : uint32; Y : uint32; Pixel : TRGB32);
@@ -30,6 +30,7 @@ procedure DrawLine(x1,y1,x2,y2 : uint32; thickness : uint32; Color : TRGB32);
procedure DrawRect(x1,y1,x2,y2 : uint32; line_thickness : uint32; Color : TRGB32);
procedure FillRect(x1,y1,x2,y2 : uint32; line_thickness : uint32; Line_Color : TRGB32; Fill_Color : TRGB32);
procedure Flush();
procedure reinit(fb_addr, width, height, pitch : uint32; bpp : uint8);
function register(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean;
function enable(DriverIdentifier : pchar) : boolean;
@@ -47,6 +48,9 @@ Procedure basicFDrawTexture(Buffer : PVideoBuffer; X : uint32; Y : uint32; Textu
implementation
uses
VESA8, VESA16, VESA24, VESA32;
Procedure dummyFDrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32);
begin
tracer.push_trace('video.dummyFDrawPixel.enter');
@@ -191,6 +195,14 @@ var
VideoInterface : TVideoInterface;
DriverMap : PHashMap;
{ ============================================================
GPU mode-change callback — reinits front/back buffers
============================================================ }
procedure videoModeChanged(const info : TGPUModeInfo);
begin
reinit(info.Framebuffer, info.Width, info.Height, info.Pitch, info.BPP);
end;
procedure init();
var
RGB : TRGB32;
@@ -226,6 +238,9 @@ begin
//Initialize our 'DriverMap', a hashmap of loadable display drivers.
DriverMap:= hashmap.new;
{ Register for GPU mode-change notifications so reinit fires automatically }
gpu.registerModeChangeCallback(@videoModeChanged);
tracer.push_trace('video.init.exit');
end;
@@ -327,4 +342,47 @@ begin
frontBufferLocation:= VideoInterface.FrontBuffer.Location;
end;
procedure reinit(fb_addr, width, height, pitch : uint32; bpp : uint8);
begin
tracer.push_trace('video.reinit.enter');
{ Free old back buffer if allocated }
if VideoInterface.BackBuffer.Initialized then begin
kfree(void(VideoInterface.BackBuffer.Location));
VideoInterface.BackBuffer.Initialized := false;
VideoInterface.BackBuffer.Location := 0;
VideoInterface.BackBuffer.Width := 0;
VideoInterface.BackBuffer.Height := 0;
end;
{ Reset front buffer so it can be re-initialized }
VideoInterface.FrontBuffer.Initialized := false;
VideoInterface.FrontBuffer.Location := 0;
VideoInterface.FrontBuffer.Width := 0;
VideoInterface.FrontBuffer.Height := 0;
{ Point default buffer back to front (in case doublebuffer re-enable fails) }
VideoInterface.DefaultBuffer := @VideoInterface.FrontBuffer;
{ Set front buffer directly from GPU mode info }
VideoInterface.FrontBuffer.Location := fb_addr;
VideoInterface.FrontBuffer.Width := width;
VideoInterface.FrontBuffer.Height := height;
VideoInterface.FrontBuffer.BitsPerPixel := bpp;
if fb_addr <> 0 then
VideoInterface.FrontBuffer.Initialized := true;
{ Set up BPP-specific draw routines }
case bpp of
08: VESA8.init(@VideoInterface.DrawRoutines);
16: VESA16.init(@VideoInterface.DrawRoutines);
24: VESA24.init(@VideoInterface.DrawRoutines);
32: VESA32.init(@VideoInterface.DrawRoutines);
end;
{ Re-enable double buffer (allocates new back buffer matching front) }
enable('BASIC_DOUBLE_BUFFER');
tracer.push_trace('video.reinit.exit');
end;
end.
+1 -1
View File
@@ -18,7 +18,7 @@ const
PROCESS_STACK_SIZE = 8192;
{ Base quantum multiplier: quantum = Priority * BASE_QUANTUM ticks }
BASE_QUANTUM = 8;
BASE_QUANTUM = 5;
type
{ Forward declaration }
+32 -12
View File
@@ -25,7 +25,7 @@ interface
uses
multiboot, bios_data_area,
util,
gdt, idt, isr, irq, tss,
gdt, idt, isr, irq,
TMR_0_ISR,
syslog, stdio,
keyboard, mouse,
@@ -33,7 +33,6 @@ uses
vmemorymanager, pmemorymanager, lmemorymanager,
tracer,
drivermanagement,
scheduler,
progmanager,
processmanager, contextswitcher,
testprocs,
@@ -66,11 +65,29 @@ uses
md5,
base64,
rand,
hashmap, vfs,
video, vesa, doublebuffer, color, lvgl, desktop, uidebug,
hashmap,
vfs,
video,
vesa,
doublebuffer,
color,
lvgl,
desktop,
uidebug,
gpu,
bga,
vterminal,
graphicsrefresh, usbhotplug,
fifo, cfifo, cfifols, lifo, circ, minh, maxh, prio;
graphicsrefresh,
usbhotplug,
fifo,
cfifo,
cfifols,
lifo,
circ,
minh,
maxh,
prio,
v86;
procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall;
@@ -166,13 +183,13 @@ begin
vmemorymanager.init();
lmemorymanager.init();
{ V86 Monitor Init }
v86.init();
{ Stdio Init }
stdio.init();
stdio.registerCommand('BSOD', @terminal_command_bsod, 'Force a Panic Screen.');
tss.init();
scheduler.init();
{ CPUID }
syslog.logln('CPU', 'Init begin');
cpu.init();
@@ -181,10 +198,15 @@ begin
{ Call Tracer }
tracer.init();
tracer.push_trace('kmain.DRVMGMT');
drivermanagement.init();
{ Video Init }
gpu.init();
video.init();
vesa.init(@video.register);
doublebuffer.init(@video.register);
bga.init();
video.enable('VESA');
video.enable('BASIC_DOUBLE_BUFFER');
@@ -192,8 +214,6 @@ begin
vfs.init();
{ Management Interfaces }
tracer.push_trace('kmain.DRVMGMT');
drivermanagement.init();
tracer.push_trace('kmain.STRMGMT');
storagemanagement.init();
@@ -277,7 +297,7 @@ begin
{ Enable preemptive context switching (replaces ISR_32) }
contextswitcher.init;
{ All work is now driven by timer interrupts — idle the CPU }
syslog.logln('KERNEL', 'All tasks registered. Halting into idle.');
kernel.yield();
+76
View File
@@ -0,0 +1,76 @@
{
prog->GraphicsRefresh - Continuous graphics rendering process.
Spawns a dedicated render process that loops indefinitely, driving the
desktop, LVGL and video-flush pipeline. The loop does real work every
iteration (especially the 7.3 MB SSE framebuffer copy in video.Flush),
which keeps the vCPU active so the NEM/Hyper-V back-end never
deschedules it and starves the PIT of interrupts.
@author(Kieron Morris <[email protected]>)
}
unit graphicsrefresh;
interface
procedure init;
implementation
uses
desktop,
uidebug,
lvgl,
video,
windows,
processmanager,
proctypes,
syslog,
TMR_0_ISR;
{ Render process entry point — runs as a normal scheduled process with
interrupts enabled. Continuously drives the full render pipeline so
the vCPU is always executing real work (no HLT / PAUSE spin-waits
that would trigger pause-loop exits under NEM/Hyper-V). }
const
TICKS_PER_FRAME = 32; { target ticks per frame; adjust as needed to balance refresh rate and CPU usage }
var
LAST_UPDATE : uint32 = 0;
CURRENT_TICK : uint32 = 0;
procedure render_loop(ctx : PProcessContext);
var
should_update : boolean;
begin
while true do begin
should_update := (CURRENT_TICK - LAST_UPDATE) >= TICKS_PER_FRAME;
should_update := should_update or (CURRENT_TICK < LAST_UPDATE); { handle tick counter wraparound }
if (should_update) then begin
LAST_UPDATE := CURRENT_TICK;
windows.reapOrphanedWindows;
desktop.update;
uidebug.update;
lvgl_handler;
video.Flush;
end;
end;
end;
procedure tick;
begin
{ This function is called on every timer tick (interrupt 32) via the ISR hooks.
It can be used to trigger periodic tasks without needing a dedicated process. }
CURRENT_TICK := CURRENT_TICK + 1;
end;
procedure init;
begin
TMR_0_ISR.hook(uint32(@tick)); { Register the tick handler to run on every timer interrupt }
processmanager.create('gfxd', @render_loop, nil, 5);
syslog.logln('gfxd', 'Render process spawned.');
end;
end.
+83
View File
@@ -0,0 +1,83 @@
{
Prog->setres - Set display resolution via GPU driver framework.
Usage: SETRES <width> <height>
Example: SETRES 1024 768
Uses the GPU driver framework to switch display modes. Tries BGA first,
then falls back to VBE/VESA.
@author(Kieron Morris <[email protected]>)
}
unit setres;
interface
uses
stdio, gpu, util, strings, tracer, syslog;
procedure init();
implementation
procedure run(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
var
w, h : uint32;
wStr, hStr : pchar;
info : TGPUModeInfo;
begin
tracer.push_trace('setres.run');
if paramCount(params) < 2 then begin
stdio.bufWriteStrLn(stderr_buf, 'Usage: SETRES <width> <height>');
stdio.bufWriteStrLn(stderr_buf, 'Example: SETRES 1024 768');
tracer.pop_trace;
exit;
end;
wStr := getParam(0, params);
hStr := getParam(1, params);
w := stringToInt(wStr);
h := stringToInt(hStr);
if (w = 0) or (h = 0) then begin
stdio.bufWriteStrLn(stderr_buf, 'Error: Invalid resolution values.');
tracer.pop_trace;
exit;
end;
stdio.bufWriteStr(stdout_buf, 'Setting resolution to ');
stdio.bufWriteInt(stdout_buf, w);
stdio.bufWriteStr(stdout_buf, 'x');
stdio.bufWriteInt(stdout_buf, h);
stdio.bufWriteStrLn(stdout_buf, 'x32...');
{ Step 1: Set display mode via GPU framework (tries BGA first, then VBE) }
if not gpu.setMode(w, h, 32, info) then begin
stdio.bufWriteStrLn(stderr_buf, 'Error: Mode switch failed. Mode may not be supported.');
tracer.pop_trace;
exit;
end;
stdio.bufWriteStr(stdout_buf, 'Mode set via ');
stdio.bufWriteStrLn(stdout_buf, gpu.activeDriverName());
stdio.bufWriteStr(stdout_buf, 'Resolution set to ');
stdio.bufWriteInt(stdout_buf, w);
stdio.bufWriteStr(stdout_buf, 'x');
stdio.bufWriteInt(stdout_buf, h);
stdio.bufWriteStrLn(stdout_buf, 'x32 successfully.');
tracer.pop_trace;
end;
procedure init();
begin
tracer.push_trace('setres.init');
stdio.registerCommand('SETRES', @Run, 'Set display resolution. Usage: SETRES <width> <height>');
tracer.pop_trace;
end;
end.
@@ -365,7 +365,7 @@ begin
now_tick := lvgl_get_ticks;
if (now_tick - last_tick) >= FPS_INTERVAL then begin
current_fps := safeDiv32(frame_count * 1000, now_tick - last_tick);
current_fps := safeDiv32(frame_count * 8000, now_tick - last_tick);
frame_count := 0;
last_tick := now_tick;
+38
View File
@@ -0,0 +1,38 @@
{
Prog->USBHotplug - USB hotplug daemon process.
Spawns a dedicated 'usbd' process that polls for USB port changes
approximately once per second using processmanager.proc_sleep_ms.
@author(Kieron Morris <[email protected]>)
}
unit usbhotplug;
interface
procedure init;
implementation
uses
usbcore,
processmanager,
proctypes,
syslog;
{ USB daemon process entry point — polls for hotplug events once per second. }
procedure usbd_loop(ctx : PProcessContext);
begin
while true do begin
usbcore.usb_check_hotplug;
processmanager.proc_sleep_ms(1000);
end;
end;
procedure init;
begin
processmanager.create('usbd', @usbd_loop, nil, 2);
syslog.logln('usbd', 'USB hotplug daemon spawned.');
end;
end.
+2 -1
View File
@@ -24,7 +24,7 @@ interface
uses
tracer,
//progs
base64_prog, md5sum, dhclient, vbeinfo, testcmd, ping, meminfo;
base64_prog, md5sum, dhclient, vbeinfo, testcmd, ping, meminfo, setres;
{ Initialize all baked-in programs }
procedure init();
@@ -64,6 +64,7 @@ begin
testcmd.init();
ping.init();
meminfo.init();
setres.init();
end;
end.
-132
View File
@@ -1,132 +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.
{
Scheduler - Schedules Context Switches.
@author(Kieron Morris <[email protected]>)
}
unit scheduler;
interface
uses
syslog, stdio,
TMR_0_ISR,
lmemorymanager;
const
Quantum = 64;
type
TTaskState = packed record
//EAX, EDX,
end;
TScheduler_Entry = packed record
ThreadID : uint32;
Priority : uint8;
Delta : uint32;
Next : void;
end;
PScheduler_Entry = ^TScheduler_Entry;
var
Active : Boolean;
procedure init;
procedure add_task(priority : uint8);
implementation
var
Tick : uint32;
Root_Task : PScheduler_Entry = nil;
Current_Task : PScheduler_Entry = nil;
procedure context_switch();
begin
Current_Task:= PScheduler_Entry(Current_Task^.Next);
end;
procedure add_task(priority : uint8);
var
new_task : PScheduler_Entry;
task : PScheduler_Entry;
i : uint32;
begin
new_task:= PScheduler_Entry(kalloc(sizeof(TScheduler_Entry)));
new_task^.Priority:= priority;
new_task^.Delta:= Tick;
new_task^.Next:= void(Root_Task);
task:= Root_Task;
i:= 1;
while PScheduler_Entry(task^.next) <> Root_Task do begin
i:= i+1;
task:= PScheduler_Entry(task^.next);
end;
task^.next:= void(new_task);
new_task^.ThreadID:= i;
end;
procedure delta(data : void);
begin
If Active then begin
Tick:= Tick + 1;
If Tick = 0 then context_switch();
If (Current_Task^.Delta + (Current_Task^.Priority * Quantum)) <= Tick then context_switch();
end;
end;
procedure terminal_command_tasks(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
var
list : PScheduler_Entry;
begin
stdio.bufWriteStrLn(stdout_buf, 'ThreadID - Priority - Delta');
list:= Root_Task;
stdio.bufWriteInt(stdout_buf, list^.ThreadID);
stdio.bufWriteStr(stdout_buf, ' - ');
stdio.bufWriteInt(stdout_buf, list^.Priority);
stdio.bufWriteStr(stdout_buf, ' - ');
stdio.bufWriteIntLn(stdout_buf, list^.Delta);
list:= PScheduler_Entry(list^.Next);
while list <> Root_Task do begin
stdio.bufWriteInt(stdout_buf, list^.ThreadID);
stdio.bufWriteStr(stdout_buf, ' - ');
stdio.bufWriteInt(stdout_buf, list^.Priority);
stdio.bufWriteStr(stdout_buf, ' - ');
stdio.bufWriteIntLn(stdout_buf, list^.Delta);
list:= PScheduler_Entry(list^.Next);
end;
end;
procedure init;
begin
syslog.logln('SCHEDULER','INIT BEGIN.');
Root_Task:= PScheduler_Entry(kalloc(sizeof(TScheduler_Entry)));
Root_Task^.ThreadID:= 0;
Root_Task^.Priority:= 1;
Root_Task^.Delta:= 0;
Root_Task^.Next:= void(Root_Task);
Current_Task:= Root_Task;
Tick:= 0;
Active:= False;
TMR_0_ISR.hook(uint32(@delta));
//stdio.registerCommand('TASKS', @terminal_command_tasks, 'List Active Processes.');
syslog.logln('SCHEDULER','INIT END.');
end;
end.
Loaded 20 of 23 files, more files were not shown because too many files have changed in this diff. Show more