Patchwork EFI: Expose GOP mode number through sysfs and add documentation.

login
register
mail settings
Submitter Peter Jones
Date Jan. 29, 2019, 7:22 p.m.
Message ID <20190129192227.1530-1-pjones@redhat.com>
Download mbox | patch
Permalink /patch/712855/
State New
Headers show

Comments

Peter Jones - Jan. 29, 2019, 7:22 p.m.
To use the EFI firmware update "UX Capsule" extension, we need to know
what the GOP video mode number was during boot.  This patch adds it to
the efi-framebuffer.N devices in sysfs and adds the various files in
/sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/ to the
sysfs documentation.

Signed-off-by: Peter Jones <pjones@redhat.com>
---
 drivers/firmware/efi/libstub/gop.c           | 16 ++++++++++++----
 drivers/video/fbdev/efifb.c                  | 11 +++++++++++
 include/uapi/linux/screen_info.h             |  4 ++--
 Documentation/ABI/testing/sysfs-firmware-efi | 15 +++++++++++++++
 4 files changed, 40 insertions(+), 6 deletions(-)
Ard Biesheuvel - Jan. 30, 2019, 1:13 p.m.
(add Arnd and linux-api for the uapi change)

On Tue, 29 Jan 2019 at 20:22, Peter Jones <pjones@redhat.com> wrote:
>
> To use the EFI firmware update "UX Capsule" extension, we need to know
> what the GOP video mode number was during boot.  This patch adds it to
> the efi-framebuffer.N devices in sysfs and adds the various files in
> /sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/ to the
> sysfs documentation.
>
> Signed-off-by: Peter Jones <pjones@redhat.com>
> ---
>  drivers/firmware/efi/libstub/gop.c           | 16 ++++++++++++----
>  drivers/video/fbdev/efifb.c                  | 11 +++++++++++
>  include/uapi/linux/screen_info.h             |  4 ++--
>  Documentation/ABI/testing/sysfs-firmware-efi | 15 +++++++++++++++
>  4 files changed, 40 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c
> index 24c461dea7a..f9e174acb0b 100644
> --- a/drivers/firmware/efi/libstub/gop.c
> +++ b/drivers/firmware/efi/libstub/gop.c
> @@ -89,7 +89,7 @@ static efi_status_t
>  __gop_query32(efi_system_table_t *sys_table_arg,
>               struct efi_graphics_output_protocol_32 *gop32,
>               struct efi_graphics_output_mode_info **info,
> -             unsigned long *size, u64 *fb_base)
> +             unsigned long *size, u64 *fb_base, u32 *mode_num)
>  {
>         struct efi_graphics_output_protocol_mode_32 *mode;
>         efi_graphics_output_protocol_query_mode query_mode;
> @@ -106,6 +106,7 @@ __gop_query32(efi_system_table_t *sys_table_arg,
>                 return status;
>
>         *fb_base = mode->frame_buffer_base;
> +       *mode_num = mode->mode;
>         return status;
>  }
>
> @@ -115,6 +116,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
>  {
>         struct efi_graphics_output_protocol_32 *gop32, *first_gop;
>         unsigned long nr_gops;
> +       u32 mode_num;
>         u16 width, height;
>         u32 pixels_per_scan_line;
>         u32 ext_lfb_base;
> @@ -148,7 +150,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
>                         conout_found = true;
>
>                 status = __gop_query32(sys_table_arg, gop32, &info, &size,
> -                                      &current_fb_base);
> +                                      &current_fb_base, &mode_num);
>                 if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
>                     info->pixel_format != PIXEL_BLT_ONLY) {
>                         /*
> @@ -182,6 +184,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
>         /* EFI framebuffer */
>         si->orig_video_isVGA = VIDEO_TYPE_EFI;
>
> +       si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
> +       si->efi_gop_mode_low = (mode_num & 0xff);
>         si->lfb_width = width;
>         si->lfb_height = height;
>         si->lfb_base = fb_base;
> @@ -207,7 +211,7 @@ static efi_status_t
>  __gop_query64(efi_system_table_t *sys_table_arg,
>               struct efi_graphics_output_protocol_64 *gop64,
>               struct efi_graphics_output_mode_info **info,
> -             unsigned long *size, u64 *fb_base)
> +             unsigned long *size, u64 *fb_base, u32 *mode_num)
>  {
>         struct efi_graphics_output_protocol_mode_64 *mode;
>         efi_graphics_output_protocol_query_mode query_mode;
> @@ -224,6 +228,7 @@ __gop_query64(efi_system_table_t *sys_table_arg,
>                 return status;
>
>         *fb_base = mode->frame_buffer_base;
> +       *mode_num = mode->mode;
>         return status;
>  }
>
> @@ -233,6 +238,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
>  {
>         struct efi_graphics_output_protocol_64 *gop64, *first_gop;
>         unsigned long nr_gops;
> +       u32 mode_num;
>         u16 width, height;
>         u32 pixels_per_scan_line;
>         u32 ext_lfb_base;
> @@ -266,7 +272,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
>                         conout_found = true;
>
>                 status = __gop_query64(sys_table_arg, gop64, &info, &size,
> -                                      &current_fb_base);
> +                                      &current_fb_base, &mode_num);
>                 if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
>                     info->pixel_format != PIXEL_BLT_ONLY) {
>                         /*
> @@ -300,6 +306,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
>         /* EFI framebuffer */
>         si->orig_video_isVGA = VIDEO_TYPE_EFI;
>
> +       si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
> +       si->efi_gop_mode_low = (mode_num & 0xff);
>         si->lfb_width = width;
>         si->lfb_height = height;
>         si->lfb_base = fb_base;
> diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
> index ba906876cc4..3250f3f9152 100644
> --- a/drivers/video/fbdev/efifb.c
> +++ b/drivers/video/fbdev/efifb.c
> @@ -331,12 +331,23 @@ efifb_attr_decl(height, "%u");
>  efifb_attr_decl(width, "%u");
>  efifb_attr_decl(depth, "%u");
>
> +static ssize_t gop_mode_show(struct device *dev,
> +                            struct device_attribute *attr,
> +                            char *buf)
> +{
> +       return sprintf(buf, "0x%04hx%04hx\n",
> +                      screen_info.efi_gop_mode_high,
> +                      screen_info.efi_gop_mode_low);
> +}
> +static DEVICE_ATTR_RO(gop_mode);
> +
>  static struct attribute *efifb_attrs[] = {
>         &dev_attr_base.attr,
>         &dev_attr_linelength.attr,
>         &dev_attr_width.attr,
>         &dev_attr_height.attr,
>         &dev_attr_depth.attr,
> +       &dev_attr_gop_mode.attr,
>         NULL
>  };
>  ATTRIBUTE_GROUPS(efifb);
> diff --git a/include/uapi/linux/screen_info.h b/include/uapi/linux/screen_info.h
> index 87e5c086938..a8eb2d76167 100644
> --- a/include/uapi/linux/screen_info.h
> +++ b/include/uapi/linux/screen_info.h
> @@ -18,7 +18,7 @@ struct screen_info {
>         __u8  flags;            /* 0x08 */
>         __u8  unused2;          /* 0x09 */
>         __u16 orig_video_ega_bx;/* 0x0a */
> -       __u16 unused3;          /* 0x0c */
> +       __u16 efi_gop_mode_low; /* 0x0c */
>         __u8  orig_video_lines; /* 0x0e */
>         __u8  orig_video_isVGA; /* 0x0f */
>         __u16 orig_video_points;/* 0x10 */
> @@ -45,7 +45,7 @@ struct screen_info {
>         __u16 vesa_attributes;  /* 0x34 */
>         __u32 capabilities;     /* 0x36 */
>         __u32 ext_lfb_base;     /* 0x3a */
> -       __u8  _reserved[2];     /* 0x3e */
> +       __u16 efi_gop_mode_high;/* 0x3e */
>  } __attribute__((packed));
>
>  #define VIDEO_TYPE_MDA         0x10    /* Monochrome Text Display      */
> diff --git a/Documentation/ABI/testing/sysfs-firmware-efi b/Documentation/ABI/testing/sysfs-firmware-efi
> index e794eac32a9..6c169599863 100644
> --- a/Documentation/ABI/testing/sysfs-firmware-efi
> +++ b/Documentation/ABI/testing/sysfs-firmware-efi
> @@ -28,3 +28,18 @@ Description: Displays the physical addresses of all EFI Configuration
>                 versions are always printed first, i.e. ACPI20 comes
>                 before ACPI.
>  Users:         dmidecode
> +
> +What:          /sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/
> +Date:          October 2016
> +Contact:       linux-efi@vger.kernel.org
> +Description:   The characteristics of the EFI GOP framebuffer device.
> +
> +               base: The physical address of the framebuffer memory.
> +               depth: The color depth of the framebuffer, in bits.
> +               height: The height of the displayed frame in pixels.
> +               linelength: The size of one line (i.e. the stride) of the
> +                           framebuffer memory, in bytes.
> +               width: The width of the displayed frame in pixels.
> +               gop_mode: The index into the EFI GOP mode table for the mode in
> +                         use during boot-up.
> +Users:         fwupd
> --
> 2.20.1
>
Ard Biesheuvel - Jan. 30, 2019, 1:29 p.m.
On Wed, 30 Jan 2019 at 14:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>
> (add Arnd and linux-api for the uapi change)
>

(... and team-x86)

> On Tue, 29 Jan 2019 at 20:22, Peter Jones <pjones@redhat.com> wrote:
> >
> > To use the EFI firmware update "UX Capsule" extension, we need to know
> > what the GOP video mode number was during boot.  This patch adds it to
> > the efi-framebuffer.N devices in sysfs and adds the various files in
> > /sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/ to the
> > sysfs documentation.
> >
> > Signed-off-by: Peter Jones <pjones@redhat.com>
> > ---
> >  drivers/firmware/efi/libstub/gop.c           | 16 ++++++++++++----
> >  drivers/video/fbdev/efifb.c                  | 11 +++++++++++
> >  include/uapi/linux/screen_info.h             |  4 ++--
> >  Documentation/ABI/testing/sysfs-firmware-efi | 15 +++++++++++++++
> >  4 files changed, 40 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c
> > index 24c461dea7a..f9e174acb0b 100644
> > --- a/drivers/firmware/efi/libstub/gop.c
> > +++ b/drivers/firmware/efi/libstub/gop.c
> > @@ -89,7 +89,7 @@ static efi_status_t
> >  __gop_query32(efi_system_table_t *sys_table_arg,
> >               struct efi_graphics_output_protocol_32 *gop32,
> >               struct efi_graphics_output_mode_info **info,
> > -             unsigned long *size, u64 *fb_base)
> > +             unsigned long *size, u64 *fb_base, u32 *mode_num)
> >  {
> >         struct efi_graphics_output_protocol_mode_32 *mode;
> >         efi_graphics_output_protocol_query_mode query_mode;
> > @@ -106,6 +106,7 @@ __gop_query32(efi_system_table_t *sys_table_arg,
> >                 return status;
> >
> >         *fb_base = mode->frame_buffer_base;
> > +       *mode_num = mode->mode;
> >         return status;
> >  }
> >
> > @@ -115,6 +116,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
> >  {
> >         struct efi_graphics_output_protocol_32 *gop32, *first_gop;
> >         unsigned long nr_gops;
> > +       u32 mode_num;
> >         u16 width, height;
> >         u32 pixels_per_scan_line;
> >         u32 ext_lfb_base;
> > @@ -148,7 +150,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
> >                         conout_found = true;
> >
> >                 status = __gop_query32(sys_table_arg, gop32, &info, &size,
> > -                                      &current_fb_base);
> > +                                      &current_fb_base, &mode_num);
> >                 if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
> >                     info->pixel_format != PIXEL_BLT_ONLY) {
> >                         /*
> > @@ -182,6 +184,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
> >         /* EFI framebuffer */
> >         si->orig_video_isVGA = VIDEO_TYPE_EFI;
> >
> > +       si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
> > +       si->efi_gop_mode_low = (mode_num & 0xff);
> >         si->lfb_width = width;
> >         si->lfb_height = height;
> >         si->lfb_base = fb_base;
> > @@ -207,7 +211,7 @@ static efi_status_t
> >  __gop_query64(efi_system_table_t *sys_table_arg,
> >               struct efi_graphics_output_protocol_64 *gop64,
> >               struct efi_graphics_output_mode_info **info,
> > -             unsigned long *size, u64 *fb_base)
> > +             unsigned long *size, u64 *fb_base, u32 *mode_num)
> >  {
> >         struct efi_graphics_output_protocol_mode_64 *mode;
> >         efi_graphics_output_protocol_query_mode query_mode;
> > @@ -224,6 +228,7 @@ __gop_query64(efi_system_table_t *sys_table_arg,
> >                 return status;
> >
> >         *fb_base = mode->frame_buffer_base;
> > +       *mode_num = mode->mode;
> >         return status;
> >  }
> >
> > @@ -233,6 +238,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
> >  {
> >         struct efi_graphics_output_protocol_64 *gop64, *first_gop;
> >         unsigned long nr_gops;
> > +       u32 mode_num;
> >         u16 width, height;
> >         u32 pixels_per_scan_line;
> >         u32 ext_lfb_base;
> > @@ -266,7 +272,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
> >                         conout_found = true;
> >
> >                 status = __gop_query64(sys_table_arg, gop64, &info, &size,
> > -                                      &current_fb_base);
> > +                                      &current_fb_base, &mode_num);
> >                 if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
> >                     info->pixel_format != PIXEL_BLT_ONLY) {
> >                         /*
> > @@ -300,6 +306,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
> >         /* EFI framebuffer */
> >         si->orig_video_isVGA = VIDEO_TYPE_EFI;
> >
> > +       si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
> > +       si->efi_gop_mode_low = (mode_num & 0xff);
> >         si->lfb_width = width;
> >         si->lfb_height = height;
> >         si->lfb_base = fb_base;
> > diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
> > index ba906876cc4..3250f3f9152 100644
> > --- a/drivers/video/fbdev/efifb.c
> > +++ b/drivers/video/fbdev/efifb.c
> > @@ -331,12 +331,23 @@ efifb_attr_decl(height, "%u");
> >  efifb_attr_decl(width, "%u");
> >  efifb_attr_decl(depth, "%u");
> >
> > +static ssize_t gop_mode_show(struct device *dev,
> > +                            struct device_attribute *attr,
> > +                            char *buf)
> > +{
> > +       return sprintf(buf, "0x%04hx%04hx\n",
> > +                      screen_info.efi_gop_mode_high,
> > +                      screen_info.efi_gop_mode_low);
> > +}
> > +static DEVICE_ATTR_RO(gop_mode);
> > +
> >  static struct attribute *efifb_attrs[] = {
> >         &dev_attr_base.attr,
> >         &dev_attr_linelength.attr,
> >         &dev_attr_width.attr,
> >         &dev_attr_height.attr,
> >         &dev_attr_depth.attr,
> > +       &dev_attr_gop_mode.attr,
> >         NULL
> >  };
> >  ATTRIBUTE_GROUPS(efifb);
> > diff --git a/include/uapi/linux/screen_info.h b/include/uapi/linux/screen_info.h
> > index 87e5c086938..a8eb2d76167 100644
> > --- a/include/uapi/linux/screen_info.h
> > +++ b/include/uapi/linux/screen_info.h
> > @@ -18,7 +18,7 @@ struct screen_info {
> >         __u8  flags;            /* 0x08 */
> >         __u8  unused2;          /* 0x09 */
> >         __u16 orig_video_ega_bx;/* 0x0a */
> > -       __u16 unused3;          /* 0x0c */
> > +       __u16 efi_gop_mode_low; /* 0x0c */
> >         __u8  orig_video_lines; /* 0x0e */
> >         __u8  orig_video_isVGA; /* 0x0f */
> >         __u16 orig_video_points;/* 0x10 */
> > @@ -45,7 +45,7 @@ struct screen_info {
> >         __u16 vesa_attributes;  /* 0x34 */
> >         __u32 capabilities;     /* 0x36 */
> >         __u32 ext_lfb_base;     /* 0x3a */
> > -       __u8  _reserved[2];     /* 0x3e */
> > +       __u16 efi_gop_mode_high;/* 0x3e */
> >  } __attribute__((packed));
> >
> >  #define VIDEO_TYPE_MDA         0x10    /* Monochrome Text Display      */
> > diff --git a/Documentation/ABI/testing/sysfs-firmware-efi b/Documentation/ABI/testing/sysfs-firmware-efi
> > index e794eac32a9..6c169599863 100644
> > --- a/Documentation/ABI/testing/sysfs-firmware-efi
> > +++ b/Documentation/ABI/testing/sysfs-firmware-efi
> > @@ -28,3 +28,18 @@ Description: Displays the physical addresses of all EFI Configuration
> >                 versions are always printed first, i.e. ACPI20 comes
> >                 before ACPI.
> >  Users:         dmidecode
> > +
> > +What:          /sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/
> > +Date:          October 2016
> > +Contact:       linux-efi@vger.kernel.org
> > +Description:   The characteristics of the EFI GOP framebuffer device.
> > +
> > +               base: The physical address of the framebuffer memory.
> > +               depth: The color depth of the framebuffer, in bits.
> > +               height: The height of the displayed frame in pixels.
> > +               linelength: The size of one line (i.e. the stride) of the
> > +                           framebuffer memory, in bytes.
> > +               width: The width of the displayed frame in pixels.
> > +               gop_mode: The index into the EFI GOP mode table for the mode in
> > +                         use during boot-up.
> > +Users:         fwupd
> > --
> > 2.20.1
> >

Patch

diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c
index 24c461dea7a..f9e174acb0b 100644
--- a/drivers/firmware/efi/libstub/gop.c
+++ b/drivers/firmware/efi/libstub/gop.c
@@ -89,7 +89,7 @@  static efi_status_t
 __gop_query32(efi_system_table_t *sys_table_arg,
 	      struct efi_graphics_output_protocol_32 *gop32,
 	      struct efi_graphics_output_mode_info **info,
-	      unsigned long *size, u64 *fb_base)
+	      unsigned long *size, u64 *fb_base, u32 *mode_num)
 {
 	struct efi_graphics_output_protocol_mode_32 *mode;
 	efi_graphics_output_protocol_query_mode query_mode;
@@ -106,6 +106,7 @@  __gop_query32(efi_system_table_t *sys_table_arg,
 		return status;
 
 	*fb_base = mode->frame_buffer_base;
+	*mode_num = mode->mode;
 	return status;
 }
 
@@ -115,6 +116,7 @@  setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
 {
 	struct efi_graphics_output_protocol_32 *gop32, *first_gop;
 	unsigned long nr_gops;
+	u32 mode_num;
 	u16 width, height;
 	u32 pixels_per_scan_line;
 	u32 ext_lfb_base;
@@ -148,7 +150,7 @@  setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
 			conout_found = true;
 
 		status = __gop_query32(sys_table_arg, gop32, &info, &size,
-				       &current_fb_base);
+				       &current_fb_base, &mode_num);
 		if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
 		    info->pixel_format != PIXEL_BLT_ONLY) {
 			/*
@@ -182,6 +184,8 @@  setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
 	/* EFI framebuffer */
 	si->orig_video_isVGA = VIDEO_TYPE_EFI;
 
+	si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
+	si->efi_gop_mode_low = (mode_num & 0xff);
 	si->lfb_width = width;
 	si->lfb_height = height;
 	si->lfb_base = fb_base;
@@ -207,7 +211,7 @@  static efi_status_t
 __gop_query64(efi_system_table_t *sys_table_arg,
 	      struct efi_graphics_output_protocol_64 *gop64,
 	      struct efi_graphics_output_mode_info **info,
-	      unsigned long *size, u64 *fb_base)
+	      unsigned long *size, u64 *fb_base, u32 *mode_num)
 {
 	struct efi_graphics_output_protocol_mode_64 *mode;
 	efi_graphics_output_protocol_query_mode query_mode;
@@ -224,6 +228,7 @@  __gop_query64(efi_system_table_t *sys_table_arg,
 		return status;
 
 	*fb_base = mode->frame_buffer_base;
+	*mode_num = mode->mode;
 	return status;
 }
 
@@ -233,6 +238,7 @@  setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
 {
 	struct efi_graphics_output_protocol_64 *gop64, *first_gop;
 	unsigned long nr_gops;
+	u32 mode_num;
 	u16 width, height;
 	u32 pixels_per_scan_line;
 	u32 ext_lfb_base;
@@ -266,7 +272,7 @@  setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
 			conout_found = true;
 
 		status = __gop_query64(sys_table_arg, gop64, &info, &size,
-				       &current_fb_base);
+				       &current_fb_base, &mode_num);
 		if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
 		    info->pixel_format != PIXEL_BLT_ONLY) {
 			/*
@@ -300,6 +306,8 @@  setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
 	/* EFI framebuffer */
 	si->orig_video_isVGA = VIDEO_TYPE_EFI;
 
+	si->efi_gop_mode_high = (mode_num & 0xff00) >> 16;
+	si->efi_gop_mode_low = (mode_num & 0xff);
 	si->lfb_width = width;
 	si->lfb_height = height;
 	si->lfb_base = fb_base;
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index ba906876cc4..3250f3f9152 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -331,12 +331,23 @@  efifb_attr_decl(height, "%u");
 efifb_attr_decl(width, "%u");
 efifb_attr_decl(depth, "%u");
 
+static ssize_t gop_mode_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return sprintf(buf, "0x%04hx%04hx\n",
+		       screen_info.efi_gop_mode_high,
+		       screen_info.efi_gop_mode_low);
+}
+static DEVICE_ATTR_RO(gop_mode);
+
 static struct attribute *efifb_attrs[] = {
 	&dev_attr_base.attr,
 	&dev_attr_linelength.attr,
 	&dev_attr_width.attr,
 	&dev_attr_height.attr,
 	&dev_attr_depth.attr,
+	&dev_attr_gop_mode.attr,
 	NULL
 };
 ATTRIBUTE_GROUPS(efifb);
diff --git a/include/uapi/linux/screen_info.h b/include/uapi/linux/screen_info.h
index 87e5c086938..a8eb2d76167 100644
--- a/include/uapi/linux/screen_info.h
+++ b/include/uapi/linux/screen_info.h
@@ -18,7 +18,7 @@  struct screen_info {
 	__u8  flags;		/* 0x08 */
 	__u8  unused2;		/* 0x09 */
 	__u16 orig_video_ega_bx;/* 0x0a */
-	__u16 unused3;		/* 0x0c */
+	__u16 efi_gop_mode_low;	/* 0x0c */
 	__u8  orig_video_lines;	/* 0x0e */
 	__u8  orig_video_isVGA;	/* 0x0f */
 	__u16 orig_video_points;/* 0x10 */
@@ -45,7 +45,7 @@  struct screen_info {
 	__u16 vesa_attributes;	/* 0x34 */
 	__u32 capabilities;     /* 0x36 */
 	__u32 ext_lfb_base;	/* 0x3a */
-	__u8  _reserved[2];	/* 0x3e */
+	__u16 efi_gop_mode_high;/* 0x3e */
 } __attribute__((packed));
 
 #define VIDEO_TYPE_MDA		0x10	/* Monochrome Text Display	*/
diff --git a/Documentation/ABI/testing/sysfs-firmware-efi b/Documentation/ABI/testing/sysfs-firmware-efi
index e794eac32a9..6c169599863 100644
--- a/Documentation/ABI/testing/sysfs-firmware-efi
+++ b/Documentation/ABI/testing/sysfs-firmware-efi
@@ -28,3 +28,18 @@  Description:	Displays the physical addresses of all EFI Configuration
 		versions are always printed first, i.e. ACPI20 comes
 		before ACPI.
 Users:		dmidecode
+
+What:		/sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.N/
+Date:		October 2016
+Contact:	linux-efi@vger.kernel.org
+Description:	The characteristics of the EFI GOP framebuffer device.
+
+		base: The physical address of the framebuffer memory.
+		depth: The color depth of the framebuffer, in bits.
+		height: The height of the displayed frame in pixels.
+		linelength: The size of one line (i.e. the stride) of the
+			    framebuffer memory, in bytes.
+		width: The width of the displayed frame in pixels.
+		gop_mode: The index into the EFI GOP mode table for the mode in
+			  use during boot-up.
+Users:		fwupd