Compare 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
11 changed files with 1704 additions and 18 deletions

No files matched your search

File diff suppressed because it is too large. Load diff
+52 -6
View File
@@ -15,7 +15,7 @@ unit desktop;
interface interface
uses 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 type
TProgLaunchProc = procedure; TProgLaunchProc = procedure;
@@ -25,6 +25,7 @@ procedure registerProgram(name: pchar; launcher: TProgLaunchProc);
procedure init; procedure init;
procedure update; procedure update;
procedure relayout;
implementation implementation
@@ -36,7 +37,7 @@ const
DOCK_ITEM_H = 36; DOCK_ITEM_H = 36;
SEARCH_W = 220; SEARCH_W = 220;
SEARCH_RADIUS = 18; SEARCH_RADIUS = 16;
RESULTS_W = SEARCH_W; RESULTS_W = SEARCH_W;
RESULTS_ROW_H = 36; RESULTS_ROW_H = 36;
@@ -299,12 +300,12 @@ begin
addInfoRow(content, cw, 'CPU Clock', clk_str); addInfoRow(content, cw, 'CPU Clock', clk_str);
mem_str := stringConcat(intToString(((multibootinfo^.mem_upper + 1000) div 1024) + 1), ' MB'); mem_str := stringConcat(intToString(((multibootinfo^.mem_upper + 1000) div 1024) + 1), ' MB');
addInfoRow(content, cw, 'Memory', mem_str); addInfoRow(content, cw, 'Memory', mem_str);
res_str := stringConcat(intToString(multibootinfo^.framebuffer_width), 'x'); res_str := stringConcat(intToString(video.frontBufferWidth), 'x');
res_str := stringConcat(res_str, intToString(multibootinfo^.framebuffer_height)); res_str := stringConcat(res_str, intToString(video.frontBufferHeight));
res_str := stringConcat(res_str, 'x'); 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, 'Resolution', res_str);
addInfoRow(content, cw, 'Graphics', 'VESA VBE'); addInfoRow(content, cw, 'Graphics', gpu.activeDriverName);
addSeparator(content, cw); addSeparator(content, cw);
@@ -677,6 +678,14 @@ begin
lv_obj_set_pos(results_panel, lv_obj_get_x(results_panel), anim_current_y); lv_obj_set_pos(results_panel, lv_obj_get_x(results_panel), anim_current_y);
end; end;
{ ============================================================
Mode-change callback — fired by GPU framework after setMode
============================================================ }
procedure desktopModeChanged(const info : TGPUModeInfo);
begin
relayout;
end;
{ ============================================================ { ============================================================
Init — create the desktop UI Init — create the desktop UI
============================================================ } ============================================================ }
@@ -819,6 +828,43 @@ begin
{ ---- Register built-in programs ---- } { ---- Register built-in programs ---- }
registerProgram('System Information', @openSysInfo); 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; tracer.pop_trace;
end; end;
File diff suppressed because it is too large. Load diff
+46 -1
View File
@@ -13,7 +13,7 @@ interface
uses uses
video, videotypes, color, serial, tracer, lmemorymanager, 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) 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); procedure lvgl_set_mouse_cursor(cursor: Plv_obj);
function lvgl_get_ticks: uint32; function lvgl_get_ticks: uint32;
function lvgl_get_kb_group: Plv_group; function lvgl_get_kb_group: Plv_group;
procedure lvgl_update_resolution(screen_w, screen_h: uint32);
{ Color helper (Pascal wrapper for inline C function) } { Color helper (Pascal wrapper for inline C function) }
function lv_color_make(r, g, b: uint8): lv_color_t; function lv_color_make(r, g, b: uint8): lv_color_t;
@@ -1909,6 +1910,14 @@ begin
tick_accumulator := tick_accumulator + 1; tick_accumulator := tick_accumulator + 1;
end; 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 High-level init
============================================================ } ============================================================ }
@@ -1962,9 +1971,45 @@ begin
{ Hook 1024Hz timer for accurate LVGL tick } { Hook 1024Hz timer for accurate LVGL tick }
TMR_0_ISR.hook(uint32(@lvgl_timer_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'); tracer.push_trace('lvgl.init.exit');
end; 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; function lvgl_handler: uint32;
var var
elapsed: uint32; elapsed: uint32;
File diff suppressed because it is too large. Load diff
+59 -1
View File
@@ -22,7 +22,7 @@ unit video;
interface interface
uses uses
lmemorymanager, tracer, color, videotypes, hashmap, util, texture; lmemorymanager, tracer, color, videotypes, hashmap, util, texture, gpu;
procedure init(); procedure init();
procedure DrawPixel(X : uint32; Y : uint32; Pixel : TRGB32); 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 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 FillRect(x1,y1,x2,y2 : uint32; line_thickness : uint32; Line_Color : TRGB32; Fill_Color : TRGB32);
procedure Flush(); procedure Flush();
procedure reinit(fb_addr, width, height, pitch : uint32; bpp : uint8);
function register(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean; function register(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean;
function enable(DriverIdentifier : pchar) : boolean; function enable(DriverIdentifier : pchar) : boolean;
@@ -47,6 +48,9 @@ Procedure basicFDrawTexture(Buffer : PVideoBuffer; X : uint32; Y : uint32; Textu
implementation implementation
uses
VESA8, VESA16, VESA24, VESA32;
Procedure dummyFDrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); Procedure dummyFDrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32);
begin begin
tracer.push_trace('video.dummyFDrawPixel.enter'); tracer.push_trace('video.dummyFDrawPixel.enter');
@@ -191,6 +195,14 @@ var
VideoInterface : TVideoInterface; VideoInterface : TVideoInterface;
DriverMap : PHashMap; 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(); procedure init();
var var
RGB : TRGB32; RGB : TRGB32;
@@ -226,6 +238,9 @@ begin
//Initialize our 'DriverMap', a hashmap of loadable display drivers. //Initialize our 'DriverMap', a hashmap of loadable display drivers.
DriverMap:= hashmap.new; DriverMap:= hashmap.new;
{ Register for GPU mode-change notifications so reinit fires automatically }
gpu.registerModeChangeCallback(@videoModeChanged);
tracer.push_trace('video.init.exit'); tracer.push_trace('video.init.exit');
end; end;
@@ -327,4 +342,47 @@ begin
frontBufferLocation:= VideoInterface.FrontBuffer.Location; frontBufferLocation:= VideoInterface.FrontBuffer.Location;
end; 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. end.
+31 -7
View File
@@ -65,11 +65,29 @@ uses
md5, md5,
base64, base64,
rand, rand,
hashmap, vfs, hashmap,
video, vesa, doublebuffer, color, lvgl, desktop, uidebug, windows, vfs,
video,
vesa,
doublebuffer,
color,
lvgl,
desktop,
uidebug,
gpu,
bga,
vterminal, vterminal,
graphicsrefresh, usbhotplug, graphicsrefresh,
fifo, cfifo, cfifols, lifo, circ, minh, maxh, prio; usbhotplug,
fifo,
cfifo,
cfifols,
lifo,
circ,
minh,
maxh,
prio,
v86;
procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall; procedure kmain(mbinfo: Pmultiboot_info_t; mbmagic: uint32); stdcall;
@@ -165,6 +183,9 @@ begin
vmemorymanager.init(); vmemorymanager.init();
lmemorymanager.init(); lmemorymanager.init();
{ V86 Monitor Init }
v86.init();
{ Stdio Init } { Stdio Init }
stdio.init(); stdio.init();
stdio.registerCommand('BSOD', @terminal_command_bsod, 'Force a Panic Screen.'); stdio.registerCommand('BSOD', @terminal_command_bsod, 'Force a Panic Screen.');
@@ -177,10 +198,15 @@ begin
{ Call Tracer } { Call Tracer }
tracer.init(); tracer.init();
tracer.push_trace('kmain.DRVMGMT');
drivermanagement.init();
{ Video Init } { Video Init }
gpu.init();
video.init(); video.init();
vesa.init(@video.register); vesa.init(@video.register);
doublebuffer.init(@video.register); doublebuffer.init(@video.register);
bga.init();
video.enable('VESA'); video.enable('VESA');
video.enable('BASIC_DOUBLE_BUFFER'); video.enable('BASIC_DOUBLE_BUFFER');
@@ -188,8 +214,6 @@ begin
vfs.init(); vfs.init();
{ Management Interfaces } { Management Interfaces }
tracer.push_trace('kmain.DRVMGMT');
drivermanagement.init();
tracer.push_trace('kmain.STRMGMT'); tracer.push_trace('kmain.STRMGMT');
storagemanagement.init(); storagemanagement.init();
@@ -273,7 +297,7 @@ begin
{ Enable preemptive context switching (replaces ISR_32) } { Enable preemptive context switching (replaces ISR_32) }
contextswitcher.init; contextswitcher.init;
{ All work is now driven by timer interrupts — idle the CPU } { All work is now driven by timer interrupts — idle the CPU }
syslog.logln('KERNEL', 'All tasks registered. Halting into idle.'); syslog.logln('KERNEL', 'All tasks registered. Halting into idle.');
kernel.yield(); kernel.yield();
+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.
+2 -1
View File
@@ -24,7 +24,7 @@ interface
uses uses
tracer, tracer,
//progs //progs
base64_prog, md5sum, dhclient, vbeinfo, testcmd, ping, meminfo; base64_prog, md5sum, dhclient, vbeinfo, testcmd, ping, meminfo, setres;
{ Initialize all baked-in programs } { Initialize all baked-in programs }
procedure init(); procedure init();
@@ -64,6 +64,7 @@ begin
testcmd.init(); testcmd.init();
ping.init(); ping.init();
meminfo.init(); meminfo.init();
setres.init();
end; end;
end. end.
+775
View File
File diff suppressed because it is too large. Load diff
+19
View File
@@ -62,6 +62,7 @@ procedure free_page_at_address(address : uint32);
function new_page_directory : uint32; function new_page_directory : uint32;
function new_kernel_mapped_page_directory : uint32; function new_kernel_mapped_page_directory : uint32;
function vtop(address : uint32) : uint32; function vtop(address : uint32) : uint32;
function map_page_user(page_number : uint16; block : uint16) : boolean;
implementation implementation
@@ -273,4 +274,22 @@ begin
pop_trace; pop_trace;
end; end;
function map_page_user(page_number : uint16; block : uint16) : boolean;
var
rldpd : uint32;
begin
push_trace('vmemorymanager.map_page_user');
{ Map a page with User bit set (needed for V86 mode access) }
map_page_user := map_page_ex(page_number, block, PageDirectory);
PageDirectory^[page_number].UserMode := true;
{ Reload CR3 to flush TLB }
rldpd := uint32(PageDirectory) - KERNEL_VIRTUAL_BASE;
asm
mov eax, rldpd
mov CR3, eax
end;
pop_trace;
end;
end. end.