Skip to content

Commit b52587c

Browse files
committed
efi/libstub: Refactor and clean up GOP resolution picker code
The EFI stub implements various ways of setting the resolution of the EFI framebuffer at boot, and this duplicates a lot of boilerplate for iterating over the supported modes and extracting the resolution and color depth. Refactor this into a single helper that takes a callback, and use it for the 'auto', 'list' and 'res' selection methods. Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 60a3408 commit b52587c

File tree

1 file changed

+103
-162
lines changed
  • drivers/firmware/efi/libstub

1 file changed

+103
-162
lines changed

drivers/firmware/efi/libstub/gop.c

Lines changed: 103 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,11 @@ void efi_parse_option_graphics(char *option)
133133

134134
static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
135135
{
136-
efi_status_t status;
137-
136+
efi_graphics_output_mode_info_t *info __free(efi_pool) = NULL;
138137
efi_graphics_output_protocol_mode_t *mode;
139-
efi_graphics_output_mode_info_t *info;
140138
unsigned long info_size;
141-
142139
u32 max_mode, cur_mode;
140+
efi_status_t status;
143141
int pf;
144142

145143
mode = efi_table_attr(gop, mode);
@@ -154,17 +152,13 @@ static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
154152
return cur_mode;
155153
}
156154

157-
status = efi_call_proto(gop, query_mode, cmdline.mode,
158-
&info_size, &info);
155+
status = efi_call_proto(gop, query_mode, cmdline.mode, &info_size, &info);
159156
if (status != EFI_SUCCESS) {
160157
efi_err("Couldn't get mode information\n");
161158
return cur_mode;
162159
}
163160

164161
pf = info->pixel_format;
165-
166-
efi_bs_call(free_pool, info);
167-
168162
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) {
169163
efi_err("Invalid PixelFormat\n");
170164
return cur_mode;
@@ -173,6 +167,28 @@ static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
173167
return cmdline.mode;
174168
}
175169

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+
176192
static u8 pixel_bpp(int pixel_format, efi_pixel_bitmask_t pixel_info)
177193
{
178194
if (pixel_format == PIXEL_BIT_MASK) {
@@ -185,192 +201,117 @@ static u8 pixel_bpp(int pixel_format, efi_pixel_bitmask_t pixel_info)
185201
return 32;
186202
}
187203

188-
static u32 choose_mode_res(efi_graphics_output_protocol_t *gop)
204+
static bool match_res(const efi_graphics_output_mode_info_t *info, u32 mode, void *ctx)
189205
{
190-
efi_status_t status;
206+
efi_pixel_bitmask_t pi = info->pixel_information;
207+
int pf = info->pixel_format;
191208

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;
209+
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
210+
return false;
200211

201-
mode = efi_table_attr(gop, mode);
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+
}
202217

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;
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);
209222

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)))
223+
if (match_res(efi_table_attr(mode, info), cur_mode, NULL))
213224
return cur_mode;
214225

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;
226+
return choose_mode(gop, match_res, (void *)cur_mode);
227+
}
225228

226-
pf = info->pixel_format;
227-
pi = info->pixel_information;
228-
w = info->horizontal_resolution;
229-
h = info->vertical_resolution;
229+
struct match {
230+
u32 mode;
231+
u32 area;
232+
u8 depth;
233+
};
230234

231-
efi_bs_call(free_pool, info);
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;
232242

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-
}
243+
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
244+
return false;
240245

241-
efi_err("Couldn't find requested mode\n");
246+
if (area > m->area || (area == m->area && depth > m->depth))
247+
*m = (struct match){ mode, area, depth };
242248

243-
return cur_mode;
249+
return false;
244250
}
245251

246252
static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop)
247253
{
248-
efi_status_t status;
254+
struct match match = {};
249255

250-
efi_graphics_output_protocol_mode_t *mode;
251-
efi_graphics_output_mode_info_t *info;
252-
unsigned long info_size;
256+
choose_mode(gop, match_auto, &match);
253257

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;
258+
return match.mode;
259+
}
285260

286-
pf = info->pixel_format;
287-
pi = info->pixel_information;
288-
w = info->horizontal_resolution;
289-
h = info->vertical_resolution;
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;
290269

291-
efi_bs_call(free_pool, info);
270+
valid = !(pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX);
292271

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;
303-
}
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;
304289
}
305290

306-
return best_mode;
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;
307300
}
308301

309302
static u32 choose_mode_list(efi_graphics_output_protocol_t *gop)
310303
{
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;
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);
324307
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);
308+
efi_status_t status;
330309

331310
efi_printk("Available graphics modes are 0-%u\n", max_mode-1);
332311
efi_puts(" * = current mode\n"
333312
" - = 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;
339313

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-
}
314+
choose_mode(gop, match_list, (void *)cur_mode);
374315

375316
efi_puts("\nPress any key to continue (or wait 10 seconds)\n");
376317
status = efi_wait_for_key(10 * EFI_USEC_PER_SEC, &key);

0 commit comments

Comments
 (0)