Merge pull request 'GPU Stack, V8086 Monitor & BGA Driver' (#50) from feature/gpu-stack-v8086-bga into develop
continuous-integration/drone/push Build is passing

Reviewed-on: #50
Reviewed-by: Aaron Hance <[email protected]>
This commit was merged in pull request #50.
This commit is contained in:
2026-03-07 20:56:19 +00:00
17 changed files with 2062 additions and 80 deletions
+1 -1
View File
@@ -10,4 +10,4 @@ for dir in $(find src wasuro -type d 2>/dev/null); do
FU_PATHS="$FU_PATHS -Fu$dir"
done
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/kernel.pas
fpc -Aelf -gw -g -gl -n -v0e -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/kernel.pas
+1
View File
@@ -5,3 +5,4 @@ echo " "
echo "Compiling Stub..."
echo " "
nasm -f elf src/stub/stub.asm -o lib/stub.o
nasm -f elf src/stub/splash_tga.asm -o lib/splash_tga.o
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

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.
+29 -19
View File
@@ -12,7 +12,7 @@ type
PTARGAColor = ^TTARGAColor;
TTARGAHeader = packed record
Magic: uint8;
IDLength: uint8;
ColorMapType: uint8;
ImageType: uint8;
ColorMapOrigin: uint16;
@@ -24,7 +24,6 @@ type
Height: uint16;
PixelDepth: uint8;
ImageDescriptor: uint8;
Data : PTARGAColor;
end;
PTARGAHeader = ^TTARGAHeader;
@@ -35,29 +34,40 @@ implementation
Function Parse(buffer : puint8; len : uint32) : PTexture;
var
header : PTARGAHeader;
i, j : uint32;
data : PTARGAColor;
tex : PTexture;
src : PTARGAColor;
tex : PTexture;
x, y : uint32;
dstRow : uint32;
topDown: boolean;
begin
if (len < sizeof(TTARGAHeader)) then exit;
Parse := nil;
if len < sizeof(TTARGAHeader) then exit;
header := PTARGAHeader(buffer);
if (header^.Magic <> $0) or (header^.ImageType <> 2) or (header^.PixelDepth <> 32) then exit;
if (header^.ImageType <> 2) or (header^.PixelDepth <> 32) then exit;
//Create a new texture
tex:= texture.newTexture(header^.Width, header^.Height);
tex^.Width:= header^.Width;
tex^.Height:= header^.Height;
{ Pixel data starts after the 18-byte header + any ID field. }
src := PTARGAColor(buffer + sizeof(TTARGAHeader) + header^.IDLength);
//Copy the data
data := PTARGAColor(header^.Data);
for i := 0 to header^.Height - 1 do begin
for j := 0 to header^.Width - 1 do begin
tex^.Pixels[i * header^.Width + j].r := data^.r;
tex^.Pixels[i * header^.Width + j].g := data^.g;
tex^.Pixels[i * header^.Width + j].b := data^.b;
tex^.Pixels[i * header^.Width + j].a := data^.a;
{ Bit 5 of ImageDescriptor: 1 = top-to-bottom, 0 = bottom-to-top. }
topDown := (header^.ImageDescriptor AND $20) <> 0;
tex := texture.newTexture(header^.Width, header^.Height);
for y := 0 to header^.Height - 1 do begin
{ Flip vertically when origin is bottom-left (the TGA default). }
if topDown then
dstRow := y
else
dstRow := (header^.Height - 1) - y;
for x := 0 to header^.Width - 1 do begin
tex^.Pixels[dstRow * header^.Width + x].b := src^.b;
tex^.Pixels[dstRow * header^.Width + x].g := src^.g;
tex^.Pixels[dstRow * header^.Width + x].r := src^.r;
tex^.Pixels[dstRow * header^.Width + x].a := src^.a;
Inc(src);
end;
end;
+64 -43
View File
File diff suppressed because it is too large Load Diff
+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.
+265
View File
File diff suppressed because it is too large Load Diff
+8 -3
View File
@@ -25,7 +25,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();
@@ -37,7 +37,7 @@ uses
//command provider units
kernel, cpu, drivermanagement, processmanager,
arp, ipv4, tcp,
diskcmd, usbcore;
diskcmd, usbcore, diskutil, notepad, partcmd, volcmd;
procedure init();
begin
@@ -54,10 +54,14 @@ begin
stdio.registerCommand('TCPCONNECT', @tcp.terminal_command_tcpconnect, 'Connect to a TCP host and send Hello World.');
stdio.registerCommand('TCPLISTEN', @tcp.terminal_command_tcplisten, 'Listen on a TCP port and log received data.');
stdio.registerCommand('TCPHTTP', @tcp.terminal_command_tcphttp, 'Send HTTP GET to a host IP (port 80 default).');
diskcmd.init();
stdio.registerCommand('USB', @usbcore.terminal_command_usb, 'USB subsystem information.');
{ Initialize baked-in programs }
diskcmd.init();
partcmd.init();
volcmd.init();
diskutil.init;
notepad.init;
md5sum.init();
base64_prog.init();
dhclient.init();
@@ -65,6 +69,7 @@ begin
testcmd.init();
ping.init();
meminfo.init();
setres.init();
end;
end.
+19
View File
@@ -0,0 +1,19 @@
; Embed the boot splash TGA image into .rodata so it is linked
; directly into the kernel binary.
;
; Exported symbols:
; _splash_tga_start pointer to the first byte of the TGA file
; _splash_tga_end pointer one past the last byte
; _splash_tga_size uint32 containing the file size
section .rodata
global _splash_tga_start
global _splash_tga_end
global _splash_tga_size
_splash_tga_start:
incbin "img/asuro.tga"
_splash_tga_end:
_splash_tga_size: dd (_splash_tga_end - _splash_tga_start)
+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_kernel_mapped_page_directory : uint32;
function vtop(address : uint32) : uint32;
function map_page_user(page_number : uint16; block : uint16) : boolean;
implementation
@@ -273,4 +274,22 @@ begin
pop_trace;
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.