Group :: System/Kernel and hardware
RPM: grub
Main Changelog Spec Patches Sources Download Gear Bugs and FR Repocop
Patch: grub-0.92-suse-graphics.patch
Download
Download
--- docs/grub.texi Mon Apr 29 02:34:43 2002
+++ docs/grub.texi Wed Jul 17 14:05:25 2002
@@ -1812,6 +1812,7 @@
* default:: Set the default entry
* fallback:: Set the fallback entry
* hiddenmenu:: Hide the menu interface
+* gfxmenu:: Use graphical menu interface
* timeout:: Set the timeout
* title:: Start a menu entry
@end menu
@@ -1843,6 +1844,15 @@
@end deffn
+@node gfxmenu
+@subsection gfxmenu
+
+@deffn Command gfxmenu file
+Use the graphical menu interface. The graphics data are taken from
+@var{file} and must be created using 'mkbootmsg' from the gfxboot package.
+@end deffn
+
+
@node hiddenmenu
@subsection hiddenmenu
--- grub/asmstub.c Sat Jan 19 20:05:43 2002
+++ grub/asmstub.c Wed Jul 17 11:45:46 2002
@@ -473,6 +473,32 @@
return 0;
}
+/* graphical menu functions . */
+int
+gfx_init (gfx_data_t *gfx_data)
+{
+ return 0;
+}
+
+int
+gfx_done (gfx_data_t *gfx_data)
+{
+ return 0;
+}
+
+int
+gfx_input (gfx_data_t *gfx_data, int *menu_entry)
+{
+ return 0;
+}
+
+int
+gfx_setup_menu (gfx_data_t *gfx_data)
+{
+ return 0;
+}
+
+
/* low-level timing info */
int
getrtsecs (void)
--- stage2/asm.S Mon Nov 12 07:57:29 2001
+++ stage2/asm.S Thu Jul 18 14:35:59 2002
@@ -1682,6 +1682,262 @@
popl %ebp
ret
+
+/*
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ *
+ * graphical menu functions
+ *
+ */
+
+/*
+ * int gfx_init (gfx_data_t *gfx_data)
+ *
+ * init gfx things
+ *
+ * return vales:
+ * 0: ok
+ * 1: failed
+ * sets gfx_data->ok
+ */
+
+ENTRY(gfx_init)
+ pushl %ebp
+ movl %esp, %ebp
+
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ movl 8(%ebp),%edx
+ movl %edx,%edi
+ andl $0xf,%edi
+ shrl $4,%edx
+
+ pushl %ebp
+
+ call EXT_C(prot_to_real)
+ .code16
+
+ pushw %ds
+
+ movw %dx,%ds
+ shll $4,%edx
+ leal gfx_ofs_sys_cfg(%di),%esi
+ movl gfx_ofs_mem_start(%di),%eax
+ movl gfx_ofs_mem_cur(%di),%ebx
+ movl gfx_ofs_mem_max(%di),%ecx
+ movw %ds,%dx
+
+ lcall *gfx_ofs_jmp_table + 4 * 0 (%di)
+
+ movl $0,%ebx
+ adcl $0,%ebx
+
+ popw %ds
+
+ DATA32 call EXT_C(real_to_prot)
+ .code32
+
+ popl %ebp
+
+ movl %ebx,%eax
+ negl %ebx
+ incl %ebx
+ movl 8(%ebp),%edx
+ movl %ebx,gfx_ofs_ok(%edx)
+
+ popl %ebx
+ popl %esi
+ popl %edi
+
+ popl %ebp
+ ret
+
+
+/*
+ * int gfx_done (gfx_data_t *gfx_data)
+ *
+ * shut down gfx things
+ *
+ * return vales:
+ * always 0
+ * sets gfx_data->ok
+ */
+
+ENTRY(gfx_done)
+ pushl %ebp
+ movl %esp, %ebp
+
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ movl 8(%ebp),%edx
+ movl %edx,%ebx
+ andl $0xf,%ebx
+ shrl $4,%edx
+
+ pushl %ebp
+
+ call EXT_C(prot_to_real)
+ .code16
+
+ pushw %ds
+
+ movw %dx,%ds
+
+ lcall *gfx_ofs_jmp_table + 4 * 1 (%bx)
+
+ popw %ds
+
+ DATA32 call EXT_C(real_to_prot)
+ .code32
+
+ popl %ebp
+
+ xorl %eax,%eax
+ movl 8(%ebp),%edx
+ movl %eax,gfx_ofs_ok(%edx)
+
+ popl %ebx
+ popl %esi
+ popl %edi
+
+ popl %ebp
+ ret
+
+
+/*
+ * int gfx_input (gfx_data_t *gfx_data, int *menu_entry)
+ *
+ * let user enter a command line
+ *
+ * uses gfx_data->cmdline as buffer
+ *
+ * return values:
+ * 1: abort
+ * 2: boot
+ * menu_entry: selected entry
+ */
+
+ENTRY(gfx_input)
+ pushl %ebp
+ movl %esp, %ebp
+
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ movl 8(%ebp),%edx
+ movl %edx,%ebx
+ andl $0xf,%ebx
+ shrl $4,%edx
+
+ pushl %ebp
+
+ call EXT_C(prot_to_real)
+ .code16
+
+ pushw %ds
+
+ movw %dx,%ds
+ shll $4,%edx
+ movl gfx_ofs_cmdline(%bx),%edi
+ subl %edx,%edi
+ movw gfx_ofs_cmdline_len(%bx),%cx
+ movw gfx_ofs_timeout(%bx),%ax
+ imulw $18,%ax
+
+ pushl %ebp
+ lcall *gfx_ofs_jmp_table + 4 * 2 (%bx)
+ popl %ebp
+ movl %eax,%ecx
+
+ popw %ds
+
+ DATA32 call EXT_C(real_to_prot)
+ .code32
+
+ popl %ebp
+
+ movl 12(%ebp),%edx
+ movl %ebx,(%edx)
+
+ movl %ecx,%eax
+
+ popl %ebx
+ popl %esi
+ popl %edi
+
+ popl %ebp
+ ret
+
+
+/*
+ * int gfx_setup_menu (gfx_data_t *gfx_data)
+ *
+ * draw boot menu
+ *
+ * return values:
+ * always 0
+ */
+
+ENTRY(gfx_setup_menu)
+ pushl %ebp
+ movl %esp, %ebp
+
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ movl 8(%ebp),%edx
+ movl %edx,%ebx
+ andl $0xf,%ebx
+ shrl $4,%edx
+
+ call EXT_C(prot_to_real)
+ .code16
+
+ pushw %ds
+
+ movw %dx,%ds
+ shll $4,%edx
+ movl gfx_ofs_menu_list(%bx),%edi
+ movl gfx_ofs_menu_default_entry(%bx),%esi
+ movl gfx_ofs_args_list(%bx),%ebp
+ subl %edx,%edi
+ subl %edx,%esi
+ subl %edx,%ebp
+ movl gfx_ofs_menu_entry_len(%bx),%edx
+ movl gfx_ofs_args_entry_len(%bx),%ecx
+ movl gfx_ofs_menu_entries(%bx),%eax
+
+ xchg %bx,%bp
+ lcall %ds: *gfx_ofs_jmp_table + 4 * 3 (%bp)
+
+ popw %ds
+
+ DATA32 call EXT_C(real_to_prot)
+ .code32
+
+ xorl %eax,%eax
+
+ popl %ebx
+ popl %esi
+ popl %edi
+
+ popl %ebp
+ ret
+
+
+/*
+ *
+ * end graphics stuff
+ *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
/*
* gateA20(int linear)
--- stage2/builtins.c Mon Apr 29 02:26:49 2002
+++ stage2/builtins.c Wed Jul 17 14:11:30 2002
@@ -62,6 +62,8 @@
int fallback_entry = -1;
/* The number of current entry. */
int current_entryno;
+/* graphics file */
+char graphics_file[64];
/* The address for Multiboot command-line buffer. */
static char *mb_cmdline;
/* The password. */
@@ -1327,6 +1329,26 @@
};
+/* graphics */
+static int
+gfxmenu_func (char *arg, int flags)
+{
+ memmove(graphics_file, arg, sizeof graphics_file - 1);
+ graphics_file[sizeof graphics_file - 1] = 0;
+
+ return 0;
+}
+
+static struct builtin builtin_gfxmenu =
+{
+ "gfxmenu",
+ gfxmenu_func,
+ BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "gfxmenu FILE",
+ "Use the graphical menu from FILE."
+};
+
+
/* geometry */
static int
geometry_func (char *arg, int flags)
@@ -4605,6 +4627,7 @@
&builtin_find,
&builtin_fstest,
&builtin_geometry,
+ &builtin_gfxmenu,
&builtin_halt,
&builtin_help,
&builtin_hiddenmenu,
--- stage2/shared.h Mon Mar 25 22:43:55 2002
+++ stage2/shared.h Wed Jul 17 12:18:36 2002
@@ -379,6 +379,25 @@
#endif /* WITHOUT_LIBC_STUBS */
+/* see typedef gfx_data_t below */
+#define gfx_ofs_ok 0x00
+#define gfx_ofs_mem_start 0x04
+#define gfx_ofs_mem_cur 0x08
+#define gfx_ofs_mem_max 0x0c
+#define gfx_ofs_code_seg 0x10
+#define gfx_ofs_jmp_table 0x14
+#define gfx_ofs_sys_cfg 0x44
+#define gfx_ofs_cmdline 0x48
+#define gfx_ofs_cmdline_len 0x4c
+#define gfx_ofs_menu_list 0x50
+#define gfx_ofs_menu_default_entry 0x54
+#define gfx_ofs_menu_entries 0x58
+#define gfx_ofs_menu_entry_len 0x5c
+#define gfx_ofs_args_list 0x60
+#define gfx_ofs_args_entry_len 0x64
+#define gfx_ofs_timeout 0x68
+
+
#ifndef ASM_FILE
/*
* Below this should be ONLY defines and other constructs for C code.
@@ -596,6 +615,39 @@
extern int default_entry;
extern int current_entryno;
+
+/*
+ * graphics menu stuff
+ *
+ * Note: gfx_data and all data referred to in it must lie within a 64k area.
+ */
+typedef struct {
+ unsigned ok; /* set while we're in graphics mode */
+ unsigned mem_start, mem_cur, mem_max;
+ unsigned code_seg; /* code segment of binary graphics code */
+ unsigned jmp_table[12]; /* link to graphics functions */
+ unsigned char sys_cfg[4]; /* sys_cfg[3]: identifies boot loader (grub == 2) */
+ char *cmdline; /* command line returned by gfx_input() */
+ unsigned cmdline_len; /* length of the above */
+ char *menu_list; /* list of menu entries, each of fixed length (menu_entry_len) */
+ char *menu_default_entry; /* the default entry */
+ unsigned menu_entries; /* number of entries in menu_list */
+ unsigned menu_entry_len; /* one entry */
+ char *args_list; /* same structure as menu_list, menu_entries entries */
+ unsigned args_entry_len; /* one entry */
+ unsigned timeout; /* in seconds (0: no timeout) */
+} __attribute__ ((packed)) gfx_data_t;
+
+extern gfx_data_t *graphics_data;
+
+/* pointer to graphics image data */
+extern char graphics_file[64];
+
+int gfx_init(gfx_data_t *gfx_data);
+int gfx_done(gfx_data_t *gfx_data);
+int gfx_input(gfx_data_t *gfx_data, int *menu_entry);
+int gfx_setup_menu(gfx_data_t *gfx_data);
+
/* The constants for password types. */
typedef enum
{
--- stage2/stage2.c Sun Mar 24 13:28:54 2002
+++ stage2/stage2.c Thu Jul 18 14:34:14 2002
@@ -21,6 +21,8 @@
grub_jmp_buf restart_env;
+gfx_data_t *graphics_data;
+
#if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
# if defined(PRESET_MENU_STRING)
@@ -845,6 +847,334 @@
}
+
+/* for debugging */
+static void hexdump(unsigned char *buf, unsigned len)
+{
+ int i, j = 0;
+ char s[17];
+ unsigned addr = (unsigned) buf;
+
+ s[16] = 0;
+ while(len--) {
+ i = buf[j];
+ i = i & 0xff;
+ s[j & 15] = (i >= 0x20 && i <= 0x7e) ? i : '.';
+ if(!(j & 15)) {
+ printf("%x ", j + addr);
+ }
+ if(!(j & 7) && (j & 15)) printf(" ");
+ /* stupid grub_printf */
+ printf("%x", (i >> 4) & 0x0f);
+ printf("%x ", i & 0x0f);
+ if(!(++j & 15)) {
+ printf(" %s\n", s);
+ }
+ }
+
+ if(j & 15) {
+ s[j & 15] = 0;
+ if(!(j & 8)) printf(" ");
+ i = 1 + 3 * (16 - (j & 15));
+ while(i--) printf(" ");
+ printf("%s\n", s);
+ }
+}
+
+
+/*
+ * Go through config entry and find kernel args, if any.
+ */
+static char *get_kernel_args(char *cfg)
+{
+ int j;
+ char *s, *t = "";
+
+ for(j = 0; ; j++) {
+ s = get_entry(cfg, j, 0);
+ if(!*s) break;
+ if(!memcmp(s, "kernel", 6) && (s[6] == ' ' || s[6] == '\t')) {
+ t = skip_to(0, s);
+ if(*t) t = skip_to(0, t);
+ break;
+ }
+ }
+
+ return t;
+}
+
+
+/*
+ * Leave that much space on the heap. Everything else goes to the graphics
+ * functions.
+ *
+ * 0x2000 is _not_ enough
+ */
+#define MIN_HEAP_SIZE 0x4000
+
+/* gfx code needs at least this much free memory */
+#define MIN_GFX_FREE 0x4000
+
+/*
+ * Does normally not return.
+ */
+static void
+run_graphics_menu (char *menu_entries, char *config_entries, int num_entries,
+ char *heap, int entryno)
+{
+ unsigned char *buf;
+ unsigned buf_size, code_start;
+ char *s, *t, *cfg, *new_config;
+ int i, j, max_len;
+ int selected_entry;
+ gfx_data_t *gfx_data;
+
+ /*
+ * check gfx_data_t struct offsets for consistency; gcc will optimize away
+ * the whole block
+ */
+
+ /* dummy function to make ld fail */
+ {
+ extern void wrong_struct_size(void);
+ #define gfx_ofs_check(a) if(gfx_ofs_##a != (char *) &gfx_data->##a - (char *) gfx_data) wrong_struct_size();
+ gfx_ofs_check(ok);
+ gfx_ofs_check(mem_start);
+ gfx_ofs_check(mem_cur);
+ gfx_ofs_check(mem_max);
+ gfx_ofs_check(code_seg);
+ gfx_ofs_check(jmp_table);
+ gfx_ofs_check(sys_cfg);
+ gfx_ofs_check(cmdline);
+ gfx_ofs_check(cmdline_len);
+ gfx_ofs_check(menu_list);
+ gfx_ofs_check(menu_default_entry);
+ gfx_ofs_check(menu_entries);
+ gfx_ofs_check(menu_entry_len);
+ gfx_ofs_check(args_list);
+ gfx_ofs_check(args_entry_len);
+ gfx_ofs_check(timeout);
+ #undef gfx_ofs_check
+ }
+
+ if(!num_entries) return;
+
+ graphics_data = gfx_data = (gfx_data_t *) heap;
+ heap += sizeof *gfx_data;
+ memset(gfx_data, 0, sizeof *gfx_data);
+
+ gfx_data->sys_cfg[2] = 2; /* bootloader: grub */
+ gfx_data->timeout = grub_timeout >= 0 ? grub_timeout : 0;
+
+
+ /* setup command line edit buffer */
+
+ gfx_data->cmdline_len = 256;
+
+ gfx_data->cmdline = heap;
+ heap += gfx_data->cmdline_len;
+ memset(gfx_data->cmdline, 0, gfx_data->cmdline_len);
+
+
+ /* setup menu entries */
+
+ for(i = max_len = 0; i < num_entries; i++) {
+ j = strlen(get_entry(menu_entries, i, 0));
+ if(j > max_len) max_len = j;
+ }
+
+ if(!max_len) return;
+
+ gfx_data->menu_entry_len = max_len + 1;
+ gfx_data->menu_entries = num_entries;
+
+ gfx_data->menu_list = heap;
+ heap += gfx_data->menu_entry_len * gfx_data->menu_entries;
+
+ memset(gfx_data->menu_list, 0, gfx_data->menu_entry_len * gfx_data->menu_entries);
+
+ for(i = 0; i < gfx_data->menu_entries; i++) {
+ strcpy(gfx_data->menu_list + i * gfx_data->menu_entry_len, get_entry(menu_entries, i, 0));
+ }
+
+ gfx_data->menu_default_entry = gfx_data->menu_list + entryno * gfx_data->menu_entry_len;
+
+
+ /* setup list of kernel args */
+
+ for(i = max_len = 0; i < num_entries; i++) {
+ s = get_kernel_args(get_entry(config_entries, i, 1));
+ j = strlen(s);
+ if(j > max_len) max_len = j;
+ }
+
+ gfx_data->args_entry_len = max_len + 1;
+
+ gfx_data->args_list = heap;
+ heap += gfx_data->args_entry_len * gfx_data->menu_entries;
+
+ memset(gfx_data->args_list, 0, gfx_data->args_entry_len * gfx_data->menu_entries);
+
+ for(i = 0; i < gfx_data->menu_entries; i++) {
+ strcpy(gfx_data->args_list + i* gfx_data->args_entry_len, get_kernel_args(get_entry(config_entries, i, 1)));
+ }
+
+
+ /* get memory area to be used by graphics functions */
+
+ buf = (unsigned char *) (((unsigned) heap + 0xf) & ~0xf);
+
+ buf_size = (unsigned char *) &buf - buf - MIN_HEAP_SIZE;
+ buf_size &= ~0xf;
+
+ /* too small */
+ if(buf_size < 0x10000) return;
+
+ gfx_data->mem_start = (unsigned) buf;
+ gfx_data->mem_max = gfx_data->mem_start + buf_size;
+
+#if 0
+ printf("graphics menu\n");
+ printf(
+ "heap = 0x%x, buf = 0x%x (0x%x bytes), graphics_file = %s\n",
+ heap, gfx_data->mem_start, buf_size, graphics_file
+ );
+ getkey();
+#endif
+
+ heap += buf_size;
+
+
+ /* read the file */
+
+ if(!grub_open(graphics_file)) {
+ printf("graphics file \"%s\" missing, press a key to continue...\n", graphics_file);
+ getkey();
+ return;
+ }
+
+ i = grub_read(buf, buf_size);
+
+ grub_close();
+
+ if(i <= 0) {
+ printf("error reading \"%s\", press a key to continue...\n", graphics_file);
+ getkey();
+ return;
+ }
+
+ /* besides the file, we need some working memory, too */
+ if(i + MIN_GFX_FREE >= buf_size) {
+ printf("file \"%s\" too large, press a key to continue...\n", graphics_file);
+ getkey();
+ return;
+ }
+
+ gfx_data->mem_cur = gfx_data->mem_start + ((i + 3) & ~3); /* align it */
+
+ // printf("image: %d bytes (%d bytes left)\n", i, gfx_data->mem_max - gfx_data->mem_cur);
+ // getkey();
+
+ if(
+ *(unsigned *) buf != 0x0b2d97f00 || /* magic id */
+ buf[4] != 3 || /* version 3 */
+ !(code_start = *(unsigned *) (buf + 8)) ||
+ (code_start & 0xf) /* check alignment */
+ ) {
+ printf("\"%s\" has wrong format, press a key to continue...\n", graphics_file);
+ getkey();
+ return;
+ }
+
+
+ /* init interface to graphics functions */
+
+ code_start += gfx_data->mem_start;
+
+ gfx_data->code_seg = code_start >> 4;
+
+ // printf("code start = 0x%x, code_seg = 0x%x\n", code_start, gfx_data->code_seg);
+
+ for(i = 0; i < sizeof gfx_data->jmp_table / sizeof *gfx_data->jmp_table; i++) {
+ gfx_data->jmp_table[i] = (gfx_data->code_seg << 16) + ((unsigned short *) code_start)[i];
+ }
+
+#if 0
+ for(i = 0; i < 12; i++) {
+ printf("%d: 0x%x\n", i, gfx_data->jmp_table[i]);
+ }
+
+ for(i = 0; i < gfx_data->menu_entries; i++) {
+ printf(">%s< - >%s<\n",
+ gfx_data->menu_list + i * gfx_data->menu_entry_len,
+ gfx_data->args_list + i * gfx_data->args_entry_len
+ );
+ }
+
+ printf("def: >%s<\n", gfx_data->menu_default_entry);
+#endif
+
+
+ /* switch to graphics mode */
+
+ if(gfx_init(gfx_data)) return;
+
+ gfx_setup_menu(gfx_data);
+
+ i = gfx_input(gfx_data, &selected_entry);
+
+ /* ESC -> show text menu */
+ if(i == 1) {
+ gfx_done(gfx_data);
+ grub_timeout = -1;
+
+ return;
+ }
+
+ gfx_done(gfx_data);
+
+ // printf("cmdline: >%s<, entry = %d\n", gfx_data->cmdline, selected_entry);
+
+ if(selected_entry < 0 || selected_entry > num_entries) return;
+
+
+ /* create new config with modified kernel option */
+
+ cfg = get_entry(config_entries, selected_entry, 1);
+
+ new_config = heap;
+
+ for(i = 0; ; i++) {
+ s = get_entry(cfg, i, 0);
+ if(!*s) {
+ if(!i) *heap++ = 0;
+ *heap++ = 0;
+ break;
+ }
+ if(!memcmp(s, "kernel", 6) && (s[6] == ' ' || s[6] == '\t')) {
+ t = skip_to(0, s);
+ if(*t) t = skip_to(0, t);
+ memmove(heap, s, t - s);
+ heap += t - s;
+ *heap++ = ' ';
+ strcpy(heap, gfx_data->cmdline);
+ heap += strlen(gfx_data->cmdline) + 1;
+ }
+ else {
+ strcpy(heap, s);
+ heap += strlen(s) + 1;
+ }
+ }
+
+ *heap++ = 0;
+
+ // hexdump(new_config, heap - new_config);
+ // getkey();
+
+ run_script(new_config, heap);
+}
+
+
static int
get_line_from_config (char *cmdline, int maxlen, int read_from_file)
{
@@ -1078,9 +1408,12 @@
}
else
{
- /* Run menu interface. */
- run_menu (menu_entries, config_entries, num_entries,
- menu_entries + menu_len, default_entry);
+ if (*graphics_file)
+ {
+ run_graphics_menu(menu_entries, config_entries, num_entries,menu_entries + menu_len, default_entry);
+ }
+ /* Run menu interface. */
+ run_menu (menu_entries, config_entries, num_entries, menu_entries + menu_len, default_entry);
}
}
}