5 * A com32 module to load gfxboot graphics.
7 * Copyright (c) 2009 Steffen Winterfeldt.
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, Inc., 53 Temple Place Ste 330, Boston MA
12 * 02111-1307, USA; either version 2 of the License, or (at your option) any
13 * later version; incorporated herein by reference.
22 #include <sys/types.h>
26 #include <syslinux/loadfile.h>
27 #include <syslinux/config.h>
28 #include <syslinux/linux.h>
29 #include <syslinux/boot.h>
34 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35 #define MAX_CONFIG_LINE_LEN 2048
36 #define MAX_CMDLINE_LEN 2048
38 // buffer for realmode callback
39 // must be at least block size; can in theory be larger than 4k, but there's
40 // not enough space left
41 #define REALMODE_BUF_SIZE 4096
43 // gfxboot working memory in MB
44 #define GFX_MEMORY_SIZE 7
46 // read chunk size for progress bar
47 #define CHUNK_SIZE (64 << 10)
49 // callback function numbers
52 #define GFX_CB_INPUT 2
53 #define GFX_CB_MENU_INIT 3
54 #define GFX_CB_INFOBOX_INIT 4
55 #define GFX_CB_INFOBOX_DONE 5
56 #define GFX_CB_PROGRESS_INIT 6
57 #define GFX_CB_PROGRESS_DONE 7
58 #define GFX_CB_PROGRESS_UPDATE 8
59 #define GFX_CB_PROGRESS_LIMIT 9 // unused
60 #define GFX_CB_PASSWORD_INIT 10
61 #define GFX_CB_PASSWORD_DONE 11
63 // real mode code chunk, will be placed into bounce buffer
64 extern void realmode_callback_start
, realmode_callback_end
;
70 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71 // gfxboot config data (64 bytes)
72 typedef struct __attribute__ ((packed
)) {
73 uint8_t bootloader
; // 0: boot loader type (0: lilo, 1: syslinux, 2: grub)
74 uint8_t sector_shift
; // 1: sector shift
75 uint8_t media_type
; // 2: media type (0: disk, 1: floppy, 2: cdrom)
76 uint8_t failsafe
; // 3: turn on failsafe mode (bitmask)
79 // 2: skip monitor detection
80 uint8_t sysconfig_size
; // 4: size of sysconfig data
81 uint8_t boot_drive
; // 5: BIOS boot drive
82 uint16_t callback
; // 6: offset to callback handler
83 uint16_t bootloader_seg
; // 8: code/data segment used by bootloader; must follow gfx_callback
84 uint16_t serial_port
; // 10: syslinux initialized serial port from 'serial' option
85 uint32_t user_info_0
; // 12: data for info box
86 uint32_t user_info_1
; // 16: data for info box
87 uint32_t bios_mem_size
; // 20: BIOS memory size (in bytes)
88 uint16_t xmem_0
; // 24: extended mem area 0 (start:size in MB; 12:4 bits) - obsolete
89 uint16_t xmem_1
; // 26: extended mem area 1 - obsolete
90 uint16_t xmem_2
; // 28: extended mem area 2 - obsolete
91 uint16_t xmem_3
; // 30: extended mem area 3 - obsolete
92 uint32_t file
; // 32: start of gfx file
93 uint32_t archive_start
; // 36: start of cpio archive
94 uint32_t archive_end
; // 40: end of cpio archive
95 uint32_t mem0_start
; // 44: low free memory start
96 uint32_t mem0_end
; // 48: low free memory end
97 uint32_t xmem_start
; // 52: extended mem start
98 uint32_t xmem_end
; // 56: extended mem end
99 uint16_t features
; // 60: feature flags returned by GFX_CB_INIT
100 // 0: GFX_CB_MENU_INIT accepts 32 bit addresses
101 // 1: knows about xmem_start, xmem_end
102 uint16_t reserved_1
; // 62:
106 // gfxboot menu description (18 bytes)
107 typedef struct __attribute__ ((packed
)) {
118 typedef struct menu_s
{
120 char *label
; // config entry name
121 char *menu_label
; // text to show in boot menu
122 char *kernel
; // name of program to load
123 char *alt_kernel
; // alternative name in case user has replaced it
124 char *linux
; // de facto an alias for 'kernel'
125 char *localboot
; // boot from local disk
126 char *initrd
; // initrd as separate line (instead of as part of 'append')
127 char *append
; // kernel args
128 char *ipappend
; // append special pxelinux args (see doc)
132 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133 gfx_config_t gfx_config
;
137 menu_t
*menu_default
;
138 static menu_t
*menu_ptr
, **menu_next
;
141 uint32_t jmp_table
[12];
147 unsigned lowmem_buf_size
;
151 char cmdline
[MAX_CMDLINE_LEN
];
154 unsigned save_buf_size
;
156 // progress bar is visible
157 unsigned progress_active
;
160 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161 void show_message(char *file
);
162 char *get_config_file_name(void);
163 char *skip_spaces(char *s
);
164 char *skip_nonspaces(char *s
);
165 void chop_line(char *s
);
166 int read_config_file(const char *filename
);
167 unsigned magic_ok(unsigned char *buf
, unsigned *code_size
);
168 unsigned find_file(unsigned char *buf
, unsigned len
, unsigned *gfx_file_start
, unsigned *file_len
, unsigned *code_size
);
169 int gfx_init(char *file
);
170 int gfx_menu_init(void);
173 void gfx_infobox(int type
, char *str1
, char *str2
);
174 void gfx_progress_init(ssize_t kernel_size
, char *label
);
175 void gfx_progress_update(ssize_t size
);
176 void gfx_progress_done(void);
177 ssize_t
save_read(int fd
, void *buf
, size_t size
);
178 void *load_one(char *file
, ssize_t
*file_size
);
179 void boot(int index
);
180 void boot_entry(menu_t
*menu_ptr
, char *arg
);
183 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
184 int main(int argc
, char **argv
)
187 const union syslinux_derivative_info
*sdi
;
189 openconsole(&dev_stdcon_r
, &dev_stdcon_w
);
191 lowmem_buf
= __com32
.cs_bounce
;
192 lowmem_buf_size
= __com32
.cs_bounce_size
;
194 sdi
= syslinux_derivative_info();
196 gfx_config
.sector_shift
= sdi
->disk
.sector_shift
;
197 gfx_config
.boot_drive
= sdi
->disk
.drive_number
;
199 if(sdi
->c
.filesystem
== SYSLINUX_FS_PXELINUX
) {
200 gfx_config
.sector_shift
= 11;
201 gfx_config
.boot_drive
= 0;
204 gfx_config
.media_type
= gfx_config
.boot_drive
< 0x80 ? 1 : 0;
206 if(sdi
->c
.filesystem
== SYSLINUX_FS_ISOLINUX
) {
207 gfx_config
.media_type
= sdi
->iso
.cd_mode
? 0 : 2;
210 gfx_config
.bootloader
= 1;
211 gfx_config
.sysconfig_size
= sizeof gfx_config
;
212 gfx_config
.bootloader_seg
= 0; // apparently not needed
214 save_buf_size
= lowmem_buf_size
;
215 save_buf
= malloc(save_buf_size
);
218 printf("Usage: gfxboot.c32 bootlogo_file [message_file]\n");
219 if(argc
> 2) show_message(argv
[2]);
224 if(read_config_file("~")) {
225 printf("Error reading config file\n");
226 if(argc
> 2) show_message(argv
[2]);
231 if(gfx_init(argv
[1])) {
232 printf("Error setting up gfxboot\n");
233 if(argc
> 2) show_message(argv
[2]);
241 menu_index
= gfx_input();
243 // abort gfx, return to text mode prompt
244 if(menu_index
== -1) {
249 // does not return if it succeeds
253 if(argc
> 2) show_message(argv
[2]);
259 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
260 void show_message(char *file
)
265 if(!(f
= fopen(file
, "r"))) return;
267 while((c
= getc(f
)) != EOF
) {
268 if(c
< ' ' && c
!= '\n' && c
!= '\t') continue;
276 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
277 char *skip_spaces(char *s
)
279 while(*s
&& (*s
== ' ' || *s
== '\t')) s
++;
285 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
286 char *skip_nonspaces(char *s
)
288 while(*s
&& *s
!= ' ' && *s
!= '\t') s
++;
294 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
295 void chop_line(char *s
)
302 if(s
[i
] == ' ' || s
[i
] == '\t' || s
[i
] == '\n') {
312 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
313 // Read and parse syslinux config file.
318 int read_config_file(const char *filename
)
321 char *s
, *t
, buf
[MAX_CONFIG_LINE_LEN
];
322 unsigned u
, top_level
= 0;
324 if(!strcmp(filename
, "~")) {
326 filename
= syslinux_config_file();
327 gfx_menu
.entries
= 0;
328 gfx_menu
.label_size
= 0;
329 gfx_menu
.arg_size
= 0;
332 menu_default
= calloc(1, sizeof *menu_default
);
335 if(!(f
= fopen(filename
, "r"))) return 1;
337 while((s
= fgets(buf
, sizeof buf
, f
))) {
340 if(!*s
|| *s
== '#') continue;
341 t
= skip_nonspaces(s
);
345 if(!strcasecmp(s
, "timeout")) {
350 if(!strcasecmp(s
, "default")) {
351 menu_default
->label
= strdup(t
);
353 if(u
> gfx_menu
.label_size
) gfx_menu
.label_size
= u
;
357 if(!strcasecmp(s
, "label")) {
358 menu_ptr
= *menu_next
= calloc(1, sizeof **menu_next
);
359 menu_next
= &menu_ptr
->next
;
361 menu_ptr
->label
= menu_ptr
->menu_label
= strdup(t
);
363 if(u
> gfx_menu
.label_size
) gfx_menu
.label_size
= u
;
367 if(!strcasecmp(s
, "kernel") && menu_ptr
) {
368 menu_ptr
->kernel
= strdup(t
);
372 if(!strcasecmp(s
, "linux") && menu_ptr
) {
373 menu_ptr
->linux
= strdup(t
);
377 if(!strcasecmp(s
, "localboot") && menu_ptr
) {
378 menu_ptr
->localboot
= strdup(t
);
382 if(!strcasecmp(s
, "initrd") && menu_ptr
) {
383 menu_ptr
->initrd
= strdup(t
);
387 if(!strcasecmp(s
, "append")) {
388 (menu_ptr
?: menu_default
)->append
= strdup(t
);
390 if(u
> gfx_menu
.arg_size
) gfx_menu
.arg_size
= u
;
394 if(!strcasecmp(s
, "ipappend")) {
395 (menu_ptr
?: menu_default
)->ipappend
= strdup(t
);
399 if(!strcasecmp(s
, "menu") && menu_ptr
) {
401 t
= skip_nonspaces(s
);
405 if(!strcasecmp(s
, "label")) {
406 menu_ptr
->menu_label
= strdup(t
);
408 if(u
> gfx_menu
.label_size
) gfx_menu
.label_size
= u
;
412 if(!strcasecmp(s
, "include")) {
417 if (!strcasecmp(s
, "include")) {
420 t
= skip_nonspaces(s
);
432 gfx_menu
.label_size
++;
435 // ensure we have a default entry
436 if(!menu_default
->label
) menu_default
->label
= menu
->label
;
438 if(menu_default
->label
) {
439 for(menu_ptr
= menu
; menu_ptr
; menu_ptr
= menu_ptr
->next
) {
440 if(!strcmp(menu_default
->label
, menu_ptr
->label
)) {
441 menu_default
->menu_label
= menu_ptr
->menu_label
;
447 gfx_menu
.default_entry
= menu_default
->menu_label
;
448 gfx_menu
.label_list
= calloc(gfx_menu
.entries
, gfx_menu
.label_size
);
449 gfx_menu
.arg_list
= calloc(gfx_menu
.entries
, gfx_menu
.arg_size
);
451 for(u
= 0, menu_ptr
= menu
; menu_ptr
; menu_ptr
= menu_ptr
->next
, u
++) {
452 if(!menu_ptr
->append
) menu_ptr
->append
= menu_default
->append
;
453 if(!menu_ptr
->ipappend
) menu_ptr
->ipappend
= menu_default
->ipappend
;
455 if(menu_ptr
->menu_label
) strcpy(gfx_menu
.label_list
+ u
* gfx_menu
.label_size
, menu_ptr
->menu_label
);
456 if(menu_ptr
->append
) strcpy(gfx_menu
.arg_list
+ u
* gfx_menu
.arg_size
, menu_ptr
->append
);
463 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
464 // Check header and return code start offset.
466 unsigned magic_ok(unsigned char *buf
, unsigned *code_size
)
469 *(unsigned *) buf
== 0x0b2d97f00 && // magic id
470 (buf
[4] == 8) // version 8
472 *code_size
= *(unsigned *) (buf
+ 12);
473 return *(unsigned *) (buf
+ 8);
480 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
481 // Search (cpio archive) for gfx file.
483 unsigned find_file(unsigned char *buf
, unsigned len
, unsigned *gfx_file_start
, unsigned *file_len
, unsigned *code_size
)
485 unsigned i
, fname_len
, code_start
= 0;
490 if((code_start
= magic_ok(buf
, code_size
))) return code_start
;
492 for(i
= 0; i
< len
;) {
493 if((len
- i
) >= 0x1a && (buf
[i
] + (buf
[i
+ 1] << 8)) == 0x71c7) {
494 fname_len
= *(unsigned short *) (buf
+ i
+ 20);
495 *file_len
= *(unsigned short *) (buf
+ i
+ 24) + (*(unsigned short *) (buf
+ i
+ 22) << 16);
498 if((code_start
= magic_ok(buf
+ i
, code_size
))) {
514 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
515 // Initialize gfxboot code.
520 int gfx_init(char *file
)
522 size_t archive_size
= 0;
524 unsigned code_start
, code_size
, file_start
, file_len
, u
;
526 void *lowmem
= lowmem_buf
;
527 unsigned lowmem_size
= lowmem_buf_size
;
531 printf("Loading %s...\n", file
);
532 if(loadfile(file
, &archive
, &archive_size
)) return 1;
534 if(!archive_size
) return 1;
536 // printf("%s: %d\n", file, archive_size);
538 gfx_config
.archive_start
= (uint32_t) archive
;
539 gfx_config
.archive_end
= gfx_config
.archive_start
+ archive_size
;
541 // locate file inside cpio archive
542 if(!(code_start
= find_file(archive
, archive_size
, &file_start
, &file_len
, &code_size
))) {
543 printf("%s: invalid file format\n", file
);
549 "code_start = 0x%x, code_size = 0x%x\n"
550 "archive_start = 0x%x, archive size = 0x%x\n"
551 "file_start = 0x%x, file_len = 0x%x\n",
552 code_start
, code_size
,
553 gfx_config
.archive_start
, archive_size
,
558 gfx_config
.file
= gfx_config
.archive_start
+ file_start
;
560 u
= &realmode_callback_end
- &realmode_callback_start
;
561 u
= (u
+ REALMODE_BUF_SIZE
+ 0xf) & ~0xf;
563 if(u
+ code_size
> lowmem_size
) {
564 printf("bounce buffer too small: size %u, needed %u\n", lowmem_size
, u
+ code_size
);
568 memcpy(lowmem
+ REALMODE_BUF_SIZE
, &realmode_callback_start
, &realmode_callback_end
- &realmode_callback_start
);
570 // fill in buffer size and location
571 *(uint16_t *) (lowmem
+ REALMODE_BUF_SIZE
) = REALMODE_BUF_SIZE
;
572 *(uint16_t *) (lowmem
+ REALMODE_BUF_SIZE
+ 2) = (uint32_t) lowmem
>> 4;
574 gfx_config
.bootloader_seg
= ((uint32_t) lowmem
+ REALMODE_BUF_SIZE
) >> 4;
575 gfx_config
.callback
= 4; // start address
580 memcpy(lowmem
, archive
+ file_start
+ code_start
, code_size
);
582 gfx_config
.mem0_start
= (uint32_t) lowmem
+ code_size
;
583 gfx_config
.mem0_end
= (uint32_t) lowmem
+ lowmem_size
;
585 gfx_config
.mem0_start
= (gfx_config
.mem0_start
+ 0xf) & ~0xf;
587 gfx_config
.xmem_start
= (uint32_t) malloc(GFX_MEMORY_SIZE
<< 20);
588 if(gfx_config
.xmem_start
) {
589 gfx_config
.xmem_end
= gfx_config
.xmem_start
+ (GFX_MEMORY_SIZE
<< 20);
592 // fake; not used anyway
593 gfx_config
.bios_mem_size
= 256 << 20;
595 gfx
.code_seg
= (uint32_t) lowmem
>> 4;
597 for(u
= 0; u
< sizeof gfx
.jmp_table
/ sizeof *gfx
.jmp_table
; u
++) {
598 gfx
.jmp_table
[u
] = (gfx
.code_seg
<< 16) + *(uint16_t *) (lowmem
+ 2 * u
);
602 for(u
= 0; u
< sizeof gfx
.jmp_table
/ sizeof *gfx
.jmp_table
; u
++) {
603 printf("%d: 0x%08x\n", u
, gfx
.jmp_table
[u
]);
607 // we are ready to start
609 r
.esi
.l
= (uint32_t) &gfx_config
;
610 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_INIT
], &r
, &r
);
612 if((r
.eflags
.l
& EFLAGS_CF
)) {
613 printf("graphics initialization failed\n");
618 if((gfx_config
.features
& 3) != 3) {
621 printf("%s: boot graphics code too old, please use newer version\n", file
);
631 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
632 int gfx_menu_init(void)
636 r
.esi
.l
= (uint32_t) &gfx_menu
;
637 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_MENU_INIT
], &r
, &r
);
643 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
650 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_DONE
], &r
, &r
);
654 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
655 // Run gfxboot main loop.
658 // boot menu index (-1: go to text mode prompt)
664 r
.edi
.l
= (uint32_t) cmdline
;
665 r
.ecx
.l
= sizeof cmdline
;
666 r
.eax
.l
= timeout
* 182 / 100;
667 timeout
= 0; // use timeout only first time
668 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_INPUT
], &r
, &r
);
669 if((r
.eflags
.l
& EFLAGS_CF
)) r
.eax
.l
= 1;
671 if(r
.eax
.l
== 1) return -1;
677 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
678 void gfx_infobox(int type
, char *str1
, char *str2
)
683 r
.esi
.l
= (uint32_t) str1
;
684 r
.edi
.l
= (uint32_t) str2
;
685 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_INFOBOX_INIT
], &r
, &r
);
686 r
.edi
.l
= r
.eax
.l
= 0;
687 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_INPUT
], &r
, &r
);
688 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_INFOBOX_DONE
], &r
, &r
);
692 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
693 void gfx_progress_init(ssize_t kernel_size
, char *label
)
697 if(!progress_active
) {
698 r
.eax
.l
= kernel_size
>> gfx_config
.sector_shift
; // in sectors
699 r
.esi
.l
= (uint32_t) label
;
700 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_PROGRESS_INIT
], &r
, &r
);
707 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
708 void gfx_progress_update(ssize_t advance
)
712 if(progress_active
) {
713 r
.eax
.l
= advance
>> gfx_config
.sector_shift
; // in sectors
714 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_PROGRESS_UPDATE
], &r
, &r
);
719 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
720 void gfx_progress_done(void)
724 if(progress_active
) {
725 __farcall(gfx
.code_seg
, gfx
.jmp_table
[GFX_CB_PROGRESS_DONE
], &r
, &r
);
732 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
733 // Like read(2) but preserve bounce buffer.
735 ssize_t
save_read(int fd
, void *buf
, size_t size
)
739 memcpy(save_buf
, lowmem_buf
, save_buf_size
);
740 i
= read(fd
, buf
, size
);
741 memcpy(lowmem_buf
, save_buf
, save_buf_size
);
747 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
748 // Read file and update progress bar.
750 void *load_one(char *file
, ssize_t
*file_size
)
756 ssize_t size
= 0, cur
, i
;
760 if((fd
= open(file
, O_RDONLY
)) == -1) {
761 asprintf(&str
, "%s: file not found", file
);
762 gfx_infobox(0, str
, NULL
);
767 if(!fstat(fd
, &sbuf
) && S_ISREG(sbuf
.st_mode
)) size
= sbuf
.st_size
;
773 for(i
= 1, cur
= 0 ; cur
< size
&& i
> 0; cur
+= i
) {
774 i
= save_read(fd
, buf
+ cur
, min(CHUNK_SIZE
, size
- cur
));
776 gfx_progress_update(i
);
781 buf
= realloc(buf
, size
+ CHUNK_SIZE
);
782 i
= save_read(fd
, buf
+ size
, CHUNK_SIZE
);
785 gfx_progress_update(i
);
792 asprintf(&str
, "%s: read error @ %d", file
, size
);
793 gfx_infobox(0, str
, NULL
);
806 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
809 // cmdline can optionally start with label string.
813 char *arg
, *alt_kernel
;
817 const struct syslinux_ipappend_strings
*ipappend
;
819 for(menu_ptr
= menu
; menu_ptr
; menu_ptr
= menu_ptr
->next
, index
--) {
823 // invalid index or menu entry
824 if(!menu_ptr
|| !menu_ptr
->menu_label
) return;
826 arg
= skip_spaces(cmdline
);
827 label_len
= strlen(menu_ptr
->menu_label
);
829 // if it does not start with label string, assume first word is kernel name
830 if(strncmp(arg
, menu_ptr
->menu_label
, label_len
)) {
832 arg
= skip_nonspaces(arg
);
834 if(*alt_kernel
) menu_ptr
->alt_kernel
= alt_kernel
;
840 arg
= skip_spaces(arg
);
843 if(menu_ptr
->ipappend
&& (ipapp
= atoi(menu_ptr
->ipappend
))) {
844 ipappend
= syslinux_ipappend_strings();
845 for(i
= 0; i
< ipappend
->count
; i
++) {
846 if((ipapp
& (1 << i
)) && ipappend
->ptr
[i
]) {
847 sprintf(arg
+ strlen(arg
), " %s", ipappend
->ptr
[i
]);
852 boot_entry(menu_ptr
, arg
);
858 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
859 // Load & run kernel.
861 // Returns only on error.
863 void boot_entry(menu_t
*menu_ptr
, char *arg
)
865 void *kernel
, *initrd_buf
;
866 ssize_t kernel_size
= 0, initrd_size
= 0;
867 struct initramfs
*initrd
= NULL
;
868 char *file
, *cmd_buf
;
871 char *s
, *s0
, *t
, *initrd_arg
;
873 if(!menu_ptr
) return;
875 if(menu_ptr
->localboot
) {
877 syslinux_local_boot(strtol(menu_ptr
->localboot
, NULL
, 0));
882 file
= menu_ptr
->alt_kernel
;
883 if(!file
) file
= menu_ptr
->kernel
;
884 if(!file
) file
= menu_ptr
->linux
;
887 asprintf(&cmd_buf
, "%s %s", menu_ptr
->label
, arg
);
888 syslinux_run_command(cmd_buf
);
892 // first, load kernel
896 if((fd
= open(file
, O_RDONLY
)) >= 0) {
897 if(!fstat(fd
, &sbuf
) && S_ISREG(sbuf
.st_mode
)) kernel_size
= sbuf
.st_size
;
901 gfx_progress_init(kernel_size
, file
);
903 kernel
= load_one(file
, &kernel_size
);
909 if(kernel_size
< 1024 || *(uint32_t *) (kernel
+ 0x202) != 0x53726448) {
910 // not a linux kernel
912 asprintf(&cmd_buf
, "%s %s", menu_ptr
->label
, arg
);
913 syslinux_run_command(cmd_buf
);
917 // printf("kernel = %p, size = %d\n", kernel, kernel_size);
919 // parse cmdline for "initrd" option
921 initrd_arg
= menu_ptr
->initrd
;
923 s
= s0
= strdup(arg
);
925 while(*s
&& strncmp(s
, "initrd=", sizeof "initrd=" - 1)) {
926 s
= skip_spaces(skip_nonspaces(s
));
930 s
+= sizeof "initrd=" - 1;
931 *skip_nonspaces(s
) = 0;
936 initrd
= initramfs_init();
938 while((t
= strsep(&s
, ","))) {
939 initrd_buf
= load_one(t
, &initrd_size
);
942 printf("%s: read error\n", t
);
947 initramfs_add_data(initrd
, initrd_buf
, initrd_size
, initrd_size
, 4);
949 // printf("initrd = %p, size = %d\n", initrd_buf, initrd_size);
957 syslinux_boot_linux(kernel
, kernel_size
, initrd
, arg
);