Home | History | Annotate | Download | only in efi
      1 /*
      2  * Copyright 2011-2014 Intel Corporation - All Rights Reserved
      3  */
      4 
      5 #include <syslinux/linux.h>
      6 #include "efi.h"
      7 #include <string.h>
      8 
      9 extern EFI_GUID GraphicsOutputProtocol;
     10 
     11 static uint32_t console_default_attribute;
     12 static bool console_default_cursor;
     13 
     14 /*
     15  * We want to restore the console state when we boot a kernel or return
     16  * to the firmware.
     17  */
     18 void efi_console_save(void)
     19 {
     20     SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
     21     SIMPLE_TEXT_OUTPUT_MODE *mode = out->Mode;
     22 
     23     console_default_attribute = mode->Attribute;
     24     console_default_cursor = mode->CursorVisible;
     25 }
     26 
     27 void efi_console_restore(void)
     28 {
     29     SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
     30 
     31     uefi_call_wrapper(out->SetAttribute, 2, out, console_default_attribute);
     32     uefi_call_wrapper(out->EnableCursor, 2, out, console_default_cursor);
     33 }
     34 
     35 __export void writechr(char data)
     36 {
     37 	efi_write_char(data, 0);
     38 }
     39 
     40 static inline EFI_STATUS open_protocol(EFI_HANDLE handle, EFI_GUID *protocol,
     41 				       void **interface, EFI_HANDLE agent,
     42 				       EFI_HANDLE controller, UINT32 attributes)
     43 {
     44 	return uefi_call_wrapper(BS->OpenProtocol, 6, handle, protocol,
     45 				 interface, agent, controller, attributes);
     46 }
     47 
     48 static inline EFI_STATUS
     49 gop_query_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN *size,
     50 	       EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **info)
     51 {
     52 	return uefi_call_wrapper(gop->QueryMode, 4, gop,
     53 				 gop->Mode->Mode, size, info);
     54 }
     55 
     56 static inline void bit_mask(uint32_t mask, uint8_t *pos, uint8_t *size)
     57 {
     58 	*pos = 0;
     59 	*size = 0;
     60 
     61 	if (mask) {
     62 		while (!(mask & 0x1)) {
     63 			mask >>= 1;
     64 			(*pos)++;
     65 		}
     66 
     67 		while (mask & 0x1) {
     68 			mask >>= 1;
     69 			(*size)++;
     70 		}
     71 	}
     72 }
     73 
     74 static int setup_gop(struct screen_info *si)
     75 {
     76 	EFI_HANDLE *handles = NULL;
     77 	EFI_STATUS status;
     78 	EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, *found;
     79 	EFI_GRAPHICS_PIXEL_FORMAT pixel_fmt;
     80 	EFI_PIXEL_BITMASK pixel_info;
     81 	uint32_t pixel_scanline;
     82 	UINTN i, nr_handles;
     83 	UINTN size;
     84 	uint16_t lfb_width, lfb_height;
     85 	uint32_t lfb_base, lfb_size;
     86 	int err = 0;
     87 	void **gop_handle = NULL;
     88 
     89 	size = 0;
     90 	status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &GraphicsOutputProtocol,
     91 				NULL, &size, gop_handle);
     92 	/* LibLocateHandle handle already returns the number of handles.
     93 	 * There is no need to divide by sizeof(EFI_HANDLE)
     94 	 */
     95 	status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
     96 				 NULL, &nr_handles, &handles);
     97 	if (status == EFI_BUFFER_TOO_SMALL) {
     98 
     99 		handles = AllocatePool(nr_handles);
    100 		if (!handles)
    101 			return 0;
    102 
    103 		status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
    104 					 NULL, &nr_handles, &handles);
    105 	}
    106 	if (status != EFI_SUCCESS)
    107 		goto out;
    108 
    109 	found = NULL;
    110 	for (i = 0; i < nr_handles; i++) {
    111 		EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
    112 		EFI_PCI_IO *pciio = NULL;
    113 		EFI_HANDLE *h = handles[i];
    114 
    115 		status = uefi_call_wrapper(BS->HandleProtocol, 3, h,
    116 					   &GraphicsOutputProtocol, (void **)&gop);
    117 		if (status != EFI_SUCCESS)
    118 			continue;
    119 		uefi_call_wrapper(BS->HandleProtocol, 3, h,
    120 				  &PciIoProtocol, (void **)&pciio);
    121 		status = gop_query_mode(gop, &size, &info);
    122 		if (status == EFI_SUCCESS && (!found || pciio)) {
    123 			lfb_width = info->HorizontalResolution;
    124 			lfb_height = info->VerticalResolution;
    125 			lfb_base = gop->Mode->FrameBufferBase;
    126 			lfb_size = gop->Mode->FrameBufferSize;
    127 			pixel_fmt = info->PixelFormat;
    128 			pixel_info = info->PixelInformation;
    129 			pixel_scanline = info->PixelsPerScanLine;
    130 			if (pciio)
    131 				break;
    132 			found = gop;
    133 		}
    134 	}
    135 
    136 	if (!found)
    137 		goto out;
    138 
    139 	err = 1;
    140 
    141 	dprintf("setup_screen: set up screen parameters for EFI GOP\n");
    142 	si->orig_video_isVGA = 0x70; /* EFI framebuffer */
    143 
    144 	si->lfb_base = lfb_base;
    145 	si->lfb_size = lfb_size;
    146 	si->lfb_width = lfb_width;
    147 	si->lfb_height = lfb_height;
    148 	si->pages = 1;
    149 
    150 	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);
    151 	switch (pixel_fmt) {
    152 	case PixelRedGreenBlueReserved8BitPerColor:
    153 		si->lfb_depth = 32;
    154 		si->lfb_linelength = pixel_scanline * 4;
    155 		si->red_size = 8;
    156 		si->red_pos = 0;
    157 		si->green_size = 8;
    158 		si->green_pos = 8;
    159 		si->blue_size = 8;
    160 		si->blue_pos = 16;
    161 		si->rsvd_size = 8;
    162 		si->rsvd_pos = 24;
    163 		break;
    164 	case PixelBlueGreenRedReserved8BitPerColor:
    165 		si->lfb_depth = 32;
    166 		si->lfb_linelength = pixel_scanline * 4;
    167 		si->red_size = 8;
    168 		si->red_pos = 16;
    169 		si->green_size = 8;
    170 		si->green_pos = 8;
    171 		si->blue_size = 8;
    172 		si->blue_pos = 0;
    173 		si->rsvd_size = 8;
    174 		si->rsvd_pos = 24;
    175 		break;
    176 	case PixelBitMask:
    177 		bit_mask(pixel_info.RedMask, &si->red_pos,
    178 			 &si->red_size);
    179 		bit_mask(pixel_info.GreenMask, &si->green_pos,
    180 			 &si->green_size);
    181 		bit_mask(pixel_info.BlueMask, &si->blue_pos,
    182 			 &si->blue_size);
    183 		bit_mask(pixel_info.ReservedMask, &si->rsvd_pos,
    184 			 &si->rsvd_size);
    185 		si->lfb_depth = si->red_size + si->green_size +
    186 			si->blue_size + si->rsvd_size;
    187 		si->lfb_linelength = (pixel_scanline * si->lfb_depth) / 8;
    188 		break;
    189 	default:
    190 		si->lfb_depth = 4;;
    191 		si->lfb_linelength = si->lfb_width / 2;
    192 		si->red_size = 0;
    193 		si->red_pos = 0;
    194 		si->green_size = 0;
    195 		si->green_pos = 0;
    196 		si->blue_size = 0;
    197 		si->blue_pos = 0;
    198 		si->rsvd_size = 0;
    199 		si->rsvd_pos = 0;
    200 		break;
    201 	}
    202 	dprintf("setup_screen: depth %d line %d rpos %d rsize %d gpos %d gsize %d bpos %d bsize %d rsvpos %d rsvsize %d\n",
    203 		si->lfb_depth, si->lfb_linelength,
    204 		si->red_pos, si->red_size,
    205 		si->green_pos, si->green_size,
    206 		si->blue_pos, si->blue_size,
    207 		si->blue_pos, si->blue_size,
    208 		si->rsvd_pos, si->rsvd_size);
    209 
    210 out:
    211 	if (handles) FreePool(handles);
    212 
    213 	return err;
    214 }
    215 
    216 #define EFI_UGA_PROTOCOL_GUID \
    217   { \
    218     0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 } \
    219   }
    220 
    221 typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL;
    222 
    223 typedef
    224 EFI_STATUS
    225 (EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) (
    226   IN  EFI_UGA_DRAW_PROTOCOL *This,
    227   OUT UINT32 *Width,
    228   OUT UINT32 *Height,
    229   OUT UINT32 *Depth,
    230   OUT UINT32 *Refresh
    231   )
    232 ;
    233 
    234 struct _EFI_UGA_DRAW_PROTOCOL {
    235 	EFI_UGA_DRAW_PROTOCOL_GET_MODE	GetMode;
    236 	void	*SetMode;
    237 	void	*Blt;
    238 };
    239 
    240 static int setup_uga(struct screen_info *si)
    241 {
    242 	EFI_UGA_DRAW_PROTOCOL *uga, *first;
    243 	EFI_GUID UgaProtocol = EFI_UGA_PROTOCOL_GUID;
    244 	UINT32 width, height;
    245 	EFI_STATUS status;
    246 	EFI_HANDLE *handles;
    247 	UINTN i, nr_handles;
    248 	int rv = 0;
    249 
    250 	status = LibLocateHandle(ByProtocol, &UgaProtocol,
    251 				 NULL, &nr_handles, &handles);
    252 	if (status != EFI_SUCCESS)
    253 		return rv;
    254 
    255 	for (i = 0; i < nr_handles; i++) {
    256 		EFI_PCI_IO *pciio = NULL;
    257 		EFI_HANDLE *handle = handles[i];
    258 		UINT32 w, h, depth, refresh;
    259 
    260 		status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
    261 					   &UgaProtocol, (void **)&uga);
    262 		if (status != EFI_SUCCESS)
    263 			continue;
    264 
    265 		uefi_call_wrapper(BS->HandleProtocol, 3, handle,
    266 				  &PciIoProtocol, (void **)&pciio);
    267 
    268 		status = uefi_call_wrapper(uga->GetMode, 5, uga, &w, &h,
    269 					   &depth, &refresh);
    270 
    271 		if (status == EFI_SUCCESS && (!first || pciio)) {
    272 			width = w;
    273 			height = h;
    274 
    275 			if (pciio)
    276 				break;
    277 
    278 			first = uga;
    279 		}
    280 	}
    281 
    282 	if (!first)
    283 		goto out;
    284 	rv = 1;
    285 
    286 	si->orig_video_isVGA = 0x70; /* EFI framebuffer */
    287 
    288 	si->lfb_depth = 32;
    289 	si->lfb_width = width;
    290 	si->lfb_height = height;
    291 
    292 	si->red_size = 8;
    293 	si->red_pos = 16;
    294 	si->green_size = 8;
    295 	si->green_pos = 8;
    296 	si->blue_size = 8;
    297 	si->blue_pos = 0;
    298 	si->rsvd_size = 8;
    299 	si->rsvd_pos = 24;
    300 
    301 out:
    302 	FreePool(handles);
    303 	return rv;
    304 }
    305 
    306 void setup_screen(struct screen_info *si)
    307 {
    308 	memset(si, 0, sizeof(*si));
    309 
    310 	if (!setup_gop(si))
    311 		setup_uga(si);
    312 }
    313