~psusi/ubuntu/saucy/grub2/fix-dmraid

« back to all changes in this revision

Viewing changes to .pc/blacklist_1440x900x32.patch/grub-core/video/i386/pc/vbe.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2013-01-03 11:40:44 UTC
  • mfrom: (17.6.31 experimental)
  • Revision ID: package-import@ubuntu.com-20130103114044-et8gar9lol415wc9
Tags: 2.00-10ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme and an appropriate background for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel option.
  - Bypass menu unless other OSes are installed or Shift is pressed.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Reduce visual clutter in normal mode.
  - Remove verbose messages printed before reading configuration.
  - Suppress kernel/initrd progress messages, except in recovery mode.
  - Show the boot menu if the previous boot failed.
  - Adjust upgrade version checks for Ubuntu.
  - Suppress "GRUB loading" message unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Check hardware support before using gfxpayload=keep.
  - Set vt.handoff=7 for smooth handoff to kernel graphical mode.
  - In recovery mode, add nomodeset to the Linux kernel arguments, and
    remove the 'set gfxpayload=keep' command.
  - Skip Windows os-prober entries on Wubi systems, and suppress the menu
    by default if those are the only other-OS entries.
  - Handle probing striped DM-RAID devices.
  - Replace 'single' by 'recovery' when friendly-recovery is installed.
  - Disable cursor as early as possible in grub_main.
  - Apply patch from Fedora to add a "linuxefi" loader.
  - Automatically call linuxefi from linux when necessary.
  - On amd64, add raw-uefi custom upload tarballs for signing.
  - Generate configuration for signed UEFI kernels if available.
  - Install signed images if UEFI Secure Boot is enabled.
  - Output a menu entry for firmware setup on UEFI FastBoot systems.
  - Stop using the /usr/share/images/desktop-base/desktop-grub.png
    alternative as the fallback background.
  - If the postinst is running in a container, skip grub-install and all
    its associated questions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/machine/memory.h>
 
23
#include <grub/i386/pc/vbe.h>
 
24
#include <grub/video_fb.h>
 
25
#include <grub/types.h>
 
26
#include <grub/dl.h>
 
27
#include <grub/misc.h>
 
28
#include <grub/mm.h>
 
29
#include <grub/video.h>
 
30
#include <grub/i386/pc/int.h>
 
31
#include <grub/i18n.h>
 
32
#include <grub/cpu/tsc.h>
 
33
 
 
34
GRUB_MOD_LICENSE ("GPLv3+");
 
35
 
 
36
static int vbe_detected = -1;
 
37
 
 
38
static struct grub_vbe_info_block controller_info;
 
39
 
 
40
/* Track last mode to support cards which fail on get_mode.  */
 
41
static grub_uint32_t last_set_mode = 3;
 
42
 
 
43
static struct
 
44
{
 
45
  struct grub_video_mode_info mode_info;
 
46
 
 
47
  grub_uint8_t *ptr;
 
48
  int mtrr;
 
49
} framebuffer;
 
50
 
 
51
static grub_uint32_t initial_vbe_mode;
 
52
static grub_uint16_t *vbe_mode_list;
 
53
 
 
54
static void *
 
55
real2pm (grub_vbe_farptr_t ptr)
 
56
{
 
57
  return (void *) ((((unsigned long) ptr & 0xFFFF0000) >> 12UL)
 
58
                   + ((unsigned long) ptr & 0x0000FFFF));
 
59
}
 
60
 
 
61
#define cpuid(num,a,b,c,d) \
 
62
  asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
 
63
                : "=a" (a), "=r" (b), "=c" (c), "=d" (d)  \
 
64
                : "0" (num))
 
65
 
 
66
#define rdmsr(num,a,d) \
 
67
  asm volatile ("rdmsr" : "=a" (a), "=d" (d) : "c" (num))
 
68
 
 
69
#define wrmsr(num,lo,hi) \
 
70
  asm volatile ("wrmsr" : : "c" (num), "a" (lo), "d" (hi) : "memory")
 
71
 
 
72
#define mtrr_base(reg) (0x200 + (reg) * 2)
 
73
#define mtrr_mask(reg) (0x200 + (reg) * 2 + 1)
 
74
 
 
75
/* Try to set up a variable-range write-combining MTRR for a memory region.
 
76
   This is best-effort; if it seems too hard, we just accept the performance
 
77
   degradation rather than risking undefined behaviour.  It is intended
 
78
   exclusively to work around BIOS bugs, as the BIOS should already be
 
79
   setting up a suitable MTRR.  */
 
80
static void
 
81
grub_vbe_enable_mtrr_entry (int mtrr)
 
82
{
 
83
  grub_uint32_t eax, edx;
 
84
  grub_uint32_t mask_lo, mask_hi;
 
85
 
 
86
  rdmsr (mtrr_mask (mtrr), eax, edx);
 
87
  mask_lo = eax;
 
88
  mask_hi = edx;
 
89
 
 
90
  mask_lo |= 0x800 /* valid */;
 
91
  wrmsr (mtrr_mask (mtrr), mask_lo, mask_hi);
 
92
}
 
93
 
 
94
static void
 
95
grub_vbe_enable_mtrr (grub_uint8_t *base, grub_size_t size)
 
96
{
 
97
  grub_uint32_t eax, ebx, ecx, edx;
 
98
  grub_uint32_t features;
 
99
  grub_uint32_t mtrrcap;
 
100
  int var_mtrrs;
 
101
  grub_uint32_t max_extended_cpuid;
 
102
  grub_uint32_t maxphyaddr;
 
103
  grub_uint64_t fb_base, fb_size;
 
104
  grub_uint64_t size_bits, fb_mask;
 
105
  grub_uint32_t bits_lo, bits_hi;
 
106
  grub_uint64_t bits;
 
107
  int i, first_unused = -1;
 
108
  grub_uint32_t base_lo, base_hi, mask_lo, mask_hi;
 
109
 
 
110
  fb_base = (grub_uint64_t) (grub_size_t) base;
 
111
  fb_size = (grub_uint64_t) size;
 
112
 
 
113
  /* Check that fb_base and fb_size can be represented using a single
 
114
     MTRR.  */
 
115
 
 
116
  if (fb_base < (1 << 20))
 
117
    return; /* under 1MB, so covered by fixed-range MTRRs */
 
118
  if (fb_base >= (1LL << 36))
 
119
    return; /* over 36 bits, so out of range */
 
120
  if (fb_size < (1 << 12))
 
121
    return; /* variable-range MTRRs must cover at least 4KB */
 
122
 
 
123
  size_bits = fb_size;
 
124
  while (size_bits > 1)
 
125
    size_bits >>= 1;
 
126
  if (size_bits != 1)
 
127
    return; /* not a power of two */
 
128
 
 
129
  if (fb_base & (fb_size - 1))
 
130
    return; /* not aligned on size boundary */
 
131
 
 
132
  fb_mask = ~(fb_size - 1);
 
133
 
 
134
  /* Check CPU capabilities.  */
 
135
 
 
136
  if (! grub_cpu_is_cpuid_supported ())
 
137
    return;
 
138
 
 
139
  cpuid (1, eax, ebx, ecx, edx);
 
140
  features = edx;
 
141
  if (! (features & 0x00001000)) /* MTRR */
 
142
    return;
 
143
 
 
144
  rdmsr (0xFE, eax, edx);
 
145
  mtrrcap = eax;
 
146
  if (! (mtrrcap & 0x00000400)) /* write-combining */
 
147
    return;
 
148
  var_mtrrs = (mtrrcap & 0xFF);
 
149
 
 
150
  cpuid (0x80000000, eax, ebx, ecx, edx);
 
151
  max_extended_cpuid = eax;
 
152
  if (max_extended_cpuid >= 0x80000008)
 
153
    {
 
154
      cpuid (0x80000008, eax, ebx, ecx, edx);
 
155
      maxphyaddr = (eax & 0xFF);
 
156
    }
 
157
  else
 
158
    maxphyaddr = 36;
 
159
  bits_lo = 0xFFFFF000; /* assume maxphyaddr >= 36 */
 
160
  bits_hi = (1 << (maxphyaddr - 32)) - 1;
 
161
  bits = bits_lo | ((grub_uint64_t) bits_hi << 32);
 
162
 
 
163
  /* Check whether an MTRR already covers this region.  If not, take an
 
164
     unused one if possible.  */
 
165
  for (i = 0; i < var_mtrrs; i++)
 
166
    {
 
167
      rdmsr (mtrr_mask (i), eax, edx);
 
168
      mask_lo = eax;
 
169
      mask_hi = edx;
 
170
      if (mask_lo & 0x800) /* valid */
 
171
        {
 
172
          grub_uint64_t real_base, real_mask;
 
173
 
 
174
          rdmsr (mtrr_base (i), eax, edx);
 
175
          base_lo = eax;
 
176
          base_hi = edx;
 
177
 
 
178
          real_base = ((grub_uint64_t) (base_hi & bits_hi) << 32) |
 
179
                      (base_lo & bits_lo);
 
180
          real_mask = ((grub_uint64_t) (mask_hi & bits_hi) << 32) |
 
181
                       (mask_lo & bits_lo);
 
182
          if (real_base < (fb_base + fb_size) &&
 
183
              real_base + (~real_mask & bits) >= fb_base)
 
184
            return; /* existing MTRR overlaps this region */
 
185
        }
 
186
      else if (first_unused < 0)
 
187
        first_unused = i;
 
188
    }
 
189
 
 
190
  if (first_unused < 0)
 
191
    return; /* all MTRRs in use */
 
192
 
 
193
  /* Set up the first unused MTRR we found.  */
 
194
  rdmsr (mtrr_base (first_unused), eax, edx);
 
195
  base_lo = eax;
 
196
  base_hi = edx;
 
197
  rdmsr (mtrr_mask (first_unused), eax, edx);
 
198
  mask_lo = eax;
 
199
  mask_hi = edx;
 
200
 
 
201
  base_lo = (base_lo & ~bits_lo & ~0xFF) |
 
202
            (fb_base & bits_lo) | 0x01 /* WC */;
 
203
  base_hi = (base_hi & ~bits_hi) | ((fb_base >> 32) & bits_hi);
 
204
  wrmsr (mtrr_base (first_unused), base_lo, base_hi);
 
205
  mask_lo = (mask_lo & ~bits_lo) | (fb_mask & bits_lo) | 0x800 /* valid */;
 
206
  mask_hi = (mask_hi & ~bits_hi) | ((fb_mask >> 32) & bits_hi);
 
207
  wrmsr (mtrr_mask (first_unused), mask_lo, mask_hi);
 
208
 
 
209
  framebuffer.mtrr = first_unused;
 
210
}
 
211
 
 
212
static void
 
213
grub_vbe_disable_mtrr (int mtrr)
 
214
{
 
215
  grub_uint32_t eax, edx;
 
216
  grub_uint32_t mask_lo, mask_hi;
 
217
 
 
218
  rdmsr (mtrr_mask (mtrr), eax, edx);
 
219
  mask_lo = eax;
 
220
  mask_hi = edx;
 
221
 
 
222
  mask_lo &= ~0x800 /* valid */;
 
223
  wrmsr (mtrr_mask (mtrr), mask_lo, mask_hi);
 
224
}
 
225
 
 
226
/* Call VESA BIOS 0x4f09 to set palette data, return status.  */
 
227
static grub_vbe_status_t 
 
228
grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
 
229
                                grub_uint32_t start_index,
 
230
                                struct grub_vbe_palette_data *palette_data)
 
231
{
 
232
  struct grub_bios_int_registers regs;
 
233
  regs.eax = 0x4f09;
 
234
  regs.ebx = 0;
 
235
  regs.ecx = color_count;
 
236
  regs.edx = start_index;
 
237
  regs.es = (((grub_addr_t) palette_data) & 0xffff0000) >> 4;
 
238
  regs.edi = ((grub_addr_t) palette_data) & 0xffff;
 
239
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
240
  grub_bios_interrupt (0x10, &regs);
 
241
  return regs.eax & 0xffff;
 
242
}
 
243
 
 
244
/* Call VESA BIOS 0x4f00 to get VBE Controller Information, return status.  */
 
245
grub_vbe_status_t 
 
246
grub_vbe_bios_get_controller_info (struct grub_vbe_info_block *ci)
 
247
{
 
248
  struct grub_bios_int_registers regs;
 
249
  /* Store *controller_info to %es:%di.  */
 
250
  regs.es = (((grub_addr_t) ci) & 0xffff0000) >> 4;
 
251
  regs.edi = ((grub_addr_t) ci) & 0xffff;
 
252
  regs.eax = 0x4f00;
 
253
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
254
  grub_bios_interrupt (0x10, &regs);
 
255
  return regs.eax & 0xffff;
 
256
}
 
257
 
 
258
/* Call VESA BIOS 0x4f01 to get VBE Mode Information, return status.  */
 
259
grub_vbe_status_t 
 
260
grub_vbe_bios_get_mode_info (grub_uint32_t mode,
 
261
                             struct grub_vbe_mode_info_block *mode_info)
 
262
{
 
263
  struct grub_bios_int_registers regs;
 
264
  regs.eax = 0x4f01;
 
265
  regs.ecx = mode;
 
266
  /* Store *mode_info to %es:%di.  */
 
267
  regs.es = ((grub_addr_t) mode_info & 0xffff0000) >> 4;
 
268
  regs.edi = (grub_addr_t) mode_info & 0x0000ffff;
 
269
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
270
  grub_bios_interrupt (0x10, &regs);
 
271
  return regs.eax & 0xffff;
 
272
}
 
273
 
 
274
/* Call VESA BIOS 0x4f02 to set video mode, return status.  */
 
275
static grub_vbe_status_t
 
276
grub_vbe_bios_set_mode (grub_uint32_t mode,
 
277
                        struct grub_vbe_crtc_info_block *crtc_info)
 
278
{
 
279
  struct grub_bios_int_registers regs;
 
280
 
 
281
  regs.eax = 0x4f02;
 
282
  regs.ebx = mode;
 
283
  /* Store *crtc_info to %es:%di.  */
 
284
  regs.es = (((grub_addr_t) crtc_info) & 0xffff0000) >> 4;
 
285
  regs.edi = ((grub_addr_t) crtc_info) & 0xffff;
 
286
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
287
  grub_bios_interrupt (0x10, &regs);
 
288
 
 
289
  return regs.eax & 0xffff;
 
290
}
 
291
 
 
292
/* Call VESA BIOS 0x4f03 to return current VBE Mode, return status.  */
 
293
grub_vbe_status_t 
 
294
grub_vbe_bios_get_mode (grub_uint32_t *mode)
 
295
{
 
296
  struct grub_bios_int_registers regs;
 
297
 
 
298
  regs.eax = 0x4f03;
 
299
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
300
  grub_bios_interrupt (0x10, &regs);
 
301
  *mode = regs.ebx & 0xffff;
 
302
 
 
303
  return regs.eax & 0xffff;
 
304
}
 
305
 
 
306
grub_vbe_status_t 
 
307
grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size)
 
308
{
 
309
  struct grub_bios_int_registers regs;
 
310
 
 
311
  regs.eax = 0x4f08;
 
312
  regs.ebx = (*dac_mask_size & 0xff) >> 8;
 
313
  regs.ebx = set ? 1 : 0;
 
314
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
315
  grub_bios_interrupt (0x10, &regs);
 
316
  *dac_mask_size = (regs.ebx >> 8) & 0xff;
 
317
 
 
318
  return regs.eax & 0xffff;
 
319
}
 
320
 
 
321
/* Call VESA BIOS 0x4f05 to set memory window, return status.  */
 
322
grub_vbe_status_t
 
323
grub_vbe_bios_set_memory_window (grub_uint32_t window,
 
324
                                 grub_uint32_t position)
 
325
{
 
326
  struct grub_bios_int_registers regs;
 
327
 
 
328
  /* BL = window, BH = 0, Set memory window.  */
 
329
  regs.ebx = window & 0x00ff;
 
330
  regs.edx = position;
 
331
  regs.eax = 0x4f05;
 
332
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
333
  grub_bios_interrupt (0x10, &regs);
 
334
  return regs.eax & 0xffff;
 
335
}
 
336
 
 
337
/* Call VESA BIOS 0x4f05 to return memory window, return status.  */
 
338
grub_vbe_status_t
 
339
grub_vbe_bios_get_memory_window (grub_uint32_t window,
 
340
                                 grub_uint32_t *position)
 
341
{
 
342
  struct grub_bios_int_registers regs;
 
343
 
 
344
  regs.eax = 0x4f05;
 
345
  /* BH = 1, Get memory window. BL = window.  */
 
346
  regs.ebx = (window & 0x00ff) | 0x100;
 
347
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
348
  grub_bios_interrupt (0x10, &regs);
 
349
 
 
350
  *position = regs.edx & 0xffff;
 
351
  return regs.eax & 0xffff;
 
352
}
 
353
 
 
354
/* Call VESA BIOS 0x4f06 to set scanline length (in bytes), return status.  */
 
355
grub_vbe_status_t 
 
356
grub_vbe_bios_set_scanline_length (grub_uint32_t length)
 
357
{
 
358
  struct grub_bios_int_registers regs;
 
359
 
 
360
  regs.ecx = length;
 
361
  regs.eax = 0x4f06;
 
362
  /* BL = 2, Set Scan Line in Bytes.  */
 
363
  regs.ebx = 0x0002;    
 
364
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
365
  grub_bios_interrupt (0x10, &regs);
 
366
  return regs.eax & 0xffff;
 
367
}
 
368
 
 
369
/* Call VESA BIOS 0x4f06 to return scanline length (in bytes), return status.  */
 
370
grub_vbe_status_t 
 
371
grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
 
372
{
 
373
  struct grub_bios_int_registers regs;
 
374
 
 
375
  regs.eax = 0x4f06;
 
376
  regs.ebx = 0x0001;
 
377
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
378
  /* BL = 1, Get Scan Line Length (in bytes).  */
 
379
  grub_bios_interrupt (0x10, &regs);
 
380
 
 
381
  *length = regs.ebx & 0xffff;
 
382
  return regs.eax & 0xffff;
 
383
}
 
384
 
 
385
/* Call VESA BIOS 0x4f07 to set display start, return status.  */
 
386
static grub_vbe_status_t 
 
387
grub_vbe_bios_set_display_start (grub_uint32_t x, grub_uint32_t y)
 
388
{
 
389
  struct grub_bios_int_registers regs;
 
390
 
 
391
  if (framebuffer.mtrr >= 0)
 
392
    grub_vbe_disable_mtrr (framebuffer.mtrr);
 
393
 
 
394
  /* Store x in %ecx.  */
 
395
  regs.ecx = x;
 
396
  regs.edx = y;
 
397
  regs.eax = 0x4f07;
 
398
  /* BL = 80h, Set Display Start during Vertical Retrace.  */
 
399
  regs.ebx = 0x0080;    
 
400
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
401
  grub_bios_interrupt (0x10, &regs);
 
402
 
 
403
  if (framebuffer.mtrr >= 0)
 
404
    grub_vbe_enable_mtrr_entry (framebuffer.mtrr);
 
405
 
 
406
  return regs.eax & 0xffff;
 
407
}
 
408
 
 
409
/* Call VESA BIOS 0x4f07 to get display start, return status.  */
 
410
grub_vbe_status_t 
 
411
grub_vbe_bios_get_display_start (grub_uint32_t *x,
 
412
                                 grub_uint32_t *y)
 
413
{
 
414
  struct grub_bios_int_registers regs;
 
415
 
 
416
  regs.eax = 0x4f07;
 
417
  /* BL = 1, Get Display Start.  */
 
418
  regs.ebx = 0x0001;
 
419
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
420
  grub_bios_interrupt (0x10, &regs);
 
421
 
 
422
  *x = regs.ecx & 0xffff;
 
423
  *y = regs.edx & 0xffff;
 
424
  return regs.eax & 0xffff;
 
425
}
 
426
 
 
427
/* Call VESA BIOS 0x4f0a.  */
 
428
grub_vbe_status_t 
 
429
grub_vbe_bios_get_pm_interface (grub_uint16_t *segment, grub_uint16_t *offset,
 
430
                                grub_uint16_t *length)
 
431
{
 
432
  struct grub_bios_int_registers regs;
 
433
 
 
434
  regs.eax = 0x4f0a;
 
435
  regs.ebx = 0x0000;
 
436
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
437
  grub_bios_interrupt (0x10, &regs);
 
438
 
 
439
  if ((regs.eax & 0xffff) != GRUB_VBE_STATUS_OK)
 
440
    {
 
441
      *segment = 0;
 
442
      *offset = 0;
 
443
      *length = 0;
 
444
    }
 
445
 
 
446
  *segment = regs.es & 0xffff;
 
447
  *offset = regs.edi & 0xffff;
 
448
  *length = regs.ecx & 0xffff;
 
449
  return regs.eax & 0xffff;
 
450
}
 
451
 
 
452
/* Call VESA BIOS 0x4f11 to get flat panel information, return status.  */
 
453
static grub_vbe_status_t
 
454
grub_vbe_bios_get_flat_panel_info (struct grub_vbe_flat_panel_info *flat_panel_info)
 
455
{
 
456
  struct grub_bios_int_registers regs;
 
457
 
 
458
  regs.eax = 0x4f11;
 
459
  regs.ebx = 0x0001;
 
460
  regs.es = (((grub_addr_t) flat_panel_info) & 0xffff0000) >> 4;
 
461
  regs.edi = ((grub_addr_t) flat_panel_info) & 0xffff;
 
462
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
463
  grub_bios_interrupt (0x10, &regs);
 
464
  return regs.eax & 0xffff;
 
465
}
 
466
 
 
467
/* Call VESA BIOS 0x4f15 to get DDC availability, return status.  */
 
468
static grub_vbe_status_t
 
469
grub_vbe_bios_get_ddc_capabilities (grub_uint8_t *level)
 
470
{
 
471
  struct grub_bios_int_registers regs;
 
472
 
 
473
  regs.eax = 0x4f15;
 
474
  regs.ebx = 0x0000;
 
475
  regs.ecx = 0x0000;
 
476
  regs.es = 0x0000;
 
477
  regs.edi = 0x0000;
 
478
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
479
  grub_bios_interrupt (0x10, &regs);
 
480
 
 
481
  *level = regs.ebx & 0xff;
 
482
  return regs.eax & 0xffff;
 
483
}
 
484
 
 
485
/* Call VESA BIOS 0x4f15 to read EDID information, return status.  */
 
486
static grub_vbe_status_t
 
487
grub_vbe_bios_read_edid (struct grub_video_edid_info *edid_info)
 
488
{
 
489
  struct grub_bios_int_registers regs;
 
490
 
 
491
  regs.eax = 0x4f15;
 
492
  regs.ebx = 0x0001;
 
493
  regs.ecx = 0x0000;
 
494
  regs.edx = 0x0000;
 
495
  regs.es = (((grub_addr_t) edid_info) & 0xffff0000) >> 4;
 
496
  regs.edi = ((grub_addr_t) edid_info) & 0xffff;
 
497
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
498
  grub_bios_interrupt (0x10, &regs);
 
499
  return regs.eax & 0xffff;
 
500
}
 
501
 
 
502
grub_err_t
 
503
grub_vbe_probe (struct grub_vbe_info_block *info_block)
 
504
{
 
505
  struct grub_vbe_info_block *vbe_ib;
 
506
  grub_vbe_status_t status;
 
507
 
 
508
  /* Clear caller's controller info block.  */
 
509
  if (info_block)
 
510
    grub_memset (info_block, 0, sizeof (*info_block));
 
511
 
 
512
  /* Do not probe more than one time, if not necessary.  */
 
513
  if (vbe_detected == -1 || info_block)
 
514
    {
 
515
      /* Clear old copy of controller info block.  */
 
516
      grub_memset (&controller_info, 0, sizeof (controller_info));
 
517
 
 
518
      /* Mark VESA BIOS extension as undetected.  */
 
519
      vbe_detected = 0;
 
520
 
 
521
      /* Use low memory scratch area as temporary storage
 
522
         for VESA BIOS call.  */
 
523
      vbe_ib = (struct grub_vbe_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
 
524
 
 
525
      /* Prepare info block.  */
 
526
      grub_memset (vbe_ib, 0, sizeof (*vbe_ib));
 
527
 
 
528
      vbe_ib->signature[0] = 'V';
 
529
      vbe_ib->signature[1] = 'B';
 
530
      vbe_ib->signature[2] = 'E';
 
531
      vbe_ib->signature[3] = '2';
 
532
 
 
533
      /* Try to get controller info block.  */
 
534
      status = grub_vbe_bios_get_controller_info (vbe_ib);
 
535
      if (status == GRUB_VBE_STATUS_OK)
 
536
        {
 
537
          /* Copy it for later usage.  */
 
538
          grub_memcpy (&controller_info, vbe_ib, sizeof (controller_info));
 
539
 
 
540
          /* Mark VESA BIOS extension as detected.  */
 
541
          vbe_detected = 1;
 
542
        }
 
543
    }
 
544
 
 
545
  if (! vbe_detected)
 
546
    return grub_error (GRUB_ERR_BAD_DEVICE, "VESA BIOS Extension not found");
 
547
 
 
548
  /* Make copy of controller info block to caller.  */
 
549
  if (info_block)
 
550
    grub_memcpy (info_block, &controller_info, sizeof (*info_block));
 
551
 
 
552
  return GRUB_ERR_NONE;
 
553
}
 
554
 
 
555
static grub_err_t
 
556
grub_video_vbe_get_edid (struct grub_video_edid_info *edid_info)
 
557
{
 
558
  struct grub_video_edid_info *edid_info_lowmem;
 
559
 
 
560
  /* Use low memory scratch area as temporary storage for VESA BIOS calls.  */
 
561
  edid_info_lowmem =
 
562
    (struct grub_video_edid_info *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
 
563
  grub_memset (edid_info_lowmem, 0, sizeof (*edid_info_lowmem));
 
564
 
 
565
  if (grub_vbe_bios_read_edid (edid_info_lowmem) != GRUB_VBE_STATUS_OK)
 
566
    return grub_error (GRUB_ERR_BAD_DEVICE, "EDID information not available");
 
567
 
 
568
  grub_memcpy (edid_info, edid_info_lowmem, sizeof (*edid_info));
 
569
 
 
570
  return GRUB_ERR_NONE;
 
571
}
 
572
 
 
573
static grub_err_t
 
574
grub_vbe_get_preferred_mode (unsigned int *width, unsigned int *height)
 
575
{
 
576
  grub_vbe_status_t status;
 
577
  grub_uint8_t ddc_level;
 
578
  struct grub_video_edid_info edid_info;
 
579
  struct grub_vbe_flat_panel_info *flat_panel_info;
 
580
 
 
581
  /* Use low memory scratch area as temporary storage for VESA BIOS calls.  */
 
582
  flat_panel_info = (struct grub_vbe_flat_panel_info *)
 
583
    (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + sizeof (struct grub_video_edid_info));
 
584
 
 
585
  if (controller_info.version >= 0x200
 
586
      && (grub_vbe_bios_get_ddc_capabilities (&ddc_level) & 0xff)
 
587
         == GRUB_VBE_STATUS_OK)
 
588
    {
 
589
      if (grub_video_vbe_get_edid (&edid_info) == GRUB_ERR_NONE
 
590
          && grub_video_edid_checksum (&edid_info) == GRUB_ERR_NONE
 
591
          && grub_video_edid_preferred_mode (&edid_info, width, height)
 
592
              == GRUB_ERR_NONE && *width < 4096 && *height < 4096)
 
593
        return GRUB_ERR_NONE;
 
594
 
 
595
      grub_errno = GRUB_ERR_NONE;
 
596
    }
 
597
 
 
598
  grub_memset (flat_panel_info, 0, sizeof (*flat_panel_info));
 
599
  status = grub_vbe_bios_get_flat_panel_info (flat_panel_info);
 
600
  if (status == GRUB_VBE_STATUS_OK
 
601
      && flat_panel_info->horizontal_size && flat_panel_info->vertical_size
 
602
      && flat_panel_info->horizontal_size < 4096
 
603
      && flat_panel_info->vertical_size < 4096)
 
604
    {
 
605
      *width = flat_panel_info->horizontal_size;
 
606
      *height = flat_panel_info->vertical_size;
 
607
      return GRUB_ERR_NONE;
 
608
    }
 
609
 
 
610
  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot get preferred mode");
 
611
}
 
612
 
 
613
static grub_err_t
 
614
grub_vbe_set_video_mode (grub_uint32_t vbe_mode,
 
615
                         struct grub_vbe_mode_info_block *vbe_mode_info)
 
616
{
 
617
  grub_vbe_status_t status;
 
618
  grub_uint32_t old_vbe_mode;
 
619
  struct grub_vbe_mode_info_block new_vbe_mode_info;
 
620
  grub_err_t err;
 
621
 
 
622
  /* Make sure that VBE is supported.  */
 
623
  grub_vbe_probe (0);
 
624
  if (grub_errno != GRUB_ERR_NONE)
 
625
    return grub_errno;
 
626
 
 
627
  /* Try to get mode info.  */
 
628
  grub_vbe_get_video_mode_info (vbe_mode, &new_vbe_mode_info);
 
629
  if (grub_errno != GRUB_ERR_NONE)
 
630
    return grub_errno;
 
631
 
 
632
  /* For all VESA BIOS modes, force linear frame buffer.  */
 
633
  if (vbe_mode >= 0x100)
 
634
    {
 
635
      /* We only want linear frame buffer modes.  */
 
636
      vbe_mode |= 1 << 14;
 
637
 
 
638
      /* Determine frame buffer pixel format.  */
 
639
      if (new_vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL
 
640
          && new_vbe_mode_info.memory_model
 
641
          != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR)
 
642
        return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 
643
                           "unsupported pixel format 0x%x",
 
644
                           new_vbe_mode_info.memory_model);
 
645
    }
 
646
 
 
647
  /* Get current mode.  */
 
648
  grub_vbe_get_video_mode (&old_vbe_mode);
 
649
  if (grub_errno != GRUB_ERR_NONE)
 
650
    return grub_errno;
 
651
 
 
652
  /* Try to set video mode.  */
 
653
  status = grub_vbe_bios_set_mode (vbe_mode, 0);
 
654
  if (status != GRUB_VBE_STATUS_OK)
 
655
    return grub_error (GRUB_ERR_BAD_DEVICE, "cannot set VBE mode %x", vbe_mode);
 
656
  last_set_mode = vbe_mode;
 
657
 
 
658
  if (vbe_mode < 0x100)
 
659
    {
 
660
      /* If this is not a VESA mode, guess address.  */
 
661
      framebuffer.ptr = (grub_uint8_t *) 0xa0000;
 
662
    }
 
663
  else
 
664
    {
 
665
      framebuffer.ptr = (grub_uint8_t *) new_vbe_mode_info.phys_base_addr;
 
666
    }
 
667
 
 
668
  /* Check whether mode is text mode or graphics mode.  */
 
669
  if (new_vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
 
670
    {
 
671
      /* Text mode.  */
 
672
 
 
673
      /* No special action needed for text mode as it is not supported for
 
674
         graphical support.  */
 
675
    }
 
676
  else
 
677
    {
 
678
      /* Graphics mode.  */
 
679
 
 
680
      /* If video mode is in indexed color, setup default VGA palette.  */
 
681
      if (vbe_mode < 0x100 || new_vbe_mode_info.memory_model
 
682
          == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
 
683
        {
 
684
          struct grub_vbe_palette_data *palette
 
685
            = (struct grub_vbe_palette_data *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
 
686
          unsigned i;
 
687
 
 
688
          /* Make sure that the BIOS can reach the palette.  */
 
689
          for (i = 0; i < GRUB_VIDEO_FBSTD_NUMCOLORS; i++)
 
690
            {
 
691
              palette[i].red = grub_video_fbstd_colors[i].r;
 
692
              palette[i].green = grub_video_fbstd_colors[i].g;
 
693
              palette[i].blue = grub_video_fbstd_colors[i].b;
 
694
              palette[i].alignment = 0;
 
695
            }
 
696
 
 
697
          status = grub_vbe_bios_set_palette_data (GRUB_VIDEO_FBSTD_NUMCOLORS,
 
698
                                                   0, palette);
 
699
 
 
700
          /* Just ignore the status.  */
 
701
          err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
 
702
                                           grub_video_fbstd_colors);
 
703
          if (err)
 
704
            return err;
 
705
 
 
706
        }
 
707
    }
 
708
 
 
709
  /* Copy mode info for caller.  */
 
710
  if (vbe_mode_info)
 
711
    grub_memcpy (vbe_mode_info, &new_vbe_mode_info, sizeof (*vbe_mode_info));
 
712
 
 
713
  return GRUB_ERR_NONE;
 
714
}
 
715
 
 
716
grub_err_t
 
717
grub_vbe_get_video_mode (grub_uint32_t *mode)
 
718
{
 
719
  grub_vbe_status_t status;
 
720
 
 
721
  /* Make sure that VBE is supported.  */
 
722
  grub_vbe_probe (0);
 
723
  if (grub_errno != GRUB_ERR_NONE)
 
724
    return grub_errno;
 
725
 
 
726
  /* Try to query current mode from VESA BIOS.  */
 
727
  status = grub_vbe_bios_get_mode (mode);
 
728
  /* XXX: ATI cards don't support get_mode.  */
 
729
  if (status != GRUB_VBE_STATUS_OK)
 
730
    *mode = last_set_mode;
 
731
 
 
732
  return GRUB_ERR_NONE;
 
733
}
 
734
 
 
735
grub_err_t
 
736
grub_vbe_get_video_mode_info (grub_uint32_t mode,
 
737
                              struct grub_vbe_mode_info_block *mode_info)
 
738
{
 
739
  struct grub_vbe_mode_info_block *mi_tmp
 
740
    = (struct grub_vbe_mode_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
 
741
  grub_vbe_status_t status;
 
742
 
 
743
  /* Make sure that VBE is supported.  */
 
744
  grub_vbe_probe (0);
 
745
  if (grub_errno != GRUB_ERR_NONE)
 
746
    return grub_errno;
 
747
 
 
748
  /* If mode is not VESA mode, skip mode info query.  */
 
749
  if (mode >= 0x100)
 
750
    {
 
751
      /* Try to get mode info from VESA BIOS.  */
 
752
      status = grub_vbe_bios_get_mode_info (mode, mi_tmp);
 
753
      if (status != GRUB_VBE_STATUS_OK)
 
754
        return grub_error (GRUB_ERR_BAD_DEVICE,
 
755
                           "cannot get information on the mode %x", mode);
 
756
 
 
757
      /* Make copy of mode info block.  */
 
758
      grub_memcpy (mode_info, mi_tmp, sizeof (*mode_info));
 
759
    }
 
760
  else
 
761
    /* Just clear mode info block if it isn't a VESA mode.  */
 
762
    grub_memset (mode_info, 0, sizeof (*mode_info));
 
763
 
 
764
  return GRUB_ERR_NONE;
 
765
}
 
766
 
 
767
static grub_err_t
 
768
grub_video_vbe_init (void)
 
769
{
 
770
  grub_uint16_t *rm_vbe_mode_list;
 
771
  grub_uint16_t *p;
 
772
  grub_size_t vbe_mode_list_size;
 
773
  struct grub_vbe_info_block info_block;
 
774
 
 
775
  /* Check if there is adapter present.
 
776
 
 
777
     Firmware note: There has been a report that some cards store video mode
 
778
     list in temporary memory.  So we must first use vbe probe to get
 
779
     refreshed information to receive valid pointers and data, and then
 
780
     copy this information to somewhere safe.  */
 
781
  grub_vbe_probe (&info_block);
 
782
  if (grub_errno != GRUB_ERR_NONE)
 
783
    return grub_errno;
 
784
 
 
785
  /* Copy modelist to local memory.  */
 
786
  p = rm_vbe_mode_list = real2pm (info_block.video_mode_ptr);
 
787
  while(*p++ != 0xFFFF)
 
788
    ;
 
789
 
 
790
  vbe_mode_list_size = (grub_addr_t) p - (grub_addr_t) rm_vbe_mode_list;
 
791
  vbe_mode_list = grub_malloc (vbe_mode_list_size);
 
792
  if (! vbe_mode_list)
 
793
    return grub_errno;
 
794
  grub_memcpy (vbe_mode_list, rm_vbe_mode_list, vbe_mode_list_size);
 
795
 
 
796
  /* Adapter could be found, figure out initial video mode.  */
 
797
  grub_vbe_get_video_mode (&initial_vbe_mode);
 
798
  if (grub_errno != GRUB_ERR_NONE)
 
799
    {
 
800
      /* Free allocated resources.  */
 
801
      grub_free (vbe_mode_list);
 
802
      vbe_mode_list = NULL;
 
803
 
 
804
      return grub_errno;
 
805
    }
 
806
 
 
807
  /* Reset frame buffer.  */
 
808
  grub_memset (&framebuffer, 0, sizeof(framebuffer));
 
809
  framebuffer.mtrr = -1;
 
810
 
 
811
  return grub_video_fb_init ();
 
812
}
 
813
 
 
814
static grub_err_t
 
815
grub_video_vbe_fini (void)
 
816
{
 
817
  grub_vbe_status_t status;
 
818
  grub_err_t err;
 
819
 
 
820
  /* Restore old video mode.  */
 
821
  if (last_set_mode != initial_vbe_mode)
 
822
    {
 
823
      status = grub_vbe_bios_set_mode (initial_vbe_mode, 0);
 
824
      if (status != GRUB_VBE_STATUS_OK)
 
825
        /* TODO: Decide, is this something we want to do.  */
 
826
        return grub_errno;
 
827
    }
 
828
  last_set_mode = initial_vbe_mode;
 
829
 
 
830
  /* TODO: Free any resources allocated by driver.  */
 
831
  grub_free (vbe_mode_list);
 
832
  vbe_mode_list = NULL;
 
833
 
 
834
  err = grub_video_fb_fini ();
 
835
  if (framebuffer.mtrr >= 0)
 
836
    {
 
837
      grub_vbe_disable_mtrr (framebuffer.mtrr);
 
838
      framebuffer.mtrr = -1;
 
839
    }
 
840
  return err;
 
841
}
 
842
 
 
843
/*
 
844
  Set framebuffer render target page and display the proper page, based on
 
845
  `doublebuf_state.render_page' and `doublebuf_state.displayed_page',
 
846
  respectively.
 
847
*/
 
848
static grub_err_t
 
849
doublebuf_pageflipping_set_page (int page)
 
850
{
 
851
  /* Tell the video adapter to display the new front page.  */
 
852
  int display_start_line
 
853
    = framebuffer.mode_info.height * page;
 
854
 
 
855
  grub_vbe_status_t vbe_err =
 
856
    grub_vbe_bios_set_display_start (0, display_start_line);
 
857
 
 
858
  if (vbe_err != GRUB_VBE_STATUS_OK)
 
859
    return grub_error (GRUB_ERR_IO, "couldn't commit pageflip");
 
860
 
 
861
  return 0;
 
862
}
 
863
 
 
864
static void
 
865
vbe2videoinfo (grub_uint32_t mode,
 
866
               const struct grub_vbe_mode_info_block *vbeinfo,
 
867
               struct grub_video_mode_info *mode_info)
 
868
{
 
869
  mode_info->mode_number = mode;
 
870
 
 
871
  mode_info->width = vbeinfo->x_resolution;
 
872
  mode_info->height = vbeinfo->y_resolution;
 
873
  mode_info->mode_type = 0;
 
874
  switch (vbeinfo->memory_model)
 
875
    {
 
876
    case GRUB_VBE_MEMORY_MODEL_TEXT:
 
877
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_PURE_TEXT;
 
878
      break;
 
879
 
 
880
      /* CGA is basically 4-bit packed pixel.  */
 
881
    case GRUB_VBE_MEMORY_MODEL_CGA:
 
882
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_CGA;
 
883
    case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL:
 
884
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
 
885
      break;
 
886
 
 
887
    case GRUB_VBE_MEMORY_MODEL_HERCULES:
 
888
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_HERCULES
 
889
        | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP;
 
890
      break;
 
891
 
 
892
      /* Non chain 4 is a special case of planar.  */
 
893
    case GRUB_VBE_MEMORY_MODEL_NONCHAIN4_256:
 
894
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_NONCHAIN4;
 
895
    case GRUB_VBE_MEMORY_MODEL_PLANAR:
 
896
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_PLANAR
 
897
        | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
 
898
      break;
 
899
 
 
900
    case GRUB_VBE_MEMORY_MODEL_YUV:
 
901
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_YUV;
 
902
      break;
 
903
      
 
904
    case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR:
 
905
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_RGB;
 
906
      break;
 
907
    default:
 
908
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UNKNOWN;
 
909
      break;
 
910
    }
 
911
 
 
912
  mode_info->bpp = vbeinfo->bits_per_pixel;
 
913
  /* Calculate bytes_per_pixel value.  */
 
914
  switch(vbeinfo->bits_per_pixel)
 
915
    {
 
916
    case 32:
 
917
      mode_info->bytes_per_pixel = 4;
 
918
      break;
 
919
    case 24:
 
920
      mode_info->bytes_per_pixel = 3;
 
921
      break;
 
922
    case 16:
 
923
      mode_info->bytes_per_pixel = 2;
 
924
      break;
 
925
    case 15:
 
926
      mode_info->bytes_per_pixel = 2;
 
927
      break;
 
928
    case 8:
 
929
      mode_info->bytes_per_pixel = 1;
 
930
      break;  
 
931
    case 4:
 
932
      mode_info->bytes_per_pixel = 0;
 
933
      break;  
 
934
    }
 
935
 
 
936
  if (controller_info.version >= 0x300)
 
937
    mode_info->pitch = vbeinfo->lin_bytes_per_scan_line;
 
938
  else
 
939
    mode_info->pitch = vbeinfo->bytes_per_scan_line;
 
940
 
 
941
  mode_info->number_of_colors = 256; /* TODO: fix me.  */
 
942
  mode_info->red_mask_size = vbeinfo->red_mask_size;
 
943
  mode_info->red_field_pos = vbeinfo->red_field_position;
 
944
  mode_info->green_mask_size = vbeinfo->green_mask_size;
 
945
  mode_info->green_field_pos = vbeinfo->green_field_position;
 
946
  mode_info->blue_mask_size = vbeinfo->blue_mask_size;
 
947
  mode_info->blue_field_pos = vbeinfo->blue_field_position;
 
948
  mode_info->reserved_mask_size = vbeinfo->rsvd_mask_size;
 
949
  mode_info->reserved_field_pos = vbeinfo->rsvd_field_position;
 
950
 
 
951
  mode_info->blit_format = grub_video_get_blit_format (mode_info);
 
952
}
 
953
 
 
954
static int
 
955
grub_video_vbe_iterate (int (*hook) (const struct grub_video_mode_info *info))
 
956
{
 
957
  grub_uint16_t *p;
 
958
  struct grub_vbe_mode_info_block vbe_mode_info;
 
959
  struct grub_video_mode_info mode_info;
 
960
 
 
961
  for (p = vbe_mode_list; *p != 0xFFFF; p++)
 
962
    {
 
963
      grub_vbe_get_video_mode_info (*p, &vbe_mode_info);
 
964
      if (grub_errno != GRUB_ERR_NONE)
 
965
        {
 
966
          /* Could not retrieve mode info, retreat.  */
 
967
          grub_errno = GRUB_ERR_NONE;
 
968
          break;
 
969
        }
 
970
 
 
971
      vbe2videoinfo (*p, &vbe_mode_info, &mode_info);
 
972
      if (hook (&mode_info))
 
973
        return 1;
 
974
    }
 
975
  return 0;
 
976
}
 
977
 
 
978
static grub_err_t
 
979
grub_video_vbe_setup (unsigned int width, unsigned int height,
 
980
                      grub_video_mode_type_t mode_type, 
 
981
                      grub_video_mode_type_t mode_mask)
 
982
{
 
983
  grub_uint16_t *p;
 
984
  struct grub_vbe_mode_info_block vbe_mode_info;
 
985
  struct grub_vbe_mode_info_block best_vbe_mode_info;
 
986
  grub_uint32_t best_vbe_mode = 0;
 
987
  int depth;
 
988
  int preferred_mode = 0;
 
989
 
 
990
  /* Decode depth from mode_type.  If it is zero, then autodetect.  */
 
991
  depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
 
992
          >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
 
993
 
 
994
  if (width == 0 && height == 0)
 
995
    {
 
996
      grub_vbe_get_preferred_mode (&width, &height);
 
997
      if (grub_errno == GRUB_ERR_NONE)
 
998
        preferred_mode = 1;
 
999
      else
 
1000
        {
 
1001
          /* Fall back to 640x480.  This is conservative, but the largest
 
1002
             mode supported by the graphics card may not be safe for the
 
1003
             display device.  */
 
1004
          grub_errno = GRUB_ERR_NONE;
 
1005
          width = 640;
 
1006
          height = 480;
 
1007
        }
 
1008
    }
 
1009
 
 
1010
  /* Walk thru mode list and try to find matching mode.  */
 
1011
  for (p = vbe_mode_list; *p != 0xFFFF; p++)
 
1012
    {
 
1013
      grub_uint32_t vbe_mode = *p;
 
1014
 
 
1015
      grub_vbe_get_video_mode_info (vbe_mode, &vbe_mode_info);
 
1016
      if (grub_errno != GRUB_ERR_NONE)
 
1017
        {
 
1018
          /* Could not retrieve mode info, retreat.  */
 
1019
          grub_errno = GRUB_ERR_NONE;
 
1020
          break;
 
1021
        }
 
1022
 
 
1023
      if ((vbe_mode_info.mode_attributes & 0x001) == 0)
 
1024
        /* If not available, skip it.  */
 
1025
        continue;
 
1026
 
 
1027
      if ((vbe_mode_info.mode_attributes & 0x008) == 0)
 
1028
        /* Monochrome is unusable.  */
 
1029
        continue;
 
1030
 
 
1031
      if ((vbe_mode_info.mode_attributes & 0x080) == 0)
 
1032
        /* We support only linear frame buffer modes.  */
 
1033
        continue;
 
1034
 
 
1035
      if ((vbe_mode_info.mode_attributes & 0x010) == 0)
 
1036
        /* We allow only graphical modes.  */
 
1037
        continue;
 
1038
 
 
1039
      if ((vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
 
1040
          && (vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR))
 
1041
        /* Not compatible memory model.  */
 
1042
        continue;
 
1043
 
 
1044
      if (vbe_mode_info.bits_per_pixel != 8
 
1045
          && vbe_mode_info.bits_per_pixel != 15
 
1046
          && vbe_mode_info.bits_per_pixel != 16
 
1047
          && vbe_mode_info.bits_per_pixel != 24
 
1048
          && vbe_mode_info.bits_per_pixel != 32)
 
1049
        /* Unsupported bitdepth . */
 
1050
        continue;
 
1051
 
 
1052
      if (preferred_mode)
 
1053
        {
 
1054
          if (vbe_mode_info.x_resolution > width
 
1055
              || vbe_mode_info.y_resolution > height)
 
1056
            /* Resolution exceeds that of preferred mode.  */
 
1057
            continue;
 
1058
        }
 
1059
      else
 
1060
        {
 
1061
          if (((vbe_mode_info.x_resolution != width)
 
1062
               || (vbe_mode_info.y_resolution != height))
 
1063
              && width != 0 && height != 0)
 
1064
            /* Non matching resolution.  */
 
1065
            continue;
 
1066
        }
 
1067
 
 
1068
      /* Check if user requested RGB or index color mode.  */
 
1069
      if ((mode_mask & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0)
 
1070
        {
 
1071
          unsigned my_mode_type = 0;
 
1072
 
 
1073
          if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
 
1074
            my_mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
 
1075
 
 
1076
          if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR)
 
1077
            my_mode_type |= GRUB_VIDEO_MODE_TYPE_RGB;
 
1078
 
 
1079
          if ((my_mode_type & mode_mask
 
1080
               & (GRUB_VIDEO_MODE_TYPE_RGB | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR))
 
1081
              != (mode_type & mode_mask
 
1082
                  & (GRUB_VIDEO_MODE_TYPE_RGB
 
1083
                     | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)))
 
1084
            continue;
 
1085
        }
 
1086
 
 
1087
      /* If there is a request for specific depth, ignore others.  */
 
1088
      if ((depth != 0) && (vbe_mode_info.bits_per_pixel != depth))
 
1089
        continue;
 
1090
 
 
1091
      /* Select mode with most of "volume" (size of framebuffer in bits).  */
 
1092
      if (best_vbe_mode != 0)
 
1093
        if ((grub_uint64_t) vbe_mode_info.bits_per_pixel
 
1094
            * vbe_mode_info.x_resolution * vbe_mode_info.y_resolution
 
1095
            < (grub_uint64_t) best_vbe_mode_info.bits_per_pixel
 
1096
            * best_vbe_mode_info.x_resolution * best_vbe_mode_info.y_resolution)
 
1097
          continue;
 
1098
 
 
1099
      /* Save so far best mode information for later use.  */
 
1100
      best_vbe_mode = vbe_mode;
 
1101
      grub_memcpy (&best_vbe_mode_info, &vbe_mode_info, sizeof (vbe_mode_info));
 
1102
    }
 
1103
 
 
1104
  /* Try to initialize best mode found.  */
 
1105
  if (best_vbe_mode != 0)
 
1106
    {
 
1107
      grub_err_t err;
 
1108
      static struct grub_vbe_mode_info_block active_vbe_mode_info;
 
1109
      /* If this fails, then we have mode selection heuristics problem,
 
1110
         or adapter failure.  */
 
1111
      grub_vbe_set_video_mode (best_vbe_mode, &active_vbe_mode_info);
 
1112
      if (grub_errno != GRUB_ERR_NONE)
 
1113
        return grub_errno;
 
1114
 
 
1115
      /* Fill mode info details.  */
 
1116
      vbe2videoinfo (best_vbe_mode, &active_vbe_mode_info,
 
1117
                     &framebuffer.mode_info);
 
1118
 
 
1119
      {
 
1120
        /* Get video RAM size in bytes.  */
 
1121
        grub_size_t vram_size = controller_info.total_memory << 16;
 
1122
        grub_size_t page_size;        /* The size of a page in bytes.  */
 
1123
 
 
1124
        page_size = framebuffer.mode_info.pitch * framebuffer.mode_info.height;
 
1125
 
 
1126
        if (vram_size >= 2 * page_size)
 
1127
          err = grub_video_fb_setup (mode_type, mode_mask,
 
1128
                                     &framebuffer.mode_info,
 
1129
                                     framebuffer.ptr,
 
1130
                                     doublebuf_pageflipping_set_page,
 
1131
                                     framebuffer.ptr + page_size);
 
1132
        else
 
1133
          err = grub_video_fb_setup (mode_type, mode_mask,
 
1134
                                     &framebuffer.mode_info,
 
1135
                                     framebuffer.ptr, 0, 0);
 
1136
      }
 
1137
 
 
1138
      /* Copy default palette to initialize emulated palette.  */
 
1139
      err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
 
1140
                                       grub_video_fbstd_colors);
 
1141
 
 
1142
      grub_vbe_enable_mtrr (framebuffer.ptr,
 
1143
                            controller_info.total_memory << 16);
 
1144
 
 
1145
      return err;
 
1146
    }
 
1147
 
 
1148
  /* Couldn't found matching mode.  */
 
1149
  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found");
 
1150
}
 
1151
 
 
1152
static grub_err_t
 
1153
grub_video_vbe_set_palette (unsigned int start, unsigned int count,
 
1154
                            struct grub_video_palette_data *palette_data)
 
1155
{
 
1156
  if (framebuffer.mode_info.mode_type == GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
 
1157
    {
 
1158
      /* TODO: Implement setting indexed color mode palette to hardware.  */
 
1159
      //status = grub_vbe_bios_set_palette_data (sizeof (vga_colors)
 
1160
      //                                         / sizeof (struct grub_vbe_palette_data),
 
1161
      //                                         0,
 
1162
      //                                         palette);
 
1163
 
 
1164
    }
 
1165
 
 
1166
  /* Then set color to emulated palette.  */
 
1167
 
 
1168
  return grub_video_fb_set_palette (start, count, palette_data);
 
1169
}
 
1170
 
 
1171
static grub_err_t
 
1172
grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info,
 
1173
                                  void **framebuf)
 
1174
{
 
1175
  grub_err_t err;
 
1176
  grub_free (vbe_mode_list);
 
1177
  vbe_mode_list = NULL;
 
1178
  err = grub_video_fb_get_info_and_fini (mode_info, framebuf);
 
1179
  if (err)
 
1180
    return err;
 
1181
  if (framebuffer.mtrr >= 0)
 
1182
    {
 
1183
      grub_vbe_disable_mtrr (framebuffer.mtrr);
 
1184
      framebuffer.mtrr = -1;
 
1185
    }
 
1186
  return GRUB_ERR_NONE;
 
1187
}
 
1188
 
 
1189
static void
 
1190
grub_video_vbe_print_adapter_specific_info (void)
 
1191
{
 
1192
  grub_printf_ (N_("  VBE info:   version: %d.%d  OEM software rev: %d.%d\n"),
 
1193
                controller_info.version >> 8,
 
1194
                controller_info.version & 0xFF,
 
1195
                controller_info.oem_software_rev >> 8,
 
1196
                controller_info.oem_software_rev & 0xFF);
 
1197
  
 
1198
  /* The total_memory field is in 64 KiB units.  */
 
1199
  grub_printf_ (N_("              total memory: %d KiB\n"),
 
1200
                (controller_info.total_memory << 16) / 1024);
 
1201
}
 
1202
 
 
1203
static struct grub_video_adapter grub_video_vbe_adapter =
 
1204
  {
 
1205
    .name = "VESA BIOS Extension Video Driver",
 
1206
    .id = GRUB_VIDEO_DRIVER_VBE,
 
1207
 
 
1208
    .prio = GRUB_VIDEO_ADAPTER_PRIO_FIRMWARE,
 
1209
 
 
1210
    .init = grub_video_vbe_init,
 
1211
    .fini = grub_video_vbe_fini,
 
1212
    .setup = grub_video_vbe_setup,
 
1213
    .get_info = grub_video_fb_get_info,
 
1214
    .get_info_and_fini = grub_video_vbe_get_info_and_fini,
 
1215
    .set_palette = grub_video_vbe_set_palette,
 
1216
    .get_palette = grub_video_fb_get_palette,
 
1217
    .set_viewport = grub_video_fb_set_viewport,
 
1218
    .get_viewport = grub_video_fb_get_viewport,
 
1219
    .map_color = grub_video_fb_map_color,
 
1220
    .map_rgb = grub_video_fb_map_rgb,
 
1221
    .map_rgba = grub_video_fb_map_rgba,
 
1222
    .unmap_color = grub_video_fb_unmap_color,
 
1223
    .fill_rect = grub_video_fb_fill_rect,
 
1224
    .blit_bitmap = grub_video_fb_blit_bitmap,
 
1225
    .blit_render_target = grub_video_fb_blit_render_target,
 
1226
    .scroll = grub_video_fb_scroll,
 
1227
    .swap_buffers = grub_video_fb_swap_buffers,
 
1228
    .create_render_target = grub_video_fb_create_render_target,
 
1229
    .delete_render_target = grub_video_fb_delete_render_target,
 
1230
    .set_active_render_target = grub_video_fb_set_active_render_target,
 
1231
    .get_active_render_target = grub_video_fb_get_active_render_target,
 
1232
    .iterate = grub_video_vbe_iterate,
 
1233
    .get_edid = grub_video_vbe_get_edid,
 
1234
    .print_adapter_specific_info = grub_video_vbe_print_adapter_specific_info,
 
1235
 
 
1236
    .next = 0
 
1237
  };
 
1238
 
 
1239
GRUB_MOD_INIT(video_i386_pc_vbe)
 
1240
{
 
1241
  grub_video_register (&grub_video_vbe_adapter);
 
1242
}
 
1243
 
 
1244
GRUB_MOD_FINI(video_i386_pc_vbe)
 
1245
{
 
1246
  grub_video_unregister (&grub_video_vbe_adapter);
 
1247
}