svn commit: r285679 - in head/usr.sbin/bsdinstall: partedit scripts

Allan Jude allanjude at FreeBSD.org
Sat Jul 18 18:49:48 UTC 2015


Author: allanjude (doc committer)
Date: Sat Jul 18 18:49:44 2015
New Revision: 285679
URL: https://svnweb.freebsd.org/changeset/base/285679

Log:
  Add support for two workarounds for known issues booting GPT in legacy mode on some hardware
  
  For Lenovo laptops with buggy bios (x220, t420, t520):
  	Write the 0xee entry into the second slot in the pmbr instead of the first
  
  For some Dell and HP models:
  	The BIOS gives a warning message when booting in legacy mode from a GPT partitioned disk where the 0xee partition in the pmbr is not flagged active
  	For models known to have this problem, mark the pmbr active during installation
  
  Use smbios data to identify machines known to be affected by any of the above, and offer the user the option to apply the workaround
  
  In bsdinstall's ufs auto mode (autopart partition wizard):
  	Allow users to select which type of partition table to use
  	Keep current defaults: MBR for BIOS, GPT for UEFI
  	This allows users to choose GPT for legacy boot if they wish
  
  PR:		184910
  PR:		194359
  Reviewed by:	Michael Dexter
  Approved by:	marcel
  MFC after:	3 days
  X-MFC-With:	r285594
  Relnotes:	yes
  Sponsored by:	ScaleEngine Inc.
  Differential Revision:	https://reviews.freebsd.org/D3091

Modified:
  head/usr.sbin/bsdinstall/partedit/gpart_ops.c
  head/usr.sbin/bsdinstall/partedit/part_wizard.c
  head/usr.sbin/bsdinstall/partedit/partedit.c
  head/usr.sbin/bsdinstall/partedit/partedit.h
  head/usr.sbin/bsdinstall/scripts/auto
  head/usr.sbin/bsdinstall/scripts/zfsboot

Modified: head/usr.sbin/bsdinstall/partedit/gpart_ops.c
==============================================================================
--- head/usr.sbin/bsdinstall/partedit/gpart_ops.c	Sat Jul 18 16:56:51 2015	(r285678)
+++ head/usr.sbin/bsdinstall/partedit/gpart_ops.c	Sat Jul 18 18:49:44 2015	(r285679)
@@ -206,12 +206,11 @@ newfs_command(const char *fstype, char *
 	}
 }
 
-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 @@ gpart_partition(const char *lg_name, con
 		    "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 @@ gpart_activate(struct gprovider *pp)
 	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)
 {

Modified: head/usr.sbin/bsdinstall/partedit/part_wizard.c
==============================================================================
--- head/usr.sbin/bsdinstall/partedit/part_wizard.c	Sat Jul 18 16:56:51 2015	(r285678)
+++ head/usr.sbin/bsdinstall/partedit/part_wizard.c	Sat Jul 18 18:49:44 2015	(r285679)
@@ -257,8 +257,10 @@ query:
 			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 @@ 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 (strcmp(scheme, "PC98") == 0 || strcmp(scheme, "MBR") == 0) {

Modified: head/usr.sbin/bsdinstall/partedit/partedit.c
==============================================================================
--- head/usr.sbin/bsdinstall/partedit/partedit.c	Sat Jul 18 16:56:51 2015	(r285678)
+++ head/usr.sbin/bsdinstall/partedit/partedit.c	Sat Jul 18 18:49:44 2015	(r285679)
@@ -44,6 +44,7 @@ struct pmetadata_head part_metadata;
 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 @@ main(int argc, const char **argv)
 
 			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 @@ apply_changes(struct gmesh *mesh)
 	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)
 {

Modified: head/usr.sbin/bsdinstall/partedit/partedit.h
==============================================================================
--- head/usr.sbin/bsdinstall/partedit/partedit.h	Sat Jul 18 16:56:51 2015	(r285678)
+++ head/usr.sbin/bsdinstall/partedit/partedit.h	Sat Jul 18 18:49:44 2015	(r285679)
@@ -72,6 +72,8 @@ void gpart_commit(struct gmesh *mesh);
 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);

Modified: head/usr.sbin/bsdinstall/scripts/auto
==============================================================================
--- head/usr.sbin/bsdinstall/scripts/auto	Sat Jul 18 16:56:51 2015	(r285678)
+++ head/usr.sbin/bsdinstall/scripts/auto	Sat Jul 18 18:49:44 2015	(r285679)
@@ -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 @@ error() {
 	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 @@ fi
 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)\" \

Modified: head/usr.sbin/bsdinstall/scripts/zfsboot
==============================================================================
--- head/usr.sbin/bsdinstall/scripts/zfsboot	Sat Jul 18 16:56:51 2015	(r285678)
+++ head/usr.sbin/bsdinstall/scripts/zfsboot	Sat Jul 18 18:49:44 2015	(r285679)
@@ -196,6 +196,8 @@ GPART_BOOTCODE_PART='gpart bootcode -b "
 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_index_argument="NULL index argu
 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 @@ zfs_create_diskpart()
 
 	# 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 @@ zfs_create_diskpart()
 	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 @@ zfs_create_diskpart()
 		             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" \
@@ -1584,6 +1597,10 @@ while :; do
 		# 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


More information about the svn-src-all mailing list