Select the best mode for the EFI framebuffer.
This chooses the lowest resolution that supports our main display.
This commit is contained in:
parent
2cd060b22c
commit
6e9bdce92d
|
@ -123,12 +123,12 @@ typedef struct {
|
||||||
uintn_t frame_buffer_size;
|
uintn_t frame_buffer_size;
|
||||||
} efi_gop_mode_t;
|
} efi_gop_mode_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct efi_graphics_output_s {
|
||||||
void *query_mode;
|
efi_status_t (efiapi *query_mode)(struct efi_graphics_output_s *, uint32_t, uintn_t *, efi_gop_mode_info_t **);
|
||||||
void *set_mode;
|
efi_status_t (efiapi *set_mode)(struct efi_graphics_output_s *, uint32_t);
|
||||||
void *blt;
|
void *blt;
|
||||||
efi_gop_mode_t *mode;
|
efi_gop_mode_t *mode;
|
||||||
} efi_graphics_output_protocol_t;
|
} efi_graphics_output_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t signature;
|
uint64_t signature;
|
||||||
|
|
113
boot/efisetup.c
113
boot/efisetup.c
|
@ -24,6 +24,9 @@
|
||||||
|
|
||||||
#define MAP_BUFFER_HEADROOM 8 // number of descriptors
|
#define MAP_BUFFER_HEADROOM 8 // number of descriptors
|
||||||
|
|
||||||
|
#define MIN_H_RESOLUTION 640 // as required by our main display
|
||||||
|
#define MIN_V_RESOLUTION 400
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Private Variables
|
// Private Variables
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -249,37 +252,61 @@ static void get_bit_range(uint32_t mask, uint8_t *pos, uint8_t *size)
|
||||||
*size = length;
|
*size = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *handles, size_t handles_size)
|
static efi_graphics_output_t *find_gop(efi_handle_t *handles, size_t handles_size)
|
||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
|
|
||||||
efi_graphics_output_protocol_t *gop = NULL;
|
efi_graphics_output_t *first_gop = NULL;
|
||||||
for (int i = 0; i < efi_get_num_handles(handles_size); i++) {
|
for (int i = 0; i < efi_get_num_handles(handles_size); i++) {
|
||||||
efi_handle_t handle = efi_get_handle_at(handles, i);
|
efi_handle_t handle = efi_get_handle_at(handles, i);
|
||||||
|
|
||||||
efi_graphics_output_protocol_t *current_gop = NULL;
|
efi_graphics_output_t *gop = NULL;
|
||||||
status = efi_call_bs(handle_protocol, handle, &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, (void **)¤t_gop);
|
status = efi_call_bs(handle_protocol, handle, &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, (void **)&gop);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *con_out = NULL;
|
efi_gop_mode_t *mode = efi_table_attr(gop, mode);
|
||||||
status = efi_call_bs(handle_protocol, handle, &EFI_CONSOLE_OUT_DEVICE_GUID, &con_out);
|
efi_gop_mode_info_t *info = efi_table_attr(mode, info);
|
||||||
|
|
||||||
efi_gop_mode_t *current_mode = efi_table_attr(current_gop, mode);
|
// BLT is not available after we call ExitBootServices().
|
||||||
efi_gop_mode_info_t *current_info = efi_table_attr(current_mode, info);
|
if (info->pixel_format == PIXEL_BLT_ONLY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
print_string("Found GOP with ");
|
||||||
|
print_dec(mode->max_mode);
|
||||||
|
print_string(" modes\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Systems that use the UEFI Console Splitter may provide multiple GOP
|
// Systems that use the UEFI Console Splitter may provide multiple GOP
|
||||||
// devices, not all of which are backed by real hardware. The workaround
|
// devices, not all of which are backed by real hardware. The workaround
|
||||||
// is to search for a GOP implementing the ConOut protocol, and if one
|
// is to search for a GOP implementing the ConOut protocol, and if one
|
||||||
// isn't found, to just fall back to the first GOP.
|
// isn't found, to just fall back to the first GOP.
|
||||||
if ((!gop || con_out) && current_info->pixel_format != PIXEL_BLT_ONLY) {
|
|
||||||
gop = current_gop;
|
void *con_out = NULL;
|
||||||
if (con_out) {
|
status = efi_call_bs(handle_protocol, handle, &EFI_CONSOLE_OUT_DEVICE_GUID, &con_out);
|
||||||
break;
|
if (status == EFI_SUCCESS) {
|
||||||
}
|
#if DEBUG
|
||||||
|
print_string("This GOP implements the ConOut protocol\n");
|
||||||
|
#endif
|
||||||
|
return gop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_gop == NULL) {
|
||||||
|
first_gop = gop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return first_gop;
|
||||||
|
}
|
||||||
|
|
||||||
|
static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *handles, size_t handles_size)
|
||||||
|
{
|
||||||
|
efi_status_t status;
|
||||||
|
|
||||||
|
efi_graphics_output_t *gop = find_gop(handles, handles_size);
|
||||||
if (!gop) {
|
if (!gop) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print_string("GOP not found\n");
|
print_string("GOP not found\n");
|
||||||
|
@ -287,15 +314,43 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
||||||
return EFI_NOT_FOUND;
|
return EFI_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
efi_gop_mode_t *mode = efi_table_attr(gop, mode);
|
efi_gop_mode_t *mode = efi_table_attr(gop, mode);
|
||||||
efi_gop_mode_info_t *info = efi_table_attr(mode, info);
|
|
||||||
|
efi_gop_mode_info_t best_info;
|
||||||
|
best_info.h_resolution = UINT32_MAX;
|
||||||
|
best_info.v_resolution = UINT32_MAX;
|
||||||
|
|
||||||
|
uint32_t best_mode = UINT32_MAX;
|
||||||
|
for (uint32_t mode_num = 0; mode_num < mode->max_mode; mode_num++) {
|
||||||
|
efi_gop_mode_info_t *info;
|
||||||
|
uintn_t info_size;
|
||||||
|
status = efi_call_proto(gop, query_mode, mode_num, &info_size, &info);
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->h_resolution >= MIN_H_RESOLUTION
|
||||||
|
&& info->v_resolution >= MIN_V_RESOLUTION
|
||||||
|
&& info->h_resolution < best_info.h_resolution) {
|
||||||
|
best_mode = mode_num;
|
||||||
|
best_info = *info;
|
||||||
|
}
|
||||||
|
|
||||||
|
efi_call_bs(free_pool, info);
|
||||||
|
}
|
||||||
|
if (best_mode == UINT32_MAX) {
|
||||||
|
#if DEBUG
|
||||||
|
print_string("No suitable GOP screen resolution\n");
|
||||||
|
#endif
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
efi_phys_addr_t lfb_base = efi_table_attr(mode, frame_buffer_base);
|
efi_phys_addr_t lfb_base = efi_table_attr(mode, frame_buffer_base);
|
||||||
|
|
||||||
si->orig_video_isVGA = VIDEO_TYPE_EFI;
|
si->orig_video_isVGA = VIDEO_TYPE_EFI;
|
||||||
|
|
||||||
si->lfb_width = info->h_resolution;
|
si->lfb_width = best_info.h_resolution;
|
||||||
si->lfb_height = info->v_resolution;
|
si->lfb_height = best_info.v_resolution;
|
||||||
si->lfb_base = lfb_base;
|
si->lfb_base = lfb_base;
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
if (lfb_base >> 32) {
|
if (lfb_base >> 32) {
|
||||||
|
@ -304,13 +359,13 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (info->pixel_format) {
|
switch (best_info.pixel_format) {
|
||||||
case PIXEL_RGB_RESERVED_8BIT_PER_COLOR:
|
case PIXEL_RGB_RESERVED_8BIT_PER_COLOR:
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print_string("RGB32 mode\n");
|
print_string("RGB32 mode\n");
|
||||||
#endif
|
#endif
|
||||||
si->lfb_depth = 32;
|
si->lfb_depth = 32;
|
||||||
si->lfb_linelength = info->pixels_per_scan_line * 4;
|
si->lfb_linelength = best_info.pixels_per_scan_line * 4;
|
||||||
si->red_size = 8;
|
si->red_size = 8;
|
||||||
si->red_pos = 0;
|
si->red_pos = 0;
|
||||||
si->green_size = 8;
|
si->green_size = 8;
|
||||||
|
@ -325,7 +380,7 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
||||||
print_string("BGR32 mode\n");
|
print_string("BGR32 mode\n");
|
||||||
#endif
|
#endif
|
||||||
si->lfb_depth = 32;
|
si->lfb_depth = 32;
|
||||||
si->lfb_linelength = info->pixels_per_scan_line * 4;
|
si->lfb_linelength = best_info.pixels_per_scan_line * 4;
|
||||||
si->red_size = 8;
|
si->red_size = 8;
|
||||||
si->red_pos = 16;
|
si->red_pos = 16;
|
||||||
si->green_size = 8;
|
si->green_size = 8;
|
||||||
|
@ -339,12 +394,12 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
print_string("Bit mask mode\n");
|
print_string("Bit mask mode\n");
|
||||||
#endif
|
#endif
|
||||||
get_bit_range(info->pixel_info.red_mask, &si->red_pos, &si->red_size);
|
get_bit_range(best_info.pixel_info.red_mask, &si->red_pos, &si->red_size);
|
||||||
get_bit_range(info->pixel_info.green_mask, &si->green_pos, &si->green_size);
|
get_bit_range(best_info.pixel_info.green_mask, &si->green_pos, &si->green_size);
|
||||||
get_bit_range(info->pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
|
get_bit_range(best_info.pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
|
||||||
get_bit_range(info->pixel_info.rsvd_mask, &si->rsvd_pos, &si->rsvd_size);
|
get_bit_range(best_info.pixel_info.rsvd_mask, &si->rsvd_pos, &si->rsvd_size);
|
||||||
si->lfb_depth = si->red_size + si->green_size + si->blue_size + si->rsvd_size;
|
si->lfb_depth = si->red_size + si->green_size + si->blue_size + si->rsvd_size;
|
||||||
si->lfb_linelength = (info->pixels_per_scan_line * si->lfb_depth) / 8;
|
si->lfb_linelength = (best_info.pixels_per_scan_line * si->lfb_depth) / 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -386,6 +441,14 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
||||||
wait_for_key();
|
wait_for_key();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
status = efi_call_proto(gop, set_mode, best_mode);
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
#if DEBUG
|
||||||
|
print_string("Set GOP mode failed\n");
|
||||||
|
#endif
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue