1 // SPDX-License-Identifier: GPL-2.0 2 /* ----------------------------------------------------------------------- 3 * 4 * Copyright 2011 Intel Corporation; author Matt Fleming 5 * 6 * ----------------------------------------------------------------------- */ 7 8 #include <linux/bitops.h> 9 #include <linux/ctype.h> 10 #include <linux/efi.h> 11 #include <linux/screen_info.h> 12 #include <linux/string.h> 13 #include <asm/efi.h> 14 #include <asm/setup.h> 15 16 #include "efistub.h" 17 18 enum efi_cmdline_option { 19 EFI_CMDLINE_NONE, 20 EFI_CMDLINE_MODE_NUM, 21 EFI_CMDLINE_RES, 22 EFI_CMDLINE_AUTO, 23 EFI_CMDLINE_LIST 24 }; 25 26 static struct { 27 enum efi_cmdline_option option; 28 union { 29 u32 mode; 30 struct { 31 u32 width, height; 32 int format; 33 u8 depth; 34 } res; 35 }; 36 } cmdline = { .option = EFI_CMDLINE_NONE }; 37 38 static bool parse_modenum(char *option, char **next) 39 { 40 u32 m; 41 42 if (!strstarts(option, "mode=")) 43 return false; 44 option += strlen("mode="); 45 m = simple_strtoull(option, &option, 0); 46 if (*option && *option++ != ',') 47 return false; 48 cmdline.option = EFI_CMDLINE_MODE_NUM; 49 cmdline.mode = m; 50 51 *next = option; 52 return true; 53 } 54 55 static bool parse_res(char *option, char **next) 56 { 57 u32 w, h, d = 0; 58 int pf = -1; 59 60 if (!isdigit(*option)) 61 return false; 62 w = simple_strtoull(option, &option, 10); 63 if (*option++ != 'x' || !isdigit(*option)) 64 return false; 65 h = simple_strtoull(option, &option, 10); 66 if (*option == '-') { 67 option++; 68 if (strstarts(option, "rgb")) { 69 option += strlen("rgb"); 70 pf = PIXEL_RGB_RESERVED_8BIT_PER_COLOR; 71 } else if (strstarts(option, "bgr")) { 72 option += strlen("bgr"); 73 pf = PIXEL_BGR_RESERVED_8BIT_PER_COLOR; 74 } else if (isdigit(*option)) 75 d = simple_strtoull(option, &option, 10); 76 else 77 return false; 78 } 79 if (*option && *option++ != ',') 80 return false; 81 cmdline.option = EFI_CMDLINE_RES; 82 cmdline.res.width = w; 83 cmdline.res.height = h; 84 cmdline.res.format = pf; 85 cmdline.res.depth = d; 86 87 *next = option; 88 return true; 89 } 90 91 static bool parse_auto(char *option, char **next) 92 { 93 if (!strstarts(option, "auto")) 94 return false; 95 option += strlen("auto"); 96 if (*option && *option++ != ',') 97 return false; 98 cmdline.option = EFI_CMDLINE_AUTO; 99 100 *next = option; 101 return true; 102 } 103 104 static bool parse_list(char *option, char **next) 105 { 106 if (!strstarts(option, "list")) 107 return false; 108 option += strlen("list"); 109 if (*option && *option++ != ',') 110 return false; 111 cmdline.option = EFI_CMDLINE_LIST; 112 113 *next = option; 114 return true; 115 } 116 117 void efi_parse_option_graphics(char *option) 118 { 119 while (*option) { 120 if (parse_modenum(option, &option)) 121 continue; 122 if (parse_res(option, &option)) 123 continue; 124 if (parse_auto(option, &option)) 125 continue; 126 if (parse_list(option, &option)) 127 continue; 128 129 while (*option && *option++ != ',') 130 ; 131 } 132 } 133 134 static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop) 135 { 136 efi_graphics_output_mode_info_t *info __free(efi_pool) = NULL; 137 efi_graphics_output_protocol_mode_t *mode; 138 unsigned long info_size; 139 u32 max_mode, cur_mode; 140 efi_status_t status; 141 int pf; 142 143 mode = efi_table_attr(gop, mode); 144 145 cur_mode = efi_table_attr(mode, mode); 146 if (cmdline.mode == cur_mode) 147 return cur_mode; 148 149 max_mode = efi_table_attr(mode, max_mode); 150 if (cmdline.mode >= max_mode) { 151 efi_err("Requested mode is invalid\n"); 152 return cur_mode; 153 } 154 155 status = efi_call_proto(gop, query_mode, cmdline.mode, &info_size, &info); 156 if (status != EFI_SUCCESS) { 157 efi_err("Couldn't get mode information\n"); 158 return cur_mode; 159 } 160 161 pf = info->pixel_format; 162 if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) { 163 efi_err("Invalid PixelFormat\n"); 164 return cur_mode; 165 } 166 167 return cmdline.mode; 168 } 169 170 static u32 choose_mode(efi_graphics_output_protocol_t *gop, 171 bool (*match)(const efi_graphics_output_mode_info_t *, u32, void *), 172 void *ctx) 173 { 174 efi_graphics_output_protocol_mode_t *mode = efi_table_attr(gop, mode); 175 u32 max_mode = efi_table_attr(mode, max_mode); 176 177 for (u32 m = 0; m < max_mode; m++) { 178 efi_graphics_output_mode_info_t *info __free(efi_pool) = NULL; 179 unsigned long info_size; 180 efi_status_t status; 181 182 status = efi_call_proto(gop, query_mode, m, &info_size, &info); 183 if (status != EFI_SUCCESS) 184 continue; 185 186 if (match(info, m, ctx)) 187 return m; 188 } 189 return (unsigned long)ctx; 190 } 191 192 static u8 pixel_bpp(int pixel_format, efi_pixel_bitmask_t pixel_info) 193 { 194 if (pixel_format == PIXEL_BIT_MASK) { 195 u32 mask = pixel_info.red_mask | pixel_info.green_mask | 196 pixel_info.blue_mask | pixel_info.reserved_mask; 197 if (!mask) 198 return 0; 199 return __fls(mask) - __ffs(mask) + 1; 200 } else 201 return 32; 202 } 203 204 static bool match_res(const efi_graphics_output_mode_info_t *info, u32 mode, void *ctx) 205 { 206 efi_pixel_bitmask_t pi = info->pixel_information; 207 int pf = info->pixel_format; 208 209 if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) 210 return false; 211 212 return cmdline.res.width == info->horizontal_resolution && 213 cmdline.res.height == info->vertical_resolution && 214 (cmdline.res.format < 0 || cmdline.res.format == pf) && 215 (!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi)); 216 } 217 218 static u32 choose_mode_res(efi_graphics_output_protocol_t *gop) 219 { 220 efi_graphics_output_protocol_mode_t *mode = efi_table_attr(gop, mode); 221 unsigned long cur_mode = efi_table_attr(mode, mode); 222 223 if (match_res(efi_table_attr(mode, info), cur_mode, NULL)) 224 return cur_mode; 225 226 return choose_mode(gop, match_res, (void *)cur_mode); 227 } 228 229 struct match { 230 u32 mode; 231 u32 area; 232 u8 depth; 233 }; 234 235 static bool match_auto(const efi_graphics_output_mode_info_t *info, u32 mode, void *ctx) 236 { 237 u32 area = info->horizontal_resolution * info->vertical_resolution; 238 efi_pixel_bitmask_t pi = info->pixel_information; 239 int pf = info->pixel_format; 240 u8 depth = pixel_bpp(pf, pi); 241 struct match *m = ctx; 242 243 if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) 244 return false; 245 246 if (area > m->area || (area == m->area && depth > m->depth)) 247 *m = (struct match){ mode, area, depth }; 248 249 return false; 250 } 251 252 static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop) 253 { 254 struct match match = {}; 255 256 choose_mode(gop, match_auto, &match); 257 258 return match.mode; 259 } 260 261 static bool match_list(const efi_graphics_output_mode_info_t *info, u32 mode, void *ctx) 262 { 263 efi_pixel_bitmask_t pi = info->pixel_information; 264 u32 cur_mode = (unsigned long)ctx; 265 int pf = info->pixel_format; 266 const char *dstr; 267 u8 depth = 0; 268 bool valid; 269 270 valid = !(pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX); 271 272 switch (pf) { 273 case PIXEL_RGB_RESERVED_8BIT_PER_COLOR: 274 dstr = "rgb"; 275 break; 276 case PIXEL_BGR_RESERVED_8BIT_PER_COLOR: 277 dstr = "bgr"; 278 break; 279 case PIXEL_BIT_MASK: 280 dstr = ""; 281 depth = pixel_bpp(pf, pi); 282 break; 283 case PIXEL_BLT_ONLY: 284 dstr = "blt"; 285 break; 286 default: 287 dstr = "xxx"; 288 break; 289 } 290 291 efi_printk("Mode %3u %c%c: Resolution %ux%u-%s%.0hhu\n", 292 mode, 293 (mode == cur_mode) ? '*' : ' ', 294 !valid ? '-' : ' ', 295 info->horizontal_resolution, 296 info->vertical_resolution, 297 dstr, depth); 298 299 return false; 300 } 301 302 static u32 choose_mode_list(efi_graphics_output_protocol_t *gop) 303 { 304 efi_graphics_output_protocol_mode_t *mode = efi_table_attr(gop, mode); 305 unsigned long cur_mode = efi_table_attr(mode, mode); 306 u32 max_mode = efi_table_attr(mode, max_mode); 307 efi_input_key_t key; 308 efi_status_t status; 309 310 efi_printk("Available graphics modes are 0-%u\n", max_mode-1); 311 efi_puts(" * = current mode\n" 312 " - = unusable mode\n"); 313 314 choose_mode(gop, match_list, (void *)cur_mode); 315 316 efi_puts("\nPress any key to continue (or wait 10 seconds)\n"); 317 status = efi_wait_for_key(10 * EFI_USEC_PER_SEC, &key); 318 if (status != EFI_SUCCESS && status != EFI_TIMEOUT) { 319 efi_err("Unable to read key, continuing in 10 seconds\n"); 320 efi_bs_call(stall, 10 * EFI_USEC_PER_SEC); 321 } 322 323 return cur_mode; 324 } 325 326 static void set_mode(efi_graphics_output_protocol_t *gop) 327 { 328 efi_graphics_output_protocol_mode_t *mode; 329 u32 cur_mode, new_mode; 330 331 switch (cmdline.option) { 332 case EFI_CMDLINE_MODE_NUM: 333 new_mode = choose_mode_modenum(gop); 334 break; 335 case EFI_CMDLINE_RES: 336 new_mode = choose_mode_res(gop); 337 break; 338 case EFI_CMDLINE_AUTO: 339 new_mode = choose_mode_auto(gop); 340 break; 341 case EFI_CMDLINE_LIST: 342 new_mode = choose_mode_list(gop); 343 break; 344 default: 345 return; 346 } 347 348 mode = efi_table_attr(gop, mode); 349 cur_mode = efi_table_attr(mode, mode); 350 351 if (new_mode == cur_mode) 352 return; 353 354 if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS) 355 efi_err("Failed to set requested mode\n"); 356 } 357 358 static void find_bits(u32 mask, u8 *pos, u8 *size) 359 { 360 if (!mask) { 361 *pos = *size = 0; 362 return; 363 } 364 365 /* UEFI spec guarantees that the set bits are contiguous */ 366 *pos = __ffs(mask); 367 *size = __fls(mask) - *pos + 1; 368 } 369 370 static void 371 setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, 372 efi_pixel_bitmask_t pixel_info, int pixel_format) 373 { 374 if (pixel_format == PIXEL_BIT_MASK) { 375 find_bits(pixel_info.red_mask, 376 &si->red_pos, &si->red_size); 377 find_bits(pixel_info.green_mask, 378 &si->green_pos, &si->green_size); 379 find_bits(pixel_info.blue_mask, 380 &si->blue_pos, &si->blue_size); 381 find_bits(pixel_info.reserved_mask, 382 &si->rsvd_pos, &si->rsvd_size); 383 si->lfb_depth = si->red_size + si->green_size + 384 si->blue_size + si->rsvd_size; 385 si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8; 386 } else { 387 if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) { 388 si->red_pos = 0; 389 si->blue_pos = 16; 390 } else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ { 391 si->blue_pos = 0; 392 si->red_pos = 16; 393 } 394 395 si->green_pos = 8; 396 si->rsvd_pos = 24; 397 si->red_size = si->green_size = 398 si->blue_size = si->rsvd_size = 8; 399 400 si->lfb_depth = 32; 401 si->lfb_linelength = pixels_per_scan_line * 4; 402 } 403 } 404 405 static efi_graphics_output_protocol_t *find_gop(unsigned long num, 406 const efi_handle_t handles[]) 407 { 408 efi_graphics_output_protocol_t *first_gop; 409 efi_handle_t h; 410 411 first_gop = NULL; 412 413 for_each_efi_handle(h, handles, num) { 414 efi_status_t status; 415 416 efi_graphics_output_protocol_t *gop; 417 efi_graphics_output_protocol_mode_t *mode; 418 efi_graphics_output_mode_info_t *info; 419 void *dummy = NULL; 420 421 status = efi_bs_call(handle_protocol, h, 422 &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, 423 (void **)&gop); 424 if (status != EFI_SUCCESS) 425 continue; 426 427 mode = efi_table_attr(gop, mode); 428 info = efi_table_attr(mode, info); 429 if (info->pixel_format == PIXEL_BLT_ONLY || 430 info->pixel_format >= PIXEL_FORMAT_MAX) 431 continue; 432 433 /* 434 * Systems that use the UEFI Console Splitter may 435 * provide multiple GOP devices, not all of which are 436 * backed by real hardware. The workaround is to search 437 * for a GOP implementing the ConOut protocol, and if 438 * one isn't found, to just fall back to the first GOP. 439 * 440 * Once we've found a GOP supporting ConOut, 441 * don't bother looking any further. 442 */ 443 status = efi_bs_call(handle_protocol, h, 444 &EFI_CONSOLE_OUT_DEVICE_GUID, &dummy); 445 if (status == EFI_SUCCESS) 446 return gop; 447 448 if (!first_gop) 449 first_gop = gop; 450 } 451 452 return first_gop; 453 } 454 455 efi_status_t efi_setup_gop(struct screen_info *si) 456 { 457 efi_handle_t *handles __free(efi_pool) = NULL; 458 efi_graphics_output_protocol_mode_t *mode; 459 efi_graphics_output_mode_info_t *info; 460 efi_graphics_output_protocol_t *gop; 461 efi_status_t status; 462 unsigned long num; 463 464 status = efi_bs_call(locate_handle_buffer, EFI_LOCATE_BY_PROTOCOL, 465 &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, NULL, &num, 466 &handles); 467 if (status != EFI_SUCCESS) 468 return status; 469 470 gop = find_gop(num, handles); 471 if (!gop) 472 return EFI_NOT_FOUND; 473 474 /* Change mode if requested */ 475 set_mode(gop); 476 477 /* EFI framebuffer */ 478 mode = efi_table_attr(gop, mode); 479 info = efi_table_attr(mode, info); 480 481 si->orig_video_isVGA = VIDEO_TYPE_EFI; 482 483 si->lfb_width = info->horizontal_resolution; 484 si->lfb_height = info->vertical_resolution; 485 486 efi_set_u64_split(efi_table_attr(mode, frame_buffer_base), 487 &si->lfb_base, &si->ext_lfb_base); 488 if (si->ext_lfb_base) 489 si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; 490 491 si->pages = 1; 492 493 setup_pixel_info(si, info->pixels_per_scan_line, 494 info->pixel_information, info->pixel_format); 495 496 si->lfb_size = si->lfb_linelength * si->lfb_height; 497 498 si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; 499 500 return EFI_SUCCESS; 501 } 502