2 * Copyright (C) 2001-2003 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
5 * This file is part of the ELILO, the EFI Linux boot loader.
7 * ELILO is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * ELILO is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with ELILO; see the file COPYING. If not, write to the Free
19 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 * Please check out the elilo.txt for complete documentation on how
23 * to use this program.
32 /* static is ugly but does the job here! */
33 static CHAR16 **alt_argv;
36 display_label_info(CHAR16 *name)
39 CHAR16 initrd_name[CMDLINE_MAXLEN];
40 CHAR16 options_tmp[CMDLINE_MAXLEN];
41 CHAR16 options[CMDLINE_MAXLEN];
42 CHAR16 kname[FILENAME_MAXLEN];
44 desc = find_description(name);
46 Print(L"desc : %s\n", desc);
49 initrd_name[0] = options_tmp[0] = kname[0] = CHAR_NULL;
51 if (find_label(name, kname, options_tmp, initrd_name) == -1) {
55 subst_vars(options_tmp, options, CMDLINE_MAXLEN);
57 Print(L"cmdline: %s %s\n", kname, options);
58 if (initrd_name[0]) Print(L"initrd : %s\n", initrd_name);
62 print_infos(int force)
65 CHAR16 dpath[FILENAME_MAXLEN];
66 CHAR16 *boot_dev_name;
69 boot_dev_name = fops_bootdev_name();
70 config_file = get_config_file();
72 fops_getdefault_path(dpath, FILENAME_MAXLEN);
74 if (force || elilo_opt.verbose > 0)
75 Print(L"default file path: %s:%s\n", boot_dev_name, dpath);
77 is_abs = config_file && (config_file[0] == CHAR_BACKSLASH || config_file[0] == CHAR_SLASH) ? 1 : 0;
79 if (force || elilo_opt.verbose > 0)
80 Print(L"config file : %s%s\n", config_file && is_abs == 0 ? dpath : L"", config_file ? config_file : L"none used");
83 CHAR16 **p = alt_argv;
84 Print(L"found alternate default choice :");
85 while (*p) Print(L" %s", *p++);
93 if (force || elilo_opt.verbose > 0)
94 Print(L"command list (must be first character):\n=:print device list, %%:print variable list, &:print paths, ?:help\nTAB:print label information\n");
98 * interactively select a kernel image and options.
99 * The kernel can be an actual filename or a label in the config file
105 select_kernel(CHAR16 *buffer, INTN size)
107 #define CHAR_CTRL_C L'\003' /* Unicode CTRL-C */
108 #define CHAR_CTRL_D L'\004' /* Unicode CTRL-D */
109 #define CHAR_CTRL_U L'\025' /* Unicode CTRL-U */
110 //#define CHAR_TAB L'\t'
111 SIMPLE_INPUT_INTERFACE *ip = systab->ConIn;
118 * let's give some help first
125 buffer[pos] = CHAR_NULL;
127 Print(L"\nELILO boot: %s", buffer);
129 * autoboot with default choice after timeout expires
131 if (first_time && (ret=wait_timeout(elilo_opt.timeout)) != 1) {
132 return ret == -1 ? -1: 0;
137 while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
138 if (EFI_ERROR(status)) {
139 ERR_PRT((L"select_kernel readkey: %r", status));
142 switch (key.UnicodeChar) {
147 Print(L"(or a kernel file name: [[dev_name:/]path/]kernel_image cmdline options)\n");
149 buffer[pos] = CHAR_NULL;
150 display_label_info(buffer);
154 if (pos>0) goto normal_char;
159 if (pos>0) goto normal_char;
164 if (pos>0) goto normal_char;
169 if (pos>0) goto normal_char;
178 case CHAR_CTRL_U: /* clear line */
184 case CHAR_CTRL_C: /* kill line */
188 case CHAR_CARRIAGE_RETURN:
189 buffer[pos] = CHAR_NULL;
194 if (key.UnicodeChar == CHAR_CTRL_D || key.ScanCode == 0x17 ) {
195 Print(L"\nGiving up then...\n");
198 if (key.UnicodeChar == CHAR_NULL) break;
200 if (pos > size-1) break;
202 buffer[pos++] = key.UnicodeChar;
204 /* Write the character out */
205 Print(L"%c", key.UnicodeChar);
212 display_message(VOID)
220 if ((filename = get_message_filename(0)) == NULL) return;
222 if (*filename == CHAR_NULL) return;
224 VERB_PRT(3, Print(L"opening message file %s\n", filename));
226 status = fops_open(filename, &fd);
227 if (EFI_ERROR(status)) {
228 VERB_PRT(3, Print(L"message file %s not found\n", filename));
233 while ((status = fops_read(fd, buf, &len)) == EFI_SUCCESS) {
235 for (i=0; i < len; i++) {
236 Print(L"%c", (CHAR16)buf[i]);
238 if (len < 256) break;
244 simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdline)
246 # define BOOT_IMG_STR L"BOOT_IMAGE="
247 CHAR16 buffer[CMDLINE_MAXLEN];
248 CHAR16 alt_buffer[CMDLINE_MAXLEN];
249 CHAR16 initrd_name[CMDLINE_MAXLEN];
250 CHAR16 args[CMDLINE_MAXLEN];
251 CHAR16 devname[CMDLINE_MAXLEN];
252 CHAR16 dpath[FILENAME_MAXLEN];
253 CHAR16 *slash_pos, *colon_pos, *backslash_pos;
257 buffer[0] = alt_buffer[0] = CHAR_NULL;
262 initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
264 /* reset per image loader options */
265 Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
268 * check for alternate kernel image and params in EFI variable
270 if (elilo_opt.alt_check && alternate_kernel(alt_buffer, sizeof(alt_buffer)) == 0) {
271 argc = argify(alt_buffer,sizeof(alt_buffer), argv);
274 args[0] = initrd_name[0] = 0;
276 * don't check twice because the variable is deleted after
279 elilo_opt.alt_check = 0;
282 if (elilo_opt.prompt) {
283 ret = select_kernel(buffer, sizeof(buffer));
284 if (ret == -1) return -1;
285 argc = argify(buffer,sizeof(buffer), argv);
290 * if we found an alternate choice and the user
291 * did not force it manually, then use the alternate
294 if (alt_buffer[0] && buffer[0] == CHAR_NULL) {
295 StrCpy(buffer, alt_buffer);
299 * First search for matching label in the config file
300 * if options were specified on command line, they take
301 * precedence over the ones in the config file
303 * if no match is found, the args and initrd arguments may
304 * still be modified by global options in the config file.
306 ret = find_label(argv[index], kname, args, initrd_name);
309 * not found, so assume first argument is kernel name and
314 StrCpy(kname, argv[index]);
316 StrCpy(kname, elilo_opt.default_kernel);
319 * no matter what happened for kname, if user specified
320 * additional options, they override the ones in the
323 if (argc > 1+index) {
324 /*StrCpy(args, argv[++index]);*/
325 while (++index < argc) {
327 StrCat(args, argv[index]);
331 * if initrd specified on command line, it overrides
332 * the one defined in config file, if any
334 if (elilo_opt.initrd[0] == CHAR_NULL && initrd_name[0] != CHAR_NULL) {
335 StrCpy(elilo_opt.initrd, initrd_name);
338 VERB_PRT(1, { Print(L"kernel is '%s'\n", kname);
339 Print(L"arguments are '%s'\n", args);
340 if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd);
343 if (elilo_opt.prompt == 0) {
344 /* minimal printing */
346 ret = wait_timeout(elilo_opt.delay);
348 elilo_opt.prompt = 1;
349 elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
354 * add the device name, if not already specified,
355 * so that we know where we came from
357 slash_pos = StrChr(kname, L'/');
358 backslash_pos = StrChr(kname, L'\\');
359 colon_pos = StrChr(kname, L':');
361 if (backslash_pos && backslash_pos < slash_pos) slash_pos = backslash_pos;
363 if (colon_pos == NULL || (slash_pos && (slash_pos < colon_pos))) {
364 StrCpy(devname, fops_bootdev_name());
365 StrCat(devname, L":");
367 /* the default path is always terminated with a separator */
368 if (kname[0] != L'/' && kname[0] != L'\\') {
369 fops_getdefault_path(dpath,FILENAME_MAXLEN);
370 StrCat(devname, dpath);
373 devname[0] = CHAR_NULL;
377 * create final argument list to the kernel
379 len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */
380 +StrLen(devname) /* device name */
381 +StrLen(kname) /* kernel name */
383 +StrLen(args); /* args length */
385 if (len >= CMDLINE_MAXLEN-1) {
386 ERR_PRT((L" arguments list too long cannot fit BOOT_IMAGE\n"));
389 StrCpy(cmdline, L"BOOT_IMAGE=");
390 StrCat(cmdline, devname);
391 StrCat(cmdline, kname);
392 StrCat(cmdline, L" ");
393 StrCat(cmdline, args);
399 simple_probe(EFI_HANDLE dev)
401 /* this chooser always work */
405 chooser_t simple_chooser={