Peleando con el inicio de Linux: MRB, UEFI, GPT, USB


El principal objetivo de esta entrada es explicar como disponer de una unidad USB con Linux que arranque en cualquier ordenador. Actualmente la BIOS de las placas base disponen de dos modos de arranque: BIOS-Legacy y UEFI, sin entrar en detalles, pretendo conseguir que un USB arranque para ambas configuraciones.

Además, las instrucciones aquí descritas sirven para migrar un Linux que arranca en modo BIOS-Legacy a UEFI. La mayor parte de este contenido lo he obtenido de Legacy to UEFI boot donde se explica cómo hacer la migración.

Nota

No es necesario iniciar desde un livecd para hacer el cambio de MBR → GPT → UEFI, se puede hacer desde el propio Linux en ejecución. De todas formas, con un LiveCD cambia un poco el modo de hacerlo y es más seguro.

Todas la pruebas mostradas las hago desde una máquina virtual con disco USB por eso el dispositivo es /dev/vda

Antes de empezar hay que tener clara la configuración que se tiene en el disco. Hay 2 posibles puntos de partida:

  1. Un Linux instalado con la tabla de particiones MBR y no GPT
  2. Un Linux instalador con la tabla de particiones MBR y GPT

En la siguiente sección se explica como partir de cada uno de los puntos anteriores.

Partiendo de una tabla de particiones MBR (no GPT)

Para comprobar si se tiene una tabla de particiones MBR el comando gdisk -l /dev/vda muestra la información de la tabla de particiones. En el siguiente ejemplo se puede ver que la tabla de particiones GPT no está presente.

gdisk /dev/vda
GPT fdisk (gdisk) version 1.0.8

Partition table scan:
  MBR: MBR only
  BSD: not present
  APM: not present
  GPT: not present

***************************************************************
Found invalid GPT and valid MBR; converting MBR to GPT format
in memory. THIS OPERATION IS POTENTIALLY DESTRUCTIVE! Exit by
typing 'q' if you don't want to convert your MBR partitions
to GPT format!
***************************************************************

Partir de este punto es delicado, ya que tras convertir la tabla de particiones a GPT se necesita añadir una partición de arranque BIOS-Legacy para que reinicie. De todas formas explico el modo de hacerlo saltando esta restricción.

El primer paso es convertir la tabla de particiones. Ejecutando gdisk /dev/vda, aparece el mensaje anterior y sin salir de gdisk tras el aviso hay que usar la tecla w y aceptar para que se convierta la tabla de particiones.

En este punto hay que forzar una instalación de grub, ignorando las advertencias, para poder reiniciar el sistema tras los cambios en las particiones. El comando sería:

grub-install --force /dev/vda

Instalando para plataforma i386-pc.
grub-install: aviso: esta etiqueta de partición GPT no contiene ninguna Partición de Arranque BIOS; el embebido no será posible.
grub-install: aviso: El embebido no es posible.  GRUB podrá ser instalado con esta configuración únicamente usando listas de bloques.  No obstante, las listas de bloques son INSEGURAS y su uso está desaconsejado..
Instalación terminada. No se notificó ningún error.

A partir de aquí se supone que tenemos la tabla de particiones GPT-MBR.

Partiendo de una tabla de particiones GPT

Para asegurarse que ya se tiene una tabla de particiones GPT, se puede usar de nuevo el comando gdisk -l /dev/vda

gdisk -l /dev/vda
GPT fdisk (gdisk) version 1.0.8

Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present

Found valid GPT with protective MBR; using GPT.
Disk /dev/vda: 468862128 sectors, 223.6 GiB
Model: Generic
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): DC1E5F8B-E340-4A23-8EAC-BA50D55C9F83
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 468862094
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
1            2048         2000895   976.0 MiB   8300
2         2000896       468862094   222.6 GiB   8300

En el sistema que estoy usando de ejemplo tengo una configuración típica de un Linux instalado con la partición raíz cifrada con Luks. Así, en el sistema está montado lo siguiente:

df -h
S.ficheros                  Tamaño Usados  Disp Uso% Montado en
/dev/mapper/nvme0n1p2_crypt   219G    50G  160G  24% /
/dev/vda1                     943M   263M  616M  30% /boot

Por tanto, en este escenario se parte de lo siguiente:

  • Disco con tabla de particiones MBR y GPT
  • Un Linux instalado que arranca en modo Legacy, tiene instalado el paquete grub-pc
  • La partición 1 correspondiente a /boot con el kernel sin cifrar
  • La partición 2 con el resto del sistema Linux cifrado con Luks

Para realizar la migración hay que crear dos particiones nuevas, una el arranque BIOS-Legacy y otra para el arranque UEFI. Estas particiones no tienen que ser muy grandes, pero hay que hacerles hueco en el disco. Para EFI se recomiendan unos 300MB, pero en el caso de Linux basta con unos 50MB. En el caso de la BIOS debe caber el código de arranque de Grub-legacy, que ocupa un 1MB.

Finalmente usaré 50MB para EFI y 2MB para BIOS-Legacy, y el hueco lo haré reduciendo la partición /boot que no está cifrada. Desde el mismo Linux en ejecución se pude desmontar /boot de forma segura y reducir el esa partición:

umount /boot
fsck.ext4 -f /dev/vda1
resize2fs -p -M /dev/vda1

El sistema de ficheros en /dev/vda1 tiene ahora 109467 bloques (de 4k).

Hay que revisar en la salida anterior el tamaño resultando del sistema de ficheros que es fácil de calcula 109467*4096 ⁄ 1024 ⁄ 1024 = 427MBytes. Con este resultado no hay problema para reducir la partición en 50MB. Se puede hacer con gdisk /dev/vda de la siguiente forma:

  1. Se listan las particiones y se apunta el sector donde comienza /dev/vda1 (en mi caso 2048)
  2. Se borra la partición 1 (tecla d)
  3. Se crea una nueva partición (tecla c) y se escoge como primer sector el mismo (2048)
  4. Se indican el tamaño de la nueva partición, mi caso 976M - 50M = 917M
  5. Se deja el código 8003
  6. Se escriben las particiones con la tecla w.

A partir de aquí hay que crear una o dos particiones según el objetivo:

Objetivo 1: Migrar sólo a arranque UEFI, en este caso sólo se necesita una partición EFI.

Objetivo 2: Tener arranque UEFI y arranque Legacy. En este caso se necesitan 2 particiones una EFI y otra para Grub-legacy.

Voy a crear las dos, ya que me interesa tener una unidad USB capaz de arrancar con cualquier configuración BIOS.

Creando las particiones

De nuevo se puede usar gdisk para crear las particiones. El orden de las particiones no es importante, pero sí deben estar las dos en el hueco que se acaba de hacer. La mejor forma es crear la de 2M primero y después el hueco restante para la EFI haciendo lo siguiente con gdisk:

  1. Crear nueva partición de 2M y ponerle HEX code EF02.
  2. Crear otra con el tamaño restantes (opciones por defecto) con Hex code EF00.

El resultado en mi caso es este:

Number  Start (sector)    End (sector)  Size       Code  Name
 1            2048         1878016   916.0 MiB   8300  Linux filesystem
 2         2000896       468862094   222.6 GiB   8300
 3         1880064         1884159   2.0 MiB     EF02  BIOS boot partition
 4         1884160         2000895   57.0 MiB    EF00  EFI system partition

Al estar el sistema iniciado el núcleo no puede actualizar los dispositivos de bloques con las nuevas particiones. Así que hay que reiniciar para poder usar las nuevas particiones, en este punto puede que se rompa el inicio y sea necesario usar un Livecd para continuar.

Si se consigue reiniciar, lo primero es extender el sistema de ficheros de /boot al nuevo tamaño:

df -h /dev/vda1

S.ficheros     Tamaño Usados  Disp Uso% Montado en
/dev/vda1        403M   263M  111M  71% /boot

resize2fs /dev/vda1

El sistema de ficheros en /dev/vda1 tiene ahora 234496 bloques (de 4k).

S.ficheros     Tamaño Usados  Disp Uso% Montado en
/dev/vda1        883M   263M  574M  32% /boot

Se puede comprobar las particiones y el tamaño cargados en el núcleo con el siguiente comando:

lsblk /dev/vda
NAME                MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
vda                 252:0    0 223,6G  0 disk
├─vda1              252:1    0   916M  0 part  /boot
├─vda2              252:2    0 222,6G  0 part
│ └─nvme0n1p2_crypt 253:0    0 222,6G  0 crypt /
├─vda3              252:3    0     2M  0 part
└─vda4              252:4    0    57M  0 part

Ahora, la partición EFI hay que formatearla en FAT32. Es la de 57M (/dev/vda4) hay que hacer los siguiente:

  1. Formatear la partición en Fat32
  2. Crear un punto de montaje en /boot/efi
  3. Editar /etc/fstab para que se monte automáticamente usado su UUID

Los comandos serían los siguientes (usando el UUID que corresponda):

mkfs.vfat /dev/vda4
mkdir /boot/efi
ls /dev/disk/by-uuid/ -l

lrwxrwxrwx 1 root root 10 nov 21 13:21 0B4D-8154 -> ../../vda4

echo "UUID=0B4D-8154 /boot/efi vfat defaults 0 2" >> /etc/fstab
mount /boot/efi

Ejecutando mount -a hay que asegurarse que esté montado /boot/efi correctamente ya que ahora hay que cambiar grub.

Cambiando GRUB

En este punto hay que cambiar el paquete grub-pc por grub-efi y reinstalar el cargador forzando el objetivo a x86_64-efi.

apt-get remove grub-pc
apt-get install grub-efi
grub-install --target=x86_64-efi /dev/vda

Si todo ha ido bien en /boot/efi/EFI estarán los directorios y ficheros de inicio. Pueden ser Ubuntu, Debian, etc. según la distribución que se esté usando. En este punto sólo está instalado el arranque UEFI, en teoría se puede reiniciar y cambiar la configuración de la BIOS para que arranque en modo UEFI.

Si también se quiere tener el arranque en modo Legacy hay que instalar sólo una parte de Grub, concretamente el paquete grub-pc-bin y reinstalar forzando esa plataforma. Esto sólo funcionará si se ha creado la partición BIOS boot partition de 2M. Los comandos son:

apt install grub-pc-bin
grub-install --target=i386-pc  /dev/vda