source: grub-pc/trunk/fuentes/grub-core/video/efi_uga.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 8.9 KB
Line 
1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2005,2006,2007,2008,2009  Free Software Foundation, Inc.
4 *
5 *  GRUB is free software: you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  GRUB is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#define grub_video_render_target grub_video_fbrender_target
20
21#include <grub/err.h>
22#include <grub/types.h>
23#include <grub/dl.h>
24#include <grub/misc.h>
25#include <grub/mm.h>
26#include <grub/video.h>
27#include <grub/video_fb.h>
28#include <grub/efi/api.h>
29#include <grub/efi/efi.h>
30#include <grub/efi/uga_draw.h>
31#include <grub/pci.h>
32
33GRUB_MOD_LICENSE ("GPLv3+");
34
35static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
36static struct grub_efi_uga_draw_protocol *uga;
37static grub_uint32_t uga_fb;
38static grub_uint32_t uga_pitch;
39
40static struct
41{
42  struct grub_video_mode_info mode_info;
43  struct grub_video_render_target *render_target;
44  grub_uint8_t *ptr;
45} framebuffer;
46
47#define RGB_MASK        0xffffff
48#define RGB_MAGIC       0x121314
49#define LINE_MIN        800
50#define LINE_MAX        4096
51#define FBTEST_STEP     (0x10000 >> 2)
52#define FBTEST_COUNT    8
53
54static int
55find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
56{
57  grub_uint32_t *base = (grub_uint32_t *) (grub_addr_t) *fb_base;
58  int i;
59
60  for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
61    {
62      if ((*base & RGB_MASK) == RGB_MAGIC)
63        {
64          int j;
65
66          for (j = LINE_MIN; j <= LINE_MAX; j++)
67            {
68              if ((base[j] & RGB_MASK) == RGB_MAGIC)
69                {
70                  *fb_base = (grub_uint32_t) (grub_addr_t) base;
71                  *line_len = j << 2;
72
73                  return 1;
74                }
75            }
76
77          break;
78        }
79    }
80
81  return 0;
82}
83
84/* Context for find_framebuf.  */
85struct find_framebuf_ctx
86{
87  grub_uint32_t *fb_base;
88  grub_uint32_t *line_len;
89  int found;
90};
91
92/* Helper for find_framebuf.  */
93static int
94find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
95{
96  struct find_framebuf_ctx *ctx = data;
97  grub_pci_address_t addr;
98
99  addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
100  if (grub_pci_read (addr) >> 24 == 0x3)
101    {
102      int i;
103
104      grub_dprintf ("fb", "Display controller: %d:%d.%d\nDevice id: %x\n",
105                    grub_pci_get_bus (dev), grub_pci_get_device (dev),
106                    grub_pci_get_function (dev), pciid);
107      addr += 8;
108      for (i = 0; i < 6; i++, addr += 4)
109        {
110          grub_uint32_t old_bar1, old_bar2, type;
111          grub_uint64_t base64;
112
113          old_bar1 = grub_pci_read (addr);
114          if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
115            continue;
116
117          type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
118          if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
119            {
120              if (i == 5)
121                break;
122
123              old_bar2 = grub_pci_read (addr + 4);
124            }
125          else
126            old_bar2 = 0;
127
128          base64 = old_bar2;
129          base64 <<= 32;
130          base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
131
132          grub_dprintf ("fb", "%s(%d): 0x%llx\n",
133                        ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
134                        "VMEM" : "MMIO"), i,
135                       (unsigned long long) base64);
136
137          if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! ctx->found))
138            {
139              *ctx->fb_base = base64;
140              if (find_line_len (ctx->fb_base, ctx->line_len))
141                ctx->found++;
142            }
143
144          if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
145            {
146              i++;
147              addr += 4;
148            }
149        }
150    }
151
152  return ctx->found;
153}
154
155static int
156find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
157{
158  struct find_framebuf_ctx ctx = {
159    .fb_base = fb_base,
160    .line_len = line_len,
161    .found = 0
162  };
163
164  grub_pci_iterate (find_card, &ctx);
165  return ctx.found;
166}
167
168static int
169check_protocol (void)
170{
171  grub_efi_uga_draw_protocol_t *c;
172
173  c = grub_efi_locate_protocol (&uga_draw_guid, 0);
174  if (c)
175    {
176      grub_uint32_t width, height, depth, rate, pixel;
177      int ret;
178
179      if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
180        return 0;
181
182      grub_efi_set_text_mode (0);
183      pixel = RGB_MAGIC;
184      efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
185                   GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
186      ret = find_framebuf (&uga_fb, &uga_pitch);
187      grub_efi_set_text_mode (1);
188
189      if (ret)
190        {
191          uga = c;
192          return 1;
193        }
194    }
195
196  return 0;
197}
198
199static grub_err_t
200grub_video_uga_init (void)
201{
202  grub_memset (&framebuffer, 0, sizeof(framebuffer));
203  return grub_video_fb_init ();
204}
205
206static grub_err_t
207grub_video_uga_fini (void)
208{
209  return grub_video_fb_fini ();
210}
211
212static grub_err_t
213grub_video_uga_setup (unsigned int width, unsigned int height,
214                      unsigned int mode_type,
215                      unsigned int mode_mask __attribute__ ((unused)))
216{
217  unsigned int depth;
218  int found = 0;
219
220  depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
221    >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
222
223  {
224    grub_uint32_t w;
225    grub_uint32_t h;
226    grub_uint32_t d;
227    grub_uint32_t r;
228
229    if ((! efi_call_5 (uga->get_mode, uga, &w, &h, &d, &r)) &&
230        ((! width) || (width == w)) &&
231        ((! height) || (height == h)) &&
232        ((! depth) || (depth == d)))
233      {
234        framebuffer.mode_info.width = w;
235        framebuffer.mode_info.height = h;
236        framebuffer.mode_info.pitch = uga_pitch;
237        framebuffer.ptr = (grub_uint8_t *) (grub_addr_t) uga_fb;
238
239        found = 1;
240      }
241  }
242
243  if (found)
244    {
245      grub_err_t err;
246
247      framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
248      framebuffer.mode_info.bpp = 32;
249      framebuffer.mode_info.bytes_per_pixel = 4;
250      framebuffer.mode_info.number_of_colors = 256;
251      framebuffer.mode_info.red_mask_size = 8;
252      framebuffer.mode_info.red_field_pos = 16;
253      framebuffer.mode_info.green_mask_size = 8;
254      framebuffer.mode_info.green_field_pos = 8;
255      framebuffer.mode_info.blue_mask_size = 8;
256      framebuffer.mode_info.blue_field_pos = 0;
257      framebuffer.mode_info.reserved_mask_size = 8;
258      framebuffer.mode_info.reserved_field_pos = 24;
259
260      framebuffer.mode_info.blit_format =
261        grub_video_get_blit_format (&framebuffer.mode_info);
262
263      err = grub_video_fb_create_render_target_from_pointer
264        (&framebuffer.render_target,
265         &framebuffer.mode_info,
266         framebuffer.ptr);
267
268      if (err)
269        return err;
270
271      err = grub_video_fb_set_active_render_target
272        (framebuffer.render_target);
273
274      if (err)
275        return err;
276
277      err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
278                                       grub_video_fbstd_colors);
279
280      return err;
281    }
282
283  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found");
284}
285
286static grub_err_t
287grub_video_uga_swap_buffers (void)
288{
289  /* TODO: Implement buffer swapping.  */
290  return GRUB_ERR_NONE;
291}
292
293static grub_err_t
294grub_video_uga_set_active_render_target (struct grub_video_render_target *target)
295{
296  if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY)
297    target = framebuffer.render_target;
298
299  return grub_video_fb_set_active_render_target (target);
300}
301
302static grub_err_t
303grub_video_uga_get_info_and_fini (struct grub_video_mode_info *mode_info,
304                                  void **framebuf)
305{
306  grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info));
307  *framebuf = (char *) framebuffer.ptr;
308
309  grub_video_fb_fini ();
310
311  return GRUB_ERR_NONE;
312}
313
314static struct grub_video_adapter grub_video_uga_adapter =
315  {
316    .name = "EFI UGA driver",
317    .id = GRUB_VIDEO_DRIVER_EFI_UGA,
318
319    .prio = GRUB_VIDEO_ADAPTER_PRIO_FIRMWARE_DIRTY,
320
321    .init = grub_video_uga_init,
322    .fini = grub_video_uga_fini,
323    .setup = grub_video_uga_setup,
324    .get_info = grub_video_fb_get_info,
325    .get_info_and_fini = grub_video_uga_get_info_and_fini,
326    .set_palette = grub_video_fb_set_palette,
327    .get_palette = grub_video_fb_get_palette,
328    .set_viewport = grub_video_fb_set_viewport,
329    .get_viewport = grub_video_fb_get_viewport,
330    .set_region = grub_video_fb_set_region,
331    .get_region = grub_video_fb_get_region,
332    .set_area_status = grub_video_fb_set_area_status,
333    .get_area_status = grub_video_fb_get_area_status,
334    .map_color = grub_video_fb_map_color,
335    .map_rgb = grub_video_fb_map_rgb,
336    .map_rgba = grub_video_fb_map_rgba,
337    .unmap_color = grub_video_fb_unmap_color,
338    .fill_rect = grub_video_fb_fill_rect,
339    .blit_bitmap = grub_video_fb_blit_bitmap,
340    .blit_render_target = grub_video_fb_blit_render_target,
341    .scroll = grub_video_fb_scroll,
342    .swap_buffers = grub_video_uga_swap_buffers,
343    .create_render_target = grub_video_fb_create_render_target,
344    .delete_render_target = grub_video_fb_delete_render_target,
345    .set_active_render_target = grub_video_uga_set_active_render_target,
346    .get_active_render_target = grub_video_fb_get_active_render_target,
347  };
348
349GRUB_MOD_INIT(efi_uga)
350{
351  if (check_protocol ())
352    grub_video_register (&grub_video_uga_adapter);
353}
354
355GRUB_MOD_FINI(efi_uga)
356{
357  if (uga)
358    grub_video_unregister (&grub_video_uga_adapter);
359}
Note: See TracBrowser for help on using the repository browser.