Frank, please send patches to bug-grub rather than me. I'm not the
only one who is working on GRUB. Thus, I forward your mail to the
list.

  About your patch: Hercules support is great. I'll apply this
part. But the VBE support is not very good. Certainly, a command to
switch to a graphics mode explicitly is necessary, but the mode
switching shouldn't happen until you actually boot up your OS, because
you won't be able to control GRUB interactively on the ordinary
console after switching to a graphics mode. There are some other
problems as well. Anyway, I think this work must be done myself, to
make the graphics support ideal for me. I'll work on this, once a new
implementation of track_int13 is stabilized (I have the code, but I
haven't checked it in yet, because of some known bugs).

Thanks,
Okuji


Hi Okuji Yoshinori,

I've appended a patch to the current GRUB in cvs. This patch adds two
features to GRUB:

- The "terminal" command knows about a "hercules" type:

   "terminal hercules" 

  switches to a hercules screen. In our test machines we usually have two
  graphics cards installed: The primary VGA card and an additional Hercules
  graphics card for debugging purposes.
  
  (added hercules functions to shared.h, asm.S, stage2.c, char_io.c and
   builtins.c)

- There is a new command vbeset: vbeset <mode> switches into VESA2 graphics
  mode <mode>. This works simular to testvbe but there are some differents
  to testvbe:
  
  * the mode will _not_ switched back to text after the command finished
  * the VESA2 graphics mode info and controller mode info is stored in a
    memory block, and pointers to this info is stored in the multiboot_info
    structure (create_vbe_module in boot.c) so that all multiboot modules
    can use the information

  (added vbeset stuff to shared.h, builtins.c and boot.c)

  drawbacks of my solution:
  * because I allocate a memory chunk with help of the cur_addr pointer,
    a multiboot kernel has to be loaded before the vbeset command may be
    executed.
  * for each vbeset command a new chunk of memory is allocated
  => perhaps we could overcome these two drawbacks when we allocate a single
    memory area for the VESA2 info and reuse it on every vbeset command.

Please apply the patch with the following commands to the current CVS release
(12-14-2000) of grub:

  cd grub/stage2
  patch < grub_stage2_patch

Greetings,

Frank
-- 
Frank Mehnert
## Dept. of Computer Science, Dresden University of Technology, Germany ##
## E-Mail: [EMAIL PROTECTED]    http://os.inf.tu-dresden.de/~fm3 ##
--- asm.S	Wed Nov 29 15:14:57 2000
+++ /home/fm3/src/prj/grub/grub/stage2/asm.S	Thu Dec 14 10:18:19 2000
@@ -1669,7 +1669,66 @@
 	popl	%ebp
 	ret
 
-		
+
+ENTRY(reset_vbe_mode)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ebx
+
+	call	EXT_C(prot_to_real)
+	.code16
+
+	movw	$0x0003, %ax
+	int	$0x10
+
+	DATA32	call	EXT_C(real_to_prot)
+	.code32
+
+	popl	%ebx
+	popl	%ebp
+	ret
+
+
+ENTRY(get_vbe_pmif)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ebx
+	pushl	%edi
+
+	pushl	%ebp
+
+	call	EXT_C(prot_to_real)
+	.code16
+
+	movw	$0x4F0A, %ax
+	xorw	%bx,%bx
+	xorw	%di,%di
+	int	$0x10
+	xorl	%ebx,%ebx
+	cmpw	$0x004F,%ax
+	jnz	nopm
+
+	movw	%es,%bx
+	shll	$16,%ebx
+	movw	%di,%bx
+
+nopm:	DATA32	call	EXT_C(real_to_prot)
+	.code32
+
+	popl	%ebp
+
+	movl	0x8(%ebp),%eax
+	movl	%ebx,(%eax)
+	movl	0xc(%ebp),%eax
+	andl	$0xFFFF,%ecx
+	movl	%ecx,(%eax)
+	
+	popl	%edi
+	popl	%ebx
+	popl	%ebp
+	ret
+
+
 /*
  * gateA20(int linear)
  *
@@ -2169,6 +2228,162 @@
 	pop	%ebp
 	ret
 
+
+	.p2align 2
+hercx:
+	.long	0
+hercy:
+	.long	0
+
+/*
+ * console functions for output on hercules screen.
+ */
+
+ENTRY(console_herc_putchar)
+	push	%ebx
+
+	movb	0x08(%esp),%bl
+	movb	$07,%bh
+
+	cmpb	$8,%bl
+	jnz	chp0
+	cmpb	$0,(hercx)
+	jz	chp3
+	decb	(hercx)
+	jmp	chp3
+
+chp0:	cmpb	$10,%bl			/* 0x0A -> new line */
+	jnz	chp1
+	incl	(hercy)
+	jmp	chp3
+
+chp1:	cmpb	$13,%bl			/* 0x0D -> line feed */
+	jnz	chp2
+	movl	$0,(hercx)
+	jmp	chp3
+	
+chp2:	imull	$80,(hercy),%eax
+	addl	(hercx),%eax
+	shll	$1,%eax
+	addl	$0xB0000,%eax
+	
+	movw	%bx,(%eax)
+	incl	(hercx)
+
+chp3:	cmpb	$80,(hercx)		/* test if x >= 80 */
+	jb	chp4
+	incl	(hercy)
+	movl	$0,(hercx)
+
+chp4:	cmpb	$25,(hercy)		/* test if y >= 25 */
+	jb	chpe
+	movl	$24,(hercy)
+
+	movl	$0xB0000+160,%eax
+	movl	$0xB0000,%ebx
+	movl	$1000-40,%ecx
+chp5:	movl	(%eax),%edx
+	movl	%edx,(%ebx)
+	addl	$4,%eax
+	addl	$4,%ebx
+	decl	%ecx
+	jnz	chp5
+
+	movl	$40,%ecx
+	movl	$0x07200720,%eax
+chp6:	movl	%eax,(%ebx)
+	addl	$4,%ebx
+	decl	%ecx
+	jnz	chp6
+	
+chpe:	pop	%ebx
+	ret
+
+
+ENTRY(console_herc_cls)
+	push	%ebx
+	
+	movl	$0xB0000,%eax
+	movl	$0x07200720,%ebx
+	movl	$1000,%ecx
+
+chc1:	movl	%ebx,(%eax)
+	addl	$4,%eax
+	decl	%ecx
+	jnz	chc1
+
+	xorl	%eax,%eax
+	movl	%eax,(hercx)
+	movl	%eax,(hercy)
+
+	pop	%ebx
+	jmp	console_herc_set_cursor
+
+
+ENTRY(console_herc_getxy)
+	xorl	%eax,%eax
+	movb	(hercx),%ah
+	movb	(hercy),%al
+	ret
+
+
+ENTRY(console_herc_gotoxy)
+	xorl	%eax,%eax
+	movb	0x4(%esp), %al
+	movl	%eax, (hercx)
+	movb	0x8(%esp), %al
+	movl	%eax, (hercy)
+	jmp	console_herc_set_cursor
+
+
+ENTRY(console_herc_set_attrib)
+	push	%ebx
+
+	movl	0x8(%esp), %ecx
+
+	imull	$80,(hercy),%eax
+	addl	(hercx),%eax
+	shll	$1,%eax
+	addl	$0xB0001,%eax
+
+	movb	$0x07,%ch
+	test	$0xf0,%cl
+	jz	chsa1
+	movb	$0x70,%ch
+
+chsa1:	movb	%ch,(%eax)
+
+	pop	%ebx
+	ret
+
+
+ENTRY(console_herc_set_cursor)
+	push	%ebx
+	
+	imull	$80,(hercy),%ebx
+	addl	(hercx),%ebx
+	movl	$0x3b4,%edx
+
+	movb	$0x0f,%al
+	outb	%al,%dx
+	outb	%al,$0x80
+	incl	%edx
+	movb	%bl,%al
+	outb	%al,%dx
+	outb	%al,$0x80
+	decl	%edx
+	
+	movb	$0x0e,%al
+	outb	%al,%dx
+	outb	%al,$0x80
+	incl	%edx
+	movb	%bh,%al
+	outb	%al,%dx
+	outb	%al,$0x80
+
+	pop	%ebx
+	ret
+	
 #endif /* STAGE1_5 */
 
 /*
--- boot.c	Wed Oct 25 16:47:35 2000
+++ /home/fm3/src/prj/grub/grub/stage2/boot.c	Thu Dec  7 13:03:43 2000
@@ -610,6 +618,35 @@
   return 1;
 }
 
+void
+create_vbe_module(void *ctrl_info, int ctrl_info_len,
+                  void *mode_info, int mode_info_len, 
+		  int mode, int pmif, int pmif_len,
+		  unsigned int version)
+{
+  /* if we are supposed to load on 4K boundaries */
+  cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
+
+  printf ("   [VESA %d.%d info @ 0x%x, 0x%x bytes]\n",
+      version >> 8, version & 0xFF,
+      cur_addr, ctrl_info_len + mode_info_len);
+
+  grub_memmove((char*)cur_addr, ctrl_info, ctrl_info_len);
+  mbi.vbe_control_info = (int)cur_addr;
+  cur_addr += ctrl_info_len;
+  
+  grub_memmove((char*)cur_addr, mode_info, mode_info_len);
+  mbi.vbe_mode_info    = (int)cur_addr;
+  cur_addr += mode_info_len;
+
+  mbi.flags |= MB_INFO_VIDEO_INFO;
+
+  mbi.vbe_mode         = mode;
+  mbi.vbe_interface_seg = (pmif >> 16) & 0xFFFF;
+  mbi.vbe_interface_off =  pmif        & 0xFFFF;
+  mbi.vbe_interface_len = pmif_len;
+}
+
 int
 load_initrd (char *initrd)
 {
--- builtins.c	Wed Nov 29 15:14:57 2000
+++ /home/fm3/src/prj/grub/grub/stage2/builtins.c	Thu Dec 14 10:20:04 2000
@@ -3838,8 +3873,9 @@
   if (! *arg)
     {
       if (terminal & TERMINAL_CONSOLE)
-	grub_printf ("console%s\n",
-		     terminal & TERMINAL_DUMB ? " (dumb)" : "");
+	grub_printf ("console%s%s\n",
+		     terminal & TERMINAL_DUMB ? " (dumb)" : "",
+		     terminal & TERMINAL_CONSOLE_HERC ? " (hercules)" : "");
       else if (terminal & TERMINAL_SERIAL)
 	grub_printf ("serial%s\n",
 		     terminal & TERMINAL_DUMB ? " (dumb)" : " (vt100)");
@@ -3857,6 +3893,14 @@
 	  if (! default_terminal)
 	    default_terminal = TERMINAL_CONSOLE;
 	}
+#ifndef GRUB_UTIL
+      else if (grub_memcmp (arg, "hercules", sizeof ("hercules") - 1) == 0)
+	{
+	  terminal |= (TERMINAL_CONSOLE | TERMINAL_CONSOLE_HERC);
+	  if (! default_terminal)
+	    default_terminal = TERMINAL_CONSOLE | TERMINAL_CONSOLE_HERC;
+	}
+#endif
       else if (grub_memcmp (arg, "serial", sizeof ("serial") - 1) == 0)
 	{
 	  terminal |= TERMINAL_SERIAL;
@@ -3926,7 +3970,7 @@
   "terminal",
   terminal_func,
   BUILTIN_MENU | BUILTIN_CMDLINE,
-  "terminal [--dumb] [--timeout=SECS] [console] [serial]",
+  "terminal [--dumb] [--timeout=SECS] [console] [serial] [hercules]",
   "Select a terminal. When serial is specified, wait until you push any key"
   " to continue. If both console and serial are specified, the terminal"
   " to which you input a key first will be selected. If no argument is"
@@ -4366,6 +4410,89 @@
 };
   
 
+/* vbeset MODE */
+static int
+vbeset_func (char *arg, int flags)
+{
+#ifndef GRUB_UTIL
+  int mode_number;
+  int pmif_segoff, pmif_len;
+  struct vbe_controller controller;
+  struct vbe_mode mode;
+
+  if (kernel_type != KERNEL_TYPE_MULTIBOOT)
+    {
+      grub_printf("Multiboot kernel must be loaded before vbeset command\n");
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+  
+  if (! *arg)
+    {
+      reset_vbe_mode ();
+      return 0;
+    }
+
+  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)
+    {
+      grub_printf (" VBE BIOS is not present.\n");
+      return 1;
+    }
+  
+  if (controller.version < 0x0200)
+    {
+      grub_printf (" VBE version %d.%d is not supported.\n",
+		   (int) (controller.version >> 8),
+		   (int) (controller.version & 0xFF));
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+
+  if (get_vbe_mode_info (mode_number, &mode) != 0x004F
+      || (mode.mode_attributes & 0x0091) != 0x0091)
+    {
+      grub_printf (" Mode 0x%x is not supported.\n", mode_number);
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+
+  /* Now trip to the graphics mode.  */
+  if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
+    {
+      grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
+      errnum = MAX_ERR_NUM;
+      return 1;
+    }
+
+  get_vbe_pmif(&pmif_segoff, &pmif_len);
+  create_vbe_module(&controller, sizeof(struct vbe_controller),
+                    &mode, sizeof(struct vbe_mode), 
+		    mode_number, pmif_segoff, pmif_len, controller.version);
+
+  /* mode setting was successful */
+  return 0;
+#else
+  errnum = ERR_BAD_ARGUMENT;
+  return 1;
+#endif
+}
+
+static struct builtin builtin_vbeset =
+{
+  "vbeset",
+  vbeset_func,
+  BUILTIN_CMDLINE | BUILTIN_MENU,
+  "vbeset [MODE]",
+  "Set the VBE mode MODE. If no MODE is given, switch back to text mode."
+};
+
 /* The table of builtin commands. Sorted in dictionary order.  */
 struct builtin *builtin_table[] =
 {
@@ -4444,5 +4572,6 @@
   &builtin_unhide,
   &builtin_uppermem,
   &builtin_vbeprobe,
+  &builtin_vbeset,
   0
 };
--- char_io.c	Wed Oct 25 16:47:45 2000
+++ /home/fm3/src/prj/grub/grub/stage2/char_io.c	Thu Dec 14 10:23:25 2000
@@ -1088,7 +1088,14 @@
     }
 
   if (terminal & TERMINAL_CONSOLE)
-    console_putchar (c);
+    {
+#ifndef GRUB_UTIL
+      if (terminal & TERMINAL_CONSOLE_HERC)
+	console_herc_putchar (c);
+      else
+#endif
+	console_putchar (c);
+    }
 
 # ifdef SUPPORT_SERIAL
   if (terminal & TERMINAL_SERIAL)
@@ -1103,7 +1110,14 @@
 gotoxy (int x, int y)
 {
   if (terminal & TERMINAL_CONSOLE)
-    console_gotoxy (x, y);
+    {
+#ifndef GRUB_UTIL
+      if (terminal & TERMINAL_CONSOLE_HERC)
+	console_herc_gotoxy (x, y);
+      else
+#endif
+	console_gotoxy(x, y);
+    }
 #ifdef SUPPORT_SERIAL
   else if (terminal & TERMINAL_SERIAL)
     serial_gotoxy (x, y);
@@ -1125,7 +1139,14 @@
   int ret = 0;
   
   if (terminal & TERMINAL_CONSOLE)
-    ret = console_getxy ();
+    {
+#ifndef GRUB_UTIL
+      if (terminal & TERMINAL_CONSOLE_HERC)
+	ret = console_herc_getxy ();
+      else
+#endif
+	ret = console_getxy ();
+    }
 #ifdef SUPPORT_SERIAL
   else if (terminal & TERMINAL_SERIAL)
     ret = serial_getxy ();
@@ -1224,7 +1245,14 @@
 cls (void)
 {
   if (terminal & TERMINAL_CONSOLE)
-    console_cls ();
+    {
+#ifndef GRUB_UTIL
+      if (terminal & TERMINAL_CONSOLE_HERC)
+	console_herc_cls ();
+      else
+#endif
+	console_cls ();
+    }
 #ifdef SUPPORT_SERIAL
   else if (terminal & TERMINAL_SERIAL)
     serial_cls ();
--- stage2.c	Wed Nov 29 15:14:58 2000
+++ /home/fm3/src/prj/grub/grub/stage2/stage2.c	Fri Dec  1 11:07:17 2000
@@ -173,7 +173,10 @@
 	  for (j = 0; j < 75; j++)
 	    {
 	      gotoxy (j + 1, i + y);
-	      set_attrib (normal_color);
+	      if (terminal & TERMINAL_CONSOLE_HERC)
+		console_herc_set_attrib (normal_color);
+	      else
+		set_attrib (normal_color);
 	    }
 	}
     }
@@ -233,7 +236,12 @@
       for (x = 2; x < 75; x++)
 	{
 	  gotoxy (x, y);
-	  set_attrib (attr);
+#ifndef GRUB_UTIL
+	  if (terminal & TERMINAL_CONSOLE_HERC)
+	    console_herc_set_attrib (attr);
+	  else
+#endif
+	    set_attrib (attr);
 	}
     }
 
  boot_entry:
   /* Enable the auto fill mode.  */
   auto_fill = 1;
--- shared.h	Wed Nov 29 15:14:57 2000
+++ /home/fm3/src/prj/grub/grub/stage2/shared.h	Thu Dec  7 10:04:47 2000
@@ -748,6 +748,12 @@
 /* Set VBE mode.  */
 int set_vbe_mode (int mode_number);
 
+/* Switch to text mode */
+void reset_vbe_mode (void);
+
+/* Get VBE pm interface entry */
+void get_vbe_pmif (unsigned int *segoff, unsigned int *len);
+
 /* Return the data area immediately following our code. */
 int get_code_end (void);
 
@@ -760,6 +766,7 @@
 
 /* The console part of cls.  */
 void console_cls (void);
+void console_herc_cls (void);
 
 #ifndef GRUB_UTIL
 /* Turn off cursor. */
@@ -773,12 +780,14 @@
 
 /* The console part of getxy.  */
 int console_getxy (void);
+int console_herc_getxy (void);
 
 /* Set the cursor position. */
 void gotoxy (int x, int y);
 
 /* The console part of gotoxy.  */
 void console_gotoxy (int x, int y);
+void console_herc_gotoxy (int x, int y);
 
 /* Displays an ASCII character.  IBM displays will translate some
    characters to special graphical ones (see the DISP_* constants). */
@@ -786,6 +795,7 @@
 
 /* The console part of grub_putchar.  */
 void console_putchar (int c);
+void console_herc_putchar (int c);
 
 /* Wait for a keypress, and return its packed BIOS/ASCII key code.
    Use ASCII_CHAR(ret) to extract the ASCII code. */
@@ -804,6 +814,7 @@
 /* Sets text mode character attribute at the cursor position.  See A_*
    constants defined above. */
 void set_attrib (int attr);
+void console_herc_set_attrib (int attr);
 
 /* Low-level disk I/O */
 int get_diskinfo (int drive, struct geometry *geometry);
@@ -864,6 +875,7 @@
 
 #define TERMINAL_CONSOLE	(1 << 0)	/* keyboard and screen */
 #define TERMINAL_SERIAL		(1 << 1)	/* serial console */
+#define TERMINAL_CONSOLE_HERC	(1 << 2)	/* hercules output */
 
 #define TERMINAL_DUMB		(1 << 16)	/* dumb terminal */
 
@@ -994,6 +1006,10 @@
 
 int load_module (char *module, char *arg);
 int load_initrd (char *initrd);
+void create_vbe_module(void *ctrl_info, int ctrl_info_len,
+                       void *mode_info, int mode_info_len, 
+		       int mode, int pmif, int pmif_len, 
+		       unsigned int version);
 
 int check_password(char *entered, char* expected, password_t type);
 #endif


Reply via email to