fix(vkernel): _render 的刷新/背景循环按屏幕高度夹取行界,避免脏行值被写坏时死循环越界写

面包屑定位:卡在 “[rc] vblank done” 与 “[rc] flush done” 之间 —— 即帧缓冲刷新循环。

_dirty_y_max 是 .bss 全局,一旦被写坏成很大的正数:
- 循环退化成死循环 → 卡死(故 [dt] 心跳一行都不打印);
- run_start*pitch 越写越远,写出 0x80000000 帧缓冲之外 → 落进 MMIO →
  宿主 QEMU 被写崩(unknown software exception 0x40000015 = STATUS_FATAL_APP_EXIT),
  且屏幕只留下顶部已写的那一小块。

两个循环(背景铺底 + 帧缓冲刷新)的行界现夹到 [0, h-1]。这不是根因修复
(.bss 仍被写坏),但:
- 止血:不再死循环、不再把宿主 QEMU 写崩;
- 兼作探针:[dt] 心跳里的 dymin/dymax 若明显越界,即可确认 .bss 被写坏的量级。
This commit is contained in:
TermiNexus committed 2026-10-14 14:18:21 +08:00
1 parent cfbb0c1286
commit c9c507c67d
1 file changed
+11 -5
+11 -5
View File
@@ -1306,9 +1306,15 @@ def _render():
t0: uint64 = timer.timer_get_ticks()
row_bytes: int = w * 4
# 行界夹取:_dirty_y_min/_dirty_y_max 若被写坏成异常值,会退化成死循环并越界写
# 到帧缓冲之外的 MMIO(实测把宿主 QEMU 写崩)。这里夹到 [0, h-1]。
_dymin_bg: int = _dirty_y_min
if _dymin_bg < 0: _dymin_bg = 0
_dymax_bg: int = _dirty_y_max
if _dymax_bg > h - 1: _dymax_bg = h - 1
if _bg_row_buf and _dirty_count > 0:
py_bg: int = _dirty_y_min
while py_bg <= _dirty_y_max:
py_bg: int = _dymin_bg
while py_bg <= _dymax_bg:
if _dirty_rows[py_bg]:
string.memcpy(rawptr(uint64(back) + py_bg * row_bytes), _bg_row_buf, row_bytes)
py_bg += 1
@@ -1351,11 +1357,11 @@ def _render():
_wait_vblank()
serial.puts("[rc] vblank done\n")
if _dirty_count > 0:
py_fb: int = _dirty_y_min
while py_fb <= _dirty_y_max:
py_fb: int = _dymin_bg
while py_fb <= _dymax_bg:
if _dirty_rows[py_fb]:
run_start: int = py_fb
while py_fb <= _dirty_y_max and _dirty_rows[py_fb]:
while py_fb <= _dymax_bg and _dirty_rows[py_fb]:
py_fb += 1
run_bytes: int = (py_fb - run_start) * row_bytes
string.memcpy(rawptr(uint64(_fb) + run_start * pitch), rawptr(uint64(back) + run_start * row_bytes), run_bytes)