History

efifb: Add support for 64-bit frame buffer addresses

The EFI Graphics Output Protocol uses 64-bit frame buffer addresses but these get truncated to 32-bit by the EFI boot stub when storing the address in the 'lfb_base' field of 'struct screen_info'. Add a 'ext_lfb_base' field for the upper 32-bits of the frame buffer address and set VIDEO_TYPE_CAPABILITY_64BIT_BASE when the field is useable. It turns out that the reason no one has required this support so far is that there's actually code in tianocore to "downgrade" PCI resources that have option ROMs and 64-bit BARS from 64-bit to 32-bit to cope with legacy option ROMs that can't handle 64-bit addresses. The upshot is that basically all GOP devices in the wild use a 32-bit frame buffer address. Still, it is possible to build firmware that uses a full 64-bit GOP frame buffer address. Chad did, which led to him reporting this issue. Add support in anticipation of GOP devices using 64-bit addresses more widely, and so that efifb works out of the box when that happens.

Matt Fleming committed 11 years ago

Commit ae2ee621 parent 7968c0e3 files · +46 −7Browse files

Unified · Split

3 files
  1. arch/x86/boot/compressed/eboot.c +20 −4
  2. drivers/video/fbdev/efifb.c +23 −1
  3. include/uapi/linux/screen_info.h +3 −2
arch/x86/boot/compressed/eboot.c+20−4
@@ -624,7 +624,7 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, · 623 unmodified lines
624static efi_status_t624static efi_status_t
625__gop_query32(struct efi_graphics_output_protocol_32 *gop32,625__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
626 struct efi_graphics_output_mode_info **info,626 struct efi_graphics_output_mode_info **info,
627 unsigned long *size, u32 *fb_base)627 unsigned long *size, u64 *fb_base)
628{628{
629 struct efi_graphics_output_protocol_mode_32 *mode;629 struct efi_graphics_output_protocol_mode_32 *mode;
630 efi_status_t status;630 efi_status_t status;
@@ -650,7 +650,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, · 19 unmodified lines
650 unsigned long nr_gops;650 unsigned long nr_gops;
651 u16 width, height;651 u16 width, height;
652 u32 pixels_per_scan_line;652 u32 pixels_per_scan_line;
653 u32 fb_base;653 u32 ext_lfb_base;
654 u64 fb_base;
654 struct efi_pixel_bitmask pixel_info;655 struct efi_pixel_bitmask pixel_info;
655 int pixel_format;656 int pixel_format;
656 efi_status_t status;657 efi_status_t status;
@@ -713,6 +714,13 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, · 56 unmodified lines
713 si->lfb_width = width;714 si->lfb_width = width;
714 si->lfb_height = height;715 si->lfb_height = height;
715 si->lfb_base = fb_base;716 si->lfb_base = fb_base;
717
718 ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
719 if (ext_lfb_base) {
720 si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
721 si->ext_lfb_base = ext_lfb_base;
722 }
723
716 si->pages = 1;724 si->pages = 1;
717 725
718 setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);726 setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
@@ -727,7 +735,7 @@ out: · 8 unmodified lines
727static efi_status_t735static efi_status_t
728__gop_query64(struct efi_graphics_output_protocol_64 *gop64,736__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
729 struct efi_graphics_output_mode_info **info,737 struct efi_graphics_output_mode_info **info,
730 unsigned long *size, u32 *fb_base)738 unsigned long *size, u64 *fb_base)
731{739{
732 struct efi_graphics_output_protocol_mode_64 *mode;740 struct efi_graphics_output_protocol_mode_64 *mode;
733 efi_status_t status;741 efi_status_t status;
@@ -753,7 +761,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, · 19 unmodified lines
753 unsigned long nr_gops;761 unsigned long nr_gops;
754 u16 width, height;762 u16 width, height;
755 u32 pixels_per_scan_line;763 u32 pixels_per_scan_line;
756 u32 fb_base;764 u32 ext_lfb_base;
765 u64 fb_base;
757 struct efi_pixel_bitmask pixel_info;766 struct efi_pixel_bitmask pixel_info;
758 int pixel_format;767 int pixel_format;
759 efi_status_t status;768 efi_status_t status;
@@ -816,6 +825,13 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, · 56 unmodified lines
816 si->lfb_width = width;825 si->lfb_width = width;
817 si->lfb_height = height;826 si->lfb_height = height;
818 si->lfb_base = fb_base;827 si->lfb_base = fb_base;
828
829 ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
830 if (ext_lfb_base) {
831 si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
832 si->ext_lfb_base = ext_lfb_base;
833 }
834
819 si->pages = 1;835 si->pages = 1;
820 836
821 setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);837 setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
drivers/video/fbdev/efifb.c+23−1
@@ -114,6 +114,20 @@ static int efifb_setup(char *options) · 113 unmodified lines
114 return 0;114 return 0;
115}115}
116 116
117static inline bool fb_base_is_valid(void)
118{
119 if (screen_info.lfb_base)
120 return true;
121
122 if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
123 return false;
124
125 if (screen_info.ext_lfb_base)
126 return true;
127
128 return false;
129}
130
117static int efifb_probe(struct platform_device *dev)131static int efifb_probe(struct platform_device *dev)
118{132{
119 struct fb_info *info;133 struct fb_info *info;
@@ -141,7 +155,7 @@ static int efifb_probe(struct platform_device *dev) · 21 unmodified lines
141 screen_info.lfb_depth = 32;155 screen_info.lfb_depth = 32;
142 if (!screen_info.pages)156 if (!screen_info.pages)
143 screen_info.pages = 1;157 screen_info.pages = 1;
144 if (!screen_info.lfb_base) {158 if (!fb_base_is_valid()) {
145 printk(KERN_DEBUG "efifb: invalid framebuffer address\n");159 printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
146 return -ENODEV;160 return -ENODEV;
147 }161 }
@@ -160,6 +174,14 @@ static int efifb_probe(struct platform_device *dev) · 12 unmodified lines
160 }174 }
161 175
162 efifb_fix.smem_start = screen_info.lfb_base;176 efifb_fix.smem_start = screen_info.lfb_base;
177
178 if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
179 u64 ext_lfb_base;
180
181 ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
182 efifb_fix.smem_start |= ext_lfb_base;
183 }
184
163 efifb_defined.bits_per_pixel = screen_info.lfb_depth;185 efifb_defined.bits_per_pixel = screen_info.lfb_depth;
164 efifb_defined.xres = screen_info.lfb_width;186 efifb_defined.xres = screen_info.lfb_width;
165 efifb_defined.yres = screen_info.lfb_height;187 efifb_defined.yres = screen_info.lfb_height;
include/uapi/linux/screen_info.h+3−2
@@ -43,7 +43,8 @@ struct screen_info { · 42 unmodified lines
43 __u16 pages; /* 0x32 */43 __u16 pages; /* 0x32 */
44 __u16 vesa_attributes; /* 0x34 */44 __u16 vesa_attributes; /* 0x34 */
45 __u32 capabilities; /* 0x36 */45 __u32 capabilities; /* 0x36 */
46 __u8 _reserved[6]; /* 0x3a */46 __u32 ext_lfb_base; /* 0x3a */
47 __u8 _reserved[2]; /* 0x3e */
47} __attribute__((packed));48} __attribute__((packed));
48 49
49#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */50#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
@@ -69,6 +70,6 @@ struct screen_info { · 19 unmodified lines
69#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */70#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */
70 71
71#define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0)72#define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0)
72 73#define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit */
73 74
74#endif /* _UAPI_SCREEN_INFO_H */75#endif /* _UAPI_SCREEN_INFO_H */