source: bootcd/isolinux/syslinux-6.03/com32/gfxboot/gfxboot.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 23.6 KB
Line 
1/*
2 *
3 * gfxboot.c
4 *
5 * A com32 module to load gfxboot graphics.
6 *
7 * Copyright (c) 2009 Steffen Winterfeldt.
8 *
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.
14 *
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21#include <fcntl.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <minmax.h>
25#include <ctype.h>
26
27#include <syslinux/loadfile.h>
28#include <syslinux/config.h>
29#include <syslinux/linux.h>
30#include <syslinux/boot.h>
31#include <console.h>
32#include <com32.h>
33
34
35// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
36#define MAX_CONFIG_LINE_LEN     2048
37#define MAX_CMDLINE_LEN         2048
38
39// buffer for realmode callback
40// must be at least block size; can in theory be larger than 4k, but there's
41// not enough space left
42#define REALMODE_BUF_SIZE       4096
43#define LOWMEM_BUF_SIZE         65536
44
45// gfxboot working memory in MB
46#define GFX_MEMORY_SIZE         7
47
48// read chunk size for progress bar
49#define CHUNK_SIZE      (64 << 10)
50
51// callback function numbers
52#define GFX_CB_INIT             0
53#define GFX_CB_DONE             1
54#define GFX_CB_INPUT            2
55#define GFX_CB_MENU_INIT        3
56#define GFX_CB_INFOBOX_INIT     4
57#define GFX_CB_INFOBOX_DONE     5
58#define GFX_CB_PROGRESS_INIT    6
59#define GFX_CB_PROGRESS_DONE    7
60#define GFX_CB_PROGRESS_UPDATE  8
61#define GFX_CB_PROGRESS_LIMIT   9               // unused
62#define GFX_CB_PASSWORD_INIT    10
63#define GFX_CB_PASSWORD_DONE    11
64
65// real mode code chunk, will be placed into lowmem buffer
66extern const char realmode_callback_start[], realmode_callback_end[];
67
68// gets in the way
69#undef linux
70
71
72// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73// gfxboot config data (64 bytes)
74typedef struct __attribute__ ((packed)) {
75  uint8_t bootloader;           //  0: boot loader type (0: lilo, 1: syslinux, 2: grub)
76  uint8_t sector_shift;         //  1: sector shift
77  uint8_t media_type;           //  2: media type (0: disk, 1: floppy, 2: cdrom)
78  uint8_t failsafe;             //  3: turn on failsafe mode (bitmask)
79                                //    0: SHIFT pressed
80                                //    1: skip gfxboot
81                                //    2: skip monitor detection
82  uint8_t sysconfig_size;       //  4: size of sysconfig data
83  uint8_t boot_drive;           //  5: BIOS boot drive
84  uint16_t callback;            //  6: offset to callback handler
85  uint16_t bootloader_seg;      //  8: code/data segment used by bootloader; must follow gfx_callback
86  uint16_t serial_port;         // 10: syslinux initialized serial port from 'serial' option
87  uint32_t user_info_0;         // 12: data for info box
88  uint32_t user_info_1;         // 16: data for info box
89  uint32_t bios_mem_size;       // 20: BIOS memory size (in bytes)
90  uint16_t xmem_0;              // 24: extended mem area 0 (start:size in MB; 12:4 bits) - obsolete
91  uint16_t xmem_1;              // 26: extended mem area 1 - obsolete
92  uint16_t xmem_2;              // 28: extended mem area 2 - obsolete
93  uint16_t xmem_3;              // 30: extended mem area 3 - obsolete
94  uint32_t file;                // 32: start of gfx file
95  uint32_t archive_start;       // 36: start of cpio archive
96  uint32_t archive_end;         // 40: end of cpio archive
97  uint32_t mem0_start;          // 44: low free memory start
98  uint32_t mem0_end;            // 48: low free memory end
99  uint32_t xmem_start;          // 52: extended mem start
100  uint32_t xmem_end;            // 56: extended mem end
101  uint16_t features;            // 60: feature flags returned by GFX_CB_INIT
102                                //    0: GFX_CB_MENU_INIT accepts 32 bit addresses
103                                //    1: knows about xmem_start, xmem_end
104  uint16_t reserved_1;          // 62:
105  uint32_t gfxboot_cwd;         // 64: if set, points to current gfxboot working directory relative
106                                //     to syslinux working directory
107} gfx_config_t;
108
109
110// gfxboot menu description (18 bytes)
111typedef struct __attribute__ ((packed)) {
112  uint16_t entries;
113  char *default_entry;
114  char *label_list;
115  uint16_t label_size;
116  char *arg_list;
117  uint16_t arg_size;
118} gfx_menu_t;
119
120
121// menu description
122typedef struct menu_s {
123  struct menu_s *next;
124  char *label;          // config entry name
125  char *menu_label;     // text to show in boot menu
126  char *kernel;         // name of program to load
127  char *alt_kernel;     // alternative name in case user has replaced it
128  char *linux;          // de facto an alias for 'kernel'
129  char *localboot;      // boot from local disk
130  char *initrd;         // initrd as separate line (instead of as part of 'append')
131  char *append;         // kernel args
132  char *ipappend;       // append special pxelinux args (see doc)
133} menu_t;
134
135
136// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137gfx_config_t gfx_config;
138gfx_menu_t gfx_menu;
139
140menu_t *menu;
141menu_t *menu_default;
142static menu_t *menu_ptr, **menu_next;
143
144struct {
145  uint32_t jmp_table[12];
146  uint16_t code_seg;
147  char fname_buf[64];
148} gfx;
149
150void *lowmem_buf;
151
152int timeout;
153
154char cmdline[MAX_CMDLINE_LEN];
155
156// progress bar is visible
157unsigned progress_active;
158
159
160// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161void show_message(char *file);
162char *get_config_file_name(void);
163char *skip_nonspaces(char *s);
164void chop_line(char *s);
165int read_config_file(const char *filename);
166unsigned magic_ok(unsigned char *buf, unsigned *code_size);
167unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len, unsigned *code_size);
168int gfx_init(char *file);
169int gfx_menu_init(void);
170void gfx_done(void);
171int gfx_input(void);
172void gfx_infobox(int type, char *str1, char *str2);
173void gfx_progress_init(ssize_t kernel_size, char *label);
174void gfx_progress_update(ssize_t size);
175void gfx_progress_done(void);
176void *load_one(char *file, ssize_t *file_size);
177void boot(int index);
178void boot_entry(menu_t *menu_ptr, char *arg);
179
180
181// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
182int main(int argc, char **argv)
183{
184  int menu_index;
185  const union syslinux_derivative_info *sdi;
186  char working_dir[256];
187
188  openconsole(&dev_stdcon_r, &dev_stdcon_w);
189
190  lowmem_buf = lmalloc(LOWMEM_BUF_SIZE);
191  if (!lowmem_buf) {
192    printf("Could not allocate memory.\n");
193    return 1;
194  }
195
196  sdi = syslinux_derivative_info();
197
198  gfx_config.sector_shift = sdi->disk.sector_shift;
199  gfx_config.boot_drive = sdi->disk.drive_number;
200
201  if(sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
202    gfx_config.sector_shift = 11;
203    gfx_config.boot_drive = 0;
204  }
205
206  gfx_config.media_type = gfx_config.boot_drive < 0x80 ? 1 : 0;
207
208  if(sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
209    gfx_config.media_type = sdi->iso.cd_mode ? 0 : 2;
210  }
211
212  gfx_config.bootloader = 1;
213  gfx_config.sysconfig_size = sizeof gfx_config;
214  gfx_config.bootloader_seg = 0;        // apparently not needed
215
216  if(argc < 2) {
217    printf("Usage: gfxboot.c32 bootlogo_file [message_file]\n");
218    if(argc > 2) show_message(argv[2]);
219
220    return 0;
221  }
222
223  if(read_config_file("~")) {
224    printf("Error reading config file\n");
225    if(argc > 2) show_message(argv[2]);
226
227    return 0;
228  }
229
230  if(getcwd(working_dir, sizeof working_dir)) {
231    gfx_config.gfxboot_cwd = (uint32_t) working_dir;
232  }
233
234  if(gfx_init(argv[1])) {
235    printf("Error setting up gfxboot\n");
236    if(argc > 2) show_message(argv[2]);
237
238    return 0;
239  }
240
241  gfx_menu_init();
242
243  for(;;) {
244    menu_index = gfx_input();
245
246    // abort gfx, return to text mode prompt
247    if(menu_index == -1) {
248      gfx_done();
249      break;
250    }
251
252    // does not return if it succeeds
253    boot(menu_index);
254  }
255
256  if(argc > 2) show_message(argv[2]);
257
258  return 0;
259}
260
261
262// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
263void show_message(char *file)
264{
265  int c;
266  FILE *f;
267
268  if(!(f = fopen(file, "r"))) return;
269
270  while((c = getc(f)) != EOF) {
271    if(c < ' ' && c != '\n' && c != '\t') continue;
272    printf("%c", c);
273  }
274
275  fclose(f);
276}
277
278
279// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
280char *skip_nonspaces(char *s)
281{
282  while(*s && *s != ' ' && *s != '\t') s++;
283
284  return s;
285}
286
287
288// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
289void chop_line(char *s)
290{
291  int i = strlen(s);
292
293  if(!i) return;
294
295  while(--i >= 0) {
296    if(s[i] == ' ' || s[i] == '\t' || s[i] == '\n') {
297      s[i] = 0;
298    }
299    else {
300      break;
301    }
302  }
303}
304
305
306// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
307// Read and parse syslinux config file.
308//
309// return:
310//   0: ok, 1: error
311//
312int read_config_file(const char *filename)
313{
314  FILE *f;
315  char *s, *t, buf[MAX_CONFIG_LINE_LEN];
316  unsigned u, top_level = 0, text = 0;
317
318  if(!strcmp(filename, "~")) {
319    top_level = 1;
320    filename = syslinux_config_file();
321    gfx_menu.entries = 0;
322    gfx_menu.label_size = 0;
323    gfx_menu.arg_size = 0;
324    menu_ptr = NULL;
325    menu_next = &menu;
326    menu_default = calloc(1, sizeof *menu_default);
327  }
328
329  if(!(f = fopen(filename, "r"))) return 1;
330
331  while((s = fgets(buf, sizeof buf, f))) {
332    chop_line(s);
333    s = skipspace(s);
334    if(!*s || *s == '#') continue;
335    t = skip_nonspaces(s);
336    if(*t) *t++ = 0;
337    t = skipspace(t);
338
339    if(!strcasecmp(s, "endtext")) {
340      text = 0;
341      continue;
342    }
343
344    if (text)
345      continue;
346
347    if(!strcasecmp(s, "timeout")) {
348      timeout = atoi(t);
349      continue;
350    }
351
352    if(!strcasecmp(s, "default")) {
353      menu_default->label = strdup(t);
354      u = strlen(t);
355      if(u > gfx_menu.label_size) gfx_menu.label_size = u;
356      continue;
357    }
358
359    if(!strcasecmp(s, "label")) {
360      menu_ptr = *menu_next = calloc(1, sizeof **menu_next);
361      menu_next = &menu_ptr->next;
362      gfx_menu.entries++;
363      menu_ptr->label = menu_ptr->menu_label = strdup(t);
364      u = strlen(t);
365      if(u > gfx_menu.label_size) gfx_menu.label_size = u;
366      continue;
367    }
368
369    if(!strcasecmp(s, "kernel") && menu_ptr) {
370      menu_ptr->kernel = strdup(t);
371      continue;
372    }
373
374    if(!strcasecmp(s, "linux") && menu_ptr) {
375      menu_ptr->linux = strdup(t);
376      continue;
377    }
378
379    if(!strcasecmp(s, "localboot") && menu_ptr) {
380      menu_ptr->localboot = strdup(t);
381      continue;
382    }
383
384    if(!strcasecmp(s, "initrd") && menu_ptr) {
385      menu_ptr->initrd = strdup(t);
386      continue;
387    }
388
389    if(!strcasecmp(s, "append")) {
390      (menu_ptr ?: menu_default)->append = strdup(t);
391      u = strlen(t);
392      if(u > gfx_menu.arg_size) gfx_menu.arg_size = u;
393      continue;
394    }
395
396    if(!strcasecmp(s, "ipappend") || !strcasecmp(s, "sysappend")) {
397      (menu_ptr ?: menu_default)->ipappend = strdup(t);
398      continue;
399    }
400
401    if(!strcasecmp(s, "text")) {
402      text = 1;
403      continue;
404    }
405
406    if(!strcasecmp(s, "menu") && menu_ptr) {
407      s = skipspace(t);
408      t = skip_nonspaces(s);
409      if(*t) *t++ = 0;
410      t = skipspace(t);
411
412      if(!strcasecmp(s, "label")) {
413        menu_ptr->menu_label = strdup(t);
414        u = strlen(t);
415        if(u > gfx_menu.label_size) gfx_menu.label_size = u;
416        continue;
417      }
418
419      if(!strcasecmp(s, "include")) {
420        goto do_include;
421      }
422    }
423
424    if (!strcasecmp(s, "include")) {
425do_include:
426      s = t;
427      t = skip_nonspaces(s);
428      if (*t) *t = 0;
429      read_config_file(s);
430    }
431  }
432
433  fclose(f);
434
435  if (!top_level)
436    return 0;
437
438  if (gfx_menu.entries == 0) {
439    printf("No LABEL keywords found.\n");
440    return 1;
441  }
442
443  // final '\0'
444  gfx_menu.label_size++;
445  gfx_menu.arg_size++;
446
447  // ensure we have a default entry
448  if(!menu_default->label) menu_default->label = menu->label;
449
450  if(menu_default->label) {
451    for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next) {
452      if(!strcmp(menu_default->label, menu_ptr->label)) {
453        menu_default->menu_label = menu_ptr->menu_label;
454        break;
455      }
456    }
457  }
458
459  gfx_menu.default_entry = menu_default->menu_label;
460  gfx_menu.label_list = calloc(gfx_menu.entries, gfx_menu.label_size);
461  gfx_menu.arg_list = calloc(gfx_menu.entries, gfx_menu.arg_size);
462
463  for(u = 0, menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next, u++) {
464    if(!menu_ptr->append) menu_ptr->append = menu_default->append;
465    if(!menu_ptr->ipappend) menu_ptr->ipappend = menu_default->ipappend;
466
467    if(menu_ptr->menu_label) strcpy(gfx_menu.label_list + u * gfx_menu.label_size, menu_ptr->menu_label);
468    if(menu_ptr->append) strcpy(gfx_menu.arg_list + u * gfx_menu.arg_size, menu_ptr->append);
469  }
470
471  return 0;
472}
473
474
475// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
476// Check header and return code start offset.
477//
478unsigned magic_ok(unsigned char *buf, unsigned *code_size)
479{
480  if(
481    *(unsigned *) buf == 0x0b2d97f00 &&         // magic id
482    (buf[4] == 8)                               // version 8
483  ) {
484    *code_size = *(unsigned *) (buf + 12);
485    return *(unsigned *) (buf + 8);
486  }
487
488  return 0;
489}
490
491
492// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
493// Search (cpio archive) for gfx file.
494//
495unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len, unsigned *code_size)
496{
497  unsigned i, fname_len, code_start = 0;
498
499  *gfx_file_start = 0;
500  *code_size = 0;
501
502  if((code_start = magic_ok(buf, code_size))) return code_start;
503
504  for(i = 0; i < len;) {
505    if((len - i) >= 0x1a && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) {
506      fname_len = *(unsigned short *) (buf + i + 20);
507      *file_len = *(unsigned short *) (buf + i + 24) + (*(unsigned short *) (buf + i + 22) << 16);
508      i += 26 + fname_len;
509      i = ((i + 1) & ~1);
510      if((code_start = magic_ok(buf + i, code_size))) {
511        *gfx_file_start = i;
512        return code_start;
513      }
514      i += *file_len;
515      i = ((i + 1) & ~1);
516    }
517    else {
518      break;
519    }
520  }
521
522  return code_start;
523}
524
525
526// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
527// Initialize gfxboot code.
528//
529// return:
530//   0: ok, 1: error
531//
532int gfx_init(char *file)
533{
534  size_t archive_size = 0;
535  void *archive;
536  unsigned code_start, code_size, file_start, file_len, u;
537  com32sys_t r;
538  void *lowmem = lowmem_buf;
539  unsigned lowmem_size = LOWMEM_BUF_SIZE;
540
541  memset(&r,0,sizeof(r));
542  progress_active = 0;
543
544  printf("Loading %s...\n", file);
545  if(loadfile(file, &archive, &archive_size)) return 1;
546
547  if(!archive_size) return 1;
548
549  // printf("%s: %d\n", file, archive_size);
550
551  gfx_config.archive_start = (uint32_t) archive;
552  gfx_config.archive_end = gfx_config.archive_start + archive_size;
553
554  // locate file inside cpio archive
555  if(!(code_start = find_file(archive, archive_size, &file_start, &file_len, &code_size))) {
556    printf("%s: invalid file format\n", file);
557    return 1;
558  }
559
560#if 0
561  printf(
562    "code_start = 0x%x, code_size = 0x%x\n"
563    "archive_start = 0x%x, archive size = 0x%x\n"
564    "file_start = 0x%x, file_len = 0x%x\n",
565    code_start, code_size,
566    gfx_config.archive_start, archive_size,
567    file_start, file_len
568  );
569#endif
570
571  gfx_config.file = gfx_config.archive_start + file_start;
572
573  u = realmode_callback_end - realmode_callback_start;
574  u = (u + REALMODE_BUF_SIZE + 0xf) & ~0xf;
575
576  if(u + code_size > lowmem_size) {
577    printf("lowmem buffer too small: size %u, needed %u\n", lowmem_size, u + code_size);
578    return 1;
579  }
580
581  memcpy(lowmem + REALMODE_BUF_SIZE, realmode_callback_start,
582         realmode_callback_end - realmode_callback_start);
583
584  // fill in buffer size and location
585  *(uint16_t *) (lowmem + REALMODE_BUF_SIZE) = REALMODE_BUF_SIZE;
586  *(uint16_t *) (lowmem + REALMODE_BUF_SIZE + 2) = (uint32_t) lowmem >> 4;
587
588  gfx_config.bootloader_seg = ((uint32_t) lowmem + REALMODE_BUF_SIZE) >> 4;
589  gfx_config.callback = 4;      // start address
590
591  lowmem += u;
592  lowmem_size -= u;
593
594  memcpy(lowmem, archive + file_start + code_start, code_size);
595
596  gfx_config.mem0_start = (uint32_t) lowmem + code_size;
597  gfx_config.mem0_end = (uint32_t) lowmem + lowmem_size;
598  // align a bit
599  gfx_config.mem0_start = (gfx_config.mem0_start + 0xf) & ~0xf;
600
601  gfx_config.xmem_start = (uint32_t) malloc(GFX_MEMORY_SIZE << 20);
602  if(gfx_config.xmem_start) {
603    gfx_config.xmem_end = gfx_config.xmem_start + (GFX_MEMORY_SIZE << 20);
604  }
605
606  // fake; not used anyway
607  gfx_config.bios_mem_size = 256 << 20;
608
609  gfx.code_seg = (uint32_t) lowmem >> 4;
610
611  for(u = 0; u < sizeof gfx.jmp_table / sizeof *gfx.jmp_table; u++) {
612    gfx.jmp_table[u] = (gfx.code_seg << 16) + *(uint16_t *) (lowmem + 2 * u);
613  }
614
615#if 0
616  for(u = 0; u < sizeof gfx.jmp_table / sizeof *gfx.jmp_table; u++) {
617    printf("%d: 0x%08x\n", u, gfx.jmp_table[u]);
618  }
619#endif
620
621  // we are ready to start
622
623  r.esi.l = (uint32_t) &gfx_config;
624  __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INIT], &r, &r);
625
626  if((r.eflags.l & EFLAGS_CF)) {
627    printf("graphics initialization failed\n");
628
629    return 1;
630  }
631
632  if((gfx_config.features & 3) != 3) {
633    gfx_done();
634
635    printf("%s: boot graphics code too old, please use newer version\n", file);
636
637    return 1;
638  }
639
640
641  return 0;
642}
643
644
645// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
646int gfx_menu_init(void)
647{
648  com32sys_t r;
649
650  memset(&r,0,sizeof(r));
651  r.esi.l = (uint32_t) &gfx_menu;
652  __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_MENU_INIT], &r, &r);
653
654  return 0;
655}
656
657
658// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
659void gfx_done(void)
660{
661  com32sys_t r;
662
663  memset(&r,0,sizeof(r));
664  gfx_progress_done();
665
666  __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_DONE], &r, &r);
667}
668
669
670// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
671// Run gfxboot main loop.
672//
673// return:
674//   boot menu index (-1: go to text mode prompt)
675//
676int gfx_input(void)
677{
678  com32sys_t r;
679
680  memset(&r,0,sizeof(r));
681  r.edi.l = (uint32_t) cmdline;
682  r.ecx.l = sizeof cmdline;
683  r.eax.l = timeout * 182 / 100;
684  timeout = 0;          // use timeout only first time
685  __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INPUT], &r, &r);
686  if((r.eflags.l & EFLAGS_CF)) r.eax.l = 1;
687
688  if(r.eax.l == 1) return -1;
689
690  return r.ebx.l;
691}
692
693
694// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
695void gfx_infobox(int type, char *str1, char *str2)
696{
697  com32sys_t r;
698
699  memset(&r,0,sizeof(r));
700  r.eax.l = type;
701  r.esi.l = (uint32_t) str1;
702  r.edi.l = (uint32_t) str2;
703  __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INFOBOX_INIT], &r, &r);
704  r.edi.l = r.eax.l = 0;
705  __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INPUT], &r, &r);
706  __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INFOBOX_DONE], &r, &r);
707}
708
709
710// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
711void gfx_progress_init(ssize_t kernel_size, char *label)
712{
713  com32sys_t r;
714
715  memset(&r,0,sizeof(r));
716  if(!progress_active) {
717    r.eax.l = kernel_size >> gfx_config.sector_shift;           // in sectors
718    r.esi.l = (uint32_t) label;
719    __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_INIT], &r, &r);
720  }
721
722  progress_active = 1;
723}
724
725
726// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
727void gfx_progress_update(ssize_t advance)
728{
729  com32sys_t r;
730
731  memset(&r,0,sizeof(r));
732  if(progress_active) {
733    r.eax.l = advance >> gfx_config.sector_shift;               // in sectors
734    __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_UPDATE], &r, &r);
735  }
736}
737
738
739// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
740void gfx_progress_done(void)
741{
742  com32sys_t r;
743
744  memset(&r,0,sizeof(r));
745  if(progress_active) {
746    __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_DONE], &r, &r);
747  }
748
749  progress_active = 0;
750}
751
752
753// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
754// Read file and update progress bar.
755//
756void *load_one(char *file, ssize_t *file_size)
757{
758  int fd;
759  void *buf = NULL;
760  char *str;
761  struct stat sbuf;
762  ssize_t size = 0, cur, i;
763
764  *file_size = 0;
765
766  if((fd = open(file, O_RDONLY)) == -1) {
767    asprintf(&str, "%s: file not found", file);
768    gfx_infobox(0, str, NULL);
769    free(str);
770    return buf;
771  }
772
773  if(!fstat(fd, &sbuf) && S_ISREG(sbuf.st_mode)) size = sbuf.st_size;
774
775  i = 0;
776
777  if(size) {
778    buf = malloc(size);
779    for(i = 1, cur = 0 ; cur < size && i > 0; cur += i) {
780      i = read(fd, buf + cur, min(CHUNK_SIZE, size - cur));
781      if(i == -1) break;
782      gfx_progress_update(i);
783    }
784  }
785  else {
786    do {
787      buf = realloc(buf, size + CHUNK_SIZE);
788      i = read(fd, buf + size, CHUNK_SIZE);
789      if(i == -1) break;
790      size += i;
791      gfx_progress_update(i);
792    } while(i > 0);
793  }
794
795  close(fd);
796
797  if(i == -1) {
798    asprintf(&str, "%s: read error @ %d", file, size);
799    gfx_infobox(0, str, NULL);
800    free(str);
801    free(buf);
802    buf = NULL;
803    size = 0;
804  }
805
806  *file_size = size;
807
808  return buf;
809}
810
811
812// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
813// Boot menu entry.
814//
815// cmdline can optionally start with label string.
816//
817void boot(int index)
818{
819  char *arg, *alt_kernel;
820  menu_t *menu_ptr;
821  int i, label_len;
822  unsigned ipapp;
823  const struct syslinux_ipappend_strings *ipappend;
824  char *gfxboot_cwd = (char *) gfx_config.gfxboot_cwd;
825
826  if(gfxboot_cwd) {
827    chdir(gfxboot_cwd);
828    gfx_config.gfxboot_cwd = 0;
829  }
830
831  for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next, index--) {
832    if(!index) break;
833  }
834
835  // invalid index or menu entry
836  if(!menu_ptr || !menu_ptr->menu_label) return;
837
838  arg = skipspace(cmdline);
839  label_len = strlen(menu_ptr->menu_label);
840
841  // if it does not start with label string, assume first word is kernel name
842  if(strncmp(arg, menu_ptr->menu_label, label_len)) {
843    alt_kernel = arg;
844    arg = skip_nonspaces(arg);
845    if(*arg) *arg++ = 0;
846    if(*alt_kernel) menu_ptr->alt_kernel = alt_kernel;
847  }
848  else {
849    arg += label_len;
850  }
851
852  arg = skipspace(arg);
853
854  // handle IPAPPEND
855  if(menu_ptr->ipappend && (ipapp = atoi(menu_ptr->ipappend))) {
856    ipappend = syslinux_ipappend_strings();
857    for(i = 0; i < ipappend->count; i++) {
858      if((ipapp & (1 << i)) && ipappend->ptr[i]) {
859        sprintf(arg + strlen(arg), " %s", ipappend->ptr[i]);
860      }
861    }
862  }
863
864  boot_entry(menu_ptr, arg);
865
866  gfx_progress_done();
867}
868
869
870// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
871// Load & run kernel.
872//
873// Returns only on error.
874//
875void boot_entry(menu_t *menu_ptr, char *arg)
876{
877  void *kernel, *initrd_buf;
878  ssize_t kernel_size = 0, initrd_size = 0;
879  struct initramfs *initrd = NULL;
880  char *file, *cmd_buf;
881  int fd;
882  struct stat sbuf;
883  char *s, *s0, *t, *initrd_arg;
884
885  if(!menu_ptr) return;
886
887  if(menu_ptr->localboot) {
888    gfx_done();
889    syslinux_local_boot(strtol(menu_ptr->localboot, NULL, 0));
890
891    return;
892  }
893
894  file = menu_ptr->alt_kernel;
895  if(!file) file = menu_ptr->kernel;
896  if(!file) file = menu_ptr->linux;
897  if(!file) {
898    gfx_done();
899    asprintf(&cmd_buf, "%s %s", menu_ptr->label, arg);
900    syslinux_run_command(cmd_buf);
901    return;
902  }
903
904  // first, load kernel
905
906  kernel_size = 0;
907
908  if((fd = open(file, O_RDONLY)) >= 0) {
909    if(!fstat(fd, &sbuf) && S_ISREG(sbuf.st_mode)) kernel_size = sbuf.st_size;
910    close(fd);
911  }
912
913  gfx_progress_init(kernel_size, file);
914
915  kernel = load_one(file, &kernel_size);
916
917  if(!kernel) {
918    return;
919  }
920
921  if(kernel_size < 1024 || *(uint32_t *) (kernel + 0x202) != 0x53726448) {
922    // not a linux kernel
923    gfx_done();
924    asprintf(&cmd_buf, "%s %s", menu_ptr->label, arg);
925    syslinux_run_command(cmd_buf);
926    return;
927  }
928
929  // printf("kernel = %p, size = %d\n", kernel, kernel_size);
930
931  // parse cmdline for "initrd" option
932
933  initrd_arg = menu_ptr->initrd;
934
935  s = s0 = strdup(arg);
936
937  while(*s && strncmp(s, "initrd=", sizeof "initrd=" - 1)) {
938    s = skipspace(skip_nonspaces(s));
939  }
940
941  if(*s) {
942    s += sizeof "initrd=" - 1;
943    *skip_nonspaces(s) = 0;
944    initrd_arg = s;
945  }
946  else if(initrd_arg) {
947    free(s0);
948    initrd_arg = s0 = strdup(initrd_arg);
949  }
950
951  if(initrd_arg) {
952    initrd = initramfs_init();
953
954    while((t = strsep(&initrd_arg, ","))) {
955      initrd_buf = load_one(t, &initrd_size);
956
957      if(!initrd_buf) {
958        printf("%s: read error\n", t);
959        free(s0);
960        return;
961      }
962
963      initramfs_add_data(initrd, initrd_buf, initrd_size, initrd_size, 4);
964
965      // printf("initrd = %p, size = %d\n", initrd_buf, initrd_size);
966    }
967  }
968
969  free(s0);
970
971  gfx_done();
972
973  syslinux_boot_linux(kernel, kernel_size, initrd, NULL, arg);
974}
975
976
Note: See TracBrowser for help on using the repository browser.