efi loader: Respect efi_max_resolution in loader.conf(5)

Default the max resolution to 1080p, we'll accept Width x Height
specifications along with the following presets:

- 480p
- 720p
- 1080p
- 2160p or 4k
- 5k

PR:		224825
Differential Revision:	https://reviews.freebsd.org/D14801
This commit is contained in:
kevans 2018-03-23 21:02:46 +00:00
parent 733307e991
commit c3f6753615
2 changed files with 97 additions and 2 deletions

View File

@ -75,6 +75,9 @@ acpi_video_load="NO" # Load the ACPI video extension driver
#geom_eli_passphrase_prompt="NO" # Prompt for geli(8) passphrase to mount root
bootenv_autolist="YES" # Auto populate the list of ZFS Boot Environments
#beastie_disable="NO" # Turn the beastie boot menu on and off
efi_max_resolution="1080p" # Set the max resolution for EFI loader to use:
# 480p, 720p, 1080p, 2160p/4k, 5k, or specify
# WidthxHeight (e.g. 1920x1080)
#kernels="kernel kernel.old" # Kernels to display in the boot menu
#loader_logo="orbbw" # Desired logo: orbbw, orb, fbsdbw, beastiebw, beastie, none
#comconsole_speed="9600" # Set the current serial console speed

View File

@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#include <bootstrap.h>
#include <sys/endian.h>
#include <sys/param.h>
#include <stand.h>
#include <efi.h>
@ -45,6 +46,40 @@ static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID;
static struct named_resolution {
const char *name;
const char *alias;
unsigned int width;
unsigned int height;
} resolutions[] = {
{
.name = "480p",
.width = 640,
.height = 480,
},
{
.name = "720p",
.width = 1280,
.height = 720,
},
{
.name = "1080p",
.width = 1920,
.height = 1080,
},
{
.name = "2160p",
.alias = "4k",
.width = 3840,
.height = 2160,
},
{
.name = "5k",
.width = 5120,
.height = 2880,
}
};
static u_int
efifb_color_depth(struct efi_fb *efifb)
{
@ -462,6 +497,57 @@ print_efifb(int mode, struct efi_fb *efifb, int verbose)
}
}
static bool
efi_resolution_compare(struct named_resolution *res, const char *cmp)
{
if (strcasecmp(res->name, cmp) == 0)
return (true);
if (res->alias != NULL && strcasecmp(res->alias, cmp) == 0)
return (true);
return (false);
}
static void
efi_get_max_resolution(int *width, int *height)
{
struct named_resolution *res;
char *maxres;
char *height_start, *width_start;
int idx;
*width = *height = 0;
maxres = getenv("efi_max_resolution");
/* No max_resolution set? Bail out; choose highest resolution */
if (maxres == NULL)
return;
/* See if it matches one of our known resolutions */
for (idx = 0; idx < nitems(resolutions); ++idx) {
res = &resolutions[idx];
if (efi_resolution_compare(res, maxres)) {
*width = res->width;
*height = res->height;
return;
}
}
/* Not a known resolution, try to parse it; make a copy we can modify */
maxres = strdup(maxres);
if (maxres == NULL)
return;
height_start = strchr(maxres, 'x');
if (height_start == NULL) {
free(maxres);
return;
}
width_start = maxres;
*height_start++ = 0;
/* Errors from this will effectively mean "no max" */
*width = (int)strtol(width_start, NULL, 0);
*height = (int)strtol(height_start, NULL, 0);
free(maxres);
}
static int
gop_autoresize(EFI_GRAPHICS_OUTPUT *gop)
{
@ -470,16 +556,22 @@ gop_autoresize(EFI_GRAPHICS_OUTPUT *gop)
EFI_STATUS status;
UINTN infosz;
UINT32 best_mode, currdim, maxdim, mode;
int height, max_height, max_width, width;
best_mode = maxdim = 0;
efi_get_max_resolution(&max_width, &max_height);
for (mode = 0; mode < gop->Mode->MaxMode; mode++) {
status = gop->QueryMode(gop, mode, &infosz, &info);
if (EFI_ERROR(status))
continue;
efifb_from_gop(&efifb, gop->Mode, info);
currdim = info->HorizontalResolution * info->VerticalResolution;
/* XXX TODO: Allow tunable or something for max resolution */
width = info->HorizontalResolution;
height = info->VerticalResolution;
currdim = width * height;
if (currdim > maxdim) {
if ((max_width != 0 && width > max_width) ||
(max_height != 0 && height > max_height))
continue;
maxdim = currdim;
best_mode = mode;
}