2 * Copyright (C) 2001-2003 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
4 * Contributed by Fenghua Yu <fenghua.yu@intel.com>
5 * Contributed by Bibo Mao <bibo.mao@intel.com>
6 * Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
8 * This file is part of the ELILO, the EFI Linux boot loader.
10 * ELILO is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * ELILO is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with ELILO; see the file COPYING. If not, write to the Free
22 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 * Please check out the elilo.txt for complete documentation on how
26 * to use this program.
28 * Portions of this file are derived from the LILO/x86
29 * Copyright 1992-1997 Werner Almesberger.
34 #include <efistdarg.h>
40 * The first default config file is architecture dependent. This is useful
41 * in case of network booting where the server is used for both types of
44 #if defined(CONFIG_ia64)
45 #define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf"
46 #elif defined (CONFIG_ia32)
47 #define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf"
48 #elif defined (CONFIG_x86_64)
49 #define ELILO_ARCH_DEFAULT_CONFIG L"elilo-x86_64.conf"
51 #error "You need to specfy your default arch config file"
55 * last resort config file. Common to all architectures
57 #define ELILO_DEFAULT_CONFIG L"elilo.conf"
59 #define MAX_STRING 512
60 #define CONFIG_BUFSIZE 512 /* input buffer size */
63 * maximum number of message files.
65 * main message= goes at entry 0, entries [1-12] are used for function keys
68 #define MAX_MESSAGES 13
70 typedef struct boot_image {
71 struct boot_image *next;
72 CHAR16 label[MAX_STRING];
73 CHAR16 kname[FILENAME_MAXLEN];
74 CHAR16 options[CMDLINE_MAXLEN];
75 CHAR16 initrd[FILENAME_MAXLEN];
76 CHAR16 vmcode[FILENAME_MAXLEN];
77 CHAR16 root[FILENAME_MAXLEN];
78 CHAR16 fallback[MAX_STRING];
79 CHAR16 description[MAX_STRING];
85 sys_img_options_t sys_img_opts; /* architecture specific image options */
96 * global shared options
97 * architecture specific global options are private to each architecture
100 CHAR16 root[FILENAME_MAXLEN]; /* globally defined root fs */
101 CHAR16 initrd[FILENAME_MAXLEN];/* globally defined initrd */
102 CHAR16 vmcode[FILENAME_MAXLEN];/* globally defined boot-time module */
103 CHAR16 options[CMDLINE_MAXLEN];
104 CHAR16 default_image_name[MAX_STRING];
105 CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN];
106 CHAR16 chooser[FILENAME_MAXLEN];/* which image chooser to use */
107 CHAR16 config_file[FILENAME_MAXLEN];
108 boot_image_t *default_image;
113 * options that may affect global elilo options
121 UINTN edd30_no_force; /* don't force EDD30 if not set */
125 * structure used to point to a group of options.
126 * Several group for the same category are supported via a linked list.
128 typedef struct _config_option_group {
129 struct _config_option_group *next; /* pointer to next group */
130 config_option_t *options; /* the table of options for this group */
131 UINTN nentries; /* number of entries for this group */
132 } config_option_group_t;
134 static option_action_t do_image, do_literal, do_options;
135 static INTN check_verbosity(VOID *), check_chooser(VOID *);
137 static global_config_t global_config; /* options shared by all images */
140 * Core global options: shared by all architectures, all modules
142 static config_option_t global_common_options[]={
143 {OPT_STR, OPT_GLOBAL, L"default", NULL, NULL, global_config.default_image_name},
144 {OPT_NUM, OPT_GLOBAL, L"timeout", NULL, NULL, &global_config.timeout},
145 {OPT_NUM, OPT_GLOBAL, L"delay", NULL, NULL, &global_config.delay},
146 {OPT_BOOL, OPT_GLOBAL, L"debug", NULL, NULL, &global_config.debug},
147 {OPT_BOOL, OPT_GLOBAL, L"prompt", NULL, NULL, &global_config.prompt},
148 {OPT_NUM, OPT_GLOBAL, L"verbose", NULL, check_verbosity, &global_config.verbose},
149 {OPT_FILE, OPT_GLOBAL, L"root", NULL, NULL, global_config.root},
150 {OPT_BOOL, OPT_GLOBAL, L"read-only", NULL, NULL, &global_config.readonly},
151 {OPT_BOOL, OPT_GLOBAL, L"noedd30", NULL, NULL, &global_config.edd30_no_force},
152 {OPT_CMD, OPT_GLOBAL, L"append", NULL, NULL, global_config.options},
153 {OPT_FILE, OPT_GLOBAL, L"initrd", NULL, NULL, global_config.initrd},
154 {OPT_FILE, OPT_GLOBAL, L"vmm", NULL, NULL, global_config.vmcode},
155 {OPT_FILE, OPT_GLOBAL, L"image", do_image, NULL, opt_offsetof(kname)},
156 {OPT_BOOL, OPT_GLOBAL, L"checkalt", NULL, NULL, &global_config.alt_check},
157 {OPT_STR, OPT_GLOBAL, L"chooser", NULL, check_chooser, global_config.chooser},
158 {OPT_FILE, OPT_GLOBAL, L"message", NULL, NULL, global_config.message_file[0]},
159 {OPT_FILE, OPT_GLOBAL, L"f1", NULL, NULL, global_config.message_file[1]},
160 {OPT_FILE, OPT_GLOBAL, L"f2", NULL, NULL, global_config.message_file[2]},
161 {OPT_FILE, OPT_GLOBAL, L"f3", NULL, NULL, global_config.message_file[3]},
162 {OPT_FILE, OPT_GLOBAL, L"f4", NULL, NULL, global_config.message_file[4]},
163 {OPT_FILE, OPT_GLOBAL, L"f5", NULL, NULL, global_config.message_file[5]},
164 {OPT_FILE, OPT_GLOBAL, L"f6", NULL, NULL, global_config.message_file[6]},
165 {OPT_FILE, OPT_GLOBAL, L"f7", NULL, NULL, global_config.message_file[7]},
166 {OPT_FILE, OPT_GLOBAL, L"f8", NULL, NULL, global_config.message_file[8]},
167 {OPT_FILE, OPT_GLOBAL, L"f9", NULL, NULL, global_config.message_file[9]},
168 {OPT_FILE, OPT_GLOBAL, L"f10", NULL, NULL, global_config.message_file[10]},
169 {OPT_FILE, OPT_GLOBAL, L"f11", NULL, NULL, global_config.message_file[11]},
170 {OPT_FILE, OPT_GLOBAL, L"f12", NULL, NULL, global_config.message_file[12]}
173 static config_option_t image_common_options[]={
174 {OPT_FILE, OPT_IMAGE, L"root", NULL, NULL, opt_offsetof(root)},
175 {OPT_BOOL, OPT_IMAGE, L"read-only", NULL, NULL, opt_offsetof(readonly)},
176 {OPT_CMD, OPT_IMAGE, L"append", do_options, NULL, opt_offsetof(options)},
177 {OPT_CMD, OPT_IMAGE, L"literal", do_literal, NULL, NULL},
178 {OPT_FILE, OPT_IMAGE, L"initrd", NULL, NULL, opt_offsetof(initrd)},
179 {OPT_FILE, OPT_IMAGE, L"vmm", NULL, NULL, opt_offsetof(vmcode)},
180 {OPT_STR, OPT_IMAGE, L"label", NULL, NULL, opt_offsetof(label)},
181 {OPT_FILE, OPT_IMAGE, L"image", do_image, NULL, opt_offsetof(kname)},
182 {OPT_STR, OPT_IMAGE, L"description", NULL, NULL, opt_offsetof(description)},
185 #define OPTION_IS_GLOBAL(p) ((p)->scope == OPT_GLOBAL)
186 #define OPTION_IS_IMG_SYS(p) ((p)->scope == OPT_IMAGE_SYS)
188 #define CHAR_EOF (CHAR16)-1 /* Unicode version of EOF */
189 #define CHAR_NUM0 L'0'
190 #define CHAR_NUM9 L'9'
192 static UINTN line_num;
193 static INTN back; /* can go back by one char */
195 static config_option_group_t *global_option_list;
196 static config_option_group_t *image_option_list;
199 static config_option_group_t *current_options;
201 static boot_image_t *image_list, *first_image;
202 static boot_image_t *current_img;
204 static INT8 config_buf[CONFIG_BUFSIZE]; /* input buffer: file must be in ASCII! */
205 static UINTN buf_max, buf_pos;
207 static fops_fd_t config_fd;
210 config_error(CHAR16 *msg,...)
212 Print(L"near line %d: ",line_num);
213 IPrint(systab->ConOut, msg);
218 * low level read routine
222 * - the next available unicode character
224 * - CHAR_EOF : indicating error or EOF
226 * XXX: we suppose that the file is in ASCII format!
233 if (buf_pos == 0 || buf_pos == buf_max) {
234 buf_max = CONFIG_BUFSIZE;
235 status = fops_read(config_fd, config_buf, &buf_max);
236 if (EFI_ERROR(status) || buf_max == 0) return CHAR_EOF;
240 return (CHAR16)config_buf[buf_pos++];
245 * get the next unicode character with a one character
259 * config files served from pxe/tftpboot windows servers can contain
260 * extraneous '\r' characters, often the first char in the file, and
261 * we need to simply skip over those and continue on
271 * rewind by one character
276 if (back) { config_error(L"config: again invoked twice"); }
281 * Look for matching option in the current group
284 * - pointer to option if found
285 * - NULL if not found
287 static config_option_t *
288 find_option(config_option_group_t *grp, CHAR16 *str)
290 config_option_t *p = NULL;
291 config_option_t *end;
295 end = grp->options+grp->nentries;
298 if (!StrCmp(str, p->name)) return p;
307 * main parser function
309 * - a token code representing the kind of element found
310 * - TOK_EOF: end-of-file (or error) detected
311 * - TOK_STR: if string is found
312 * - TOK_EQUAL: for the '=' sign
313 * - TOK_ERR: in case of (parsing) error
316 get_token_core(CHAR16 *str, UINTN maxlen, BOOLEAN rhs)
322 while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n' ) line_num++;
324 if (ch == CHAR_EOF) return TOK_EOF;
326 /* skip comment line */
327 if (ch != '#') break;
329 while ((ch = next()), ch != '\n') if (ch == CHAR_EOF) return TOK_EOF;
332 if (ch == '=' && !rhs) return TOK_EQUAL;
336 while (here-str < maxlen) {
337 if ((ch = next()) == CHAR_EOF) {
338 config_error(L"EOF in quoted string");
347 if (ch != '"' && ch != '\\' && ch != '\n') {
348 config_error(L"Bad use of \\ in quoted string");
351 if (ch == '\n') continue;
353 while ((ch = next()), ch == ' ' || ch == '\t');
360 if (ch == '\n' || ch == '\t') {
361 config_error(L"\\n and \\t are not allowed in quoted strings");
366 config_error(L"Quoted string is too long");
373 while (here-str < maxlen) {
375 if (ch == CHAR_EOF) {
376 config_error(L"\\ precedes EOF");
379 if (ch == '\n') line_num++;
380 else *here++ = ch == '\t' ? ' ' : ch;
384 if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
385 ch == CHAR_EOF || (ch == '=' && !rhs)) {
390 if (!(escaped = (ch == '\\'))) *here++ = ch;
394 config_error(L"Token is too long");
399 get_token(CHAR16 *str, UINTN maxlen)
401 return get_token_core(str, maxlen, FALSE);
405 get_token_rhs(CHAR16 *str, UINTN maxlen)
407 return get_token_core(str, maxlen, TRUE);
411 image_check(boot_image_t *img)
415 if (img == NULL) return -1;
417 /* do the obvious first */
418 if (img->label[0] == '\0') {
419 config_error(L"image has no label");
423 /* image_list points to the */
424 for(b=image_list; b; b = b->next) {
425 if (img == b) continue;
426 if (!StrCmp(img->label, b->label)) {
427 config_error(L"image with label %s already defined", img->label);
445 if (global_config.default_image_name[0]) {
446 for(b=image_list; b; b = b->next) {
447 if (!StrCmp(b->label, global_config.default_image_name)) goto found;
449 config_error(L"default image '%s' not defined ", global_config.default_image_name);
452 global_config.default_image = first_image;
455 global_config.default_image = b;
460 * depending on the active set of options
461 * adjust the option data pointer to:
462 * if global option set:
463 * - just the straight value from p->data
464 * if image option set:
465 * - adjust as offset to image
467 * - the adjusted pointer
470 adjust_pointer(config_option_t *p)
475 if (OPTION_IS_GLOBAL(p)) return p->data;
477 if (OPTION_IS_IMG_SYS(p)) return (VOID *)((UINTN)¤t_img->sys_img_opts + p->data);
479 return (VOID *)((UINTN)current_img + p->data);
483 * create a new image entry
486 do_image(config_option_t *p, VOID *str)
491 * if we move to a new image from the current one
492 * then we need to check for validity of current.
494 * if this is the first image, then check the global
498 if (image_check(current_img) == -1) return -1;
499 } else if (global_check() == -1) return -1;
501 img = (boot_image_t *)alloc(sizeof(boot_image_t), EfiLoaderData);
502 if (img == NULL) return -1;
504 Memset(img, 0, sizeof(boot_image_t));
506 DBG_PRT((L"must do image on %s", (CHAR16 *)str));
508 /* copy kernel file name */
509 StrCpy(img->kname, str);
511 /* switch to image mode */
512 current_options = image_option_list;
514 /* keep track of first image in case no default is defined */
515 if (image_list == NULL) first_image = img;
517 /* append to end of image list, so when a chooser asks for the list
518 * it gets them in the order they were in in the config file
520 if (image_list == NULL)
523 boot_image_t * p = image_list;
530 /* update current image */
537 * by default all boolean options are defined
538 * as false. This function sets the boolean
542 do_boolean(config_option_t *p)
546 buf = adjust_pointer(p);
548 if (p->action) return p->action(p, NULL);
550 /* set the field to true, overwrite if already defined */
557 * the image option 'literal' requires special handling
558 * because it overrides any defined option be it global or
559 * local. so we use the option field and record the fact that
560 * it should be interpreted as literal
563 do_literal(config_option_t *p, VOID *str)
566 * we know we have a valid current image at this point
568 StrCpy(current_img->options, str);
570 current_img->literal = 1;
576 do_options(config_option_t *p, VOID *str)
578 /* we ignore append if literal is already defined */
579 if (current_img->literal) return 0;
582 * we know we have a valid current image at this point
584 StrCpy(current_img->options, str);
590 do_numeric(config_option_t *p)
592 CHAR16 numstr[MAX_STRING];
601 tok = get_token(numstr, MAX_STRING);
602 if (tok != TOK_EQUAL) {
603 config_error(L"Option %s expects an equal signal + value", p->name);
609 * XXX: = lexer should return TOK_NUM (and we'd be done)
611 tok = get_token(numstr, MAX_STRING);
612 if (tok != TOK_STR) {
613 config_error(L"Option %s expects a value", p->name);
618 * if there is a customized way of doing the operation
619 * do it and bypass generic
621 if (p->action) return p->action(p, str);
626 if (p->data == NULL) return 0;
628 buf = (UINTN *)adjust_pointer(p);
630 while (*str && *str >= CHAR_NUM0 && *str <= CHAR_NUM9) str++;
632 config_error(L"%s is expecting a numeric decimal value", p->name);
638 if (p->check && p->check(&tmp) == -1) return -1;
641 * check for multiple definitions in the same context
642 * XXX: zero must not be a valid number !
645 config_error(L"option %s is already defined in this context", p->name);
655 check_verbosity(VOID *data)
657 UINTN *val = (UINTN *)data;
660 config_error(L"Verbosity level must be in [0-5] and not %d", *val);
668 * here we simply check if chooser is compiled in. At this point, the chooser
669 * initialization is not done, so we don't know if that chooser will even be
673 check_chooser(VOID *data)
675 CHAR16 *chooser = (CHAR16 *)data;
677 if (exist_chooser(chooser) == -1) {
678 config_error(L"chooser %s is unknown\n", chooser);
686 do_string_core(config_option_t *p, CHAR16 *str, UINTN maxlen, CHAR16 *msg)
694 tok = get_token(str, maxlen);
695 if (tok != TOK_EQUAL) {
696 config_error(L"Option %s expects an equal signal + %s", p->name, msg);
703 tok = get_token_rhs(str, maxlen);
704 if (tok != TOK_STR) {
705 config_error(L"Option %s expects %s", p->name, msg);
710 * if there is a customized way of doing the operation
711 * do it and bypass generic
713 if (p->action) return p->action(p, str);
718 if (p->data == NULL) return 0;
720 buf = adjust_pointer(p);
722 if (*buf != CHAR_NULL) {
723 config_error(L"'%s' already defined", p->name);
726 if (p->check && p->check(str) == -1) return -1;
737 do_string(config_option_t *p)
739 CHAR16 str[MAX_STRING];
741 return do_string_core(p, str, MAX_STRING, L"string");
745 do_file(config_option_t *p)
747 CHAR16 str[FILENAME_MAXLEN];
749 return do_string_core(p, str, FILENAME_MAXLEN, L"filename");
754 do_cmd(config_option_t *p)
756 CHAR16 str[CMDLINE_MAXLEN];
757 return do_string_core(p, str, CMDLINE_MAXLEN, L"kernel options");
764 CHAR16 str[MAX_STRING];
770 tok = get_token(str, MAX_STRING);
772 if (tok == TOK_EOF) break;
774 if (tok == TOK_ERR) {
775 Print(L"Bad Token from elilo config file, parser read: %s\n elilo exiting\n", str);
779 if ( (p = find_option(current_options, str)) == NULL) {
780 config_error(L"Unkown option %s", str);
784 /* make sure we trap in case of error */
804 config_error(L"Unkown option type %d", p->type);
806 if (ret == -1) goto error;
809 ret = image_check(current_img);
811 config_error(L"No image defined !");
813 if (ret == 0) ret = final_check();
819 update_elilo_opt(VOID)
822 * update boolean options first
823 * Rule: by default not set unless explcitely requested on command line
824 * therefore we can just update from global_config is set there.
826 if (global_config.alt_check) elilo_opt.alt_check = 1;
828 if (global_config.debug) elilo_opt.debug = 1;
829 if (global_config.prompt) elilo_opt.prompt = 1;
832 * update only if not set on command line
833 * XXX: rely on the existence of a non-valid value as a marker than
834 * the option was not specified on the command line
836 if (global_config.verbose && elilo_opt.verbose == 0)
837 elilo_opt.verbose = global_config.verbose;
839 if (global_config.chooser[0] && elilo_opt.chooser[0] == 0)
840 StrCpy(elilo_opt.chooser, global_config.chooser);
843 * if edd30_no_force not set by command line option but via config
844 * file, then propagate
846 if (global_config.edd30_no_force && elilo_opt.edd30_no_force == 0)
847 elilo_opt.edd30_no_force = 1;
850 * Difficult case of numeric where 0 can be a valid value
851 * XXX: find a better way of handling these options!
853 if (global_config.delay && elilo_opt.delay_set == 0)
854 elilo_opt.delay = global_config.delay;
856 /* readjusted by caller if necessary. 0 not a valid value here */
857 elilo_opt.timeout = global_config.timeout;
859 /* initrd is updated later when we have an image match */
863 * When called after read_config(), this function returns the config file
864 * used by the loader, or NULL if no file was found.
867 get_config_file(VOID)
869 return global_config.config_file[0] ? global_config.config_file : NULL;
873 read_config(CHAR16 *filename)
878 if (filename == NULL) return EFI_INVALID_PARAMETER;
880 VERB_PRT(3, Print(L"trying config file %s\n", filename));
882 StrCpy(global_config.config_file, filename);
884 status = fops_open(filename, &config_fd);
885 if (EFI_ERROR(status)) {
886 VERB_PRT(3, Print(L"cannot open config file %s\n", filename));
890 * start numbering at line 1
894 ret = config_parse();
896 fops_close(config_fd);
898 DBG_PRT((L"done parsing config file\n"));
900 if (ret != 0) return EFI_INVALID_PARAMETER;
908 print_label_list(VOID)
910 boot_image_t *img, *dfl = global_config.default_image;
912 if (dfl) Print(L" %s\n", dfl->label);
914 for (img = image_list; img; img = img->next) {
915 if (img != dfl) Print(L" %s\n", img->label);
919 /* Make labels and corresponding descriptions available to choosers. The
920 * idea is that the caller passes NULL for 'prev'; the first time, and
921 * passes the previously returned value on subsequent calls. The caller
922 * repeats until this fn returns NULL.
926 get_next_description(VOID *prev, CHAR16 **label, CHAR16 **description)
928 boot_image_t *img = (boot_image_t *)prev;
937 *description = img->description;
945 * find a description using the label name
946 * return NULL if label not found or no description defined
949 find_description(CHAR16 *label)
953 /* Attempt to find the image name now */
954 for (img = image_list; img; img = img->next) {
955 if (StriCmp(img->label, label) == 0) {
956 return img->description;
963 add_root_to_options(CHAR16 *options, CHAR16 *root, CHAR16 *vmcode)
965 CHAR16 *o, ko[CMDLINE_MAXLEN];
968 for (o = options; *o; o++) {
969 if (*o == '-' && *(o+1) == '-')
973 /* no separator found, add one */
978 /* advance past separator and whitespace */
980 while (*o == ' ') o++;
985 /* insert root param at this point */
994 find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16 *vmcode)
999 if (global_config.default_image == NULL) return -1;
1000 img = global_config.default_image;
1006 /* Attempt to find the image name now */
1007 for (img = image_list; img; img = img->next) {
1008 if (StriCmp(img->label, label) == 0) {
1013 * when the label does not exist, we still propagate the global options
1015 if (global_config.options[0]) {
1016 StrCat(options, L" ");
1017 StrCat(options, global_config.options);
1019 if (global_config.root[0])
1020 add_root_to_options(options, global_config.root, global_config.vmcode);
1021 if (global_config.readonly) StrCat(options, L" ro");
1023 if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd);
1024 if (global_config.vmcode[0]) StrCpy(vmcode, global_config.vmcode);
1026 /* make sure we don't get garbage here */
1027 elilo_opt.sys_img_opts = NULL;
1031 StrCpy(kname, img->kname);
1033 /* per image initrd has precedence over global initrd */
1035 StrCpy(initrd, img->initrd);
1037 StrCpy(initrd, global_config.initrd);
1039 /* per image vmcode has precedence over global vmcode */
1041 StrCpy(vmcode, img->vmcode);
1043 StrCpy(vmcode, global_config.vmcode);
1046 * literal option overrides any other image-based or global option
1048 * In any case, the image option has priority over the global option
1050 if (img->literal == 0) {
1051 /* XXX: check max length */
1052 if (img->options[0] || global_config.options[0]) {
1053 StrCat(options, L" ");
1054 StrCat(options, img->options[0] ? img->options: global_config.options);
1056 if (img->root[0] || global_config.root[0]) {
1057 add_root_to_options(options, img->root[0]
1058 ? img->root : global_config.root, vmcode);
1060 if (img->readonly || global_config.readonly) {
1061 StrCat(options, L" ro");
1064 /* literal options replace everything */
1065 StrCpy(options, img->options);
1069 * point to architecture dependent options for this image
1071 elilo_opt.sys_img_opts = &img->sys_img_opts;
1073 DBG_PRT((L"label %s: kname=%s options=%s initrd=%s vmcode=%s", img->label, kname, options, initrd, vmcode));
1079 print_options(config_option_group_t *grp, BOOLEAN first)
1081 config_option_t *end, *p;
1086 end = grp->options+grp->nentries;
1097 str = L"%s=filename";
1100 str = L"%s=kernel_options";
1108 if (str && first == FALSE) Print(L", ");
1109 if (str) Print(str, p->name);
1119 print_config_options(VOID)
1121 Print(L"Global options supported:\n");
1123 print_options(global_option_list, TRUE);
1126 Print(L"Image options supported:\n");
1127 print_options(image_option_list, TRUE);
1133 * returns a pointer to filename used for message N (which). NULL if it does
1137 get_message_filename(INTN which)
1139 if (which < 0 || which >= MAX_MESSAGES) return NULL;
1140 return global_config.message_file[which];
1144 register_config_options(config_option_t *opt, UINTN n, config_option_group_scope_t group)
1146 config_option_group_t *newgrp, **grp;
1148 if (opt == NULL || n == 0 || (group != OPTIONS_GROUP_GLOBAL && group != OPTIONS_GROUP_IMAGE)) return -1;
1150 VERB_PRT(3, Print(L"registering %d options for group %s\n", n, group == OPTIONS_GROUP_GLOBAL ? L"global" : L"image"));
1152 newgrp = alloc(sizeof(config_option_group_t), EfiLoaderData);
1153 if (newgrp == NULL) return -1;
1155 grp = group == OPTIONS_GROUP_GLOBAL ? &global_option_list : &image_option_list;
1157 if (*grp) while ((*grp)->next) grp = &(*grp)->next;
1159 newgrp->options = opt;
1160 newgrp->next = NULL;
1161 newgrp->nentries = n;
1164 (*grp)->next = newgrp;
1172 * initialize config options: register global and per image options
1179 ret = register_config_options(global_common_options,
1180 sizeof(global_common_options)/sizeof(config_option_t),
1181 OPTIONS_GROUP_GLOBAL);
1182 if (ret == -1) return -1;
1184 ret = register_config_options(image_common_options,
1185 sizeof(image_common_options)/sizeof(config_option_t),
1186 OPTIONS_GROUP_IMAGE);
1188 current_options = global_option_list;