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