]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blame - src/patches/grub-gfxmenu-v8.diff
Das kleine AJAX-Bandbreitenmeter gefixt. Zeigte zu hohe Werte aufgrund eines Berechnu...
[people/teissler/ipfire-2.x.git] / src / patches / grub-gfxmenu-v8.diff
CommitLineData
c98e55d8
HS
1--- docs/grub.texi
2+++ docs/grub.texi
3@@ -2118,6 +2118,7 @@
4 * default:: Set the default entry
5 * fallback:: Set the fallback entry
6 * hiddenmenu:: Hide the menu interface
7+* gfxmenu:: Use graphical menu interface
8 * timeout:: Set the timeout
9 * title:: Start a menu entry
10 @end menu
11@@ -2150,6 +2151,15 @@
12 @end deffn
13
14
15+@node gfxmenu
16+@subsection gfxmenu
17+
18+@deffn Command gfxmenu file
19+Use the graphical menu interface. The graphics data are taken from
20+@var{file} and must be created using 'mkbootmsg' from the gfxboot package.
21+@end deffn
22+
23+
24 @node hiddenmenu
25 @subsection hiddenmenu
26
27--- grub/asmstub.c
28+++ grub/asmstub.c
29@@ -498,6 +498,32 @@
30 return 0;
31 }
32
33+/* graphical menu functions . */
34+int
35+gfx_init (gfx_data_t *gfx_data)
36+{
37+ return 0;
38+}
39+
40+int
41+gfx_done (gfx_data_t *gfx_data)
42+{
43+ return 0;
44+}
45+
46+int
47+gfx_input (gfx_data_t *gfx_data, int *menu_entry)
48+{
49+ return 0;
50+}
51+
52+int
53+gfx_setup_menu (gfx_data_t *gfx_data)
54+{
55+ return 0;
56+}
57+
58+
59 /* low-level timing info */
60 int
61 getrtsecs (void)
62--- stage2/asm.S
63+++ stage2/asm.S
64@@ -1614,6 +1614,286 @@
65 popl %ebp
66 ret
67
68+
69+/*
70+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71+ *
72+ * graphical menu functions
73+ *
74+ */
75+
76+/*
77+ * int gfx_init (gfx_data_t *gfx_data)
78+ *
79+ * init gfx things
80+ *
81+ * return vales:
82+ * 0: ok
83+ * 1: failed
84+ * sets gfx_data->ok
85+ */
86+
87+ENTRY(gfx_init)
88+ pushl %ebp
89+ movl %esp, %ebp
90+
91+ pushl %edi
92+ pushl %esi
93+ pushl %ebx
94+
95+ movl 8(%ebp),%edx
96+ movl %edx,%edi
97+ leal gfx_ofs_sys_cfg(%edx),%esi
98+ andl $0xf,%edi
99+ shrl $4,%edx
100+
101+ pushl %ebp
102+
103+ call EXT_C(prot_to_real)
104+ .code16
105+
106+ pushw %ds
107+ movw %dx,%ds
108+
109+ lcall *gfx_ofs_jmp_table + 4 * 0 (%di)
110+
111+ sbbl %ebx,%ebx
112+ negl %ebx
113+
114+ popw %ds
115+
116+ DATA32 call EXT_C(real_to_prot)
117+ .code32
118+
119+ popl %ebp
120+
121+ movl %ebx,%eax
122+ xorl $1,%ebx
123+ movl 8(%ebp),%edx
124+ movl %ebx,gfx_ofs_ok(%edx)
125+
126+ popl %ebx
127+ popl %esi
128+ popl %edi
129+
130+ popl %ebp
131+ ret
132+
133+
134+/*
135+ * int gfx_done (gfx_data_t *gfx_data)
136+ *
137+ * shut down gfx things
138+ *
139+ * return vales:
140+ * always 0
141+ * sets gfx_data->ok
142+ */
143+
144+ENTRY(gfx_done)
145+ pushl %ebp
146+ movl %esp, %ebp
147+
148+ pushl %edi
149+ pushl %esi
150+ pushl %ebx
151+
152+ movl 8(%ebp),%edx
153+ movl %edx,%ebx
154+ andl $0xf,%ebx
155+ shrl $4,%edx
156+
157+ pushl %ebp
158+
159+ call EXT_C(prot_to_real)
160+ .code16
161+
162+ pushw %ds
163+
164+ movw %dx,%ds
165+
166+ lcall *gfx_ofs_jmp_table + 4 * 1 (%bx)
167+
168+ popw %ds
169+
170+ DATA32 call EXT_C(real_to_prot)
171+ .code32
172+
173+ popl %ebp
174+
175+ xorl %eax,%eax
176+ movl 8(%ebp),%edx
177+ movl %eax,gfx_ofs_ok(%edx)
178+
179+ popl %ebx
180+ popl %esi
181+ popl %edi
182+
183+ popl %ebp
184+ ret
185+
186+
187+/*
188+ * int gfx_input (gfx_data_t *gfx_data, int *menu_entry)
189+ *
190+ * let user enter a command line
191+ *
192+ * uses gfx_data->cmdline as buffer
193+ *
194+ * return values:
195+ * 1: abort
196+ * 2: boot
197+ * menu_entry: selected entry
198+ */
199+
200+ENTRY(gfx_input)
201+ pushl %ebp
202+ movl %esp, %ebp
203+
204+ pushl %edi
205+ pushl %esi
206+ pushl %ebx
207+
208+ movl 8(%ebp),%edx
209+ movl %edx,%ebx
210+ leal gfx_ofs_sys_cfg(%edx),%esi
211+ andl $0xf,%ebx
212+ shrl $4,%edx
213+
214+ pushl %ebp
215+
216+ call EXT_C(prot_to_real)
217+ .code16
218+
219+ pushw %ds
220+
221+ movw %dx,%ds
222+
223+ movl gfx_ofs_cmdline(%bx),%edi
224+ movl gfx_ofs_cmdline_len(%bx),%ecx
225+ movl gfx_ofs_timeout(%bx),%eax
226+ imull $18,%eax
227+
228+ lcall *gfx_ofs_jmp_table + 4 * 2 (%bx)
229+
230+ movl %eax,%ecx
231+
232+ popw %ds
233+
234+ DATA32 call EXT_C(real_to_prot)
235+ .code32
236+
237+ popl %ebp
238+
239+ movl 12(%ebp),%edx
240+ movl %ebx,(%edx)
241+
242+ movl %ecx,%eax
243+
244+ popl %ebx
245+ popl %esi
246+ popl %edi
247+
248+ popl %ebp
249+ ret
250+
251+
252+/*
253+ * int gfx_setup_menu (gfx_data_t *gfx_data)
254+ *
255+ * draw boot menu
256+ *
257+ * return values:
258+ * always 0
259+ */
260+
261+/* menu entry descriptor */
262+#define menu_entries 0
263+#define menu_default 2 /* seg:ofs */
264+#define menu_ent_list 6 /* seg:ofs */
265+#define menu_ent_size 10
266+#define menu_arg_list 12 /* seg:ofs */
267+#define menu_arg_size 16
268+#define sizeof_menu_desc 18
269+
270+ENTRY(gfx_setup_menu)
271+ pushl %ebp
272+ movl %esp, %ebp
273+
274+ pushl %edi
275+ pushl %esi
276+ pushl %ebx
277+
278+ movl 8(%ebp),%edx
279+ movl %edx,%ebx
280+ andl $0xf,%ebx
281+ shrl $4,%edx
282+
283+ call EXT_C(prot_to_real)
284+ .code16
285+
286+ pushw %ds
287+
288+ movw %dx,%ds
289+ shll $4,%edx
290+
291+ subw $sizeof_menu_desc,%sp
292+ movw %esp,%ebp
293+
294+ movl gfx_ofs_menu_entries(%bx),%eax
295+ movw %ax,menu_entries(%bp)
296+
297+ movl gfx_ofs_menu_default_entry(%bx),%eax
298+ subl %edx,%eax
299+ movw %ax,menu_default(%bp)
300+ movw %ds,menu_default+2(%bp)
301+
302+ movl gfx_ofs_menu_list(%bx),%eax
303+ subl %edx,%eax
304+ movw %ax,menu_ent_list(%bp)
305+ movw %ds,menu_ent_list+2(%bp)
306+
307+ movl gfx_ofs_menu_entry_len(%bx),%eax
308+ movw %ax,menu_ent_size(%bp)
309+
310+ movl gfx_ofs_args_list(%bx),%eax
311+ subl %edx,%eax
312+ movw %ax,menu_arg_list(%bp)
313+ movw %ds,menu_arg_list+2(%bp)
314+
315+ movl gfx_ofs_args_entry_len(%bx),%eax
316+ movw %ax,menu_arg_size(%bp)
317+
318+ movl %ss,%esi
319+ shll $4,%esi
320+ addl %ebp,%esi
321+
322+ lcall %ds: *gfx_ofs_jmp_table + 4 * 3 (%bx)
323+
324+ addw $sizeof_menu_desc,%sp
325+
326+ popw %ds
327+
328+ DATA32 call EXT_C(real_to_prot)
329+ .code32
330+
331+ xorl %eax,%eax
332+
333+ popl %ebx
334+ popl %esi
335+ popl %edi
336+
337+ popl %ebp
338+ ret
339+
340+
341+/*
342+ *
343+ * end graphics stuff
344+ *
345+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
346+ */
347+
348
349 /*
350 * gateA20(int linear)
351--- stage2/builtins.c
352+++ stage2/builtins.c
353@@ -63,6 +63,8 @@
354 int fallback_entries[MAX_FALLBACK_ENTRIES];
355 /* The number of current entry. */
356 int current_entryno;
357+/* graphics file */
358+char graphics_file[64];
359 /* The address for Multiboot command-line buffer. */
360 static char *mb_cmdline;
361 /* The password. */
362@@ -1351,6 +1353,26 @@
363 };
364
365 \f
366+/* graphics */
367+static int
368+gfxmenu_func (char *arg, int flags)
369+{
370+ memmove(graphics_file, arg, sizeof graphics_file - 1);
371+ graphics_file[sizeof graphics_file - 1] = 0;
372+
373+ return 0;
374+}
375+
376+static struct builtin builtin_gfxmenu =
377+{
378+ "gfxmenu",
379+ gfxmenu_func,
380+ BUILTIN_MENU | BUILTIN_HELP_LIST,
381+ "gfxmenu FILE",
382+ "Use the graphical menu from FILE."
383+};
384+
385+\f
386 /* geometry */
387 static int
388 geometry_func (char *arg, int flags)
389@@ -4874,6 +4896,7 @@
390 &builtin_find,
391 &builtin_fstest,
392 &builtin_geometry,
393+ &builtin_gfxmenu,
394 &builtin_halt,
395 &builtin_help,
396 &builtin_hiddenmenu,
397--- stage2/shared.h
398+++ stage2/shared.h
399@@ -374,6 +374,22 @@
400 #endif /* WITHOUT_LIBC_STUBS */
401
402
403+/* see typedef gfx_data_t below */
404+#define gfx_ofs_ok 0x00
405+#define gfx_ofs_code_seg 0x04
406+#define gfx_ofs_jmp_table 0x08
407+#define gfx_ofs_sys_cfg 0x38
408+#define gfx_ofs_cmdline 0x6c
409+#define gfx_ofs_cmdline_len 0x70
410+#define gfx_ofs_menu_list 0x74
411+#define gfx_ofs_menu_default_entry 0x78
412+#define gfx_ofs_menu_entries 0x7c
413+#define gfx_ofs_menu_entry_len 0x80
414+#define gfx_ofs_args_list 0x84
415+#define gfx_ofs_args_entry_len 0x88
416+#define gfx_ofs_timeout 0x8c
417+
418+
419 #ifndef ASM_FILE
420 /*
421 * Below this should be ONLY defines and other constructs for C code.
422@@ -595,6 +611,38 @@
423 extern int default_entry;
424 extern int current_entryno;
425
426+
427+/*
428+ * graphics menu stuff
429+ *
430+ * Note: gfx_data and all data referred to in it must lie within a 64k area.
431+ */
432+typedef struct {
433+ unsigned ok; /* set while we're in graphics mode */
434+ unsigned code_seg; /* code segment of binary graphics code */
435+ unsigned jmp_table[12]; /* link to graphics functions */
436+ unsigned char sys_cfg[52]; /* sys_cfg[0]: identifies boot loader (grub == 2) */
437+ char *cmdline; /* command line returned by gfx_input() */
438+ unsigned cmdline_len; /* length of the above */
439+ char *menu_list; /* list of menu entries, each of fixed length (menu_entry_len) */
440+ char *menu_default_entry; /* the default entry */
441+ unsigned menu_entries; /* number of entries in menu_list */
442+ unsigned menu_entry_len; /* one entry */
443+ char *args_list; /* same structure as menu_list, menu_entries entries */
444+ unsigned args_entry_len; /* one entry */
445+ unsigned timeout; /* in seconds (0: no timeout) */
446+} __attribute__ ((packed)) gfx_data_t;
447+
448+extern gfx_data_t *graphics_data;
449+
450+/* pointer to graphics image data */
451+extern char graphics_file[64];
452+
453+int gfx_init(gfx_data_t *gfx_data);
454+int gfx_done(gfx_data_t *gfx_data);
455+int gfx_input(gfx_data_t *gfx_data, int *menu_entry);
456+int gfx_setup_menu(gfx_data_t *gfx_data);
457+
458 /* The constants for password types. */
459 typedef enum
460 {
461--- stage2/stage2.c
462+++ stage2/stage2.c
463@@ -22,6 +22,8 @@
464
465 grub_jmp_buf restart_env;
466
467+gfx_data_t *graphics_data;
468+
469 #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
470
471 # if defined(PRESET_MENU_STRING)
472@@ -310,6 +312,12 @@
473
474 if (! auth && password)
475 {
476+ if (*graphics_file)
477+ {
478+ printf ("\
479+ WARNING: graphical menu doesn\'t work\
480+ in conjunction with the password feature\n" );
481+ }
482 printf ("\
483 Press enter to boot the selected OS or \'p\' to enter a\n\
484 password to unlock the next set of features.");
485@@ -753,6 +761,493 @@
486 }
487
488
489+
490+#if 0
491+/* for debugging */
492+static void hexdump(unsigned char *buf, unsigned len)
493+{
494+ int i, j = 0;
495+ char s[17];
496+ unsigned addr = (unsigned) buf;
497+
498+ s[16] = 0;
499+ while(len--) {
500+ i = buf[j];
501+ i = i & 0xff;
502+ s[j & 15] = (i >= 0x20 && i <= 0x7e) ? i : '.';
503+ if(!(j & 15)) {
504+ printf("%x ", j + addr);
505+ }
506+ if(!(j & 7) && (j & 15)) printf(" ");
507+ /* stupid grub_printf */
508+ printf("%x", (i >> 4) & 0x0f);
509+ printf("%x ", i & 0x0f);
510+ if(!(++j & 15)) {
511+ printf(" %s\n", s);
512+ }
513+ }
514+
515+ if(j & 15) {
516+ s[j & 15] = 0;
517+ if(!(j & 8)) printf(" ");
518+ i = 1 + 3 * (16 - (j & 15));
519+ while(i--) printf(" ");
520+ printf("%s\n", s);
521+ }
522+}
523+#endif
524+
525+
526+/* kernel + (grub-)module options */
527+#define GFX_CMD_BUF_SIZE 512
528+
529+/* command line separator char */
530+#define GFX_CMD_SEP 1
531+
532+/*
533+ * Go through config entry and find kernel args, if any.
534+ * Put things into buf and return it.
535+ */
536+static char *get_kernel_args(char *cfg, char *buf)
537+{
538+ int i, j;
539+ char *s, *t = "", *p, *t2;
540+
541+ *(p = buf) = 0;
542+
543+ for(j = 0; ; j++) {
544+ s = get_entry(cfg, j, 0);
545+ if(!*s) break;
546+ if(
547+ (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) &&
548+ (s[6] == ' ' || s[6] == '\t')
549+ ) {
550+ t = skip_to(0, s);
551+ t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL;
552+ if(*t) t = skip_to(0, t);
553+ if(t2 && t2 < t) break; /* module is likely a normal initrd -> skip */
554+ i = strlen(t);
555+ if(p - buf + i > GFX_CMD_BUF_SIZE - 2) break;
556+ *p++ = GFX_CMD_SEP;
557+ strcpy(p, t);
558+ p += i;
559+
560+ continue;
561+ }
562+ }
563+
564+ if(*buf) buf++; /* skip initial separator char */
565+
566+ return buf;
567+}
568+
569+
570+/*
571+ * Check header and return code start offset.
572+ */
573+static unsigned magic_ok(unsigned char *buf)
574+{
575+ if(
576+ *(unsigned *) buf == 0x0b2d97f00 && /* magic id */
577+ (buf[4] == 8) /* version 8 */
578+ ) {
579+ return *(unsigned *) (buf + 8);
580+ }
581+
582+ return 0;
583+}
584+
585+
586+/*
587+ * Search cpio archive for gfx file.
588+ */
589+static unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len)
590+{
591+ unsigned i, fname_len, code_start = 0;
592+
593+ *gfx_file_start = 0;
594+
595+ for(i = 0; i < len;) {
596+ if((len - i) >= 0x1a && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) {
597+ fname_len = *(unsigned short *) (buf + i + 20);
598+ *file_len = *(unsigned short *) (buf + i + 24) + (*(unsigned short *) (buf + i + 22) << 16);
599+ i += 26 + fname_len;
600+ i = ((i + 1) & ~1);
601+ if((code_start = magic_ok(buf + i))) {
602+ *gfx_file_start = i;
603+ return code_start;
604+ }
605+ i += *file_len;
606+ i = ((i + 1) & ~1);
607+ }
608+ else {
609+ break;
610+ }
611+ }
612+
613+ return code_start;
614+}
615+
616+static inline unsigned char * stack_ptr(void)
617+{
618+ unsigned char * u;
619+
620+ asm("movl %%esp, %0" : "=r" (u));
621+
622+ return u;
623+}
624+
625+static void sleep(int delay)
626+{
627+ int tick, last_tick = currticks();
628+
629+ delay *= 18;
630+
631+ while(delay--) {
632+ while((tick = currticks()) == last_tick) { }
633+ last_tick = tick;
634+ }
635+}
636+
637+static void wait_for_key()
638+{
639+ printf("Press a key to continue...");
640+ getkey();
641+ printf("\r \r");
642+}
643+
644+
645+/*
646+ * Leave that much space on the heap. Everything else goes to the graphics
647+ * functions.
648+ *
649+ * 0x2000 is _not_ enough
650+ */
651+#define MIN_HEAP_SIZE 0x4000
652+#define MIN_GFX_FREE 0x1000
653+
654+#define SC_BOOTLOADER 0
655+#define SC_FAILSAFE 3
656+#define SC_SYSCONFIG_SIZE 4
657+#define SC_BOOTLOADER_SEG 8
658+#define SC_XMEM_0 24
659+#define SC_XMEM_1 26
660+#define SC_XMEM_2 28
661+#define SC_XMEM_3 30
662+#define SC_FILE 32
663+#define SC_ARCHIVE_START 36
664+#define SC_ARCHIVE_END 40
665+#define SC_MEM0_START 44
666+#define SC_MEM0_END 48
667+
668+/*
669+ * Does normally not return.
670+ */
671+static void
672+run_graphics_menu (char *menu_entries, char *config_entries, int num_entries,
673+ char *heap, int entryno)
674+{
675+ unsigned char *buf, *buf_ext;
676+ unsigned buf_size, buf_ext_size, code_start, file_start;
677+ char *s, *t, *t2, *cfg, *new_config, *p;
678+ char *saved_heap;
679+ int i, j, max_len, gfx_file_size, verbose;
680+ int selected_entry;
681+ gfx_data_t *gfx_data;
682+ char *cmd_buf;
683+ unsigned mem0_start, mem0_end, file_len;
684+
685+ /*
686+ * check gfx_data_t struct offsets for consistency; gcc will optimize away
687+ * the whole block
688+ */
689+
690+ /* dummy function to make ld fail */
691+ {
692+ extern void wrong_struct_size(void);
693+ #define gfx_ofs_check(a) if(gfx_ofs_##a != (char *) &gfx_data->a - (char *) gfx_data) wrong_struct_size();
694+ gfx_ofs_check(ok);
695+ gfx_ofs_check(code_seg);
696+ gfx_ofs_check(jmp_table);
697+ gfx_ofs_check(sys_cfg);
698+ gfx_ofs_check(cmdline);
699+ gfx_ofs_check(cmdline_len);
700+ gfx_ofs_check(menu_list);
701+ gfx_ofs_check(menu_default_entry);
702+ gfx_ofs_check(menu_entries);
703+ gfx_ofs_check(menu_entry_len);
704+ gfx_ofs_check(args_list);
705+ gfx_ofs_check(args_entry_len);
706+ gfx_ofs_check(timeout);
707+ #undef gfx_ofs_check
708+ }
709+
710+ if(!num_entries) return;
711+
712+ graphics_data = gfx_data = (gfx_data_t *) heap;
713+ heap += sizeof *gfx_data;
714+ memset(gfx_data, 0, sizeof *gfx_data);
715+
716+ gfx_data->sys_cfg[SC_BOOTLOADER] = 2; /* bootloader: grub */
717+ gfx_data->sys_cfg[SC_SYSCONFIG_SIZE] = 52; /* config data size */
718+ *(unsigned short *) (gfx_data->sys_cfg + SC_BOOTLOADER_SEG) = (unsigned) gfx_data >> 4; /* segment */
719+ gfx_data->sys_cfg[SC_XMEM_0] = 0x21; /* 1MB @ 2MB */
720+ gfx_data->sys_cfg[SC_XMEM_1] = 0x41; /* 1MB @ 4MB */
721+ verbose = (*(unsigned char *) 0x417) & 3 ? 1 : 0; /* SHIFT pressed */
722+ gfx_data->sys_cfg[SC_FAILSAFE] = verbose;
723+
724+ gfx_data->timeout = grub_timeout >= 0 ? grub_timeout : 0;
725+
726+
727+ /* setup command line edit buffer */
728+
729+ gfx_data->cmdline_len = 256;
730+
731+ gfx_data->cmdline = heap;
732+ heap += gfx_data->cmdline_len;
733+ memset(gfx_data->cmdline, 0, gfx_data->cmdline_len);
734+
735+ cmd_buf = heap;
736+ heap += GFX_CMD_BUF_SIZE;
737+
738+ /* setup menu entries */
739+
740+ for(i = max_len = 0; i < num_entries; i++) {
741+ j = strlen(get_entry(menu_entries, i, 0));
742+ if(j > max_len) max_len = j;
743+ }
744+
745+ if(!max_len) return;
746+
747+ gfx_data->menu_entry_len = max_len + 1;
748+ gfx_data->menu_entries = num_entries;
749+
750+ gfx_data->menu_list = heap;
751+ heap += gfx_data->menu_entry_len * gfx_data->menu_entries;
752+
753+ memset(gfx_data->menu_list, 0, gfx_data->menu_entry_len * gfx_data->menu_entries);
754+
755+ for(i = 0; i < (int) gfx_data->menu_entries; i++) {
756+ strcpy(gfx_data->menu_list + i * gfx_data->menu_entry_len, get_entry(menu_entries, i, 0));
757+ }
758+
759+ gfx_data->menu_default_entry = gfx_data->menu_list + entryno * gfx_data->menu_entry_len;
760+
761+
762+ /* setup list of kernel args */
763+
764+ for(i = max_len = 0; i < num_entries; i++) {
765+ s = get_kernel_args(get_entry(config_entries, i, 1), cmd_buf);
766+ j = strlen(s);
767+ if(j > max_len) max_len = j;
768+ }
769+
770+ gfx_data->args_entry_len = max_len + 1;
771+
772+ gfx_data->args_list = heap;
773+ heap += gfx_data->args_entry_len * gfx_data->menu_entries;
774+
775+ memset(gfx_data->args_list, 0, gfx_data->args_entry_len * gfx_data->menu_entries);
776+
777+ for(i = 0; i < (int) gfx_data->menu_entries; i++) {
778+ strcpy(gfx_data->args_list + i* gfx_data->args_entry_len, get_kernel_args(get_entry(config_entries, i, 1), cmd_buf));
779+ }
780+
781+
782+ /* go back here when we no longer need the graphics data */
783+ saved_heap = heap;
784+
785+
786+ /* get memory area to be used by graphics functions */
787+
788+ /* use 1MB starting at 2MB as file buffer */
789+ buf_ext = (unsigned char *) (2 << 20);
790+ buf_ext_size = 1 << 20;
791+
792+ /* must be 16-byte aligned */
793+ buf = (unsigned char *) (((unsigned) heap + 0xf) & ~0xf);
794+
795+ buf_size = stack_ptr() - buf - MIN_HEAP_SIZE;
796+ buf_size &= ~0xf;
797+
798+ mem0_start = (unsigned) buf;
799+ mem0_end = mem0_start + buf_size;
800+
801+ if(verbose) {
802+ printf("low memory 0x%x - 0x%x (%d bytes)\n", mem0_start, mem0_end, buf_size);
803+ wait_for_key();
804+ }
805+
806+ heap += buf_size;
807+
808+ /* read the file */
809+
810+ if(!grub_open(graphics_file)) {
811+ printf("%s: file not found\n", graphics_file);
812+ sleep(5);
813+ heap = saved_heap;
814+ return;
815+ }
816+
817+ gfx_file_size = grub_read(buf_ext, buf_ext_size);
818+
819+ grub_close();
820+
821+ if(gfx_file_size <= 0) {
822+ printf("%s: read error\n", graphics_file);
823+ sleep(5);
824+ heap = saved_heap;
825+ return;
826+ }
827+
828+ if(verbose) {
829+ printf("%s: %d bytes (%d bytes left)\n", graphics_file, gfx_file_size, buf_ext_size - gfx_file_size);
830+ wait_for_key();
831+ }
832+
833+ /* locate file inside cpio archive */
834+ if(!(code_start = find_file(buf_ext, gfx_file_size, &file_start, &file_len))) {
835+ printf("%s: invalid file format\n", graphics_file);
836+ sleep(5);
837+ heap = saved_heap;
838+ return;
839+ }
840+
841+ if(verbose) {
842+ printf("init: start 0x%x, len %d; code offset 0x%x\n", file_start, file_len, code_start);
843+ wait_for_key();
844+ }
845+
846+ if(file_len - code_start + MIN_GFX_FREE > buf_size) {
847+ printf("not enough free memory: %d extra bytes need\n", file_len - code_start + MIN_GFX_FREE - buf_size);
848+ sleep(5);
849+ heap = saved_heap;
850+ return;
851+ }
852+
853+ memcpy((void *) buf, (void *) (buf_ext + file_start + code_start), file_len - code_start);
854+
855+ mem0_start += file_len - code_start;
856+ mem0_start = (mem0_start + 3) & ~3; /* align */
857+
858+ /* init interface to graphics functions */
859+
860+ *(unsigned *) (gfx_data->sys_cfg + SC_FILE) = (unsigned) buf_ext + file_start;
861+ *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_START) = (unsigned) buf_ext;
862+ *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_END) = (unsigned) buf_ext + gfx_file_size;
863+ *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_START) = mem0_start;
864+ *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_END) = mem0_end;
865+
866+ gfx_data->code_seg = (unsigned) buf >> 4;
867+
868+ if(verbose) {
869+ printf("init 0x%x, archive 0x%x - 0x%x, low mem 0x%x - 0x%x\ncode seg 0x%x\n",
870+ (unsigned) buf_ext + file_start,
871+ (unsigned) buf_ext, (unsigned) buf_ext + gfx_file_size,
872+ mem0_start, mem0_end, gfx_data->code_seg
873+ );
874+ wait_for_key();
875+ }
876+
877+ for(i = 0; (unsigned) i < sizeof gfx_data->jmp_table / sizeof *gfx_data->jmp_table; i++) {
878+ gfx_data->jmp_table[i] = (gfx_data->code_seg << 16) + ((unsigned short *) buf)[i];
879+ }
880+
881+ if(verbose) {
882+ for(i = 0; i < 12; i++) {
883+ printf("%d: 0x%x\n", i, gfx_data->jmp_table[i]);
884+ }
885+
886+ for(i = 0; i < gfx_data->menu_entries; i++) {
887+ printf("\"%s\" -- \"%s\"\n",
888+ gfx_data->menu_list + i * gfx_data->menu_entry_len,
889+ gfx_data->args_list + i * gfx_data->args_entry_len
890+ );
891+ }
892+
893+ printf("default: \"%s\"\n", gfx_data->menu_default_entry);
894+ wait_for_key();
895+ }
896+
897+ /* switch to graphics mode */
898+
899+ if(gfx_init(gfx_data)) {
900+ printf("graphics initialization failed\n");
901+ sleep(5);
902+ heap = saved_heap;
903+ return;
904+ }
905+
906+ gfx_setup_menu(gfx_data);
907+
908+ i = gfx_input(gfx_data, &selected_entry);
909+
910+ /* ESC -> show text menu */
911+ if(i == 1) {
912+ gfx_done(gfx_data);
913+ grub_timeout = -1;
914+
915+ heap = saved_heap;
916+ return;
917+ }
918+
919+ gfx_done(gfx_data);
920+
921+ heap = saved_heap; /* free most of the graphics data */
922+
923+ // printf("cmdline: >%s<, entry = %d\n", gfx_data->cmdline, selected_entry);
924+
925+ if(selected_entry < 0 || selected_entry > num_entries) return;
926+
927+
928+ /* create new config with modified kernel option */
929+
930+ cfg = get_entry(config_entries, selected_entry, 1);
931+
932+ new_config = heap;
933+
934+ for(p = gfx_data->cmdline, i = 0; ; i++) {
935+ s = get_entry(cfg, i, 0);
936+ if(!*s) {
937+ if(!i) *heap++ = 0;
938+ *heap++ = 0;
939+ break;
940+ }
941+ /* note: must match get_kernel_args() */
942+ if(
943+ (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) &&
944+ (s[6] == ' ' || s[6] == '\t')
945+ ) {
946+ t = skip_to(0, s);
947+ t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL;
948+ if(*t) t = skip_to(0, t);
949+ if(t2 && t2 < t) { /* module is likely a normal initrd -> skip */
950+ strcpy(heap, s);
951+ heap += strlen(s) + 1;
952+ continue;
953+ }
954+ memmove(heap, s, t - s);
955+ heap += t - s;
956+ *heap++ = ' ';
957+ while(*p && *p != GFX_CMD_SEP) *heap++ = *p++;
958+ *heap++ = 0;
959+ if(*p == GFX_CMD_SEP) p++;
960+ }
961+ else {
962+ strcpy(heap, s);
963+ heap += strlen(s) + 1;
964+ }
965+ }
966+
967+ *heap++ = 0;
968+
969+ // hexdump(new_config, heap - new_config);
970+ // getkey();
971+
972+ run_script(new_config, heap);
973+}
974+
975+
976 static int
977 get_line_from_config (char *cmdline, int maxlen, int read_from_file)
978 {
979@@ -1062,9 +1557,12 @@
980 }
981 else
982 {
983- /* Run menu interface. */
984- run_menu (menu_entries, config_entries, num_entries,
985- menu_entries + menu_len, default_entry);
986+ if (*graphics_file && !password && show_menu && grub_timeout)
987+ {
988+ run_graphics_menu(menu_entries, config_entries, num_entries,menu_entries + menu_len, default_entry);
989+ }
990+ /* Run menu interface. */
991+ run_menu (menu_entries, config_entries, num_entries, menu_entries + menu_len, default_entry);
992 }
993 }
994 }