hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/drivers/firmware/efi/libstub/gop.c
....@@ -1,276 +1,550 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /* -----------------------------------------------------------------------
23 *
34 * Copyright 2011 Intel Corporation; author Matt Fleming
45 *
5
- * This file is part of the Linux kernel, and is made available under
6
- * the terms of the GNU General Public License version 2.
7
- *
86 * ----------------------------------------------------------------------- */
97
8
+#include <linux/bitops.h>
9
+#include <linux/ctype.h>
1010 #include <linux/efi.h>
1111 #include <linux/screen_info.h>
12
+#include <linux/string.h>
1213 #include <asm/efi.h>
1314 #include <asm/setup.h>
1415
15
-static void find_bits(unsigned long mask, u8 *pos, u8 *size)
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)
1639 {
17
- u8 first, len;
40
+ u32 m;
1841
19
- first = 0;
20
- len = 0;
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;
2150
22
- if (mask) {
23
- while (!(mask & 0x1)) {
24
- mask = mask >> 1;
25
- first++;
26
- }
51
+ *next = option;
52
+ return true;
53
+}
2754
28
- while (mask & 0x1) {
29
- mask = mask >> 1;
30
- len++;
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_status_t status;
137
+
138
+ efi_graphics_output_protocol_mode_t *mode;
139
+ efi_graphics_output_mode_info_t *info;
140
+ unsigned long info_size;
141
+
142
+ u32 max_mode, cur_mode;
143
+ int pf;
144
+
145
+ mode = efi_table_attr(gop, mode);
146
+
147
+ cur_mode = efi_table_attr(mode, mode);
148
+ if (cmdline.mode == cur_mode)
149
+ return cur_mode;
150
+
151
+ max_mode = efi_table_attr(mode, max_mode);
152
+ if (cmdline.mode >= max_mode) {
153
+ efi_err("Requested mode is invalid\n");
154
+ return cur_mode;
155
+ }
156
+
157
+ status = efi_call_proto(gop, query_mode, cmdline.mode,
158
+ &info_size, &info);
159
+ if (status != EFI_SUCCESS) {
160
+ efi_err("Couldn't get mode information\n");
161
+ return cur_mode;
162
+ }
163
+
164
+ pf = info->pixel_format;
165
+
166
+ efi_bs_call(free_pool, info);
167
+
168
+ if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) {
169
+ efi_err("Invalid PixelFormat\n");
170
+ return cur_mode;
171
+ }
172
+
173
+ return cmdline.mode;
174
+}
175
+
176
+static u8 pixel_bpp(int pixel_format, efi_pixel_bitmask_t pixel_info)
177
+{
178
+ if (pixel_format == PIXEL_BIT_MASK) {
179
+ u32 mask = pixel_info.red_mask | pixel_info.green_mask |
180
+ pixel_info.blue_mask | pixel_info.reserved_mask;
181
+ if (!mask)
182
+ return 0;
183
+ return __fls(mask) - __ffs(mask) + 1;
184
+ } else
185
+ return 32;
186
+}
187
+
188
+static u32 choose_mode_res(efi_graphics_output_protocol_t *gop)
189
+{
190
+ efi_status_t status;
191
+
192
+ efi_graphics_output_protocol_mode_t *mode;
193
+ efi_graphics_output_mode_info_t *info;
194
+ unsigned long info_size;
195
+
196
+ u32 max_mode, cur_mode;
197
+ int pf;
198
+ efi_pixel_bitmask_t pi;
199
+ u32 m, w, h;
200
+
201
+ mode = efi_table_attr(gop, mode);
202
+
203
+ cur_mode = efi_table_attr(mode, mode);
204
+ info = efi_table_attr(mode, info);
205
+ pf = info->pixel_format;
206
+ pi = info->pixel_information;
207
+ w = info->horizontal_resolution;
208
+ h = info->vertical_resolution;
209
+
210
+ if (w == cmdline.res.width && h == cmdline.res.height &&
211
+ (cmdline.res.format < 0 || cmdline.res.format == pf) &&
212
+ (!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi)))
213
+ return cur_mode;
214
+
215
+ max_mode = efi_table_attr(mode, max_mode);
216
+
217
+ for (m = 0; m < max_mode; m++) {
218
+ if (m == cur_mode)
219
+ continue;
220
+
221
+ status = efi_call_proto(gop, query_mode, m,
222
+ &info_size, &info);
223
+ if (status != EFI_SUCCESS)
224
+ continue;
225
+
226
+ pf = info->pixel_format;
227
+ pi = info->pixel_information;
228
+ w = info->horizontal_resolution;
229
+ h = info->vertical_resolution;
230
+
231
+ efi_bs_call(free_pool, info);
232
+
233
+ if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
234
+ continue;
235
+ if (w == cmdline.res.width && h == cmdline.res.height &&
236
+ (cmdline.res.format < 0 || cmdline.res.format == pf) &&
237
+ (!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi)))
238
+ return m;
239
+ }
240
+
241
+ efi_err("Couldn't find requested mode\n");
242
+
243
+ return cur_mode;
244
+}
245
+
246
+static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop)
247
+{
248
+ efi_status_t status;
249
+
250
+ efi_graphics_output_protocol_mode_t *mode;
251
+ efi_graphics_output_mode_info_t *info;
252
+ unsigned long info_size;
253
+
254
+ u32 max_mode, cur_mode, best_mode, area;
255
+ u8 depth;
256
+ int pf;
257
+ efi_pixel_bitmask_t pi;
258
+ u32 m, w, h, a;
259
+ u8 d;
260
+
261
+ mode = efi_table_attr(gop, mode);
262
+
263
+ cur_mode = efi_table_attr(mode, mode);
264
+ max_mode = efi_table_attr(mode, max_mode);
265
+
266
+ info = efi_table_attr(mode, info);
267
+
268
+ pf = info->pixel_format;
269
+ pi = info->pixel_information;
270
+ w = info->horizontal_resolution;
271
+ h = info->vertical_resolution;
272
+
273
+ best_mode = cur_mode;
274
+ area = w * h;
275
+ depth = pixel_bpp(pf, pi);
276
+
277
+ for (m = 0; m < max_mode; m++) {
278
+ if (m == cur_mode)
279
+ continue;
280
+
281
+ status = efi_call_proto(gop, query_mode, m,
282
+ &info_size, &info);
283
+ if (status != EFI_SUCCESS)
284
+ continue;
285
+
286
+ pf = info->pixel_format;
287
+ pi = info->pixel_information;
288
+ w = info->horizontal_resolution;
289
+ h = info->vertical_resolution;
290
+
291
+ efi_bs_call(free_pool, info);
292
+
293
+ if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
294
+ continue;
295
+ a = w * h;
296
+ if (a < area)
297
+ continue;
298
+ d = pixel_bpp(pf, pi);
299
+ if (a > area || d > depth) {
300
+ best_mode = m;
301
+ area = a;
302
+ depth = d;
31303 }
32304 }
33305
34
- *pos = first;
35
- *size = len;
306
+ return best_mode;
307
+}
308
+
309
+static u32 choose_mode_list(efi_graphics_output_protocol_t *gop)
310
+{
311
+ efi_status_t status;
312
+
313
+ efi_graphics_output_protocol_mode_t *mode;
314
+ efi_graphics_output_mode_info_t *info;
315
+ unsigned long info_size;
316
+
317
+ u32 max_mode, cur_mode;
318
+ int pf;
319
+ efi_pixel_bitmask_t pi;
320
+ u32 m, w, h;
321
+ u8 d;
322
+ const char *dstr;
323
+ bool valid;
324
+ efi_input_key_t key;
325
+
326
+ mode = efi_table_attr(gop, mode);
327
+
328
+ cur_mode = efi_table_attr(mode, mode);
329
+ max_mode = efi_table_attr(mode, max_mode);
330
+
331
+ efi_printk("Available graphics modes are 0-%u\n", max_mode-1);
332
+ efi_puts(" * = current mode\n"
333
+ " - = unusable mode\n");
334
+ for (m = 0; m < max_mode; m++) {
335
+ status = efi_call_proto(gop, query_mode, m,
336
+ &info_size, &info);
337
+ if (status != EFI_SUCCESS)
338
+ continue;
339
+
340
+ pf = info->pixel_format;
341
+ pi = info->pixel_information;
342
+ w = info->horizontal_resolution;
343
+ h = info->vertical_resolution;
344
+
345
+ efi_bs_call(free_pool, info);
346
+
347
+ valid = !(pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX);
348
+ d = 0;
349
+ switch (pf) {
350
+ case PIXEL_RGB_RESERVED_8BIT_PER_COLOR:
351
+ dstr = "rgb";
352
+ break;
353
+ case PIXEL_BGR_RESERVED_8BIT_PER_COLOR:
354
+ dstr = "bgr";
355
+ break;
356
+ case PIXEL_BIT_MASK:
357
+ dstr = "";
358
+ d = pixel_bpp(pf, pi);
359
+ break;
360
+ case PIXEL_BLT_ONLY:
361
+ dstr = "blt";
362
+ break;
363
+ default:
364
+ dstr = "xxx";
365
+ break;
366
+ }
367
+
368
+ efi_printk("Mode %3u %c%c: Resolution %ux%u-%s%.0hhu\n",
369
+ m,
370
+ m == cur_mode ? '*' : ' ',
371
+ !valid ? '-' : ' ',
372
+ w, h, dstr, d);
373
+ }
374
+
375
+ efi_puts("\nPress any key to continue (or wait 10 seconds)\n");
376
+ status = efi_wait_for_key(10 * EFI_USEC_PER_SEC, &key);
377
+ if (status != EFI_SUCCESS && status != EFI_TIMEOUT) {
378
+ efi_err("Unable to read key, continuing in 10 seconds\n");
379
+ efi_bs_call(stall, 10 * EFI_USEC_PER_SEC);
380
+ }
381
+
382
+ return cur_mode;
383
+}
384
+
385
+static void set_mode(efi_graphics_output_protocol_t *gop)
386
+{
387
+ efi_graphics_output_protocol_mode_t *mode;
388
+ u32 cur_mode, new_mode;
389
+
390
+ switch (cmdline.option) {
391
+ case EFI_CMDLINE_MODE_NUM:
392
+ new_mode = choose_mode_modenum(gop);
393
+ break;
394
+ case EFI_CMDLINE_RES:
395
+ new_mode = choose_mode_res(gop);
396
+ break;
397
+ case EFI_CMDLINE_AUTO:
398
+ new_mode = choose_mode_auto(gop);
399
+ break;
400
+ case EFI_CMDLINE_LIST:
401
+ new_mode = choose_mode_list(gop);
402
+ break;
403
+ default:
404
+ return;
405
+ }
406
+
407
+ mode = efi_table_attr(gop, mode);
408
+ cur_mode = efi_table_attr(mode, mode);
409
+
410
+ if (new_mode == cur_mode)
411
+ return;
412
+
413
+ if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS)
414
+ efi_err("Failed to set requested mode\n");
415
+}
416
+
417
+static void find_bits(u32 mask, u8 *pos, u8 *size)
418
+{
419
+ if (!mask) {
420
+ *pos = *size = 0;
421
+ return;
422
+ }
423
+
424
+ /* UEFI spec guarantees that the set bits are contiguous */
425
+ *pos = __ffs(mask);
426
+ *size = __fls(mask) - *pos + 1;
36427 }
37428
38429 static void
39430 setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
40
- struct efi_pixel_bitmask pixel_info, int pixel_format)
431
+ efi_pixel_bitmask_t pixel_info, int pixel_format)
41432 {
42
- if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
43
- si->lfb_depth = 32;
44
- si->lfb_linelength = pixels_per_scan_line * 4;
45
- si->red_size = 8;
46
- si->red_pos = 0;
47
- si->green_size = 8;
48
- si->green_pos = 8;
49
- si->blue_size = 8;
50
- si->blue_pos = 16;
51
- si->rsvd_size = 8;
52
- si->rsvd_pos = 24;
53
- } else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) {
54
- si->lfb_depth = 32;
55
- si->lfb_linelength = pixels_per_scan_line * 4;
56
- si->red_size = 8;
57
- si->red_pos = 16;
58
- si->green_size = 8;
59
- si->green_pos = 8;
60
- si->blue_size = 8;
61
- si->blue_pos = 0;
62
- si->rsvd_size = 8;
63
- si->rsvd_pos = 24;
64
- } else if (pixel_format == PIXEL_BIT_MASK) {
65
- find_bits(pixel_info.red_mask, &si->red_pos, &si->red_size);
66
- find_bits(pixel_info.green_mask, &si->green_pos,
67
- &si->green_size);
68
- find_bits(pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
69
- find_bits(pixel_info.reserved_mask, &si->rsvd_pos,
70
- &si->rsvd_size);
433
+ if (pixel_format == PIXEL_BIT_MASK) {
434
+ find_bits(pixel_info.red_mask,
435
+ &si->red_pos, &si->red_size);
436
+ find_bits(pixel_info.green_mask,
437
+ &si->green_pos, &si->green_size);
438
+ find_bits(pixel_info.blue_mask,
439
+ &si->blue_pos, &si->blue_size);
440
+ find_bits(pixel_info.reserved_mask,
441
+ &si->rsvd_pos, &si->rsvd_size);
71442 si->lfb_depth = si->red_size + si->green_size +
72443 si->blue_size + si->rsvd_size;
73444 si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
74445 } else {
75
- si->lfb_depth = 4;
76
- si->lfb_linelength = si->lfb_width / 2;
77
- si->red_size = 0;
78
- si->red_pos = 0;
79
- si->green_size = 0;
80
- si->green_pos = 0;
81
- si->blue_size = 0;
82
- si->blue_pos = 0;
83
- si->rsvd_size = 0;
84
- si->rsvd_pos = 0;
446
+ if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
447
+ si->red_pos = 0;
448
+ si->blue_pos = 16;
449
+ } else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ {
450
+ si->blue_pos = 0;
451
+ si->red_pos = 16;
452
+ }
453
+
454
+ si->green_pos = 8;
455
+ si->rsvd_pos = 24;
456
+ si->red_size = si->green_size =
457
+ si->blue_size = si->rsvd_size = 8;
458
+
459
+ si->lfb_depth = 32;
460
+ si->lfb_linelength = pixels_per_scan_line * 4;
85461 }
86462 }
87463
88
-static efi_status_t
89
-setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
90
- efi_guid_t *proto, unsigned long size, void **gop_handle)
464
+static efi_graphics_output_protocol_t *
465
+find_gop(efi_guid_t *proto, unsigned long size, void **handles)
91466 {
92
- struct efi_graphics_output_protocol_32 *gop32, *first_gop;
93
- unsigned long nr_gops;
94
- u16 width, height;
95
- u32 pixels_per_scan_line;
96
- u32 ext_lfb_base;
97
- u64 fb_base;
98
- struct efi_pixel_bitmask pixel_info;
99
- int pixel_format;
100
- efi_status_t status;
101
- u32 *handles = (u32 *)(unsigned long)gop_handle;
467
+ efi_graphics_output_protocol_t *first_gop;
468
+ efi_handle_t h;
102469 int i;
103470
104471 first_gop = NULL;
105
- gop32 = NULL;
106472
107
- nr_gops = size / sizeof(u32);
108
- for (i = 0; i < nr_gops; i++) {
109
- struct efi_graphics_output_protocol_mode_32 *mode;
110
- struct efi_graphics_output_mode_info *info = NULL;
473
+ for_each_efi_handle(h, handles, size, i) {
474
+ efi_status_t status;
475
+
476
+ efi_graphics_output_protocol_t *gop;
477
+ efi_graphics_output_protocol_mode_t *mode;
478
+ efi_graphics_output_mode_info_t *info;
479
+
111480 efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
112
- bool conout_found = false;
113481 void *dummy = NULL;
114
- efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
115
- u64 current_fb_base;
116482
117
- status = efi_call_early(handle_protocol, h,
118
- proto, (void **)&gop32);
483
+ status = efi_bs_call(handle_protocol, h, proto, (void **)&gop);
119484 if (status != EFI_SUCCESS)
120485 continue;
121486
122
- status = efi_call_early(handle_protocol, h,
123
- &conout_proto, &dummy);
487
+ mode = efi_table_attr(gop, mode);
488
+ info = efi_table_attr(mode, info);
489
+ if (info->pixel_format == PIXEL_BLT_ONLY ||
490
+ info->pixel_format >= PIXEL_FORMAT_MAX)
491
+ continue;
492
+
493
+ /*
494
+ * Systems that use the UEFI Console Splitter may
495
+ * provide multiple GOP devices, not all of which are
496
+ * backed by real hardware. The workaround is to search
497
+ * for a GOP implementing the ConOut protocol, and if
498
+ * one isn't found, to just fall back to the first GOP.
499
+ *
500
+ * Once we've found a GOP supporting ConOut,
501
+ * don't bother looking any further.
502
+ */
503
+ status = efi_bs_call(handle_protocol, h, &conout_proto, &dummy);
124504 if (status == EFI_SUCCESS)
125
- conout_found = true;
505
+ return gop;
126506
127
- mode = (void *)(unsigned long)gop32->mode;
128
- info = (void *)(unsigned long)mode->info;
129
- current_fb_base = mode->frame_buffer_base;
130
-
131
- if ((!first_gop || conout_found) &&
132
- info->pixel_format != PIXEL_BLT_ONLY) {
133
- /*
134
- * Systems that use the UEFI Console Splitter may
135
- * provide multiple GOP devices, not all of which are
136
- * backed by real hardware. The workaround is to search
137
- * for a GOP implementing the ConOut protocol, and if
138
- * one isn't found, to just fall back to the first GOP.
139
- */
140
- width = info->horizontal_resolution;
141
- height = info->vertical_resolution;
142
- pixel_format = info->pixel_format;
143
- pixel_info = info->pixel_information;
144
- pixels_per_scan_line = info->pixels_per_scan_line;
145
- fb_base = current_fb_base;
146
-
147
- /*
148
- * Once we've found a GOP supporting ConOut,
149
- * don't bother looking any further.
150
- */
151
- first_gop = gop32;
152
- if (conout_found)
153
- break;
154
- }
507
+ if (!first_gop)
508
+ first_gop = gop;
155509 }
156510
157
- /* Did we find any GOPs? */
158
- if (!first_gop)
159
- return EFI_NOT_FOUND;
160
-
161
- /* EFI framebuffer */
162
- si->orig_video_isVGA = VIDEO_TYPE_EFI;
163
-
164
- si->lfb_width = width;
165
- si->lfb_height = height;
166
- si->lfb_base = fb_base;
167
-
168
- ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
169
- if (ext_lfb_base) {
170
- si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
171
- si->ext_lfb_base = ext_lfb_base;
172
- }
173
-
174
- si->pages = 1;
175
-
176
- setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
177
-
178
- si->lfb_size = si->lfb_linelength * si->lfb_height;
179
-
180
- si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
181
-
182
- return EFI_SUCCESS;
511
+ return first_gop;
183512 }
184513
185
-static efi_status_t
186
-setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
187
- efi_guid_t *proto, unsigned long size, void **gop_handle)
514
+static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
515
+ unsigned long size, void **handles)
188516 {
189
- struct efi_graphics_output_protocol_64 *gop64, *first_gop;
190
- unsigned long nr_gops;
191
- u16 width, height;
192
- u32 pixels_per_scan_line;
193
- u32 ext_lfb_base;
194
- u64 fb_base;
195
- struct efi_pixel_bitmask pixel_info;
196
- int pixel_format;
197
- efi_status_t status;
198
- u64 *handles = (u64 *)(unsigned long)gop_handle;
199
- int i;
517
+ efi_graphics_output_protocol_t *gop;
518
+ efi_graphics_output_protocol_mode_t *mode;
519
+ efi_graphics_output_mode_info_t *info;
200520
201
- first_gop = NULL;
202
- gop64 = NULL;
203
-
204
- nr_gops = size / sizeof(u64);
205
- for (i = 0; i < nr_gops; i++) {
206
- struct efi_graphics_output_protocol_mode_64 *mode;
207
- struct efi_graphics_output_mode_info *info = NULL;
208
- efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
209
- bool conout_found = false;
210
- void *dummy = NULL;
211
- efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
212
- u64 current_fb_base;
213
-
214
- status = efi_call_early(handle_protocol, h,
215
- proto, (void **)&gop64);
216
- if (status != EFI_SUCCESS)
217
- continue;
218
-
219
- status = efi_call_early(handle_protocol, h,
220
- &conout_proto, &dummy);
221
- if (status == EFI_SUCCESS)
222
- conout_found = true;
223
-
224
- mode = (void *)(unsigned long)gop64->mode;
225
- info = (void *)(unsigned long)mode->info;
226
- current_fb_base = mode->frame_buffer_base;
227
-
228
- if ((!first_gop || conout_found) &&
229
- info->pixel_format != PIXEL_BLT_ONLY) {
230
- /*
231
- * Systems that use the UEFI Console Splitter may
232
- * provide multiple GOP devices, not all of which are
233
- * backed by real hardware. The workaround is to search
234
- * for a GOP implementing the ConOut protocol, and if
235
- * one isn't found, to just fall back to the first GOP.
236
- */
237
- width = info->horizontal_resolution;
238
- height = info->vertical_resolution;
239
- pixel_format = info->pixel_format;
240
- pixel_info = info->pixel_information;
241
- pixels_per_scan_line = info->pixels_per_scan_line;
242
- fb_base = current_fb_base;
243
-
244
- /*
245
- * Once we've found a GOP supporting ConOut,
246
- * don't bother looking any further.
247
- */
248
- first_gop = gop64;
249
- if (conout_found)
250
- break;
251
- }
252
- }
521
+ gop = find_gop(proto, size, handles);
253522
254523 /* Did we find any GOPs? */
255
- if (!first_gop)
524
+ if (!gop)
256525 return EFI_NOT_FOUND;
257526
527
+ /* Change mode if requested */
528
+ set_mode(gop);
529
+
258530 /* EFI framebuffer */
531
+ mode = efi_table_attr(gop, mode);
532
+ info = efi_table_attr(mode, info);
533
+
259534 si->orig_video_isVGA = VIDEO_TYPE_EFI;
260535
261
- si->lfb_width = width;
262
- si->lfb_height = height;
263
- si->lfb_base = fb_base;
536
+ si->lfb_width = info->horizontal_resolution;
537
+ si->lfb_height = info->vertical_resolution;
264538
265
- ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
266
- if (ext_lfb_base) {
539
+ efi_set_u64_split(efi_table_attr(mode, frame_buffer_base),
540
+ &si->lfb_base, &si->ext_lfb_base);
541
+ if (si->ext_lfb_base)
267542 si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
268
- si->ext_lfb_base = ext_lfb_base;
269
- }
270543
271544 si->pages = 1;
272545
273
- setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
546
+ setup_pixel_info(si, info->pixels_per_scan_line,
547
+ info->pixel_information, info->pixel_format);
274548
275549 si->lfb_size = si->lfb_linelength * si->lfb_height;
276550
....@@ -282,33 +556,25 @@
282556 /*
283557 * See if we have Graphics Output Protocol
284558 */
285
-efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
286
- struct screen_info *si, efi_guid_t *proto,
559
+efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
287560 unsigned long size)
288561 {
289562 efi_status_t status;
290563 void **gop_handle = NULL;
291564
292
- status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
293
- size, (void **)&gop_handle);
565
+ status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
566
+ (void **)&gop_handle);
294567 if (status != EFI_SUCCESS)
295568 return status;
296569
297
- status = efi_call_early(locate_handle,
298
- EFI_LOCATE_BY_PROTOCOL,
299
- proto, NULL, &size, gop_handle);
570
+ status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, proto, NULL,
571
+ &size, gop_handle);
300572 if (status != EFI_SUCCESS)
301573 goto free_handle;
302574
303
- if (efi_is_64bit()) {
304
- status = setup_gop64(sys_table_arg, si, proto, size,
305
- gop_handle);
306
- } else {
307
- status = setup_gop32(sys_table_arg, si, proto, size,
308
- gop_handle);
309
- }
575
+ status = setup_gop(si, proto, size, gop_handle);
310576
311577 free_handle:
312
- efi_call_early(free_pool, gop_handle);
578
+ efi_bs_call(free_pool, gop_handle);
313579 return status;
314580 }