Index: stable/10/usr.sbin/bsdinstall/partedit/gpart_ops.c =================================================================== --- stable/10/usr.sbin/bsdinstall/partedit/gpart_ops.c +++ stable/10/usr.sbin/bsdinstall/partedit/gpart_ops.c @@ -206,12 +206,11 @@ } } -int -gpart_partition(const char *lg_name, const char *scheme) +const char * +choose_part_type(const char *def_scheme) { int cancel, choice; - struct gctl_req *r; - const char *errstr; + const char *scheme = NULL; DIALOG_LISTITEM items[] = { {"APM", "Apple Partition Map", @@ -228,30 +227,61 @@ "Bootable on Sun SPARC systems", 0 }, }; +parttypemenu: + dialog_vars.default_item = __DECONST(char *, def_scheme); + cancel = dlg_menu("Partition Scheme", + "Select a partition scheme for this volume:", 0, 0, 0, + sizeof(items) / sizeof(items[0]), items, &choice, NULL); + dialog_vars.default_item = NULL; + + if (cancel) + return NULL; + + if (!is_scheme_bootable(items[choice].name)) { + char message[512]; + sprintf(message, "This partition scheme (%s) is not " + "bootable on this platform. Are you sure you want " + "to proceed?", items[choice].name); + dialog_vars.defaultno = TRUE; + cancel = dialog_yesno("Warning", message, 0, 0); + dialog_vars.defaultno = FALSE; + if (cancel) /* cancel */ + goto parttypemenu; + } + + scheme = items[choice].name; + + return scheme; +} + +int +gpart_partition(const char *lg_name, const char *scheme) +{ + int cancel; + struct gctl_req *r; + const char *errstr; + schememenu: if (scheme == NULL) { - dialog_vars.default_item = __DECONST(char *, default_scheme()); - cancel = dlg_menu("Partition Scheme", - "Select a partition scheme for this volume:", 0, 0, 0, - sizeof(items) / sizeof(items[0]), items, &choice, NULL); - dialog_vars.default_item = NULL; + scheme = choose_part_type(default_scheme()); - if (cancel) + if (scheme == NULL) return (-1); - if (!is_scheme_bootable(items[choice].name)) { + if (!is_scheme_bootable(scheme)) { char message[512]; sprintf(message, "This partition scheme (%s) is not " "bootable on this platform. Are you sure you want " - "to proceed?", items[choice].name); + "to proceed?", scheme); dialog_vars.defaultno = TRUE; cancel = dialog_yesno("Warning", message, 0, 0); dialog_vars.defaultno = FALSE; - if (cancel) /* cancel */ + if (cancel) { /* cancel */ + /* Reset scheme so user can choose another */ + scheme = NULL; goto schememenu; + } } - - scheme = items[choice].name; } r = gctl_get_handle(); @@ -322,6 +352,26 @@ gctl_free(r); } +void +gpart_set_root(const char *lg_name, const char *attribute) +{ + struct gctl_req *r; + const char *errstr; + + r = gctl_get_handle(); + gctl_ro_param(r, "class", -1, "PART"); + gctl_ro_param(r, "arg0", -1, lg_name); + gctl_ro_param(r, "flags", -1, "C"); + gctl_ro_param(r, "verb", -1, "set"); + gctl_ro_param(r, "attrib", -1, attribute); + + errstr = gctl_issue(r); + if (errstr != NULL && errstr[0] != '\0') + gpart_show_error("Error", "Error setting parameter on disk:", + errstr); + gctl_free(r); +} + static void gpart_bootcode(struct ggeom *gp) { Index: stable/10/usr.sbin/bsdinstall/partedit/part_wizard.c =================================================================== --- stable/10/usr.sbin/bsdinstall/partedit/part_wizard.c +++ stable/10/usr.sbin/bsdinstall/partedit/part_wizard.c @@ -257,8 +257,10 @@ goto query; gpart_destroy(gpart); - gpart_partition(disk, default_scheme()); - scheme = default_scheme(); + scheme = choose_part_type(default_scheme()); + if (scheme == NULL) + return NULL; + gpart_partition(disk, scheme); } if (scheme == NULL || choice == 0) { @@ -272,8 +274,10 @@ gpart_destroy(gpart); } - gpart_partition(disk, default_scheme()); - scheme = default_scheme(); + scheme = choose_part_type(default_scheme()); + if (scheme == NULL) + return NULL; + gpart_partition(disk, scheme); } if (strcmp(scheme, "PC98") == 0 || strcmp(scheme, "MBR") == 0) { Index: stable/10/usr.sbin/bsdinstall/partedit/partedit.h =================================================================== --- stable/10/usr.sbin/bsdinstall/partedit/partedit.h +++ stable/10/usr.sbin/bsdinstall/partedit/partedit.h @@ -72,6 +72,8 @@ int gpart_partition(const char *lg_name, const char *scheme); void set_default_part_metadata(const char *name, const char *scheme, const char *type, const char *mountpoint, const char *newfs); +void gpart_set_root(const char *lg_name, const char *attribute); +const char *choose_part_type(const char *def_scheme); /* machine-dependent bootability checks */ const char *default_scheme(void); Index: stable/10/usr.sbin/bsdinstall/partedit/partedit.c =================================================================== --- stable/10/usr.sbin/bsdinstall/partedit/partedit.c +++ stable/10/usr.sbin/bsdinstall/partedit/partedit.c @@ -44,6 +44,7 @@ static int sade_mode = 0; static int apply_changes(struct gmesh *mesh); +static void apply_workaround(struct gmesh *mesh); static struct partedit_item *read_geom_mesh(struct gmesh *mesh, int *nitems); static void add_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items, int *nitems); @@ -189,6 +190,8 @@ if (op == 0 && validate_setup()) { /* Save */ error = apply_changes(&mesh); + if (!error) + apply_workaround(&mesh); break; } else if (op == 3) { /* Quit */ gpart_revert_all(&mesh); @@ -390,6 +393,43 @@ return (0); } +static void +apply_workaround(struct gmesh *mesh) +{ + struct gclass *classp; + struct ggeom *gp; + struct gconfig *gc; + const char *scheme = NULL, *modified = NULL; + + LIST_FOREACH(classp, &mesh->lg_class, lg_class) { + if (strcmp(classp->lg_name, "PART") == 0) + break; + } + + if (strcmp(classp->lg_name, "PART") != 0) { + dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); + return; + } + + LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { + LIST_FOREACH(gc, &gp->lg_config, lg_config) { + if (strcmp(gc->lg_name, "scheme") == 0) { + scheme = gc->lg_val; + } else if (strcmp(gc->lg_name, "modified") == 0) { + modified = gc->lg_val; + } + } + + if (scheme && strcmp(scheme, "GPT") == 0 && + modified && strcmp(modified, "true") == 0) { + if (getenv("WORKAROUND_LENOVO")) + gpart_set_root(gp->lg_name, "lenovofix"); + if (getenv("WORKAROUND_GPTACTIVE")) + gpart_set_root(gp->lg_name, "active"); + } + } +} + static struct partedit_item * read_geom_mesh(struct gmesh *mesh, int *nitems) { Index: stable/10/usr.sbin/bsdinstall/scripts/auto =================================================================== --- stable/10/usr.sbin/bsdinstall/scripts/auto +++ stable/10/usr.sbin/bsdinstall/scripts/auto @@ -31,6 +31,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 +f_include $BSDCFG_SHARE/dialog.subr ############################################################ FUNCTIONS @@ -51,6 +52,54 @@ fi } +hline_arrows_tab_enter="Press arrows, TAB or ENTER" +msg_gpt_active_fix="Your hardware is known to have issues booting in BIOS mode from GPT partitions that are not set active. Would you like the installer to apply this workaround for you?" +msg_lenovo_fix="Your model of Lenovo is known to have a BIOS bug that prevents it booting from GPT partitions without UEFI. Would you like the installer to apply a workaround for you?" +msg_no="NO" +msg_yes="YES" + +# dialog_workaround +# +# Ask the user if they wish to apply a workaround +# +dialog_workaround() +{ + local passed_msg="$1" + local title="$DIALOG_TITLE" + local btitle="$DIALOG_BACKTITLE" + local prompt # Calculated below + local hline="$hline_arrows_tab_enter" + + local height=8 width=50 prefix=" " + local plen=${#prefix} list= line= + local max_width=$(( $width - 3 - $plen )) + + local yes no defaultno extra_args format + if [ "$USE_XDIALOG" ]; then + yes=ok no=cancel defaultno=default-no + extra_args="--wrap --left" + format="$passed_msg" + else + yes=yes no=no defaultno=defaultno + extra_args="--cr-wrap" + format="$passed_msg" + fi + + # Add height for Xdialog(1) + [ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 )) + + prompt=$( printf "$format" ) + f_dprintf "%s: Workaround prompt" "$0" + $DIALOG \ + --title "$title" \ + --backtitle "$btitle" \ + --hline "$hline" \ + --$yes-label "$msg_yes" \ + --$no-label "$msg_no" \ + $extra_args \ + --yesno "$prompt" $height $width +} + ############################################################ MAIN f_dprintf "Began Installation at %s" "$( date )" @@ -106,6 +155,47 @@ rm -f $PATH_FSTAB touch $PATH_FSTAB +# +# Try to detect known broken platforms and apply their workarounds +# + +if f_interactive; then + sys_maker=$( kenv -q smbios.system.maker ) + f_dprintf "smbios.system.maker=[%s]" "$sys_maker" + sys_model=$( kenv -q smbios.system.product ) + f_dprintf "smbios.system.product=[%s]" "$sys_model" + sys_version=$( kenv -q smbios.system.version ) + f_dprintf "smbios.system.version=[%s]" "$sys_version" + case "$sys_maker" in + "LENOVO") + case "$sys_version" in + "ThinkPad X220"|"ThinkPad T420"|"ThinkPad T520") + dialog_workaround "$msg_lenovo_fix" + retval=$? + f_dprintf "lenovofix_prompt=[%s]" "$retval" + if [ $retval -eq $DIALOG_OK ]; then + export ZFSBOOT_PARTITION_SCHEME="GPT + Lenovo Fix" + export WORKAROUND_LENOVO=1 + fi + ;; + esac + ;; + "Dell Inc.") + case "$sys_model" in + "Latitude E7440") + dialog_workaround "$msg_gpt_active_fix" + retval=$? + f_dprintf "gpt_active_fix_prompt=[%s]" "$retval" + if [ $retval -eq $DIALOG_OK ]; then + export ZFSBOOT_PARTITION_SCHEME="GPT + Active" + export WORKAROUND_GPTACTIVE=1 + fi + ;; + esac + ;; + esac +fi + PMODES="\ \"Auto (UFS)\" \"Guided Disk Setup\" \ Manual \"Manual Disk Setup (experts)\" \ Index: stable/10/usr.sbin/bsdinstall/scripts/zfsboot =================================================================== --- stable/10/usr.sbin/bsdinstall/scripts/zfsboot +++ stable/10/usr.sbin/bsdinstall/scripts/zfsboot @@ -196,6 +196,8 @@ GPART_CREATE='gpart create -s %s "%s"' GPART_DESTROY_F='gpart destroy -F "%s"' GPART_SET_ACTIVE='gpart set -a active -i %s "%s"' +GPART_SET_LENOVOFIX='gpart set -a lenovofix "%s"' +GPART_SET_PMBR_ACTIVE='gpart set -a active "%s"' GRAID_DELETE='graid delete "%s"' LN_SF='ln -sf "%s" "%s"' MKDIR_P='mkdir -p "%s"' @@ -263,7 +265,7 @@ msg_null_poolname="NULL poolname" msg_ok="OK" msg_partition_scheme="Partition Scheme" -msg_partition_scheme_help="Toggle between GPT and MBR partitioning schemes" +msg_partition_scheme_help="Select partitioning scheme. GPT is recommended." msg_please_enter_a_name_for_your_zpool="Please enter a name for your zpool:" msg_please_enter_amount_of_swap_space="Please enter amount of swap space (SI-Unit suffixes\nrecommended; e.g., \`2g' for 2 Gigabytes):" msg_please_select_one_or_more_disks="Please select one or more disks to create a zpool:" @@ -779,7 +781,7 @@ # Check for unknown partition scheme before proceeding further case "$ZFSBOOT_PARTITION_SCHEME" in - ""|MBR|GPT) : known good ;; + ""|MBR|GPT*) : known good ;; *) f_dprintf "$funcname: %s is an unsupported partition scheme" \ "$ZFSBOOT_PARTITION_SCHEME" @@ -826,7 +828,7 @@ fi case "$ZFSBOOT_PARTITION_SCHEME" in - ""|GPT) f_dprintf "$funcname: Creating GPT layout..." + ""|GPT*) f_dprintf "$funcname: Creating GPT layout..." # # 1. Create GPT layout using labels # @@ -834,6 +836,17 @@ return $FAILURE # + # Apply workarounds if requested by the user + # + if [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT + Lenovo Fix" ]; then + f_eval_catch $funcname gpart "$GPART_SET_LENOVOFIX" \ + $disk || return $FAILURE + elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT + Active" ]; then + f_eval_catch $funcname gpart "$GPART_SET_PMBR_ACTIVE" \ + $disk || return $FAILURE + fi + + # # 2. Add small freebsd-boot partition labeled `boot#' # f_eval_catch $funcname gpart "$GPART_ADD_ALIGN_LABEL_WITH_SIZE" \ @@ -1581,6 +1594,10 @@ # Toggle between GPT and MBR if [ "$ZFSBOOT_PARTITION_SCHEME" = GPT ]; then ZFSBOOT_PARTITION_SCHEME=MBR + elif [ "$ZFSBOOT_PARTITION_SCHEME" = MBR ]; then + ZFSBOOT_PARTITION_SCHEME="GPT + Active" + elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT + Active" ]; then + ZFSBOOT_PARTITION_SCHEME="GPT + Lenovo Fix" else ZFSBOOT_PARTITION_SCHEME=GPT fi