The source code
The file which handles the aspect of generating the GRUB configuration you're interested in modifying is /etc/grub.d/10_linux
and the $vt_handoff element of the kernel command line is processed twice within its code (as of the version I currently have installed, v2.04).
First (and more relevant to your desired outcome, since this is where the placement of the $vt_handoff
variable is handled) in the nested if block on lines 154-160:
...
if [ "$vt_handoff" = 1 ]; then
for word in $GRUB_CMDLINE_LINUX_DEFAULT; do
if [ "$word" = splash ]; then
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT \$vt_handoff"
fi
done
fi
...
Then again in the nested if block on lines 348-358, where the decision of what value to set for the $vt_handoff
variable is made:
...
set gfxpayload="${1}"
EOF
if [ "$vt_handoff" = 1 ]; then
cat << 'EOF'
if [ "${1}" = "keep" ]; then
set vt_handoff=vt.handoff=7
else
set vt_handoff=
fi
EOF
fi
...
Analysis
In the first instance shown above, we see the Dash shell interpreter concatenating the value of the $GRUB_CMDLINE_LINUX_DEFAULT
sourced from the /etc/default/grub
file with the $vt_handoff
variable name¹. The code as written chooses to append the latter to the former, but you could make it prepend instead as easily as reversing the position of the elements in the reassigned $GRUB_CMDLINE_LINUX_DEFAULT
variable on line 157. It would then look like this:
...
if [ "$word" = splash ]; then
GRUB_CMDLINE_LINUX_DEFAULT="\$vt_handoff $GRUB_CMDLINE_LINUX_DEFAULT"
fi
...
That is certainly the most direct way to effect the outcome you seek, though it falls short of my own definition of a "permanent" solution, because that file will be overwritten every time your system installs an update to GRUB. In light of that, I'd consider this more accurately a "persistent" solution as it will indeed survive from one power cycle to another for the lifetime of any given GRUB package release but no further.
Potential permanent solutions
Using the value of GRUB_GFXPAYLOAD_LINUX
As it's most often advisable to "work with" systems as they are (when possible), rather than "working against" them, I see one potential means of doing so residing in the second code snippet from the /etc/grub.d/10_linux
file shown above. Specifically, we see the script logic evaluating a positional parameter and only activating the $vt_handoff
variable if its value is 'keep'. The parameter in question (through several levels of shell logic obfuscation) is, in fact, the value for GRUB_GFXPAYLOAD_LINUX
that is supplied in /etc/default/grub
, a file which is intended to be modified by end users and thus survives package updates unscathed.
Only if GRUB_GFXPAYLOAD_LINUX is set to keep
does the $vt_handoff
variable have a value set. According to the GNU GRUB Manual, while the most common choices for GRUB_GFXPAYLOAD_LINUX are keep
(your current setting) and text
(obviously not suited to your use case), it may also be set to any valid value for gfxmode. This means that you could change it to auto
or, even better, to the precise width✕height
default screen resolution selected by your system's BIOS/EFI (which is what keep
is meant to be the equivalent of) which can be discovered with the videoinfo
command within the bootloader itself (and also, in most instances, with the sudo fbset -s
command in the terminal after your system has booted).
This offers the advantage of leaving your current boot process unchanged EXCEPT for removing the value assignment for $vt_handoff
, and even though you'll still see it at the end of the kernel command line when pressing e at the bootloader menu entry, since it now has no value it won't in fact be passed to the kernel. You can verify this to be the case by entering cat /proc/cmdline
in the terminal after changing GRUB_GFXPAYLOAD_LINUX and restarting your computer.
The final step is to restore the value that GRUB ultimately replaces $vt_handoff
with to your kernel command line, this time in the location YOU want. In the second code snippet above we see that when GRUB_GFXPAYLOAD_LINUX is set to keep
that $vt_handoff
is given the value vt.handoff=7
, and that part in bold is what you need to add in front of your other kernel command line settings assigned to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub
. Once again, you can verify that all is as expected with cat /proc/cmdline
after making the change and rebooting. This is how I would approach your issue myself if confronted with it.
GRUB Customizer
An alternative to editing the /etc/default/grub
file directly is to install and use GRUB Customizer, which exposes these same variables in a thoughtful GUI layout. Installing it is simple if you're using a recent release (19.10 "Eoan Ermine" or later) of Ubuntu or one of its flavors like Kubuntu with sudo apt install grub-customizer
in the terminal. It has an Advanced Settings dialog (shown below) that exposes the same values you need to modify in /etc/default/grub
and keeps backups of modified files in case you need to revert the changes at some later time.
¹ It should be noted that throughout the GRUB configuration process herein examined, all references to $vt_handoff
are instances of the variable name itself and not the more commonly seen parameter expansion/substitution behavior performed by *NIX shells of various and sundry flavors. The expected behavior of the Ubuntu variant of the GRUB framework is that the references to it will remain as the variable name in all instances of the kernel command line leading up to and including within the grub.cfg
file which is the end result of the initial grub mkconfig
process and each subsequent update-grub
invocation. The value for the variable is defined within the GRUB configuration file as well and the bootloader itself performs the substitution during each boot cycle. That is why it is often seen escaped as \$vt_handoff
in the code snippets above as that prevents any premature substitution of the variable name for its value.
$vt_handoff
was not present in the grub file when I opened it even though I could see it after pressing 'e' in the kernel parameters. Should I edit and mention this in the question?