Subject: [bug#41011] [PATCH] gnu: grub: Support for network boot via tftp/nfs.

From: Stefan <[email-masked]>
Date: Sun, 10 May 2020 23:13:20 +0200

Hi Mathieu!

Thanks for your reply again! :-)

> Am 10.05.2020 um 10:20 schrieb Mathieu Othacehe <[email-masked]>:
> 
> This patch does not apply here. Could you rebase it on top of master?

I’ll try.

>> -      ;; Intel and EFI systems need to be switched into graphics mode, whereas
>> -      ;; most other modern architectures have no other mode and therefore
>> -      ;; don't need to be switched.
>> -
>> -      ;; XXX: Do we really need to restrict to x86 systems?  We could imitate
>> -      ;; what the GRUB default configuration does and decide based on whether
>> -      ;; a user provided 'gfxterm' in the terminal-outputs field of their
>> -      ;; bootloader-configuration record.
>> -      (if (string-match "^(x86_64|i[3-6]86)-" system)
>> -          (format #f "
>> +    (format #f "
>>   set gfxmode=~a
>>   insmod all_video
>> -  insmod gfxterm~%" gfxmode)
>> -          "")))
>> +  insmod gfxterm~%"
>> +            (string-join
>> +             (grub-gfxmode (bootloader-theme config))
>> +             ";")))
> 
> Why not enable graphic mode only if 'gfxterm' is provided in
> terminal-outputs fields, like suggested by the comment?

Good point.

Looking into this topic it seem's questionable to me that the default of (bootloader-configuration (terminal-output …)) with '(gfxterm) is grub-specific. This doesn't make sense for other boot-loaders, e.g. U-Boot. I expect this to be changed in future. ;-)

>> +         (efi-bootloader-link (string-append "boot"
>> +                                       (match arch
>> +                                         ("i686" "ia32")
>> +                                         ("x86_64" "x64")
>> +                                         ("armhf" "arm")
> 
> If cross-building for "arm-linux-gnueabihf", arch will be "arm" and
> won't match anything here.

Good catch!

>> +          (catch 'system-error
>> +            (lambda () (delete-file efi-bootloader-link))
>> +            (lambda _ #f))
> 
> You can use "false-if-exception" here I think.

Nice trick.

>> +          (symlink #$efi-bootloader
>> +                   efi-bootloader-link)
>> +          (catch 'system-error
>> +            (lambda () (delete-file store-link))
>> +            (lambda _ #f))
> 
> Same here.

Sure.

>> +(define* (grub-efi-net-bootloader #:key (target #f) (efi-subdir #f))
> 
> #f if implicit if omitted.

I wasn’t aware of this.

>> +  (let ((target (or target "boot"))
>> +        (efi-subdir (or efi-subdir "efi/boot")))
> 
> It would be better to keep grub-efi-net-bootloader as a variable, like
> all other bootloaders. You could default configuration-file to
> "boot/efi/boot/grub.cfg" instead?

Actually there is a problem with all this in guix: There is (bootloader (target …)), which gives the impression that one is able to freely chose a folder for the bootloader files. However, the path “/boot/grub.cfg” is kind of hard coded.

Yes, it’s kind of possible to inherit from grub-efi-bootloader and overwrite the (configuration-file) field. In a first step this seems to work. But when e.g. deleting a system generation, in guix/scripts/system.scm (reinstall-bootloader) there is this code:

    ;; Use the detected bootloader with default configuration.
    ;; It will be enough to allow the system to boot.
    (bootloader-config (bootloader-configuration
                        (bootloader bootloader))) 

It reads this information form /var/guix/profiles/system/parameters: (bootloader-name grub-efi-bootloader).
With this again the hard-coded path “/boot/grub.cfg” of is used, ignoring any value overwritten in (configuration-file).

Another issue is (install-dir (string-append mount-point "/boot")) in (install-grub-efi), which ignores any (configuration-file) setting, too – well, it has no access to that setting –, and implies at least “/boot” to be the prefix of (bootloader (target …)). 

Beside the wish to avoid this hard-coded “/boot“ assumption, I made this a function with two parameters for two more reasons. 

One is simply to suite my needs. The folder for my tftp server is not “boot” but “boot-nfs”. For my SBC I’m using different operating systems from time to time, e.g. LibreELEC. As I have bad experiences with unreliable micro SD cards and as an nfs root file system is nice for tinkering, I copy such operating systems onto my tftp/nfs server. This includes of corse their “boot” folder. The build-in update functionalities overwrite stuff inside there. But I need to modify stuff for network booting. To not loose these modifications during updates and for later comparisons I keep such modifications in a copy as “boot-nfs”.

The other reason is that I’m not sure, if the efi-dir for network booting should be “efi/Guix” instead of “efi/boot” in other constellations. U-Boot expects “efi/boot“ over tftp like for a removable media by default. I guess this can be changed with DNS options. Also for real UEFI firmware this might be configurable. I don’t know, so I don’t want these paths to be hard-coded.

However, digging up all this and now re-trying to delete a system generation, I get this error with my new boot-efi-net-bootloader as a function:

stefan@guix ~/development/guix$ sudo guix system delete-generations 151
/var/guix/profiles/system-151-link wird gelöscht
guix system: error: grub-efi-net-bootloader: no such bootloader

So thanks for your hint, it can’t be a function! (Not now …)

Bye

Stefan