Index: sys/boot/efi/loader/arch/amd64/framebuffer.c =================================================================== --- sys/boot/efi/loader/arch/amd64/framebuffer.c (revision 287317) +++ sys/boot/efi/loader/arch/amd64/framebuffer.c (working copy) @@ -43,6 +43,21 @@ static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID; static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; +static u_int +efifb_color_depth(struct efi_fb *efifb) +{ + uint32_t mask; + u_int depth; + + mask = efifb->fb_mask_red | efifb->fb_mask_green | + efifb->fb_mask_blue | efifb->fb_mask_reserved; + if (mask == 0) + return (0); + for (depth = 1; mask != 1; depth++) + mask >>= 1; + return (depth); +} + static int efifb_mask_from_pixfmt(struct efi_fb *efifb, EFI_GRAPHICS_PIXEL_FORMAT pixfmt, EFI_PIXEL_BITMASK *pixinfo) @@ -95,6 +110,7 @@ static int efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) { + EFI_UGA_PIXEL pix0, pix1; uint8_t *buf; EFI_PCI_IO_PROTOCOL *pciio; EFI_HANDLE handle; @@ -102,7 +118,8 @@ UINTN bufofs, bufsz; uint64_t address, length; uint32_t horiz, vert, depth, refresh; - u_int bar; + uint32_t raw0, raw1; + u_int bar, bpp, fbbar; status = uga->GetMode(uga, &horiz, &vert, &depth, &refresh); if (EFI_ERROR(status)) @@ -138,6 +155,7 @@ /* Attempt to get the frame buffer address (imprecise). */ efifb->fb_addr = 0; efifb->fb_size = 0; + fbbar = -1; for (bar = 0; bar < 6; bar++) { status = pciio->GetBarAttributes(pciio, bar, NULL, (EFI_HANDLE *)&buf); @@ -163,12 +181,34 @@ if (length > efifb->fb_size) { efifb->fb_addr = address; efifb->fb_size = length; + fbbar = bar; } } if (efifb->fb_addr == 0 || efifb->fb_size == 0) return (1); - /* TODO determine the stride. */ - efifb->fb_stride = efifb->fb_width; /* XXX */ + /* + * Determine the stride by changing the frame buffer, starting at + * the offset in the frame buffer that corresponds to the width, + * and checking if the first pixel on the second scan line changed. + */ + uga->Blt(uga, &pix0, EfiUgaVideoToBltBuffer, 0, 1, 0, 0, 1, 1, 0); + bpp = (efifb_color_depth(efifb) + 7) >> 3; + efifb->fb_stride = efifb->fb_width; + while (1) { + address = efifb->fb_stride * bpp; + pciio->Mem.Read(pciio, EfiPciIoWidthUint32, fbbar, address, + 1, &raw0); + raw1 = ~raw0; + pciio->Mem.Write(pciio, EfiPciIoWidthUint32, fbbar, address, + 1, &raw1); + uga->Blt(uga, &pix1, EfiUgaVideoToBltBuffer, 0, 1, 0, 0, + 1, 1, 0); + pciio->Mem.Write(pciio, EfiPciIoWidthUint32, fbbar, address, + 1, &raw0); + if (memcmp(&pix0, &pix1, sizeof(EFI_UGA_PIXEL))) + break; + efifb->fb_stride++; + } return (0); } @@ -193,18 +233,11 @@ static void print_efifb(int mode, struct efi_fb *efifb, int verbose) { - uint32_t mask; u_int depth; if (mode >= 0) printf("mode %d: ", mode); - mask = efifb->fb_mask_red | efifb->fb_mask_green | - efifb->fb_mask_blue | efifb->fb_mask_reserved; - if (mask > 0) { - for (depth = 1; mask != 1; depth++) - mask >>= 1; - } else - depth = 0; + depth = efifb_color_depth(efifb); printf("%ux%ux%u, stride=%u", efifb->fb_width, efifb->fb_height, depth, efifb->fb_stride); if (verbose) {