aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@FreeBSD.org>2021-01-16 17:51:23 +0000
committerToomas Soome <tsoome@FreeBSD.org>2021-01-16 23:29:35 +0000
commitef698fabe42827bad43bf046143ef26e47d57514 (patch)
tree3e4c88130938241b1f79b85571136f90d9638ccb
parent944041f936a60b078419dd9c5375792fe5aa6cf1 (diff)
downloadsrc-ef698fabe42827bad43bf046143ef26e47d57514.tar.gz
src-ef698fabe42827bad43bf046143ef26e47d57514.zip
loader.efi: handle multiple gop instances
Some systems may provide multiple GOP instances and not all are bound to hardware. The current loader is picking up the first GOP, which may not be usable. Instead we load the GOP handle array, and test every handle to have registered ConOut protocol. If ConOut is present, we can use this GOP handle to open GOP protocol.
-rw-r--r--stand/efi/loader/framebuffer.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c
index a2bd054e16dc..1650f7da8760 100644
--- a/stand/efi/loader/framebuffer.c
+++ b/stand/efi/loader/framebuffer.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include "bootstrap.h"
#include "framebuffer.h"
+EFI_GUID conout_guid = EFI_CONSOLE_OUT_DEVICE_GUID;
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID;
@@ -466,6 +467,8 @@ efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga)
int
efi_find_framebuffer(teken_gfx_t *gfx_state)
{
+ EFI_HANDLE h, *hlist;
+ UINTN nhandles, i, hsize;
struct efi_fb efifb;
EFI_GRAPHICS_OUTPUT *gop;
EFI_UGA_DRAW_PROTOCOL *uga;
@@ -474,7 +477,39 @@ efi_find_framebuffer(teken_gfx_t *gfx_state)
gfx_state->tg_fb_type = FB_TEXT;
- status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop);
+ hsize = 0;
+ status = BS->LocateHandle(ByProtocol, &gop_guid, NULL, &hsize, hlist);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ hlist = malloc(hsize);
+ if (hlist == NULL)
+ return (ENOMEM);
+ status = BS->LocateHandle(ByProtocol, &gop_guid, NULL, &hsize,
+ hlist);
+ if (EFI_ERROR(status))
+ free(hlist);
+ }
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+
+ nhandles = hsize / sizeof(*hlist);
+
+ /*
+ * Search for ConOut protocol, if not found, use first handle.
+ */
+ h = *hlist;
+ for (i = 0; i < nhandles; i++) {
+ void *dummy = NULL;
+
+ status = OpenProtocolByHandle(hlist[i], &conout_guid, &dummy);
+ if (status == EFI_SUCCESS) {
+ h = hlist[i];
+ break;
+ }
+ }
+
+ status = OpenProtocolByHandle(h, &gop_guid, (void **)&gop);
+ free(hlist);
+
if (status == EFI_SUCCESS) {
gfx_state->tg_fb_type = FB_GOP;
gfx_state->tg_private = gop;