diff --git a/src/app/app.base64.pas b/src/app/app.base64.pas index 17fa8419..8e396e6a 100644 --- a/src/app/app.base64.pas +++ b/src/app/app.base64.pas @@ -22,7 +22,7 @@ unit app.base64; interface uses - io.stdio, core.util, arch.x86.util, core.strings, debug.tracer, core.enc.base64, memory.heap; + io.stdio, core.util, arch.platform.cpu, core.strings, debug.tracer, core.enc.base64, memory.heap; procedure init(); diff --git a/src/app/app.diskcmd.pas b/src/app/app.diskcmd.pas index ec73b5b4..bb50d8cf 100644 --- a/src/app/app.diskcmd.pas +++ b/src/app/app.diskcmd.pas @@ -25,7 +25,7 @@ uses core.strings, io.stdio, debug.tracer, - core.util, arch.x86.util, + core.util, arch.platform.cpu, driver.storage.vol.mgr; var @@ -254,7 +254,7 @@ begin { Allocate a zero buffer - 64 sectors at a time } bufSects := 64; buf := puint32(kalloc(bufSects * device^.sectorSize)); - memset(uint32(buf), 0, bufSects * device^.sectorSize); + memset(PtrUInt(buf), 0, bufSects * device^.sectorSize); print('Wiping device '); printint(idx); diff --git a/src/app/app.diskutil.pas b/src/app/app.diskutil.pas index df6d4202..fcbbc3fb 100644 --- a/src/app/app.diskutil.pas +++ b/src/app/app.diskutil.pas @@ -34,7 +34,7 @@ uses driver.video, driver.storage.vol.mgr, driver.video.windows, - core.util, arch.x86.util; + core.util, arch.platform.cpu; const WIN_W = 740; @@ -129,9 +129,9 @@ begin item := PUIText(kalloc(sizeof(TUIText)+n+m+1)); if item = nil then exit; item^.Next := TextTemps; TextTemps := item; - dest := pchar(uint32(item)+sizeof(TUIText)); - if n > 0 then memcpy(uint32(a), uint32(dest), n); - if m > 0 then memcpy(uint32(b), uint32(dest)+n, m); + dest := pchar(PtrUInt(item)+sizeof(TUIText)); + if n > 0 then memcpy(PtrUInt(a), PtrUInt(dest), n); + if m > 0 then memcpy(PtrUInt(b), PtrUInt(dest)+n, m); dest[n+m] := #0; uiConcat := dest; end; @@ -606,7 +606,7 @@ begin end; end; - memset(uint32(@part), 0, sizeof(TPartition_table)); + memset(PtrUInt(@part), 0, sizeof(TPartition_table)); driver.storage.vol.mbr.setup_partition(@part, lba, sectors); cbCtx := begin_partition_ui(1); if cbCtx = nil then exit; @@ -702,18 +702,19 @@ end; procedure operation_done(error : TError; userdata : pointer); var ctx : PFmtUICallbackCtx; - flags : uint32; + flags : PtrUInt; begin ctx := PFmtUICallbackCtx(userdata); if ctx <> nil then begin - asm pushfd; cli; pop flags end; + flags := arch.platform.cpu.lock; if ctx^.SessionID = ui_session_id then begin fmt_done_error := error; fmt_done_vol_idx := ctx^.VolumeIdx; - done_kind := ctx^.Kind; done_device := ctx^.DeviceIdx; + done_kind := ctx^.Kind; + done_device := ctx^.DeviceIdx; puint32(@fmt_done_flag)^ := 1; end; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(flags); kfree(void(ctx)); end; end; @@ -824,7 +825,7 @@ begin fs := driver.storage.fs.mgr.get_filesystem(selIdx); if fs = nil then begin closeMsgBox; exit; end; - memset(uint32(@params), 0, sizeof(TFSFormatParams)); + memset(PtrUInt(@params), 0, sizeof(TFSFormatParams)); params.Version := FS_FORMAT_PARAMS_VERSION_1; paramPtr := nil; @@ -874,7 +875,7 @@ begin if fs^.validateLabelCallback(text,normalized) <> eNone then begin set_fmt_param_error('Use up to 11 ASCII characters without punctuation such as / or :'); exit; end; - memcpy(uint32(@normalized[0]),uint32(@params.LabelText[0]),12); + memcpy(PtrUInt(@normalized[0]),PtrUInt(@params.LabelText[0]),12); params.Flags := params.Flags or FS_FORMAT_PARAM_LABEL; paramPtr := @params; end; diff --git a/src/app/app.filebrowser.pas b/src/app/app.filebrowser.pas index 32a01157..3c0cdfe4 100644 --- a/src/app/app.filebrowser.pas +++ b/src/app/app.filebrowser.pas @@ -32,7 +32,7 @@ uses core.gfx.fileicons, debug.tracer, core.util, - arch.x86.util; + arch.platform.cpu; const WIN_W = 800; @@ -785,9 +785,9 @@ begin dir_names := PNameBuf(kalloc(sizeof(TNameBuf))); file_names := PNameBuf(kalloc(sizeof(TNameBuf))); file_sizes := PSizeBuf(kalloc(sizeof(TSizeBuf))); - memset(uint32(dir_names), 0, sizeof(TNameBuf)); - memset(uint32(file_names), 0, sizeof(TNameBuf)); - memset(uint32(file_sizes), 0, sizeof(TSizeBuf)); + memset(PtrUInt(dir_names), 0, sizeof(TNameBuf)); + memset(PtrUInt(file_names), 0, sizeof(TNameBuf)); + memset(PtrUInt(file_sizes), 0, sizeof(TSizeBuf)); { Load directory from VFS — this may do disk I/O } Map := driver.storage.vfs.GetDirectoryListingFrom(state^.cur_path, '/'); @@ -1330,7 +1330,7 @@ begin parent := stringCopy('/') else begin parent := pchar(kalloc(uint32(i) + 1)); - memcpy(uint32(cur), uint32(parent), uint32(i)); + memcpy(PtrUInt(cur), PtrUInt(parent), uint32(i)); parent[i] := char(0); end; navigate_to(state, parent); @@ -1440,7 +1440,7 @@ begin { Segment name label } segBuf := pchar(kalloc(segEnd - segStart + 1)); - memcpy(uint32(@path[segStart]), uint32(segBuf), segEnd - segStart); + memcpy(PtrUInt(@path[segStart]), uint32(segBuf), segEnd - segStart); segBuf[segEnd - segStart] := char(0); lbl := lv_label_create(btn); lv_label_set_text(lbl, segBuf); @@ -1979,7 +1979,7 @@ begin if state^.tabs[idx] <> nil then free_tab_snapshot(state^.tabs[idx]); snap := PTabSnapshot(kalloc(sizeof(TTabSnapshot))); - memset(uint32(snap), 0, sizeof(TTabSnapshot)); + memset(PtrUInt(snap), 0, sizeof(TTabSnapshot)); if state^.cur_path <> nil then snap^.cur_path := stringCopy(state^.cur_path) else @@ -2090,7 +2090,7 @@ begin save_tab(state, state^.active_tab); { Create snapshot for new tab } snap := PTabSnapshot(kalloc(sizeof(TTabSnapshot))); - memset(uint32(snap), 0, sizeof(TTabSnapshot)); + memset(PtrUInt(snap), 0, sizeof(TTabSnapshot)); snap^.cur_path := stringCopy(path); snap^.hist_len := 0; snap^.hist_pos := 0; @@ -3053,7 +3053,7 @@ begin { Allocate and zero-initialise state } state := PFileBrowserState(kalloc(sizeof(TFileBrowserState))); - memset(uint32(state), 0, sizeof(TFileBrowserState)); + memset(PtrUInt(state), 0, sizeof(TFileBrowserState)); state^.win_id := g_win_id; state^.cur_path := stringCopy('/'); state^.view_mode := vmDetail; diff --git a/src/app/app.filepicker.pas b/src/app/app.filepicker.pas index 40f7dd7c..be242f60 100644 --- a/src/app/app.filepicker.pas +++ b/src/app/app.filepicker.pas @@ -64,7 +64,7 @@ uses core.strings.helpers, io.syslog, debug.tracer, - core.util, arch.x86.util, + core.util, arch.platform.cpu, driver.storage.vfs; const @@ -325,9 +325,9 @@ begin dir_names := PNameBuf(kalloc(sizeof(TNameBuf))); file_names := PNameBuf(kalloc(sizeof(TNameBuf))); file_sizes := PSizeBuf(kalloc(sizeof(TSizeBuf))); - memset(uint32(dir_names), 0, sizeof(TNameBuf)); - memset(uint32(file_names), 0, sizeof(TNameBuf)); - memset(uint32(file_sizes), 0, sizeof(TSizeBuf)); + memset(PtrUInt(dir_names), 0, sizeof(TNameBuf)); + memset(PtrUInt(file_names), 0, sizeof(TNameBuf)); + memset(PtrUInt(file_sizes), 0, sizeof(TSizeBuf)); { Sync path bar } if p^.path_bar <> nil then @@ -898,7 +898,7 @@ begin io.syslog.logln('FPCIK', 'make_picker: enter'); p := PPicker(kalloc(sizeof(TPicker))); - memset(uint32(p), 0, sizeof(TPicker)); + memset(PtrUInt(p), 0, sizeof(TPicker)); p^.cb := cb; p^.userdata := userdata; p^.is_save := is_save; diff --git a/src/app/app.md5sum.pas b/src/app/app.md5sum.pas index a16950bc..39879c91 100644 --- a/src/app/app.md5sum.pas +++ b/src/app/app.md5sum.pas @@ -22,7 +22,7 @@ unit app.md5sum; interface uses - io.stdio, core.util, arch.x86.util, core.strings, debug.tracer, core.enc.md5; + memory.heap, io.stdio, core.util, arch.platform.cpu, core.strings, debug.tracer, core.enc.md5; procedure init(); @@ -36,6 +36,10 @@ var i : uint32; begin + if paramCount(Params) = 0 then begin + io.stdio.bufWriteStrLn(stderr_buf, 'Usage: MD5SUM '); + exit; + end; md5word:= getParam(0, Params); wordlen:= stringSize(md5word); MD5_Hash := MD5Buffer(puint8(md5word), wordlen); @@ -43,6 +47,7 @@ begin io.stdio.bufWriteHexPair(stdout_buf, MD5_Hash^[i]); end; io.stdio.bufWriteStrLn(stdout_buf, ' '); + memory.heap.kfree(void(MD5_Hash)); end; procedure init(); @@ -51,4 +56,4 @@ begin io.stdio.registerCommand('MD5SUM', @Run, 'Perform MD5SUM on a word.'); end; -end. \ No newline at end of file +end. diff --git a/src/app/app.meminfo.pas b/src/app/app.meminfo.pas index c747a820..7c11ab50 100644 --- a/src/app/app.meminfo.pas +++ b/src/app/app.meminfo.pas @@ -22,7 +22,7 @@ unit app.meminfo; interface uses - io.stdio, arch.x86.multiboot, arch.x86.memory.physical, memory.heap, debug.tracer; + io.stdio, arch.platform.memory, memory.heap, debug.tracer; procedure init(); @@ -30,50 +30,30 @@ implementation procedure run(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf); var - pmm_total, pmm_free, pmm_used : uint32; - lmm_pages, lmm_free : uint32; + total, available: uint64; + heapPages: uint32; begin - { Multiboot memory info } - io.stdio.bufWriteStrLn(stdout_buf, '--- Multiboot ---'); - io.stdio.bufWriteStr(stdout_buf, 'Lower Memory : '); - io.stdio.bufWriteInt(stdout_buf, multibootinfo^.mem_lower); - io.stdio.bufWriteStrLn(stdout_buf, ' KB'); - io.stdio.bufWriteStr(stdout_buf, 'Upper Memory : '); - io.stdio.bufWriteInt(stdout_buf, multibootinfo^.mem_upper); - io.stdio.bufWriteStrLn(stdout_buf, ' KB'); - io.stdio.bufWriteStr(stdout_buf, 'Total Memory : '); - io.stdio.bufWriteInt(stdout_buf, ((multibootinfo^.mem_upper + 1000) div 1024) + 1); - io.stdio.bufWriteStrLn(stdout_buf, ' MB'); - - { PMM stats } - io.stdio.bufWriteStrLn(stdout_buf, '--- PMM (4 MB blocks) ---'); - pmm_total := arch.x86.memory.physical.pmm_total_blocks; - pmm_free := arch.x86.memory.physical.pmm_free_blocks; - pmm_used := pmm_total - pmm_free; - io.stdio.bufWriteStr(stdout_buf, 'Total Blocks : '); - io.stdio.bufWriteIntLn(stdout_buf, pmm_total); - io.stdio.bufWriteStr(stdout_buf, 'Free Blocks : '); - io.stdio.bufWriteIntLn(stdout_buf, pmm_free); - io.stdio.bufWriteStr(stdout_buf, 'Used Blocks : '); - io.stdio.bufWriteIntLn(stdout_buf, pmm_used); - io.stdio.bufWriteStr(stdout_buf, 'Free Physical : '); - io.stdio.bufWriteInt(stdout_buf, pmm_free * 4); - io.stdio.bufWriteStrLn(stdout_buf, ' MB'); - - { LMM heap stats } - io.stdio.bufWriteStrLn(stdout_buf, '--- LMM (Heap) ---'); - lmm_pages := memory.heap.lmm_page_count; - lmm_free := memory.heap.lmm_total_free; - io.stdio.bufWriteStr(stdout_buf, 'Heap Pages : '); - io.stdio.bufWriteIntLn(stdout_buf, lmm_pages); - io.stdio.bufWriteStr(stdout_buf, 'Heap Size : '); - io.stdio.bufWriteInt(stdout_buf, lmm_pages * 4); - io.stdio.bufWriteStrLn(stdout_buf, ' MB'); - io.stdio.bufWriteStr(stdout_buf, 'Heap Free : '); - io.stdio.bufWriteInt(stdout_buf, lmm_free div 1024); - io.stdio.bufWriteStrLn(stdout_buf, ' KB'); + total := arch.platform.memory.totalPhysicalBytes; + available := arch.platform.memory.freePhysicalBytes; + io.stdio.bufWriteStr(stdout_buf, 'Usable Physical: '); + io.stdio.bufWriteInt(stdout_buf, total div 1024); + io.stdio.bufWriteStrLn(stdout_buf, ' KiB'); + io.stdio.bufWriteStr(stdout_buf, 'Free Physical : '); + io.stdio.bufWriteInt(stdout_buf, available div 1024); + io.stdio.bufWriteStrLn(stdout_buf, ' KiB'); + io.stdio.bufWriteStr(stdout_buf, 'Used Physical : '); + io.stdio.bufWriteInt(stdout_buf, (total - available) div 1024); + io.stdio.bufWriteStrLn(stdout_buf, ' KiB'); + heapPages := memory.heap.lmm_page_count; + io.stdio.bufWriteStr(stdout_buf, 'Heap Regions : '); + io.stdio.bufWriteIntLn(stdout_buf, heapPages); + io.stdio.bufWriteStr(stdout_buf, 'Heap Size : '); + io.stdio.bufWriteInt(stdout_buf, uint64(heapPages) * PAGE_SIZE_LMM div 1024); + io.stdio.bufWriteStrLn(stdout_buf, ' KiB'); + io.stdio.bufWriteStr(stdout_buf, 'Heap Free : '); + io.stdio.bufWriteInt(stdout_buf, memory.heap.lmm_total_free div 1024); + io.stdio.bufWriteStrLn(stdout_buf, ' KiB'); end; - procedure init(); begin debug.tracer.push_trace('meminfo.init'); diff --git a/src/app/app.notepad.pas b/src/app/app.notepad.pas index 0a524c56..455a0462 100644 --- a/src/app/app.notepad.pas +++ b/src/app/app.notepad.pas @@ -11,8 +11,7 @@ - Status bar showing Line, Col, filename, and dirty flag Key design notes: - - lv_event_t.stop_processing (bit 1 at struct byte offset 24) is set - directly to prevent LVGL's default textarea key handler from also + - lv_event_stop_processing prevents LVGL's default textarea handler from also acting on keys we have fully handled ourselves. - Shift state is read from driver.hid.keyboard.is_shift / driver.hid.keyboard.is_ctrl. - selection anchor (sel_anchor) is stored as a sint32 byte offset; @@ -43,7 +42,7 @@ uses io.syslog, io.stdio, debug.tracer, - core.util, arch.x86.util, + core.util, arch.platform.cpu, driver.storage.vfs, driver.video, driver.video.windows; @@ -62,19 +61,6 @@ const FILE_BUF_SIZE = 65536; { 64 KB read / write buffer } - { - Byte offset and bitmask for lv_event_t.stop_processing. - struct lv_event_t (32-bit ABI): - offset 0: current_target (ptr) - offset 4: original_target (ptr) - offset 8: code (uint32 — lv_event_code_t) - offset 12: user_data (ptr) - offset 16: param (ptr) - offset 20: prev (ptr) - offset 24: flags byte [bit0=deleted, bit1=stop_processing, bit2=stop_bubbling] - } - LV_EVT_STOP_OFF = 24; - LV_EVT_STOP_BIT = 2; { bit 1 = stop_processing } type PNotepadState = ^TNotepadState; @@ -130,8 +116,7 @@ procedure removeInstance(state: PNotepadState); forward; ============================================================ } procedure stopEvent(e: Plv_event); begin - puint8(uint32(e) + LV_EVT_STOP_OFF)^ := - puint8(uint32(e) + LV_EVT_STOP_OFF)^ or LV_EVT_STOP_BIT; + lv_event_stop_processing(e); end; { ============================================================ @@ -157,18 +142,18 @@ begin if to_idx < from_idx then to_idx := from_idx; result_len := from_idx + ins_len + (src_len - to_idx); buf := pchar(kalloc(result_len + 1)); - memset(uint32(buf), 0, result_len + 1); + memset(PtrUInt(buf), 0, result_len + 1); pos := 0; if from_idx > 0 then begin - memcpy(uint32(src), uint32(buf), from_idx); + memcpy(PtrUInt(src), PtrUInt(buf), from_idx); pos := from_idx; end; if ins_len > 0 then begin - memcpy(uint32(insert), uint32(@buf[pos]), ins_len); + memcpy(PtrUInt(insert), PtrUInt(@buf[pos]), ins_len); pos := pos + ins_len; end; if to_idx < src_len then - memcpy(uint32(@src[to_idx]), uint32(@buf[pos]), src_len - to_idx); + memcpy(PtrUInt(@src[to_idx]), PtrUInt(@buf[pos]), src_len - to_idx); buildSplicedString := buf; end; @@ -198,12 +183,12 @@ begin { Generous output buffer: original + 4 bytes per line (worst case ~512 lines) } out_buf := pchar(kalloc(src_len + 2049)); - memset(uint32(out_buf), 0, src_len + 2049); + memset(PtrUInt(out_buf), 0, src_len + 2049); out_pos := 0; { Copy everything before the affected region verbatim } if first_ls > 0 then begin - memcpy(uint32(src), uint32(out_buf), first_ls); + memcpy(PtrUInt(src), PtrUInt(out_buf), first_ls); out_pos := first_ls; end; @@ -215,7 +200,7 @@ begin if i >= sel_end then begin { Past the affected region: copy the remainder verbatim } if i < src_len then begin - memcpy(uint32(@src[i]), uint32(@out_buf[out_pos]), src_len - i); + memcpy(PtrUInt(@src[i]), PtrUInt(@out_buf[out_pos]), src_len - i); out_pos := out_pos + (src_len - i); end; break; @@ -426,8 +411,8 @@ begin len := stringSize(txt); if len > FILE_BUF_SIZE - 1 then len := FILE_BUF_SIZE - 1; buf := pchar(kalloc(FILE_BUF_SIZE)); - memset(uint32(buf), 0, FILE_BUF_SIZE); - memcpy(uint32(txt), uint32(buf), len); + memset(PtrUInt(buf), 0, FILE_BUF_SIZE); + memcpy(PtrUInt(txt), PtrUInt(buf), len); fHandle := driver.storage.vfs.OpenFile(state^.currentPath, omReadWrite, @fError); if fHandle = 0 then fHandle := driver.storage.vfs.OpenFile(state^.currentPath, omCreate, @fError); @@ -477,7 +462,7 @@ begin exit; end; buf := pchar(kalloc(FILE_BUF_SIZE)); - memset(uint32(buf), 0, FILE_BUF_SIZE); + memset(PtrUInt(buf), 0, FILE_BUF_SIZE); driver.storage.vfs.ReadFile(fHandle, 0, puint8(buf), FILE_BUF_SIZE - 1); driver.storage.vfs.CloseFile(fHandle); if state^.currentPath <> nil then kfree(void(state^.currentPath)); @@ -943,7 +928,7 @@ begin { Allocate and zero-initialise state } state := PNotepadState(kalloc(sizeof(TNotepadState))); - memset(uint32(state), 0, sizeof(TNotepadState)); + memset(PtrUInt(state), 0, sizeof(TNotepadState)); state^.win_id := wid; state^.sel_anchor := -1; addInstance(state); diff --git a/src/app/app.setres.pas b/src/app/app.setres.pas index 7b0af214..88878662 100644 --- a/src/app/app.setres.pas +++ b/src/app/app.setres.pas @@ -14,7 +14,7 @@ unit app.setres; interface uses - io.stdio, driver.video.gpu, core.util, arch.x86.util, core.strings, debug.tracer, io.syslog; + io.stdio, driver.video.lvgl, driver.video.gpu, core.util, arch.platform.cpu, core.strings, debug.tracer, io.syslog; procedure init(); @@ -25,6 +25,7 @@ var w, h : uint32; wStr, hStr : pchar; info : TGPUModeInfo; + changed: boolean; begin debug.tracer.push_trace('setres.run'); @@ -55,7 +56,10 @@ begin io.stdio.bufWriteStrLn(stdout_buf, 'x32...'); { Step 1: Set display mode via GPU framework (tries BGA first, then VBE) } - if not driver.video.gpu.setMode(w, h, 32, info) then begin + driver.video.lvgl.lvgl_lock; + changed := driver.video.gpu.setMode(w, h, 32, info); + driver.video.lvgl.lvgl_unlock; + if not changed then begin io.stdio.bufWriteStrLn(stderr_buf, 'Error: Mode switch failed. Mode may not be supported.'); debug.tracer.pop_trace; exit; diff --git a/src/app/app.uidebug.pas b/src/app/app.uidebug.pas index 04293c24..61834154 100644 --- a/src/app/app.uidebug.pas +++ b/src/app/app.uidebug.pas @@ -19,7 +19,7 @@ unit app.uidebug; interface uses - driver.video.lvgl, driver.video.windows, driver.hid.mouse, driver.video, arch.x86.multiboot, debug.tracer; + driver.video.lvgl, driver.video.windows, driver.hid.mouse, driver.video, boot.multiboot, debug.tracer; { Call once per frame from the main loop (before lvgl_handler). } procedure update; diff --git a/src/app/app.vterminal.pas b/src/app/app.vterminal.pas index 2a7da820..d7d1c3f9 100644 --- a/src/app/app.vterminal.pas +++ b/src/app/app.vterminal.pas @@ -17,7 +17,7 @@ interface uses driver.video.lvgl, driver.video, driver.video.windows, driver.video.desktop, driver.hid.keyboard, debug.tracer, - core.strings, core.util, arch.x86.util, memory.heap, core.version, io.stdio, driver.storage.vfs, + core.strings, core.util, arch.platform.cpu, memory.heap, core.version, io.stdio, driver.storage.vfs, proc.mgr, proc.types, core.ds.lists, core.ds.hashmap, driver.storage.filedispatch; procedure init; @@ -114,10 +114,10 @@ begin if slen = 0 then exit; if state^.text_len + slen >= MAX_TEXT - 1 then begin i := MAX_TEXT div 2; - memcpy(uint32(@state^.text_buf[i]), uint32(@state^.text_buf[0]), state^.text_len - i); + memcpy(PtrUInt(@state^.text_buf[i]), PtrUInt(@state^.text_buf[0]), state^.text_len - i); state^.text_len := state^.text_len - i; end; - memcpy(uint32(s), uint32(@state^.text_buf[state^.text_len]), slen); + memcpy(PtrUInt(s), PtrUInt(@state^.text_buf[state^.text_len]), slen); state^.text_len := state^.text_len + slen; state^.text_buf[state^.text_len] := #0; end; @@ -144,6 +144,17 @@ begin end; end; +procedure showLaunchError(state: PVTermState; errors: POutBuf); +begin + if (errors <> nil) and (errors^.len > 0) then begin + errors^.buf[errors^.len] := #0; + appendText(state, errors^.buf); + end else begin + appendText(state, 'Unknown command. Type HELP for a list.'); + appendChar(state, #10); + end; +end; + procedure showPrompt(state : PVTermState); begin appendText(state, 'asuro:'); @@ -223,7 +234,7 @@ end; procedure drainBackgroundJobs(state : PVTermState); var i : sint32; - slotPtr : ^uint32; + slotPtr : ^PtrUInt; job : PBackgroundJob; ctx : PProcessContext; finished: boolean; @@ -233,7 +244,7 @@ begin if state^.bg_jobs = nil then exit; dirty := false; for i := sint32(DL_Size(state^.bg_jobs)) - 1 downto 0 do begin - slotPtr := DL_Get(state^.bg_jobs, uint32(i)); + slotPtr := pointer(DL_Get(state^.bg_jobs, uint32(i))); if slotPtr = nil then continue; job := PBackgroundJob(slotPtr^); if job = nil then continue; @@ -312,7 +323,7 @@ begin showPrompt(state); { Clear any partial input line } state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); end; { ============================================================ @@ -444,7 +455,7 @@ var pcount : uint32; lastParam : pchar; job : PBackgroundJob; - slotPtr : ^uint32; + slotPtr : ^PtrUInt; absPath : pchar; dispatchPID : uint32; begin @@ -456,8 +467,8 @@ begin { Push non-empty lines into history } if state^.line_len > 0 then begin - memcpy(uint32(@state^.line_buf[0]), - uint32(@state^.hist[state^.hist_head][0]), + memcpy(PtrUInt(@state^.line_buf[0]), + PtrUInt(@state^.hist[state^.hist_head][0]), state^.line_len + 1); state^.hist_head := (state^.hist_head + 1) mod HIST_SIZE; if state^.hist_count < HIST_SIZE then inc(state^.hist_count); @@ -467,7 +478,7 @@ begin if state^.line_len = 0 then begin showPrompt(state); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); exit; end; @@ -484,7 +495,7 @@ begin kfree(void(uppera)); io.stdio.freeParams(params); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); showPrompt(state); exit; end; @@ -495,7 +506,7 @@ begin kfree(void(uppera)); io.stdio.freeParams(params); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); showPrompt(state); exit; end; @@ -504,7 +515,7 @@ begin kfree(void(uppera)); io.stdio.freeParams(params); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); showPrompt(state); exit; end; @@ -513,7 +524,7 @@ begin kfree(void(uppera)); io.stdio.freeParams(params); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); showPrompt(state); exit; end; @@ -522,7 +533,7 @@ begin kfree(void(uppera)); io.stdio.freeParams(params); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); showPrompt(state); exit; end; @@ -531,7 +542,7 @@ begin if stringEquals(uppera, 'JOBS') then begin if (state^.bg_jobs <> nil) and (DL_Size(state^.bg_jobs) > 0) then begin for pcount := 0 to DL_Size(state^.bg_jobs) - 1 do begin - slotPtr := DL_Get(state^.bg_jobs, pcount); + slotPtr := pointer(DL_Get(state^.bg_jobs, pcount)); if (slotPtr <> nil) then begin job := PBackgroundJob(slotPtr^); if job <> nil then begin @@ -564,7 +575,7 @@ begin kfree(void(uppera)); io.stdio.freeParams(params); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); showPrompt(state); exit; end; @@ -573,7 +584,7 @@ begin if stringEquals(uppera, 'FG') then begin if (state^.bg_jobs <> nil) and (DL_Size(state^.bg_jobs) > 0) then begin { Use first bg job if no arg given } - slotPtr := DL_Get(state^.bg_jobs, 0); + slotPtr := pointer(DL_Get(state^.bg_jobs, 0)); if (slotPtr <> nil) then begin job := PBackgroundJob(slotPtr^); if job <> nil then begin @@ -600,7 +611,7 @@ begin kfree(void(uppera)); io.stdio.freeParams(params); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); exit; end; @@ -621,7 +632,7 @@ begin { --- Background launch --- } job := PBackgroundJob(kalloc(SizeOf(TBackgroundJob))); if job <> nil then begin - memset(uint32(job), 0, SizeOf(TBackgroundJob)); + memset(PtrUInt(job), 0, SizeOf(TBackgroundJob)); job^.StdOut := io.stdio.createOutBuf(1024); job^.StdErr := io.stdio.createOutBuf(1024); job^.LastDrain := 0; @@ -632,7 +643,7 @@ begin { Copy command name } pcount := stringSize(params^.Param); if pcount > 31 then pcount := 31; - memcpy(uint32(params^.Param), uint32(@job^.CmdName[0]), pcount); + memcpy(PtrUInt(params^.Param), PtrUInt(@job^.CmdName[0]), pcount); job^.CmdName[pcount] := #0; { Launch but don't set ForegroundPID } @@ -644,9 +655,9 @@ begin if ctx <> nil then begin job^.PID := ctx^.ProcessID; if state^.bg_jobs = nil then - state^.bg_jobs := DL_New(SizeOf(uint32)); - slotPtr := DL_Add(state^.bg_jobs); - slotPtr^ := uint32(job); + state^.bg_jobs := DL_New(SizeOf(PtrUInt)); + slotPtr := pointer(DL_Add(state^.bg_jobs)); + slotPtr^ := PtrUInt(job); appendText(state, '['); lastParam := intToString(job^.JobNum); appendText(state, lastParam); @@ -702,7 +713,7 @@ begin { Background file dispatch } job := PBackgroundJob(kalloc(SizeOf(TBackgroundJob))); if job <> nil then begin - memset(uint32(job), 0, SizeOf(TBackgroundJob)); + memset(PtrUInt(job), 0, SizeOf(TBackgroundJob)); job^.StdOut := io.stdio.createOutBuf(1024); job^.StdErr := io.stdio.createOutBuf(1024); job^.LastDrain := 0; @@ -711,7 +722,7 @@ begin job^.JobNum := state^.bg_next_job; pcount := stringSize(params^.Param); if pcount > 31 then pcount := 31; - memcpy(uint32(params^.Param), uint32(@job^.CmdName[0]), pcount); + memcpy(PtrUInt(params^.Param), PtrUInt(@job^.CmdName[0]), pcount); job^.CmdName[pcount] := #0; dispatchPID := driver.storage.filedispatch.dispatch(absPath, params, @@ -719,9 +730,9 @@ begin if dispatchPID > 0 then begin job^.PID := dispatchPID; if state^.bg_jobs = nil then - state^.bg_jobs := DL_New(SizeOf(uint32)); - slotPtr := DL_Add(state^.bg_jobs); - slotPtr^ := uint32(job); + state^.bg_jobs := DL_New(SizeOf(PtrUInt)); + slotPtr := pointer(DL_Add(state^.bg_jobs)); + slotPtr^ := PtrUInt(job); appendText(state, '['); lastParam := intToString(job^.JobNum); appendText(state, lastParam); @@ -732,8 +743,7 @@ begin kfree(void(lastParam)); appendChar(state, #10); end else begin - appendText(state, 'Unknown command. Type HELP for a list.'); - appendChar(state, #10); + showLaunchError(state, job^.StdErr); io.stdio.freeOutBuf(job^.StdOut); io.stdio.freeOutBuf(job^.StdErr); kfree(void(job)); @@ -758,8 +768,7 @@ begin if dispatchPID > 0 then begin state^.ForegroundPID := dispatchPID; end else begin - appendText(state, 'Unknown command. Type HELP for a list.'); - appendChar(state, #10); + showLaunchError(state, state^.fg_stderr); io.stdio.freeOutBuf(state^.fg_stdout); state^.fg_stdout := nil; io.stdio.freeOutBuf(state^.fg_stderr); state^.fg_stderr := nil; io.stdio.freeOutBuf(state^.fg_stdin); state^.fg_stdin := nil; @@ -783,7 +792,7 @@ begin { Reset input line } state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); end; { ============================================================ @@ -831,7 +840,7 @@ begin appendText(state, '^C'); appendChar(state, #10); state^.line_len := 0; - memset(uint32(@state^.line_buf[0]), 0, MAX_LINE); + memset(PtrUInt(@state^.line_buf[0]), 0, MAX_LINE); showPrompt(state); end; exit; @@ -849,8 +858,8 @@ begin if key = LV_KEY_UP then begin if state^.hist_count > 0 then begin if state^.hist_pos = -1 then begin - memcpy(uint32(@state^.line_buf[0]), - uint32(@state^.saved_line[0]), + memcpy(PtrUInt(@state^.line_buf[0]), + PtrUInt(@state^.saved_line[0]), state^.line_len + 1); state^.saved_len := state^.line_len; state^.hist_pos := 0; @@ -863,8 +872,8 @@ begin state^.text_buf[state^.text_len] := #0; state^.line_len := stringSize( @state^.hist[(sint32(state^.hist_head) - 1 - state^.hist_pos + HIST_SIZE * 2) mod HIST_SIZE][0]); - memcpy(uint32(@state^.hist[(sint32(state^.hist_head) - 1 - state^.hist_pos + HIST_SIZE * 2) mod HIST_SIZE][0]), - uint32(@state^.line_buf[0]), + memcpy(PtrUInt(@state^.hist[(sint32(state^.hist_head) - 1 - state^.hist_pos + HIST_SIZE * 2) mod HIST_SIZE][0]), + PtrUInt(@state^.line_buf[0]), state^.line_len + 1); appendText(state, @state^.line_buf[0]); refreshDisplay(state); @@ -882,12 +891,12 @@ begin if state^.hist_pos >= 0 then begin state^.line_len := stringSize( @state^.hist[(sint32(state^.hist_head) - 1 - state^.hist_pos + HIST_SIZE * 2) mod HIST_SIZE][0]); - memcpy(uint32(@state^.hist[(sint32(state^.hist_head) - 1 - state^.hist_pos + HIST_SIZE * 2) mod HIST_SIZE][0]), - uint32(@state^.line_buf[0]), + memcpy(PtrUInt(@state^.hist[(sint32(state^.hist_head) - 1 - state^.hist_pos + HIST_SIZE * 2) mod HIST_SIZE][0]), + PtrUInt(@state^.line_buf[0]), state^.line_len + 1); end else begin - memcpy(uint32(@state^.saved_line[0]), - uint32(@state^.line_buf[0]), + memcpy(PtrUInt(@state^.saved_line[0]), + PtrUInt(@state^.line_buf[0]), state^.saved_len + 1); state^.line_len := state^.saved_len; end; @@ -941,7 +950,7 @@ procedure onClose(wid: uint32); var cnt : Plv_obj; state : PVTermState; - slotPtr : ^uint32; + slotPtr : ^PtrUInt; bgJob : PBackgroundJob; scr_w : sint32; begin @@ -969,7 +978,7 @@ begin { Kill and free background jobs } if state^.bg_jobs <> nil then begin for scr_w := sint32(DL_Size(state^.bg_jobs)) - 1 downto 0 do begin - slotPtr := DL_Get(state^.bg_jobs, uint32(scr_w)); + slotPtr := pointer(DL_Get(state^.bg_jobs, uint32(scr_w))); if slotPtr <> nil then begin bgJob := PBackgroundJob(slotPtr^); if bgJob <> nil then begin @@ -1020,7 +1029,7 @@ begin { Allocate a new instance } state := PVTermState(kalloc(SizeOf(TVTermState))); if state = nil then exit; - memset(uint32(state), 0, SizeOf(TVTermState)); + memset(PtrUInt(state), 0, SizeOf(TVTermState)); state^.hist_pos := -1; state^.cwd := stringCopy('/'); diff --git a/src/driver/hid/driver.hid.mouse.pas b/src/driver/hid/driver.hid.mouse.pas index e88702ff..7b912173 100644 --- a/src/driver/hid/driver.hid.mouse.pas +++ b/src/driver/hid/driver.hid.mouse.pas @@ -12,9 +12,6 @@ unit driver.hid.mouse; interface -uses - driver.video; - type TMouseEventType = ( MOUSE_MOVE, @@ -36,6 +33,7 @@ function getMouseRMB: boolean; function getMouseScroll: sint32; { Setters - called by driver.hid.mouse drivers (PS/2, driver.bus.usb) } +procedure setBounds(width, height: uint32); procedure setMousePos(x, y: sint32); procedure setMouseLMB(down: boolean); procedure setMouseRMB(down: boolean); @@ -53,6 +51,7 @@ const MAX_MOUSE_HOOKS = 8; var + maxW, maxH : sint32; MouseX : sint32 = 0; MouseY : sint32 = 0; MouseLMB : boolean = false; @@ -87,12 +86,17 @@ begin ScrollAccum := 0; end; +procedure setBounds(width, height: uint32); +begin + if width > $7FFFFFFF then width := $7FFFFFFF; + if height > $7FFFFFFF then height := $7FFFFFFF; + maxW := sint32(width); + maxH := sint32(height); + setMousePos(MouseX, MouseY); +end; + procedure setMousePos(x, y: sint32); -var - maxW, maxH : sint32; begin - maxW := sint32(driver.video.frontBufferWidth); - maxH := sint32(driver.video.frontBufferHeight); if x < 0 then x := 0; if y < 0 then y := 0; if (maxW > 0) and (x >= maxW) then x := maxW - 1; diff --git a/src/driver/hid/ps2/driver.hid.ps2.keyboard.pas b/src/driver/hid/ps2/driver.hid.ps2.keyboard.pas index 98ce4b39..099ab201 100644 --- a/src/driver/hid/ps2/driver.hid.ps2.keyboard.pas +++ b/src/driver/hid/ps2/driver.hid.ps2.keyboard.pas @@ -12,18 +12,17 @@ unit driver.hid.ps2.keyboard; interface uses - boot.mgr, driver.hid.keyboard, io.syslog, - core.util, arch.x86.util, - arch.x86.isr.ps2keyboard; + core.util, arch.platform.cpu, + arch.platform.interrupts, arch.common.legacyirq; var - key_matrix : array [1..256] of TKeyInfo; - key_matrix_shift : array [1..256] of TKeyInfo; + key_matrix : array [0..255] of TKeyInfo; + key_matrix_shift : array [0..255] of TKeyInfo; procedure init(); -procedure init_layout(keyboard_layout : array of TKeyInfo); +procedure init_layout(const keyboard_layout : array of TKeyInfo); procedure disable; procedure lang_USA(); @@ -32,14 +31,16 @@ implementation uses driver.mgr; -procedure callback(scan_code : void); +var enabled: boolean = false; + +procedure callback(scan_code : uint8); var info : TKeyInfo; raw : uint8; baseCode : uint8; isBreak : boolean; begin - raw := uint8(scan_code); + raw := scan_code; { In PS/2 scancode set 1, bit 7 set = key release (break code) } isBreak := (raw AND $80) <> 0; @@ -71,26 +72,36 @@ begin end; end; +procedure keyboardIRQ; +var + code: uint8; +begin + if (inb($64) and $21) <> 1 then exit; + code := inb($60); + if enabled then callback(code); +end; + function load(ptr : void) : boolean; begin - arch.x86.isr.ps2keyboard.register(); - arch.x86.isr.ps2keyboard.hook(uint32(@callback)); + enabled := true; + arch.platform.interrupts.registerIRQ(33, @keyboardIRQ); + arch.common.legacyirq.enableLine(1); io.syslog.logln('PS/2 KEYBOARD', 'LOADED.'); load := true; end; procedure disable; begin - arch.x86.isr.ps2keyboard.unhook(uint32(@callback)); + enabled := false; io.syslog.logln('PS/2 KEYBOARD', 'Disabled (driver.bus.usb driver.hid.keyboard active).'); end; -procedure init_layout(keyboard_layout : array of TKeyInfo); +procedure init_layout(const keyboard_layout : array of TKeyInfo); var devid : TDeviceIdentifier; begin io.syslog.logln('PS/2 KEYBOARD', 'INIT BEGIN.'); - if keyboard_layout[1].key_code = 0 then lang_USA(); + if (High(keyboard_layout) < 1) or (keyboard_layout[1].key_code = 0) then lang_USA(); devid.bus := biUnknown; devid.id0 := 0; devid.id1 := 0; @@ -354,7 +365,4 @@ begin key_matrix_shift[53].key_code := $3F; end; -initialization - boot.mgr.registerBoot('driver.hid.ps2.keyboard', @init, 'PS/2 Keyboard Driver', BOOT_MGR_BARRIER_DEVICE); - end. diff --git a/src/driver/hid/ps2/driver.hid.ps2.mouse.pas b/src/driver/hid/ps2/driver.hid.ps2.mouse.pas index 71bae687..7feaa429 100644 --- a/src/driver/hid/ps2/driver.hid.ps2.mouse.pas +++ b/src/driver/hid/ps2/driver.hid.ps2.mouse.pas @@ -11,15 +11,14 @@ unit driver.hid.ps2.mouse; interface uses - boot.mgr, debug.tracer, driver.hid.mouse, io.syslog, driver.video, - core.util, arch.x86.util, + core.util, arch.platform.cpu, memory.heap, core.strings, - arch.x86.isr.mgr, + arch.platform.interrupts, arch.common.legacyirq, driver.mgr; type @@ -114,6 +113,7 @@ end; procedure main(); var i : integer; + bytesRead: uint32; b : byte; packet : TMousePacket; x, y, f : byte; @@ -124,7 +124,9 @@ begin 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 + bytesRead := 0; + while (bytesRead < 32) and ((inb($64) and $21) = $21) do begin + inc(bytesRead); b := inb($60); if Cycle = 0 then begin if (b AND $08) = $08 then begin @@ -213,8 +215,10 @@ var status : uint8; devid_byte : uint8; tmp : uint8; + irqFlags: PtrUInt; begin push_trace('driver.hid.ps2.mouse.load'); + irqFlags := arch.platform.cpu.lock; { Disable both PS/2 ports while configuring } mouse_wait_long(1); @@ -290,10 +294,12 @@ begin mouse_write($F4); mouse_read(); - arch.x86.isr.mgr.registerISR(44, @Main); + arch.platform.interrupts.registerIRQ(44, @Main); + arch.common.legacyirq.enableLine(12); io.syslog.logln('PS/2 MOUSE', 'LOADED.'); io.syslog.log('PS/2 MOUSE', 'Memory: '); - io.syslog.writehexln(uint32(@current)); + io.syslog.writehexln(PtrUInt(@current)); + arch.platform.cpu.unlock(irqFlags); load := true; pop_trace; end; @@ -320,7 +326,4 @@ begin pop_trace; end; -initialization - boot.mgr.registerBoot('driver.hid.ps2.mouse', @init, 'PS/2 Mouse Driver', BOOT_MGR_BARRIER_DEVICE); - end. diff --git a/src/driver/video/driver.video.bga.pas b/src/driver/video/driver.video.bga.pas index 9c19e866..d795f250 100644 --- a/src/driver/video/driver.video.bga.pas +++ b/src/driver/video/driver.video.bga.pas @@ -17,9 +17,8 @@ unit driver.video.bga; interface uses - boot.mgr, - core.util, arch.x86.util, io.syslog, debug.tracer, driver.video.gpu, driver.bus.pci, driver.types, driver.mgr, - arch.x86.memory.virtual, memory.heap; + core.util, arch.platform.cpu, io.syslog, debug.tracer, driver.video.gpu, driver.bus.pci, driver.types, driver.mgr, + arch.platform.memory, memory.heap; procedure init; @@ -58,6 +57,7 @@ const var BGAPresent : boolean = false; BGAFramebuffer: uint32 = 0; + BGAMemoryBytes: uint64 = 0; BGAPCIBus : uint8 = 0; BGAPCISlot : uint8 = 0; BGAPCIFunc : uint8 = 0; @@ -76,22 +76,6 @@ begin bgaReadReg := inw(BGA_PORT_DATA); end; -{ Map the framebuffer physical memory pages so we can access it } -procedure mapFramebuffer(address, width, height : uint32; bpp : uint8); -var - framebufferSize : uint32; - lowerPage, upperPage, page : uint32; -begin - push_trace('driver.video.bga.mapFramebuffer'); - framebufferSize := (width * height * uint32(bpp)) div 8; - lowerPage := (address SHR 22) - 1; - upperPage := ((address + framebufferSize) SHR 22) + 1; - for page := lowerPage to upperPage do begin - kpalloc(page SHL 22); - end; - pop_trace; -end; - { Drivermanagement load callback: called when driver.bus.pci finds a matching device } function load(ptr : void) : boolean; var @@ -141,6 +125,18 @@ begin id := bgaReadReg(BGA_REG_ID); if (id >= BGA_ID_MIN) and (id <= BGA_ID_MAX) then begin BGAPresent := true; + { PCI's legacy device_id field contains the vendor ID. VirtualBox's + BGA data port returns VRAM bytes on a 32-bit read; index $0A is its + monitor-count interface, not the Bochs 64 KiB memory register. + See VirtualBox DevVGA.cpp, vgaIoPortReadVbeData. } + if (dev^.device_id = $80EE) or (dev^.device_id = $15AD) then + BGAMemoryBytes := inl(BGA_PORT_DATA) + else if id >= $B0C5 then + BGAMemoryBytes := uint64(bgaReadReg($0A)) * 65536 + else if id = $B0C4 then + BGAMemoryBytes := 8 * 1024 * 1024 + else + BGAMemoryBytes := 4 * 1024 * 1024; io.syslog.log('BGA', 'Detected BGA version $'); io.syslog.writehexln(id); @@ -164,6 +160,10 @@ end; { GPU framework: setMode callback } function bgaSetMode(width, height : uint32; bpp : uint8; var info : TGPUModeInfo) : boolean; +var + mapped: pointer; + bytes: uint64; + oldWidth, oldHeight, oldBPP, oldEnable: uint16; begin push_trace('driver.video.bga.bgaSetMode'); bgaSetMode := false; @@ -173,6 +173,18 @@ begin exit; end; + if (width = 0) or (height = 0) or (width > 65535) or + (height > 65535) or (bpp <> 32) then exit; + bytes := uint64(width) * height * 4; + if (BGAMemoryBytes = 0) or (bytes > BGAMemoryBytes) or + (bytes > High(SizeUInt)) then exit; + mapped := arch.platform.memory.mapDevice(BGAFramebuffer, SizeUInt(bytes)); + if mapped = nil then exit; + oldWidth := bgaReadReg(BGA_REG_XRES); + oldHeight := bgaReadReg(BGA_REG_YRES); + oldBPP := bgaReadReg(BGA_REG_BPP); + oldEnable := bgaReadReg(BGA_REG_ENABLE); + { Disable the display while changing mode } bgaWriteReg(BGA_REG_ENABLE, BGA_DISABLED); @@ -191,20 +203,28 @@ begin bgaWriteReg(BGA_REG_ENABLE, BGA_ENABLED or BGA_LFB_ENABLED); { Verify mode was set } - if bgaReadReg(BGA_REG_XRES) <> (width and $FFFF) then begin + if (bgaReadReg(BGA_REG_XRES) <> width) or + (bgaReadReg(BGA_REG_YRES) <> height) or + (bgaReadReg(BGA_REG_BPP) <> bpp) then begin + bgaWriteReg(BGA_REG_ENABLE, BGA_DISABLED); + bgaWriteReg(BGA_REG_XRES, oldWidth); + bgaWriteReg(BGA_REG_YRES, oldHeight); + bgaWriteReg(BGA_REG_BPP, oldBPP); + bgaWriteReg(BGA_REG_VIRT_WIDTH, oldWidth); + bgaWriteReg(BGA_REG_VIRT_HEIGHT, oldHeight); + bgaWriteReg(BGA_REG_ENABLE, oldEnable); io.syslog.logln('BGA', 'setMode: XRES verify failed.'); pop_trace; exit; end; - { Map the framebuffer pages } - mapFramebuffer(BGAFramebuffer, width, height, bpp); + { Fill in the mode info for the caller } info.Width := width; info.Height := height; info.BPP := bpp; - info.Framebuffer := BGAFramebuffer; + info.Framebuffer := PtrUInt(mapped); info.Pitch := (width * uint32(bpp)) div 8; io.syslog.log('BGA', 'Mode set: '); @@ -247,7 +267,5 @@ begin pop_trace; end; -initialization - boot.mgr.registerBoot('driver.video.bga', @init, 'BGA Display Driver Initialization', 'driver.video'); end. diff --git a/src/driver/video/driver.video.desktop.pas b/src/driver/video/driver.video.desktop.pas index b1383e35..e73f6061 100644 --- a/src/driver/video/driver.video.desktop.pas +++ b/src/driver/video/driver.video.desktop.pas @@ -15,8 +15,7 @@ unit driver.video.desktop; interface uses - boot.mgr, - driver.video.lvgl, driver.video, driver.video.gpu, driver.timer.rtc, core.strings, core.util, arch.x86.util, debug.tracer, arch.x86.multiboot, arch.x86.cpu, driver.io.serial, driver.video.windows, core.version; + driver.video.lvgl, driver.video, driver.video.gpu, driver.timer.rtc, core.strings, core.util, arch.platform.cpu, debug.tracer, boot.multiboot, driver.io.serial, driver.video.windows, core.version; type TProgLaunchProc = procedure; @@ -246,6 +245,9 @@ var mem_str, res_str, cpu_str, clk_str : pchar; cw : sint32; badge_h : sint32; + registers, features: TCPURegisters; + vendor: array[0..12] of char; + maxLeaf: uint32; begin if driver.video.windows.isWindowOpen(sysinfo_win_id) then exit; @@ -269,9 +271,20 @@ begin { ---- System Information ---- } addSectionHeader(content, 'System Information'); - cpu_str := @arch.x86.cpu.CPUID.Identifier[0]; + queryCPU(0, 0, registers); + maxLeaf := registers.eax; + puint32(@vendor[0])^ := registers.ebx; + puint32(@vendor[4])^ := registers.edx; + puint32(@vendor[8])^ := registers.ecx; + vendor[12] := #0; + cpu_str := @vendor[0]; + queryCPU(1, 0, features); addInfoRow(content, cw, 'CPU Vendor', cpu_str); - clk_str := stringConcat(intToString(arch.x86.cpu.CPUID.ClockSpeed.MHz), ' MHz'); + clk_str := 'Not reported'; + if maxLeaf >= $16 then begin + queryCPU($16, 0, registers); + if registers.eax <> 0 then clk_str := stringConcat(intToString(registers.eax), ' MHz'); + end; 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); @@ -314,65 +327,65 @@ begin lv_obj_remove_flag(instr_box, LV_OBJ_FLAG_SCROLLABLE); { Old capabilities (EDX) } - if arch.x86.cpu.CPUID.Capabilities0^.FPU then addBadge(instr_box, 'FPU'); - if arch.x86.cpu.CPUID.Capabilities0^.VME then addBadge(instr_box, 'VME'); - if arch.x86.cpu.CPUID.Capabilities0^.DE then addBadge(instr_box, 'DE'); - if arch.x86.cpu.CPUID.Capabilities0^.PSE then addBadge(instr_box, 'PSE'); - if arch.x86.cpu.CPUID.Capabilities0^.TSC then addBadge(instr_box, 'TSC'); - if arch.x86.cpu.CPUID.Capabilities0^.MSR then addBadge(instr_box, 'MSR'); - if arch.x86.cpu.CPUID.Capabilities0^.PAE then addBadge(instr_box, 'PAE'); - if arch.x86.cpu.CPUID.Capabilities0^.MCE then addBadge(instr_box, 'arch.x86.fault.mce'); - if arch.x86.cpu.CPUID.Capabilities0^.CX8 then addBadge(instr_box, 'CX8'); - if arch.x86.cpu.CPUID.Capabilities0^.APIC then addBadge(instr_box, 'APIC'); - if arch.x86.cpu.CPUID.Capabilities0^.SEP then addBadge(instr_box, 'SEP'); - if arch.x86.cpu.CPUID.Capabilities0^.MTRR then addBadge(instr_box, 'MTRR'); - if arch.x86.cpu.CPUID.Capabilities0^.PGE then addBadge(instr_box, 'PGE'); - if arch.x86.cpu.CPUID.Capabilities0^.MCA then addBadge(instr_box, 'MCA'); - if arch.x86.cpu.CPUID.Capabilities0^.CMOV then addBadge(instr_box, 'CMOV'); - if arch.x86.cpu.CPUID.Capabilities0^.PAT then addBadge(instr_box, 'PAT'); - if arch.x86.cpu.CPUID.Capabilities0^.PSE36 then addBadge(instr_box, 'PSE36'); - if arch.x86.cpu.CPUID.Capabilities0^.PSN then addBadge(instr_box, 'PSN'); - if arch.x86.cpu.CPUID.Capabilities0^.CLF then addBadge(instr_box, 'CLF'); - if arch.x86.cpu.CPUID.Capabilities0^.DTES then addBadge(instr_box, 'DTES'); - if arch.x86.cpu.CPUID.Capabilities0^.ACPI then addBadge(instr_box, 'ACPI'); - if arch.x86.cpu.CPUID.Capabilities0^.MMX then addBadge(instr_box, 'MMX'); - if arch.x86.cpu.CPUID.Capabilities0^.FXSR then addBadge(instr_box, 'FXSR'); - if arch.x86.cpu.CPUID.Capabilities0^.SSE then addBadge(instr_box, 'SSE'); - if arch.x86.cpu.CPUID.Capabilities0^.SSE2 then addBadge(instr_box, 'SSE2'); - if arch.x86.cpu.CPUID.Capabilities0^.SS then addBadge(instr_box, 'SS'); - if arch.x86.cpu.CPUID.Capabilities0^.HTT then addBadge(instr_box, 'HTT'); - if arch.x86.cpu.CPUID.Capabilities0^.TM1 then addBadge(instr_box, 'TM1'); - if arch.x86.cpu.CPUID.Capabilities0^.IA64 then addBadge(instr_box, 'IA64'); - if arch.x86.cpu.CPUID.Capabilities0^.PBE then addBadge(instr_box, 'PBE'); + if (features.edx and (uint32(1) shl 0) <> 0) then addBadge(instr_box, 'FPU'); + if (features.edx and (uint32(1) shl 1) <> 0) then addBadge(instr_box, 'VME'); + if (features.edx and (uint32(1) shl 2) <> 0) then addBadge(instr_box, 'DE'); + if (features.edx and (uint32(1) shl 3) <> 0) then addBadge(instr_box, 'PSE'); + if (features.edx and (uint32(1) shl 4) <> 0) then addBadge(instr_box, 'TSC'); + if (features.edx and (uint32(1) shl 5) <> 0) then addBadge(instr_box, 'MSR'); + if (features.edx and (uint32(1) shl 6) <> 0) then addBadge(instr_box, 'PAE'); + if (features.edx and (uint32(1) shl 7) <> 0) then addBadge(instr_box, 'arch.x86.fault.mce'); + if (features.edx and (uint32(1) shl 8) <> 0) then addBadge(instr_box, 'CX8'); + if (features.edx and (uint32(1) shl 9) <> 0) then addBadge(instr_box, 'APIC'); + if (features.edx and (uint32(1) shl 11) <> 0) then addBadge(instr_box, 'SEP'); + if (features.edx and (uint32(1) shl 12) <> 0) then addBadge(instr_box, 'MTRR'); + if (features.edx and (uint32(1) shl 13) <> 0) then addBadge(instr_box, 'PGE'); + if (features.edx and (uint32(1) shl 14) <> 0) then addBadge(instr_box, 'MCA'); + if (features.edx and (uint32(1) shl 15) <> 0) then addBadge(instr_box, 'CMOV'); + if (features.edx and (uint32(1) shl 16) <> 0) then addBadge(instr_box, 'PAT'); + if (features.edx and (uint32(1) shl 17) <> 0) then addBadge(instr_box, 'PSE36'); + if (features.edx and (uint32(1) shl 18) <> 0) then addBadge(instr_box, 'PSN'); + if (features.edx and (uint32(1) shl 19) <> 0) then addBadge(instr_box, 'CLF'); + if (features.edx and (uint32(1) shl 21) <> 0) then addBadge(instr_box, 'DTES'); + if (features.edx and (uint32(1) shl 22) <> 0) then addBadge(instr_box, 'ACPI'); + if (features.edx and (uint32(1) shl 23) <> 0) then addBadge(instr_box, 'MMX'); + if (features.edx and (uint32(1) shl 24) <> 0) then addBadge(instr_box, 'FXSR'); + if (features.edx and (uint32(1) shl 25) <> 0) then addBadge(instr_box, 'SSE'); + if (features.edx and (uint32(1) shl 26) <> 0) then addBadge(instr_box, 'SSE2'); + if (features.edx and (uint32(1) shl 27) <> 0) then addBadge(instr_box, 'SS'); + if (features.edx and (uint32(1) shl 28) <> 0) then addBadge(instr_box, 'HTT'); + if (features.edx and (uint32(1) shl 29) <> 0) then addBadge(instr_box, 'TM1'); + if (features.edx and (uint32(1) shl 30) <> 0) then addBadge(instr_box, 'IA64'); + if (features.edx and (uint32(1) shl 31) <> 0) then addBadge(instr_box, 'PBE'); { New capabilities (ECX) } - if arch.x86.cpu.CPUID.Capabilities1^.SSE3 then addBadge(instr_box, 'SSE3'); - if arch.x86.cpu.CPUID.Capabilities1^.PCLMUL then addBadge(instr_box, 'PCLMUL'); - if arch.x86.cpu.CPUID.Capabilities1^.DTES64 then addBadge(instr_box, 'DTES64'); - if arch.x86.cpu.CPUID.Capabilities1^.MONITOR then addBadge(instr_box, 'MONITOR'); - if arch.x86.cpu.CPUID.Capabilities1^.DS_CPL then addBadge(instr_box, 'DS_CPL'); - if arch.x86.cpu.CPUID.Capabilities1^.VMX then addBadge(instr_box, 'VMX'); - if arch.x86.cpu.CPUID.Capabilities1^.SMX then addBadge(instr_box, 'SMX'); - if arch.x86.cpu.CPUID.Capabilities1^.EST then addBadge(instr_box, 'EST'); - if arch.x86.cpu.CPUID.Capabilities1^.TM2 then addBadge(instr_box, 'TM2'); - if arch.x86.cpu.CPUID.Capabilities1^.SSSE3 then addBadge(instr_box, 'SSSE3'); - if arch.x86.cpu.CPUID.Capabilities1^.CID then addBadge(instr_box, 'CID'); - if arch.x86.cpu.CPUID.Capabilities1^.FMA then addBadge(instr_box, 'FMA'); - if arch.x86.cpu.CPUID.Capabilities1^.CX16 then addBadge(instr_box, 'CX16'); - if arch.x86.cpu.CPUID.Capabilities1^.ETPRD then addBadge(instr_box, 'ETPRD'); - if arch.x86.cpu.CPUID.Capabilities1^.PDCM then addBadge(instr_box, 'PDCM'); - if arch.x86.cpu.CPUID.Capabilities1^.PCIDE then addBadge(instr_box, 'PCIDE'); - if arch.x86.cpu.CPUID.Capabilities1^.DCA then addBadge(instr_box, 'DCA'); - if arch.x86.cpu.CPUID.Capabilities1^.SSE4_1 then addBadge(instr_box, 'SSE4.1'); - if arch.x86.cpu.CPUID.Capabilities1^.SSE4_2 then addBadge(instr_box, 'SSE4.2'); - if arch.x86.cpu.CPUID.Capabilities1^.x2APIC then addBadge(instr_box, 'x2APIC'); - if arch.x86.cpu.CPUID.Capabilities1^.MOVBE then addBadge(instr_box, 'MOVBE'); - if arch.x86.cpu.CPUID.Capabilities1^.POPCNT then addBadge(instr_box, 'POPCNT'); - if arch.x86.cpu.CPUID.Capabilities1^.AES then addBadge(instr_box, 'AES'); - if arch.x86.cpu.CPUID.Capabilities1^.XSAVE then addBadge(instr_box, 'XSAVE'); - if arch.x86.cpu.CPUID.Capabilities1^.OSXSAVE then addBadge(instr_box, 'OSXSAVE'); - if arch.x86.cpu.CPUID.Capabilities1^.AVX then addBadge(instr_box, 'AVX'); - if arch.x86.cpu.CPUID.Capabilities1^.RDRAND then addBadge(instr_box, 'RDRAND'); + if (features.ecx and (uint32(1) shl 0) <> 0) then addBadge(instr_box, 'SSE3'); + if (features.ecx and (uint32(1) shl 1) <> 0) then addBadge(instr_box, 'PCLMUL'); + if (features.ecx and (uint32(1) shl 2) <> 0) then addBadge(instr_box, 'DTES64'); + if (features.ecx and (uint32(1) shl 3) <> 0) then addBadge(instr_box, 'MONITOR'); + if (features.ecx and (uint32(1) shl 4) <> 0) then addBadge(instr_box, 'DS_CPL'); + if (features.ecx and (uint32(1) shl 5) <> 0) then addBadge(instr_box, 'VMX'); + if (features.ecx and (uint32(1) shl 6) <> 0) then addBadge(instr_box, 'SMX'); + if (features.ecx and (uint32(1) shl 7) <> 0) then addBadge(instr_box, 'EST'); + if (features.ecx and (uint32(1) shl 8) <> 0) then addBadge(instr_box, 'TM2'); + if (features.ecx and (uint32(1) shl 9) <> 0) then addBadge(instr_box, 'SSSE3'); + if (features.ecx and (uint32(1) shl 10) <> 0) then addBadge(instr_box, 'CID'); + if (features.ecx and (uint32(1) shl 12) <> 0) then addBadge(instr_box, 'FMA'); + if (features.ecx and (uint32(1) shl 13) <> 0) then addBadge(instr_box, 'CX16'); + if (features.ecx and (uint32(1) shl 14) <> 0) then addBadge(instr_box, 'ETPRD'); + if (features.ecx and (uint32(1) shl 15) <> 0) then addBadge(instr_box, 'PDCM'); + if (features.ecx and (uint32(1) shl 17) <> 0) then addBadge(instr_box, 'PCIDE'); + if (features.ecx and (uint32(1) shl 18) <> 0) then addBadge(instr_box, 'DCA'); + if (features.ecx and (uint32(1) shl 19) <> 0) then addBadge(instr_box, 'SSE4.1'); + if (features.ecx and (uint32(1) shl 20) <> 0) then addBadge(instr_box, 'SSE4.2'); + if (features.ecx and (uint32(1) shl 21) <> 0) then addBadge(instr_box, 'x2APIC'); + if (features.ecx and (uint32(1) shl 22) <> 0) then addBadge(instr_box, 'MOVBE'); + if (features.ecx and (uint32(1) shl 23) <> 0) then addBadge(instr_box, 'POPCNT'); + if (features.ecx and (uint32(1) shl 25) <> 0) then addBadge(instr_box, 'AES'); + if (features.ecx and (uint32(1) shl 26) <> 0) then addBadge(instr_box, 'XSAVE'); + if (features.ecx and (uint32(1) shl 27) <> 0) then addBadge(instr_box, 'OSXSAVE'); + if (features.ecx and (uint32(1) shl 28) <> 0) then addBadge(instr_box, 'AVX'); + if (features.ecx and (uint32(1) shl 30) <> 0) then addBadge(instr_box, 'RDRAND'); { Force layout so wrapped row heights are resolved, then set instr_box to its actual content height. } @@ -863,7 +876,4 @@ begin animateResultsPanel; end; -Initialization - boot.mgr.registerBoot('proc.desktop', @init, 'Initialize Desktop', 'boot.splash.teardown'); - end. diff --git a/src/driver/video/driver.video.doublebuffer.pas b/src/driver/video/driver.video.doublebuffer.pas index 6603cad6..7ea5a84c 100644 --- a/src/driver/video/driver.video.doublebuffer.pas +++ b/src/driver/video/driver.video.doublebuffer.pas @@ -22,17 +22,26 @@ unit driver.video.doublebuffer; interface uses - memory.heap, debug.tracer, driver.video.types, driver.io.serial, core.util, arch.x86.util; + memory.heap, debug.tracer, driver.video.types, driver.io.serial, core.util, arch.platform.cpu; //Init the driver, and register with the driver.video interface in a state ready for execution. procedure init(Register : FRegisterDriver); implementation -function allocateBackBuffer(Width : uint32; Height : uint32; BitsPerPixel : uint8) : uint64; +function allocateBackBuffer(Width : uint32; Height : uint32; BitsPerPixel : uint8) : PtrUInt; +var + bytes: uint64; begin + allocateBackBuffer := 0; + if (Width = 0) or (Height = 0) or (BitsPerPixel = 0) or + (BitsPerPixel mod 8 <> 0) then exit; + bytes := uint64(Width) * (BitsPerPixel div 8); + if bytes > High(uint32) then exit; + bytes := bytes * Height; + if bytes > High(SizeUInt) then exit; debug.tracer.push_trace('driver.video.doublebuffer.allocateBackBuffer.enter'); - allocateBackBuffer:= uint64(klalloc((Width * Height * BitsPerPixel) div 8)); + allocateBackBuffer := PtrUInt(klalloc(SizeUInt(bytes))); debug.tracer.push_trace('driver.video.doublebuffer.allocateBackBuffer.exit'); end; @@ -44,6 +53,7 @@ begin if (VInterface^.BackBuffer.Location <> 0) then begin VInterface^.BackBuffer.Width:= Width; VInterface^.BackBuffer.Height:= Height; + VInterface^.BackBuffer.Pitch := Width * (BitsPerPixel div 8); VInterface^.BackBuffer.BitsPerPixel:= BitsPerPixel; VInterface^.BackBuffer.Initialized:= True; end; @@ -53,27 +63,18 @@ end; procedure Flush(FrontBuffer : PVideoBuffer; BackBuffer : PVideoBuffer); var - idx : uint32; - Back,Front : uint32; - BufferSize : uint32; - -const - //COPY_WIDTH = 64; //Use this for 64bit copies - COPY_WIDTH = 128; //Use this for SSE copies - + row, bytes : uint32; begin - //debug.tracer.push_trace('driver.video.doublebuffer.Flush.enter'); - if not(BackBuffer^.Initialized) then exit; - if ((FrontBuffer^.Width > BackBuffer^.Width) or (FrontBuffer^.Height > BackBuffer^.Height)) then exit; - Back:= BackBuffer^.Location; - Front:= FrontBuffer^.Location; - BufferSize:= ( ( BackBuffer^.Width * BackBuffer^.Height * BackBuffer^.BitsPerPixel) div COPY_WIDTH ) - 1; - for idx:=0 to BufferSize do begin - //Front[idx]:= Back[idx]; - // -- TODO: Get SSE working here for 128bit copies -- - __SSE_128_memcpy(Back + (idx * 16), Front + (idx * 16)); - end; - //debug.tracer.push_trace('driver.video.doublebuffer.Flush.exit'); + if not (FrontBuffer^.Initialized and BackBuffer^.Initialized) then exit; + if (BackBuffer^.Width > FrontBuffer^.Width) or + (BackBuffer^.Height > FrontBuffer^.Height) or + (BackBuffer^.BitsPerPixel <> FrontBuffer^.BitsPerPixel) then exit; + bytes := BackBuffer^.Pitch; + if (bytes = 0) or (bytes > FrontBuffer^.Pitch) or + (BackBuffer^.Height = 0) then exit; + for row := 0 to BackBuffer^.Height - 1 do + memcpy(BackBuffer^.Location + SizeUInt(row) * bytes, + FrontBuffer^.Location + SizeUInt(row) * FrontBuffer^.Pitch, bytes); end; function enable(VideoInterface : PVideoInterface) : boolean; @@ -96,4 +97,4 @@ begin debug.tracer.push_trace('driver.video.doublebuffer.init.exit'); end; -end. \ No newline at end of file +end. diff --git a/src/driver/video/driver.video.gpu.pas b/src/driver/video/driver.video.gpu.pas index 5ab11a17..849863a0 100644 --- a/src/driver/video/driver.video.gpu.pas +++ b/src/driver/video/driver.video.gpu.pas @@ -15,8 +15,7 @@ unit driver.video.gpu; interface uses - boot.mgr, - core.util, arch.x86.util, io.syslog, debug.tracer, core.strings; + core.util, arch.platform.cpu, io.syslog, debug.tracer, core.strings; const GPU_MAX_DRIVERS = 8; @@ -28,7 +27,7 @@ type Width : uint32; Height : uint32; BPP : uint8; - Framebuffer : uint32; { physical address of linear framebuffer } + Framebuffer : PtrUInt; { mapped address of linear framebuffer } Pitch : uint32; { bytes per scanline } end; PGPUModeInfo = ^TGPUModeInfo; @@ -173,6 +172,7 @@ procedure fireModeChangeCallbacks(const info : TGPUModeInfo); var i : uint8; begin + if CallbackCount = 0 then exit; for i := 0 to CallbackCount - 1 do begin if Callbacks[i] <> nil then Callbacks[i](info); @@ -185,6 +185,7 @@ var begin push_trace('driver.video.gpu.setMode'); setMode := false; + if DriverCount = 0 then exit; for i := 0 to DriverCount - 1 do begin if Drivers[i].Available and (Drivers[i].SetMode <> nil) then begin @@ -224,7 +225,4 @@ begin activeDriverName := 'none'; end; -initialization - boot.mgr.registerBoot('driver.video.gpu', @init, 'GPU Driver Framework Initialization', 'driver.mgr'); - end. diff --git a/src/driver/video/driver.video.lvgl.pas b/src/driver/video/driver.video.lvgl.pas index efdc0c0e..5364e944 100644 --- a/src/driver/video/driver.video.lvgl.pas +++ b/src/driver/video/driver.video.lvgl.pas @@ -13,7 +13,7 @@ interface uses driver.video, driver.video.types, core.gfx.color, driver.io.serial, debug.tracer, memory.heap, - driver.hid.mouse, driver.hid.keyboard, arch.x86.isr.tmr0, core.util, arch.x86.util, io.syslog, driver.video.gpu; + driver.hid.mouse, driver.hid.keyboard, arch.platform.interrupts, core.util, arch.platform.cpu, io.syslog, driver.video.gpu; { ============================================================ Opaque LVGL pointer core.types (internal C structs) @@ -46,16 +46,29 @@ type { ============================================================ Stack-allocatable core.types with known sizes ============================================================ } - { lv_style_t — ~12 bytes on 32-bit, padded to 16 for safety } - lv_style_t = packed array[0..15] of uint8; + { C-aligned LVGL 9.2.2 layout. } + lv_style_t = record + values_and_props: pointer; + has_group: uint32; + prop_count: uint8; + end; Plv_style = ^lv_style_t; - { lv_anim_t — ~80-100 bytes on 32-bit, padded to 128 } - lv_anim_t = packed array[0..127] of uint8; + { C-aligned LVGL 9.2.2 layout. } + lv_anim_t = record + callbacks_and_data: array[0..8] of pointer; + values_and_timing: array[0..8] of sint32; + bezier: array[0..3] of sint32; + last_timer_run: uint32; + flags: uint8; + end; Plv_anim = ^lv_anim_t; - { lv_style_transition_dsc_t — ~20 bytes, padded to 24 } - lv_style_transition_dsc_t = packed array[0..23] of uint8; + { C-aligned LVGL 9.2.2 layout. } + lv_style_transition_dsc_t = record + properties, user_data, path_callback: pointer; + duration, delay: uint32; + end; Plv_style_transition_dsc = ^lv_style_transition_dsc_t; { ============================================================ @@ -97,7 +110,7 @@ type end; { lv_style_value_t — C union: int32/pointer/color, all 4 bytes on 32-bit } - lv_style_value_t = packed record + lv_style_value_t = record case byte of 0: (num: sint32); 1: (ptr: pointer); @@ -1669,6 +1682,8 @@ function lv_animimg_get_repeat_count(img: Plv_obj): uint32; cdecl; external; { ============================================================ High-level API for core.version ============================================================ } +procedure lv_event_stop_processing(e: Plv_event); cdecl; external; + procedure lvgl_init(screen_w, screen_h: uint32); function lvgl_handler: uint32; function lvgl_get_display: Plv_display; @@ -1683,6 +1698,8 @@ procedure lvgl_update_resolution(screen_w, screen_h: uint32); procedure lvgl_lock; procedure lvgl_unlock; +var onDebugToggle: procedure = nil; + { Color helper (Pascal wrapper for inline C function) } function lv_color_make(r, g, b: uint8): lv_color_t; @@ -1692,7 +1709,7 @@ function lv_color_make(r, g, b: uint8): lv_color_t; implementation uses - app.uidebug, proc.types, proc.mgr; + proc.types, proc.mgr, arch.common.legacyirq; { ============================================================ Wrappers for LVGL inline/macro functions @@ -1729,9 +1746,10 @@ var { Tick counter — incremented by 1024Hz timer ISR } tick_accumulator : uint32; + tick_fraction : uint64; { Keyboard ring buffer for LVGL } - kb_buf : array[0..15] of uint32; + kb_buf : array[0..63] of uint32; kb_head : uint32; { next write slot (hook side) } kb_tail : uint32; { next read slot (LVGL poll side) } kb_current_key : uint32; { key currently reported as pressed to LVGL, 0 = none } @@ -1739,7 +1757,7 @@ var kb_held_code : uint32; { the LVGL key code of the held key } const - KB_BUF_SIZE = 16; + KB_BUF_SIZE = 64; { LVGL render buffer: 1/10th of screen } LV_BUF_LINES = 120; @@ -1759,7 +1777,7 @@ begin end; { ============================================================ - LVGL Mutex — blocking, recursive, SMP-safe + LVGL Mutex — recursive, FIFO handoff on the single active CPU ============================================================ } const LVGL_MTX_MAX_WAITERS = 16; @@ -1768,84 +1786,85 @@ var lvgl_mtx_locked : uint32 = 0; lvgl_mtx_owner : pointer = nil; lvgl_mtx_depth : uint32 = 0; - lvgl_mtx_waiters : array[0..LVGL_MTX_MAX_WAITERS-1] of pointer; + lvgl_mtx_waiters : array[0..LVGL_MTX_MAX_WAITERS-1] of uint32; + lvgl_mtx_head: uint32 = 0; lvgl_mtx_nwait : uint32 = 0; procedure lvgl_lock; var - old : uint32; - cur : pointer; + irqFlags: PtrUInt; + cur: PProcessContext; + parked: boolean; begin - cur := pointer(proc.mgr.CurrentProcess); - - { Recursive lock — same owner, just bump depth } - if (lvgl_mtx_locked <> 0) and (lvgl_mtx_owner = cur) then begin - lvgl_mtx_depth := lvgl_mtx_depth + 1; + cur := proc.mgr.CurrentProcess; + irqFlags := arch.platform.cpu.lock; + if (lvgl_mtx_locked <> 0) and (lvgl_mtx_owner = pointer(cur)) then begin + inc(lvgl_mtx_depth); + arch.platform.cpu.unlock(irqFlags); exit; end; + arch.platform.cpu.unlock(irqFlags); while true do begin - { CLI to prevent scheduler preemption during lock check + park } - asm pushfd; cli end; - - { Atomic test-and-set (SMP-safe via LOCK prefix) } - old := 1; - asm - mov eax, 1 - lock xchg dword ptr [lvgl_mtx_locked], eax - mov old, eax - end; - - if old = 0 then begin - { Acquired } - lvgl_mtx_owner := cur; + irqFlags := arch.platform.cpu.lock; + if lvgl_mtx_locked = 0 then begin + lvgl_mtx_locked := 1; + lvgl_mtx_owner := pointer(cur); lvgl_mtx_depth := 1; - asm popfd end; + end; + { Unlock hands ownership directly to the oldest waiting process. } + if lvgl_mtx_owner = pointer(cur) then begin + arch.platform.cpu.unlock(irqFlags); exit; end; - - { Failed — park ourselves so the scheduler skips us. - The lock holder will wake us on unlock. } - if lvgl_mtx_nwait < LVGL_MTX_MAX_WAITERS then begin - lvgl_mtx_waiters[lvgl_mtx_nwait] := cur; - lvgl_mtx_nwait := lvgl_mtx_nwait + 1; + parked := lvgl_mtx_nwait < LVGL_MTX_MAX_WAITERS; + if parked then begin + lvgl_mtx_waiters[(lvgl_mtx_head + lvgl_mtx_nwait) mod LVGL_MTX_MAX_WAITERS] := cur^.ProcessID; + inc(lvgl_mtx_nwait); + cur^.State := psAwaiting; end; - PProcessContext(cur)^.State := psAwaiting; - asm popfd end; - - { Yield — scheduler will skip us (psAwaiting). - Resume here when the lock holder wakes us (sets psReady). } - asm hlt end; + arch.platform.cpu.unlock(irqFlags); + if parked then + proc.mgr.proc_await + else + proc.mgr.proc_yield; end; end; procedure lvgl_unlock; var - i : uint32; + irqFlags: PtrUInt; + next: PProcessContext; + pid: uint32; begin - { Recursive unlock — just decrement depth } - if lvgl_mtx_depth > 1 then begin - lvgl_mtx_depth := lvgl_mtx_depth - 1; + irqFlags := arch.platform.cpu.lock; + if lvgl_mtx_owner <> pointer(proc.mgr.CurrentProcess) then begin + arch.platform.cpu.unlock(irqFlags); exit; end; - - asm pushfd; cli end; - + if lvgl_mtx_depth > 1 then begin + dec(lvgl_mtx_depth); + arch.platform.cpu.unlock(irqFlags); + exit; + end; + while lvgl_mtx_nwait <> 0 do begin + pid := lvgl_mtx_waiters[lvgl_mtx_head]; + lvgl_mtx_head := (lvgl_mtx_head + 1) mod LVGL_MTX_MAX_WAITERS; + dec(lvgl_mtx_nwait); + next := proc.mgr.findByID(pid); + if (next <> nil) and (next^.State = psAwaiting) then begin + lvgl_mtx_owner := pointer(next); + lvgl_mtx_depth := 1; + next^.State := psReady; + arch.platform.cpu.unlock(irqFlags); + exit; + end; + end; lvgl_mtx_locked := 0; lvgl_mtx_owner := nil; lvgl_mtx_depth := 0; - - { Wake all waiters — they will compete for the lock } - if lvgl_mtx_nwait > 0 then begin - for i := 0 to lvgl_mtx_nwait - 1 do - if lvgl_mtx_waiters[i] <> nil then - PProcessContext(lvgl_mtx_waiters[i])^.State := psReady; - lvgl_mtx_nwait := 0; - end; - - asm popfd end; + arch.platform.cpu.unlock(irqFlags); end; - { ============================================================ Flush callback — copies LVGL render buffer to driver.video back buffer Handles 32bpp (direct copy) and 16bpp (ARGB8888 -> RGB565). @@ -1873,7 +1892,7 @@ begin for x := 0 to area_w - 1 do begin dst32[x] := src[x]; end; - src := puint32(uint32(src) + uint32(area_w * 4)); + src := puint32(PtrUInt(src) + uint32(area_w * 4)); end; end else if bpp = 16 then begin { 16bpp: convert ARGB8888 -> RGB565, 2 bytes per pixel } @@ -1886,7 +1905,7 @@ begin r := (pixel shr 16) and $FF; dst16[x] := uint16(((uint16(r) shr 3) shl 11) or ((uint16(g) shr 2) shl 5) or (uint16(b) shr 3)); end; - src := puint32(uint32(src) + uint32(area_w * 4)); + src := puint32(PtrUInt(src) + uint32(area_w * 4)); end; end; @@ -1934,7 +1953,7 @@ begin kb_tail := (kb_tail + 1) mod KB_BUF_SIZE; data^.key := kb_current_key; data^.state := LV_INDEV_STATE_PRESSED; - data^.continue_reading := false; { one press per timer cycle for proper long-press timing } + data^.continue_reading := (kb_tail <> kb_head); 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; @@ -1958,7 +1977,7 @@ var 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 - app.uidebug.toggle; + if onDebugToggle <> nil then onDebugToggle; exit; end; @@ -2002,7 +2021,7 @@ begin end; { ============================================================ - 1024Hz timer tick — called from arch.x86.isr.tmr0 (~1ms per tick) + PIT timer tick — called from arch.platform.interrupts ============================================================ } procedure lvgl_timer_tick(data: void); begin @@ -2025,6 +2044,7 @@ begin debug.tracer.push_trace('driver.video.lvgl.init.enter'); tick_accumulator := 0; + tick_fraction := 0; kb_head := 0; kb_tail := 0; kb_current_key := 0; @@ -2068,7 +2088,7 @@ begin driver.hid.keyboard.hook(@lvgl_keyboard_hook); { Hook 1024Hz timer for accurate LVGL tick } - arch.x86.isr.tmr0.hook(uint32(@lvgl_timer_tick)); + arch.platform.interrupts.registerTimer(@lvgl_timer_tick); { Register for GPU mode-change notifications so LVGL resolution updates automatically } driver.video.gpu.registerModeChangeCallback(@lvglModeChanged); @@ -2112,16 +2132,21 @@ end; function lvgl_handler: uint32; var elapsed: uint32; + irqFlags: PtrUInt; scroll_delta: sint32; mx, my: sint32; pt: lv_point_t; target, walk: Plv_obj; begin { Feed accumulated ticks to LVGL } + irqFlags := arch.platform.cpu.lock; elapsed := tick_accumulator; tick_accumulator := 0; - if elapsed > 0 then - lv_tick_inc(elapsed); + arch.platform.cpu.unlock(irqFlags); + tick_fraction := tick_fraction + uint64(elapsed) * PIT_DIVISOR * 1000; + elapsed := tick_fraction div PIT_INPUT_HZ; + tick_fraction := tick_fraction mod PIT_INPUT_HZ; + if elapsed > 0 then lv_tick_inc(elapsed); { Process scroll wheel } scroll_delta := driver.hid.mouse.getMouseScroll; diff --git a/src/driver/video/driver.video.pas b/src/driver/video/driver.video.pas index d858287b..b10c635d 100644 --- a/src/driver/video/driver.video.pas +++ b/src/driver/video/driver.video.pas @@ -22,8 +22,8 @@ unit driver.video; interface uses - boot.mgr, io.syslog, - memory.heap, debug.tracer, core.gfx.color, driver.video.types, core.ds.hashmap, core.util, arch.x86.util, core.gfx.texture, driver.video.gpu, core.gfx.fonts; + io.syslog, + memory.heap, debug.tracer, core.gfx.color, driver.video.types, core.ds.hashmap, core.util, arch.platform.cpu, core.gfx.texture, driver.video.gpu, core.gfx.fonts; procedure init(); procedure DrawPixel(X : uint32; Y : uint32; Pixel : TRGB32); @@ -31,7 +31,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); +procedure reinit(fb_addr : PtrUInt; width, height, pitch : uint32; bpp : uint8); function register(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean; function enable(DriverIdentifier : pchar) : boolean; @@ -42,12 +42,12 @@ function frontBufferBpp : uint8; function backBufferWidth : uint32; function backBufferHeight : uint32; function backBufferBpp : uint8; -function backBufferLocation : uint32; -function frontBufferLocation : uint32; +function backBufferLocation : PtrUInt; +function frontBufferLocation : PtrUInt; Procedure basicFDrawTexture(Buffer : PVideoBuffer; X : uint32; Y : uint32; Texture : PTexture); -{ Text drawing — renders 8x16 bitmap font glyphs directly to the +{ Text drawing — renders 8x16 bitmap font glyphs directly to the framebuffer via DrawPixel. Useful for panic screens and other contexts where LVGL is unavailable. } function DrawChar(X, Y : uint32; C : char; Color : TRGB32) : uint32; @@ -58,8 +58,9 @@ function DrawInt(X, Y : uint32; Value : uint32; Color : TRGB32) : uint32; implementation uses + driver.hid.mouse, driver.video.vesa8, driver.video.vesa16, driver.video.vesa24, driver.video.vesa32, - driver.video.lvgl, driver.video.doublebuffer, driver.video.vesa; + driver.video.doublebuffer; Procedure dummyFDrawPixel(Buffer : PVideoBuffer; X : uint32; Y : uint32; Pixel : TRGB32); begin @@ -206,7 +207,7 @@ var DriverMap : PHashMap; { ============================================================ - GPU mode-change callback — reinits front/back buffers + GPU mode-change callback — reinits front/back buffers ============================================================ } procedure videoModeChanged(const info : TGPUModeInfo); begin @@ -221,6 +222,7 @@ var begin debug.tracer.push_trace('driver.video.init.enter'); io.syslog.logln('VIDEO', 'Initializing Base Video Driver.'); + driver.hid.mouse.setBounds(0, 0); //Ensure the frontbuffer is empty & nil, ready for initialization by a driver. VideoInterface.FrontBuffer.Initialized:= false; VideoInterface.FrontBuffer.Width:= 0; @@ -255,23 +257,6 @@ begin debug.tracer.push_trace('driver.video.init.exit'); end; -procedure lateInit(); -begin - driver.video.vesa.init(@driver.video.register); - driver.video.doublebuffer.init(@driver.video.register); - - io.syslog.logln('VIDEO', 'VESA Enable.'); - driver.video.enable('VESA'); - - io.syslog.logln('VIDEO', 'Double Buffer Enable.'); - driver.video.enable('BASIC_DOUBLE_BUFFER'); - - { Initialize LVGL early so the boot.splash screen can use it } - io.syslog.logln('VIDEO', 'LVGL: INIT BEGIN.'); - lvgl_init(driver.video.frontBufferWidth, driver.video.frontBufferHeight); - io.syslog.logln('VIDEO', 'LVGL: INIT END.'); -end; - function register(DriverIdentifier : pchar; EnableCallback : FEnableDriver) : boolean; var Value : Void; @@ -297,6 +282,7 @@ begin Value:= core.ds.hashmap.get(DriverMap, DriverIdentifier); if (Value <> nil) then begin enable:= FEnableDriver(Value)(@VideoInterface); + driver.hid.mouse.setBounds(frontBufferWidth, frontBufferHeight); end; debug.tracer.push_trace('driver.video.enable.exit'); end; @@ -304,7 +290,9 @@ end; procedure DrawPixel(X : uint32; Y : uint32; Pixel : TRGB32); begin //debug.tracer.push_trace('driver.video.DrawPixel.enter'); - VideoInterface.DrawRoutines.DrawPixel(VideoInterface.DefaultBuffer, X, Y, Pixel); + if (X < VideoInterface.DefaultBuffer^.Width) and + (Y < VideoInterface.DefaultBuffer^.Height) then + VideoInterface.DrawRoutines.DrawPixel(VideoInterface.DefaultBuffer, X, Y, Pixel); //debug.tracer.push_trace('driver.video.DrawPixel.exit'); end; @@ -360,18 +348,18 @@ begin backBufferBpp:= VideoInterface.BackBuffer.BitsPerPixel; end; -function backBufferLocation : uint32; +function backBufferLocation : PtrUInt; begin backBufferLocation:= VideoInterface.BackBuffer.Location; end; -function frontBufferLocation : uint32; +function frontBufferLocation : PtrUInt; begin frontBufferLocation:= VideoInterface.FrontBuffer.Location; end; { ============================================================ - Text drawing — 8x16 bitmap font via Std_Font + Text drawing — 8x16 bitmap font via Std_Font ============================================================ } const @@ -445,7 +433,7 @@ begin DrawInt := DrawString(X, Y, @buf[0], Color); end; -procedure reinit(fb_addr, width, height, pitch : uint32; bpp : uint8); +procedure reinit(fb_addr : PtrUInt; width, height, pitch : uint32; bpp : uint8); begin debug.tracer.push_trace('driver.video.reinit.enter'); { Free old back buffer if allocated } @@ -468,8 +456,10 @@ begin { Set front buffer directly from GPU mode info } VideoInterface.FrontBuffer.Location := fb_addr; + VideoInterface.FrontBuffer.Pitch := pitch; VideoInterface.FrontBuffer.Width := width; VideoInterface.FrontBuffer.Height := height; + driver.hid.mouse.setBounds(width, height); VideoInterface.FrontBuffer.BitsPerPixel := bpp; if fb_addr <> 0 then VideoInterface.FrontBuffer.Initialized := true; @@ -488,8 +478,4 @@ begin debug.tracer.push_trace('driver.video.reinit.exit'); end; -initialization - boot.mgr.registerBoot('driver.video', @init, 'Video Driver Initialization', 'driver.video.gpu'); - boot.mgr.registerBoot('driver.video_late', @lateInit, 'Video Driver Late Initialization', 'driver.video.*'); - end. diff --git a/src/driver/video/driver.video.types.pas b/src/driver/video/driver.video.types.pas index eb8c500c..2db1015a 100644 --- a/src/driver/video/driver.video.types.pas +++ b/src/driver/video/driver.video.types.pas @@ -26,7 +26,7 @@ uses type //Arbitrary pointer to a raw driver.video buffer in memory - VideoBuffer = uint32; + VideoBuffer = PtrUInt; //Struct representing a Memory Mapped Video Buffer TVideoBuffer = record @@ -40,6 +40,7 @@ type Width : uint32; //Height of the buffer. Height : uint32; + Pitch : uint32; end; //Pointer to a driver.video buffer PVideoBuffer = ^TVideoBuffer; diff --git a/src/driver/video/driver.video.vesa.pas b/src/driver/video/driver.video.vesa.pas index 5c510a31..3b37ef7d 100644 --- a/src/driver/video/driver.video.vesa.pas +++ b/src/driver/video/driver.video.vesa.pas @@ -83,6 +83,7 @@ begin VideoBuffer^.BitsPerPixel:= BitsPerPixel; VideoBuffer^.Width:= Width; VideoBuffer^.Height:= Height; + VideoBuffer^.Pitch := Pitch; allocateVESAFrameBuffer(VideoBuffer^.Location, VideoBuffer^.Width, VideoBuffer^.Height, BitsPerPixel); if VideoBuffer^.Location <> 0 then VideoBuffer^.Initialized:= True; diff --git a/src/driver/video/driver.video.vesa16.pas b/src/driver/video/driver.video.vesa16.pas index 71c24062..73054557 100644 --- a/src/driver/video/driver.video.vesa16.pas +++ b/src/driver/video/driver.video.vesa16.pas @@ -22,7 +22,7 @@ unit driver.video.vesa16; interface uses - driver.video.types, driver.video.vesa, debug.tracer, core.gfx.color; + driver.video.types, debug.tracer, core.gfx.color; //Init the draw routines by providing what we support through the DrawRoutines struct. procedure init(DrawRoutines : PDrawRoutines); diff --git a/src/driver/video/driver.video.vesa24.pas b/src/driver/video/driver.video.vesa24.pas index fd5c7b1f..a9139cca 100644 --- a/src/driver/video/driver.video.vesa24.pas +++ b/src/driver/video/driver.video.vesa24.pas @@ -22,7 +22,7 @@ unit driver.video.vesa24; interface uses - driver.video.types, driver.video.vesa, debug.tracer, core.gfx.color; + driver.video.types, debug.tracer, core.gfx.color; //Init the draw routines by providing what we support through the DrawRoutines struct. procedure init(DrawRoutines : PDrawRoutines); diff --git a/src/driver/video/driver.video.vesa32.pas b/src/driver/video/driver.video.vesa32.pas index 436c178d..65af12ef 100644 --- a/src/driver/video/driver.video.vesa32.pas +++ b/src/driver/video/driver.video.vesa32.pas @@ -22,7 +22,7 @@ unit driver.video.vesa32; interface uses - driver.video.types, driver.video.vesa, debug.tracer, core.gfx.color; + driver.video.types, debug.tracer, core.gfx.color; //Init the draw routines by providing what we support through the DrawRoutines struct. procedure init(DrawRoutines : PDrawRoutines); @@ -37,7 +37,7 @@ var begin //debug.tracer.push_trace('vesa32.DrawPixel.enter'); Location:= Puint32(Buffer^.Location); - LocationIndex:= (Y * Buffer^.Width) + X; + LocationIndex:= (Y * (Buffer^.Pitch div 4)) + X; Location[LocationIndex]:= uint32(Pixel); //debug.tracer.push_trace('vesa32.DrawPixel.exit'); end; diff --git a/src/driver/video/driver.video.vesa8.pas b/src/driver/video/driver.video.vesa8.pas index 4d930976..cc55741d 100644 --- a/src/driver/video/driver.video.vesa8.pas +++ b/src/driver/video/driver.video.vesa8.pas @@ -22,7 +22,7 @@ unit driver.video.vesa8; interface uses - driver.video.types, driver.video.vesa, debug.tracer, core.gfx.color; + driver.video.types, debug.tracer, core.gfx.color; //Init the draw routines by providing what we support through the DrawRoutines struct. procedure init(DrawRoutines : PDrawRoutines); diff --git a/src/svc/svc.gfxd.pas b/src/svc/svc.gfxd.pas index ca7faa1e..f12f832a 100644 --- a/src/svc/svc.gfxd.pas +++ b/src/svc/svc.gfxd.pas @@ -22,7 +22,6 @@ procedure init; implementation uses - boot.mgr, driver.video.desktop, app.uidebug, driver.video.lvgl, @@ -31,7 +30,7 @@ uses proc.mgr, proc.types, io.syslog, - arch.x86.isr.tmr0; + arch.platform.interrupts; { Render process entry point — runs as a normal scheduled process with interrupts enabled. Continuously drives the full render pipeline so @@ -60,8 +59,8 @@ begin driver.video.desktop.update; app.uidebug.update; lvgl_handler; - lvgl_unlock; driver.video.Flush; + lvgl_unlock; end; if SHOULD_CRASH then begin asm @@ -72,7 +71,7 @@ begin end; end; -procedure tick; +procedure tick(data: void); 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. } @@ -81,12 +80,9 @@ end; procedure init; begin - arch.x86.isr.tmr0.hook(uint32(@tick)); { Register the tick handler to run on every timer interrupt } + arch.platform.interrupts.registerTimer(@tick); { Register the tick handler to run on every timer interrupt } proc.mgr.create('gfxd', @render_loop, nil, 5); io.syslog.logln('gfxd', 'Render process spawned.'); end; -Initialization - boot.mgr.registerBoot('svc.gfxd', @init, 'GFX Daemon', BOOT_MGR_BARRIER_LATE); - end. diff --git a/toolchain/compile_lvgl.sh b/toolchain/compile_lvgl.sh index 01b487fe..51f17a2a 100644 --- a/toolchain/compile_lvgl.sh +++ b/toolchain/compile_lvgl.sh @@ -33,7 +33,7 @@ echo " " if [ -f "${CACHE_DIR}/${LVGL_CACHE_NAME}" ]; then echo "Found cached liblvgl.a in ${CACHE_DIR}, copying to ${OUT_DIR}..." cp "${CACHE_DIR}/${LVGL_CACHE_NAME}" "${OUT_DIR}/liblvgl.a" - echo "(Delete lvgl/liblvgl.a to force a full rebuild.)" + echo "(Delete ${CACHE_DIR}/${LVGL_CACHE_NAME} to force a full rebuild.)" echo " " echo "LVGL compilation complete (cached)." echo " " @@ -122,11 +122,7 @@ fi # Cache liblvgl.a and source to host mount for next build echo "Caching LVGL to host mount..." mkdir -p "$CACHE_DIR" -rm -rf ${CACHE_DIR}/* ${CACHE_DIR}/.[!.]* ${CACHE_DIR}/..?* 2>/dev/null || true cp "${OUT_DIR}/liblvgl.a" "${CACHE_DIR}/${LVGL_CACHE_NAME}" -cp -a "$LVGL_DIR/src" "${CACHE_DIR}/src" -cp -a "$LVGL_DIR"/*.h "${CACHE_DIR}/" 2>/dev/null || true -cp -a "$LVGL_OBJ_DIR" "${CACHE_DIR}/obj" echo "Done." echo " "