Index: stand/efi/loader/bootinfo.c =================================================================== --- stand/efi/loader/bootinfo.c +++ stand/efi/loader/bootinfo.c @@ -282,7 +282,8 @@ #if defined(__amd64__) || defined(__aarch64__) struct efi_fb efifb; - if (efi_find_framebuffer(&efifb) == 0) { + efi_reset_framebuffer(); + if (efi_find_framebuffer(&efifb, NULL) == 0) { printf("EFI framebuffer information:\n"); printf("addr, size 0x%jx, 0x%jx\n", efifb.fb_addr, efifb.fb_size); Index: stand/efi/loader/framebuffer.h =================================================================== --- stand/efi/loader/framebuffer.h +++ stand/efi/loader/framebuffer.h @@ -31,6 +31,12 @@ #ifndef _EFIFB_H_ #define _EFIFB_H_ -int efi_find_framebuffer(struct efi_fb *efifb); +typedef enum efi_fb_providers { + PROVIDER_GOP = 1, + PROVIDER_UGA, +} efi_fb_providers; + +int efi_reset_framebuffer(); +int efi_find_framebuffer(struct efi_fb *efifb, efi_fb_providers *provider); #endif /* _EFIFB_H_ */ Index: stand/efi/loader/framebuffer.c =================================================================== --- stand/efi/loader/framebuffer.c +++ stand/efi/loader/framebuffer.c @@ -425,20 +425,99 @@ return (0); } +static int +efi_gop_best_mode(EFI_GRAPHICS_OUTPUT *gop) +{ + struct efi_fb efifb; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; + EFI_STATUS status; + UINTN infosz; + UINT32 best_mode, currdim, maxdim, mode; + + best_mode = maxdim = 0; + for (mode = 0; mode < gop->Mode->MaxMode; mode++) { + status = gop->QueryMode(gop, mode, &infosz, &info); + if (EFI_ERROR(status)) + continue; + efifb_from_gop(&efifb, gop->Mode, info); + currdim = info->HorizontalResolution * info->VerticalResolution; + if (currdim > maxdim) { + maxdim = currdim; + best_mode = mode; + } + } + return (best_mode); +} + +static int +efi_reset_gop(void) +{ + EFI_GRAPHICS_OUTPUT *gop; + EFI_STATUS status; + UINT32 best_mode; + + status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); + if (EFI_ERROR(status)) + return (1); + + /* + * We try to set the largest supported mode we can find. Depending on + * how our console is setup, this will either match or be larger than + * the current screen geometry, yielding a successful reset and putting + * us into a consistent state before we exit the loader. + */ + best_mode = efi_gop_best_mode(gop); + + status = gop->SetMode(gop, best_mode); + return (EFI_ERROR(status)); +} + +static int +efi_reset_uga(void) +{ + + return (0); +} + int -efi_find_framebuffer(struct efi_fb *efifb) +efi_reset_framebuffer() +{ + struct efi_fb efifb; + efi_fb_providers provider; + + if (efi_find_framebuffer(&efifb, &provider) != 0) + return (1); + + switch (provider) { + case PROVIDER_GOP: + return (efi_reset_gop()); + case PROVIDER_UGA: + return (efi_reset_uga()); + default: + return (1); + } +} + +int +efi_find_framebuffer(struct efi_fb *efifb, efi_fb_providers *provider) { EFI_GRAPHICS_OUTPUT *gop; EFI_UGA_DRAW_PROTOCOL *uga; EFI_STATUS status; status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); - if (status == EFI_SUCCESS) + if (status == EFI_SUCCESS) { + if (provider != NULL) + *provider = PROVIDER_GOP; return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); + } status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga); - if (status == EFI_SUCCESS) + if (status == EFI_SUCCESS) { + if (provider != NULL) + *provider = PROVIDER_UGA; return (efifb_from_uga(efifb, uga)); + } return (1); }