Hello,

here is the VBE patch against the current CVS. I did my best to write a 
conforming ChangeLog entry. Let me know if there is something wrong - it's 
the first time that I contribute to an open source project.
I will send a patch that fills in the remaining fields in the multiboot info 
header later.

What do you think the format of this 'videomode' builtin should be? I wanted 
to pass only the VBE mode number, but it seems that this is not general 
enough.

I am also thinking about handling graphics requests where some fields are set 
to zero: choosing an appropriate mode would require quite an amount of code 
and I would not like to squeeze all of it into load_image which is quite hard 
to read already. Don't you think this function needs some clean-up to remove 
all these nested if/else constructs? If you want to add something new it's 
quite hard to see where it should go.

Regards,

        Alex

On Tuesday 13 November 2001 17:45, you wrote:
> At Tue, 13 Nov 2001 12:37:29 +0100,
>
> Alexander Thiel wrote:
> > as the latest version of GRUB did not support VBE graphics as decribed in
> > the multiboot specification, but I wanted it for my own toy kernel, I
> > have added it myself. I could not find any hint about ongoing work for
> > VBE support in the mailing list archive, so I decided to post my patch
> > (against grub-0.90). It moves some existing code around and adds some new
> > chunks. Here is a summary of the changes:
>
> Thanks for your contribution very much! Could you write ChangeLog
> entries, as descibed in the GNU Coding Standards?
>
> > As of yet, there is only the default text mode supported, and the info on
> > the protected mode interface is not available. I am also thinking about
> > adding a builtin function 'setvbe' to explicitly set the mode passed to
> > the kernel.
>
> Agreed. I think "videomode" would be more appropriate, since we may
> add support for other modes than VBE later.
>
> Okuji
Index: ChangeLog
===================================================================
RCS file: /cvsroot/grub/grub/ChangeLog,v
retrieving revision 1.441
diff -u -r1.441 ChangeLog
--- ChangeLog	2001/11/12 06:57:28	1.441
+++ ChangeLog	2001/11/21 16:21:59
@@ -1,3 +1,27 @@
+2001-11-18  Alexander Thiel  <[EMAIL PROTECTED]>
+
+	* stage2/shared.h (VBE_FAR_PTR): New macro.
+	(mbh): Declared.
+	(vbe_info_block): Likewise.
+	(mode_info_block): Likewise.
+	(mode_list): Likewise.
+	* stage2/common.c: (vbe_info_block): Defined.
+	(mode_info_block): Likewise.
+	(mode_list): Likewise.
+	(init_bios_info): Probe for VBE compliant BIOS and
+	set mbi.flags accordingly.
+	* stage2/boot.c (mbh): Defined.
+	(load_image): Replaced pu.mb by mbh and flags by mbh->flags.
+	Added code to handle graphics request from multiboot kernels.
+	* stage2/builtins.c: 
+	(boot_func): Switch video mode before booting
+	a multiboot kernel.
+	(testvbe_func): Renamed controller to vbe_info_block and mode to 
+	mode_info_block. Check flag MB_INFO_VIDEO_INFO instead of probing 
+	the BIOS. 
+	(vbeprobe): Likewise. Replaced vbe_far_ptr_to_linear by VBE_FAR_PTR.
+	Use global mode_list.
+
 2001-11-12  Yoshinori K. Okuji  <[EMAIL PROTECTED]>
 
 	* docs/grub.texi: The copyright of this file is only held by
Index: stage2/boot.c
===================================================================
RCS file: /cvsroot/grub/grub/stage2/boot.c,v
retrieving revision 1.36
diff -u -r1.36 boot.c
--- stage2/boot.c	2001/11/12 06:57:29	1.36
+++ stage2/boot.c	2001/11/21 16:21:59
@@ -29,6 +29,7 @@
 entry_func entry_addr;
 static struct mod_list mll[99];
 
+struct multiboot_header *mbh;
 
 /*
  *  The next two functions, 'load_image' and 'load_module', are the building
@@ -43,12 +44,11 @@
   int len, i, exec_type = 0, align_4k = 1;
   entry_func real_entry_addr = 0;
   kernel_t type = KERNEL_TYPE_NONE;
-  unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0;
+  unsigned long text_len = 0, data_len = 0, bss_len = 0;
   char *str = 0, *str2 = 0;
   struct linux_kernel_header *lh;
   union
     {
-      struct multiboot_header *mb;
       struct exec *aout;
       Elf32_Ehdr *elf;
     }
@@ -57,10 +57,6 @@
      executable header */
   unsigned char buffer[MULTIBOOT_SEARCH];
 
-  /* sets the header pointer to point to the beginning of the
-     buffer by default */
-  pu.aout = (struct exec *) buffer;
-
   if (!grub_open (kernel))
     return KERNEL_TYPE_NONE;
 
@@ -78,8 +74,8 @@
     {
       if (MULTIBOOT_FOUND ((int) (buffer + i), len - i))
 	{
-	  flags = ((struct multiboot_header *) (buffer + i))->flags;
-	  if (flags & MULTIBOOT_UNSUPPORTED)
+	  mbh = (struct multiboot_header *) (buffer + i);
+	  if (mbh->flags & MULTIBOOT_UNSUPPORTED)
 	    {
 	      grub_close ();
 	      errnum = ERR_BOOT_FEATURES;
@@ -91,6 +87,57 @@
 	}
     }
 
+  /* Handle graphics request for multiboot kernels */
+  if (type == KERNEL_TYPE_MULTIBOOT &&
+      mbh->flags & MULTIBOOT_VIDEO_MODE &&
+      mbi.flags & MB_INFO_VIDEO_INFO)
+    {
+      mbi.vbe_mode = 0x03; /* default */
+
+      if (mbh->mode_type == 0) 
+	{ 
+	  unsigned short fallback = 0xFFFF;
+
+	  for (mode_list
+		 = (unsigned short *) VBE_FAR_PTR (vbe_info_block.video_mode);
+	       *mode_list != 0xFFFF;
+	       mode_list++)
+	    {
+	      if (get_vbe_mode_info (*mode_list, &mode_info_block) != 0x004F 
+		  || (mode_info_block.mode_attributes & 0x0091) != 0x0091)
+		continue;
+
+	      /* use the first valid mode as fallback */
+	      if (fallback == 0xFFFF) fallback = *mode_list;
+
+	      if (mbh->width  == mode_info_block.x_resolution &&
+		  mbh->height == mode_info_block.y_resolution &&
+		  mbh->depth  == mode_info_block.bits_per_pixel )
+		{
+		  mbi.vbe_mode = *mode_list;
+		  break;
+		}
+	    }
+
+	  if (*mode_list == 0xFFFF && fallback != 0xFFFF) 
+	    mbi.vbe_mode = fallback;
+
+	}
+
+      if (debug) 
+	{
+	  grub_printf ("%s mode requested: %dx%dx%d\n",
+		       (mbh->mode_type == 0 ? "VBE graphics" : "Text"),
+		       mbh->width, mbh->height, mbh->depth);
+	  grub_printf ("Mode selected: 0x%x\n", mbi.vbe_mode);
+	}
+
+    } /* end graphics request */
+
+  /* sets the header pointer to point to the beginning of the
+     buffer by default */
+  pu.aout = (struct exec *) buffer;
+
   /* Use BUFFER as a linux kernel header, if the image is Linux zImage
      or bzImage.  */
   lh = (struct linux_kernel_header *) buffer;
@@ -134,7 +181,7 @@
 	    }
 	}
     }
-  else if (flags & MULTIBOOT_AOUT_KLUDGE)
+  else if (mbh->flags & MULTIBOOT_AOUT_KLUDGE)
     {
       pu.mb = (struct multiboot_header *) (buffer + i);
       entry_addr = (entry_func) pu.mb->entry_addr;
@@ -397,7 +444,7 @@
 
   if (exec_type)		/* can be loaded like a.out */
     {
-      if (flags & MULTIBOOT_AOUT_KLUDGE)
+      if (mbh->flags & MULTIBOOT_AOUT_KLUDGE)
 	str = "-and-data";
 
       printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len);
@@ -407,7 +454,7 @@
 	{
 	  cur_addr += text_len;
 
-	  if (!(flags & MULTIBOOT_AOUT_KLUDGE))
+	  if (!(mbh->flags & MULTIBOOT_AOUT_KLUDGE))
 	    {
 	      /* we have to align to a 4K boundary */
 	      if (align_4k)
Index: stage2/builtins.c
===================================================================
RCS file: /cvsroot/grub/grub/stage2/builtins.c,v
retrieving revision 1.116
diff -u -r1.116 builtins.c
--- stage2/builtins.c	2001/11/12 06:57:29	1.116
+++ stage2/builtins.c	2001/11/21 16:22:02
@@ -326,6 +326,21 @@
 
     case KERNEL_TYPE_MULTIBOOT:
       /* Multiboot */
+
+      /* MB specs require this */
+      if (! (mbh->flags & MULTIBOOT_VIDEO_MODE)) 
+	mbi.flags &= ~MB_INFO_VIDEO_INFO; 
+
+      /* Switch to video mode */
+      if (mbi.vbe_mode != 0x03 &&
+	  (set_vbe_mode (mbi.vbe_mode) != 0x004F ||
+	   get_vbe_mode_info (mbi.vbe_mode, &mode_info_block) != 0x004F))
+	{
+	  /* fallback to text mode */
+	  mbi.vbe_mode = 0x03;
+	  set_vbe_mode(mbi.vbe_mode);
+	}
+
       multi_boot ((int) entry_addr, (int) &mbi);
       break;
 
@@ -4099,8 +4114,6 @@
 testvbe_func (char *arg, int flags)
 {
   int mode_number;
-  struct vbe_controller controller;
-  struct vbe_mode mode;
   
   if (! *arg)
     {
@@ -4111,26 +4124,22 @@
   if (! safe_parse_maxint (&arg, &mode_number))
     return 1;
 
-  /* Preset `VBE2'.  */
-  grub_memmove (controller.signature, "VBE2", 4);
-
-  /* Detect VBE BIOS.  */
-  if (get_vbe_controller_info (&controller) != 0x004F)
+  if (! (mbi.flags & MB_INFO_VIDEO_INFO))
     {
       grub_printf (" VBE BIOS is not present.\n");
       return 0;
     }
   
-  if (controller.version < 0x0200)
+  if (vbe_info_block.version < 0x0200)
     {
       grub_printf (" VBE version %d.%d is not supported.\n",
-		   (int) (controller.version >> 8),
-		   (int) (controller.version & 0xFF));
+		   (int) (vbe_info_block.version >> 8),
+		   (int) (vbe_info_block.version & 0xFF));
       return 0;
     }
 
-  if (get_vbe_mode_info (mode_number, &mode) != 0x004F
-      || (mode.mode_attributes & 0x0091) != 0x0091)
+  if (get_vbe_mode_info (mode_number, &mode_info_block) != 0x004F
+      || (mode_info_block.mode_attributes & 0x0091) != 0x0091)
     {
       grub_printf (" Mode 0x%x is not supported.\n", mode_number);
       return 0;
@@ -4145,13 +4154,13 @@
 
   /* Draw something on the screen...  */
   {
-    unsigned char *base_buf = (unsigned char *) mode.phys_base;
-    int scanline = controller.version >= 0x0300
-      ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
+    unsigned char *base_buf = (unsigned char *) mode_info_block.phys_base;
+    int scanline = vbe_info_block.version >= 0x0300
+      ? mode_info_block.linear_bytes_per_scanline : mode_info_block.bytes_per_scanline;
     /* FIXME: this assumes that any depth is a modulo of 8.  */
-    int bpp = mode.bits_per_pixel / 8;
-    int width = mode.x_resolution;
-    int height = mode.y_resolution;
+    int bpp = mode_info_block.bits_per_pixel / 8;
+    int width = mode_info_block.x_resolution;
+    int height = mode_info_block.y_resolution;
     int x, y;
     unsigned color = 0;
 
@@ -4319,70 +4328,53 @@
 static int
 vbeprobe_func (char *arg, int flags)
 {
-  struct vbe_controller controller;
-  unsigned short *mode_list;
   int mode_number = -1;
   int count = 1;
   
-  auto unsigned long vbe_far_ptr_to_linear (unsigned long);
-  
-  unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
-    {
-      unsigned short seg = (ptr >> 16);
-      unsigned short off = (ptr & 0xFFFF);
-
-      return (seg << 4) + off;
-    }
-  
   if (*arg)
     {
       if (! safe_parse_maxint (&arg, &mode_number))
 	return 1;
     }
   
-  /* Set the signature to `VBE2', to obtain VBE 3.0 information.  */
-  grub_memmove (controller.signature, "VBE2", 4);
-  
-  if (get_vbe_controller_info (&controller) != 0x004F)
+  if (! (mbi.flags & MB_INFO_VIDEO_INFO))
     {
       grub_printf (" VBE BIOS is not present.\n");
       return 0;
     }
 
   /* Check the version.  */
-  if (controller.version < 0x0200)
+  if (vbe_info_block.version < 0x0200)
     {
       grub_printf (" VBE version %d.%d is not supported.\n",
-		   (int) (controller.version >> 8),
-		   (int) (controller.version & 0xFF));
+		   (int) (vbe_info_block.version >> 8),
+		   (int) (vbe_info_block.version & 0xFF));
       return 0;
     }
 
   /* Print some information.  */
   grub_printf (" VBE version %d.%d\n",
-	       (int) (controller.version >> 8),
-	       (int) (controller.version & 0xFF));
+	       (int) (vbe_info_block.version >> 8),
+	       (int) (vbe_info_block.version & 0xFF));
 
   /* Iterate probing modes.  */
   for (mode_list
-	 = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
+	 = (unsigned short *) VBE_FAR_PTR (vbe_info_block.video_mode);
        *mode_list != 0xFFFF;
        mode_list++)
     {
-      struct vbe_mode mode;
-      
-      if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
+      if (get_vbe_mode_info (*mode_list, &mode_info_block) != 0x004F)
 	continue;
 
       /* Skip this, if this is not supported or linear frame buffer
 	 mode is not support.  */
-      if ((mode.mode_attributes & 0x0081) != 0x0081)
+      if ((mode_info_block.mode_attributes & 0x0001) != 0x0001)
 	continue;
 
       if (mode_number == -1 || mode_number == *mode_list)
 	{
 	  char *model;
-	  switch (mode.memory_model)
+	  switch (mode_info_block.memory_model)
 	    {
 	    case 0x00: model = "Text"; break;
 	    case 0x01: model = "CGA graphics"; break;
@@ -4398,9 +4390,9 @@
 	  grub_printf ("  0x%x: %s, %ux%ux%u\n",
 		       (unsigned) *mode_list,
 		       model,
-		       (unsigned) mode.x_resolution,
-		       (unsigned) mode.y_resolution,
-		       (unsigned) mode.bits_per_pixel);
+		       (unsigned) mode_info_block.x_resolution,
+		       (unsigned) mode_info_block.y_resolution,
+		       (unsigned) mode_info_block.bits_per_pixel);
 	  
 	  if (mode_number != -1)
 	    break;
@@ -4429,8 +4421,8 @@
   vbeprobe_func,
   BUILTIN_CMDLINE,
   "vbeprobe [MODE]",
-  "Probe VBE information. If the mode number MODE is specified, show only"
-  "the information about only the mode."
+  "Probe VBE information. If the mode number MODE is specified, show "
+  "information about that mode only."
 };
   
 
Index: stage2/common.c
===================================================================
RCS file: /cvsroot/grub/grub/stage2/common.c,v
retrieving revision 1.19
diff -u -r1.19 common.c
--- stage2/common.c	2001/11/12 06:57:29	1.19
+++ stage2/common.c	2001/11/21 16:22:02
@@ -29,6 +29,9 @@
  */
 
 struct multiboot_info mbi;
+struct vbe_controller vbe_info_block;
+struct vbe_mode mode_info_block;
+unsigned short *mode_list;
 unsigned long saved_drive;
 unsigned long saved_partition;
 #ifndef STAGE1_5
@@ -316,19 +319,29 @@
   /* Get the APM BIOS table.  */
   get_apm_info ();
   if (apm_bios_info.version)
+    {
+    mbi.flags |= MB_INFO_APM_TABLE;
     mbi.apm_table = (unsigned long) &apm_bios_info;
+    }
+
+  /* Set the signature to `VBE2', to obtain VBE 3.0 information.  */
+  grub_memmove (vbe_info_block.signature, "VBE2", 4);
+
+  if (get_vbe_controller_info (&vbe_info_block) == 0x004F) 
+    {
+      mbi.flags |= MB_INFO_VIDEO_INFO;
+      mbi.vbe_control_info = (unsigned long) &vbe_info_block;
+      mbi.vbe_mode_info = (unsigned long) &mode_info_block;
+    }
   
   /*
    *  Initialize other Multiboot Info flags.
    */
 
-  mbi.flags = (MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV
+  mbi.flags |= (MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV
 	       | MB_INFO_DRIVE_INFO | MB_INFO_CONFIG_TABLE
 	       | MB_INFO_BOOT_LOADER_NAME);
   
-  if (apm_bios_info.version)
-    mbi.flags |= MB_INFO_APM_TABLE;
-
 #endif /* STAGE1_5 */
 
 #ifdef SUPPORT_DISKLESS
Index: stage2/shared.h
===================================================================
RCS file: /cvsroot/grub/grub/stage2/shared.h,v
retrieving revision 1.79
diff -u -r1.79 shared.h
--- stage2/shared.h	2001/11/12 06:57:29	1.79
+++ stage2/shared.h	2001/11/21 16:22:02
@@ -388,6 +388,7 @@
 
 #include "mb_header.h"
 #include "mb_info.h"
+extern struct multiboot_header *mbh;
 
 /* For the Linux/i386 boot protocol version 2.02.  */
 struct linux_kernel_header
@@ -662,6 +663,9 @@
  */
 
 extern struct multiboot_info mbi;
+struct vbe_controller vbe_info_block;
+struct vbe_mode mode_info_block;
+extern unsigned short *mode_list;
 extern unsigned long saved_drive;
 extern unsigned long saved_partition;
 #ifndef STAGE1_5
@@ -760,6 +764,9 @@
 
 /* Set VBE mode.  */
 int set_vbe_mode (int mode_number);
+
+/* Convert 32-bit pointer to 16-bit segment:offset style pointer */
+#define VBE_FAR_PTR(p) (((p >> 16) << 4) + (p & 0xFFFF))
 
 /* Return the data area immediately following our code. */
 int get_code_end (void);

Reply via email to