display: a 64-bit framebuffer address, no mirroring onto itself
Three fixes for real machines that broke at any resolution but 800x600: - kmain() took the loader's framebuffer address as uint32, and vga_fb_init() re-published the scanout from that and the 16-bit VBE block. An aperture above 4 GB moved the console onto the wrong memory right after the vga: line. Both now use the loader's 64-bit display block, mapped with ioremap(). - The loader mirrored onto the console splitter's GOP, which forwards to the primary itself, and onto GOPs that share the primary's aperture. After a mode change that rewrote the screen over itself with another mode's stride. Handles without a device path and overlapping apertures are skipped, and a mode change re-matches the remaining mirrors. - A mode whose reported size, stride or aperture does not add up after SetMode is refused, and the loader returns to the previous one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
c9790df04c
commit
fe32833ade
5 changed files with 193 additions and 16 deletions
|
|
@ -69,15 +69,29 @@ vga_fb_init(uint64 phys_addr)
|
|||
{
|
||||
struct fb_info info;
|
||||
|
||||
if (phys_addr == 0)
|
||||
phys_addr = *(uint32*)(P2V(SCHBOOT_VBE_LFB));
|
||||
|
||||
fb = (volatile uchar*)P2V(phys_addr);
|
||||
fb_phys = phys_addr;
|
||||
fb_stride = *(ushort*)(P2V(SCHBOOT_VBE_STRIDE));
|
||||
fb_width = *(ushort*)(P2V(SCHBOOT_VBE_WIDTH));
|
||||
fb_height = *(ushort*)(P2V(SCHBOOT_VBE_HEIGHT));
|
||||
fb_bpp = *(uchar*)(P2V(SCHBOOT_VBE_BPP));
|
||||
// The UEFI loader's display block first, and the VBE block only without it.
|
||||
//
|
||||
// This read the VBE block alone, which is a BIOS structure: a 32-bit
|
||||
// address and 16-bit sizes. kmain() reads the loader's block and puts the
|
||||
// console on the right framebuffer; this then re-published the scanout from
|
||||
// the other one, so the two disagreed on any machine the VBE block cannot
|
||||
// describe, and the second one won.
|
||||
uint64 blk = *(uint64*)P2V(SCHBOOT_FB_BASE);
|
||||
if (blk) {
|
||||
phys_addr = blk;
|
||||
fb_stride = *(uint32*)P2V(SCHBOOT_FB_STRIDE);
|
||||
fb_width = *(uint32*)P2V(SCHBOOT_FB_WIDTH);
|
||||
fb_height = *(uint32*)P2V(SCHBOOT_FB_HEIGHT);
|
||||
fb_bpp = 32;
|
||||
} else {
|
||||
if (phys_addr == 0)
|
||||
phys_addr = *(uint32*)(P2V(SCHBOOT_VBE_LFB));
|
||||
fb_stride = *(ushort*)(P2V(SCHBOOT_VBE_STRIDE));
|
||||
fb_width = *(ushort*)(P2V(SCHBOOT_VBE_WIDTH));
|
||||
fb_height = *(ushort*)(P2V(SCHBOOT_VBE_HEIGHT));
|
||||
fb_bpp = *(uchar*)(P2V(SCHBOOT_VBE_BPP));
|
||||
}
|
||||
fb_phys = phys_addr;
|
||||
|
||||
if (fb_width == 0) fb_width = 800;
|
||||
if (fb_height == 0) fb_height = 600;
|
||||
|
|
@ -100,8 +114,16 @@ vga_fb_init(uint64 phys_addr)
|
|||
return;
|
||||
}
|
||||
|
||||
kinfo("vga: %dx%d, %d bpp, stride %d, LFB: 0x%x\n",
|
||||
fb_width, fb_height, fb_bpp, fb_stride, (uint32)phys_addr);
|
||||
// ioremap() rather than P2V(): the same address below 4 GB, and the window
|
||||
// kmain() already opened for an aperture above it.
|
||||
fb = (volatile uchar*)ioremap(phys_addr, (uint64)fb_stride * fb_height);
|
||||
if (fb == 0) {
|
||||
cprintf("vga: cannot map the framebuffer at %p\n", (void *)phys_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
kinfo("vga: %dx%d, %d bpp, stride %d, LFB: %p\n",
|
||||
fb_width, fb_height, fb_bpp, fb_stride, (void *)phys_addr);
|
||||
|
||||
info.ptr = fb;
|
||||
info.phys = fb_phys;
|
||||
|
|
|
|||
Loading…
Reference in a new issue