--- docs/grub.texi +++ docs/grub.texi @@ -2118,6 +2118,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 @@ -2150,6 +2151,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 +++ grub/asmstub.c @@ -498,6 +498,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 +++ stage2/asm.S @@ -1614,6 +1614,286 @@ 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 + leal gfx_ofs_sys_cfg(%edx),%esi + andl $0xf,%edi + shrl $4,%edx + + pushl %ebp + + call EXT_C(prot_to_real) + .code16 + + pushw %ds + movw %dx,%ds + + lcall *gfx_ofs_jmp_table + 4 * 0 (%di) + + sbbl %ebx,%ebx + negl %ebx + + popw %ds + + DATA32 call EXT_C(real_to_prot) + .code32 + + popl %ebp + + movl %ebx,%eax + xorl $1,%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 + leal gfx_ofs_sys_cfg(%edx),%esi + andl $0xf,%ebx + shrl $4,%edx + + pushl %ebp + + call EXT_C(prot_to_real) + .code16 + + pushw %ds + + movw %dx,%ds + + movl gfx_ofs_cmdline(%bx),%edi + movl gfx_ofs_cmdline_len(%bx),%ecx + movl gfx_ofs_timeout(%bx),%eax + imull $18,%eax + + lcall *gfx_ofs_jmp_table + 4 * 2 (%bx) + + 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 + */ + +/* menu entry descriptor */ +#define menu_entries 0 +#define menu_default 2 /* seg:ofs */ +#define menu_ent_list 6 /* seg:ofs */ +#define menu_ent_size 10 +#define menu_arg_list 12 /* seg:ofs */ +#define menu_arg_size 16 +#define sizeof_menu_desc 18 + +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 + + subw $sizeof_menu_desc,%sp + movw %esp,%ebp + + movl gfx_ofs_menu_entries(%bx),%eax + movw %ax,menu_entries(%bp) + + movl gfx_ofs_menu_default_entry(%bx),%eax + subl %edx,%eax + movw %ax,menu_default(%bp) + movw %ds,menu_default+2(%bp) + + movl gfx_ofs_menu_list(%bx),%eax + subl %edx,%eax + movw %ax,menu_ent_list(%bp) + movw %ds,menu_ent_list+2(%bp) + + movl gfx_ofs_menu_entry_len(%bx),%eax + movw %ax,menu_ent_size(%bp) + + movl gfx_ofs_args_list(%bx),%eax + subl %edx,%eax + movw %ax,menu_arg_list(%bp) + movw %ds,menu_arg_list+2(%bp) + + movl gfx_ofs_args_entry_len(%bx),%eax + movw %ax,menu_arg_size(%bp) + + movl %ss,%esi + shll $4,%esi + addl %ebp,%esi + + lcall %ds: *gfx_ofs_jmp_table + 4 * 3 (%bx) + + addw $sizeof_menu_desc,%sp + + 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 +++ stage2/builtins.c @@ -63,6 +63,8 @@ int fallback_entries[MAX_FALLBACK_ENTRIES]; /* 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. */ @@ -1351,6 +1353,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) @@ -4874,6 +4896,7 @@ &builtin_find, &builtin_fstest, &builtin_geometry, + &builtin_gfxmenu, &builtin_halt, &builtin_help, &builtin_hiddenmenu, --- stage2/shared.h +++ stage2/shared.h @@ -374,6 +374,22 @@ #endif /* WITHOUT_LIBC_STUBS */ +/* see typedef gfx_data_t below */ +#define gfx_ofs_ok 0x00 +#define gfx_ofs_code_seg 0x04 +#define gfx_ofs_jmp_table 0x08 +#define gfx_ofs_sys_cfg 0x38 +#define gfx_ofs_cmdline 0x6c +#define gfx_ofs_cmdline_len 0x70 +#define gfx_ofs_menu_list 0x74 +#define gfx_ofs_menu_default_entry 0x78 +#define gfx_ofs_menu_entries 0x7c +#define gfx_ofs_menu_entry_len 0x80 +#define gfx_ofs_args_list 0x84 +#define gfx_ofs_args_entry_len 0x88 +#define gfx_ofs_timeout 0x8c + + #ifndef ASM_FILE /* * Below this should be ONLY defines and other constructs for C code. @@ -595,6 +611,38 @@ 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 code_seg; /* code segment of binary graphics code */ + unsigned jmp_table[12]; /* link to graphics functions */ + unsigned char sys_cfg[52]; /* sys_cfg[0]: 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 +++ stage2/stage2.c @@ -22,6 +22,8 @@ grub_jmp_buf restart_env; +gfx_data_t *graphics_data; + #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS) # if defined(PRESET_MENU_STRING) @@ -310,6 +312,12 @@ if (! auth && password) { + if (*graphics_file) + { + printf ("\ + WARNING: graphical menu doesn\'t work\ + in conjunction with the password feature\n" ); + } printf ("\ Press enter to boot the selected OS or \'p\' to enter a\n\ password to unlock the next set of features."); @@ -753,6 +761,493 @@ } + +#if 0 +/* 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); + } +} +#endif + + +/* kernel + (grub-)module options */ +#define GFX_CMD_BUF_SIZE 512 + +/* command line separator char */ +#define GFX_CMD_SEP 1 + +/* + * Go through config entry and find kernel args, if any. + * Put things into buf and return it. + */ +static char *get_kernel_args(char *cfg, char *buf) +{ + int i, j; + char *s, *t = "", *p, *t2; + + *(p = buf) = 0; + + for(j = 0; ; j++) { + s = get_entry(cfg, j, 0); + if(!*s) break; + if( + (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) && + (s[6] == ' ' || s[6] == '\t') + ) { + t = skip_to(0, s); + t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL; + if(*t) t = skip_to(0, t); + if(t2 && t2 < t) break; /* module is likely a normal initrd -> skip */ + i = strlen(t); + if(p - buf + i > GFX_CMD_BUF_SIZE - 2) break; + *p++ = GFX_CMD_SEP; + strcpy(p, t); + p += i; + + continue; + } + } + + if(*buf) buf++; /* skip initial separator char */ + + return buf; +} + + +/* + * Check header and return code start offset. + */ +static unsigned magic_ok(unsigned char *buf) +{ + if( + *(unsigned *) buf == 0x0b2d97f00 && /* magic id */ + (buf[4] == 8) /* version 8 */ + ) { + return *(unsigned *) (buf + 8); + } + + return 0; +} + + +/* + * Search cpio archive for gfx file. + */ +static unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len) +{ + unsigned i, fname_len, code_start = 0; + + *gfx_file_start = 0; + + for(i = 0; i < len;) { + if((len - i) >= 0x1a && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) { + fname_len = *(unsigned short *) (buf + i + 20); + *file_len = *(unsigned short *) (buf + i + 24) + (*(unsigned short *) (buf + i + 22) << 16); + i += 26 + fname_len; + i = ((i + 1) & ~1); + if((code_start = magic_ok(buf + i))) { + *gfx_file_start = i; + return code_start; + } + i += *file_len; + i = ((i + 1) & ~1); + } + else { + break; + } + } + + return code_start; +} + +static inline unsigned char * stack_ptr(void) +{ + unsigned char * u; + + asm("movl %%esp, %0" : "=r" (u)); + + return u; +} + +static void sleep(int delay) +{ + int tick, last_tick = currticks(); + + delay *= 18; + + while(delay--) { + while((tick = currticks()) == last_tick) { } + last_tick = tick; + } +} + +static void wait_for_key() +{ + printf("Press a key to continue..."); + getkey(); + printf("\r \r"); +} + + +/* + * Leave that much space on the heap. Everything else goes to the graphics + * functions. + * + * 0x2000 is _not_ enough + */ +#define MIN_HEAP_SIZE 0x4000 +#define MIN_GFX_FREE 0x1000 + +#define SC_BOOTLOADER 0 +#define SC_FAILSAFE 3 +#define SC_SYSCONFIG_SIZE 4 +#define SC_BOOTLOADER_SEG 8 +#define SC_XMEM_0 24 +#define SC_XMEM_1 26 +#define SC_XMEM_2 28 +#define SC_XMEM_3 30 +#define SC_FILE 32 +#define SC_ARCHIVE_START 36 +#define SC_ARCHIVE_END 40 +#define SC_MEM0_START 44 +#define SC_MEM0_END 48 + +/* + * 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, *buf_ext; + unsigned buf_size, buf_ext_size, code_start, file_start; + char *s, *t, *t2, *cfg, *new_config, *p; + char *saved_heap; + int i, j, max_len, gfx_file_size, verbose; + int selected_entry; + gfx_data_t *gfx_data; + char *cmd_buf; + unsigned mem0_start, mem0_end, file_len; + + /* + * 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(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[SC_BOOTLOADER] = 2; /* bootloader: grub */ + gfx_data->sys_cfg[SC_SYSCONFIG_SIZE] = 52; /* config data size */ + *(unsigned short *) (gfx_data->sys_cfg + SC_BOOTLOADER_SEG) = (unsigned) gfx_data >> 4; /* segment */ + gfx_data->sys_cfg[SC_XMEM_0] = 0x21; /* 1MB @ 2MB */ + gfx_data->sys_cfg[SC_XMEM_1] = 0x41; /* 1MB @ 4MB */ + verbose = (*(unsigned char *) 0x417) & 3 ? 1 : 0; /* SHIFT pressed */ + gfx_data->sys_cfg[SC_FAILSAFE] = verbose; + + 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); + + cmd_buf = heap; + heap += GFX_CMD_BUF_SIZE; + + /* 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 < (int) 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), cmd_buf); + 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 < (int) 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), cmd_buf)); + } + + + /* go back here when we no longer need the graphics data */ + saved_heap = heap; + + + /* get memory area to be used by graphics functions */ + + /* use 1MB starting at 2MB as file buffer */ + buf_ext = (unsigned char *) (2 << 20); + buf_ext_size = 1 << 20; + + /* must be 16-byte aligned */ + buf = (unsigned char *) (((unsigned) heap + 0xf) & ~0xf); + + buf_size = stack_ptr() - buf - MIN_HEAP_SIZE; + buf_size &= ~0xf; + + mem0_start = (unsigned) buf; + mem0_end = mem0_start + buf_size; + + if(verbose) { + printf("low memory 0x%x - 0x%x (%d bytes)\n", mem0_start, mem0_end, buf_size); + wait_for_key(); + } + + heap += buf_size; + + /* read the file */ + + if(!grub_open(graphics_file)) { + printf("%s: file not found\n", graphics_file); + sleep(5); + heap = saved_heap; + return; + } + + gfx_file_size = grub_read(buf_ext, buf_ext_size); + + grub_close(); + + if(gfx_file_size <= 0) { + printf("%s: read error\n", graphics_file); + sleep(5); + heap = saved_heap; + return; + } + + if(verbose) { + printf("%s: %d bytes (%d bytes left)\n", graphics_file, gfx_file_size, buf_ext_size - gfx_file_size); + wait_for_key(); + } + + /* locate file inside cpio archive */ + if(!(code_start = find_file(buf_ext, gfx_file_size, &file_start, &file_len))) { + printf("%s: invalid file format\n", graphics_file); + sleep(5); + heap = saved_heap; + return; + } + + if(verbose) { + printf("init: start 0x%x, len %d; code offset 0x%x\n", file_start, file_len, code_start); + wait_for_key(); + } + + if(file_len - code_start + MIN_GFX_FREE > buf_size) { + printf("not enough free memory: %d extra bytes need\n", file_len - code_start + MIN_GFX_FREE - buf_size); + sleep(5); + heap = saved_heap; + return; + } + + memcpy((void *) buf, (void *) (buf_ext + file_start + code_start), file_len - code_start); + + mem0_start += file_len - code_start; + mem0_start = (mem0_start + 3) & ~3; /* align */ + + /* init interface to graphics functions */ + + *(unsigned *) (gfx_data->sys_cfg + SC_FILE) = (unsigned) buf_ext + file_start; + *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_START) = (unsigned) buf_ext; + *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_END) = (unsigned) buf_ext + gfx_file_size; + *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_START) = mem0_start; + *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_END) = mem0_end; + + gfx_data->code_seg = (unsigned) buf >> 4; + + if(verbose) { + printf("init 0x%x, archive 0x%x - 0x%x, low mem 0x%x - 0x%x\ncode seg 0x%x\n", + (unsigned) buf_ext + file_start, + (unsigned) buf_ext, (unsigned) buf_ext + gfx_file_size, + mem0_start, mem0_end, gfx_data->code_seg + ); + wait_for_key(); + } + + for(i = 0; (unsigned) i < sizeof gfx_data->jmp_table / sizeof *gfx_data->jmp_table; i++) { + gfx_data->jmp_table[i] = (gfx_data->code_seg << 16) + ((unsigned short *) buf)[i]; + } + + if(verbose) { + 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("default: \"%s\"\n", gfx_data->menu_default_entry); + wait_for_key(); + } + + /* switch to graphics mode */ + + if(gfx_init(gfx_data)) { + printf("graphics initialization failed\n"); + sleep(5); + heap = saved_heap; + 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; + + heap = saved_heap; + return; + } + + gfx_done(gfx_data); + + heap = saved_heap; /* free most of the graphics 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(p = gfx_data->cmdline, i = 0; ; i++) { + s = get_entry(cfg, i, 0); + if(!*s) { + if(!i) *heap++ = 0; + *heap++ = 0; + break; + } + /* note: must match get_kernel_args() */ + if( + (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) && + (s[6] == ' ' || s[6] == '\t') + ) { + t = skip_to(0, s); + t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL; + if(*t) t = skip_to(0, t); + if(t2 && t2 < t) { /* module is likely a normal initrd -> skip */ + strcpy(heap, s); + heap += strlen(s) + 1; + continue; + } + memmove(heap, s, t - s); + heap += t - s; + *heap++ = ' '; + while(*p && *p != GFX_CMD_SEP) *heap++ = *p++; + *heap++ = 0; + if(*p == GFX_CMD_SEP) p++; + } + 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) { @@ -1062,9 +1557,12 @@ } else { - /* Run menu interface. */ - run_menu (menu_entries, config_entries, num_entries, - menu_entries + menu_len, default_entry); + if (*graphics_file && !password && show_menu && grub_timeout) + { + 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); } } } --- stage2/stage2.c +++ stage2/stage2.c @@ -1199,6 +1199,9 @@ if(selected_entry < 0 || selected_entry > num_entries) return; + /* for 'savedefault' */ + current_entryno = selected_entry; + /* create new config with modified kernel option */