| /* Second stage boot loader |
| |
| Coyright (C) 1996 Pete A. Zaitcev |
| 1996 Maurizio Plaza |
| 1996 David S. Miller |
| 1996 Miguel de Icaza |
| 1996,1997,1998,1999 Jakub Jelinek |
| 2001 Ben Collins |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. */ |
| |
| /* TODO: This file is a good candidate for rewrite from scratch. */ |
| |
| #include <silo.h> |
| #include <elf.h> |
| #include <stringops.h> |
| |
| #ifndef NULL |
| #define NULL (void *)0 |
| #endif |
| |
| |
| struct HdrS_struct { |
| char magic[4]; |
| unsigned int linux_ver; |
| unsigned short ver; |
| unsigned short root_flags; |
| unsigned short root_dev; |
| unsigned short ram_flags; |
| unsigned int ramdisk_image; |
| unsigned int ramdisk_size; |
| /* 0x201 */ |
| unsigned int reboot_cmd_ptr_high; |
| unsigned int reboot_cmd_ptr_low; |
| /* 0x202 */ |
| unsigned int bootstr_info_ptr_high; |
| unsigned int bootstr_info_ptr_low; |
| /* 0x301 */ |
| unsigned long long ramdisk_image64; |
| }; |
| |
| /* This has to be first initialized variable in main.c */ |
| |
| extern char silo_conf[256]; |
| extern unsigned char silo_conf_part, silo_conf_parts[32], raid_dsk_number; |
| |
| int useconf = 0; |
| enum { |
| CMD_BOOT, |
| CMD_CAT, |
| CMD_LS |
| } load_cmd; |
| enum arch architecture; |
| int sun4v_cpu; |
| static int timer_status = 0; |
| static char *initrd_start; |
| static int initrd_size; |
| static int initrd_defpart; |
| static char *initrd_defdevice; |
| static char *initrd_string; |
| static int initrd_prompt; |
| static int pause_after; |
| static char *pause_message = "Press ENTER to continue."; |
| static int show_arguments = 0; |
| static char given_bootargs [512]; |
| static char my_bootargs [512]; |
| static int given_bootargs_by_user = 0; |
| static char sol_params [512]; |
| static int fill_reboot_cmd = 0; |
| static char other_device [512]; |
| static int reboot = 0; |
| static int floppyswap = 0; |
| int tab_ambiguous = 0; |
| int other_part = -1; |
| int solaris = 0; |
| int flash = 0; |
| int other = 0; |
| char *password = 0; |
| int initrd_can_do_64bit_phys = 0; |
| |
| static void parse_name (char *, int, char **, int *, char **); |
| |
| static char *next_tok (char *t) { |
| while (*t++); /* That was easy */ |
| return t; |
| } |
| |
| /* Check for possible file and target completions. Return non-zero if |
| * the caller needs to re-output the command line. */ |
| static int tab_complete(void) { |
| int image_len, defpart, part, ret = 0; |
| char *device; |
| char *p = cfg_get_strg (0, "partition"); |
| char *kname, *r; |
| |
| if ((r = strrchr(cbuff, ' ')) == NULL) |
| r = strdup(cbuff); |
| else |
| r = strdup(r + 1); |
| |
| if (p && *p >= '1' && *p <= '8' && !p[1]) |
| defpart = *p - '0'; |
| else { |
| silo_fatal("\nDefault partition could not be found"); |
| free(r); |
| return 1; |
| } |
| |
| parse_name (r, defpart, &device, &part, &kname); |
| if (!kname) { |
| /* Maybe this isn't a disk file. Maybe it's a silo.conf defined |
| * alias/label. */ |
| if (tab_ambiguous) { |
| ret = cfg_print_images (NULL, r); |
| } else { |
| char *addr = (char *)0x4000; |
| int count = cfg_print_images (addr, r); |
| if (*addr) { |
| int len = strlen(r); |
| int len2 = strlen(cbuff); |
| /* We have some completions... */ |
| if (count == 1) { |
| /* Just one, complete it... */ |
| while (addr[len]) { |
| cbuff[len2] = addr[len]; |
| cbuff[len2 + 1] = 0; |
| prom_puts(cbuff + len2, 1); |
| len++; len2++; |
| } |
| cbuff[len2] = ' '; |
| cbuff[len2 + 1] = 0; |
| prom_puts(cbuff + len2, 1); |
| } else if (count > 1) { /* This should always be true, if we get here */ |
| /* Complete the line as much as possible */ |
| int common = 1, orig = len, i; |
| while (common && addr[len]) { |
| char *cur = next_tok(addr); |
| for (i = 1; i < count && common; i++, cur = next_tok(cur)) |
| if (addr[len] != cur[len]) |
| common = 0; |
| |
| if (common) { |
| cbuff[len2] = addr[len]; |
| cbuff[len2 + 1] = 0; |
| prom_puts(cbuff + len2, 1); |
| len++; len2++; |
| } |
| } |
| if (orig == len) |
| tab_ambiguous = 1; |
| } |
| } else |
| tab_ambiguous = 1; |
| } |
| } else { |
| if (!device) device = cfg_get_strg (0, "device"); |
| |
| if (silo_load_file(device, part, kname, (unsigned char *) 0x4000, |
| (unsigned char *) &_start, &image_len, |
| LOADFILE_LS_MATCH|LOADFILE_QUIET, 0)) |
| if (do_ls((unsigned char *)0x4000, &tab_ambiguous)) |
| ret = 1; |
| } |
| |
| free(r); |
| return ret; |
| } |
| |
| static void maintabfunc (void) |
| { |
| if (cbuff[0] == 0) { |
| /* Nothing on the command line, just list the possible images from |
| * the config file. */ |
| if (cfg_print_images (NULL, NULL)) |
| printf ("boot: %s", cbuff); |
| } else { |
| /* If tab_complete() returns non-zero, then it just listed |
| * possible completions, and we need to redo our command line. */ |
| if (tab_complete()) |
| printf ("boot: %s", cbuff); |
| } |
| return; |
| } |
| |
| static void parse_name (char *imagename, int defpart, char **device, |
| int *part, char **kname) |
| { |
| static char parsebuf[1024]; |
| |
| strcpy (parsebuf, imagename); |
| imagename = parsebuf; |
| *device = 0; |
| *kname = 0; |
| if (prom_vers == PROM_V0) { |
| static char v0_buffer[20]; |
| *kname = silo_v0_device(imagename); |
| if (*kname) { |
| memcpy (v0_buffer, imagename, *kname - imagename + 1); |
| v0_buffer [*kname - imagename + 1] = 0; |
| (*kname)++; |
| *device = v0_buffer; |
| } else |
| *kname = imagename; |
| } else { |
| *kname = strchr (imagename, ';'); |
| if (!*kname) |
| *kname = imagename; |
| else { |
| **kname = 0; |
| (*kname)++; |
| *device = imagename; |
| } |
| } |
| /* Range */ |
| if (**kname >= '0' && **kname <= '8' && (*kname)[1] == '[') { |
| *part = **kname - '0'; |
| (*kname)++; |
| return; |
| } |
| if (**kname == '[') { |
| *part = 0; |
| return; |
| } |
| /* Path */ |
| if (**kname >= '1' && **kname <= '8') { |
| if ((*kname)[1] == '/' || !(*kname)[1]) { |
| *part = **kname - '0'; |
| if (!(*kname)[1]) { |
| *kname = 0; |
| } else |
| (*kname)++; |
| } |
| } else if (**kname == '/') { |
| if (defpart != -2) { |
| if (defpart != -1) |
| *part = defpart; |
| else |
| *part = 1; |
| } |
| } else |
| *kname = 0; |
| } |
| |
| static void check_initrd (char *label, int defpart, char *defdevice) |
| { |
| char *p; |
| |
| initrd_string = cfg_get_strg (label, "initrd"); |
| if (initrd_string) { |
| initrd_defpart = defpart; |
| initrd_defdevice = defdevice; |
| initrd_size = 0; |
| p = cfg_get_strg (label, "initrd-size"); |
| if (p) initrd_size = atoi (p); |
| initrd_prompt = cfg_get_flag (label, "initrd-prompt"); |
| } |
| } |
| |
| static int dig_into_params (char *params) |
| { |
| char *p, *q; |
| char *last_root = 0; |
| int root_found = 0; |
| |
| p = params; |
| for (;;) { |
| while (*p == ' ') p++; |
| if (!*p) break; |
| if (!strncmp (p, "initrd", 6)) { |
| root_found = 1; |
| p += 6; |
| if (*p == '=') { |
| for (q = p++; *q && *q != ' '; q++); |
| if (p != q) { |
| initrd_string = malloc (q - p + 1); |
| memcpy (initrd_string, p, q - p); |
| initrd_string [q - p] = 0; |
| memset (p - 7, ' ', q - p + 7); |
| } |
| } else if (!strncmp (p, "-prompt", 7)) { |
| initrd_prompt = 1; |
| memset (p - 6, ' ', 7 + 6); |
| } else if (!strncmp (p, "-size=", 6)) { |
| int i; |
| p += 6; |
| i = atoi (p); |
| if (i > 0) { |
| initrd_size = i; |
| for (q = p; *q >= '0' && *q <= '9'; q++); |
| memset (p - 12, ' ', q - p + 12); |
| } |
| } |
| } else if (!strncmp (p, "pause-after", 11)) { |
| pause_after = 1; |
| memset (p, ' ', 11); |
| } else if (!strncmp (p, "show-arguments", 14)) { |
| show_arguments = 1; |
| memset (p, ' ', 14); |
| } else if (!strncmp (p, "root=", 5)) { |
| root_found = 1; |
| if (last_root) { |
| while (*last_root != ' ') *last_root++ = ' '; |
| } |
| last_root = p; |
| } else if (!strncmp (p, "nfsroot=", 8)) { |
| root_found = 1; |
| } |
| while (*p && *p != ' ') p++; |
| } |
| return root_found; |
| } |
| |
| static void check_password(char *str) |
| { |
| int i; |
| |
| for (i = 0; i < 3; i++) { |
| printf ("\n%sassword: ", str); |
| passwdbuff[0] = 0; |
| silo_cmdedit((void (*)(void)) 0, 1); |
| printf ("\n"); |
| if (!strcmp (password, passwdbuff)) |
| return; |
| if (i < 2) |
| printf ("Wrong password. Please try again..."); |
| } |
| printf ("Seems like you don't know the access password...\n"); |
| prom_halt(); |
| } |
| |
| static char *ls_options(char *parms) |
| { |
| char *p = parms; |
| ls_opt = 0; |
| if (*parms == '-') { |
| for (p = parms + 1;*p && *p != ' ';p++) { |
| switch (*p) { |
| case 'l': ls_opt |= LSOPT_L; break; |
| case 't': ls_opt |= LSOPT_T; break; |
| case 'r': ls_opt |= LSOPT_R; break; |
| default: |
| printf ("Unhandled options to ls: `%s' - only l, t and r supported\n", parms); |
| break; |
| } |
| } |
| while (*p == ' ') p++; |
| } |
| return p; |
| } |
| |
| static int get_params (char **device, int *part, char **kname, char **proll, |
| char **params) |
| { |
| int defpart = -1; |
| char *defdevice = 0; |
| char *p, *q; |
| int c; |
| char *imagename = 0, *label = 0; |
| int timeout = -1, beg = 0, end; |
| static char buffer[2048], buffer2[2048]; |
| static char prollb[256]; /* Hmm */ |
| static int first = 1; |
| int from_prom = 0; |
| int from_siloconf = 0; |
| static int no_prom_args = 0; |
| int tabbedout = 0; |
| |
| #ifndef TFTP |
| if (raid_dsk_number) { |
| defpart = silo_conf_parts[raid_dsk_number - 1]; |
| if (defpart < 1 || defpart > 8) |
| defpart = -1; |
| } |
| #endif |
| load_cmd = CMD_BOOT; |
| other = 0; |
| fill_reboot_cmd = 0; |
| solaris = 0; |
| initrd_string = 0; |
| pause_after = 0; |
| reboot = 0; |
| *proll = 0; |
| silo_cmdinit(); |
| *params = ""; |
| if (useconf) { |
| defdevice = cfg_get_strg (0, "device"); |
| if (defpart == -1) { |
| /* For RAID1 avoid using this at all, it makes no sense |
| anyway */ |
| p = cfg_get_strg (0, "partition"); |
| if (p && *p >= '1' && *p <= '8' && !p[1]) |
| defpart = *p - '0'; |
| } |
| if (first) { |
| first = 0; |
| p = cfg_get_strg (0, "timeout"); |
| if (p && *p) |
| timeout = atoi (p); |
| if (no_prom_args) p = 0; |
| else p = silo_get_bootargs(0); |
| if (p) while (*p == ' ') p++; |
| if (p && *p) { |
| for (q = p; *q && *q != ' '; q++); |
| if (*q == ' ') { |
| *q++ = 0; |
| while (*q == ' ') q++; |
| if (*q) *params = q; |
| } |
| imagename = p; |
| from_prom = 1; |
| printf ("\n"); |
| } else if (!timeout) { |
| printf ("boot: "); |
| c = prom_nbgetchar (); |
| if (c != -1 && c != '\n' && c != '\r') { |
| if (c == '\t') { |
| maintabfunc (); |
| tabbedout = 1; |
| } else if (c >= ' ') { |
| tab_ambiguous = 0; |
| cbuff[0] = c; |
| cbuff[1] = 0; |
| } |
| } else { |
| imagename = cfg_get_default (); |
| printf ("\n"); |
| } |
| } else if (timeout != -1) { |
| if (!timer_status) { |
| if (!init_timer ()) timer_status = 1; |
| else timer_status = -1; |
| } else |
| timer_status++; |
| if (timer_status <= 0) { |
| printf ("\nYour timeout %d.%ds will never expire, since counter couldn't" |
| "\nbe initialized\nboot: ", timeout/10, timeout % 10); |
| } else { |
| printf ("boot: "); |
| reset_ticks (); |
| c = prom_nbgetchar (); |
| if (c == -1) { |
| beg = get_ticks (); |
| end = beg + 10 * timeout; |
| do { |
| c = prom_nbgetchar (); |
| if (c != -1) |
| break; |
| } while (get_ticks () <= end); |
| } |
| if (c != -1 && c != '\n' && c != '\r') { |
| if (c == '\t') { |
| maintabfunc (); |
| tabbedout = 1; |
| } else if (c >= ' ') { |
| tab_ambiguous = 0; |
| cbuff[0] = c; |
| cbuff[1] = 0; |
| if (cfg_get_flag (cbuff, "single-key")) |
| imagename = cbuff; |
| } |
| } else { |
| imagename = cfg_get_default (); |
| printf ("\n"); |
| } |
| if (timer_status >= 1) { |
| timer_status--; |
| close_timer (); |
| } |
| } |
| } |
| } |
| if (!imagename) { |
| if ((!*cbuff || (timeout > 0 && timer_status < 0)) && !tabbedout) |
| printf ("boot: "); |
| silo_cmdedit(maintabfunc, 0); |
| if (*cbuff == ' ') { |
| for (p = cbuff; *p == ' '; p++); |
| q = cbuff; |
| while ((*q++ = *p++) != 0); |
| } |
| strcpy (given_bootargs, cbuff); |
| given_bootargs_by_user = 1; |
| printf ("\n"); |
| if (!*cbuff) |
| imagename = cfg_get_default (); |
| else { |
| p = strchr (cbuff, ' '); |
| if (!p) |
| *params = ""; |
| else { |
| *p++ = 0; |
| while (*p && *p <= ' ') |
| p++; |
| *params = p; |
| } |
| imagename = cbuff; |
| } |
| } |
| p = cfg_get_strg (imagename, "image"); |
| if (p && *p) { |
| label = imagename; |
| imagename = p; |
| } else |
| label = 0; |
| p = cfg_get_strg (0, "pause-message"); |
| if (p) pause_message = p; |
| if (label) { |
| if (**params && password) |
| check_password ("To specify image arguments you need to enter your p"); |
| from_siloconf = 1; |
| defdevice = cfg_get_strg (label, "device"); |
| #ifndef TFTP |
| if (!raid_dsk_number) |
| #endif |
| { |
| p = cfg_get_strg (label, "partition"); |
| if (p && *p >= '1' && *p <= '8' && !p[1]) |
| defpart = *p - '0'; |
| } |
| *buffer = 0; |
| q = buffer; |
| if (cfg_get_flag (label, "fill-reboot-cmd")) |
| fill_reboot_cmd = 1; |
| if (cfg_get_strg (label, "other")) |
| other = 1; |
| else if (cfg_get_flag (label, "solaris")) |
| solaris = 1; |
| else if (cfg_get_flag (label, "flash")) |
| flash = 1; |
| p = cfg_get_strg (label, "literal"); |
| if (!p && other) |
| p = cfg_get_strg (label, "append"); |
| if (p) { |
| strcpy (q, p); |
| q = strchr (q, 0); |
| if (**params) { |
| if (*p) |
| *q++ = ' '; |
| strcpy (q, *params); |
| } |
| } else if (!solaris && !other) { |
| p = cfg_get_strg (label, "root"); |
| if (p) { |
| strcpy (q, "root="); |
| strcpy (q + 5, p); |
| q = strchr (q, 0); |
| *q++ = ' '; |
| } |
| if (cfg_get_flag (label, "read-only")) { |
| strcpy (q, "ro "); |
| q += 3; |
| } |
| if (cfg_get_flag (label, "read-write")) { |
| strcpy (q, "rw "); |
| q += 3; |
| } |
| p = cfg_get_strg (label, "ramdisk"); |
| if (p) { |
| strcpy (q, "ramdisk="); |
| strcpy (q + 8, p); |
| q = strchr (q, 0); |
| *q++ = ' '; |
| } |
| p = cfg_get_strg (label, "append"); |
| if (p) { |
| strcpy (q, p); |
| q = strchr (q, 0); |
| *q++ = ' '; |
| } |
| check_initrd (label, defpart, defdevice); |
| if (**params) |
| strcpy (q, *params); |
| p = cfg_get_strg (label, "proll"); |
| if (p && strlen (p) < sizeof(prollb)-1) { |
| strcpy (prollb, p); |
| *proll = prollb; |
| } |
| } |
| if (other) { |
| char *oth_device = 0; |
| char *oth_kname = 0; |
| |
| other_part = -1; |
| parse_name (imagename, -1, &oth_device, &other_part, &oth_kname); |
| if (other_part == -1 || oth_kname) { |
| printf ("Wrong syntax for other= parameter. The parameter should be\n"); |
| if (prom_vers == PROM_V0) |
| printf ("either a single number 1-8 (ie. partition of the current disk)\n" |
| "or sd(X,Y,Z)N (ie. some other disk plus partition number)\n" |
| "e.g. sd(0,3,2)4\n"); |
| else |
| printf ("either a single number 1-8 (ie. partition of the current disk)\n" |
| "or /prom/path/name;N (ie. some other disk plus partition number)\n" |
| "e.g. /iommu/sbus/espdma/esp/sd@3,0;3 \n"); |
| *kname = 0; |
| return 0; |
| } |
| if (!oth_device) { |
| if (defdevice) |
| oth_device = defdevice; |
| else |
| oth_device = silo_disk_get_bootdevice(); |
| } |
| strcpy (other_device, oth_device); |
| p = cfg_get_strg (label, "bootblock"); |
| if (p) |
| imagename = p; |
| else { |
| static char bufx[8]; |
| |
| if (architecture == sun4u) |
| reboot = 1; |
| strcpy (bufx, "x[1-16]"); |
| *bufx = other_part + '0'; |
| defdevice = other_device; |
| defpart = other_part; |
| } |
| } |
| pause_after = cfg_get_flag (label, "pause-after"); |
| p = cfg_get_strg (label, "pause-message"); |
| if (p) pause_message = p; |
| *params = buffer; |
| } |
| } else { |
| if (first) { |
| first = 0; |
| if (no_prom_args) p = 0; |
| else p = silo_get_bootargs(0); |
| if (p) while (*p == ' ') p++; |
| if (p && *p) { |
| for (q = p; *q && *q != ' '; q++); |
| if (*q == ' ') { |
| *q++ = 0; |
| while (*q == ' ') q++; |
| if (*q) *params = q; |
| } |
| imagename = p; |
| from_prom = 1; |
| printf ("\n"); |
| } |
| } |
| if (!imagename) { |
| printf ("boot: "); |
| silo_cmdedit((void (*)(void)) 0, 0); |
| if (*cbuff == ' ') { |
| for (p = cbuff; *p == ' '; p++); |
| q = cbuff; |
| while ((*q++ = *p++) != 0); |
| } |
| strcpy (given_bootargs, cbuff); |
| given_bootargs_by_user = 1; |
| printf ("\n"); |
| p = strchr (cbuff, ' '); |
| if (!p) |
| *params = ""; |
| else { |
| *p = 0; |
| p++; |
| while (*p && *p <= ' ') |
| p++; |
| *params = p; |
| } |
| imagename = cbuff; |
| } |
| } |
| if (!strcmp (imagename, "halt")) |
| return 1; |
| if (!label && password) |
| check_password ("To boot a custom image you need to enter your p"); |
| if (!strcmp (imagename, "xxdebug")) |
| return 2; |
| if (!strcmp (imagename, "help")) { |
| if (prom_vers == PROM_V0) |
| printf ("You have to type image name as {XY(...)}partno/path or {XY(...)}partno[mm-nn],\n" |
| "where XY(...) is the optional v0 prom device name (if partition number is specified,\n" |
| "it should be Sun partition number (zero based) of any partition starting at cyl. 0)\n" |
| "({} means that it is optional) and partno is a Linux partition number from 1 to 8.\n" |
| "You can specify a path into filesystem (ext2fs, ufs) - has to start with / - or\n" |
| "[mm-nn] as range of phys. blocks (512B).\n"); |
| else |
| printf ("You have to type image name as [prom_path;]partno/path, where partno is a\n" |
| "number from 1 to 8. If partno is not specified, either default from silo.conf\n" |
| "(partition=X) or 1 will be used. Instead of /path you can type [mm-nn] to\n" |
| "specify a range of phys. blocks (512B)\n"); |
| printf ("If you use silo.conf and have some image= sections there, you can type\n" |
| "its label or alias name instead of the above described image names.\n" |
| "Pressing just enter will load default image with default arguments. Special\n" |
| "image names `halt' and `help' can be used to fall back to PROM or display\n" |
| "help. All three types of image names can be followed by additional arguments.\n" |
| "Examples:\n"); |
| if (prom_vers == PROM_V0) |
| printf (" /boot/vmlinux.gz root=/dev/sda4\n" |
| " 2/boot/mykernel.gz root=/dev/sda2\n" |
| " sd(0,6,2)5/boot/old.b\n" |
| " sd(1,2,0)[1-16] root=/dev/sda4\n"); |
| else |
| printf (" /iommu/sbus/espdma/esp/sd@3,0;4/boot/vmlinux.gz root=/dev/sda4\n" |
| " 1/boot/old.b\n" |
| " /sbus/espdma/esp/sd@0,0;3[1-16] root=/dev/sda4\n"); |
| printf (" linux root=/dev/sda4\n" |
| " live\n"); |
| *kname = 0; |
| return 0; |
| } |
| strcpy (buffer2, imagename); |
| *part = -2; |
| if (!label && (!strcmp (imagename, "cat") || !strcmp (imagename, "ls"))) { |
| if (*imagename == 'c') |
| load_cmd = CMD_CAT; |
| else { |
| load_cmd = CMD_LS; |
| *params = ls_options (*params); |
| } |
| imagename = *params; |
| p = strchr (imagename, ' '); |
| if (!p) |
| *params = ""; |
| else { |
| *p++ = 0; |
| while (*p && *p <= ' ') |
| p++; |
| *params = p; |
| } |
| } else if (label && (!strncmp (imagename, "cat ", 4) || !strncmp (imagename, "ls ", 3))) { |
| if (*imagename == 'c') { |
| load_cmd = CMD_CAT; |
| imagename += 4; |
| while (*imagename == ' ') imagename++; |
| } else { |
| load_cmd = CMD_LS; |
| imagename += 3; |
| while (*imagename == ' ') imagename++; |
| imagename = ls_options (imagename); |
| } |
| } |
| parse_name (imagename, -2, device, part, kname); |
| if (!*device) |
| *device = defdevice; |
| if (*kname && *part == -2) { |
| if (defpart != -1) |
| *part = defpart; |
| else |
| *part = 1; |
| } |
| if (!*kname) { |
| if (*part != -2) { |
| other_part = *part; |
| if (!*device) |
| strcpy (other_device, silo_disk_get_bootdevice()); |
| else |
| strcpy (other_device, *device); |
| p = strstr (*params, "bootblock="); |
| if (p && (p == *params || p[-1] == ' ') && p[10] && p[10] != ' ') { |
| char tmp[512], *q; |
| |
| q = tmp; |
| p += 10; |
| while (*p && *p != ' ') |
| *q++ = *p++; |
| *q = 0; |
| parse_name (tmp, defpart, device, part, kname); |
| if (*kname) { |
| p = strstr (*params, "bootblock="); |
| memset (p, ' ', q - tmp + 10); |
| other = 1; |
| return 0; |
| } else { |
| printf ("Syntax of your bootblock= parameter is wrong. Please see help\n"); |
| } |
| } else { |
| other = 1; |
| *kname = strdup ("[1-16]"); |
| if (architecture == sun4u) |
| reboot = 1; |
| return 0; |
| } |
| } else { |
| if (defpart != -1) |
| *part = defpart; |
| else |
| *part = 1; |
| } |
| if (from_prom) { |
| int options_node, len; |
| int is_from_prom = 0; |
| char *v = ""; |
| char buffer3[2048]; |
| |
| if ((options_node = prom_searchsiblings (prom_getchild (prom_root_node), "options")) != 0) { |
| if (prom_vers != PROM_V0) { |
| prom_getstring (options_node, v = "boot-file", buffer3, 2048); |
| len = prom_getproplen (options_node, v); |
| if (len < 0) len = 0; |
| buffer3[len] = 0; |
| if (!strcmp (buffer3, my_bootargs)) |
| is_from_prom = 1; |
| else { |
| prom_getstring (options_node, v = "diag-file", buffer3, 2048); |
| len = prom_getproplen (options_node, v); |
| if (len < 0) len = 0; |
| buffer3[len] = 0; |
| if (!strcmp (buffer3, my_bootargs)) |
| is_from_prom = 1; |
| } |
| } else { |
| prom_getstring (options_node, v = "boot-from", buffer3, 2048); |
| len = prom_getproplen (options_node, v); |
| if (len < 0) len = 0; |
| buffer3[len] = 0; |
| if (!strcmp (buffer3, my_bootargs)) |
| is_from_prom = 1; |
| } |
| } |
| if (is_from_prom) { |
| first = 1; |
| no_prom_args = 1; |
| *given_bootargs = 0; |
| given_bootargs_by_user = 1; |
| printf ("You have `%s' string in your %s variable.\n" |
| "This string doesn't contain valid arguments to SILO.\n" |
| "Consider doing setenv %s. Anyway, SILO will continue as\n" |
| "if there were no arguments in %s.\n", buffer3, v, v, v); |
| return 0; |
| } |
| } |
| printf ("Your imagename `%s' and arguments `%s' have either wrong syntax,\n" |
| "or describe a label which is not present in silo.conf\n" |
| "Type `help' at the boot: prompt if you need it and then try again.\n", buffer2, *params ? *params : ""); |
| } else if (!solaris) { |
| p = strstr (*params, "solaris"); |
| if (p && (p == *params || p[-1] == ' ') && (!p[7] || p[7] == ' ')) { |
| memset (p, ' ', 7); |
| solaris = 1; |
| } else if (!strcmp (*kname, "/kernel/unix")) |
| solaris = 1; |
| if (!fill_reboot_cmd) { |
| p = strstr (*params, "fill-reboot-cmd"); |
| if (p && (p == *params || p[-1] == ' ') && (!p[15] || p[15] == ' ')) { |
| memset (p, ' ', 15); |
| fill_reboot_cmd = 1; |
| } |
| } |
| } |
| if (!flash) { |
| p = strstr (*params, "flash"); |
| if (p) |
| flash = 1; |
| } |
| return 0; |
| } |
| |
| static void initrd_lenfunc (int len, char **filebuffer, char **filelimit) |
| { |
| extern unsigned long long initrd_phys; |
| |
| initrd_start = memory_find ((len + 16383) & ~16383); |
| if (!initrd_start) { |
| silo_fatal("You do not have enough continuous available memory " |
| "for such initial ramdisk."); |
| prom_halt (); |
| } |
| initrd_size = len; |
| *filebuffer = initrd_start; |
| *filelimit = initrd_start + ((len + 16383) & ~16383); |
| printf("Loading initial ramdisk (%d bytes at 0x%Lx phys, 0x%x virt)...\n", len, |
| initrd_phys, initrd_start); |
| } |
| |
| static int parse_executable (unsigned char *base, int image_len, unsigned int *poff, |
| int *plen, unsigned *pstart, char *image_name) |
| { |
| int isfile = 0; |
| union { |
| char *b; |
| struct aout_hdr *a; |
| Elf32_Ehdr *e; |
| Elf64_Ehdr *f; |
| } hp; |
| unsigned off = 0; |
| int len = 0; |
| unsigned st = (unsigned int) base; |
| |
| /* By this point the first sector is loaded (and the rest of */ |
| /* the kernel) so we check if it is an executable file, either */ |
| /* an a.out or an elf binary */ |
| |
| hp.b = (char *)base; |
| if (hp.a->magic == 0x01030107) { |
| if (solaris) { |
| printf ("\nYour Solaris `ufsboot' is not an ELF image. Try again.\n"); |
| return -1; |
| } |
| off = sizeof (struct aout_hdr); |
| if (image_len > hp.a->ltext + hp.a->ldata) |
| len = hp.a->ltext + hp.a->ldata; |
| else |
| len = image_len; |
| isfile = 1; |
| } else if (hp.e->e_ident[EI_MAG0] == ELFMAG0 && |
| hp.e->e_ident[EI_MAG1] == ELFMAG1 && |
| hp.e->e_ident[EI_MAG2] == ELFMAG2 && |
| hp.e->e_ident[EI_MAG3] == ELFMAG3) { |
| |
| if (hp.e->e_ident[EI_DATA] != ELFDATA2MSB) { |
| silo_fatal("Image is not a MSB ELF"); |
| prom_halt (); |
| } |
| if (hp.e->e_ident[EI_CLASS] == ELFCLASS32) { |
| Elf32_Phdr *p; |
| |
| p = (Elf32_Phdr *) (hp.b + hp.e->e_phoff); |
| if (p->p_type != PT_LOAD) { |
| silo_fatal("Cannot find a loadable segment in your " |
| "ELF image"); |
| prom_halt (); |
| } |
| if (flash) { |
| int i; |
| |
| if (architecture != sun4u) { |
| silo_fatal("Flash boots only supported on sun4u " |
| "and later"); |
| prom_halt (); |
| } |
| for (i = 0; i < hp.e->e_phnum; i++, p++) { |
| printf("SILO: Loading flash segment %d at vaddr[0x%x] len[0x%x]\n", |
| i, p->p_vaddr, p->p_filesz); |
| memcpy ((char *)p->p_vaddr, |
| (base + p->p_offset), p->p_filesz); |
| if (p->p_filesz < p->p_memsz) |
| memset ((char *)(p->p_vaddr + p->p_filesz), 0, |
| p->p_memsz - p->p_filesz); |
| } |
| isfile = 1; |
| st = hp.e->e_entry; |
| printf("SILO: Flash image entry is at vaddr[0x%x]\n", st); |
| } else if (solaris) { |
| int i; |
| unsigned long sa = (unsigned long)&_start; |
| |
| for (i = 0; i < hp.e->e_phnum; i++, p++) { |
| if (p->p_vaddr < 0x4000 + image_len || |
| p->p_vaddr + p->p_memsz >= sa) { |
| silo_fatal("Unable to handle your " |
| "Solaris `ufsboot' bootloader."); |
| prom_halt (); |
| } |
| memcpy ((char *)p->p_vaddr, |
| (char *)(0x4000 + p->p_offset), p->p_filesz); |
| if (p->p_filesz < p->p_memsz) |
| memset ((char *)(p->p_vaddr + p->p_filesz), 0, |
| p->p_memsz - p->p_filesz); |
| } |
| isfile = 1; |
| st = hp.e->e_entry; |
| } else { |
| int i; |
| unsigned long n; |
| |
| Elf32_Phdr *q = p + 1; |
| |
| for (i = 1; i < hp.e->e_phnum; i++, q++) { |
| if (q->p_type != PT_LOAD) |
| break; |
| n = q->p_offset - p->p_offset; |
| if (q->p_vaddr - p->p_vaddr == n && |
| q->p_paddr - p->p_paddr == n && |
| p->p_memsz == p->p_filesz && |
| p->p_memsz <= n) { |
| p->p_filesz = n + q->p_filesz; |
| p->p_memsz = n + q->p_memsz; |
| } else { |
| silo_fatal("Multiple loadable segments in " |
| "your ELF image"); |
| prom_halt(); |
| } |
| } |
| off = p->p_offset + hp.e->e_entry - p->p_vaddr; |
| len = p->p_filesz; |
| if (len > image_len) len = image_len; |
| isfile = 1; |
| } |
| } else if (hp.e->e_ident[EI_CLASS] == ELFCLASS64) { |
| Elf64_Phdr *p; |
| unsigned long long n; |
| int i; |
| Elf64_Phdr *q; |
| |
| p = (Elf64_Phdr *) (hp.b + hp.f->e_phoff); |
| if (p->p_type != PT_LOAD) { |
| silo_fatal("Cannot find a loadable segment in your " |
| "ELF image"); |
| prom_halt (); |
| } |
| if (flash) { |
| int i; |
| |
| if (architecture != sun4u) { |
| silo_fatal("Flash boots only supported on sun4u " |
| "and later"); |
| prom_halt (); |
| } |
| for (i = 0; i < hp.f->e_phnum; i++, p++) { |
| printf("SILO: Loading flash segment %d at vaddr[0x%x] len[0x%x]\n", |
| i, (unsigned int) p->p_vaddr, (unsigned int) p->p_filesz); |
| memcpy ((Elf64_Addr *)(long)(p->p_vaddr), |
| (Elf64_Addr *)(long)(base + p->p_offset), |
| p->p_filesz); |
| if (p->p_filesz < p->p_memsz) |
| memset ((Elf64_Addr *)(long)(p->p_vaddr + p->p_filesz), |
| 0, p->p_memsz - p->p_filesz); |
| } |
| isfile = 1; |
| st = hp.f->e_entry; |
| printf("SILO: Flash image entry is at vaddr[0x%x]\n", st); |
| } else if (solaris) { |
| int i; |
| unsigned long sa = (unsigned long)&_start; |
| |
| for (i = 0; i < hp.f->e_phnum; i++, p++) { |
| if (p->p_vaddr < 0x4000 + image_len || |
| p->p_vaddr + p->p_memsz >= sa) { |
| |
| silo_fatal("Unable to handle your " |
| "Solaris `ufsboot' bootloader."); |
| prom_halt (); |
| } |
| memcpy ((Elf64_Addr *)(long)(p->p_vaddr), |
| (Elf64_Addr *)(long)(0x4000 + p->p_offset), |
| p->p_filesz); |
| if (p->p_filesz < p->p_memsz) |
| memset ((Elf64_Addr *)(long)(p->p_vaddr + p->p_filesz), |
| 0, p->p_memsz - p->p_filesz); |
| } |
| isfile = 1; |
| st = hp.f->e_entry; |
| } else { |
| q = p + 1; |
| for (i = 1; i < hp.f->e_phnum; i++, q++) { |
| if (q->p_type != PT_LOAD) |
| break; |
| n = q->p_offset - p->p_offset; |
| if (q->p_vaddr - p->p_vaddr == n && |
| q->p_paddr - p->p_paddr == n && |
| p->p_memsz == p->p_filesz && |
| p->p_memsz <= n) { |
| |
| p->p_filesz = n + q->p_filesz; |
| p->p_memsz = n + q->p_memsz; |
| } else { |
| silo_fatal("Multiple loadable segments " |
| "in your ELF image"); |
| prom_halt(); |
| } |
| } |
| } |
| off = p->p_offset + hp.f->e_entry - p->p_vaddr; |
| len = p->p_filesz; |
| if (len > image_len) len = image_len; |
| isfile = 1; |
| } |
| } |
| |
| if (isfile) { |
| if (pstart != NULL) |
| *pstart = st; |
| *poff = off; |
| *plen = len; |
| } else { |
| printf ("\nUnknown image %s format\n", image_name); |
| } |
| return isfile; |
| } |
| |
| /* Here we are launched */ |
| int bootmain (void) |
| { |
| unsigned off = 0; |
| int len = 0, image_len; |
| char *kname, *params, *device; |
| char *proll = 0; |
| unsigned char *image_base = (unsigned char *) 0x4000; |
| char *kernel_params; |
| int part; |
| int isfile, fileok = 0; |
| unsigned int ret_offset = 0; |
| char *params_device = 0; |
| int silo_conf_partition; |
| |
| prom_ranges_init (); |
| get_idprom(); |
| architecture = silo_get_architecture(); |
| strcpy (given_bootargs, silo_get_bootargs(1)); |
| strcpy (my_bootargs, silo_get_bootargs(0)); |
| |
| #ifndef TFTP |
| if (silo_diskinit() == -1) |
| prom_halt (); |
| #endif |
| |
| if (architecture == sun4u) { |
| char buffer[512], *p; |
| int node = prom_finddevice("/chosen"); |
| if (node) { |
| prom_getstring(node, "bootpath", buffer, 512); |
| if (strstr(buffer, "fdthree")) { |
| p = strchr (buffer, ':'); |
| if (p) *p = 0; |
| node = prom_finddevice(buffer); |
| if (node) { |
| if (prom_getintdefault (node, "unit", 0) == 1) |
| floppyswap = 1; |
| } |
| } |
| } |
| } |
| |
| /* Here should be code #ifdef TFTP, that will handle loading of silo.conf via tftp and this code should be on the other side #ifndef TFTP */ |
| silo_conf_partition = silo_conf_part; |
| #ifndef TFTP |
| if (raid_dsk_number) |
| silo_conf_partition = silo_conf_parts[raid_dsk_number - 1]; |
| #endif |
| if (*silo_conf && silo_conf_partition >= 1 && silo_conf_partition <= 8) { |
| int len; |
| solaris = 0; |
| fileok = silo_load_file(0, silo_conf_partition, silo_conf, |
| (unsigned char *) 0x4000, |
| (unsigned char *) &_start, |
| &len, LOADFILE_GZIP | LOADFILE_NO_ROTATE, 0); |
| if (!fileok || (unsigned) len >= 65535) |
| printf ("\nCouldn't load %s\n", silo_conf); |
| else { |
| if (!cfg_parse (silo_conf, (char *) 0x4000, len)) { |
| char *p, *q; |
| int len = 0; |
| int defpart = -1; |
| #ifndef TFTP |
| if (raid_dsk_number) |
| defpart = silo_conf_partition; |
| #endif |
| p = cfg_get_strg (0, "message"); |
| if (p) { |
| q = cfg_get_strg (0, "partition"); |
| if (q && *q >= '1' && *q <= '8' && !q[1]) |
| defpart = *q - '0'; |
| parse_name (p, defpart, &device, &part, &kname); |
| if (kname) { |
| if (!device) |
| device = cfg_get_strg (0, "device"); |
| solaris = 0; |
| if (silo_load_file(device, part, kname, |
| (unsigned char *) 0x4000, |
| (unsigned char *) &_start, &len, |
| LOADFILE_GZIP, 0)) { |
| *(unsigned char *) (0x4000 + len) = 0; |
| printf ("\n"); |
| print_message ((char *) 0x4000); |
| } |
| } |
| } |
| useconf = 1; |
| password = cfg_get_strg (0, "password"); |
| if (password && !cfg_get_flag (0, "restricted")) { |
| check_password ("P"); |
| password = 0; |
| } |
| } else { |
| printf ("Syntax error in %s\n" |
| "Please check the file for obvious bugs, and if you think it is correct, get\n" |
| "latest version of SILO. If problems still survive, contact the author\n", silo_conf); |
| } |
| } |
| } else |
| printf ("\n"); |
| if (!useconf) |
| printf ("No config file loaded, you can boot just from this command line\n" |
| "Type [prompath;]part/path_to_image [parameters] on the prompt\n" |
| "E.g. /iommu/sbus/espdma/esp/sd@3,0;4/vmlinux root=/dev/sda4\n" |
| "or 2/vmlinux.live (to load vmlinux.live from 2nd partition of boot disk)\n"); |
| try_again: |
| isfile = 0; /* RC = 0 invalid file or not an executable */ |
| while (!isfile) { |
| switch (get_params (&device, &part, &kname, &proll, ¶ms)) { |
| case 1: |
| prom_halt (); |
| case 2: |
| prom_cmdline (); |
| continue; |
| } |
| if (!kname) |
| continue; |
| |
| if (other && reboot) |
| break; |
| |
| if (solaris) { |
| char *p = seed_part_into_device ((!device || !*device) ? silo_disk_get_bootdevice() : device, part); |
| strcpy (sol_params, p); |
| params_device = strchr (sol_params, 0) + 1; |
| strcpy (params_device, kname); |
| if (params && *params) { |
| strcat (params_device, " "); |
| strcat (params_device, params); |
| } |
| } |
| |
| if (load_cmd == CMD_BOOT && proll != 0) { |
| if (other || solaris) { |
| printf ("\nNeither \"other\" nor \"solaris\" are compatible with proll\n"); |
| continue; |
| } |
| if (!silo_load_file(device, part, proll, (unsigned char *) 0x4000, |
| (unsigned char *) 0x40000, &image_len, |
| LOADFILE_GZIP, 0)) { |
| printf ("\nProll not found.... try again\n"); |
| continue; |
| } |
| if (!parse_executable ((unsigned char *)0x4000, image_len, &off, |
| &len, NULL, proll)) |
| continue; |
| memcpy ((char *) 0x4000, ((char *) 0x4000) + off, len); |
| |
| image_base = (unsigned char *) 0x40000; |
| if (!silo_load_file(device, part, kname, image_base, |
| (unsigned char *) &_start, &image_len, |
| LOADFILE_GZIP, 0)) { |
| printf ("\nImage not found.... try again\n"); |
| continue; |
| } |
| if (!(isfile = parse_executable (image_base, image_len, |
| &off, &len, NULL, kname))) |
| continue; |
| ret_offset = 0x4000; |
| |
| } else { |
| unsigned char *image_end = (unsigned char *)&_start; |
| |
| /* See if we can use some extra memory for the kernel */ |
| if (!load_cmd) { |
| unsigned int size; |
| unsigned char *mem; |
| |
| /* As of 2.6.25-rc6, an "allyesconfig" kernel is around |
| * ~42MB in size. So we try to carve out up to 64MB of |
| * memory for the kernel. |
| */ |
| for (size = 64 * 1024 * 1024; |
| size >= 4 * 1024 * 1024; |
| size -= 4 * 1024 * 1024) { |
| mem = (unsigned char *)image_memory_find(size); |
| if (mem) |
| break; |
| } |
| |
| if (mem) { |
| image_base = mem; |
| image_end = image_base + size - 0x4000; |
| printf("Allocated %d Megs of memory at 0x%x for kernel\n", |
| size >> 20, image_base - 0x4000); |
| } |
| } |
| |
| if (!silo_load_file(device, part, kname, image_base, image_end, |
| &image_len, ((load_cmd == CMD_LS) ? |
| LOADFILE_LS : |
| LOADFILE_GZIP), 0)) { |
| printf ("\nImage not found.... try again\n"); |
| |
| if (!load_cmd) |
| image_memory_release(); |
| |
| continue; |
| } |
| |
| if (load_cmd == CMD_CAT) { |
| *(image_base + image_len) = 0; |
| printf ("%s", image_base); |
| continue; |
| } |
| |
| if (load_cmd == CMD_LS) { |
| do_ls (image_base, NULL); |
| continue; |
| } |
| |
| isfile = parse_executable (image_base, image_len, &off, &len, |
| &ret_offset, kname); |
| } |
| } |
| |
| kernel_params = 0; |
| if (solaris) { |
| params = params_device; |
| params_device = sol_params; |
| } else if (!other && !flash) { |
| struct HdrS_struct *hdrs; |
| |
| params_device = 0; |
| |
| memcpy (image_base, image_base + off, len); |
| |
| hdrs = (struct HdrS_struct *) |
| silo_find_linux_HdrS((char *)image_base, image_len); |
| |
| if (hdrs && hdrs->ver < 0x300 && image_base != (unsigned char *)0x4000) { |
| /* Kernel doesn't support being loaded to other than |
| * phys_base, so let's try to copy it down there. */ |
| if ((unsigned int)&_start - 0x4000 < len) { |
| /* Fuck, can't do that */ |
| printf("Your kernel cannot fit into the memory destination. This\n" |
| "can be resolved by recompiling the kernel with more devices\n" |
| "built as modules, or upgrading your kernel to one that\n" |
| "supports being loaded to higher memory areas (currently\n" |
| "2.6.3+ or 2.4.26+).\n"); |
| goto try_again; |
| } |
| |
| printf("Kernel doesn't support loading to high memory, relocating..."); |
| |
| /* Ok, it fits, so copy it down there */ |
| memcpy ((char *)0x4000, image_base, len); |
| image_base = (unsigned char *)0x4000; |
| |
| /* Readjust some things */ |
| ret_offset = 0x4000; |
| hdrs = (struct HdrS_struct *) |
| silo_find_linux_HdrS((char *)image_base, image_len); |
| |
| printf("done.\n"); |
| } |
| |
| if (hdrs) { |
| unsigned int linux_ver = hdrs->linux_ver; |
| |
| printf("Loaded kernel version %d.%d.%d\n", (linux_ver >> 16) & 0xff, |
| (linux_ver >> 8) & 0xff, linux_ver & 0xff); |
| |
| if (fill_reboot_cmd && hdrs->ver >= 0x201) { /* ie. uses reboot_command */ |
| char *q = (char *)hdrs->reboot_cmd_ptr_high; |
| char *r; |
| |
| /* On Ultra there is xword there, this hack makes |
| * it work... |
| */ |
| if (q == (char *)0xfffff800 || !q) |
| q = (char *)hdrs->reboot_cmd_ptr_low; |
| q = (char *)(((unsigned long)q)& 0x003fffff); |
| if (q >= (char *)0x4000 && q <= (char *)0x300000) { |
| if (given_bootargs_by_user) { |
| if (strlen (silo_disk_get_bootdevice()) <= 254) { |
| strcpy (q, silo_disk_get_bootdevice()); |
| r = strchr (q, 0); |
| if (strlen (given_bootargs) < 255 - (r - q)) { |
| *r++ = ' '; |
| strcpy (r, given_bootargs); |
| } |
| } |
| } else if (strlen (given_bootargs) <= 255) |
| strcpy (q, given_bootargs); |
| } |
| } |
| if (!dig_into_params (params) && !hdrs->root_dev) { |
| char *s1, *s2; |
| |
| s1 = cfg_get_strg(0, "root"); |
| if (s1) { |
| s2 = malloc(strlen(params) + 8 + strlen(s1)); |
| strcpy(s2, params); |
| strcat(s2, " root="); |
| strcat(s2, s1); |
| params = s2; |
| } |
| } |
| |
| if (hdrs->ver >= 0x202) { |
| if (architecture == sun4u) |
| kernel_params = (char *)((hdrs->bootstr_info_ptr_low - 0x400000) + |
| (image_base - 0x4000)); |
| else |
| kernel_params = (char *)(hdrs->bootstr_info_ptr_low & 0x3fffff); |
| } |
| |
| /* Some UltraAX machines have /dev/fd1 floppies only. */ |
| if (floppyswap) { |
| char *s1; |
| |
| for (s1 = params; (s1 = strstr(s1, "root=/dev/fd0")) != NULL; s1 += 13) |
| s1[12] = '1'; |
| } |
| |
| if (initrd_string) { |
| char *q, *r, *initrd_device, *initrd_kname, *initrd_limit, *initrd_cur, c; |
| char *string; |
| int initrd_partno, len, statusok = 0; |
| |
| if (hdrs->ver >= 0x301) |
| initrd_can_do_64bit_phys = 1; |
| |
| q = strchr (initrd_string, '|'); |
| if (q && !initrd_size) { |
| silo_fatal("When more than one initial ramdisk piece " |
| "is specified, you have to give\n" |
| "a non-zero initrd-size option which is no " |
| "shorter than sum of all pieces\n" |
| "lengths. Try again...\n"); |
| prom_halt (); |
| } |
| if (q) { |
| initrd_start = memory_find ((initrd_size + 16383) & ~16383); |
| if (!initrd_start) { |
| silo_fatal("You do not have enough continuous " |
| "available memory for such initial " |
| "ramdisk."); |
| prom_halt (); |
| } |
| string = strdup (initrd_string); |
| q = strchr (string, '|'); |
| r = string; |
| initrd_cur = initrd_start; |
| initrd_limit = initrd_start + ((initrd_size + 16383) & ~16383); |
| printf ("Loading parts of initial ramdisk...\n"); |
| for (;;) { |
| c = *q; |
| *q = 0; |
| parse_name (r, initrd_defpart, &initrd_device, &initrd_partno, &initrd_kname); |
| if (!initrd_kname) break; |
| if (!initrd_device) initrd_device = initrd_defdevice; |
| if (!silo_load_file(initrd_device, initrd_partno, |
| initrd_kname, (unsigned char *)initrd_cur, |
| (unsigned char *)initrd_limit, &len, 0, 0)) |
| break; |
| initrd_cur += len; |
| if (!c) { |
| statusok = 1; |
| break; |
| } |
| r = q + 1; |
| q = strchr (r, '|'); |
| if (!q) q = strchr (r, 0); |
| if (initrd_prompt) { |
| silo_disk_close(); |
| printf ("Insert next media and press ENTER"); |
| prom_getchar (); |
| printf ("\n"); |
| } |
| } |
| free (string); |
| printf("Loaded initial ramdisk (%d bytes at 0x%x)...\n", (unsigned int)initrd_cur - |
| (unsigned int)initrd_start, initrd_start); |
| if (statusok) { |
| extern unsigned long long sun4u_initrd_phys; |
| extern unsigned long sun4m_initrd_pa; |
| |
| if (architecture == sun4u) { |
| if (initrd_can_do_64bit_phys) { |
| hdrs->ramdisk_image64 = |
| sun4u_initrd_phys + 0x400000ULL; |
| } else { |
| hdrs->ramdisk_image = |
| (unsigned int)sun4u_initrd_phys + 0x400000; |
| } |
| } else if (sun4m_initrd_pa) { |
| hdrs->ramdisk_image = ((unsigned int)sun4m_initrd_pa); |
| } else |
| hdrs->ramdisk_image = ((unsigned int)initrd_start | 0xf0000000); |
| |
| hdrs->ramdisk_size = initrd_size; |
| } else |
| printf ("Error: initial ramdisk loading failed. No initrd will be used.\n"); |
| } else { |
| parse_name (initrd_string, initrd_defpart, &initrd_device, &initrd_partno, &initrd_kname); |
| if (initrd_kname) { |
| if (!initrd_device) initrd_device = initrd_defdevice; |
| if (silo_load_file(initrd_device, initrd_partno, |
| initrd_kname, (unsigned char *) 0x300000, |
| (unsigned char *) LARGE_RELOC, |
| 0, 0, initrd_lenfunc)) { |
| extern unsigned long long sun4u_initrd_phys; |
| extern unsigned long sun4m_initrd_pa; |
| |
| if (architecture == sun4u) { |
| if (initrd_can_do_64bit_phys) { |
| hdrs->ramdisk_image64 = |
| sun4u_initrd_phys + 0x400000ULL; |
| } else { |
| hdrs->ramdisk_image = |
| (unsigned int)sun4u_initrd_phys + 0x400000; |
| } |
| } else if (sun4m_initrd_pa) { |
| hdrs->ramdisk_image = ((unsigned int)sun4m_initrd_pa); |
| } else |
| hdrs->ramdisk_image = ((unsigned int)initrd_start | 0xf0000000); |
| |
| hdrs->ramdisk_size = initrd_size; |
| } |
| } else |
| printf ("Error: initial ramdisk loading failed. No initrd will be used.\n"); |
| } |
| } |
| } |
| } else { |
| char *p; |
| |
| if (off != 0 && !reboot) |
| memcpy (image_base, image_base + off, len); |
| p = seed_part_into_device (other_device, other_part); |
| strcpy (other_device, p); |
| params_device = other_device; |
| } |
| |
| silo_disk_close(); |
| if (timer_status >= 1) |
| close_timer (); |
| if (proll) { |
| silo_set_prollargs(params, (unsigned int)image_base, len); |
| if (show_arguments) { |
| printf ("Arguments: \"%s\"\n"); |
| pause_after = 1; |
| } |
| } else { |
| silo_set_bootargs(params, params_device); |
| |
| if (kernel_params) { |
| extern char barg_out[]; |
| int len = *(unsigned int *)kernel_params; |
| |
| strncpy (kernel_params + 8, barg_out, len); |
| kernel_params [8 + len - 1] = 0; |
| *(unsigned int *)(kernel_params + 4) = 1; |
| } |
| |
| if (show_arguments) { |
| silo_show_bootargs(); |
| pause_after = 1; |
| } |
| } |
| |
| if (pause_after) { |
| printf ("%s", pause_message); |
| prom_getchar (); |
| printf ("\n"); |
| } |
| |
| memory_release(); |
| |
| if (other && reboot) { |
| strcpy (sol_params, params_device); |
| strcat (sol_params, " "); |
| strcat (sol_params, params); |
| prom_reboot(sol_params); |
| } |
| |
| return ret_offset; |
| } |