1*10499SWilliam.Kucharski@Sun.COM /* 2*10499SWilliam.Kucharski@Sun.COM * CDDL HEADER START 3*10499SWilliam.Kucharski@Sun.COM * 4*10499SWilliam.Kucharski@Sun.COM * The contents of this file are subject to the terms of the 5*10499SWilliam.Kucharski@Sun.COM * Common Development and Distribution License (the "License"). 6*10499SWilliam.Kucharski@Sun.COM * You may not use this file except in compliance with the License. 7*10499SWilliam.Kucharski@Sun.COM * 8*10499SWilliam.Kucharski@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10499SWilliam.Kucharski@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10499SWilliam.Kucharski@Sun.COM * See the License for the specific language governing permissions 11*10499SWilliam.Kucharski@Sun.COM * and limitations under the License. 12*10499SWilliam.Kucharski@Sun.COM * 13*10499SWilliam.Kucharski@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10499SWilliam.Kucharski@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10499SWilliam.Kucharski@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10499SWilliam.Kucharski@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10499SWilliam.Kucharski@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10499SWilliam.Kucharski@Sun.COM * 19*10499SWilliam.Kucharski@Sun.COM * CDDL HEADER END 20*10499SWilliam.Kucharski@Sun.COM */ 21*10499SWilliam.Kucharski@Sun.COM /* 22*10499SWilliam.Kucharski@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*10499SWilliam.Kucharski@Sun.COM * Use is subject to license terms. 24*10499SWilliam.Kucharski@Sun.COM */ 25*10499SWilliam.Kucharski@Sun.COM 26*10499SWilliam.Kucharski@Sun.COM #include <stdio.h> 27*10499SWilliam.Kucharski@Sun.COM #include <errno.h> 28*10499SWilliam.Kucharski@Sun.COM #include <stdlib.h> 29*10499SWilliam.Kucharski@Sun.COM #include <string.h> 30*10499SWilliam.Kucharski@Sun.COM #include <unistd.h> 31*10499SWilliam.Kucharski@Sun.COM #include <alloca.h> 32*10499SWilliam.Kucharski@Sun.COM #include <ctype.h> 33*10499SWilliam.Kucharski@Sun.COM #include <sys/types.h> 34*10499SWilliam.Kucharski@Sun.COM 35*10499SWilliam.Kucharski@Sun.COM #include "message.h" 36*10499SWilliam.Kucharski@Sun.COM #include "bootadm.h" 37*10499SWilliam.Kucharski@Sun.COM 38*10499SWilliam.Kucharski@Sun.COM #define HYPER_KERNEL_DIR "/platform/i86xpv/kernel" 39*10499SWilliam.Kucharski@Sun.COM #define METAL_KERNEL_DIR "/platform/i86pc/kernel" 40*10499SWilliam.Kucharski@Sun.COM 41*10499SWilliam.Kucharski@Sun.COM #define BOOTRC_FILE "/boot/solaris/bootenv.rc" 42*10499SWilliam.Kucharski@Sun.COM #define ZFS_BOOTSTR "$ZFS-BOOTFS" 43*10499SWilliam.Kucharski@Sun.COM 44*10499SWilliam.Kucharski@Sun.COM #define BFLAG "-B" 45*10499SWilliam.Kucharski@Sun.COM #define DEFAULT_SERIAL "9600,8,n,1" 46*10499SWilliam.Kucharski@Sun.COM 47*10499SWilliam.Kucharski@Sun.COM #define TTYXMODE_TO_COMNUM(ttyxmode) ((int)(*((ttyxmode) + 3) - '`')) 48*10499SWilliam.Kucharski@Sun.COM #define COMNAME_TO_COMNUM(comname) ((int)(*((comname) + 3) - '0')) 49*10499SWilliam.Kucharski@Sun.COM 50*10499SWilliam.Kucharski@Sun.COM #define WHITESPC(x) (x) 51*10499SWilliam.Kucharski@Sun.COM 52*10499SWilliam.Kucharski@Sun.COM static char *serial_config[2] = { NULL, NULL }; 53*10499SWilliam.Kucharski@Sun.COM 54*10499SWilliam.Kucharski@Sun.COM static char *console_dev = NULL; 55*10499SWilliam.Kucharski@Sun.COM 56*10499SWilliam.Kucharski@Sun.COM static unsigned zfs_boot = 0; 57*10499SWilliam.Kucharski@Sun.COM 58*10499SWilliam.Kucharski@Sun.COM /* 59*10499SWilliam.Kucharski@Sun.COM * Append the string pointed to by "str" to the string pointed to by "orig" 60*10499SWilliam.Kucharski@Sun.COM * adding the delimeter "delim" in between. 61*10499SWilliam.Kucharski@Sun.COM * 62*10499SWilliam.Kucharski@Sun.COM * Return a pointer to the new string or NULL, if we were passed a bad string 63*10499SWilliam.Kucharski@Sun.COM * or we couldn't allocate memory for the new one. 64*10499SWilliam.Kucharski@Sun.COM */ 65*10499SWilliam.Kucharski@Sun.COM static char * 66*10499SWilliam.Kucharski@Sun.COM append_str(char *orig, char *str, char *delim) 67*10499SWilliam.Kucharski@Sun.COM { 68*10499SWilliam.Kucharski@Sun.COM char *newstr; 69*10499SWilliam.Kucharski@Sun.COM int len; 70*10499SWilliam.Kucharski@Sun.COM 71*10499SWilliam.Kucharski@Sun.COM if ((orig == NULL) || (str == NULL) || (delim == NULL)) 72*10499SWilliam.Kucharski@Sun.COM return (NULL); 73*10499SWilliam.Kucharski@Sun.COM 74*10499SWilliam.Kucharski@Sun.COM if (*orig == NULL) 75*10499SWilliam.Kucharski@Sun.COM return (s_strdup(str)); 76*10499SWilliam.Kucharski@Sun.COM 77*10499SWilliam.Kucharski@Sun.COM len = strlen(orig) + strlen(str) + strlen(delim) + 1; 78*10499SWilliam.Kucharski@Sun.COM newstr = s_realloc(orig, len); 79*10499SWilliam.Kucharski@Sun.COM 80*10499SWilliam.Kucharski@Sun.COM if (newstr != NULL) 81*10499SWilliam.Kucharski@Sun.COM (void) snprintf(newstr, len, "%s%s%s", orig, delim, str); 82*10499SWilliam.Kucharski@Sun.COM 83*10499SWilliam.Kucharski@Sun.COM return (newstr); 84*10499SWilliam.Kucharski@Sun.COM } 85*10499SWilliam.Kucharski@Sun.COM 86*10499SWilliam.Kucharski@Sun.COM /* 87*10499SWilliam.Kucharski@Sun.COM * Replace the substring "old_str" in a path with the substring "new_str" 88*10499SWilliam.Kucharski@Sun.COM * 89*10499SWilliam.Kucharski@Sun.COM * Return a pointer to the modified string or NULL, if we couldn't allocate 90*10499SWilliam.Kucharski@Sun.COM * memory for the new string. 91*10499SWilliam.Kucharski@Sun.COM */ 92*10499SWilliam.Kucharski@Sun.COM static char * 93*10499SWilliam.Kucharski@Sun.COM modify_path(char *path, char *old_str, char *new_str) 94*10499SWilliam.Kucharski@Sun.COM { 95*10499SWilliam.Kucharski@Sun.COM char *newpath; 96*10499SWilliam.Kucharski@Sun.COM char *oldpath; 97*10499SWilliam.Kucharski@Sun.COM char *pc; 98*10499SWilliam.Kucharski@Sun.COM 99*10499SWilliam.Kucharski@Sun.COM oldpath = s_strdup(path); 100*10499SWilliam.Kucharski@Sun.COM 101*10499SWilliam.Kucharski@Sun.COM if ((pc = strstr(oldpath, old_str)) == NULL) { 102*10499SWilliam.Kucharski@Sun.COM free(oldpath); 103*10499SWilliam.Kucharski@Sun.COM return (path); 104*10499SWilliam.Kucharski@Sun.COM } 105*10499SWilliam.Kucharski@Sun.COM 106*10499SWilliam.Kucharski@Sun.COM /* 107*10499SWilliam.Kucharski@Sun.COM * Allocate space for duplicate of path with name changes and 108*10499SWilliam.Kucharski@Sun.COM * NULL terminating byte 109*10499SWilliam.Kucharski@Sun.COM */ 110*10499SWilliam.Kucharski@Sun.COM if ((newpath = s_realloc(path, 111*10499SWilliam.Kucharski@Sun.COM strlen(oldpath) - strlen(old_str) + strlen(new_str) + 1)) == NULL) { 112*10499SWilliam.Kucharski@Sun.COM free(oldpath); 113*10499SWilliam.Kucharski@Sun.COM return (NULL); 114*10499SWilliam.Kucharski@Sun.COM } 115*10499SWilliam.Kucharski@Sun.COM 116*10499SWilliam.Kucharski@Sun.COM (void) strlcpy(newpath, oldpath, (pc - oldpath) + 1); 117*10499SWilliam.Kucharski@Sun.COM free(oldpath); 118*10499SWilliam.Kucharski@Sun.COM 119*10499SWilliam.Kucharski@Sun.COM (void) strcat(newpath, new_str); 120*10499SWilliam.Kucharski@Sun.COM pc += strlen(old_str); 121*10499SWilliam.Kucharski@Sun.COM return (strcat(newpath, pc)); 122*10499SWilliam.Kucharski@Sun.COM } 123*10499SWilliam.Kucharski@Sun.COM 124*10499SWilliam.Kucharski@Sun.COM /* 125*10499SWilliam.Kucharski@Sun.COM * Set "token" to be the the string starting from the pointer "str" delimited 126*10499SWilliam.Kucharski@Sun.COM * by any character in the string "delim" or the end of the string, but IGNORE 127*10499SWilliam.Kucharski@Sun.COM * any characters between single or double quotes. 128*10499SWilliam.Kucharski@Sun.COM * 129*10499SWilliam.Kucharski@Sun.COM * Return a pointer to the next non-whitespace character after the delimiter 130*10499SWilliam.Kucharski@Sun.COM * or NULL if we hit the end of the string. Also return NULL upon failure to 131*10499SWilliam.Kucharski@Sun.COM * find any characters from the delimeter string or upon failure to allocate 132*10499SWilliam.Kucharski@Sun.COM * memory for the new token string. 133*10499SWilliam.Kucharski@Sun.COM */ 134*10499SWilliam.Kucharski@Sun.COM static char * 135*10499SWilliam.Kucharski@Sun.COM get_token(char **token, char *str, char *delim) 136*10499SWilliam.Kucharski@Sun.COM { 137*10499SWilliam.Kucharski@Sun.COM char *dp; 138*10499SWilliam.Kucharski@Sun.COM char *start = str; 139*10499SWilliam.Kucharski@Sun.COM unsigned len; 140*10499SWilliam.Kucharski@Sun.COM 141*10499SWilliam.Kucharski@Sun.COM *token = NULL; 142*10499SWilliam.Kucharski@Sun.COM 143*10499SWilliam.Kucharski@Sun.COM if ((str == NULL) || (*str == NULL)) 144*10499SWilliam.Kucharski@Sun.COM return (NULL); 145*10499SWilliam.Kucharski@Sun.COM 146*10499SWilliam.Kucharski@Sun.COM do { 147*10499SWilliam.Kucharski@Sun.COM if ((*str == '\'') || (*str == '"')) { 148*10499SWilliam.Kucharski@Sun.COM char quote = *str++; 149*10499SWilliam.Kucharski@Sun.COM 150*10499SWilliam.Kucharski@Sun.COM while ((*str != NULL) && (*str != quote)) 151*10499SWilliam.Kucharski@Sun.COM str++; 152*10499SWilliam.Kucharski@Sun.COM 153*10499SWilliam.Kucharski@Sun.COM /* no matching quote found in string */ 154*10499SWilliam.Kucharski@Sun.COM if (*str++ == NULL) 155*10499SWilliam.Kucharski@Sun.COM return (NULL); 156*10499SWilliam.Kucharski@Sun.COM } 157*10499SWilliam.Kucharski@Sun.COM 158*10499SWilliam.Kucharski@Sun.COM /* look for a character from the delimiter string */ 159*10499SWilliam.Kucharski@Sun.COM for (dp = delim; ((*dp != NULL) && (*dp != *str)); dp++) 160*10499SWilliam.Kucharski@Sun.COM ; 161*10499SWilliam.Kucharski@Sun.COM 162*10499SWilliam.Kucharski@Sun.COM if (*dp != NULL) { 163*10499SWilliam.Kucharski@Sun.COM len = str - start + 1; 164*10499SWilliam.Kucharski@Sun.COM 165*10499SWilliam.Kucharski@Sun.COM /* found a delimiter, so create a token string */ 166*10499SWilliam.Kucharski@Sun.COM if ((*token = malloc(len)) == NULL) { 167*10499SWilliam.Kucharski@Sun.COM bam_error(NO_MEM, len); 168*10499SWilliam.Kucharski@Sun.COM return (NULL); 169*10499SWilliam.Kucharski@Sun.COM } 170*10499SWilliam.Kucharski@Sun.COM 171*10499SWilliam.Kucharski@Sun.COM (void) strlcpy(*token, start, len); 172*10499SWilliam.Kucharski@Sun.COM 173*10499SWilliam.Kucharski@Sun.COM while (isspace((int)*++str)) 174*10499SWilliam.Kucharski@Sun.COM ; 175*10499SWilliam.Kucharski@Sun.COM 176*10499SWilliam.Kucharski@Sun.COM return (str); 177*10499SWilliam.Kucharski@Sun.COM } 178*10499SWilliam.Kucharski@Sun.COM } while (*str++ != NULL); 179*10499SWilliam.Kucharski@Sun.COM 180*10499SWilliam.Kucharski@Sun.COM /* if we hit the end of the string, the token is the whole string */ 181*10499SWilliam.Kucharski@Sun.COM *token = s_strdup(start); 182*10499SWilliam.Kucharski@Sun.COM return (NULL); 183*10499SWilliam.Kucharski@Sun.COM } 184*10499SWilliam.Kucharski@Sun.COM 185*10499SWilliam.Kucharski@Sun.COM /* 186*10499SWilliam.Kucharski@Sun.COM * Convert a metal "console" device name to an equivalent one suitable for 187*10499SWilliam.Kucharski@Sun.COM * use with the hypervisor. 188*10499SWilliam.Kucharski@Sun.COM * 189*10499SWilliam.Kucharski@Sun.COM * Default to "vga" if we can't parse the console device. 190*10499SWilliam.Kucharski@Sun.COM */ 191*10499SWilliam.Kucharski@Sun.COM static void 192*10499SWilliam.Kucharski@Sun.COM console_metal_to_hyper(char *console) 193*10499SWilliam.Kucharski@Sun.COM { 194*10499SWilliam.Kucharski@Sun.COM if ((*console == '\'') || (*console == '"')) 195*10499SWilliam.Kucharski@Sun.COM console++; 196*10499SWilliam.Kucharski@Sun.COM 197*10499SWilliam.Kucharski@Sun.COM if (strncmp(console, "ttya", 4) == 0) 198*10499SWilliam.Kucharski@Sun.COM console_dev = "console=com1"; 199*10499SWilliam.Kucharski@Sun.COM else if (strncmp(console, "ttyb", 4) == 0) 200*10499SWilliam.Kucharski@Sun.COM console_dev = "console=com2"; 201*10499SWilliam.Kucharski@Sun.COM else 202*10499SWilliam.Kucharski@Sun.COM console_dev = "console=vga"; 203*10499SWilliam.Kucharski@Sun.COM } 204*10499SWilliam.Kucharski@Sun.COM 205*10499SWilliam.Kucharski@Sun.COM static int 206*10499SWilliam.Kucharski@Sun.COM set_serial_rate(int com, char *rate) 207*10499SWilliam.Kucharski@Sun.COM { 208*10499SWilliam.Kucharski@Sun.COM char **rp = &serial_config[com - 1]; 209*10499SWilliam.Kucharski@Sun.COM 210*10499SWilliam.Kucharski@Sun.COM /* 211*10499SWilliam.Kucharski@Sun.COM * If rate is a NULL pointer, erase any existing serial configuration 212*10499SWilliam.Kucharski@Sun.COM * for this serial port. 213*10499SWilliam.Kucharski@Sun.COM */ 214*10499SWilliam.Kucharski@Sun.COM if (rate == NULL) { 215*10499SWilliam.Kucharski@Sun.COM if (*rp != NULL) { 216*10499SWilliam.Kucharski@Sun.COM free(*rp); 217*10499SWilliam.Kucharski@Sun.COM *rp = NULL; 218*10499SWilliam.Kucharski@Sun.COM } 219*10499SWilliam.Kucharski@Sun.COM return (0); 220*10499SWilliam.Kucharski@Sun.COM } 221*10499SWilliam.Kucharski@Sun.COM 222*10499SWilliam.Kucharski@Sun.COM *rp = s_realloc(*rp, strlen(rate)); 223*10499SWilliam.Kucharski@Sun.COM (void) strcpy(*rp, rate); 224*10499SWilliam.Kucharski@Sun.COM return (0); 225*10499SWilliam.Kucharski@Sun.COM } 226*10499SWilliam.Kucharski@Sun.COM 227*10499SWilliam.Kucharski@Sun.COM /* 228*10499SWilliam.Kucharski@Sun.COM * Convert "metal" serial port parameters to values compatible with the 229*10499SWilliam.Kucharski@Sun.COM * hypervisor. 230*10499SWilliam.Kucharski@Sun.COM * 231*10499SWilliam.Kucharski@Sun.COM * Return 0 on success, otherwise -1. 232*10499SWilliam.Kucharski@Sun.COM */ 233*10499SWilliam.Kucharski@Sun.COM static int 234*10499SWilliam.Kucharski@Sun.COM serial_metal_to_hyper(char *metal_port, char *metal_serial) 235*10499SWilliam.Kucharski@Sun.COM { 236*10499SWilliam.Kucharski@Sun.COM #define COM_RATE_LEN 16 /* strlen("com1=115200,8n1") */ 237*10499SWilliam.Kucharski@Sun.COM 238*10499SWilliam.Kucharski@Sun.COM char com_rate[COM_RATE_LEN]; 239*10499SWilliam.Kucharski@Sun.COM 240*10499SWilliam.Kucharski@Sun.COM unsigned com, baud, bits, stop; 241*10499SWilliam.Kucharski@Sun.COM char parity, handshake; 242*10499SWilliam.Kucharski@Sun.COM 243*10499SWilliam.Kucharski@Sun.COM if ((strcmp(metal_port, "ttya-mode") == 0) || 244*10499SWilliam.Kucharski@Sun.COM (strcmp(metal_port, "ttyb-mode") == 0)) 245*10499SWilliam.Kucharski@Sun.COM com = TTYXMODE_TO_COMNUM(metal_port); 246*10499SWilliam.Kucharski@Sun.COM else 247*10499SWilliam.Kucharski@Sun.COM return (-1); 248*10499SWilliam.Kucharski@Sun.COM 249*10499SWilliam.Kucharski@Sun.COM if ((*metal_serial == '\'') || (*metal_serial == '"')) 250*10499SWilliam.Kucharski@Sun.COM metal_serial++; 251*10499SWilliam.Kucharski@Sun.COM 252*10499SWilliam.Kucharski@Sun.COM /* 253*10499SWilliam.Kucharski@Sun.COM * Check if it's specified as the default rate; if so it defaults to 254*10499SWilliam.Kucharski@Sun.COM * "auto" and we need not set it for they hypervisor. 255*10499SWilliam.Kucharski@Sun.COM */ 256*10499SWilliam.Kucharski@Sun.COM if (strncmp(metal_serial, DEFAULT_SERIAL, 257*10499SWilliam.Kucharski@Sun.COM strlen(DEFAULT_SERIAL)) == 0) { 258*10499SWilliam.Kucharski@Sun.COM (void) set_serial_rate(com, NULL); 259*10499SWilliam.Kucharski@Sun.COM return (0); 260*10499SWilliam.Kucharski@Sun.COM } 261*10499SWilliam.Kucharski@Sun.COM 262*10499SWilliam.Kucharski@Sun.COM /* read the serial port format as set forth in common/io/asy.c */ 263*10499SWilliam.Kucharski@Sun.COM if (sscanf(metal_serial, "%u,%u,%c,%u,%c", &baud, &bits, &parity, &stop, 264*10499SWilliam.Kucharski@Sun.COM &handshake) != 5) 265*10499SWilliam.Kucharski@Sun.COM return (-1); 266*10499SWilliam.Kucharski@Sun.COM 267*10499SWilliam.Kucharski@Sun.COM /* validate serial port parameters */ 268*10499SWilliam.Kucharski@Sun.COM if (((bits < 5) || (bits > 8)) || (stop > 1) || 269*10499SWilliam.Kucharski@Sun.COM ((parity != 'n') && (parity != 'e') && (parity != 'o')) || 270*10499SWilliam.Kucharski@Sun.COM ((handshake != '-') && (handshake != 'h') && (handshake != 's'))) 271*10499SWilliam.Kucharski@Sun.COM return (-1); 272*10499SWilliam.Kucharski@Sun.COM 273*10499SWilliam.Kucharski@Sun.COM /* validate baud rate */ 274*10499SWilliam.Kucharski@Sun.COM switch (baud) { 275*10499SWilliam.Kucharski@Sun.COM case 150: 276*10499SWilliam.Kucharski@Sun.COM case 300: 277*10499SWilliam.Kucharski@Sun.COM case 600: 278*10499SWilliam.Kucharski@Sun.COM case 1200: 279*10499SWilliam.Kucharski@Sun.COM case 2400: 280*10499SWilliam.Kucharski@Sun.COM case 4800: 281*10499SWilliam.Kucharski@Sun.COM case 9600: 282*10499SWilliam.Kucharski@Sun.COM case 19200: 283*10499SWilliam.Kucharski@Sun.COM case 38400: 284*10499SWilliam.Kucharski@Sun.COM case 57600: 285*10499SWilliam.Kucharski@Sun.COM case 115200: 286*10499SWilliam.Kucharski@Sun.COM break; 287*10499SWilliam.Kucharski@Sun.COM 288*10499SWilliam.Kucharski@Sun.COM default: 289*10499SWilliam.Kucharski@Sun.COM return (-1); 290*10499SWilliam.Kucharski@Sun.COM } 291*10499SWilliam.Kucharski@Sun.COM 292*10499SWilliam.Kucharski@Sun.COM /* 293*10499SWilliam.Kucharski@Sun.COM * The hypervisor has no way to specify a handshake method, so it gets 294*10499SWilliam.Kucharski@Sun.COM * quietly dropped in the conversion. 295*10499SWilliam.Kucharski@Sun.COM */ 296*10499SWilliam.Kucharski@Sun.COM (void) snprintf(com_rate, COM_RATE_LEN, "com%d=%u,%u%c%u", com, baud, 297*10499SWilliam.Kucharski@Sun.COM bits, parity, stop); 298*10499SWilliam.Kucharski@Sun.COM (void) set_serial_rate(com, com_rate); 299*10499SWilliam.Kucharski@Sun.COM return (0); 300*10499SWilliam.Kucharski@Sun.COM } 301*10499SWilliam.Kucharski@Sun.COM 302*10499SWilliam.Kucharski@Sun.COM /* 303*10499SWilliam.Kucharski@Sun.COM * Convert bootenv.rc boot property strings of the form: 304*10499SWilliam.Kucharski@Sun.COM * 305*10499SWilliam.Kucharski@Sun.COM * setprop property value 306*10499SWilliam.Kucharski@Sun.COM * 307*10499SWilliam.Kucharski@Sun.COM * into boot option lines suitable for use with the hypervisor. 308*10499SWilliam.Kucharski@Sun.COM * 309*10499SWilliam.Kucharski@Sun.COM * Our main concerns are the console device and serial port settings. 310*10499SWilliam.Kucharski@Sun.COM * 311*10499SWilliam.Kucharski@Sun.COM * Return values: 312*10499SWilliam.Kucharski@Sun.COM * 313*10499SWilliam.Kucharski@Sun.COM * -1: Unparseable line 314*10499SWilliam.Kucharski@Sun.COM * 0: Success 315*10499SWilliam.Kucharski@Sun.COM * (n > 0): A property unimportant to us 316*10499SWilliam.Kucharski@Sun.COM */ 317*10499SWilliam.Kucharski@Sun.COM static int 318*10499SWilliam.Kucharski@Sun.COM cvt_bootprop(char *propstr) 319*10499SWilliam.Kucharski@Sun.COM { 320*10499SWilliam.Kucharski@Sun.COM char *parsestr, *port, *token; 321*10499SWilliam.Kucharski@Sun.COM 322*10499SWilliam.Kucharski@Sun.COM int retval = 0; 323*10499SWilliam.Kucharski@Sun.COM 324*10499SWilliam.Kucharski@Sun.COM /* get initial "setprop" */ 325*10499SWilliam.Kucharski@Sun.COM if ((parsestr = get_token(&token, propstr, " \t")) == NULL) { 326*10499SWilliam.Kucharski@Sun.COM if (token != NULL) 327*10499SWilliam.Kucharski@Sun.COM free(token); 328*10499SWilliam.Kucharski@Sun.COM 329*10499SWilliam.Kucharski@Sun.COM return (-1); 330*10499SWilliam.Kucharski@Sun.COM } 331*10499SWilliam.Kucharski@Sun.COM 332*10499SWilliam.Kucharski@Sun.COM if (strcmp(token, "setprop")) { 333*10499SWilliam.Kucharski@Sun.COM free(token); 334*10499SWilliam.Kucharski@Sun.COM return (1); 335*10499SWilliam.Kucharski@Sun.COM } 336*10499SWilliam.Kucharski@Sun.COM 337*10499SWilliam.Kucharski@Sun.COM free(token); 338*10499SWilliam.Kucharski@Sun.COM 339*10499SWilliam.Kucharski@Sun.COM /* get property name */ 340*10499SWilliam.Kucharski@Sun.COM if ((parsestr = get_token(&token, parsestr, " \t")) == NULL) { 341*10499SWilliam.Kucharski@Sun.COM if (token != NULL) 342*10499SWilliam.Kucharski@Sun.COM free(token); 343*10499SWilliam.Kucharski@Sun.COM 344*10499SWilliam.Kucharski@Sun.COM return (-2); 345*10499SWilliam.Kucharski@Sun.COM } 346*10499SWilliam.Kucharski@Sun.COM 347*10499SWilliam.Kucharski@Sun.COM if (strcmp(token, "console") == 0) { 348*10499SWilliam.Kucharski@Sun.COM free(token); 349*10499SWilliam.Kucharski@Sun.COM 350*10499SWilliam.Kucharski@Sun.COM /* get console property value */ 351*10499SWilliam.Kucharski@Sun.COM parsestr = get_token(&token, parsestr, " \t"); 352*10499SWilliam.Kucharski@Sun.COM if (token == NULL) 353*10499SWilliam.Kucharski@Sun.COM return (-3); 354*10499SWilliam.Kucharski@Sun.COM 355*10499SWilliam.Kucharski@Sun.COM console_metal_to_hyper(token); 356*10499SWilliam.Kucharski@Sun.COM free(token); 357*10499SWilliam.Kucharski@Sun.COM return (0); 358*10499SWilliam.Kucharski@Sun.COM } 359*10499SWilliam.Kucharski@Sun.COM 360*10499SWilliam.Kucharski@Sun.COM /* check if it's a serial port setting */ 361*10499SWilliam.Kucharski@Sun.COM if ((strcmp(token, "ttya-mode") == 0) || 362*10499SWilliam.Kucharski@Sun.COM (strcmp(token, "ttyb-mode") == 0)) { 363*10499SWilliam.Kucharski@Sun.COM port = token; 364*10499SWilliam.Kucharski@Sun.COM } else { 365*10499SWilliam.Kucharski@Sun.COM free(token); 366*10499SWilliam.Kucharski@Sun.COM return (3); 367*10499SWilliam.Kucharski@Sun.COM } 368*10499SWilliam.Kucharski@Sun.COM 369*10499SWilliam.Kucharski@Sun.COM /* get serial port setting */ 370*10499SWilliam.Kucharski@Sun.COM parsestr = get_token(&token, parsestr, " \t"); 371*10499SWilliam.Kucharski@Sun.COM 372*10499SWilliam.Kucharski@Sun.COM if (token == NULL) { 373*10499SWilliam.Kucharski@Sun.COM free(port); 374*10499SWilliam.Kucharski@Sun.COM return (-1); 375*10499SWilliam.Kucharski@Sun.COM } 376*10499SWilliam.Kucharski@Sun.COM 377*10499SWilliam.Kucharski@Sun.COM retval = serial_metal_to_hyper(port, token); 378*10499SWilliam.Kucharski@Sun.COM 379*10499SWilliam.Kucharski@Sun.COM free(port); 380*10499SWilliam.Kucharski@Sun.COM free(token); 381*10499SWilliam.Kucharski@Sun.COM return (retval); 382*10499SWilliam.Kucharski@Sun.COM } 383*10499SWilliam.Kucharski@Sun.COM 384*10499SWilliam.Kucharski@Sun.COM /* 385*10499SWilliam.Kucharski@Sun.COM * Convert "name=value" metal options to values suitable for use with the 386*10499SWilliam.Kucharski@Sun.COM * hypervisor. 387*10499SWilliam.Kucharski@Sun.COM * 388*10499SWilliam.Kucharski@Sun.COM * Our main concerns are the console device and serial port settings. 389*10499SWilliam.Kucharski@Sun.COM * 390*10499SWilliam.Kucharski@Sun.COM * Return values: 391*10499SWilliam.Kucharski@Sun.COM * 392*10499SWilliam.Kucharski@Sun.COM * -1: Unparseable line 393*10499SWilliam.Kucharski@Sun.COM * 0: Success 394*10499SWilliam.Kucharski@Sun.COM * (n > 0): A property unimportant to us 395*10499SWilliam.Kucharski@Sun.COM */ 396*10499SWilliam.Kucharski@Sun.COM static int 397*10499SWilliam.Kucharski@Sun.COM cvt_metal_option(char *optstr) 398*10499SWilliam.Kucharski@Sun.COM { 399*10499SWilliam.Kucharski@Sun.COM char *value; 400*10499SWilliam.Kucharski@Sun.COM unsigned namlen; 401*10499SWilliam.Kucharski@Sun.COM 402*10499SWilliam.Kucharski@Sun.COM if (strcmp(optstr, ZFS_BOOTSTR) == 0) { 403*10499SWilliam.Kucharski@Sun.COM zfs_boot = 1; 404*10499SWilliam.Kucharski@Sun.COM return (0); 405*10499SWilliam.Kucharski@Sun.COM } 406*10499SWilliam.Kucharski@Sun.COM 407*10499SWilliam.Kucharski@Sun.COM if ((value = strchr(optstr, '=')) == NULL) 408*10499SWilliam.Kucharski@Sun.COM return (-1); 409*10499SWilliam.Kucharski@Sun.COM 410*10499SWilliam.Kucharski@Sun.COM namlen = value - optstr; 411*10499SWilliam.Kucharski@Sun.COM 412*10499SWilliam.Kucharski@Sun.COM if (*++value == NULL) 413*10499SWilliam.Kucharski@Sun.COM return (1); 414*10499SWilliam.Kucharski@Sun.COM 415*10499SWilliam.Kucharski@Sun.COM if (strncmp(optstr, "console", namlen) == 0) { 416*10499SWilliam.Kucharski@Sun.COM console_metal_to_hyper(value); 417*10499SWilliam.Kucharski@Sun.COM return (0); 418*10499SWilliam.Kucharski@Sun.COM } 419*10499SWilliam.Kucharski@Sun.COM 420*10499SWilliam.Kucharski@Sun.COM if ((strncmp(optstr, "ttya-mode", namlen) == 0) || 421*10499SWilliam.Kucharski@Sun.COM (strncmp(optstr, "ttyb-mode", namlen) == 0)) { 422*10499SWilliam.Kucharski@Sun.COM char *port = alloca(namlen + 1); 423*10499SWilliam.Kucharski@Sun.COM 424*10499SWilliam.Kucharski@Sun.COM (void) strlcpy(port, optstr, namlen); 425*10499SWilliam.Kucharski@Sun.COM return (serial_metal_to_hyper(port, value)); 426*10499SWilliam.Kucharski@Sun.COM } 427*10499SWilliam.Kucharski@Sun.COM 428*10499SWilliam.Kucharski@Sun.COM return (1); 429*10499SWilliam.Kucharski@Sun.COM } 430*10499SWilliam.Kucharski@Sun.COM 431*10499SWilliam.Kucharski@Sun.COM /* 432*10499SWilliam.Kucharski@Sun.COM * Convert "name=value" properties for use with a bare metal kernel 433*10499SWilliam.Kucharski@Sun.COM * 434*10499SWilliam.Kucharski@Sun.COM * Our main concerns are the console setting and serial port modes. 435*10499SWilliam.Kucharski@Sun.COM * 436*10499SWilliam.Kucharski@Sun.COM * Return values: 437*10499SWilliam.Kucharski@Sun.COM * 438*10499SWilliam.Kucharski@Sun.COM * -1: Unparseable line 439*10499SWilliam.Kucharski@Sun.COM * 0: Success 440*10499SWilliam.Kucharski@Sun.COM * (n > 0): A property unimportant to us 441*10499SWilliam.Kucharski@Sun.COM */ 442*10499SWilliam.Kucharski@Sun.COM static int 443*10499SWilliam.Kucharski@Sun.COM cvt_hyper_option(char *optstr) 444*10499SWilliam.Kucharski@Sun.COM { 445*10499SWilliam.Kucharski@Sun.COM #define SER_LEN 27 /* strlen("ttyb-mode='115200,8,n,1,-'") */ 446*10499SWilliam.Kucharski@Sun.COM 447*10499SWilliam.Kucharski@Sun.COM char ser[SER_LEN]; 448*10499SWilliam.Kucharski@Sun.COM char *value; 449*10499SWilliam.Kucharski@Sun.COM 450*10499SWilliam.Kucharski@Sun.COM unsigned namlen; 451*10499SWilliam.Kucharski@Sun.COM 452*10499SWilliam.Kucharski@Sun.COM unsigned baud; 453*10499SWilliam.Kucharski@Sun.COM char bits, parity, stop; 454*10499SWilliam.Kucharski@Sun.COM 455*10499SWilliam.Kucharski@Sun.COM if (strcmp(optstr, ZFS_BOOTSTR) == 0) { 456*10499SWilliam.Kucharski@Sun.COM zfs_boot = 1; 457*10499SWilliam.Kucharski@Sun.COM return (0); 458*10499SWilliam.Kucharski@Sun.COM } 459*10499SWilliam.Kucharski@Sun.COM 460*10499SWilliam.Kucharski@Sun.COM /* 461*10499SWilliam.Kucharski@Sun.COM * If there's no "=" in the token, it's likely a standalone 462*10499SWilliam.Kucharski@Sun.COM * hypervisor token we don't care about (e.g. "noreboot" or 463*10499SWilliam.Kucharski@Sun.COM * "nosmp") so we ignore it. 464*10499SWilliam.Kucharski@Sun.COM */ 465*10499SWilliam.Kucharski@Sun.COM if ((value = strchr(optstr, '=')) == NULL) 466*10499SWilliam.Kucharski@Sun.COM return (1); 467*10499SWilliam.Kucharski@Sun.COM 468*10499SWilliam.Kucharski@Sun.COM namlen = value - optstr; 469*10499SWilliam.Kucharski@Sun.COM 470*10499SWilliam.Kucharski@Sun.COM if (*++value == NULL) 471*10499SWilliam.Kucharski@Sun.COM return (1); 472*10499SWilliam.Kucharski@Sun.COM 473*10499SWilliam.Kucharski@Sun.COM /* 474*10499SWilliam.Kucharski@Sun.COM * Note that we use strncmp against the values because the 475*10499SWilliam.Kucharski@Sun.COM * hypervisor allows setting console parameters for both the 476*10499SWilliam.Kucharski@Sun.COM * console and debugger via the format: 477*10499SWilliam.Kucharski@Sun.COM * 478*10499SWilliam.Kucharski@Sun.COM * console=cons_dev,debug_dev 479*10499SWilliam.Kucharski@Sun.COM * 480*10499SWilliam.Kucharski@Sun.COM * and we only care about "cons_dev." 481*10499SWilliam.Kucharski@Sun.COM * 482*10499SWilliam.Kucharski@Sun.COM * This also allows us to extract "comN" from hypervisor constructs 483*10499SWilliam.Kucharski@Sun.COM * like "com1H" or "com2L," concepts unsupported on bare metal kernels. 484*10499SWilliam.Kucharski@Sun.COM * 485*10499SWilliam.Kucharski@Sun.COM * Default the console device to "text" if it was "vga" or was 486*10499SWilliam.Kucharski@Sun.COM * unparseable. 487*10499SWilliam.Kucharski@Sun.COM */ 488*10499SWilliam.Kucharski@Sun.COM if (strncmp(optstr, "console", namlen) == 0) { 489*10499SWilliam.Kucharski@Sun.COM /* ignore the "console=hypervisor" option */ 490*10499SWilliam.Kucharski@Sun.COM if (strcmp(value, "hypervisor") == 0) 491*10499SWilliam.Kucharski@Sun.COM return (0); 492*10499SWilliam.Kucharski@Sun.COM 493*10499SWilliam.Kucharski@Sun.COM if (strncmp(value, "com1", 4) == 0) 494*10499SWilliam.Kucharski@Sun.COM console_dev = "console=ttya"; 495*10499SWilliam.Kucharski@Sun.COM else if (strncmp(value, "com2", 4) == 0) 496*10499SWilliam.Kucharski@Sun.COM console_dev = "console=ttyb"; 497*10499SWilliam.Kucharski@Sun.COM else 498*10499SWilliam.Kucharski@Sun.COM console_dev = "console=text"; 499*10499SWilliam.Kucharski@Sun.COM } 500*10499SWilliam.Kucharski@Sun.COM 501*10499SWilliam.Kucharski@Sun.COM /* serial port parameter conversion */ 502*10499SWilliam.Kucharski@Sun.COM 503*10499SWilliam.Kucharski@Sun.COM if ((strncmp(optstr, "com1", namlen) == 0) || 504*10499SWilliam.Kucharski@Sun.COM (strncmp(optstr, "com2", namlen) == 0)) { 505*10499SWilliam.Kucharski@Sun.COM unsigned com = COMNAME_TO_COMNUM(optstr); 506*10499SWilliam.Kucharski@Sun.COM 507*10499SWilliam.Kucharski@Sun.COM /* 508*10499SWilliam.Kucharski@Sun.COM * Check if it's "auto" - if so, use the default setting 509*10499SWilliam.Kucharski@Sun.COM * of "9600,8,n,1,-". 510*10499SWilliam.Kucharski@Sun.COM * 511*10499SWilliam.Kucharski@Sun.COM * We can't just assume the serial port will default to 512*10499SWilliam.Kucharski@Sun.COM * "9600,8,n,1" as there could be a directive in bootenv.rc 513*10499SWilliam.Kucharski@Sun.COM * that would set it to some other value and we want the serial 514*10499SWilliam.Kucharski@Sun.COM * parameters to be the same as that used by the hypervisor. 515*10499SWilliam.Kucharski@Sun.COM */ 516*10499SWilliam.Kucharski@Sun.COM if (strcmp(value, "auto") == 0) { 517*10499SWilliam.Kucharski@Sun.COM (void) snprintf(ser, SER_LEN, 518*10499SWilliam.Kucharski@Sun.COM "tty%c-mode='9600,8,n,1,-'", '`' + com); 519*10499SWilliam.Kucharski@Sun.COM 520*10499SWilliam.Kucharski@Sun.COM if (set_serial_rate(com, ser) != 0) 521*10499SWilliam.Kucharski@Sun.COM return (-1); 522*10499SWilliam.Kucharski@Sun.COM 523*10499SWilliam.Kucharski@Sun.COM return (0); 524*10499SWilliam.Kucharski@Sun.COM } 525*10499SWilliam.Kucharski@Sun.COM 526*10499SWilliam.Kucharski@Sun.COM /* 527*10499SWilliam.Kucharski@Sun.COM * Extract the "B,PS" setting from the com line; ignore other 528*10499SWilliam.Kucharski@Sun.COM * settings like io_base or IRQ. 529*10499SWilliam.Kucharski@Sun.COM */ 530*10499SWilliam.Kucharski@Sun.COM if (sscanf(value, "%u,%c%c%c", &baud, &bits, &parity, 531*10499SWilliam.Kucharski@Sun.COM &stop) != 4) 532*10499SWilliam.Kucharski@Sun.COM return (-1); 533*10499SWilliam.Kucharski@Sun.COM 534*10499SWilliam.Kucharski@Sun.COM /* validate serial port parameters */ 535*10499SWilliam.Kucharski@Sun.COM if (((stop != '0') && (stop != '1')) || 536*10499SWilliam.Kucharski@Sun.COM ((bits < '5') && (bits > '8')) || 537*10499SWilliam.Kucharski@Sun.COM ((parity != 'n') && (parity != 'e') && (parity != 'o'))) 538*10499SWilliam.Kucharski@Sun.COM return (-1); 539*10499SWilliam.Kucharski@Sun.COM 540*10499SWilliam.Kucharski@Sun.COM /* validate baud rate */ 541*10499SWilliam.Kucharski@Sun.COM switch (baud) { 542*10499SWilliam.Kucharski@Sun.COM case 150: 543*10499SWilliam.Kucharski@Sun.COM case 300: 544*10499SWilliam.Kucharski@Sun.COM case 600: 545*10499SWilliam.Kucharski@Sun.COM case 1200: 546*10499SWilliam.Kucharski@Sun.COM case 2400: 547*10499SWilliam.Kucharski@Sun.COM case 4800: 548*10499SWilliam.Kucharski@Sun.COM case 19200: 549*10499SWilliam.Kucharski@Sun.COM case 38400: 550*10499SWilliam.Kucharski@Sun.COM case 57600: 551*10499SWilliam.Kucharski@Sun.COM case 115200: 552*10499SWilliam.Kucharski@Sun.COM break; 553*10499SWilliam.Kucharski@Sun.COM 554*10499SWilliam.Kucharski@Sun.COM default: 555*10499SWilliam.Kucharski@Sun.COM return (-1); 556*10499SWilliam.Kucharski@Sun.COM } 557*10499SWilliam.Kucharski@Sun.COM 558*10499SWilliam.Kucharski@Sun.COM /* 559*10499SWilliam.Kucharski@Sun.COM * As the hypervisor has no way to denote handshaking in its 560*10499SWilliam.Kucharski@Sun.COM * serial port settings, emit a metal serial port configuration 561*10499SWilliam.Kucharski@Sun.COM * with none as well. 562*10499SWilliam.Kucharski@Sun.COM */ 563*10499SWilliam.Kucharski@Sun.COM (void) snprintf(ser, SER_LEN, "tty%c-mode='%u,%c,%c,%c,-'", 564*10499SWilliam.Kucharski@Sun.COM '`' + com, baud, bits, parity, stop); 565*10499SWilliam.Kucharski@Sun.COM 566*10499SWilliam.Kucharski@Sun.COM if (set_serial_rate(com, ser) != 0) 567*10499SWilliam.Kucharski@Sun.COM return (-1); 568*10499SWilliam.Kucharski@Sun.COM 569*10499SWilliam.Kucharski@Sun.COM return (0); 570*10499SWilliam.Kucharski@Sun.COM } 571*10499SWilliam.Kucharski@Sun.COM 572*10499SWilliam.Kucharski@Sun.COM return (1); 573*10499SWilliam.Kucharski@Sun.COM } 574*10499SWilliam.Kucharski@Sun.COM 575*10499SWilliam.Kucharski@Sun.COM /* 576*10499SWilliam.Kucharski@Sun.COM * Parse a hardware kernel's "kernel$" specifier into parameters we can then 577*10499SWilliam.Kucharski@Sun.COM * use to construct an appropriate "module$" line that can be used to specify 578*10499SWilliam.Kucharski@Sun.COM * how to boot the hypervisor's dom0. 579*10499SWilliam.Kucharski@Sun.COM * 580*10499SWilliam.Kucharski@Sun.COM * Return 0 on success, non-zero on failure. 581*10499SWilliam.Kucharski@Sun.COM */ 582*10499SWilliam.Kucharski@Sun.COM static int 583*10499SWilliam.Kucharski@Sun.COM cvt_metal_kernel(char *kernstr, char **path) 584*10499SWilliam.Kucharski@Sun.COM { 585*10499SWilliam.Kucharski@Sun.COM char *token, *parsestr; 586*10499SWilliam.Kucharski@Sun.COM 587*10499SWilliam.Kucharski@Sun.COM if ((parsestr = get_token(path, kernstr, " \t,")) == NULL) 588*10499SWilliam.Kucharski@Sun.COM return (*path == NULL); 589*10499SWilliam.Kucharski@Sun.COM 590*10499SWilliam.Kucharski@Sun.COM /* 591*10499SWilliam.Kucharski@Sun.COM * If the metal kernel specified contains the name of the hypervisor, 592*10499SWilliam.Kucharski@Sun.COM * we're probably trying to convert an entry already setup to run the 593*10499SWilliam.Kucharski@Sun.COM * hypervisor, so error out now. 594*10499SWilliam.Kucharski@Sun.COM */ 595*10499SWilliam.Kucharski@Sun.COM if (strstr(*path, XEN_MENU) != NULL) { 596*10499SWilliam.Kucharski@Sun.COM bam_error(ALREADY_HYPER); 597*10499SWilliam.Kucharski@Sun.COM return (-1); 598*10499SWilliam.Kucharski@Sun.COM } 599*10499SWilliam.Kucharski@Sun.COM 600*10499SWilliam.Kucharski@Sun.COM /* if the path was the last item on the line, that's OK. */ 601*10499SWilliam.Kucharski@Sun.COM if ((parsestr = get_token(&token, parsestr, " \t,")) == NULL) { 602*10499SWilliam.Kucharski@Sun.COM if (token != NULL) 603*10499SWilliam.Kucharski@Sun.COM free(token); 604*10499SWilliam.Kucharski@Sun.COM return (0); 605*10499SWilliam.Kucharski@Sun.COM } 606*10499SWilliam.Kucharski@Sun.COM 607*10499SWilliam.Kucharski@Sun.COM /* if the next token is "-B" process boot options */ 608*10499SWilliam.Kucharski@Sun.COM if (strncmp(token, BFLAG, strlen(BFLAG)) != 0) { 609*10499SWilliam.Kucharski@Sun.COM free(token); 610*10499SWilliam.Kucharski@Sun.COM return (0); 611*10499SWilliam.Kucharski@Sun.COM } 612*10499SWilliam.Kucharski@Sun.COM 613*10499SWilliam.Kucharski@Sun.COM while ((parsestr = get_token(&token, parsestr, ",")) != NULL) { 614*10499SWilliam.Kucharski@Sun.COM (void) cvt_metal_option(token); 615*10499SWilliam.Kucharski@Sun.COM free(token); 616*10499SWilliam.Kucharski@Sun.COM } 617*10499SWilliam.Kucharski@Sun.COM 618*10499SWilliam.Kucharski@Sun.COM if (token != NULL) { 619*10499SWilliam.Kucharski@Sun.COM (void) cvt_metal_option(token); 620*10499SWilliam.Kucharski@Sun.COM free(token); 621*10499SWilliam.Kucharski@Sun.COM } 622*10499SWilliam.Kucharski@Sun.COM 623*10499SWilliam.Kucharski@Sun.COM return (0); 624*10499SWilliam.Kucharski@Sun.COM } 625*10499SWilliam.Kucharski@Sun.COM 626*10499SWilliam.Kucharski@Sun.COM /* 627*10499SWilliam.Kucharski@Sun.COM * Parse a hypervisor's "kernel$" line into parameters that can be used to 628*10499SWilliam.Kucharski@Sun.COM * help build an appropriate "kernel$" line for booting a bare metal kernel. 629*10499SWilliam.Kucharski@Sun.COM * 630*10499SWilliam.Kucharski@Sun.COM * Return 0 on success, non-zero on failure. 631*10499SWilliam.Kucharski@Sun.COM */ 632*10499SWilliam.Kucharski@Sun.COM static int 633*10499SWilliam.Kucharski@Sun.COM cvt_hyper_kernel(char *kernel) 634*10499SWilliam.Kucharski@Sun.COM { 635*10499SWilliam.Kucharski@Sun.COM char *token, *parsestr; 636*10499SWilliam.Kucharski@Sun.COM 637*10499SWilliam.Kucharski@Sun.COM /* eat the kernel path, which should be the first token */ 638*10499SWilliam.Kucharski@Sun.COM if ((parsestr = get_token(&token, kernel, " \t,")) == NULL) 639*10499SWilliam.Kucharski@Sun.COM return (0); 640*10499SWilliam.Kucharski@Sun.COM 641*10499SWilliam.Kucharski@Sun.COM /* 642*10499SWilliam.Kucharski@Sun.COM * If the hypervisor kernel specified lives in the metal kernel 643*10499SWilliam.Kucharski@Sun.COM * directory, we're probably trying to convert an entry already setup 644*10499SWilliam.Kucharski@Sun.COM * to run on bare metal, so error out now. 645*10499SWilliam.Kucharski@Sun.COM */ 646*10499SWilliam.Kucharski@Sun.COM if (strncmp(token, METAL_KERNEL_DIR, strlen(METAL_KERNEL_DIR)) == 0) { 647*10499SWilliam.Kucharski@Sun.COM bam_error(ALREADY_METAL); 648*10499SWilliam.Kucharski@Sun.COM (void) free(token); 649*10499SWilliam.Kucharski@Sun.COM return (-1); 650*10499SWilliam.Kucharski@Sun.COM } 651*10499SWilliam.Kucharski@Sun.COM 652*10499SWilliam.Kucharski@Sun.COM /* if the path was the last item on the line, that's OK. */ 653*10499SWilliam.Kucharski@Sun.COM free(token); 654*10499SWilliam.Kucharski@Sun.COM 655*10499SWilliam.Kucharski@Sun.COM /* check for kernel options */ 656*10499SWilliam.Kucharski@Sun.COM while ((parsestr = get_token(&token, parsestr, " ")) != NULL) { 657*10499SWilliam.Kucharski@Sun.COM (void) cvt_hyper_option(token); 658*10499SWilliam.Kucharski@Sun.COM free(token); 659*10499SWilliam.Kucharski@Sun.COM } 660*10499SWilliam.Kucharski@Sun.COM 661*10499SWilliam.Kucharski@Sun.COM if (token != NULL) { 662*10499SWilliam.Kucharski@Sun.COM (void) cvt_hyper_option(token); 663*10499SWilliam.Kucharski@Sun.COM free(token); 664*10499SWilliam.Kucharski@Sun.COM } 665*10499SWilliam.Kucharski@Sun.COM 666*10499SWilliam.Kucharski@Sun.COM return (0); 667*10499SWilliam.Kucharski@Sun.COM } 668*10499SWilliam.Kucharski@Sun.COM 669*10499SWilliam.Kucharski@Sun.COM /* 670*10499SWilliam.Kucharski@Sun.COM * Parse a hypervisor's "module$" line into parameters that can be used to 671*10499SWilliam.Kucharski@Sun.COM * help build an appropriate "kernel$" line for booting a bare metal kernel. 672*10499SWilliam.Kucharski@Sun.COM */ 673*10499SWilliam.Kucharski@Sun.COM static void 674*10499SWilliam.Kucharski@Sun.COM cvt_hyper_module(char *modstr, char **path) 675*10499SWilliam.Kucharski@Sun.COM { 676*10499SWilliam.Kucharski@Sun.COM char *token; 677*10499SWilliam.Kucharski@Sun.COM char *parsestr = modstr; 678*10499SWilliam.Kucharski@Sun.COM 679*10499SWilliam.Kucharski@Sun.COM /* 680*10499SWilliam.Kucharski@Sun.COM * If multiple pathnames exist on the module$ line, we just want 681*10499SWilliam.Kucharski@Sun.COM * the last one. 682*10499SWilliam.Kucharski@Sun.COM */ 683*10499SWilliam.Kucharski@Sun.COM while ((parsestr = get_token(path, parsestr, " \t,")) != NULL) { 684*10499SWilliam.Kucharski@Sun.COM if (*parsestr != '/') 685*10499SWilliam.Kucharski@Sun.COM break; 686*10499SWilliam.Kucharski@Sun.COM 687*10499SWilliam.Kucharski@Sun.COM free(*path); 688*10499SWilliam.Kucharski@Sun.COM } 689*10499SWilliam.Kucharski@Sun.COM 690*10499SWilliam.Kucharski@Sun.COM /* if the path was the last item on the line, that's OK. */ 691*10499SWilliam.Kucharski@Sun.COM if ((parsestr == NULL) || 692*10499SWilliam.Kucharski@Sun.COM ((parsestr = get_token(&token, parsestr, " \t,")) == NULL)) { 693*10499SWilliam.Kucharski@Sun.COM if (token != NULL) 694*10499SWilliam.Kucharski@Sun.COM free(token); 695*10499SWilliam.Kucharski@Sun.COM return; 696*10499SWilliam.Kucharski@Sun.COM } 697*10499SWilliam.Kucharski@Sun.COM 698*10499SWilliam.Kucharski@Sun.COM /* check for "-B" option */ 699*10499SWilliam.Kucharski@Sun.COM if (strncmp(token, BFLAG, strlen(BFLAG)) != 0) { 700*10499SWilliam.Kucharski@Sun.COM free(token); 701*10499SWilliam.Kucharski@Sun.COM return; 702*10499SWilliam.Kucharski@Sun.COM } 703*10499SWilliam.Kucharski@Sun.COM 704*10499SWilliam.Kucharski@Sun.COM /* check for kernel options */ 705*10499SWilliam.Kucharski@Sun.COM while ((parsestr = get_token(&token, parsestr, ",")) != NULL) { 706*10499SWilliam.Kucharski@Sun.COM (void) cvt_hyper_option(token); 707*10499SWilliam.Kucharski@Sun.COM free(token); 708*10499SWilliam.Kucharski@Sun.COM } 709*10499SWilliam.Kucharski@Sun.COM 710*10499SWilliam.Kucharski@Sun.COM if (token != NULL) { 711*10499SWilliam.Kucharski@Sun.COM (void) cvt_hyper_option(token); 712*10499SWilliam.Kucharski@Sun.COM free(token); 713*10499SWilliam.Kucharski@Sun.COM } 714*10499SWilliam.Kucharski@Sun.COM } 715*10499SWilliam.Kucharski@Sun.COM 716*10499SWilliam.Kucharski@Sun.COM static void 717*10499SWilliam.Kucharski@Sun.COM parse_bootenvrc(char *osroot) 718*10499SWilliam.Kucharski@Sun.COM { 719*10499SWilliam.Kucharski@Sun.COM #define LINEBUF_SZ 1024 720*10499SWilliam.Kucharski@Sun.COM 721*10499SWilliam.Kucharski@Sun.COM FILE *fp; 722*10499SWilliam.Kucharski@Sun.COM char *rcpath; 723*10499SWilliam.Kucharski@Sun.COM char line[LINEBUF_SZ]; /* make line buffer large but not ridiculous */ 724*10499SWilliam.Kucharski@Sun.COM int len; 725*10499SWilliam.Kucharski@Sun.COM 726*10499SWilliam.Kucharski@Sun.COM assert(osroot); 727*10499SWilliam.Kucharski@Sun.COM 728*10499SWilliam.Kucharski@Sun.COM len = strlen(osroot) + strlen(BOOTRC_FILE) + 1; 729*10499SWilliam.Kucharski@Sun.COM rcpath = alloca(len); 730*10499SWilliam.Kucharski@Sun.COM (void) snprintf(rcpath, len, "%s%s", osroot, BOOTRC_FILE); 731*10499SWilliam.Kucharski@Sun.COM 732*10499SWilliam.Kucharski@Sun.COM /* if we couldn't open the bootenv.rc file, ignore the issue. */ 733*10499SWilliam.Kucharski@Sun.COM if ((fp = fopen(rcpath, "r")) == NULL) { 734*10499SWilliam.Kucharski@Sun.COM BAM_DPRINTF((D_NO_BOOTENVRC, rcpath, strerror(errno))); 735*10499SWilliam.Kucharski@Sun.COM return; 736*10499SWilliam.Kucharski@Sun.COM } 737*10499SWilliam.Kucharski@Sun.COM 738*10499SWilliam.Kucharski@Sun.COM while (s_fgets(line, LINEBUF_SZ, fp) != NULL) { 739*10499SWilliam.Kucharski@Sun.COM /* we're only interested in parsing "setprop" directives. */ 740*10499SWilliam.Kucharski@Sun.COM if (strncmp(line, "setprop", 7) != NULL) 741*10499SWilliam.Kucharski@Sun.COM continue; 742*10499SWilliam.Kucharski@Sun.COM 743*10499SWilliam.Kucharski@Sun.COM (void) cvt_bootprop(line); 744*10499SWilliam.Kucharski@Sun.COM } 745*10499SWilliam.Kucharski@Sun.COM 746*10499SWilliam.Kucharski@Sun.COM (void) fclose(fp); 747*10499SWilliam.Kucharski@Sun.COM } 748*10499SWilliam.Kucharski@Sun.COM 749*10499SWilliam.Kucharski@Sun.COM error_t 750*10499SWilliam.Kucharski@Sun.COM cvt_to_hyper(menu_t *mp, char *osroot, char *extra_args) 751*10499SWilliam.Kucharski@Sun.COM { 752*10499SWilliam.Kucharski@Sun.COM const char *fcn = "cvt_to_hyper()"; 753*10499SWilliam.Kucharski@Sun.COM 754*10499SWilliam.Kucharski@Sun.COM line_t *lp; 755*10499SWilliam.Kucharski@Sun.COM entry_t *ent; 756*10499SWilliam.Kucharski@Sun.COM size_t len, zfslen; 757*10499SWilliam.Kucharski@Sun.COM 758*10499SWilliam.Kucharski@Sun.COM char *osdev; 759*10499SWilliam.Kucharski@Sun.COM 760*10499SWilliam.Kucharski@Sun.COM char *title = NULL; 761*10499SWilliam.Kucharski@Sun.COM char *findroot = NULL; 762*10499SWilliam.Kucharski@Sun.COM char *bootfs = NULL; 763*10499SWilliam.Kucharski@Sun.COM char *kernel = NULL; 764*10499SWilliam.Kucharski@Sun.COM char *mod_kernel = NULL; 765*10499SWilliam.Kucharski@Sun.COM char *module = NULL; 766*10499SWilliam.Kucharski@Sun.COM 767*10499SWilliam.Kucharski@Sun.COM char *kern_path = NULL; 768*10499SWilliam.Kucharski@Sun.COM char *kern_bargs = NULL; 769*10499SWilliam.Kucharski@Sun.COM 770*10499SWilliam.Kucharski@Sun.COM int curdef; 771*10499SWilliam.Kucharski@Sun.COM int kp_allocated = 1; 772*10499SWilliam.Kucharski@Sun.COM int ret = BAM_ERROR; 773*10499SWilliam.Kucharski@Sun.COM 774*10499SWilliam.Kucharski@Sun.COM assert(osroot); 775*10499SWilliam.Kucharski@Sun.COM 776*10499SWilliam.Kucharski@Sun.COM BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, extra_args)); 777*10499SWilliam.Kucharski@Sun.COM 778*10499SWilliam.Kucharski@Sun.COM /* 779*10499SWilliam.Kucharski@Sun.COM * First just check to verify osroot is a sane directory. 780*10499SWilliam.Kucharski@Sun.COM */ 781*10499SWilliam.Kucharski@Sun.COM if ((osdev = get_special(osroot)) == NULL) { 782*10499SWilliam.Kucharski@Sun.COM bam_error(CANT_FIND_SPECIAL, osroot); 783*10499SWilliam.Kucharski@Sun.COM return (BAM_ERROR); 784*10499SWilliam.Kucharski@Sun.COM } 785*10499SWilliam.Kucharski@Sun.COM 786*10499SWilliam.Kucharski@Sun.COM free(osdev); 787*10499SWilliam.Kucharski@Sun.COM 788*10499SWilliam.Kucharski@Sun.COM /* 789*10499SWilliam.Kucharski@Sun.COM * While the effect is purely cosmetic, if osroot is "/" don't 790*10499SWilliam.Kucharski@Sun.COM * bother prepending it to any paths as they are constructed to 791*10499SWilliam.Kucharski@Sun.COM * begin with "/" anyway. 792*10499SWilliam.Kucharski@Sun.COM */ 793*10499SWilliam.Kucharski@Sun.COM if (strcmp(osroot, "/") == 0) 794*10499SWilliam.Kucharski@Sun.COM osroot = ""; 795*10499SWilliam.Kucharski@Sun.COM 796*10499SWilliam.Kucharski@Sun.COM /* 797*10499SWilliam.Kucharski@Sun.COM * Found the GRUB signature on the target partitions, so now get the 798*10499SWilliam.Kucharski@Sun.COM * default GRUB boot entry number from the menu.lst file 799*10499SWilliam.Kucharski@Sun.COM */ 800*10499SWilliam.Kucharski@Sun.COM curdef = atoi(mp->curdefault->arg); 801*10499SWilliam.Kucharski@Sun.COM 802*10499SWilliam.Kucharski@Sun.COM /* look for the first line of the matching boot entry */ 803*10499SWilliam.Kucharski@Sun.COM for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef)); 804*10499SWilliam.Kucharski@Sun.COM ent = ent->next) 805*10499SWilliam.Kucharski@Sun.COM ; 806*10499SWilliam.Kucharski@Sun.COM 807*10499SWilliam.Kucharski@Sun.COM /* couldn't find it, so error out */ 808*10499SWilliam.Kucharski@Sun.COM if (ent == NULL) { 809*10499SWilliam.Kucharski@Sun.COM bam_error(CANT_FIND_DEFAULT, curdef); 810*10499SWilliam.Kucharski@Sun.COM goto abort; 811*10499SWilliam.Kucharski@Sun.COM } 812*10499SWilliam.Kucharski@Sun.COM 813*10499SWilliam.Kucharski@Sun.COM /* 814*10499SWilliam.Kucharski@Sun.COM * We found the proper menu entry, so first we need to process the 815*10499SWilliam.Kucharski@Sun.COM * bootenv.rc file to look for boot options the hypervisor might need 816*10499SWilliam.Kucharski@Sun.COM * passed as kernel start options such as the console device and serial 817*10499SWilliam.Kucharski@Sun.COM * port parameters. 818*10499SWilliam.Kucharski@Sun.COM * 819*10499SWilliam.Kucharski@Sun.COM * If there's no bootenv.rc, it's not an issue. 820*10499SWilliam.Kucharski@Sun.COM */ 821*10499SWilliam.Kucharski@Sun.COM parse_bootenvrc(osroot); 822*10499SWilliam.Kucharski@Sun.COM 823*10499SWilliam.Kucharski@Sun.COM /* 824*10499SWilliam.Kucharski@Sun.COM * Now process the entry itself. 825*10499SWilliam.Kucharski@Sun.COM */ 826*10499SWilliam.Kucharski@Sun.COM for (lp = ent->start; lp != NULL; lp = lp->next) { 827*10499SWilliam.Kucharski@Sun.COM /* 828*10499SWilliam.Kucharski@Sun.COM * Process important lines from menu.lst boot entry. 829*10499SWilliam.Kucharski@Sun.COM */ 830*10499SWilliam.Kucharski@Sun.COM if (lp->flags == BAM_TITLE) { 831*10499SWilliam.Kucharski@Sun.COM title = alloca(strlen(lp->arg) + 1); 832*10499SWilliam.Kucharski@Sun.COM (void) strcpy(title, lp->arg); 833*10499SWilliam.Kucharski@Sun.COM } else if (strcmp(lp->cmd, "findroot") == 0) { 834*10499SWilliam.Kucharski@Sun.COM findroot = alloca(strlen(lp->arg) + 1); 835*10499SWilliam.Kucharski@Sun.COM (void) strcpy(findroot, lp->arg); 836*10499SWilliam.Kucharski@Sun.COM } else if (strcmp(lp->cmd, "bootfs") == 0) { 837*10499SWilliam.Kucharski@Sun.COM bootfs = alloca(strlen(lp->arg) + 1); 838*10499SWilliam.Kucharski@Sun.COM (void) strcpy(bootfs, lp->arg); 839*10499SWilliam.Kucharski@Sun.COM } else if (strcmp(lp->cmd, menu_cmds[MODULE_DOLLAR_CMD]) == 0) { 840*10499SWilliam.Kucharski@Sun.COM module = alloca(strlen(lp->arg) + 1); 841*10499SWilliam.Kucharski@Sun.COM (void) strcpy(module, lp->arg); 842*10499SWilliam.Kucharski@Sun.COM } else if ((strcmp(lp->cmd, 843*10499SWilliam.Kucharski@Sun.COM menu_cmds[KERNEL_DOLLAR_CMD]) == 0) && 844*10499SWilliam.Kucharski@Sun.COM (cvt_metal_kernel(lp->arg, &kern_path) < 0)) { 845*10499SWilliam.Kucharski@Sun.COM ret = BAM_NOCHANGE; 846*10499SWilliam.Kucharski@Sun.COM goto abort; 847*10499SWilliam.Kucharski@Sun.COM } 848*10499SWilliam.Kucharski@Sun.COM 849*10499SWilliam.Kucharski@Sun.COM if (lp == ent->end) 850*10499SWilliam.Kucharski@Sun.COM break; 851*10499SWilliam.Kucharski@Sun.COM } 852*10499SWilliam.Kucharski@Sun.COM 853*10499SWilliam.Kucharski@Sun.COM /* 854*10499SWilliam.Kucharski@Sun.COM * If findroot, module or kern_path are NULL, boot entry was malformed 855*10499SWilliam.Kucharski@Sun.COM */ 856*10499SWilliam.Kucharski@Sun.COM if (findroot == NULL) { 857*10499SWilliam.Kucharski@Sun.COM bam_error(FINDROOT_NOT_FOUND, curdef); 858*10499SWilliam.Kucharski@Sun.COM goto abort; 859*10499SWilliam.Kucharski@Sun.COM } 860*10499SWilliam.Kucharski@Sun.COM 861*10499SWilliam.Kucharski@Sun.COM if (module == NULL) { 862*10499SWilliam.Kucharski@Sun.COM bam_error(MODULE_NOT_PARSEABLE, curdef); 863*10499SWilliam.Kucharski@Sun.COM goto abort; 864*10499SWilliam.Kucharski@Sun.COM } 865*10499SWilliam.Kucharski@Sun.COM 866*10499SWilliam.Kucharski@Sun.COM if (kern_path == NULL) { 867*10499SWilliam.Kucharski@Sun.COM bam_error(KERNEL_NOT_FOUND, curdef); 868*10499SWilliam.Kucharski@Sun.COM goto abort; 869*10499SWilliam.Kucharski@Sun.COM } 870*10499SWilliam.Kucharski@Sun.COM 871*10499SWilliam.Kucharski@Sun.COM /* assemble new kernel and module arguments from parsed values */ 872*10499SWilliam.Kucharski@Sun.COM if (console_dev != NULL) { 873*10499SWilliam.Kucharski@Sun.COM kern_bargs = s_strdup(console_dev); 874*10499SWilliam.Kucharski@Sun.COM 875*10499SWilliam.Kucharski@Sun.COM if (serial_config[0] != NULL) 876*10499SWilliam.Kucharski@Sun.COM kern_bargs = append_str(kern_bargs, serial_config[0], 877*10499SWilliam.Kucharski@Sun.COM " "); 878*10499SWilliam.Kucharski@Sun.COM 879*10499SWilliam.Kucharski@Sun.COM if (serial_config[1] != NULL) 880*10499SWilliam.Kucharski@Sun.COM kern_bargs = append_str(kern_bargs, serial_config[1], 881*10499SWilliam.Kucharski@Sun.COM " "); 882*10499SWilliam.Kucharski@Sun.COM } 883*10499SWilliam.Kucharski@Sun.COM 884*10499SWilliam.Kucharski@Sun.COM if ((extra_args != NULL) && (*extra_args != NULL)) 885*10499SWilliam.Kucharski@Sun.COM kern_bargs = append_str(kern_bargs, extra_args, " "); 886*10499SWilliam.Kucharski@Sun.COM 887*10499SWilliam.Kucharski@Sun.COM len = strlen(osroot) + strlen(XEN_MENU) + strlen(kern_bargs) + 888*10499SWilliam.Kucharski@Sun.COM WHITESPC(1) + 1; 889*10499SWilliam.Kucharski@Sun.COM 890*10499SWilliam.Kucharski@Sun.COM kernel = alloca(len); 891*10499SWilliam.Kucharski@Sun.COM 892*10499SWilliam.Kucharski@Sun.COM if ((kern_bargs != NULL) && (*kern_bargs != NULL)) { 893*10499SWilliam.Kucharski@Sun.COM (void) snprintf(kernel, len, "%s%s %s", osroot, XEN_MENU, 894*10499SWilliam.Kucharski@Sun.COM kern_bargs); 895*10499SWilliam.Kucharski@Sun.COM free(kern_bargs); 896*10499SWilliam.Kucharski@Sun.COM } else { 897*10499SWilliam.Kucharski@Sun.COM (void) snprintf(kernel, len, "%s%s", osroot, XEN_MENU); 898*10499SWilliam.Kucharski@Sun.COM } 899*10499SWilliam.Kucharski@Sun.COM 900*10499SWilliam.Kucharski@Sun.COM /* 901*10499SWilliam.Kucharski@Sun.COM * Change the kernel directory from the metal version to that needed for 902*10499SWilliam.Kucharski@Sun.COM * the hypervisor. Convert either "direct boot" path to the default 903*10499SWilliam.Kucharski@Sun.COM * path. 904*10499SWilliam.Kucharski@Sun.COM */ 905*10499SWilliam.Kucharski@Sun.COM if ((strcmp(kern_path, DIRECT_BOOT_32) == 0) || 906*10499SWilliam.Kucharski@Sun.COM (strcmp(kern_path, DIRECT_BOOT_64) == 0)) { 907*10499SWilliam.Kucharski@Sun.COM kern_path = HYPERVISOR_KERNEL; 908*10499SWilliam.Kucharski@Sun.COM kp_allocated = 0; 909*10499SWilliam.Kucharski@Sun.COM } else { 910*10499SWilliam.Kucharski@Sun.COM kern_path = modify_path(kern_path, METAL_KERNEL_DIR, 911*10499SWilliam.Kucharski@Sun.COM HYPER_KERNEL_DIR); 912*10499SWilliam.Kucharski@Sun.COM } 913*10499SWilliam.Kucharski@Sun.COM 914*10499SWilliam.Kucharski@Sun.COM /* 915*10499SWilliam.Kucharski@Sun.COM * We need to allocate space for the kernel path (twice) plus an 916*10499SWilliam.Kucharski@Sun.COM * intervening space, possibly the ZFS boot string, and NULL, 917*10499SWilliam.Kucharski@Sun.COM * of course. 918*10499SWilliam.Kucharski@Sun.COM */ 919*10499SWilliam.Kucharski@Sun.COM len = (strlen(kern_path) * 2) + WHITESPC(1) + 1; 920*10499SWilliam.Kucharski@Sun.COM zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0); 921*10499SWilliam.Kucharski@Sun.COM 922*10499SWilliam.Kucharski@Sun.COM mod_kernel = alloca(len + zfslen); 923*10499SWilliam.Kucharski@Sun.COM 924*10499SWilliam.Kucharski@Sun.COM (void) snprintf(mod_kernel, len, "%s %s", kern_path, kern_path); 925*10499SWilliam.Kucharski@Sun.COM 926*10499SWilliam.Kucharski@Sun.COM if (kp_allocated) 927*10499SWilliam.Kucharski@Sun.COM free(kern_path); 928*10499SWilliam.Kucharski@Sun.COM 929*10499SWilliam.Kucharski@Sun.COM if (zfs_boot) { 930*10499SWilliam.Kucharski@Sun.COM char *zfsstr = alloca(zfslen + 1); 931*10499SWilliam.Kucharski@Sun.COM 932*10499SWilliam.Kucharski@Sun.COM (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT); 933*10499SWilliam.Kucharski@Sun.COM (void) strcat(mod_kernel, zfsstr); 934*10499SWilliam.Kucharski@Sun.COM } 935*10499SWilliam.Kucharski@Sun.COM 936*10499SWilliam.Kucharski@Sun.COM /* shut off warning messages from the entry line parser */ 937*10499SWilliam.Kucharski@Sun.COM if (ent->flags & BAM_ENTRY_BOOTADM) 938*10499SWilliam.Kucharski@Sun.COM ent->flags &= ~BAM_ENTRY_BOOTADM; 939*10499SWilliam.Kucharski@Sun.COM 940*10499SWilliam.Kucharski@Sun.COM BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, kernel)); 941*10499SWilliam.Kucharski@Sun.COM BAM_DPRINTF((D_CVT_CMD_MOD_DOLLAR, fcn, mod_kernel)); 942*10499SWilliam.Kucharski@Sun.COM 943*10499SWilliam.Kucharski@Sun.COM /* 944*10499SWilliam.Kucharski@Sun.COM * Now try to delete the current default entry from the menu and add 945*10499SWilliam.Kucharski@Sun.COM * the new hypervisor entry with the parameters we've setup. 946*10499SWilliam.Kucharski@Sun.COM */ 947*10499SWilliam.Kucharski@Sun.COM if (delete_boot_entry(mp, curdef, DBE_QUIET) != BAM_SUCCESS) 948*10499SWilliam.Kucharski@Sun.COM bam_print(NEW_BOOT_ENTRY, title); 949*10499SWilliam.Kucharski@Sun.COM 950*10499SWilliam.Kucharski@Sun.COM curdef = add_boot_entry(mp, title, findroot, kernel, mod_kernel, 951*10499SWilliam.Kucharski@Sun.COM module, bootfs); 952*10499SWilliam.Kucharski@Sun.COM 953*10499SWilliam.Kucharski@Sun.COM /* 954*10499SWilliam.Kucharski@Sun.COM * If we successfully created the new entry, set the default boot 955*10499SWilliam.Kucharski@Sun.COM * entry to that entry and let the caller know the new menu should 956*10499SWilliam.Kucharski@Sun.COM * be written out. 957*10499SWilliam.Kucharski@Sun.COM */ 958*10499SWilliam.Kucharski@Sun.COM if (curdef != BAM_ERROR) 959*10499SWilliam.Kucharski@Sun.COM return (set_global(mp, menu_cmds[DEFAULT_CMD], curdef)); 960*10499SWilliam.Kucharski@Sun.COM 961*10499SWilliam.Kucharski@Sun.COM return (BAM_ERROR); 962*10499SWilliam.Kucharski@Sun.COM 963*10499SWilliam.Kucharski@Sun.COM abort: 964*10499SWilliam.Kucharski@Sun.COM if ((kp_allocated) && (kern_path != NULL)) 965*10499SWilliam.Kucharski@Sun.COM free(kern_path); 966*10499SWilliam.Kucharski@Sun.COM 967*10499SWilliam.Kucharski@Sun.COM if (ret != BAM_NOCHANGE) 968*10499SWilliam.Kucharski@Sun.COM bam_error(HYPER_ABORT, ((*osroot == NULL) ? "/" : osroot)); 969*10499SWilliam.Kucharski@Sun.COM 970*10499SWilliam.Kucharski@Sun.COM return (ret); 971*10499SWilliam.Kucharski@Sun.COM } 972*10499SWilliam.Kucharski@Sun.COM 973*10499SWilliam.Kucharski@Sun.COM /*ARGSUSED*/ 974*10499SWilliam.Kucharski@Sun.COM error_t 975*10499SWilliam.Kucharski@Sun.COM cvt_to_metal(menu_t *mp, char *osroot, char *menu_root) 976*10499SWilliam.Kucharski@Sun.COM { 977*10499SWilliam.Kucharski@Sun.COM const char *fcn = "cvt_to_metal()"; 978*10499SWilliam.Kucharski@Sun.COM 979*10499SWilliam.Kucharski@Sun.COM line_t *lp; 980*10499SWilliam.Kucharski@Sun.COM entry_t *ent; 981*10499SWilliam.Kucharski@Sun.COM size_t len, zfslen; 982*10499SWilliam.Kucharski@Sun.COM 983*10499SWilliam.Kucharski@Sun.COM char *delim = ", "; 984*10499SWilliam.Kucharski@Sun.COM char *osdev; 985*10499SWilliam.Kucharski@Sun.COM 986*10499SWilliam.Kucharski@Sun.COM char *title = NULL; 987*10499SWilliam.Kucharski@Sun.COM char *findroot = NULL; 988*10499SWilliam.Kucharski@Sun.COM char *bootfs = NULL; 989*10499SWilliam.Kucharski@Sun.COM char *kernel = NULL; 990*10499SWilliam.Kucharski@Sun.COM char *module = NULL; 991*10499SWilliam.Kucharski@Sun.COM 992*10499SWilliam.Kucharski@Sun.COM char *barchive_path = DIRECT_BOOT_ARCHIVE; 993*10499SWilliam.Kucharski@Sun.COM char *kern_path = NULL; 994*10499SWilliam.Kucharski@Sun.COM 995*10499SWilliam.Kucharski@Sun.COM int curdef; 996*10499SWilliam.Kucharski@Sun.COM int emit_bflag = 1; 997*10499SWilliam.Kucharski@Sun.COM int ret = BAM_ERROR; 998*10499SWilliam.Kucharski@Sun.COM 999*10499SWilliam.Kucharski@Sun.COM assert(osroot); 1000*10499SWilliam.Kucharski@Sun.COM 1001*10499SWilliam.Kucharski@Sun.COM BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, "")); 1002*10499SWilliam.Kucharski@Sun.COM 1003*10499SWilliam.Kucharski@Sun.COM /* 1004*10499SWilliam.Kucharski@Sun.COM * First just check to verify osroot is a sane directory. 1005*10499SWilliam.Kucharski@Sun.COM */ 1006*10499SWilliam.Kucharski@Sun.COM if ((osdev = get_special(osroot)) == NULL) { 1007*10499SWilliam.Kucharski@Sun.COM bam_error(CANT_FIND_SPECIAL, osroot); 1008*10499SWilliam.Kucharski@Sun.COM return (BAM_ERROR); 1009*10499SWilliam.Kucharski@Sun.COM } 1010*10499SWilliam.Kucharski@Sun.COM 1011*10499SWilliam.Kucharski@Sun.COM free(osdev); 1012*10499SWilliam.Kucharski@Sun.COM 1013*10499SWilliam.Kucharski@Sun.COM /* 1014*10499SWilliam.Kucharski@Sun.COM * Found the GRUB signature on the target partitions, so now get the 1015*10499SWilliam.Kucharski@Sun.COM * default GRUB boot entry number from the menu.lst file 1016*10499SWilliam.Kucharski@Sun.COM */ 1017*10499SWilliam.Kucharski@Sun.COM curdef = atoi(mp->curdefault->arg); 1018*10499SWilliam.Kucharski@Sun.COM 1019*10499SWilliam.Kucharski@Sun.COM /* look for the first line of the matching boot entry */ 1020*10499SWilliam.Kucharski@Sun.COM for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef)); 1021*10499SWilliam.Kucharski@Sun.COM ent = ent->next) 1022*10499SWilliam.Kucharski@Sun.COM ; 1023*10499SWilliam.Kucharski@Sun.COM 1024*10499SWilliam.Kucharski@Sun.COM /* couldn't find it, so error out */ 1025*10499SWilliam.Kucharski@Sun.COM if (ent == NULL) { 1026*10499SWilliam.Kucharski@Sun.COM bam_error(CANT_FIND_DEFAULT, curdef); 1027*10499SWilliam.Kucharski@Sun.COM goto abort; 1028*10499SWilliam.Kucharski@Sun.COM } 1029*10499SWilliam.Kucharski@Sun.COM 1030*10499SWilliam.Kucharski@Sun.COM /* 1031*10499SWilliam.Kucharski@Sun.COM * Now process the entry itself. 1032*10499SWilliam.Kucharski@Sun.COM */ 1033*10499SWilliam.Kucharski@Sun.COM for (lp = ent->start; lp != NULL; lp = lp->next) { 1034*10499SWilliam.Kucharski@Sun.COM /* 1035*10499SWilliam.Kucharski@Sun.COM * Process important lines from menu.lst boot entry. 1036*10499SWilliam.Kucharski@Sun.COM */ 1037*10499SWilliam.Kucharski@Sun.COM if (lp->flags == BAM_TITLE) { 1038*10499SWilliam.Kucharski@Sun.COM title = alloca(strlen(lp->arg) + 1); 1039*10499SWilliam.Kucharski@Sun.COM (void) strcpy(title, lp->arg); 1040*10499SWilliam.Kucharski@Sun.COM } else if (strcmp(lp->cmd, "findroot") == 0) { 1041*10499SWilliam.Kucharski@Sun.COM findroot = alloca(strlen(lp->arg) + 1); 1042*10499SWilliam.Kucharski@Sun.COM (void) strcpy(findroot, lp->arg); 1043*10499SWilliam.Kucharski@Sun.COM } else if (strcmp(lp->cmd, "bootfs") == 0) { 1044*10499SWilliam.Kucharski@Sun.COM bootfs = alloca(strlen(lp->arg) + 1); 1045*10499SWilliam.Kucharski@Sun.COM (void) strcpy(bootfs, lp->arg); 1046*10499SWilliam.Kucharski@Sun.COM } else if (strcmp(lp->cmd, menu_cmds[MODULE_DOLLAR_CMD]) == 0) { 1047*10499SWilliam.Kucharski@Sun.COM if (strstr(lp->arg, "boot_archive") == NULL) { 1048*10499SWilliam.Kucharski@Sun.COM module = alloca(strlen(lp->arg) + 1); 1049*10499SWilliam.Kucharski@Sun.COM (void) strcpy(module, lp->arg); 1050*10499SWilliam.Kucharski@Sun.COM cvt_hyper_module(module, &kern_path); 1051*10499SWilliam.Kucharski@Sun.COM } else { 1052*10499SWilliam.Kucharski@Sun.COM barchive_path = alloca(strlen(lp->arg) + 1); 1053*10499SWilliam.Kucharski@Sun.COM (void) strcpy(barchive_path, lp->arg); 1054*10499SWilliam.Kucharski@Sun.COM } 1055*10499SWilliam.Kucharski@Sun.COM } else if ((strcmp(lp->cmd, 1056*10499SWilliam.Kucharski@Sun.COM menu_cmds[KERNEL_DOLLAR_CMD]) == 0) && 1057*10499SWilliam.Kucharski@Sun.COM (cvt_hyper_kernel(lp->arg) < 0)) { 1058*10499SWilliam.Kucharski@Sun.COM ret = BAM_NOCHANGE; 1059*10499SWilliam.Kucharski@Sun.COM goto abort; 1060*10499SWilliam.Kucharski@Sun.COM } 1061*10499SWilliam.Kucharski@Sun.COM 1062*10499SWilliam.Kucharski@Sun.COM if (lp == ent->end) 1063*10499SWilliam.Kucharski@Sun.COM break; 1064*10499SWilliam.Kucharski@Sun.COM } 1065*10499SWilliam.Kucharski@Sun.COM 1066*10499SWilliam.Kucharski@Sun.COM /* 1067*10499SWilliam.Kucharski@Sun.COM * If findroot, module or kern_path are NULL, boot entry was malformed 1068*10499SWilliam.Kucharski@Sun.COM */ 1069*10499SWilliam.Kucharski@Sun.COM if (findroot == NULL) { 1070*10499SWilliam.Kucharski@Sun.COM bam_error(FINDROOT_NOT_FOUND, curdef); 1071*10499SWilliam.Kucharski@Sun.COM goto abort; 1072*10499SWilliam.Kucharski@Sun.COM } 1073*10499SWilliam.Kucharski@Sun.COM 1074*10499SWilliam.Kucharski@Sun.COM if (module == NULL) { 1075*10499SWilliam.Kucharski@Sun.COM bam_error(MODULE_NOT_PARSEABLE, curdef); 1076*10499SWilliam.Kucharski@Sun.COM goto abort; 1077*10499SWilliam.Kucharski@Sun.COM } 1078*10499SWilliam.Kucharski@Sun.COM 1079*10499SWilliam.Kucharski@Sun.COM if (kern_path == NULL) { 1080*10499SWilliam.Kucharski@Sun.COM bam_error(KERNEL_NOT_FOUND, curdef); 1081*10499SWilliam.Kucharski@Sun.COM goto abort; 1082*10499SWilliam.Kucharski@Sun.COM } 1083*10499SWilliam.Kucharski@Sun.COM 1084*10499SWilliam.Kucharski@Sun.COM /* 1085*10499SWilliam.Kucharski@Sun.COM * Assemble new kernel and module arguments from parsed values. 1086*10499SWilliam.Kucharski@Sun.COM * 1087*10499SWilliam.Kucharski@Sun.COM * First, change the kernel directory from the hypervisor version to 1088*10499SWilliam.Kucharski@Sun.COM * that needed for a metal kernel. 1089*10499SWilliam.Kucharski@Sun.COM */ 1090*10499SWilliam.Kucharski@Sun.COM kern_path = modify_path(kern_path, HYPER_KERNEL_DIR, METAL_KERNEL_DIR); 1091*10499SWilliam.Kucharski@Sun.COM 1092*10499SWilliam.Kucharski@Sun.COM /* allocate initial space for the kernel path */ 1093*10499SWilliam.Kucharski@Sun.COM len = strlen(kern_path) + 1; 1094*10499SWilliam.Kucharski@Sun.COM zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0); 1095*10499SWilliam.Kucharski@Sun.COM 1096*10499SWilliam.Kucharski@Sun.COM if ((kernel = malloc(len + zfslen)) == NULL) { 1097*10499SWilliam.Kucharski@Sun.COM free(kern_path); 1098*10499SWilliam.Kucharski@Sun.COM bam_error(NO_MEM, len); 1099*10499SWilliam.Kucharski@Sun.COM goto abort; 1100*10499SWilliam.Kucharski@Sun.COM } 1101*10499SWilliam.Kucharski@Sun.COM 1102*10499SWilliam.Kucharski@Sun.COM (void) snprintf(kernel, len, "%s", kern_path); 1103*10499SWilliam.Kucharski@Sun.COM free(kern_path); 1104*10499SWilliam.Kucharski@Sun.COM 1105*10499SWilliam.Kucharski@Sun.COM if (zfs_boot) { 1106*10499SWilliam.Kucharski@Sun.COM char *zfsstr = alloca(zfslen + 1); 1107*10499SWilliam.Kucharski@Sun.COM 1108*10499SWilliam.Kucharski@Sun.COM (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT); 1109*10499SWilliam.Kucharski@Sun.COM (void) strcat(kernel, zfsstr); 1110*10499SWilliam.Kucharski@Sun.COM emit_bflag = 0; 1111*10499SWilliam.Kucharski@Sun.COM } 1112*10499SWilliam.Kucharski@Sun.COM 1113*10499SWilliam.Kucharski@Sun.COM if (console_dev != NULL) { 1114*10499SWilliam.Kucharski@Sun.COM if (emit_bflag) { 1115*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, BFLAG, " "); 1116*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, console_dev, " "); 1117*10499SWilliam.Kucharski@Sun.COM emit_bflag = 0; 1118*10499SWilliam.Kucharski@Sun.COM } else { 1119*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, console_dev, ", "); 1120*10499SWilliam.Kucharski@Sun.COM } 1121*10499SWilliam.Kucharski@Sun.COM } 1122*10499SWilliam.Kucharski@Sun.COM 1123*10499SWilliam.Kucharski@Sun.COM /* 1124*10499SWilliam.Kucharski@Sun.COM * We have to do some strange processing here because the 1125*10499SWilliam.Kucharski@Sun.COM * hypervisor's serial ports default to "9600,8,n,1,-" if 1126*10499SWilliam.Kucharski@Sun.COM * "comX=auto" is specified, or to "auto" if nothing is 1127*10499SWilliam.Kucharski@Sun.COM * specified. 1128*10499SWilliam.Kucharski@Sun.COM * 1129*10499SWilliam.Kucharski@Sun.COM * Since there could be entries in the bootenv.rc file that 1130*10499SWilliam.Kucharski@Sun.COM * set the serial port to some other setting, when converting 1131*10499SWilliam.Kucharski@Sun.COM * a hypervisor entry to a metal entry we must force the 1132*10499SWilliam.Kucharski@Sun.COM * serial ports to their defaults. 1133*10499SWilliam.Kucharski@Sun.COM */ 1134*10499SWilliam.Kucharski@Sun.COM 1135*10499SWilliam.Kucharski@Sun.COM if (emit_bflag) { 1136*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, BFLAG, " "); 1137*10499SWilliam.Kucharski@Sun.COM delim = " "; 1138*10499SWilliam.Kucharski@Sun.COM emit_bflag = 0; 1139*10499SWilliam.Kucharski@Sun.COM } 1140*10499SWilliam.Kucharski@Sun.COM 1141*10499SWilliam.Kucharski@Sun.COM if (serial_config[0] != NULL) 1142*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, serial_config[0], delim); 1143*10499SWilliam.Kucharski@Sun.COM else 1144*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, "ttya-mode='9600,8,n,1,-'", delim); 1145*10499SWilliam.Kucharski@Sun.COM 1146*10499SWilliam.Kucharski@Sun.COM if (serial_config[1] != NULL) 1147*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, serial_config[1], ", "); 1148*10499SWilliam.Kucharski@Sun.COM else 1149*10499SWilliam.Kucharski@Sun.COM kernel = append_str(kernel, "ttyb-mode='9600,8,n,1,-'", ", "); 1150*10499SWilliam.Kucharski@Sun.COM 1151*10499SWilliam.Kucharski@Sun.COM /* shut off warning messages from the entry line parser */ 1152*10499SWilliam.Kucharski@Sun.COM if (ent->flags & BAM_ENTRY_BOOTADM) 1153*10499SWilliam.Kucharski@Sun.COM ent->flags &= ~BAM_ENTRY_BOOTADM; 1154*10499SWilliam.Kucharski@Sun.COM 1155*10499SWilliam.Kucharski@Sun.COM BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, kernel)); 1156*10499SWilliam.Kucharski@Sun.COM BAM_DPRINTF((D_CVT_CMD_MOD_DOLLAR, fcn, module)); 1157*10499SWilliam.Kucharski@Sun.COM 1158*10499SWilliam.Kucharski@Sun.COM /* 1159*10499SWilliam.Kucharski@Sun.COM * Now try to delete the current default entry from the menu and add 1160*10499SWilliam.Kucharski@Sun.COM * the new hypervisor entry with the parameters we've setup. 1161*10499SWilliam.Kucharski@Sun.COM */ 1162*10499SWilliam.Kucharski@Sun.COM if (delete_boot_entry(mp, curdef, DBE_QUIET) != BAM_SUCCESS) 1163*10499SWilliam.Kucharski@Sun.COM bam_print(NEW_BOOT_ENTRY, title); 1164*10499SWilliam.Kucharski@Sun.COM 1165*10499SWilliam.Kucharski@Sun.COM curdef = add_boot_entry(mp, title, findroot, kernel, NULL, 1166*10499SWilliam.Kucharski@Sun.COM barchive_path, bootfs); 1167*10499SWilliam.Kucharski@Sun.COM 1168*10499SWilliam.Kucharski@Sun.COM /* 1169*10499SWilliam.Kucharski@Sun.COM * If we successfully created the new entry, set the default boot 1170*10499SWilliam.Kucharski@Sun.COM * entry to that entry and let the caller know the new menu should 1171*10499SWilliam.Kucharski@Sun.COM * be written out. 1172*10499SWilliam.Kucharski@Sun.COM */ 1173*10499SWilliam.Kucharski@Sun.COM if (curdef != BAM_ERROR) 1174*10499SWilliam.Kucharski@Sun.COM return (set_global(mp, menu_cmds[DEFAULT_CMD], curdef)); 1175*10499SWilliam.Kucharski@Sun.COM 1176*10499SWilliam.Kucharski@Sun.COM return (BAM_ERROR); 1177*10499SWilliam.Kucharski@Sun.COM 1178*10499SWilliam.Kucharski@Sun.COM abort: 1179*10499SWilliam.Kucharski@Sun.COM if (ret != BAM_NOCHANGE) 1180*10499SWilliam.Kucharski@Sun.COM bam_error(METAL_ABORT, osroot); 1181*10499SWilliam.Kucharski@Sun.COM 1182*10499SWilliam.Kucharski@Sun.COM return (ret); 1183*10499SWilliam.Kucharski@Sun.COM } 1184