~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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/machine/vga.h>
 
24
#include <grub/machine/vbe.h>
 
25
#include <grub/video_fb.h>
 
26
#include <grub/types.h>
 
27
#include <grub/dl.h>
 
28
#include <grub/misc.h>
 
29
#include <grub/mm.h>
 
30
#include <grub/video.h>
 
31
#include <grub/machine/int.h>
 
32
 
 
33
static int vbe_detected = -1;
 
34
 
 
35
static struct grub_vbe_info_block controller_info;
 
36
 
 
37
/* Track last mode to support cards which fail on get_mode.  */
 
38
static grub_uint32_t last_set_mode = 3;
 
39
 
 
40
static struct
 
41
{
 
42
  struct grub_video_mode_info mode_info;
 
43
 
 
44
  grub_uint8_t *ptr;
 
45
} framebuffer;
 
46
 
 
47
static grub_uint32_t initial_vbe_mode;
 
48
static grub_uint16_t *vbe_mode_list;
 
49
 
 
50
static void *
 
51
real2pm (grub_vbe_farptr_t ptr)
 
52
{
 
53
  return (void *) ((((unsigned long) ptr & 0xFFFF0000) >> 12UL)
 
54
                   + ((unsigned long) ptr & 0x0000FFFF));
 
55
}
 
56
 
 
57
/* Call VESA BIOS 0x4f09 to set palette data, return status.  */
 
58
static grub_vbe_status_t 
 
59
grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
 
60
                                grub_uint32_t start_index,
 
61
                                struct grub_vbe_palette_data *palette_data)
 
62
{
 
63
  struct grub_bios_int_registers regs;
 
64
  regs.eax = 0x4f09;
 
65
  regs.ebx = 0;
 
66
  regs.ecx = color_count;
 
67
  regs.edx = start_index;
 
68
  regs.es = (((grub_addr_t) palette_data) & 0xffff0000) >> 4;
 
69
  regs.edi = ((grub_addr_t) palette_data) & 0xffff;
 
70
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
71
  grub_bios_interrupt (0x10, &regs);
 
72
  return regs.eax & 0xffff;
 
73
}
 
74
 
 
75
/* Call VESA BIOS 0x4f00 to get VBE Controller Information, return status.  */
 
76
grub_vbe_status_t 
 
77
grub_vbe_bios_get_controller_info (struct grub_vbe_info_block *ci)
 
78
{
 
79
  struct grub_bios_int_registers regs;
 
80
  /* Store *controller_info to %es:%di.  */
 
81
  regs.es = (((grub_addr_t) ci) & 0xffff0000) >> 4;
 
82
  regs.edi = ((grub_addr_t) ci) & 0xffff;
 
83
  regs.eax = 0x4f00;
 
84
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
85
  grub_bios_interrupt (0x10, &regs);
 
86
  return regs.eax & 0xffff;
 
87
}
 
88
 
 
89
/* Call VESA BIOS 0x4f01 to get VBE Mode Information, return status.  */
 
90
grub_vbe_status_t 
 
91
grub_vbe_bios_get_mode_info (grub_uint32_t mode,
 
92
                             struct grub_vbe_mode_info_block *mode_info)
 
93
{
 
94
  struct grub_bios_int_registers regs;
 
95
  regs.eax = 0x4f01;
 
96
  regs.ecx = mode;
 
97
  /* Store *mode_info to %es:%di.  */
 
98
  regs.es = ((grub_addr_t) mode_info & 0xffff0000) >> 4;
 
99
  regs.edi = (grub_addr_t) mode_info & 0x0000ffff;
 
100
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
101
  grub_bios_interrupt (0x10, &regs);
 
102
  return regs.eax & 0xffff;
 
103
}
 
104
 
 
105
/* Call VESA BIOS 0x4f02 to set video mode, return status.  */
 
106
static grub_vbe_status_t
 
107
grub_vbe_bios_set_mode (grub_uint32_t mode,
 
108
                        struct grub_vbe_crtc_info_block *crtc_info)
 
109
{
 
110
  struct grub_bios_int_registers regs;
 
111
 
 
112
  regs.eax = 0x4f02;
 
113
  regs.ebx = mode;
 
114
  /* Store *crtc_info to %es:%di.  */
 
115
  regs.es = (((grub_addr_t) crtc_info) & 0xffff0000) >> 4;
 
116
  regs.edi = ((grub_addr_t) crtc_info) & 0xffff;
 
117
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
118
  grub_bios_interrupt (0x10, &regs);
 
119
 
 
120
  return regs.eax & 0xffff;
 
121
}
 
122
 
 
123
/* Call VESA BIOS 0x4f03 to return current VBE Mode, return status.  */
 
124
grub_vbe_status_t 
 
125
grub_vbe_bios_get_mode (grub_uint32_t *mode)
 
126
{
 
127
  struct grub_bios_int_registers regs;
 
128
 
 
129
  regs.eax = 0x4f03;
 
130
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
131
  grub_bios_interrupt (0x10, &regs);
 
132
  *mode = regs.ebx & 0xffff;
 
133
 
 
134
  return regs.eax & 0xffff;
 
135
}
 
136
 
 
137
grub_vbe_status_t 
 
138
grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size)
 
139
{
 
140
  struct grub_bios_int_registers regs;
 
141
 
 
142
  regs.eax = 0x4f08;
 
143
  regs.ebx = (*dac_mask_size & 0xff) >> 8;
 
144
  regs.ebx = set ? 1 : 0;
 
145
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
146
  grub_bios_interrupt (0x10, &regs);
 
147
  *dac_mask_size = (regs.ebx >> 8) & 0xff;
 
148
 
 
149
  return regs.eax & 0xffff;
 
150
}
 
151
 
 
152
/* Call VESA BIOS 0x4f05 to set memory window, return status.  */
 
153
grub_vbe_status_t
 
154
grub_vbe_bios_set_memory_window (grub_uint32_t window,
 
155
                                 grub_uint32_t position)
 
156
{
 
157
  struct grub_bios_int_registers regs;
 
158
 
 
159
  /* BL = window, BH = 0, Set memory window.  */
 
160
  regs.ebx = window & 0x00ff;
 
161
  regs.edx = position;
 
162
  regs.eax = 0x4f05;
 
163
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
164
  grub_bios_interrupt (0x10, &regs);
 
165
  return regs.eax & 0xffff;
 
166
}
 
167
 
 
168
/* Call VESA BIOS 0x4f05 to return memory window, return status.  */
 
169
grub_vbe_status_t
 
170
grub_vbe_bios_get_memory_window (grub_uint32_t window,
 
171
                                 grub_uint32_t *position)
 
172
{
 
173
  struct grub_bios_int_registers regs;
 
174
 
 
175
  regs.eax = 0x4f05;
 
176
  /* BH = 1, Get memory window. BL = window.  */
 
177
  regs.ebx = (window & 0x00ff) | 0x100;
 
178
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
179
  grub_bios_interrupt (0x10, &regs);
 
180
 
 
181
  *position = regs.edx & 0xffff;
 
182
  return regs.eax & 0xffff;
 
183
}
 
184
 
 
185
/* Call VESA BIOS 0x4f06 to set scanline length (in bytes), return status.  */
 
186
grub_vbe_status_t 
 
187
grub_vbe_bios_set_scanline_length (grub_uint32_t length)
 
188
{
 
189
  struct grub_bios_int_registers regs;
 
190
 
 
191
  regs.ecx = length;
 
192
  regs.eax = 0x4f06;
 
193
  /* BL = 2, Set Scan Line in Bytes.  */
 
194
  regs.ebx = 0x0002;    
 
195
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
196
  grub_bios_interrupt (0x10, &regs);
 
197
  return regs.eax & 0xffff;
 
198
}
 
199
 
 
200
/* Call VESA BIOS 0x4f06 to return scanline length (in bytes), return status.  */
 
201
grub_vbe_status_t 
 
202
grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
 
203
{
 
204
  struct grub_bios_int_registers regs;
 
205
 
 
206
  regs.eax = 0x4f06;
 
207
  regs.ebx = 0x0001;
 
208
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
209
  /* BL = 1, Get Scan Line Length (in bytes).  */
 
210
  grub_bios_interrupt (0x10, &regs);
 
211
 
 
212
  *length = regs.ebx & 0xffff;
 
213
  return regs.eax & 0xffff;
 
214
}
 
215
 
 
216
/* Call VESA BIOS 0x4f07 to set display start, return status.  */
 
217
static grub_vbe_status_t 
 
218
grub_vbe_bios_set_display_start (grub_uint32_t x, grub_uint32_t y)
 
219
{
 
220
  struct grub_bios_int_registers regs;
 
221
 
 
222
  /* Store x in %ecx.  */
 
223
  regs.ecx = x;
 
224
  regs.edx = y;
 
225
  regs.eax = 0x4f07;
 
226
  /* BL = 80h, Set Display Start during Vertical Retrace.  */
 
227
  regs.ebx = 0x0080;    
 
228
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
229
  grub_bios_interrupt (0x10, &regs);
 
230
  return regs.eax & 0xffff;
 
231
}
 
232
 
 
233
/* Call VESA BIOS 0x4f07 to get display start, return status.  */
 
234
grub_vbe_status_t 
 
235
grub_vbe_bios_get_display_start (grub_uint32_t *x,
 
236
                                 grub_uint32_t *y)
 
237
{
 
238
  struct grub_bios_int_registers regs;
 
239
 
 
240
  regs.eax = 0x4f07;
 
241
  /* BL = 1, Get Display Start.  */
 
242
  regs.ebx = 0x0001;
 
243
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
244
  grub_bios_interrupt (0x10, &regs);
 
245
 
 
246
  *x = regs.ecx & 0xffff;
 
247
  *y = regs.edx & 0xffff;
 
248
  return regs.eax & 0xffff;
 
249
}
 
250
 
 
251
/* Call VESA BIOS 0x4f0a.  */
 
252
grub_vbe_status_t 
 
253
grub_vbe_bios_get_pm_interface (grub_uint16_t *segment, grub_uint16_t *offset,
 
254
                                grub_uint16_t *length)
 
255
{
 
256
  struct grub_bios_int_registers regs;
 
257
 
 
258
  regs.eax = 0x4f0a;
 
259
  regs.ebx = 0x0000;
 
260
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
261
  grub_bios_interrupt (0x10, &regs);
 
262
 
 
263
  if ((regs.eax & 0xffff) != GRUB_VBE_STATUS_OK)
 
264
    {
 
265
      *segment = 0;
 
266
      *offset = 0;
 
267
      *length = 0;
 
268
    }
 
269
 
 
270
  *segment = regs.es & 0xffff;
 
271
  *offset = regs.edi & 0xffff;
 
272
  *length = regs.ecx & 0xffff;
 
273
  return regs.eax & 0xffff;
 
274
}
 
275
 
 
276
 
 
277
grub_err_t
 
278
grub_vbe_probe (struct grub_vbe_info_block *info_block)
 
279
{
 
280
  struct grub_vbe_info_block *vbe_ib;
 
281
  grub_vbe_status_t status;
 
282
 
 
283
  /* Clear caller's controller info block.  */
 
284
  if (info_block)
 
285
    grub_memset (info_block, 0, sizeof (*info_block));
 
286
 
 
287
  /* Do not probe more than one time, if not necessary.  */
 
288
  if (vbe_detected == -1 || info_block)
 
289
    {
 
290
      /* Clear old copy of controller info block.  */
 
291
      grub_memset (&controller_info, 0, sizeof (controller_info));
 
292
 
 
293
      /* Mark VESA BIOS extension as undetected.  */
 
294
      vbe_detected = 0;
 
295
 
 
296
      /* Use low memory scratch area as temporary storage
 
297
         for VESA BIOS call.  */
 
298
      vbe_ib = (struct grub_vbe_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
 
299
 
 
300
      /* Prepare info block.  */
 
301
      grub_memset (vbe_ib, 0, sizeof (*vbe_ib));
 
302
 
 
303
      vbe_ib->signature[0] = 'V';
 
304
      vbe_ib->signature[1] = 'B';
 
305
      vbe_ib->signature[2] = 'E';
 
306
      vbe_ib->signature[3] = '2';
 
307
 
 
308
      /* Try to get controller info block.  */
 
309
      status = grub_vbe_bios_get_controller_info (vbe_ib);
 
310
      if (status == GRUB_VBE_STATUS_OK)
 
311
        {
 
312
          /* Copy it for later usage.  */
 
313
          grub_memcpy (&controller_info, vbe_ib, sizeof (controller_info));
 
314
 
 
315
          /* Mark VESA BIOS extension as detected.  */
 
316
          vbe_detected = 1;
 
317
        }
 
318
    }
 
319
 
 
320
  if (! vbe_detected)
 
321
    return grub_error (GRUB_ERR_BAD_DEVICE, "VESA BIOS Extension not found");
 
322
 
 
323
  /* Make copy of controller info block to caller.  */
 
324
  if (info_block)
 
325
    grub_memcpy (info_block, &controller_info, sizeof (*info_block));
 
326
 
 
327
  return GRUB_ERR_NONE;
 
328
}
 
329
 
 
330
grub_err_t
 
331
grub_vbe_set_video_mode (grub_uint32_t vbe_mode,
 
332
                         struct grub_vbe_mode_info_block *vbe_mode_info)
 
333
{
 
334
  grub_vbe_status_t status;
 
335
  grub_uint32_t old_vbe_mode;
 
336
  struct grub_vbe_mode_info_block new_vbe_mode_info;
 
337
  grub_err_t err;
 
338
 
 
339
  /* Make sure that VBE is supported.  */
 
340
  grub_vbe_probe (0);
 
341
  if (grub_errno != GRUB_ERR_NONE)
 
342
    return grub_errno;
 
343
 
 
344
  /* Try to get mode info.  */
 
345
  grub_vbe_get_video_mode_info (vbe_mode, &new_vbe_mode_info);
 
346
  if (grub_errno != GRUB_ERR_NONE)
 
347
    return grub_errno;
 
348
 
 
349
  /* For all VESA BIOS modes, force linear frame buffer.  */
 
350
  if (vbe_mode >= 0x100)
 
351
    {
 
352
      /* We only want linear frame buffer modes.  */
 
353
      vbe_mode |= 1 << 14;
 
354
 
 
355
      /* Determine frame buffer pixel format.  */
 
356
      if (new_vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL
 
357
          && new_vbe_mode_info.memory_model
 
358
          != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR)
 
359
        return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 
360
                           "unsupported pixel format 0x%x",
 
361
                           new_vbe_mode_info.memory_model);
 
362
    }
 
363
 
 
364
  /* Get current mode.  */
 
365
  grub_vbe_get_video_mode (&old_vbe_mode);
 
366
  if (grub_errno != GRUB_ERR_NONE)
 
367
    return grub_errno;
 
368
 
 
369
  /* Try to set video mode.  */
 
370
  status = grub_vbe_bios_set_mode (vbe_mode, 0);
 
371
  if (status != GRUB_VBE_STATUS_OK)
 
372
    return grub_error (GRUB_ERR_BAD_DEVICE, "cannot set VBE mode %x", vbe_mode);
 
373
  last_set_mode = vbe_mode;
 
374
 
 
375
  if (vbe_mode < 0x100)
 
376
    {
 
377
      /* If this is not a VESA mode, guess address.  */
 
378
      framebuffer.ptr = (grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR;
 
379
    }
 
380
  else
 
381
    {
 
382
      framebuffer.ptr = (grub_uint8_t *) new_vbe_mode_info.phys_base_addr;
 
383
    }
 
384
 
 
385
  /* Check whether mode is text mode or graphics mode.  */
 
386
  if (new_vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
 
387
    {
 
388
      /* Text mode.  */
 
389
 
 
390
      /* No special action needed for text mode as it is not supported for
 
391
         graphical support.  */
 
392
    }
 
393
  else
 
394
    {
 
395
      /* Graphics mode.  */
 
396
 
 
397
      /* If video mode is in indexed color, setup default VGA palette.  */
 
398
      if (vbe_mode < 0x100 || new_vbe_mode_info.memory_model
 
399
          == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
 
400
        {
 
401
          struct grub_vbe_palette_data *palette
 
402
            = (struct grub_vbe_palette_data *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
 
403
          unsigned i;
 
404
 
 
405
          /* Make sure that the BIOS can reach the palette.  */
 
406
          for (i = 0; i < GRUB_VIDEO_FBSTD_NUMCOLORS; i++)
 
407
            {
 
408
              palette[i].red = grub_video_fbstd_colors[i].r;
 
409
              palette[i].green = grub_video_fbstd_colors[i].g;
 
410
              palette[i].blue = grub_video_fbstd_colors[i].b;
 
411
              palette[i].alignment = 0;
 
412
            }
 
413
 
 
414
          status = grub_vbe_bios_set_palette_data (GRUB_VIDEO_FBSTD_NUMCOLORS,
 
415
                                                   0, palette);
 
416
 
 
417
          /* Just ignore the status.  */
 
418
          err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
 
419
                                           grub_video_fbstd_colors);
 
420
          if (err)
 
421
            return err;
 
422
 
 
423
        }
 
424
    }
 
425
 
 
426
  /* Copy mode info for caller.  */
 
427
  if (vbe_mode_info)
 
428
    grub_memcpy (vbe_mode_info, &new_vbe_mode_info, sizeof (*vbe_mode_info));
 
429
 
 
430
  return GRUB_ERR_NONE;
 
431
}
 
432
 
 
433
grub_err_t
 
434
grub_vbe_get_video_mode (grub_uint32_t *mode)
 
435
{
 
436
  grub_vbe_status_t status;
 
437
 
 
438
  /* Make sure that VBE is supported.  */
 
439
  grub_vbe_probe (0);
 
440
  if (grub_errno != GRUB_ERR_NONE)
 
441
    return grub_errno;
 
442
 
 
443
  /* Try to query current mode from VESA BIOS.  */
 
444
  status = grub_vbe_bios_get_mode (mode);
 
445
  /* XXX: ATI cards don't support get_mode.  */
 
446
  if (status != GRUB_VBE_STATUS_OK)
 
447
    *mode = last_set_mode;
 
448
 
 
449
  return GRUB_ERR_NONE;
 
450
}
 
451
 
 
452
grub_err_t
 
453
grub_vbe_get_video_mode_info (grub_uint32_t mode,
 
454
                              struct grub_vbe_mode_info_block *mode_info)
 
455
{
 
456
  struct grub_vbe_mode_info_block *mi_tmp
 
457
    = (struct grub_vbe_mode_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
 
458
  grub_vbe_status_t status;
 
459
 
 
460
  /* Make sure that VBE is supported.  */
 
461
  grub_vbe_probe (0);
 
462
  if (grub_errno != GRUB_ERR_NONE)
 
463
    return grub_errno;
 
464
 
 
465
  /* If mode is not VESA mode, skip mode info query.  */
 
466
  if (mode >= 0x100)
 
467
    {
 
468
      /* Try to get mode info from VESA BIOS.  */
 
469
      status = grub_vbe_bios_get_mode_info (mode, mi_tmp);
 
470
      if (status != GRUB_VBE_STATUS_OK)
 
471
        return grub_error (GRUB_ERR_BAD_DEVICE,
 
472
                           "cannot get information on the mode %x", mode);
 
473
 
 
474
      /* Make copy of mode info block.  */
 
475
      grub_memcpy (mode_info, mi_tmp, sizeof (*mode_info));
 
476
    }
 
477
  else
 
478
    /* Just clear mode info block if it isn't a VESA mode.  */
 
479
    grub_memset (mode_info, 0, sizeof (*mode_info));
 
480
 
 
481
  return GRUB_ERR_NONE;
 
482
}
 
483
 
 
484
static grub_err_t
 
485
grub_video_vbe_init (void)
 
486
{
 
487
  grub_uint16_t *rm_vbe_mode_list;
 
488
  grub_uint16_t *p;
 
489
  grub_size_t vbe_mode_list_size;
 
490
  struct grub_vbe_info_block info_block;
 
491
 
 
492
  /* Check if there is adapter present.
 
493
 
 
494
     Firmware note: There has been a report that some cards store video mode
 
495
     list in temporary memory.  So we must first use vbe probe to get
 
496
     refreshed information to receive valid pointers and data, and then
 
497
     copy this information to somewhere safe.  */
 
498
  grub_vbe_probe (&info_block);
 
499
  if (grub_errno != GRUB_ERR_NONE)
 
500
    return grub_errno;
 
501
 
 
502
  /* Copy modelist to local memory.  */
 
503
  p = rm_vbe_mode_list = real2pm (info_block.video_mode_ptr);
 
504
  while(*p++ != 0xFFFF)
 
505
    ;
 
506
 
 
507
  vbe_mode_list_size = (grub_addr_t) p - (grub_addr_t) rm_vbe_mode_list;
 
508
  vbe_mode_list = grub_malloc (vbe_mode_list_size);
 
509
  if (! vbe_mode_list)
 
510
    return grub_errno;
 
511
  grub_memcpy (vbe_mode_list, rm_vbe_mode_list, vbe_mode_list_size);
 
512
 
 
513
  /* Adapter could be found, figure out initial video mode.  */
 
514
  grub_vbe_get_video_mode (&initial_vbe_mode);
 
515
  if (grub_errno != GRUB_ERR_NONE)
 
516
    {
 
517
      /* Free allocated resources.  */
 
518
      grub_free (vbe_mode_list);
 
519
      vbe_mode_list = NULL;
 
520
 
 
521
      return grub_errno;
 
522
    }
 
523
 
 
524
  /* Reset frame buffer.  */
 
525
  grub_memset (&framebuffer, 0, sizeof(framebuffer));
 
526
 
 
527
  return grub_video_fb_init ();
 
528
}
 
529
 
 
530
static grub_err_t
 
531
grub_video_vbe_fini (void)
 
532
{
 
533
  grub_vbe_status_t status;
 
534
  grub_err_t err;
 
535
 
 
536
  /* Restore old video mode.  */
 
537
  if (last_set_mode != initial_vbe_mode)
 
538
    {
 
539
      status = grub_vbe_bios_set_mode (initial_vbe_mode, 0);
 
540
      if (status != GRUB_VBE_STATUS_OK)
 
541
        /* TODO: Decide, is this something we want to do.  */
 
542
        return grub_errno;
 
543
    }
 
544
  last_set_mode = initial_vbe_mode;
 
545
 
 
546
  /* TODO: Free any resources allocated by driver.  */
 
547
  grub_free (vbe_mode_list);
 
548
  vbe_mode_list = NULL;
 
549
 
 
550
  err = grub_video_fb_fini ();
 
551
  return err;
 
552
}
 
553
 
 
554
/*
 
555
  Set framebuffer render target page and display the proper page, based on
 
556
  `doublebuf_state.render_page' and `doublebuf_state.displayed_page',
 
557
  respectively.
 
558
*/
 
559
static grub_err_t
 
560
doublebuf_pageflipping_set_page (int page)
 
561
{
 
562
  /* Tell the video adapter to display the new front page.  */
 
563
  int display_start_line
 
564
    = framebuffer.mode_info.height * page;
 
565
 
 
566
  grub_vbe_status_t vbe_err =
 
567
    grub_vbe_bios_set_display_start (0, display_start_line);
 
568
 
 
569
  if (vbe_err != GRUB_VBE_STATUS_OK)
 
570
    return grub_error (GRUB_ERR_IO, "couldn't commit pageflip");
 
571
 
 
572
  return 0;
 
573
}
 
574
 
 
575
static void
 
576
vbe2videoinfo (grub_uint32_t mode,
 
577
               const struct grub_vbe_mode_info_block *vbeinfo,
 
578
               struct grub_video_mode_info *mode_info)
 
579
{
 
580
  mode_info->mode_number = mode;
 
581
 
 
582
  mode_info->width = vbeinfo->x_resolution;
 
583
  mode_info->height = vbeinfo->y_resolution;
 
584
  mode_info->mode_type = 0;
 
585
  switch (vbeinfo->memory_model)
 
586
    {
 
587
    case GRUB_VBE_MEMORY_MODEL_TEXT:
 
588
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_PURE_TEXT;
 
589
      break;
 
590
 
 
591
      /* CGA is basically 4-bit packed pixel.  */
 
592
    case GRUB_VBE_MEMORY_MODEL_CGA:
 
593
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_CGA;
 
594
    case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL:
 
595
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
 
596
      break;
 
597
 
 
598
    case GRUB_VBE_MEMORY_MODEL_HERCULES:
 
599
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_HERCULES
 
600
        | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP;
 
601
      break;
 
602
 
 
603
      /* Non chain 4 is a special case of planar.  */
 
604
    case GRUB_VBE_MEMORY_MODEL_NONCHAIN4_256:
 
605
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_NONCHAIN4;
 
606
    case GRUB_VBE_MEMORY_MODEL_PLANAR:
 
607
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_PLANAR
 
608
        | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
 
609
      break;
 
610
 
 
611
    case GRUB_VBE_MEMORY_MODEL_YUV:
 
612
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_YUV;
 
613
      break;
 
614
      
 
615
    case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR:
 
616
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_RGB;
 
617
      break;
 
618
    default:
 
619
      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UNKNOWN;
 
620
      break;
 
621
    }
 
622
 
 
623
  mode_info->bpp = vbeinfo->bits_per_pixel;
 
624
  /* Calculate bytes_per_pixel value.  */
 
625
  switch(vbeinfo->bits_per_pixel)
 
626
    {
 
627
    case 32:
 
628
      mode_info->bytes_per_pixel = 4;
 
629
      break;
 
630
    case 24:
 
631
      mode_info->bytes_per_pixel = 3;
 
632
      break;
 
633
    case 16:
 
634
      mode_info->bytes_per_pixel = 2;
 
635
      break;
 
636
    case 15:
 
637
      mode_info->bytes_per_pixel = 2;
 
638
      break;
 
639
    case 8:
 
640
      mode_info->bytes_per_pixel = 1;
 
641
      break;  
 
642
    case 4:
 
643
      mode_info->bytes_per_pixel = 0;
 
644
      break;  
 
645
    }
 
646
 
 
647
  if (controller_info.version >= 0x300)
 
648
    mode_info->pitch = vbeinfo->lin_bytes_per_scan_line;
 
649
  else
 
650
    mode_info->pitch = vbeinfo->bytes_per_scan_line;
 
651
 
 
652
  mode_info->number_of_colors = 256; /* TODO: fix me.  */
 
653
  mode_info->red_mask_size = vbeinfo->red_mask_size;
 
654
  mode_info->red_field_pos = vbeinfo->red_field_position;
 
655
  mode_info->green_mask_size = vbeinfo->green_mask_size;
 
656
  mode_info->green_field_pos = vbeinfo->green_field_position;
 
657
  mode_info->blue_mask_size = vbeinfo->blue_mask_size;
 
658
  mode_info->blue_field_pos = vbeinfo->blue_field_position;
 
659
  mode_info->reserved_mask_size = vbeinfo->rsvd_mask_size;
 
660
  mode_info->reserved_field_pos = vbeinfo->rsvd_field_position;
 
661
 
 
662
  mode_info->blit_format = grub_video_get_blit_format (mode_info);
 
663
}
 
664
 
 
665
static int
 
666
grub_video_vbe_iterate (int (*hook) (const struct grub_video_mode_info *info))
 
667
{
 
668
  grub_uint16_t *p;
 
669
  struct grub_vbe_mode_info_block vbe_mode_info;
 
670
  struct grub_video_mode_info mode_info;
 
671
 
 
672
  for (p = vbe_mode_list; *p != 0xFFFF; p++)
 
673
    {
 
674
      grub_vbe_get_video_mode_info (*p, &vbe_mode_info);
 
675
      if (grub_errno != GRUB_ERR_NONE)
 
676
        {
 
677
          /* Could not retrieve mode info, retreat.  */
 
678
          grub_errno = GRUB_ERR_NONE;
 
679
          break;
 
680
        }
 
681
 
 
682
      vbe2videoinfo (*p, &vbe_mode_info, &mode_info);
 
683
      if (hook (&mode_info))
 
684
        return 1;
 
685
    }
 
686
  return 0;
 
687
}
 
688
 
 
689
static grub_err_t
 
690
grub_video_vbe_setup (unsigned int width, unsigned int height,
 
691
                      unsigned int mode_type, unsigned int mode_mask)
 
692
{
 
693
  grub_uint16_t *p;
 
694
  struct grub_vbe_mode_info_block vbe_mode_info;
 
695
  struct grub_vbe_mode_info_block best_vbe_mode_info;
 
696
  grub_uint32_t best_vbe_mode = 0;
 
697
  int depth;
 
698
 
 
699
  /* Decode depth from mode_type.  If it is zero, then autodetect.  */
 
700
  depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
 
701
          >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
 
702
 
 
703
  /* Walk thru mode list and try to find matching mode.  */
 
704
  for (p = vbe_mode_list; *p != 0xFFFF; p++)
 
705
    {
 
706
      grub_uint32_t vbe_mode = *p;
 
707
 
 
708
      grub_vbe_get_video_mode_info (vbe_mode, &vbe_mode_info);
 
709
      if (grub_errno != GRUB_ERR_NONE)
 
710
        {
 
711
          /* Could not retrieve mode info, retreat.  */
 
712
          grub_errno = GRUB_ERR_NONE;
 
713
          break;
 
714
        }
 
715
 
 
716
      if ((vbe_mode_info.mode_attributes & 0x001) == 0)
 
717
        /* If not available, skip it.  */
 
718
        continue;
 
719
 
 
720
      if ((vbe_mode_info.mode_attributes & 0x008) == 0)
 
721
        /* Monochrome is unusable.  */
 
722
        continue;
 
723
 
 
724
      if ((vbe_mode_info.mode_attributes & 0x080) == 0)
 
725
        /* We support only linear frame buffer modes.  */
 
726
        continue;
 
727
 
 
728
      if ((vbe_mode_info.mode_attributes & 0x010) == 0)
 
729
        /* We allow only graphical modes.  */
 
730
        continue;
 
731
 
 
732
      if ((vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
 
733
          && (vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR))
 
734
        /* Not compatible memory model.  */
 
735
        continue;
 
736
 
 
737
      if (vbe_mode_info.bits_per_pixel != 8
 
738
          && vbe_mode_info.bits_per_pixel != 15
 
739
          && vbe_mode_info.bits_per_pixel != 16
 
740
          && vbe_mode_info.bits_per_pixel != 24
 
741
          && vbe_mode_info.bits_per_pixel != 32)
 
742
        /* Unsupported bitdepth . */
 
743
        continue;
 
744
 
 
745
      if (((vbe_mode_info.x_resolution != width)
 
746
           || (vbe_mode_info.y_resolution != height)) && width != 0 && height != 0)
 
747
        /* Non matching resolution.  */
 
748
        continue;
 
749
 
 
750
      /* Check if user requested RGB or index color mode.  */
 
751
      if ((mode_mask & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0)
 
752
        {
 
753
          unsigned my_mode_type = 0;
 
754
 
 
755
          if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
 
756
            my_mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
 
757
 
 
758
          if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR)
 
759
            my_mode_type |= GRUB_VIDEO_MODE_TYPE_RGB;
 
760
 
 
761
          if ((my_mode_type & mode_mask
 
762
               & (GRUB_VIDEO_MODE_TYPE_RGB | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR))
 
763
              != (mode_type & mode_mask
 
764
                  & (GRUB_VIDEO_MODE_TYPE_RGB
 
765
                     | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)))
 
766
            continue;
 
767
        }
 
768
 
 
769
      /* If there is a request for specific depth, ignore others.  */
 
770
      if ((depth != 0) && (vbe_mode_info.bits_per_pixel != depth))
 
771
        continue;
 
772
 
 
773
      /* Select mode with most of "volume" (size of framebuffer in bits).  */
 
774
      if (best_vbe_mode != 0)
 
775
        if ((grub_uint64_t) vbe_mode_info.bits_per_pixel
 
776
            * vbe_mode_info.x_resolution * vbe_mode_info.y_resolution
 
777
            < (grub_uint64_t) best_vbe_mode_info.bits_per_pixel
 
778
            * best_vbe_mode_info.x_resolution * best_vbe_mode_info.y_resolution)
 
779
          continue;
 
780
 
 
781
      /* Save so far best mode information for later use.  */
 
782
      best_vbe_mode = vbe_mode;
 
783
      grub_memcpy (&best_vbe_mode_info, &vbe_mode_info, sizeof (vbe_mode_info));
 
784
    }
 
785
 
 
786
  /* Try to initialize best mode found.  */
 
787
  if (best_vbe_mode != 0)
 
788
    {
 
789
      grub_err_t err;
 
790
      static struct grub_vbe_mode_info_block active_vbe_mode_info;
 
791
      /* If this fails, then we have mode selection heuristics problem,
 
792
         or adapter failure.  */
 
793
      grub_vbe_set_video_mode (best_vbe_mode, &active_vbe_mode_info);
 
794
      if (grub_errno != GRUB_ERR_NONE)
 
795
        return grub_errno;
 
796
 
 
797
      /* Fill mode info details.  */
 
798
      vbe2videoinfo (best_vbe_mode, &active_vbe_mode_info,
 
799
                     &framebuffer.mode_info);
 
800
 
 
801
      {
 
802
        /* Get video RAM size in bytes.  */
 
803
        grub_size_t vram_size = controller_info.total_memory << 16;
 
804
        grub_size_t page_size;        /* The size of a page in bytes.  */
 
805
 
 
806
        page_size = framebuffer.mode_info.pitch * framebuffer.mode_info.height;
 
807
 
 
808
        if (vram_size >= 2 * page_size)
 
809
          err = grub_video_fb_setup (mode_type, mode_mask,
 
810
                                     &framebuffer.mode_info,
 
811
                                     framebuffer.ptr,
 
812
                                     doublebuf_pageflipping_set_page,
 
813
                                     framebuffer.ptr + page_size);
 
814
        else
 
815
          err = grub_video_fb_setup (mode_type, mode_mask,
 
816
                                     &framebuffer.mode_info,
 
817
                                     framebuffer.ptr, 0, 0);
 
818
      }
 
819
 
 
820
      /* Copy default palette to initialize emulated palette.  */
 
821
      err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
 
822
                                       grub_video_fbstd_colors);
 
823
      return err;
 
824
    }
 
825
 
 
826
  /* Couldn't found matching mode.  */
 
827
  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found");
 
828
}
 
829
 
 
830
static grub_err_t
 
831
grub_video_vbe_set_palette (unsigned int start, unsigned int count,
 
832
                            struct grub_video_palette_data *palette_data)
 
833
{
 
834
  if (framebuffer.mode_info.mode_type == GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
 
835
    {
 
836
      /* TODO: Implement setting indexed color mode palette to hardware.  */
 
837
      //status = grub_vbe_bios_set_palette_data (sizeof (vga_colors)
 
838
      //                                         / sizeof (struct grub_vbe_palette_data),
 
839
      //                                         0,
 
840
      //                                         palette);
 
841
 
 
842
    }
 
843
 
 
844
  /* Then set color to emulated palette.  */
 
845
 
 
846
  return grub_video_fb_set_palette (start, count, palette_data);
 
847
}
 
848
 
 
849
static grub_err_t
 
850
grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info,
 
851
                                  void **framebuf)
 
852
{
 
853
  grub_free (vbe_mode_list);
 
854
  vbe_mode_list = NULL;
 
855
  return grub_video_fb_get_info_and_fini (mode_info, framebuf);
 
856
}
 
857
 
 
858
static void
 
859
grub_video_vbe_print_adapter_specific_info (void)
 
860
{
 
861
  grub_printf ("  VBE info:   version: %d.%d  OEM software rev: %d.%d\n",
 
862
               controller_info.version >> 8,
 
863
               controller_info.version & 0xFF,
 
864
               controller_info.oem_software_rev >> 8,
 
865
               controller_info.oem_software_rev & 0xFF);
 
866
 
 
867
  /* The total_memory field is in 64 KiB units.  */
 
868
  grub_printf ("              total memory: %d KiB\n",
 
869
               (controller_info.total_memory << 16) / 1024);
 
870
}
 
871
 
 
872
static struct grub_video_adapter grub_video_vbe_adapter =
 
873
  {
 
874
    .name = "VESA BIOS Extension Video Driver",
 
875
    .id = GRUB_VIDEO_DRIVER_VBE,
 
876
 
 
877
    .prio = GRUB_VIDEO_ADAPTER_PRIO_FIRMWARE,
 
878
 
 
879
    .init = grub_video_vbe_init,
 
880
    .fini = grub_video_vbe_fini,
 
881
    .setup = grub_video_vbe_setup,
 
882
    .get_info = grub_video_fb_get_info,
 
883
    .get_info_and_fini = grub_video_vbe_get_info_and_fini,
 
884
    .set_palette = grub_video_vbe_set_palette,
 
885
    .get_palette = grub_video_fb_get_palette,
 
886
    .set_viewport = grub_video_fb_set_viewport,
 
887
    .get_viewport = grub_video_fb_get_viewport,
 
888
    .map_color = grub_video_fb_map_color,
 
889
    .map_rgb = grub_video_fb_map_rgb,
 
890
    .map_rgba = grub_video_fb_map_rgba,
 
891
    .unmap_color = grub_video_fb_unmap_color,
 
892
    .fill_rect = grub_video_fb_fill_rect,
 
893
    .blit_bitmap = grub_video_fb_blit_bitmap,
 
894
    .blit_render_target = grub_video_fb_blit_render_target,
 
895
    .scroll = grub_video_fb_scroll,
 
896
    .swap_buffers = grub_video_fb_swap_buffers,
 
897
    .create_render_target = grub_video_fb_create_render_target,
 
898
    .delete_render_target = grub_video_fb_delete_render_target,
 
899
    .set_active_render_target = grub_video_fb_set_active_render_target,
 
900
    .get_active_render_target = grub_video_fb_get_active_render_target,
 
901
    .iterate = grub_video_vbe_iterate,
 
902
    .print_adapter_specific_info = grub_video_vbe_print_adapter_specific_info,
 
903
 
 
904
    .next = 0
 
905
  };
 
906
 
 
907
GRUB_MOD_INIT(video_i386_pc_vbe)
 
908
{
 
909
  grub_video_register (&grub_video_vbe_adapter);
 
910
}
 
911
 
 
912
GRUB_MOD_FINI(video_i386_pc_vbe)
 
913
{
 
914
  grub_video_unregister (&grub_video_vbe_adapter);
 
915
}