144da779fSWilliam Kucharski /* 244da779fSWilliam Kucharski * CDDL HEADER START 344da779fSWilliam Kucharski * 444da779fSWilliam Kucharski * The contents of this file are subject to the terms of the 544da779fSWilliam Kucharski * Common Development and Distribution License (the "License"). 644da779fSWilliam Kucharski * You may not use this file except in compliance with the License. 744da779fSWilliam Kucharski * 844da779fSWilliam Kucharski * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 944da779fSWilliam Kucharski * or http://www.opensolaris.org/os/licensing. 1044da779fSWilliam Kucharski * See the License for the specific language governing permissions 1144da779fSWilliam Kucharski * and limitations under the License. 1244da779fSWilliam Kucharski * 1344da779fSWilliam Kucharski * When distributing Covered Code, include this CDDL HEADER in each 1444da779fSWilliam Kucharski * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1544da779fSWilliam Kucharski * If applicable, add the following below this CDDL HEADER, with the 1644da779fSWilliam Kucharski * fields enclosed by brackets "[]" replaced with your own identifying 1744da779fSWilliam Kucharski * information: Portions Copyright [yyyy] [name of copyright owner] 1844da779fSWilliam Kucharski * 1944da779fSWilliam Kucharski * CDDL HEADER END 2044da779fSWilliam Kucharski */ 2123a1cceaSRoger A. Faulkner 2244da779fSWilliam Kucharski /* 23*f64ca102SToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com> 2423a1cceaSRoger A. Faulkner * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2544da779fSWilliam Kucharski */ 2644da779fSWilliam Kucharski 2744da779fSWilliam Kucharski #include <stdio.h> 2844da779fSWilliam Kucharski #include <errno.h> 2944da779fSWilliam Kucharski #include <stdlib.h> 3044da779fSWilliam Kucharski #include <string.h> 3144da779fSWilliam Kucharski #include <unistd.h> 3244da779fSWilliam Kucharski #include <alloca.h> 3344da779fSWilliam Kucharski #include <ctype.h> 3444da779fSWilliam Kucharski #include <sys/types.h> 3544da779fSWilliam Kucharski 3644da779fSWilliam Kucharski #include "bootadm.h" 3744da779fSWilliam Kucharski 3844da779fSWilliam Kucharski #define HYPER_KERNEL_DIR "/platform/i86xpv/kernel" 3944da779fSWilliam Kucharski #define METAL_KERNEL_DIR "/platform/i86pc/kernel" 4044da779fSWilliam Kucharski 4144da779fSWilliam Kucharski #define BOOTRC_FILE "/boot/solaris/bootenv.rc" 4244da779fSWilliam Kucharski #define ZFS_BOOTSTR "$ZFS-BOOTFS" 4344da779fSWilliam Kucharski 4444da779fSWilliam Kucharski #define BFLAG "-B" 4544da779fSWilliam Kucharski #define DEFAULT_SERIAL "9600,8,n,1" 4644da779fSWilliam Kucharski 4744da779fSWilliam Kucharski #define TTYXMODE_TO_COMNUM(ttyxmode) ((int)(*((ttyxmode) + 3) - '`')) 4844da779fSWilliam Kucharski #define COMNAME_TO_COMNUM(comname) ((int)(*((comname) + 3) - '0')) 4944da779fSWilliam Kucharski 5044da779fSWilliam Kucharski #define WHITESPC(x) (x) 5144da779fSWilliam Kucharski 5244da779fSWilliam Kucharski static char *serial_config[2] = { NULL, NULL }; 5344da779fSWilliam Kucharski static char *console_dev = NULL; 5444da779fSWilliam Kucharski 55772d6a58SWilliam Kucharski static char *bootenv_rc_serial[2] = { NULL, NULL }; 56772d6a58SWilliam Kucharski static char *bootenv_rc_console = NULL; 57772d6a58SWilliam Kucharski 5844da779fSWilliam Kucharski static unsigned zfs_boot = 0; 5944da779fSWilliam Kucharski 6044da779fSWilliam Kucharski /* 6144da779fSWilliam Kucharski * Append the string pointed to by "str" to the string pointed to by "orig" 6244da779fSWilliam Kucharski * adding the delimeter "delim" in between. 6344da779fSWilliam Kucharski * 6466b6aef6SWilliam Kucharski * Return a pointer to the new string or NULL, if we were passed a bad string. 6544da779fSWilliam Kucharski */ 6644da779fSWilliam Kucharski static char * 6744da779fSWilliam Kucharski append_str(char *orig, char *str, char *delim) 6844da779fSWilliam Kucharski { 6944da779fSWilliam Kucharski char *newstr; 7044da779fSWilliam Kucharski int len; 7144da779fSWilliam Kucharski 7266b6aef6SWilliam Kucharski if ((str == NULL) || (delim == NULL)) 7344da779fSWilliam Kucharski return (NULL); 7444da779fSWilliam Kucharski 7566b6aef6SWilliam Kucharski if ((orig == NULL) || (*orig == NULL)) { 7666b6aef6SWilliam Kucharski /* 7766b6aef6SWilliam Kucharski * Return a pointer to a copy of the path so a caller can 7866b6aef6SWilliam Kucharski * always rely upon being able to free() a returned pointer. 7966b6aef6SWilliam Kucharski */ 8044da779fSWilliam Kucharski return (s_strdup(str)); 8166b6aef6SWilliam Kucharski } 8244da779fSWilliam Kucharski 8344da779fSWilliam Kucharski len = strlen(orig) + strlen(str) + strlen(delim) + 1; 8466b6aef6SWilliam Kucharski if ((newstr = malloc(len)) == NULL) { 85*f64ca102SToomas Soome bam_error(_("could not allocate memory: size = %u\n"), len); 8666b6aef6SWilliam Kucharski bam_exit(1); 8766b6aef6SWilliam Kucharski } 8844da779fSWilliam Kucharski 8944da779fSWilliam Kucharski (void) snprintf(newstr, len, "%s%s%s", orig, delim, str); 9044da779fSWilliam Kucharski return (newstr); 9144da779fSWilliam Kucharski } 9244da779fSWilliam Kucharski 9344da779fSWilliam Kucharski /* 9444da779fSWilliam Kucharski * Replace the substring "old_str" in a path with the substring "new_str" 9544da779fSWilliam Kucharski * 9666b6aef6SWilliam Kucharski * Return a pointer to the modified string. 9744da779fSWilliam Kucharski */ 9844da779fSWilliam Kucharski static char * 9944da779fSWilliam Kucharski modify_path(char *path, char *old_str, char *new_str) 10044da779fSWilliam Kucharski { 10144da779fSWilliam Kucharski char *newpath; 10244da779fSWilliam Kucharski char *pc; 10366b6aef6SWilliam Kucharski int len; 10444da779fSWilliam Kucharski 10566b6aef6SWilliam Kucharski /* 10666b6aef6SWilliam Kucharski * Return a pointer to a copy of the path so a caller can always rely 10766b6aef6SWilliam Kucharski * upon being able to free() a returned pointer. 10866b6aef6SWilliam Kucharski */ 10966b6aef6SWilliam Kucharski if ((pc = strstr(path, old_str)) == NULL) 11066b6aef6SWilliam Kucharski return (s_strdup(path)); 11144da779fSWilliam Kucharski 11244da779fSWilliam Kucharski /* 11344da779fSWilliam Kucharski * Allocate space for duplicate of path with name changes and 11444da779fSWilliam Kucharski * NULL terminating byte 11544da779fSWilliam Kucharski */ 11666b6aef6SWilliam Kucharski len = strlen(path) - strlen(old_str) + strlen(new_str) + 1; 11766b6aef6SWilliam Kucharski 11866b6aef6SWilliam Kucharski if ((newpath = malloc(len)) == NULL) { 119*f64ca102SToomas Soome bam_error(_("could not allocate memory: size = %u\n"), len); 12066b6aef6SWilliam Kucharski bam_exit(1); 12144da779fSWilliam Kucharski } 12244da779fSWilliam Kucharski 12366b6aef6SWilliam Kucharski (void) strlcpy(newpath, path, (pc - path) + 1); 12466b6aef6SWilliam Kucharski pc += strlen(old_str); 12544da779fSWilliam Kucharski 12644da779fSWilliam Kucharski (void) strcat(newpath, new_str); 12766b6aef6SWilliam Kucharski (void) strcat(newpath, pc); 12866b6aef6SWilliam Kucharski return (newpath); 12944da779fSWilliam Kucharski } 13044da779fSWilliam Kucharski 13144da779fSWilliam Kucharski /* 13244da779fSWilliam Kucharski * Set "token" to be the the string starting from the pointer "str" delimited 13344da779fSWilliam Kucharski * by any character in the string "delim" or the end of the string, but IGNORE 13444da779fSWilliam Kucharski * any characters between single or double quotes. 13544da779fSWilliam Kucharski * 13644da779fSWilliam Kucharski * Return a pointer to the next non-whitespace character after the delimiter 13744da779fSWilliam Kucharski * or NULL if we hit the end of the string. Also return NULL upon failure to 13844da779fSWilliam Kucharski * find any characters from the delimeter string or upon failure to allocate 13944da779fSWilliam Kucharski * memory for the new token string. 14044da779fSWilliam Kucharski */ 14144da779fSWilliam Kucharski static char * 14244da779fSWilliam Kucharski get_token(char **token, char *str, char *delim) 14344da779fSWilliam Kucharski { 14444da779fSWilliam Kucharski char *dp; 14544da779fSWilliam Kucharski char *start = str; 14644da779fSWilliam Kucharski unsigned len; 14744da779fSWilliam Kucharski 14844da779fSWilliam Kucharski *token = NULL; 14944da779fSWilliam Kucharski 15044da779fSWilliam Kucharski if ((str == NULL) || (*str == NULL)) 15144da779fSWilliam Kucharski return (NULL); 15244da779fSWilliam Kucharski 15344da779fSWilliam Kucharski do { 15444da779fSWilliam Kucharski if ((*str == '\'') || (*str == '"')) { 15544da779fSWilliam Kucharski char quote = *str++; 15644da779fSWilliam Kucharski 15744da779fSWilliam Kucharski while ((*str != NULL) && (*str != quote)) 15844da779fSWilliam Kucharski str++; 15944da779fSWilliam Kucharski 16044da779fSWilliam Kucharski /* no matching quote found in string */ 16144da779fSWilliam Kucharski if (*str++ == NULL) 16244da779fSWilliam Kucharski return (NULL); 16344da779fSWilliam Kucharski } 16444da779fSWilliam Kucharski 16544da779fSWilliam Kucharski /* look for a character from the delimiter string */ 16644da779fSWilliam Kucharski for (dp = delim; ((*dp != NULL) && (*dp != *str)); dp++) 16744da779fSWilliam Kucharski ; 16844da779fSWilliam Kucharski 16944da779fSWilliam Kucharski if (*dp != NULL) { 17044da779fSWilliam Kucharski len = str - start + 1; 17144da779fSWilliam Kucharski 17244da779fSWilliam Kucharski /* found a delimiter, so create a token string */ 17344da779fSWilliam Kucharski if ((*token = malloc(len)) == NULL) { 174*f64ca102SToomas Soome bam_error(_("could not allocate memory: " 175*f64ca102SToomas Soome "size = %u\n"), len); 17666b6aef6SWilliam Kucharski bam_exit(1); 17744da779fSWilliam Kucharski } 17844da779fSWilliam Kucharski 17944da779fSWilliam Kucharski (void) strlcpy(*token, start, len); 18044da779fSWilliam Kucharski 18144da779fSWilliam Kucharski while (isspace((int)*++str)) 18244da779fSWilliam Kucharski ; 18344da779fSWilliam Kucharski 18444da779fSWilliam Kucharski return (str); 18544da779fSWilliam Kucharski } 18644da779fSWilliam Kucharski } while (*str++ != NULL); 18744da779fSWilliam Kucharski 18844da779fSWilliam Kucharski /* if we hit the end of the string, the token is the whole string */ 18944da779fSWilliam Kucharski *token = s_strdup(start); 19044da779fSWilliam Kucharski return (NULL); 19144da779fSWilliam Kucharski } 19244da779fSWilliam Kucharski 19344da779fSWilliam Kucharski /* 19444da779fSWilliam Kucharski * Convert a metal "console" device name to an equivalent one suitable for 19544da779fSWilliam Kucharski * use with the hypervisor. 19644da779fSWilliam Kucharski * 19744da779fSWilliam Kucharski * Default to "vga" if we can't parse the console device. 19844da779fSWilliam Kucharski */ 19944da779fSWilliam Kucharski static void 20044da779fSWilliam Kucharski console_metal_to_hyper(char *console) 20144da779fSWilliam Kucharski { 20244da779fSWilliam Kucharski if ((*console == '\'') || (*console == '"')) 20344da779fSWilliam Kucharski console++; 20444da779fSWilliam Kucharski 20544da779fSWilliam Kucharski if (strncmp(console, "ttya", 4) == 0) 20644da779fSWilliam Kucharski console_dev = "console=com1"; 20744da779fSWilliam Kucharski else if (strncmp(console, "ttyb", 4) == 0) 20844da779fSWilliam Kucharski console_dev = "console=com2"; 20944da779fSWilliam Kucharski else 21044da779fSWilliam Kucharski console_dev = "console=vga"; 21144da779fSWilliam Kucharski } 21244da779fSWilliam Kucharski 21344da779fSWilliam Kucharski static int 21444da779fSWilliam Kucharski set_serial_rate(int com, char *rate) 21544da779fSWilliam Kucharski { 21644da779fSWilliam Kucharski char **rp = &serial_config[com - 1]; 21744da779fSWilliam Kucharski 218772d6a58SWilliam Kucharski if ((com < 1) || (com > 2)) 219772d6a58SWilliam Kucharski return (-1); 220772d6a58SWilliam Kucharski 22144da779fSWilliam Kucharski /* 22244da779fSWilliam Kucharski * If rate is a NULL pointer, erase any existing serial configuration 22344da779fSWilliam Kucharski * for this serial port. 22444da779fSWilliam Kucharski */ 22544da779fSWilliam Kucharski if (rate == NULL) { 22644da779fSWilliam Kucharski if (*rp != NULL) { 22744da779fSWilliam Kucharski free(*rp); 22844da779fSWilliam Kucharski *rp = NULL; 22944da779fSWilliam Kucharski } 23044da779fSWilliam Kucharski return (0); 23144da779fSWilliam Kucharski } 23244da779fSWilliam Kucharski 23366b6aef6SWilliam Kucharski *rp = s_realloc(*rp, strlen(rate) + 1); 23444da779fSWilliam Kucharski (void) strcpy(*rp, rate); 23544da779fSWilliam Kucharski return (0); 23644da779fSWilliam Kucharski } 23744da779fSWilliam Kucharski 23844da779fSWilliam Kucharski /* 23944da779fSWilliam Kucharski * Convert "metal" serial port parameters to values compatible with the 24044da779fSWilliam Kucharski * hypervisor. 24144da779fSWilliam Kucharski * 24244da779fSWilliam Kucharski * Return 0 on success, otherwise -1. 24344da779fSWilliam Kucharski */ 24444da779fSWilliam Kucharski static int 24544da779fSWilliam Kucharski serial_metal_to_hyper(char *metal_port, char *metal_serial) 24644da779fSWilliam Kucharski { 24744da779fSWilliam Kucharski #define COM_RATE_LEN 16 /* strlen("com1=115200,8n1") */ 24844da779fSWilliam Kucharski 24944da779fSWilliam Kucharski char com_rate[COM_RATE_LEN]; 25044da779fSWilliam Kucharski 25144da779fSWilliam Kucharski unsigned com, baud, bits, stop; 25244da779fSWilliam Kucharski char parity, handshake; 25344da779fSWilliam Kucharski 25444da779fSWilliam Kucharski if ((strcmp(metal_port, "ttya-mode") == 0) || 25544da779fSWilliam Kucharski (strcmp(metal_port, "ttyb-mode") == 0)) 25644da779fSWilliam Kucharski com = TTYXMODE_TO_COMNUM(metal_port); 25744da779fSWilliam Kucharski else 25844da779fSWilliam Kucharski return (-1); 25944da779fSWilliam Kucharski 26044da779fSWilliam Kucharski if ((*metal_serial == '\'') || (*metal_serial == '"')) 26144da779fSWilliam Kucharski metal_serial++; 26244da779fSWilliam Kucharski 26344da779fSWilliam Kucharski /* 26444da779fSWilliam Kucharski * Check if it's specified as the default rate; if so it defaults to 26544da779fSWilliam Kucharski * "auto" and we need not set it for they hypervisor. 26644da779fSWilliam Kucharski */ 26744da779fSWilliam Kucharski if (strncmp(metal_serial, DEFAULT_SERIAL, 26844da779fSWilliam Kucharski strlen(DEFAULT_SERIAL)) == 0) { 26944da779fSWilliam Kucharski (void) set_serial_rate(com, NULL); 27044da779fSWilliam Kucharski return (0); 27144da779fSWilliam Kucharski } 27244da779fSWilliam Kucharski 27344da779fSWilliam Kucharski /* read the serial port format as set forth in common/io/asy.c */ 27444da779fSWilliam Kucharski if (sscanf(metal_serial, "%u,%u,%c,%u,%c", &baud, &bits, &parity, &stop, 27544da779fSWilliam Kucharski &handshake) != 5) 27644da779fSWilliam Kucharski return (-1); 27744da779fSWilliam Kucharski 27844da779fSWilliam Kucharski /* validate serial port parameters */ 27944da779fSWilliam Kucharski if (((bits < 5) || (bits > 8)) || (stop > 1) || 28044da779fSWilliam Kucharski ((parity != 'n') && (parity != 'e') && (parity != 'o')) || 28144da779fSWilliam Kucharski ((handshake != '-') && (handshake != 'h') && (handshake != 's'))) 28244da779fSWilliam Kucharski return (-1); 28344da779fSWilliam Kucharski 28444da779fSWilliam Kucharski /* validate baud rate */ 28544da779fSWilliam Kucharski switch (baud) { 28644da779fSWilliam Kucharski case 150: 28744da779fSWilliam Kucharski case 300: 28844da779fSWilliam Kucharski case 600: 28944da779fSWilliam Kucharski case 1200: 29044da779fSWilliam Kucharski case 2400: 29144da779fSWilliam Kucharski case 4800: 29244da779fSWilliam Kucharski case 9600: 29344da779fSWilliam Kucharski case 19200: 29444da779fSWilliam Kucharski case 38400: 29544da779fSWilliam Kucharski case 57600: 29644da779fSWilliam Kucharski case 115200: 29744da779fSWilliam Kucharski break; 29844da779fSWilliam Kucharski 29944da779fSWilliam Kucharski default: 30044da779fSWilliam Kucharski return (-1); 30144da779fSWilliam Kucharski } 30244da779fSWilliam Kucharski 30344da779fSWilliam Kucharski /* 30444da779fSWilliam Kucharski * The hypervisor has no way to specify a handshake method, so it gets 30544da779fSWilliam Kucharski * quietly dropped in the conversion. 30644da779fSWilliam Kucharski */ 30744da779fSWilliam Kucharski (void) snprintf(com_rate, COM_RATE_LEN, "com%d=%u,%u%c%u", com, baud, 30844da779fSWilliam Kucharski bits, parity, stop); 30944da779fSWilliam Kucharski (void) set_serial_rate(com, com_rate); 31044da779fSWilliam Kucharski return (0); 31144da779fSWilliam Kucharski } 31244da779fSWilliam Kucharski 31344da779fSWilliam Kucharski /* 31444da779fSWilliam Kucharski * Convert "name=value" metal options to values suitable for use with the 31544da779fSWilliam Kucharski * hypervisor. 31644da779fSWilliam Kucharski * 31744da779fSWilliam Kucharski * Our main concerns are the console device and serial port settings. 31844da779fSWilliam Kucharski * 31944da779fSWilliam Kucharski * Return values: 32044da779fSWilliam Kucharski * 32144da779fSWilliam Kucharski * -1: Unparseable line 32244da779fSWilliam Kucharski * 0: Success 32344da779fSWilliam Kucharski * (n > 0): A property unimportant to us 32444da779fSWilliam Kucharski */ 32544da779fSWilliam Kucharski static int 32644da779fSWilliam Kucharski cvt_metal_option(char *optstr) 32744da779fSWilliam Kucharski { 32844da779fSWilliam Kucharski char *value; 32944da779fSWilliam Kucharski unsigned namlen; 33044da779fSWilliam Kucharski 33144da779fSWilliam Kucharski if (strcmp(optstr, ZFS_BOOTSTR) == 0) { 33244da779fSWilliam Kucharski zfs_boot = 1; 33344da779fSWilliam Kucharski return (0); 33444da779fSWilliam Kucharski } 33544da779fSWilliam Kucharski 33644da779fSWilliam Kucharski if ((value = strchr(optstr, '=')) == NULL) 33744da779fSWilliam Kucharski return (-1); 33844da779fSWilliam Kucharski 33944da779fSWilliam Kucharski namlen = value - optstr; 34044da779fSWilliam Kucharski 34144da779fSWilliam Kucharski if (*++value == NULL) 34244da779fSWilliam Kucharski return (1); 34344da779fSWilliam Kucharski 34444da779fSWilliam Kucharski if (strncmp(optstr, "console", namlen) == 0) { 34544da779fSWilliam Kucharski console_metal_to_hyper(value); 34644da779fSWilliam Kucharski return (0); 34744da779fSWilliam Kucharski } 34844da779fSWilliam Kucharski 34944da779fSWilliam Kucharski if ((strncmp(optstr, "ttya-mode", namlen) == 0) || 35044da779fSWilliam Kucharski (strncmp(optstr, "ttyb-mode", namlen) == 0)) { 35123a1cceaSRoger A. Faulkner char *port = strndupa(optstr, namlen); 35244da779fSWilliam Kucharski 35344da779fSWilliam Kucharski return (serial_metal_to_hyper(port, value)); 35444da779fSWilliam Kucharski } 35544da779fSWilliam Kucharski 35644da779fSWilliam Kucharski return (1); 35744da779fSWilliam Kucharski } 35844da779fSWilliam Kucharski 35944da779fSWilliam Kucharski /* 36044da779fSWilliam Kucharski * Convert "name=value" properties for use with a bare metal kernel 36144da779fSWilliam Kucharski * 36244da779fSWilliam Kucharski * Our main concerns are the console setting and serial port modes. 36344da779fSWilliam Kucharski * 36444da779fSWilliam Kucharski * Return values: 36544da779fSWilliam Kucharski * 36644da779fSWilliam Kucharski * -1: Unparseable line 36744da779fSWilliam Kucharski * 0: Success 36844da779fSWilliam Kucharski * (n > 0): A property unimportant to us 36944da779fSWilliam Kucharski */ 37044da779fSWilliam Kucharski static int 37144da779fSWilliam Kucharski cvt_hyper_option(char *optstr) 37244da779fSWilliam Kucharski { 373772d6a58SWilliam Kucharski #define SER_LEN 15 /* strlen("115200,8,n,1,-") + 1 */ 37444da779fSWilliam Kucharski 37544da779fSWilliam Kucharski char ser[SER_LEN]; 37644da779fSWilliam Kucharski char *value; 37744da779fSWilliam Kucharski 37844da779fSWilliam Kucharski unsigned namlen; 37944da779fSWilliam Kucharski 38044da779fSWilliam Kucharski unsigned baud; 38144da779fSWilliam Kucharski char bits, parity, stop; 38244da779fSWilliam Kucharski 38344da779fSWilliam Kucharski if (strcmp(optstr, ZFS_BOOTSTR) == 0) { 38444da779fSWilliam Kucharski zfs_boot = 1; 38544da779fSWilliam Kucharski return (0); 38644da779fSWilliam Kucharski } 38744da779fSWilliam Kucharski 38844da779fSWilliam Kucharski /* 38944da779fSWilliam Kucharski * If there's no "=" in the token, it's likely a standalone 39044da779fSWilliam Kucharski * hypervisor token we don't care about (e.g. "noreboot" or 39144da779fSWilliam Kucharski * "nosmp") so we ignore it. 39244da779fSWilliam Kucharski */ 39344da779fSWilliam Kucharski if ((value = strchr(optstr, '=')) == NULL) 39444da779fSWilliam Kucharski return (1); 39544da779fSWilliam Kucharski 39644da779fSWilliam Kucharski namlen = value - optstr; 39744da779fSWilliam Kucharski 39844da779fSWilliam Kucharski if (*++value == NULL) 39944da779fSWilliam Kucharski return (1); 40044da779fSWilliam Kucharski 40144da779fSWilliam Kucharski /* 40244da779fSWilliam Kucharski * Note that we use strncmp against the values because the 40344da779fSWilliam Kucharski * hypervisor allows setting console parameters for both the 40444da779fSWilliam Kucharski * console and debugger via the format: 40544da779fSWilliam Kucharski * 40644da779fSWilliam Kucharski * console=cons_dev,debug_dev 40744da779fSWilliam Kucharski * 40844da779fSWilliam Kucharski * and we only care about "cons_dev." 40944da779fSWilliam Kucharski * 41044da779fSWilliam Kucharski * This also allows us to extract "comN" from hypervisor constructs 41144da779fSWilliam Kucharski * like "com1H" or "com2L," concepts unsupported on bare metal kernels. 41244da779fSWilliam Kucharski * 41344da779fSWilliam Kucharski * Default the console device to "text" if it was "vga" or was 41444da779fSWilliam Kucharski * unparseable. 41544da779fSWilliam Kucharski */ 41644da779fSWilliam Kucharski if (strncmp(optstr, "console", namlen) == 0) { 41744da779fSWilliam Kucharski /* ignore the "console=hypervisor" option */ 41844da779fSWilliam Kucharski if (strcmp(value, "hypervisor") == 0) 41944da779fSWilliam Kucharski return (0); 42044da779fSWilliam Kucharski 42144da779fSWilliam Kucharski if (strncmp(value, "com1", 4) == 0) 422772d6a58SWilliam Kucharski console_dev = "ttya"; 42344da779fSWilliam Kucharski else if (strncmp(value, "com2", 4) == 0) 424772d6a58SWilliam Kucharski console_dev = "ttyb"; 42544da779fSWilliam Kucharski else 426772d6a58SWilliam Kucharski console_dev = "text"; 42744da779fSWilliam Kucharski } 42844da779fSWilliam Kucharski 42944da779fSWilliam Kucharski /* serial port parameter conversion */ 43044da779fSWilliam Kucharski 43144da779fSWilliam Kucharski if ((strncmp(optstr, "com1", namlen) == 0) || 43244da779fSWilliam Kucharski (strncmp(optstr, "com2", namlen) == 0)) { 43344da779fSWilliam Kucharski unsigned com = COMNAME_TO_COMNUM(optstr); 43444da779fSWilliam Kucharski 43544da779fSWilliam Kucharski /* 43644da779fSWilliam Kucharski * Check if it's "auto" - if so, use the default setting 43744da779fSWilliam Kucharski * of "9600,8,n,1,-". 43844da779fSWilliam Kucharski * 43944da779fSWilliam Kucharski * We can't just assume the serial port will default to 44044da779fSWilliam Kucharski * "9600,8,n,1" as there could be a directive in bootenv.rc 44144da779fSWilliam Kucharski * that would set it to some other value and we want the serial 44244da779fSWilliam Kucharski * parameters to be the same as that used by the hypervisor. 44344da779fSWilliam Kucharski */ 44444da779fSWilliam Kucharski if (strcmp(value, "auto") == 0) { 445772d6a58SWilliam Kucharski (void) snprintf(ser, SER_LEN, "9600,8,n,1,-"); 446772d6a58SWilliam Kucharski } else { 44744da779fSWilliam Kucharski /* 448772d6a58SWilliam Kucharski * Extract the "B,PS" setting from the com line; ignore 449772d6a58SWilliam Kucharski * other settings like io_base or IRQ. 45044da779fSWilliam Kucharski */ 45144da779fSWilliam Kucharski if (sscanf(value, "%u,%c%c%c", &baud, &bits, &parity, 45244da779fSWilliam Kucharski &stop) != 4) 45344da779fSWilliam Kucharski return (-1); 45444da779fSWilliam Kucharski 45544da779fSWilliam Kucharski /* validate serial port parameters */ 45644da779fSWilliam Kucharski if (((stop != '0') && (stop != '1')) || 45744da779fSWilliam Kucharski ((bits < '5') && (bits > '8')) || 458772d6a58SWilliam Kucharski ((parity != 'n') && (parity != 'e') && 459772d6a58SWilliam Kucharski (parity != 'o'))) 46044da779fSWilliam Kucharski return (-1); 46144da779fSWilliam Kucharski 46244da779fSWilliam Kucharski /* validate baud rate */ 46344da779fSWilliam Kucharski switch (baud) { 46444da779fSWilliam Kucharski case 150: 46544da779fSWilliam Kucharski case 300: 46644da779fSWilliam Kucharski case 600: 46744da779fSWilliam Kucharski case 1200: 46844da779fSWilliam Kucharski case 2400: 46944da779fSWilliam Kucharski case 4800: 47044da779fSWilliam Kucharski case 19200: 47144da779fSWilliam Kucharski case 38400: 47244da779fSWilliam Kucharski case 57600: 47344da779fSWilliam Kucharski case 115200: 47444da779fSWilliam Kucharski break; 47544da779fSWilliam Kucharski 47644da779fSWilliam Kucharski default: 47744da779fSWilliam Kucharski return (-1); 47844da779fSWilliam Kucharski } 47944da779fSWilliam Kucharski 48044da779fSWilliam Kucharski /* 481772d6a58SWilliam Kucharski * As the hypervisor has no way to denote handshaking 482772d6a58SWilliam Kucharski * in its serial port settings, emit a metal serial 483772d6a58SWilliam Kucharski * port configuration with none as well. 48444da779fSWilliam Kucharski */ 485772d6a58SWilliam Kucharski (void) snprintf(ser, SER_LEN, "%u,%c,%c,%c,-", baud, 486772d6a58SWilliam Kucharski bits, parity, stop); 487772d6a58SWilliam Kucharski } 48844da779fSWilliam Kucharski 48944da779fSWilliam Kucharski if (set_serial_rate(com, ser) != 0) 49044da779fSWilliam Kucharski return (-1); 49144da779fSWilliam Kucharski 49244da779fSWilliam Kucharski return (0); 49344da779fSWilliam Kucharski } 49444da779fSWilliam Kucharski 49544da779fSWilliam Kucharski return (1); 49644da779fSWilliam Kucharski } 49744da779fSWilliam Kucharski 49844da779fSWilliam Kucharski /* 49944da779fSWilliam Kucharski * Parse a hardware kernel's "kernel$" specifier into parameters we can then 50044da779fSWilliam Kucharski * use to construct an appropriate "module$" line that can be used to specify 50144da779fSWilliam Kucharski * how to boot the hypervisor's dom0. 50244da779fSWilliam Kucharski * 50366b6aef6SWilliam Kucharski * Return values: 50466b6aef6SWilliam Kucharski * 50566b6aef6SWilliam Kucharski * -1: error parsing kernel path 50666b6aef6SWilliam Kucharski * 0: success 50766b6aef6SWilliam Kucharski * 1: kernel already a hypervisor kernel 50844da779fSWilliam Kucharski */ 50944da779fSWilliam Kucharski static int 51044da779fSWilliam Kucharski cvt_metal_kernel(char *kernstr, char **path) 51144da779fSWilliam Kucharski { 51244da779fSWilliam Kucharski char *token, *parsestr; 51344da779fSWilliam Kucharski 51466b6aef6SWilliam Kucharski parsestr = get_token(path, kernstr, " \t,"); 51566b6aef6SWilliam Kucharski if (*path == NULL) 51666b6aef6SWilliam Kucharski return (-1); 51744da779fSWilliam Kucharski 51844da779fSWilliam Kucharski /* 51944da779fSWilliam Kucharski * If the metal kernel specified contains the name of the hypervisor, 52044da779fSWilliam Kucharski * we're probably trying to convert an entry already setup to run the 52144da779fSWilliam Kucharski * hypervisor, so error out now. 52244da779fSWilliam Kucharski */ 52344da779fSWilliam Kucharski if (strstr(*path, XEN_MENU) != NULL) { 524*f64ca102SToomas Soome bam_error(_("default entry already setup for use with the " 525*f64ca102SToomas Soome "hypervisor!\n")); 52666b6aef6SWilliam Kucharski free(*path); 52766b6aef6SWilliam Kucharski *path = NULL; 52866b6aef6SWilliam Kucharski return (1); 52944da779fSWilliam Kucharski } 53044da779fSWilliam Kucharski 53144da779fSWilliam Kucharski /* if the path was the last item on the line, that's OK. */ 53244da779fSWilliam Kucharski if ((parsestr = get_token(&token, parsestr, " \t,")) == NULL) { 53344da779fSWilliam Kucharski if (token != NULL) 53444da779fSWilliam Kucharski free(token); 53544da779fSWilliam Kucharski return (0); 53644da779fSWilliam Kucharski } 53744da779fSWilliam Kucharski 53844da779fSWilliam Kucharski /* if the next token is "-B" process boot options */ 53944da779fSWilliam Kucharski if (strncmp(token, BFLAG, strlen(BFLAG)) != 0) { 54044da779fSWilliam Kucharski free(token); 54144da779fSWilliam Kucharski return (0); 54244da779fSWilliam Kucharski } 54344da779fSWilliam Kucharski 54466b6aef6SWilliam Kucharski free(token); 54566b6aef6SWilliam Kucharski 54644da779fSWilliam Kucharski while ((parsestr = get_token(&token, parsestr, ",")) != NULL) { 54744da779fSWilliam Kucharski (void) cvt_metal_option(token); 54844da779fSWilliam Kucharski free(token); 54944da779fSWilliam Kucharski } 55044da779fSWilliam Kucharski 55144da779fSWilliam Kucharski if (token != NULL) { 55244da779fSWilliam Kucharski (void) cvt_metal_option(token); 55344da779fSWilliam Kucharski free(token); 55444da779fSWilliam Kucharski } 55544da779fSWilliam Kucharski 55644da779fSWilliam Kucharski return (0); 55744da779fSWilliam Kucharski } 55844da779fSWilliam Kucharski 55944da779fSWilliam Kucharski /* 56044da779fSWilliam Kucharski * Parse a hypervisor's "kernel$" line into parameters that can be used to 56144da779fSWilliam Kucharski * help build an appropriate "kernel$" line for booting a bare metal kernel. 56244da779fSWilliam Kucharski * 56344da779fSWilliam Kucharski * Return 0 on success, non-zero on failure. 56444da779fSWilliam Kucharski */ 56544da779fSWilliam Kucharski static int 56644da779fSWilliam Kucharski cvt_hyper_kernel(char *kernel) 56744da779fSWilliam Kucharski { 56844da779fSWilliam Kucharski char *token, *parsestr; 56944da779fSWilliam Kucharski 57066b6aef6SWilliam Kucharski parsestr = get_token(&token, kernel, " \t,"); 57166b6aef6SWilliam Kucharski 57266b6aef6SWilliam Kucharski if (token == NULL) 57366b6aef6SWilliam Kucharski return (-1); 57444da779fSWilliam Kucharski 57544da779fSWilliam Kucharski /* 57644da779fSWilliam Kucharski * If the hypervisor kernel specified lives in the metal kernel 57744da779fSWilliam Kucharski * directory, we're probably trying to convert an entry already setup 57844da779fSWilliam Kucharski * to run on bare metal, so error out now. 57944da779fSWilliam Kucharski */ 58044da779fSWilliam Kucharski if (strncmp(token, METAL_KERNEL_DIR, strlen(METAL_KERNEL_DIR)) == 0) { 581*f64ca102SToomas Soome bam_error(_("default entry already setup for use with a metal " 582*f64ca102SToomas Soome "kernel!\n")); 58366b6aef6SWilliam Kucharski free(token); 58444da779fSWilliam Kucharski return (-1); 58544da779fSWilliam Kucharski } 58644da779fSWilliam Kucharski 58744da779fSWilliam Kucharski free(token); 58844da779fSWilliam Kucharski 58944da779fSWilliam Kucharski /* check for kernel options */ 59044da779fSWilliam Kucharski while ((parsestr = get_token(&token, parsestr, " ")) != NULL) { 59144da779fSWilliam Kucharski (void) cvt_hyper_option(token); 59244da779fSWilliam Kucharski free(token); 59344da779fSWilliam Kucharski } 59444da779fSWilliam Kucharski 59544da779fSWilliam Kucharski if (token != NULL) { 59644da779fSWilliam Kucharski (void) cvt_hyper_option(token); 59744da779fSWilliam Kucharski free(token); 59844da779fSWilliam Kucharski } 59944da779fSWilliam Kucharski 60044da779fSWilliam Kucharski return (0); 60144da779fSWilliam Kucharski } 60244da779fSWilliam Kucharski 60344da779fSWilliam Kucharski /* 60444da779fSWilliam Kucharski * Parse a hypervisor's "module$" line into parameters that can be used to 60544da779fSWilliam Kucharski * help build an appropriate "kernel$" line for booting a bare metal kernel. 60644da779fSWilliam Kucharski */ 60744da779fSWilliam Kucharski static void 60844da779fSWilliam Kucharski cvt_hyper_module(char *modstr, char **path) 60944da779fSWilliam Kucharski { 61066b6aef6SWilliam Kucharski char *token = NULL; 61144da779fSWilliam Kucharski char *parsestr = modstr; 61244da779fSWilliam Kucharski 61344da779fSWilliam Kucharski /* 61444da779fSWilliam Kucharski * If multiple pathnames exist on the module$ line, we just want 61544da779fSWilliam Kucharski * the last one. 61644da779fSWilliam Kucharski */ 61744da779fSWilliam Kucharski while ((parsestr = get_token(path, parsestr, " \t,")) != NULL) { 61844da779fSWilliam Kucharski if (*parsestr != '/') 61944da779fSWilliam Kucharski break; 62066b6aef6SWilliam Kucharski else 62144da779fSWilliam Kucharski free(*path); 62244da779fSWilliam Kucharski } 62344da779fSWilliam Kucharski 62444da779fSWilliam Kucharski /* if the path was the last item on the line, that's OK. */ 62544da779fSWilliam Kucharski if ((parsestr == NULL) || 62644da779fSWilliam Kucharski ((parsestr = get_token(&token, parsestr, " \t,")) == NULL)) { 62744da779fSWilliam Kucharski if (token != NULL) 62844da779fSWilliam Kucharski free(token); 62944da779fSWilliam Kucharski return; 63044da779fSWilliam Kucharski } 63144da779fSWilliam Kucharski 63266b6aef6SWilliam Kucharski if (token == NULL) 63366b6aef6SWilliam Kucharski return; 63466b6aef6SWilliam Kucharski 63544da779fSWilliam Kucharski /* check for "-B" option */ 63644da779fSWilliam Kucharski if (strncmp(token, BFLAG, strlen(BFLAG)) != 0) { 63744da779fSWilliam Kucharski free(token); 63844da779fSWilliam Kucharski return; 63944da779fSWilliam Kucharski } 64044da779fSWilliam Kucharski 64166b6aef6SWilliam Kucharski free(token); 64266b6aef6SWilliam Kucharski 64344da779fSWilliam Kucharski /* check for kernel options */ 64444da779fSWilliam Kucharski while ((parsestr = get_token(&token, parsestr, ",")) != NULL) { 64544da779fSWilliam Kucharski (void) cvt_hyper_option(token); 64644da779fSWilliam Kucharski free(token); 64744da779fSWilliam Kucharski } 64844da779fSWilliam Kucharski 64944da779fSWilliam Kucharski if (token != NULL) { 65044da779fSWilliam Kucharski (void) cvt_hyper_option(token); 65144da779fSWilliam Kucharski free(token); 65244da779fSWilliam Kucharski } 65344da779fSWilliam Kucharski } 65444da779fSWilliam Kucharski 65544da779fSWilliam Kucharski static void 65644da779fSWilliam Kucharski parse_bootenvrc(char *osroot) 65744da779fSWilliam Kucharski { 65844da779fSWilliam Kucharski #define LINEBUF_SZ 1024 65944da779fSWilliam Kucharski 66044da779fSWilliam Kucharski FILE *fp; 66144da779fSWilliam Kucharski char *rcpath; 66244da779fSWilliam Kucharski char line[LINEBUF_SZ]; /* make line buffer large but not ridiculous */ 66344da779fSWilliam Kucharski int len; 66444da779fSWilliam Kucharski 66544da779fSWilliam Kucharski assert(osroot); 66644da779fSWilliam Kucharski 66744da779fSWilliam Kucharski len = strlen(osroot) + strlen(BOOTRC_FILE) + 1; 66844da779fSWilliam Kucharski rcpath = alloca(len); 66966b6aef6SWilliam Kucharski 67044da779fSWilliam Kucharski (void) snprintf(rcpath, len, "%s%s", osroot, BOOTRC_FILE); 67144da779fSWilliam Kucharski 67244da779fSWilliam Kucharski /* if we couldn't open the bootenv.rc file, ignore the issue. */ 67344da779fSWilliam Kucharski if ((fp = fopen(rcpath, "r")) == NULL) { 674*f64ca102SToomas Soome BAM_DPRINTF(("could not open %s: %s\n", rcpath, 675*f64ca102SToomas Soome strerror(errno))); 67644da779fSWilliam Kucharski return; 67744da779fSWilliam Kucharski } 67844da779fSWilliam Kucharski 67944da779fSWilliam Kucharski while (s_fgets(line, LINEBUF_SZ, fp) != NULL) { 680772d6a58SWilliam Kucharski char *parsestr, *token; 681772d6a58SWilliam Kucharski int port = 0; 682772d6a58SWilliam Kucharski 68344da779fSWilliam Kucharski /* we're only interested in parsing "setprop" directives. */ 68444da779fSWilliam Kucharski if (strncmp(line, "setprop", 7) != NULL) 68544da779fSWilliam Kucharski continue; 68644da779fSWilliam Kucharski 687772d6a58SWilliam Kucharski /* eat initial "setprop" */ 688772d6a58SWilliam Kucharski if ((parsestr = get_token(&token, line, " \t")) == NULL) { 689772d6a58SWilliam Kucharski if (token != NULL) 690772d6a58SWilliam Kucharski free(token); 691772d6a58SWilliam Kucharski 692772d6a58SWilliam Kucharski continue; 693772d6a58SWilliam Kucharski } 694772d6a58SWilliam Kucharski 695772d6a58SWilliam Kucharski if (strcmp(token, "setprop") != 0) { 696772d6a58SWilliam Kucharski free(token); 697772d6a58SWilliam Kucharski continue; 698772d6a58SWilliam Kucharski } 699772d6a58SWilliam Kucharski 700772d6a58SWilliam Kucharski free(token); 701772d6a58SWilliam Kucharski 702772d6a58SWilliam Kucharski /* get property name */ 703772d6a58SWilliam Kucharski if ((parsestr = get_token(&token, parsestr, " \t")) == NULL) { 704772d6a58SWilliam Kucharski if (token != NULL) 705772d6a58SWilliam Kucharski free(token); 706772d6a58SWilliam Kucharski 707772d6a58SWilliam Kucharski continue; 708772d6a58SWilliam Kucharski } 709772d6a58SWilliam Kucharski 710772d6a58SWilliam Kucharski if (strcmp(token, "console") == 0) { 711772d6a58SWilliam Kucharski free(token); 712772d6a58SWilliam Kucharski 713772d6a58SWilliam Kucharski /* get console property value */ 714772d6a58SWilliam Kucharski parsestr = get_token(&token, parsestr, " \t"); 715772d6a58SWilliam Kucharski if (token == NULL) 716772d6a58SWilliam Kucharski continue; 717772d6a58SWilliam Kucharski 718772d6a58SWilliam Kucharski if (bootenv_rc_console != NULL) 719772d6a58SWilliam Kucharski free(bootenv_rc_console); 720772d6a58SWilliam Kucharski 721772d6a58SWilliam Kucharski bootenv_rc_console = s_strdup(token); 722772d6a58SWilliam Kucharski continue; 723772d6a58SWilliam Kucharski } 724772d6a58SWilliam Kucharski 725772d6a58SWilliam Kucharski /* check if it's a serial port setting */ 726772d6a58SWilliam Kucharski if (strcmp(token, "ttya-mode") == 0) { 727772d6a58SWilliam Kucharski free(token); 728772d6a58SWilliam Kucharski port = 0; 729772d6a58SWilliam Kucharski } else if (strcmp(token, "ttyb-mode") == 0) { 730772d6a58SWilliam Kucharski free(token); 731772d6a58SWilliam Kucharski port = 1; 732772d6a58SWilliam Kucharski } else { 733772d6a58SWilliam Kucharski /* nope, so check the next line */ 734772d6a58SWilliam Kucharski free(token); 735772d6a58SWilliam Kucharski continue; 736772d6a58SWilliam Kucharski } 737772d6a58SWilliam Kucharski 738772d6a58SWilliam Kucharski /* get serial port setting */ 739772d6a58SWilliam Kucharski parsestr = get_token(&token, parsestr, " \t"); 740772d6a58SWilliam Kucharski 741772d6a58SWilliam Kucharski if (token == NULL) 742772d6a58SWilliam Kucharski continue; 743772d6a58SWilliam Kucharski 744772d6a58SWilliam Kucharski if (bootenv_rc_serial[port] != NULL) 745772d6a58SWilliam Kucharski free(bootenv_rc_serial[port]); 746772d6a58SWilliam Kucharski 747772d6a58SWilliam Kucharski bootenv_rc_serial[port] = s_strdup(token); 748772d6a58SWilliam Kucharski free(token); 74944da779fSWilliam Kucharski } 75044da779fSWilliam Kucharski 75144da779fSWilliam Kucharski (void) fclose(fp); 75244da779fSWilliam Kucharski } 75344da779fSWilliam Kucharski 75444da779fSWilliam Kucharski error_t 75544da779fSWilliam Kucharski cvt_to_hyper(menu_t *mp, char *osroot, char *extra_args) 75644da779fSWilliam Kucharski { 75744da779fSWilliam Kucharski const char *fcn = "cvt_to_hyper()"; 75844da779fSWilliam Kucharski 75944da779fSWilliam Kucharski line_t *lp; 76044da779fSWilliam Kucharski entry_t *ent; 76144da779fSWilliam Kucharski size_t len, zfslen; 76244da779fSWilliam Kucharski 76366b6aef6SWilliam Kucharski char *newstr; 76444da779fSWilliam Kucharski char *osdev; 76544da779fSWilliam Kucharski 76644da779fSWilliam Kucharski char *title = NULL; 76744da779fSWilliam Kucharski char *findroot = NULL; 76844da779fSWilliam Kucharski char *bootfs = NULL; 76944da779fSWilliam Kucharski char *kernel = NULL; 77044da779fSWilliam Kucharski char *mod_kernel = NULL; 77144da779fSWilliam Kucharski char *module = NULL; 77244da779fSWilliam Kucharski 77344da779fSWilliam Kucharski char *kern_path = NULL; 77444da779fSWilliam Kucharski char *kern_bargs = NULL; 77544da779fSWilliam Kucharski 776772d6a58SWilliam Kucharski int curdef, newdef; 77766b6aef6SWilliam Kucharski int kp_allocated = 0; 77844da779fSWilliam Kucharski int ret = BAM_ERROR; 77944da779fSWilliam Kucharski 78044da779fSWilliam Kucharski assert(osroot); 78144da779fSWilliam Kucharski 782*f64ca102SToomas Soome BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, extra_args)); 78344da779fSWilliam Kucharski 78444da779fSWilliam Kucharski /* 78544da779fSWilliam Kucharski * First just check to verify osroot is a sane directory. 78644da779fSWilliam Kucharski */ 78744da779fSWilliam Kucharski if ((osdev = get_special(osroot)) == NULL) { 788*f64ca102SToomas Soome bam_error(_("cant find special file for mount-point %s\n"), 789*f64ca102SToomas Soome osroot); 79044da779fSWilliam Kucharski return (BAM_ERROR); 79144da779fSWilliam Kucharski } 79244da779fSWilliam Kucharski 79344da779fSWilliam Kucharski free(osdev); 79444da779fSWilliam Kucharski 79544da779fSWilliam Kucharski /* 79644da779fSWilliam Kucharski * While the effect is purely cosmetic, if osroot is "/" don't 79744da779fSWilliam Kucharski * bother prepending it to any paths as they are constructed to 79844da779fSWilliam Kucharski * begin with "/" anyway. 79944da779fSWilliam Kucharski */ 80044da779fSWilliam Kucharski if (strcmp(osroot, "/") == 0) 80144da779fSWilliam Kucharski osroot = ""; 80244da779fSWilliam Kucharski 80344da779fSWilliam Kucharski /* 80444da779fSWilliam Kucharski * Found the GRUB signature on the target partitions, so now get the 80544da779fSWilliam Kucharski * default GRUB boot entry number from the menu.lst file 80644da779fSWilliam Kucharski */ 80744da779fSWilliam Kucharski curdef = atoi(mp->curdefault->arg); 80844da779fSWilliam Kucharski 80944da779fSWilliam Kucharski /* look for the first line of the matching boot entry */ 81044da779fSWilliam Kucharski for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef)); 81144da779fSWilliam Kucharski ent = ent->next) 81244da779fSWilliam Kucharski ; 81344da779fSWilliam Kucharski 81444da779fSWilliam Kucharski /* couldn't find it, so error out */ 81544da779fSWilliam Kucharski if (ent == NULL) { 816*f64ca102SToomas Soome bam_error(_("unable to find default boot entry (%d) in " 817*f64ca102SToomas Soome "menu.lst file.\n"), curdef); 81844da779fSWilliam Kucharski goto abort; 81944da779fSWilliam Kucharski } 82044da779fSWilliam Kucharski 82144da779fSWilliam Kucharski /* 82244da779fSWilliam Kucharski * We found the proper menu entry, so first we need to process the 82344da779fSWilliam Kucharski * bootenv.rc file to look for boot options the hypervisor might need 82444da779fSWilliam Kucharski * passed as kernel start options such as the console device and serial 82544da779fSWilliam Kucharski * port parameters. 82644da779fSWilliam Kucharski * 82744da779fSWilliam Kucharski * If there's no bootenv.rc, it's not an issue. 82844da779fSWilliam Kucharski */ 82944da779fSWilliam Kucharski parse_bootenvrc(osroot); 83044da779fSWilliam Kucharski 831772d6a58SWilliam Kucharski if (bootenv_rc_console != NULL) 832772d6a58SWilliam Kucharski console_metal_to_hyper(bootenv_rc_console); 833772d6a58SWilliam Kucharski 834772d6a58SWilliam Kucharski if (bootenv_rc_serial[0] != NULL) 835772d6a58SWilliam Kucharski (void) serial_metal_to_hyper("ttya-mode", bootenv_rc_serial[0]); 836772d6a58SWilliam Kucharski 837772d6a58SWilliam Kucharski if (bootenv_rc_serial[1] != NULL) 838772d6a58SWilliam Kucharski (void) serial_metal_to_hyper("ttyb-mode", bootenv_rc_serial[1]); 839772d6a58SWilliam Kucharski 84044da779fSWilliam Kucharski /* 84144da779fSWilliam Kucharski * Now process the entry itself. 84244da779fSWilliam Kucharski */ 84344da779fSWilliam Kucharski for (lp = ent->start; lp != NULL; lp = lp->next) { 84444da779fSWilliam Kucharski /* 84544da779fSWilliam Kucharski * Process important lines from menu.lst boot entry. 84644da779fSWilliam Kucharski */ 84744da779fSWilliam Kucharski if (lp->flags == BAM_TITLE) { 84823a1cceaSRoger A. Faulkner title = strdupa(lp->arg); 849eac223ccSWilliam Kucharski } else if (lp->cmd != NULL) { 850eac223ccSWilliam Kucharski if (strcmp(lp->cmd, "findroot") == 0) { 85123a1cceaSRoger A. Faulkner findroot = strdupa(lp->arg); 85244da779fSWilliam Kucharski } else if (strcmp(lp->cmd, "bootfs") == 0) { 85323a1cceaSRoger A. Faulkner bootfs = strdupa(lp->arg); 854eac223ccSWilliam Kucharski } else if (strcmp(lp->cmd, 855eac223ccSWilliam Kucharski menu_cmds[MODULE_DOLLAR_CMD]) == 0) { 85623a1cceaSRoger A. Faulkner module = strdupa(lp->arg); 85744da779fSWilliam Kucharski } else if ((strcmp(lp->cmd, 85844da779fSWilliam Kucharski menu_cmds[KERNEL_DOLLAR_CMD]) == 0) && 859eac223ccSWilliam Kucharski (ret = cvt_metal_kernel(lp->arg, 860eac223ccSWilliam Kucharski &kern_path)) != 0) { 86166b6aef6SWilliam Kucharski if (ret < 0) { 86266b6aef6SWilliam Kucharski ret = BAM_ERROR; 863*f64ca102SToomas Soome bam_error(_("kernel$ in default boot " 864*f64ca102SToomas Soome "entry (%d) missing or not " 865*f64ca102SToomas Soome "parseable.\n"), curdef); 86666b6aef6SWilliam Kucharski } else 86744da779fSWilliam Kucharski ret = BAM_NOCHANGE; 86866b6aef6SWilliam Kucharski 86944da779fSWilliam Kucharski goto abort; 87044da779fSWilliam Kucharski } 871eac223ccSWilliam Kucharski } 87244da779fSWilliam Kucharski 87344da779fSWilliam Kucharski if (lp == ent->end) 87444da779fSWilliam Kucharski break; 87544da779fSWilliam Kucharski } 87644da779fSWilliam Kucharski 87744da779fSWilliam Kucharski /* 878772d6a58SWilliam Kucharski * If findroot, module or kern_path are NULL, the boot entry is 879772d6a58SWilliam Kucharski * malformed. 88044da779fSWilliam Kucharski */ 88144da779fSWilliam Kucharski if (findroot == NULL) { 882*f64ca102SToomas Soome bam_error(_("findroot in default boot entry (%d) missing.\n"), 883*f64ca102SToomas Soome curdef); 88444da779fSWilliam Kucharski goto abort; 88544da779fSWilliam Kucharski } 88644da779fSWilliam Kucharski 88744da779fSWilliam Kucharski if (module == NULL) { 888*f64ca102SToomas Soome bam_error(_("module$ in default boot entry (%d) missing or " 889*f64ca102SToomas Soome "not parseable.\n"), curdef); 89044da779fSWilliam Kucharski goto abort; 89144da779fSWilliam Kucharski } 89244da779fSWilliam Kucharski 89344da779fSWilliam Kucharski if (kern_path == NULL) { 894*f64ca102SToomas Soome bam_error(_("kernel$ in default boot entry (%d) missing.\n"), 895*f64ca102SToomas Soome curdef); 89644da779fSWilliam Kucharski goto abort; 89744da779fSWilliam Kucharski } 89844da779fSWilliam Kucharski 89944da779fSWilliam Kucharski /* assemble new kernel and module arguments from parsed values */ 90044da779fSWilliam Kucharski if (console_dev != NULL) { 90144da779fSWilliam Kucharski kern_bargs = s_strdup(console_dev); 90244da779fSWilliam Kucharski 90366b6aef6SWilliam Kucharski if (serial_config[0] != NULL) { 90466b6aef6SWilliam Kucharski newstr = append_str(kern_bargs, serial_config[0], " "); 90566b6aef6SWilliam Kucharski free(kern_bargs); 90666b6aef6SWilliam Kucharski kern_bargs = newstr; 90744da779fSWilliam Kucharski } 90844da779fSWilliam Kucharski 90966b6aef6SWilliam Kucharski if (serial_config[1] != NULL) { 91066b6aef6SWilliam Kucharski newstr = append_str(kern_bargs, serial_config[1], " "); 91166b6aef6SWilliam Kucharski free(kern_bargs); 91266b6aef6SWilliam Kucharski kern_bargs = newstr; 91366b6aef6SWilliam Kucharski } 91466b6aef6SWilliam Kucharski } 91566b6aef6SWilliam Kucharski 91666b6aef6SWilliam Kucharski if ((extra_args != NULL) && (*extra_args != NULL)) { 91766b6aef6SWilliam Kucharski newstr = append_str(kern_bargs, extra_args, " "); 91866b6aef6SWilliam Kucharski free(kern_bargs); 91966b6aef6SWilliam Kucharski kern_bargs = newstr; 92066b6aef6SWilliam Kucharski } 92144da779fSWilliam Kucharski 92244da779fSWilliam Kucharski len = strlen(osroot) + strlen(XEN_MENU) + strlen(kern_bargs) + 92344da779fSWilliam Kucharski WHITESPC(1) + 1; 92444da779fSWilliam Kucharski 92544da779fSWilliam Kucharski kernel = alloca(len); 92644da779fSWilliam Kucharski 92766b6aef6SWilliam Kucharski if (kern_bargs != NULL) { 92866b6aef6SWilliam Kucharski if (*kern_bargs != NULL) 92966b6aef6SWilliam Kucharski (void) snprintf(kernel, len, "%s%s %s", osroot, 93066b6aef6SWilliam Kucharski XEN_MENU, kern_bargs); 93166b6aef6SWilliam Kucharski 93244da779fSWilliam Kucharski free(kern_bargs); 93344da779fSWilliam Kucharski } else { 93444da779fSWilliam Kucharski (void) snprintf(kernel, len, "%s%s", osroot, XEN_MENU); 93544da779fSWilliam Kucharski } 93644da779fSWilliam Kucharski 93744da779fSWilliam Kucharski /* 93844da779fSWilliam Kucharski * Change the kernel directory from the metal version to that needed for 93944da779fSWilliam Kucharski * the hypervisor. Convert either "direct boot" path to the default 94044da779fSWilliam Kucharski * path. 94144da779fSWilliam Kucharski */ 94244da779fSWilliam Kucharski if ((strcmp(kern_path, DIRECT_BOOT_32) == 0) || 94344da779fSWilliam Kucharski (strcmp(kern_path, DIRECT_BOOT_64) == 0)) { 94444da779fSWilliam Kucharski kern_path = HYPERVISOR_KERNEL; 94544da779fSWilliam Kucharski } else { 94666b6aef6SWilliam Kucharski newstr = modify_path(kern_path, METAL_KERNEL_DIR, 94744da779fSWilliam Kucharski HYPER_KERNEL_DIR); 94866b6aef6SWilliam Kucharski free(kern_path); 94966b6aef6SWilliam Kucharski kern_path = newstr; 95066b6aef6SWilliam Kucharski kp_allocated = 1; 95144da779fSWilliam Kucharski } 95244da779fSWilliam Kucharski 95344da779fSWilliam Kucharski /* 95444da779fSWilliam Kucharski * We need to allocate space for the kernel path (twice) plus an 95544da779fSWilliam Kucharski * intervening space, possibly the ZFS boot string, and NULL, 95644da779fSWilliam Kucharski * of course. 95744da779fSWilliam Kucharski */ 95844da779fSWilliam Kucharski len = (strlen(kern_path) * 2) + WHITESPC(1) + 1; 95944da779fSWilliam Kucharski zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0); 96044da779fSWilliam Kucharski 96144da779fSWilliam Kucharski mod_kernel = alloca(len + zfslen); 96244da779fSWilliam Kucharski (void) snprintf(mod_kernel, len, "%s %s", kern_path, kern_path); 96344da779fSWilliam Kucharski 96444da779fSWilliam Kucharski if (kp_allocated) 96544da779fSWilliam Kucharski free(kern_path); 96644da779fSWilliam Kucharski 96744da779fSWilliam Kucharski if (zfs_boot) { 96844da779fSWilliam Kucharski char *zfsstr = alloca(zfslen + 1); 96944da779fSWilliam Kucharski 97044da779fSWilliam Kucharski (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT); 97144da779fSWilliam Kucharski (void) strcat(mod_kernel, zfsstr); 97244da779fSWilliam Kucharski } 97344da779fSWilliam Kucharski 97444da779fSWilliam Kucharski /* shut off warning messages from the entry line parser */ 97544da779fSWilliam Kucharski if (ent->flags & BAM_ENTRY_BOOTADM) 97644da779fSWilliam Kucharski ent->flags &= ~BAM_ENTRY_BOOTADM; 97744da779fSWilliam Kucharski 978*f64ca102SToomas Soome BAM_DPRINTF(("%s: converted kernel cmd to %s\n", fcn, kernel)); 979*f64ca102SToomas Soome BAM_DPRINTF(("%s: converted module cmd to %s\n", fcn, mod_kernel)); 98044da779fSWilliam Kucharski 981772d6a58SWilliam Kucharski if ((newdef = add_boot_entry(mp, title, findroot, kernel, mod_kernel, 982772d6a58SWilliam Kucharski module, bootfs)) == BAM_ERROR) 983772d6a58SWilliam Kucharski return (newdef); 984772d6a58SWilliam Kucharski 98544da779fSWilliam Kucharski /* 98644da779fSWilliam Kucharski * Now try to delete the current default entry from the menu and add 98744da779fSWilliam Kucharski * the new hypervisor entry with the parameters we've setup. 98844da779fSWilliam Kucharski */ 989772d6a58SWilliam Kucharski if (delete_boot_entry(mp, curdef, DBE_QUIET) == BAM_SUCCESS) 990772d6a58SWilliam Kucharski newdef--; 991772d6a58SWilliam Kucharski else 992*f64ca102SToomas Soome bam_print(_("unable to modify default entry; creating new " 993*f64ca102SToomas Soome "boot entry for %s\n"), title); 99444da779fSWilliam Kucharski 99544da779fSWilliam Kucharski /* 99644da779fSWilliam Kucharski * If we successfully created the new entry, set the default boot 99744da779fSWilliam Kucharski * entry to that entry and let the caller know the new menu should 99844da779fSWilliam Kucharski * be written out. 99944da779fSWilliam Kucharski */ 1000772d6a58SWilliam Kucharski return (set_global(mp, menu_cmds[DEFAULT_CMD], newdef)); 100144da779fSWilliam Kucharski 100244da779fSWilliam Kucharski abort: 100344da779fSWilliam Kucharski if (ret != BAM_NOCHANGE) 1004*f64ca102SToomas Soome bam_error(_("error converting GRUB menu entry on %s for use " 1005*f64ca102SToomas Soome "with the hypervisor.\nAborting.\n"), 1006*f64ca102SToomas Soome ((*osroot == NULL) ? "/" : osroot)); 100744da779fSWilliam Kucharski 100844da779fSWilliam Kucharski return (ret); 100944da779fSWilliam Kucharski } 101044da779fSWilliam Kucharski 101144da779fSWilliam Kucharski /*ARGSUSED*/ 101244da779fSWilliam Kucharski error_t 101344da779fSWilliam Kucharski cvt_to_metal(menu_t *mp, char *osroot, char *menu_root) 101444da779fSWilliam Kucharski { 101544da779fSWilliam Kucharski const char *fcn = "cvt_to_metal()"; 101644da779fSWilliam Kucharski 101744da779fSWilliam Kucharski line_t *lp; 101844da779fSWilliam Kucharski entry_t *ent; 101944da779fSWilliam Kucharski size_t len, zfslen; 102044da779fSWilliam Kucharski 102144da779fSWilliam Kucharski char *delim = ","; 102266b6aef6SWilliam Kucharski char *newstr; 102344da779fSWilliam Kucharski char *osdev; 102444da779fSWilliam Kucharski 102544da779fSWilliam Kucharski char *title = NULL; 102644da779fSWilliam Kucharski char *findroot = NULL; 102744da779fSWilliam Kucharski char *bootfs = NULL; 102844da779fSWilliam Kucharski char *kernel = NULL; 102944da779fSWilliam Kucharski char *module = NULL; 103044da779fSWilliam Kucharski 103144da779fSWilliam Kucharski char *barchive_path = DIRECT_BOOT_ARCHIVE; 103244da779fSWilliam Kucharski char *kern_path = NULL; 103344da779fSWilliam Kucharski 1034772d6a58SWilliam Kucharski int curdef, newdef; 103544da779fSWilliam Kucharski int emit_bflag = 1; 103644da779fSWilliam Kucharski int ret = BAM_ERROR; 103744da779fSWilliam Kucharski 103844da779fSWilliam Kucharski assert(osroot); 103944da779fSWilliam Kucharski 1040*f64ca102SToomas Soome BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn, osroot, "")); 104144da779fSWilliam Kucharski 104244da779fSWilliam Kucharski /* 104344da779fSWilliam Kucharski * First just check to verify osroot is a sane directory. 104444da779fSWilliam Kucharski */ 104544da779fSWilliam Kucharski if ((osdev = get_special(osroot)) == NULL) { 1046*f64ca102SToomas Soome bam_error(_("cant find special file for mount-point %s\n"), 1047*f64ca102SToomas Soome osroot); 104844da779fSWilliam Kucharski return (BAM_ERROR); 104944da779fSWilliam Kucharski } 105044da779fSWilliam Kucharski 105144da779fSWilliam Kucharski free(osdev); 105244da779fSWilliam Kucharski 105344da779fSWilliam Kucharski /* 105444da779fSWilliam Kucharski * Found the GRUB signature on the target partitions, so now get the 105544da779fSWilliam Kucharski * default GRUB boot entry number from the menu.lst file 105644da779fSWilliam Kucharski */ 105744da779fSWilliam Kucharski curdef = atoi(mp->curdefault->arg); 105844da779fSWilliam Kucharski 105944da779fSWilliam Kucharski /* look for the first line of the matching boot entry */ 106044da779fSWilliam Kucharski for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef)); 106144da779fSWilliam Kucharski ent = ent->next) 106244da779fSWilliam Kucharski ; 106344da779fSWilliam Kucharski 106444da779fSWilliam Kucharski /* couldn't find it, so error out */ 106544da779fSWilliam Kucharski if (ent == NULL) { 1066*f64ca102SToomas Soome bam_error(_("unable to find default boot entry (%d) in " 1067*f64ca102SToomas Soome "menu.lst file.\n"), curdef); 106844da779fSWilliam Kucharski goto abort; 106944da779fSWilliam Kucharski } 107044da779fSWilliam Kucharski 107144da779fSWilliam Kucharski /* 107244da779fSWilliam Kucharski * Now process the entry itself. 107344da779fSWilliam Kucharski */ 107444da779fSWilliam Kucharski for (lp = ent->start; lp != NULL; lp = lp->next) { 107544da779fSWilliam Kucharski /* 107644da779fSWilliam Kucharski * Process important lines from menu.lst boot entry. 107744da779fSWilliam Kucharski */ 107844da779fSWilliam Kucharski if (lp->flags == BAM_TITLE) { 107923a1cceaSRoger A. Faulkner title = strdupa(lp->arg); 1080eac223ccSWilliam Kucharski } else if (lp->cmd != NULL) { 1081eac223ccSWilliam Kucharski if (strcmp(lp->cmd, "findroot") == 0) { 108223a1cceaSRoger A. Faulkner findroot = strdupa(lp->arg); 108344da779fSWilliam Kucharski } else if (strcmp(lp->cmd, "bootfs") == 0) { 108423a1cceaSRoger A. Faulkner bootfs = strdupa(lp->arg); 1085eac223ccSWilliam Kucharski } else if (strcmp(lp->cmd, 1086eac223ccSWilliam Kucharski menu_cmds[MODULE_DOLLAR_CMD]) == 0) { 108744da779fSWilliam Kucharski if (strstr(lp->arg, "boot_archive") == NULL) { 108823a1cceaSRoger A. Faulkner module = strdupa(lp->arg); 108944da779fSWilliam Kucharski cvt_hyper_module(module, &kern_path); 109044da779fSWilliam Kucharski } else { 109123a1cceaSRoger A. Faulkner barchive_path = strdupa(lp->arg); 109244da779fSWilliam Kucharski } 109344da779fSWilliam Kucharski } else if ((strcmp(lp->cmd, 109444da779fSWilliam Kucharski menu_cmds[KERNEL_DOLLAR_CMD]) == 0) && 109544da779fSWilliam Kucharski (cvt_hyper_kernel(lp->arg) < 0)) { 109644da779fSWilliam Kucharski ret = BAM_NOCHANGE; 109744da779fSWilliam Kucharski goto abort; 109844da779fSWilliam Kucharski } 1099eac223ccSWilliam Kucharski } 110044da779fSWilliam Kucharski 110144da779fSWilliam Kucharski if (lp == ent->end) 110244da779fSWilliam Kucharski break; 110344da779fSWilliam Kucharski } 110444da779fSWilliam Kucharski 110544da779fSWilliam Kucharski /* 1106772d6a58SWilliam Kucharski * If findroot, module or kern_path are NULL, the boot entry is 1107772d6a58SWilliam Kucharski * malformed. 110844da779fSWilliam Kucharski */ 110944da779fSWilliam Kucharski if (findroot == NULL) { 1110*f64ca102SToomas Soome bam_error(_("findroot in default boot entry (%d) missing.\n"), 1111*f64ca102SToomas Soome curdef); 111244da779fSWilliam Kucharski goto abort; 111344da779fSWilliam Kucharski } 111444da779fSWilliam Kucharski 111544da779fSWilliam Kucharski if (module == NULL) { 1116*f64ca102SToomas Soome bam_error(_("module$ in default boot entry (%d) missing or " 1117*f64ca102SToomas Soome "not parseable.\n"), curdef); 111844da779fSWilliam Kucharski goto abort; 111944da779fSWilliam Kucharski } 112044da779fSWilliam Kucharski 112144da779fSWilliam Kucharski if (kern_path == NULL) { 1122*f64ca102SToomas Soome bam_error(_("kernel$ in default boot entry (%d) missing.\n"), 1123*f64ca102SToomas Soome curdef); 112444da779fSWilliam Kucharski goto abort; 112544da779fSWilliam Kucharski } 112644da779fSWilliam Kucharski 112744da779fSWilliam Kucharski /* 112844da779fSWilliam Kucharski * Assemble new kernel and module arguments from parsed values. 112944da779fSWilliam Kucharski * 113044da779fSWilliam Kucharski * First, change the kernel directory from the hypervisor version to 113144da779fSWilliam Kucharski * that needed for a metal kernel. 113244da779fSWilliam Kucharski */ 113366b6aef6SWilliam Kucharski newstr = modify_path(kern_path, HYPER_KERNEL_DIR, METAL_KERNEL_DIR); 113466b6aef6SWilliam Kucharski free(kern_path); 113566b6aef6SWilliam Kucharski kern_path = newstr; 113644da779fSWilliam Kucharski 113744da779fSWilliam Kucharski /* allocate initial space for the kernel path */ 113844da779fSWilliam Kucharski len = strlen(kern_path) + 1; 113944da779fSWilliam Kucharski zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0); 114044da779fSWilliam Kucharski 114144da779fSWilliam Kucharski if ((kernel = malloc(len + zfslen)) == NULL) { 114244da779fSWilliam Kucharski free(kern_path); 1143*f64ca102SToomas Soome bam_error(_("could not allocate memory: size = %u\n"), 1144*f64ca102SToomas Soome len + zfslen); 114566b6aef6SWilliam Kucharski bam_exit(1); 114644da779fSWilliam Kucharski } 114744da779fSWilliam Kucharski 114844da779fSWilliam Kucharski (void) snprintf(kernel, len, "%s", kern_path); 114944da779fSWilliam Kucharski free(kern_path); 115044da779fSWilliam Kucharski 115144da779fSWilliam Kucharski if (zfs_boot) { 115244da779fSWilliam Kucharski char *zfsstr = alloca(zfslen + 1); 115344da779fSWilliam Kucharski 115444da779fSWilliam Kucharski (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT); 115544da779fSWilliam Kucharski (void) strcat(kernel, zfsstr); 115644da779fSWilliam Kucharski emit_bflag = 0; 115744da779fSWilliam Kucharski } 115844da779fSWilliam Kucharski 1159772d6a58SWilliam Kucharski /* 1160772d6a58SWilliam Kucharski * Process the bootenv.rc file to look for boot options that would be 1161772d6a58SWilliam Kucharski * the same as what the hypervisor had manually set, as we need not set 1162772d6a58SWilliam Kucharski * those explicitly. 1163772d6a58SWilliam Kucharski * 1164772d6a58SWilliam Kucharski * If there's no bootenv.rc, it's not an issue. 1165772d6a58SWilliam Kucharski */ 1166772d6a58SWilliam Kucharski parse_bootenvrc(osroot); 1167772d6a58SWilliam Kucharski 1168772d6a58SWilliam Kucharski /* 1169772d6a58SWilliam Kucharski * Don't emit a console setting if it's the same as what would be 1170772d6a58SWilliam Kucharski * set by bootenv.rc. 1171772d6a58SWilliam Kucharski */ 1172772d6a58SWilliam Kucharski if ((console_dev != NULL) && (bootenv_rc_console == NULL || 1173772d6a58SWilliam Kucharski (strcmp(console_dev, bootenv_rc_console) != 0))) { 117444da779fSWilliam Kucharski if (emit_bflag) { 117566b6aef6SWilliam Kucharski newstr = append_str(kernel, BFLAG, " "); 117666b6aef6SWilliam Kucharski free(kernel); 1177772d6a58SWilliam Kucharski kernel = append_str(newstr, "console=", " "); 117866b6aef6SWilliam Kucharski free(newstr); 1179772d6a58SWilliam Kucharski newstr = append_str(kernel, console_dev, ""); 118066b6aef6SWilliam Kucharski free(kernel); 118166b6aef6SWilliam Kucharski kernel = newstr; 1182772d6a58SWilliam Kucharski emit_bflag = 0; 1183772d6a58SWilliam Kucharski } else { 1184772d6a58SWilliam Kucharski newstr = append_str(kernel, "console=", ","); 1185772d6a58SWilliam Kucharski free(kernel); 1186772d6a58SWilliam Kucharski kernel = append_str(newstr, console_dev, ""); 1187772d6a58SWilliam Kucharski free(newstr); 118844da779fSWilliam Kucharski } 118944da779fSWilliam Kucharski } 119044da779fSWilliam Kucharski 119144da779fSWilliam Kucharski /* 1192772d6a58SWilliam Kucharski * We have to do some strange processing here because the hypervisor's 1193772d6a58SWilliam Kucharski * serial ports default to "9600,8,n,1,-" if "comX=auto" is specified, 1194772d6a58SWilliam Kucharski * or to "auto" if nothing is specified. 119544da779fSWilliam Kucharski * 1196772d6a58SWilliam Kucharski * This could result in a serial mode setting string being added when 1197772d6a58SWilliam Kucharski * it would otherwise not be needed, but it's better to play it safe. 119844da779fSWilliam Kucharski */ 119944da779fSWilliam Kucharski if (emit_bflag) { 120066b6aef6SWilliam Kucharski newstr = append_str(kernel, BFLAG, " "); 120166b6aef6SWilliam Kucharski free(kernel); 120266b6aef6SWilliam Kucharski kernel = newstr; 120344da779fSWilliam Kucharski delim = " "; 120444da779fSWilliam Kucharski emit_bflag = 0; 120544da779fSWilliam Kucharski } 120644da779fSWilliam Kucharski 1207772d6a58SWilliam Kucharski if ((serial_config[0] != NULL) && (bootenv_rc_serial[0] == NULL || 1208772d6a58SWilliam Kucharski (strcmp(serial_config[0], bootenv_rc_serial[0]) != 0))) { 1209772d6a58SWilliam Kucharski newstr = append_str(kernel, "ttya-mode='", delim); 121066b6aef6SWilliam Kucharski free(kernel); 121144da779fSWilliam Kucharski 1212772d6a58SWilliam Kucharski /* 1213772d6a58SWilliam Kucharski * Pass the serial configuration as the delimiter to 1214772d6a58SWilliam Kucharski * append_str() as it will be inserted between the current 1215772d6a58SWilliam Kucharski * string and the string we're appending, in this case the 1216772d6a58SWilliam Kucharski * closing single quote. 1217772d6a58SWilliam Kucharski */ 1218772d6a58SWilliam Kucharski kernel = append_str(newstr, "'", serial_config[0]); 121966b6aef6SWilliam Kucharski free(newstr); 1220772d6a58SWilliam Kucharski delim = ","; 1221772d6a58SWilliam Kucharski } 1222772d6a58SWilliam Kucharski 1223772d6a58SWilliam Kucharski if ((serial_config[1] != NULL) && (bootenv_rc_serial[1] == NULL || 1224772d6a58SWilliam Kucharski (strcmp(serial_config[1], bootenv_rc_serial[1]) != 0))) { 1225772d6a58SWilliam Kucharski newstr = append_str(kernel, "ttyb-mode='", delim); 1226772d6a58SWilliam Kucharski free(kernel); 1227772d6a58SWilliam Kucharski 1228772d6a58SWilliam Kucharski /* 1229772d6a58SWilliam Kucharski * Pass the serial configuration as the delimiter to 1230772d6a58SWilliam Kucharski * append_str() as it will be inserted between the current 1231772d6a58SWilliam Kucharski * string and the string we're appending, in this case the 1232772d6a58SWilliam Kucharski * closing single quote. 1233772d6a58SWilliam Kucharski */ 1234772d6a58SWilliam Kucharski kernel = append_str(newstr, "'", serial_config[1]); 1235772d6a58SWilliam Kucharski free(newstr); 1236772d6a58SWilliam Kucharski delim = ","; 1237772d6a58SWilliam Kucharski } 123844da779fSWilliam Kucharski 123944da779fSWilliam Kucharski /* shut off warning messages from the entry line parser */ 124044da779fSWilliam Kucharski if (ent->flags & BAM_ENTRY_BOOTADM) 124144da779fSWilliam Kucharski ent->flags &= ~BAM_ENTRY_BOOTADM; 124244da779fSWilliam Kucharski 1243*f64ca102SToomas Soome BAM_DPRINTF(("%s: converted kernel cmd to %s\n", fcn, kernel)); 1244*f64ca102SToomas Soome BAM_DPRINTF(("%s: converted module cmd to %s\n", fcn, module)); 124544da779fSWilliam Kucharski 1246772d6a58SWilliam Kucharski if ((newdef = add_boot_entry(mp, title, findroot, kernel, NULL, 1247772d6a58SWilliam Kucharski barchive_path, bootfs)) == BAM_ERROR) { 1248772d6a58SWilliam Kucharski free(kernel); 1249772d6a58SWilliam Kucharski return (newdef); 1250772d6a58SWilliam Kucharski } 1251772d6a58SWilliam Kucharski 125244da779fSWilliam Kucharski /* 125344da779fSWilliam Kucharski * Now try to delete the current default entry from the menu and add 125444da779fSWilliam Kucharski * the new hypervisor entry with the parameters we've setup. 125544da779fSWilliam Kucharski */ 1256772d6a58SWilliam Kucharski if (delete_boot_entry(mp, curdef, DBE_QUIET) == BAM_SUCCESS) 1257772d6a58SWilliam Kucharski newdef--; 1258772d6a58SWilliam Kucharski else 1259*f64ca102SToomas Soome bam_print(_("unable to modify default entry; creating new " 1260*f64ca102SToomas Soome "boot entry for %s\n"), title); 126144da779fSWilliam Kucharski 1262772d6a58SWilliam Kucharski free(kernel); 126344da779fSWilliam Kucharski 126444da779fSWilliam Kucharski /* 126544da779fSWilliam Kucharski * If we successfully created the new entry, set the default boot 126644da779fSWilliam Kucharski * entry to that entry and let the caller know the new menu should 126744da779fSWilliam Kucharski * be written out. 126844da779fSWilliam Kucharski */ 1269772d6a58SWilliam Kucharski return (set_global(mp, menu_cmds[DEFAULT_CMD], newdef)); 127044da779fSWilliam Kucharski 127144da779fSWilliam Kucharski abort: 127244da779fSWilliam Kucharski if (ret != BAM_NOCHANGE) 1273*f64ca102SToomas Soome bam_error(_("error converting GRUB menu entry on %s for use " 1274*f64ca102SToomas Soome "with a metal kernel.\nAborting.\n"), osroot); 127544da779fSWilliam Kucharski 127644da779fSWilliam Kucharski return (ret); 127744da779fSWilliam Kucharski } 1278