grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

UGA FB driver (Re: [GITGRUB] FB driver for EFI)


From: Robert Millan
Subject: UGA FB driver (Re: [GITGRUB] FB driver for EFI)
Date: Mon, 23 Nov 2009 12:26:34 +0100
User-agent: Mutt/1.5.18 (2008-05-17)

I merged this patch, with some adjustments.

GOP is intentionally left out.  It depends on missing struct definitions
not present in the patch, which would be easy to reconstruct based reusing
UGA ones but I don't have the hardware to test it.

And in any case, our future direction are standalone, free drivers.
Callback interfaces are almost invariably are implemented with proprietary
code, which puts restraints on users, is against our principles and is
often full of bugs.

There's ongoing work in bringing standalone drivers to GRUB.  I expect
these will completely superceed UGA eventually.

On Tue, Aug 18, 2009 at 09:26:45PM +0800, Bean wrote:
> Hi,
> 
> Here is the raw patch.
> 
> [...]
> -- 
> Bean
> 
> gitgrub home: http://github.com/grub/grub/
> my fork page: http://github.com/bean123/grub/

> diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
> index d335761..7f8a83f 100644
> --- a/conf/i386-efi.rmk
> +++ b/conf/i386-efi.rmk
> @@ -83,7 +83,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
>  pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
>       linux.mod halt.mod reboot.mod pci.mod lspci.mod \
>       datetime.mod date.mod datehook.mod loadbios.mod \
> -     fixvideo.mod mmap.mod acpi.mod
> +     fixvideo.mod mmap.mod acpi.mod efi_fb.mod
>  
>  # For kernel.mod.
>  kernel_mod_EXPORTS = no
> @@ -179,6 +179,11 @@ fixvideo_mod_SOURCES = commands/efi/fixvideo.c
>  fixvideo_mod_CFLAGS = $(COMMON_CFLAGS)
>  fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS)
>  
> +# For efi_fb.mod
> +efi_fb_mod_SOURCES = video/efi/efi_fb.c
> +efi_fb_mod_CFLAGS = $(COMMON_CFLAGS)
> +efi_fb_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
>  pkglib_MODULES += xnu.mod
>  xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c 
> loader/i386/efi/xnu.c\
>        loader/macho.c loader/xnu.c loader/i386/xnu_helper.S
> diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk
> index b76b63e..d93b365 100644
> --- a/conf/x86_64-efi.rmk
> +++ b/conf/x86_64-efi.rmk
> @@ -80,7 +80,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
>  pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
>       halt.mod reboot.mod linux.mod pci.mod lspci.mod \
>       datetime.mod date.mod datehook.mod loadbios.mod \
> -     fixvideo.mod mmap.mod acpi.mod
> +     fixvideo.mod mmap.mod acpi.mod efi_fb.mod
>  
>  # For kernel.mod.
>  kernel_mod_EXPORTS = no
> @@ -177,6 +177,11 @@ fixvideo_mod_SOURCES = commands/efi/fixvideo.c
>  fixvideo_mod_CFLAGS = $(COMMON_CFLAGS)
>  fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS)
>  
> +# For efi_fb.mod
> +efi_fb_mod_SOURCES = video/efi/efi_fb.c
> +efi_fb_mod_CFLAGS = $(COMMON_CFLAGS)
> +efi_fb_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
>  pkglib_MODULES += xnu.mod
>  xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c 
> loader/i386/efi/xnu.c\
>        loader/macho.c loader/xnu.c loader/i386/xnu_helper.S
> diff --git a/video/efi/efi_fb.c b/video/efi/efi_fb.c
> new file mode 100755
> index 0000000..7e8f0e8
> --- /dev/null
> +++ b/video/efi/efi_fb.c
> @@ -0,0 +1,395 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2005,2006,2007,2008,2009  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#define grub_video_render_target grub_video_fbrender_target
> +
> +#include <grub/err.h>
> +#include <grub/types.h>
> +#include <grub/dl.h>
> +#include <grub/misc.h>
> +#include <grub/mm.h>
> +#include <grub/video.h>
> +#include <grub/video_fb.h>
> +#include <grub/efi/api.h>
> +#include <grub/efi/efi.h>
> +#include <grub/efi/uga_draw.h>
> +#include <grub/efi/graphics_output.h>
> +#include <grub/pci.h>
> +
> +static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
> +static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GRAPHICS_OUTPUT_GUID;
> +static struct grub_efi_graphics_output_protocol *gop;
> +static struct grub_efi_uga_draw_protocol *uga;
> +grub_uint32_t uga_fb;
> +grub_uint32_t uga_pitch;
> +
> +static struct
> +{
> +  struct grub_video_mode_info mode_info;
> +  struct grub_video_render_target *render_target;
> +  grub_uint8_t *ptr;
> +} framebuffer;
> +
> +#define RGB_MASK     0xffffff
> +#define RGB_MAGIC    0x121314
> +#define LINE_MIN     800
> +#define LINE_MAX     4096
> +#define FBTEST_STEP  (0x10000 >> 2)
> +#define FBTEST_COUNT 8
> +
> +static int
> +find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
> +{
> +  grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base;
> +  int i;
> +
> +  for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
> +    {
> +      if ((*base & RGB_MASK) == RGB_MAGIC)
> +     {
> +       int j;
> +
> +       for (j = LINE_MIN; j <= LINE_MAX; j++)
> +         {
> +           if ((base[j] & RGB_MASK) == RGB_MAGIC)
> +             {
> +               *fb_base = (grub_uint32_t) (grub_target_addr_t) base;
> +               *line_len = j << 2;
> +
> +               return 1;
> +             }
> +         }
> +
> +       break;
> +     }
> +    }
> +
> +  return 0;
> +}
> +
> +static int
> +find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
> +{
> +  int found = 0;
> +
> +  auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
> +                                    grub_pci_id_t pciid);
> +
> +  int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
> +                               grub_pci_id_t pciid)
> +    {
> +      grub_pci_address_t addr;
> +
> +      addr = grub_pci_make_address (bus, dev, func, 2);
> +      if (grub_pci_read (addr) >> 24 == 0x3)
> +     {
> +       int i;
> +
> +       grub_dprintf ("fb", "Display controller: %d:%d.%d\nDevice id: %x\n",
> +                     bus, dev, func, pciid);
> +       addr += 8;
> +       for (i = 0; i < 6; i++, addr += 4)
> +         {
> +           grub_uint32_t old_bar1, old_bar2, type;
> +           grub_uint64_t base64;
> +
> +           old_bar1 = grub_pci_read (addr);
> +           if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
> +             continue;
> +
> +           type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
> +           if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
> +             {
> +               if (i == 5)
> +                 break;
> +
> +               old_bar2 = grub_pci_read (addr + 4);
> +             }
> +           else
> +             old_bar2 = 0;
> +
> +           base64 = old_bar2;
> +           base64 <<= 32;
> +           base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
> +
> +           grub_dprintf ("fb", "%s(%d): 0x%llx\n",
> +                         ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
> +                         "VMEM" : "MMIO"), i,
> +                        (unsigned long long) base64);
> +
> +           if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found))
> +             {
> +               *fb_base = base64;
> +               if (find_line_len (fb_base, line_len))
> +                 found++;
> +             }
> +
> +           if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
> +             {
> +               i++;
> +               addr += 4;
> +             }
> +         }
> +     }
> +
> +      return found;
> +    }
> +
> +  grub_pci_iterate (find_card);
> +  return found;
> +}
> +
> +static int
> +check_protocol (void)
> +{
> +  grub_efi_uga_draw_protocol_t *c;
> +
> +  gop = grub_efi_locate_protocol (&graphics_output_guid, 0);
> +  if (gop)
> +    return 1;
> +
> +  c = grub_efi_locate_protocol (&uga_draw_guid, 0);
> +  if (c)
> +    {
> +      grub_uint32_t width, height, depth, rate, pixel;
> +      int ret;
> +
> +      if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
> +     return 0;
> +
> +      grub_efi_set_text_mode (0);
> +      pixel = RGB_MAGIC;
> +      efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
> +                GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
> +      ret = find_framebuf (&uga_fb, &uga_pitch);
> +      grub_efi_set_text_mode (1);
> +
> +      if (ret)
> +     {
> +       uga = c;
> +       return 1;
> +     }
> +    }
> +
> +  return 0;
> +}
> +
> +static grub_err_t
> +grub_video_efi_init (void)
> +{
> +  grub_memset (&framebuffer, 0, sizeof(framebuffer));
> +  return grub_video_fb_init ();
> +}
> +
> +static grub_err_t
> +grub_video_efi_fini (void)
> +{
> +  return grub_video_fb_fini ();
> +}
> +
> +static grub_err_t
> +grub_video_efi_setup (unsigned int width, unsigned int height,
> +                   unsigned int mode_type)
> +{
> +  unsigned int depth;
> +  int found = 0;
> +
> +  depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
> +    >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
> +
> +  if (gop)
> +    {
> +      struct grub_efi_graphics_output_mode_information *info;
> +      unsigned int mode;
> +
> +      if ((width) || (height) || (depth))
> +     {
> +       for (mode = 0; mode < gop->mode->max_mode; mode++)
> +         {
> +           grub_efi_uintn_t size;
> +
> +           if (efi_call_4 (gop->query_mode, gop, mode, &size, &info))
> +             {
> +               info = 0;
> +               break;
> +             }
> +
> +           if ((info->horizontal_resolution == width) &&
> +               (info->vertical_resolution == height) &&
> +               (depth == 32))
> +             break;
> +         }
> +
> +       if (mode >= gop->mode->max_mode)
> +         info = 0;
> +     }
> +      else
> +     {
> +       mode = gop->mode->mode;
> +       info = gop->mode->info;
> +     }
> +
> +      if (info)
> +     {
> +       if (mode != gop->mode->mode)
> +         {
> +           efi_call_2 (gop->set_mode, gop, mode);
> +           info = gop->mode->info;
> +         }
> +
> +       framebuffer.mode_info.width = info->horizontal_resolution;
> +       framebuffer.mode_info.height = info->vertical_resolution;
> +       framebuffer.mode_info.pitch = info->pixels_per_scan_line * 4;
> +       framebuffer.ptr = (grub_uint8_t *) (grub_target_addr_t)
> +         (gop->mode->frame_buffer_base & 0xffffffff);
> +       found = 1;
> +     }
> +    }
> +  else
> +    {
> +      grub_uint32_t w;
> +      grub_uint32_t h;
> +      grub_uint32_t d;
> +      grub_uint32_t r;
> +
> +      if ((! efi_call_5 (uga->get_mode, uga, &w, &h, &d, &r)) &&
> +       ((! width) || (width == w)) &&
> +       ((! height) || (height == h)) &&
> +       ((! depth) || (depth == d)))
> +     {
> +       framebuffer.mode_info.width = w;
> +       framebuffer.mode_info.height = h;
> +       framebuffer.mode_info.pitch = uga_pitch;
> +       framebuffer.ptr = (grub_uint8_t *) (grub_target_addr_t) uga_fb;
> +
> +       found = 1;
> +     }
> +    }
> +
> +  if (found)
> +    {
> +      grub_err_t err;
> +
> +      framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
> +      framebuffer.mode_info.bpp = 32;
> +      framebuffer.mode_info.bytes_per_pixel = 4;
> +      framebuffer.mode_info.number_of_colors = 256; /* TODO: fix me.  */
> +      framebuffer.mode_info.red_mask_size = 8;
> +      framebuffer.mode_info.red_field_pos = 16;
> +      framebuffer.mode_info.green_mask_size = 8;
> +      framebuffer.mode_info.green_field_pos = 8;
> +      framebuffer.mode_info.blue_mask_size = 8;
> +      framebuffer.mode_info.blue_field_pos = 0;
> +      framebuffer.mode_info.reserved_mask_size = 8;
> +      framebuffer.mode_info.reserved_field_pos = 24;
> +
> +      framebuffer.mode_info.blit_format =
> +     grub_video_get_blit_format (&framebuffer.mode_info);
> +
> +      err = grub_video_fb_create_render_target_from_pointer
> +     (&framebuffer.render_target,
> +      &framebuffer.mode_info,
> +      framebuffer.ptr);
> +
> +      if (err)
> +     return err;
> +
> +      err = grub_video_fb_set_active_render_target
> +     (framebuffer.render_target);
> +
> +      if (err)
> +     return err;
> +
> +      err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
> +                                    grub_video_fbstd_colors);
> +
> +      return err;
> +    }
> +
> +  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found.");
> +}
> +
> +static grub_err_t
> +grub_video_efi_swap_buffers (void)
> +{
> +  /* TODO: Implement buffer swapping.  */
> +  return GRUB_ERR_NONE;
> +}
> +
> +static grub_err_t
> +grub_video_efi_set_active_render_target (struct grub_video_render_target 
> *target)
> +{
> +  if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY)
> +    target = framebuffer.render_target;
> +
> +  return grub_video_fb_set_active_render_target (target);
> +}
> +
> +static grub_err_t
> +grub_video_efi_get_info_and_fini (struct grub_video_mode_info *mode_info,
> +                               void **framebuf)
> +{
> +  grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info));
> +  *framebuf = (char *) framebuffer.ptr;
> +
> +  grub_video_fb_fini ();
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> +static struct grub_video_adapter grub_video_efi_adapter =
> +  {
> +    .name = "EFI frame buffer driver",
> +
> +    .init = grub_video_efi_init,
> +    .fini = grub_video_efi_fini,
> +    .setup = grub_video_efi_setup,
> +    .get_info = grub_video_fb_get_info,
> +    .get_info_and_fini = grub_video_efi_get_info_and_fini,
> +    .set_palette = grub_video_fb_set_palette,
> +    .get_palette = grub_video_fb_get_palette,
> +    .set_viewport = grub_video_fb_set_viewport,
> +    .get_viewport = grub_video_fb_get_viewport,
> +    .map_color = grub_video_fb_map_color,
> +    .map_rgb = grub_video_fb_map_rgb,
> +    .map_rgba = grub_video_fb_map_rgba,
> +    .unmap_color = grub_video_fb_unmap_color,
> +    .fill_rect = grub_video_fb_fill_rect,
> +    .blit_bitmap = grub_video_fb_blit_bitmap,
> +    .blit_render_target = grub_video_fb_blit_render_target,
> +    .scroll = grub_video_fb_scroll,
> +    .swap_buffers = grub_video_efi_swap_buffers,
> +    .create_render_target = grub_video_fb_create_render_target,
> +    .delete_render_target = grub_video_fb_delete_render_target,
> +    .set_active_render_target = grub_video_efi_set_active_render_target,
> +    .get_active_render_target = grub_video_fb_get_active_render_target,
> +
> +    .next = 0
> +  };
> +
> +GRUB_MOD_INIT(efi_fb)
> +{
> +  if (check_protocol ())
> +    grub_video_register (&grub_video_efi_adapter);
> +}
> +
> +GRUB_MOD_FINI(efi_fb)
> +{
> +  if ((gop) || (uga))
> +    grub_video_unregister (&grub_video_efi_adapter);
> +}
> -- 
> 1.5.5.1015.g9d258.dirty
> 

> _______________________________________________
> Grub-devel mailing list
> address@hidden
> http://lists.gnu.org/mailman/listinfo/grub-devel


-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."




reply via email to

[Prev in Thread] Current Thread [Next in Thread]