/* * Copyright 2011-2014 Intel Corporation - All Rights Reserved */ #include #include "efi.h" #include extern EFI_GUID GraphicsOutputProtocol; static uint32_t console_default_attribute; static bool console_default_cursor; /* * We want to restore the console state when we boot a kernel or return * to the firmware. */ void efi_console_save(void) { SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut; SIMPLE_TEXT_OUTPUT_MODE *mode = out->Mode; console_default_attribute = mode->Attribute; console_default_cursor = mode->CursorVisible; } void efi_console_restore(void) { SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut; uefi_call_wrapper(out->SetAttribute, 2, out, console_default_attribute); uefi_call_wrapper(out->EnableCursor, 2, out, console_default_cursor); } __export void writechr(char data) { efi_write_char(data, 0); } static inline EFI_STATUS open_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface, EFI_HANDLE agent, EFI_HANDLE controller, UINT32 attributes) { return uefi_call_wrapper(BS->OpenProtocol, 6, handle, protocol, interface, agent, controller, attributes); } static inline EFI_STATUS gop_query_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN *size, EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **info) { return uefi_call_wrapper(gop->QueryMode, 4, gop, gop->Mode->Mode, size, info); } static inline void bit_mask(uint32_t mask, uint8_t *pos, uint8_t *size) { *pos = 0; *size = 0; if (mask) { while (!(mask & 0x1)) { mask >>= 1; (*pos)++; } while (mask & 0x1) { mask >>= 1; (*size)++; } } } static int setup_gop(struct screen_info *si) { EFI_HANDLE *handles = NULL; EFI_STATUS status; EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, *found; EFI_GRAPHICS_PIXEL_FORMAT pixel_fmt; EFI_PIXEL_BITMASK pixel_info; uint32_t pixel_scanline; UINTN i, nr_handles; UINTN size; uint16_t lfb_width, lfb_height; uint32_t lfb_base, lfb_size; int err = 0; void **gop_handle = NULL; size = 0; status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &GraphicsOutputProtocol, NULL, &size, gop_handle); /* LibLocateHandle handle already returns the number of handles. * There is no need to divide by sizeof(EFI_HANDLE) */ status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol, NULL, &nr_handles, &handles); if (status == EFI_BUFFER_TOO_SMALL) { handles = AllocatePool(nr_handles); if (!handles) return 0; status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol, NULL, &nr_handles, &handles); } if (status != EFI_SUCCESS) goto out; found = NULL; for (i = 0; i < nr_handles; i++) { EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; EFI_PCI_IO *pciio = NULL; EFI_HANDLE *h = handles[i]; status = uefi_call_wrapper(BS->HandleProtocol, 3, h, &GraphicsOutputProtocol, (void **)&gop); if (status != EFI_SUCCESS) continue; uefi_call_wrapper(BS->HandleProtocol, 3, h, &PciIoProtocol, (void **)&pciio); status = gop_query_mode(gop, &size, &info); if (status == EFI_SUCCESS && (!found || pciio)) { lfb_width = info->HorizontalResolution; lfb_height = info->VerticalResolution; lfb_base = gop->Mode->FrameBufferBase; lfb_size = gop->Mode->FrameBufferSize; pixel_fmt = info->PixelFormat; pixel_info = info->PixelInformation; pixel_scanline = info->PixelsPerScanLine; if (pciio) break; found = gop; } } if (!found) goto out; err = 1; dprintf("setup_screen: set up screen parameters for EFI GOP\n"); si->orig_video_isVGA = 0x70; /* EFI framebuffer */ si->lfb_base = lfb_base; si->lfb_size = lfb_size; si->lfb_width = lfb_width; si->lfb_height = lfb_height; si->pages = 1; dprintf("setup_screen: lfb_base 0x%x lfb_size %d lfb_width %d lfb_height %d\n", lfb_base, lfb_size, lfb_width, lfb_height); switch (pixel_fmt) { case PixelRedGreenBlueReserved8BitPerColor: si->lfb_depth = 32; si->lfb_linelength = pixel_scanline * 4; si->red_size = 8; si->red_pos = 0; si->green_size = 8; si->green_pos = 8; si->blue_size = 8; si->blue_pos = 16; si->rsvd_size = 8; si->rsvd_pos = 24; break; case PixelBlueGreenRedReserved8BitPerColor: si->lfb_depth = 32; si->lfb_linelength = pixel_scanline * 4; si->red_size = 8; si->red_pos = 16; si->green_size = 8; si->green_pos = 8; si->blue_size = 8; si->blue_pos = 0; si->rsvd_size = 8; si->rsvd_pos = 24; break; case PixelBitMask: bit_mask(pixel_info.RedMask, &si->red_pos, &si->red_size); bit_mask(pixel_info.GreenMask, &si->green_pos, &si->green_size); bit_mask(pixel_info.BlueMask, &si->blue_pos, &si->blue_size); bit_mask(pixel_info.ReservedMask, &si->rsvd_pos, &si->rsvd_size); si->lfb_depth = si->red_size + si->green_size + si->blue_size + si->rsvd_size; si->lfb_linelength = (pixel_scanline * si->lfb_depth) / 8; break; default: si->lfb_depth = 4;; si->lfb_linelength = si->lfb_width / 2; si->red_size = 0; si->red_pos = 0; si->green_size = 0; si->green_pos = 0; si->blue_size = 0; si->blue_pos = 0; si->rsvd_size = 0; si->rsvd_pos = 0; break; } dprintf("setup_screen: depth %d line %d rpos %d rsize %d gpos %d gsize %d bpos %d bsize %d rsvpos %d rsvsize %d\n", si->lfb_depth, si->lfb_linelength, si->red_pos, si->red_size, si->green_pos, si->green_size, si->blue_pos, si->blue_size, si->blue_pos, si->blue_size, si->rsvd_pos, si->rsvd_size); out: if (handles) FreePool(handles); return err; } #define EFI_UGA_PROTOCOL_GUID \ { \ 0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 } \ } typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; typedef EFI_STATUS (EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) ( IN EFI_UGA_DRAW_PROTOCOL *This, OUT UINT32 *Width, OUT UINT32 *Height, OUT UINT32 *Depth, OUT UINT32 *Refresh ) ; struct _EFI_UGA_DRAW_PROTOCOL { EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode; void *SetMode; void *Blt; }; static int setup_uga(struct screen_info *si) { EFI_UGA_DRAW_PROTOCOL *uga, *first; EFI_GUID UgaProtocol = EFI_UGA_PROTOCOL_GUID; UINT32 width, height; EFI_STATUS status; EFI_HANDLE *handles; UINTN i, nr_handles; int rv = 0; status = LibLocateHandle(ByProtocol, &UgaProtocol, NULL, &nr_handles, &handles); if (status != EFI_SUCCESS) return rv; for (i = 0; i < nr_handles; i++) { EFI_PCI_IO *pciio = NULL; EFI_HANDLE *handle = handles[i]; UINT32 w, h, depth, refresh; status = uefi_call_wrapper(BS->HandleProtocol, 3, handle, &UgaProtocol, (void **)&uga); if (status != EFI_SUCCESS) continue; uefi_call_wrapper(BS->HandleProtocol, 3, handle, &PciIoProtocol, (void **)&pciio); status = uefi_call_wrapper(uga->GetMode, 5, uga, &w, &h, &depth, &refresh); if (status == EFI_SUCCESS && (!first || pciio)) { width = w; height = h; if (pciio) break; first = uga; } } if (!first) goto out; rv = 1; si->orig_video_isVGA = 0x70; /* EFI framebuffer */ si->lfb_depth = 32; si->lfb_width = width; si->lfb_height = height; si->red_size = 8; si->red_pos = 16; si->green_size = 8; si->green_pos = 8; si->blue_size = 8; si->blue_pos = 0; si->rsvd_size = 8; si->rsvd_pos = 24; out: FreePool(handles); return rv; } void setup_screen(struct screen_info *si) { memset(si, 0, sizeof(*si)); if (!setup_gop(si)) setup_uga(si); }