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