Skip to content

feat(validation+app): real Secure Boot VFR validation, CJK widget fix, Gate 4 closure, mouse support#43

Merged
MarsDoge merged 10 commits into
mainfrom
feat/real-hii-validation
Jun 15, 2026
Merged

feat(validation+app): real Secure Boot VFR validation, CJK widget fix, Gate 4 closure, mouse support#43
MarsDoge merged 10 commits into
mainfrom
feat/real-hii-validation

Conversation

@MarsDoge

@MarsDoge MarsDoge commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Accumulated batch on feat/real-hii-validation: real-platform VFR validation
(through actually enabling Secure Boot), the CJK widget fix it surfaced, Gate 4
closure, and full mouse support for the front-page App.

Real-VFR validation (and what it proved)

  • MODERN_SETUP_SECURE_BOOT=1 on build-ovmf-x64.sh passes
    -D SECURE_BOOT_ENABLE=TRUE through the overlay's preserved !if blocks, so
    the real SecurityPkg Secure Boot Configuration formset exercises the App
    Devices page and the modern DisplayEngine (not just DriverSampleDxe). Also
    fixes MODERN_SETUP_DEMO_DRIVER_SAMPLE + MODERN_SETUP_REPLACE_UIAPP
    combining (DriverSample re-anchored on QemuKernelLoaderFsDxe).
  • Write-chain evidence (in ProductizationValidationMatrix.md + zh): one-of
    popup select/commit with live suppressif re-evaluation; F10 save dialog;
    native-vs-modern A/B proving the Mode revert is the driver's own RouteConfig
    semantics; NV persistence across cold reboot on DriverSample.
  • Full PK enrollment through the modern engine: Custom mode -> PK Options ->
    Enroll PK -> file explorer -> Commit. Same boot: Secure Boot state flips
    Enabled; cold reboot: enforcement -- the unsigned ESP BOOTX64.EFI is
    rejected (Access Denied -- rejected probably by Secure Boot).

Fixes the validation surfaced

  • LVGL widgets rendered CJK as ? (user-reported "中文" -> "??" in the
    language dropdown on REPLACE_UIAPP lvgl firmware). Fixed at the font level: a
    custom lv_font_t serves the embedded Noto Sans CJK SC A8 subset with the
    stock Latin font as fallback; out-of-subset code points still degrade to ?
    (never an LVGL tofu box).
  • ModernUiReadInput lost pointer reports to double-waiting (the tick pre-wait
    consumed the WaitForInput signal); it now polls GetState non-blocking
    first.

Gate 4 closure

Resolution matrix validated on OVMF X64 (1920x1080 / 1024x768 kept; 800x600
auto-promoted by SelectPreferredGopMode). Method finding recorded: OVMF
QemuVideoDxe adopts the QEMU EDID over the DSC display PCDs, so the matrix is
driven via -device VGA,edid=on,xres=,yres=; a new MODERN_SETUP_VIDEO_RES
switch covers the edid=off case. Gate 4 marked closed in
LvglProductizationPlan.md.

Mouse support (IBV parity item)

  • App consumes the absolute-pointer pipeline end to end: original triangle-arrow
    cursor, and click-to-operate across all interactive surfaces --
    • top tabs (hit-testing shares the painter's scrolled-window math via a new
      ModernSetupGetTabWindow),
    • dashboard quick cards (bounded by the platform-visible count; hidden cards
      unclickable),
    • Exit rows + the open language dropdown (shared MODERN_SETUP_EXIT_ROW_*),
    • and Boot / Devices / Preferences list rows (ModernSetupHitTestPageListRow
      reuses each page's ModernSetupGetPageListLayout + selectable count).
      Clicks reuse the keyboard Enter handling (single-owner activation).
  • List rows are two-stage: first click selects (focus + highlight), a second
    click on the selected row activates -- a stray click never launches a boot
    entry. Tabs/cards/Exit keep single-click navigation.
  • Flicker-free motion via save-under compositing, backed by a new additive
    renderer API pair ModernUiCaptureRect/ModernUiRestoreRect implemented by
    both backends (GOP framebuffer read-back; LVGL shadow-canvas + region
    re-flush). Motion touches a 16x16 rect, never the full frame.
  • Overlays now include upstream UsbMouseAbsolutePointerDxe on OVMF X64 and
    LoongArchVirt (upstream platforms ship no pointer driver). The edk2 driver
    integrates relative HID mice (QEMU -device usb-mouse) into its own 0..1024
    space; usb-tablet absolute reports are not understood by it.

Validation

QEMU end-to-end with screendump evidence at every step (incl. monitor mouse
injection: card/tab/list-row clicks route correctly, dropdown click switches the
live UI language, first-click-selects / second-click-launches on Boot rows, and
multi-hop motion leaves no trails). X64 + AARCH64 app builds -Werror clean; OVMF
modern+lvgl and LoongArch firmware build; smoke (CI gate) PASS throughout.
User-validated on LoongArch QEMU (language dropdown fix, mouse function, flicker
fix, list-row clicks, two-stage activation).

🤖 Generated with Claude Code

MarsDoge and others added 10 commits June 10, 2026 14:12
Add MODERN_SETUP_SECURE_BOOT=1 to Scripts/build-ovmf-x64.sh: passes
-D SECURE_BOOT_ENABLE=TRUE through to the upstream OVMF DSC/FDF !if blocks so
SecurityPkg's real Secure Boot Configuration formset (SecureBootConfigDxe) is
included. This gives the App Devices page and the modern DisplayEngine a
production VFR surface (not just DriverSampleDxe). Display-only validation aid,
off by default, no upstream edits -- the define flows through the overlay's
preserved !if conditions.

Also fix MODERN_SETUP_DEMO_DRIVER_SAMPLE so it combines with
MODERN_SETUP_REPLACE_UIAPP: the DriverSample DSC/FDF insertion now anchors on
QemuKernelLoaderFsDxe (stable; same anchor BootManagerMenuApp uses) instead of
the UiApp component that REPLACE_UIAPP may have already replaced. The smoke OVMF
fixture gains the matching anchor component/INF.

Verified under QEMU (lvgl backend, app front page): Devices page lists the real
formsets (32 entries / 10 HII: Secure Boot, RAM Disk, OVMF Platform
Configuration, Driver Health, File Explorer, DriverSample) with the read-only
preview; Enter opens the real Secure Boot Configuration form through native
FormBrowser -- checkbox, mode dropdown, goto row, context-help rail all render
modern. Evidence captures committed as
Assets/Screenshots/modern-ovmf-x64-devices-real-hii.png and
modern-ovmf-x64-secureboot-form.png. Smoke PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Run the LVGL productization Gate 4 resolution matrix on OVMF X64 (lvgl backend,
app front page) and record the evidence:

- 1920x1080: kept (above floor) -- full 13-tab nav row, 3-column quick cards with
  detail lines, Display row reads 1920 x 1080; no clipping/overlap.
- 1024x768: kept (equals floor) -- tab scroll chevron, compact quick-card reflow
  (height guard drops detail lines), ellipsis truncation on long values.
- 800x600: auto-promoted to 1024x768 by SelectPreferredGopMode (smallest
  qualifying mode); render identical to the native 1024x768 case.

Method finding recorded in both the validation matrix and the build script:
OVMF's QemuVideoDxe adopts the QEMU EDID preferred mode and overwrites the
display PCDs at runtime (PcdVideoResolutionSource==0), so the DSC PCD default is
not the effective lever under modern QEMU -- the matrix is driven with
`-vga none -device VGA,edid=on,xres=<W>,yres=<H>`. Add an optional
MODERN_SETUP_VIDEO_RES=<W>x<H> switch to Scripts/build-ovmf-x64.sh that rewrites
the overlay's display-PCD include inline (overlay-only; upstream untouched) for
the edid=off case.

Evidence tables added to Docs/ProductizationValidationMatrix.md (+ zh mirror)
under Phase32; Gate 4 marked closed in Docs/LvglProductizationPlan.md. Smoke
PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
User-reported: the language dropdown showed "中文" as "??" on the LoongArch
REPLACE_UIAPP firmware. Root cause: the LVGL backend's widget label path
(LvglAsciiLabel) ASCII-folded every non-ASCII code point to '?', so any CJK
value text in the lv_dropdown/checkbox/textarea/ordered-list widgets degraded
to question marks. (The standalone ESP app links the GOP renderer, which is why
the same dropdown rendered correctly there -- the bug only shows when the app
renders through ModernUiLvglRendererLib, e.g. REPLACE_UIAPP lvgl firmware.)

Fix at the font level rather than per-widget special cases:

- Register a custom lv_font_t (LvglCjkFont) whose get_glyph_dsc/get_glyph_bitmap
  callbacks serve the embedded Noto Sans CJK SC 18x18 A8 subset
  (ModernUiFindBuiltinGlyph -- the same bitmaps the primitive text path
  composites), copying rows into the renderer draw buffer with the A8 stride per
  the upstream fmt_txt contract. The stock Latin font (LV_FONT_DEFAULT) is the
  fallback, so ASCII keeps the stock widget look.
- Apply the font in LvglStyleControl (single shared styling point for all five
  widget paths).
- Replace LvglAsciiLabel with LvglWidgetLabel: UTF-8 emission for subset-covered
  CJK; anything outside the subset still degrades to '?' so LVGL never draws a
  placeholder/tofu box (graceful-fallback policy).

Verified under QEMU on the REPLACE_UIAPP lvgl firmware (the exact reported
surface): the Exit-page language dropdown renders 中文 in both the value box and
the open option list. Smoke PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the end-to-end interaction evidence table (EN + zh mirror): one-of popup
select/commit with live IFR conditional re-evaluation on the real Secure Boot
form; F10 save dialog + Y; native-vs-modern A/B proving the Secure Boot Mode
revert is SecureBootConfigDxe's own RouteConfig semantics (persists only
AttemptSecureBoot; CustomMode written only by key-enrollment flows), identical
under both engines; grayed-control fidelity (Attempt checkbox, no PK); and the
full NV persistence proof on DriverSampleDxe -- change one-of, F10/Y, cold reboot
(RESET_VARS=0), value persists and dependent grayoutif/suppressif re-evaluate
correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t evidence

Extend the VFR write-chain table (EN + zh) with the complete Secure Boot
enablement flow driven end-to-end through the modern LVGL engine under QEMU:

Custom mode -> Custom Secure Boot Options -> PK Options -> Enroll PK -> file
explorer (volume -> root -> DER X509 pk.cer from the ESP) -> Commit Changes and
Exit. Same boot: Current Secure Boot State flips Enabled and the Attempt Secure
Boot checkbox un-grays/checks. Cold reboot: Secure Boot actively enforces --
the unsigned ESP BOOTX64.EFI is rejected ("Access Denied -- rejected probably
by Secure Boot" in serial) and BDS falls back to the FV-embedded app.

This exercises the deepest remaining VFR surfaces: nested goto subform
navigation, the dynamic file-explorer formset, action gotos with
RESET_REQUIRED, conditional un-graying on SetupMode transition, and real
security enforcement across reboot. Test PK is an openssl self-signed cert;
QEMU-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r QEMU

Wire the existing (but never consumed) pointer pipeline end to end and validate
it under QEMU:

- App main loop handles ModernUiInputPointer: scales the absolute report into
  framebuffer pixels via the device Mode range, tracks the cursor, throttles
  motion repaints (>=6px), and routes clicks. A successful hit updates the
  selection state and synthesizes an Enter event so the existing keyboard Enter
  handling stays the single owner of activation semantics.
- Hit-test helpers share the painters' layout math (single source of truth):
  ModernSetupHitTestTab reuses a new ModernSetupGetTabWindow extracted from
  ModernSetupDrawTabs (scroll window + chevron inset identical); the dashboard
  card test reuses the quick-grid contract and the platform-visible card count
  (hidden cards are unclickable); the Exit-row/dropdown test shares new
  MODERN_SETUP_EXIT_ROW_* constants with DrawExit.
- Original arrow cursor (two ModernUiFillTriangle primitives) composites last on
  every frame.
- Fix ModernUiReadInput losing pointer reports to double-waiting: poll GetState
  non-blocking first, so the App's tick pre-wait consuming the WaitForInput
  signal no longer swallows the report. Keyboard was unaffected (buffered).
- OVMF X64 overlay now always includes upstream UsbMouseAbsolutePointerDxe
  (upstream OVMF ships no pointer driver). Note: that edk2 driver integrates
  relative HID mice into its own 0..1024 absolute space -- QEMU validation uses
  `-device usb-mouse`; a usb-tablet's absolute reports are not understood by it.

Validated end-to-end under QEMU via monitor mouse injection: cursor renders and
follows; clicking a dashboard card routes to Devices; clicking tabs switches
pages (scrolled-window hit-testing correct); clicking the Exit Language row
opens the dropdown; clicking "English" commits and the live UI switches
language. X64 + AARCH64 app builds -Werror clean; smoke PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the OVMF X64 change: the LoongArchVirtQemu overlay now adds upstream
UsbMouseAbsolutePointerDxe next to UsbKbDxe (the platform ships only the
keyboard driver), so the app's mouse support has EFI_ABSOLUTE_POINTER on
LoongArch too. Anchored replacements no-op gracefully when absent. Smoke PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
User-reported: moving the mouse flickered the screen. Pointer motion previously
set Redraw and repainted the whole frame per event -- through the LVGL backend
that is a full-canvas composite + full-screen Blt each time.

Replace it with classic save-under cursor compositing:

- New additive renderer API pair, implemented by both backends per the
  ModernUiRenderer.h contract: ModernUiCaptureRect (GOP: EfiBltVideoToBltBuffer
  read-back; LVGL: shadow-canvas rows) and ModernUiRestoreRect (GOP:
  BufferToVideo; LVGL: canvas rows + BltCanvasRegion re-flush so later partial
  flushes cannot resurrect the overlay).
- The app cursor becomes a save-under manager (ModernSetupMovePointerCursor /
  ModernSetupInvalidatePointerCursor in Chrome.c): restore the previous 16x16
  rect, capture the new one, draw the arrow; position clamped so the fixed-size
  capture stays on screen. Motion events now touch only that rectangle -- no
  full-frame repaint, no flicker. Full repaints (clicks, page switches)
  invalidate the saved pixels first and re-composite with a fresh capture.

Verified under QEMU (GOP path): multi-hop motion leaves a single cursor with no
trails, including across click-driven full repaints. X64 + AARCH64 builds
-Werror clean; smoke PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
User-reported: on the validation FD the Boot ("启动项") page rows could not be
operated with the mouse. The first mouse pass only hit-tested tabs, dashboard
cards, and the Exit rows -- the list pages were never wired.

Add ModernSetupHitTestPageListRow (Actions.c): it looks up the page's layout
with the exact ModernSetupGetPageListLayout parameters the page draws with
(Boot: MAX_BOOT_ROWS + native tools, no preview; Devices: MAX_DEVICE_ROWS,
preview pane; Preferences: row count), bounds the click to the page's
selectable count, and maps Y to a visible row via the row stride so a click
anywhere on a row line selects it. The App click router sets the page's
selection to the hit row and synthesizes Enter, so activation stays single-owner
(launch boot option / SendForm the HII formset / open the preference popup).

Verified under QEMU: click the Boot tab, click a boot row -> it launches through
the same path as keyboard Enter. X64 + AARCH64 builds -Werror clean; smoke PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per user feedback, a single click launching a Boot entry is too eager. Make the
Boot / Devices / Preferences list rows two-stage: the first click on a row only
selects it (focus to content + highlight); a second click on the already-selected
row activates it (the existing Enter path: launch boot option, SendForm the HII
formset, or open the preference popup). A stray click can no longer launch
anything. Tabs, dashboard cards, and Exit rows keep single-click navigation.

Verified under QEMU: first click on a Boot row highlights it and stays on the
page (no boot); second click on the same row launches it. X64 + AARCH64 builds
-Werror clean; smoke PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@MarsDoge MarsDoge merged commit 893d458 into main Jun 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant