mbox series

[kvm-unit-tests,v1,0/3] x86 UEFI: pass envs and args

Message ID 20220220224234.422499-1-zxwang42@gmail.com (mailing list archive)
Headers show
Series x86 UEFI: pass envs and args | expand

Message

Zixuan Wang Feb. 20, 2022, 10:42 p.m. UTC
Hello,

This patch series enables kvm-unit-tests to get envs and args under
UEFI. The host passes envs and args through files:

1. The host stores envs into ENVS.TXT and args into ARGS.TXT
2. The guest boots up and reads data from these files through UEFI file
operation services
3. The file data is passed to corresponding setup functions

As a result, several x86 test cases (e.g., kvmclock_test and vmexit)
can now get envs/args from the host [1], thus do not report FAIL when
running ./run-tests.sh.

An alternative approach for envs/args passing under UEFI is to use
QEMU's -append/-initrd options. However, this approach requires EFI
binaries to be passed through QEMU's -kernel option. While currently,
EFI binaries are loaded from a disk image. Changing this bootup process
may make kvm-unit-tests (under UEFI) unable to run on bare-metal [2].
On the other hand, passing envs/args through files should work on
bare-metal because UEFI's file operation services do not rely on QEMU's
functionalities, thus working on bare-metal.

The summary of this patch series:

Patch #1 pulls Linux kernel's UEFI definitions for file operations.

Patch #2 implements file read functions and envs setup functions.

Patch #3 implements the args setup functions.

Best regards,
Zixuan

[1] https://github.com/TheNetAdmin/KVM-Unit-Tests-dev-fork/issues/8
[2] https://lore.kernel.org/kvm/CAEDJ5ZQLm1rz+0a7MPPz3wMAoeTq2oH9z92sd0ZhCxEjWMkOpg@mail.gmail.com

Zixuan Wang (3):
  x86 UEFI: pull UEFI definitions for file operations
  x86 UEFI: read envs from file
  x86 UEFI: read args from file

 lib/efi.c       | 150 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/linux/efi.h |  82 +++++++++++++++++++++++++-
 x86/efi/run     |  36 +++++++++++-
 3 files changed, 265 insertions(+), 3 deletions(-)

Comments

Andrew Jones Feb. 21, 2022, 8:40 a.m. UTC | #1
On Sun, Feb 20, 2022 at 02:42:31PM -0800, Zixuan Wang wrote:
> Hello,
> 
> This patch series enables kvm-unit-tests to get envs and args under
> UEFI. The host passes envs and args through files:
> 
> 1. The host stores envs into ENVS.TXT and args into ARGS.TXT

EFI already has support for an environment and EFI apps can accept args.
Why not find a way to convert kvm-unit-tests ENV and unit tests args
into the EFI system and then use that?

efi_setup_argv()[*] in my original PoC does that. It uses gnu-efi, but
it should be easy to strip away the gnu-efi stuff and go straight for
the underlining EFI functions.

[*] https://github.com/rhdrjones/kvm-unit-tests/commit/12a49a2e97b457e23af10bb25cd972362b379951#:~:text=static%20void%20efi_setup_argv(EFI_HANDLE%20Image%2C%20EFI_SYSTEM_TABLE%20*SysTab)

If you want to mimic efi_setup_argv(), then you'll also need 85baf398
("lib/argv: Allow environ to be primed") from that same branch.

EFI wrapper scripts for each unit test can be generated to pass the args
to the unit test EFI apps automatically. For the environment, the EFI
vars can be set as usual for the system. For QEMU, that means creating
a VARS.fd and then adding another flash device to the VM to exposes it.

Thanks,
drew


> 2. The guest boots up and reads data from these files through UEFI file
> operation services
> 3. The file data is passed to corresponding setup functions
> 
> As a result, several x86 test cases (e.g., kvmclock_test and vmexit)
> can now get envs/args from the host [1], thus do not report FAIL when
> running ./run-tests.sh.
> 
> An alternative approach for envs/args passing under UEFI is to use
> QEMU's -append/-initrd options. However, this approach requires EFI
> binaries to be passed through QEMU's -kernel option. While currently,
> EFI binaries are loaded from a disk image. Changing this bootup process
> may make kvm-unit-tests (under UEFI) unable to run on bare-metal [2].
> On the other hand, passing envs/args through files should work on
> bare-metal because UEFI's file operation services do not rely on QEMU's
> functionalities, thus working on bare-metal.
> 
> The summary of this patch series:
> 
> Patch #1 pulls Linux kernel's UEFI definitions for file operations.
> 
> Patch #2 implements file read functions and envs setup functions.
> 
> Patch #3 implements the args setup functions.
> 
> Best regards,
> Zixuan
> 
> [1] https://github.com/TheNetAdmin/KVM-Unit-Tests-dev-fork/issues/8
> [2] https://lore.kernel.org/kvm/CAEDJ5ZQLm1rz+0a7MPPz3wMAoeTq2oH9z92sd0ZhCxEjWMkOpg@mail.gmail.com
> 
> Zixuan Wang (3):
>   x86 UEFI: pull UEFI definitions for file operations
>   x86 UEFI: read envs from file
>   x86 UEFI: read args from file
> 
>  lib/efi.c       | 150 ++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/linux/efi.h |  82 +++++++++++++++++++++++++-
>  x86/efi/run     |  36 +++++++++++-
>  3 files changed, 265 insertions(+), 3 deletions(-)
> 
> -- 
> 2.35.1
>
Andrew Jones Feb. 21, 2022, 3:25 p.m. UTC | #2
On Mon, Feb 21, 2022 at 09:40:56AM +0100, Andrew Jones wrote:
> On Sun, Feb 20, 2022 at 02:42:31PM -0800, Zixuan Wang wrote:
> > Hello,
> > 
> > This patch series enables kvm-unit-tests to get envs and args under
> > UEFI. The host passes envs and args through files:
> > 
> > 1. The host stores envs into ENVS.TXT and args into ARGS.TXT
> 
> EFI already has support for an environment and EFI apps can accept args.
> Why not find a way to convert kvm-unit-tests ENV and unit tests args
> into the EFI system and then use that?
> 
> efi_setup_argv()[*] in my original PoC does that. It uses gnu-efi, but
> it should be easy to strip away the gnu-efi stuff and go straight for
> the underlining EFI functions.
> 
> [*] https://github.com/rhdrjones/kvm-unit-tests/commit/12a49a2e97b457e23af10bb25cd972362b379951#:~:text=static%20void%20efi_setup_argv(EFI_HANDLE%20Image%2C%20EFI_SYSTEM_TABLE%20*SysTab)
> 
> If you want to mimic efi_setup_argv(), then you'll also need 85baf398
> ("lib/argv: Allow environ to be primed") from that same branch.
> 
> EFI wrapper scripts for each unit test can be generated to pass the args
> to the unit test EFI apps automatically. For the environment, the EFI
> vars can be set as usual for the system. For QEMU, that means creating
> a VARS.fd and then adding another flash device to the VM to exposes it.

BTW, this tool from Gerd might be useful for that

https://gitlab.com/kraxel/edk2-tests/-/blob/master/tools/vars.py

Thanks,
drew

> 
> Thanks,
> drew
> 
> 
> > 2. The guest boots up and reads data from these files through UEFI file
> > operation services
> > 3. The file data is passed to corresponding setup functions
> > 
> > As a result, several x86 test cases (e.g., kvmclock_test and vmexit)
> > can now get envs/args from the host [1], thus do not report FAIL when
> > running ./run-tests.sh.
> > 
> > An alternative approach for envs/args passing under UEFI is to use
> > QEMU's -append/-initrd options. However, this approach requires EFI
> > binaries to be passed through QEMU's -kernel option. While currently,
> > EFI binaries are loaded from a disk image. Changing this bootup process
> > may make kvm-unit-tests (under UEFI) unable to run on bare-metal [2].
> > On the other hand, passing envs/args through files should work on
> > bare-metal because UEFI's file operation services do not rely on QEMU's
> > functionalities, thus working on bare-metal.
> > 
> > The summary of this patch series:
> > 
> > Patch #1 pulls Linux kernel's UEFI definitions for file operations.
> > 
> > Patch #2 implements file read functions and envs setup functions.
> > 
> > Patch #3 implements the args setup functions.
> > 
> > Best regards,
> > Zixuan
> > 
> > [1] https://github.com/TheNetAdmin/KVM-Unit-Tests-dev-fork/issues/8
> > [2] https://lore.kernel.org/kvm/CAEDJ5ZQLm1rz+0a7MPPz3wMAoeTq2oH9z92sd0ZhCxEjWMkOpg@mail.gmail.com
> > 
> > Zixuan Wang (3):
> >   x86 UEFI: pull UEFI definitions for file operations
> >   x86 UEFI: read envs from file
> >   x86 UEFI: read args from file
> > 
> >  lib/efi.c       | 150 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/linux/efi.h |  82 +++++++++++++++++++++++++-
> >  x86/efi/run     |  36 +++++++++++-
> >  3 files changed, 265 insertions(+), 3 deletions(-)
> > 
> > -- 
> > 2.35.1
> >
Zixuan Wang Feb. 21, 2022, 6:47 p.m. UTC | #3
On Mon, Feb 21, 2022 at 7:26 AM Andrew Jones <drjones@redhat.com> wrote:
>
> On Mon, Feb 21, 2022 at 09:40:56AM +0100, Andrew Jones wrote:
> > On Sun, Feb 20, 2022 at 02:42:31PM -0800, Zixuan Wang wrote:
> > > Hello,
> > >
> > > This patch series enables kvm-unit-tests to get envs and args under
> > > UEFI. The host passes envs and args through files:
> > >
> > > 1. The host stores envs into ENVS.TXT and args into ARGS.TXT
> >
> > EFI already has support for an environment and EFI apps can accept args.
> > Why not find a way to convert kvm-unit-tests ENV and unit tests args
> > into the EFI system and then use that?
> >
> > efi_setup_argv()[*] in my original PoC does that. It uses gnu-efi, but
> > it should be easy to strip away the gnu-efi stuff and go straight for
> > the underlining EFI functions.
> >
> > [*] https://github.com/rhdrjones/kvm-unit-tests/commit/12a49a2e97b457e23af10bb25cd972362b379951#:~:text=static%20void%20efi_setup_argv(EFI_HANDLE%20Image%2C%20EFI_SYSTEM_TABLE%20*SysTab)
> >
> > If you want to mimic efi_setup_argv(), then you'll also need 85baf398
> > ("lib/argv: Allow environ to be primed") from that same branch.

I think one way to implement EFI environment passing is to generate a
startup.nsh which sets the envs. But this could significantly degrade
the bootup speed because UEFI firmware waits 30 seconds for user input
before executing the startup.nsh. This slow bootup causes
./run-tests.sh to run extremely slower (~30mins or even longer), and
motivated us to implement the faster bootup process which does not
rely on the startup.nsh [**].

[**] https://lore.kernel.org/all/20211116204053.220523-10-zxwang42@gmail.com/

> > EFI wrapper scripts for each unit test can be generated to pass the args
> > to the unit test EFI apps automatically. For the environment, the EFI
> > vars can be set as usual for the system. For QEMU, that means creating
> > a VARS.fd and then adding another flash device to the VM to exposes it.

Setting up a .fd file (or an EFI NVRAM if I understand it correctly)
is interesting. Actually, I previously tried it in another way, which
is to set variables from the guest:

1. The host generates and runs a temporary test case that writes envs
and args to EFI NVRAM. This test case uses EFI firmware's
SetVariable() service with NON_VOLATILE | BOOTSERVICE_ACCESS
attributes.
2. The host calls the actual test case which reads the modified NVRAM.

This approach does not work because the guest cannot persist the NVRAM
variables in main(). This is because main() runs after EFI's
ExitBootServices(), and thus cannot set a new non-volatile variable
[***].

I can try it again with some other tricks, e.g., efi_main() creates
the non-volatile variable if not exists, then main() sets the
non-volatile variable.

[***] SetVariable(), Page 241,
https://uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf

> BTW, this tool from Gerd might be useful for that
>
> https://gitlab.com/kraxel/edk2-tests/-/blob/master/tools/vars.py

This script seems to modify the EFI .fd file from the host. I
previously checked several similar scripts but didn't try any.

One thing I was hesitant to modify EFI NVRAM from the host is, it may
introduce more lines of code than the current file-based envs/args
passing. I can try and see if I can simplify the script mentioned
above.

> Thanks,
> drew
>
> >
> > Thanks,
> > drew
> >
> >
> > > 2. The guest boots up and reads data from these files through UEFI file
> > > operation services
> > > 3. The file data is passed to corresponding setup functions
> > >
> > > As a result, several x86 test cases (e.g., kvmclock_test and vmexit)
> > > can now get envs/args from the host [1], thus do not report FAIL when
> > > running ./run-tests.sh.
> > >
> > > An alternative approach for envs/args passing under UEFI is to use
> > > QEMU's -append/-initrd options. However, this approach requires EFI
> > > binaries to be passed through QEMU's -kernel option. While currently,
> > > EFI binaries are loaded from a disk image. Changing this bootup process
> > > may make kvm-unit-tests (under UEFI) unable to run on bare-metal [2].
> > > On the other hand, passing envs/args through files should work on
> > > bare-metal because UEFI's file operation services do not rely on QEMU's
> > > functionalities, thus working on bare-metal.
> > >
> > > The summary of this patch series:
> > >
> > > Patch #1 pulls Linux kernel's UEFI definitions for file operations.
> > >
> > > Patch #2 implements file read functions and envs setup functions.
> > >
> > > Patch #3 implements the args setup functions.
> > >
> > > Best regards,
> > > Zixuan
> > >
> > > [1] https://github.com/TheNetAdmin/KVM-Unit-Tests-dev-fork/issues/8
> > > [2] https://lore.kernel.org/kvm/CAEDJ5ZQLm1rz+0a7MPPz3wMAoeTq2oH9z92sd0ZhCxEjWMkOpg@mail.gmail.com
> > >
> > > Zixuan Wang (3):
> > >   x86 UEFI: pull UEFI definitions for file operations
> > >   x86 UEFI: read envs from file
> > >   x86 UEFI: read args from file
> > >
> > >  lib/efi.c       | 150 ++++++++++++++++++++++++++++++++++++++++++++++++
> > >  lib/linux/efi.h |  82 +++++++++++++++++++++++++-
> > >  x86/efi/run     |  36 +++++++++++-
> > >  3 files changed, 265 insertions(+), 3 deletions(-)
> > >
> > > --
> > > 2.35.1
> > >
>

Best regards,
Zixuan
Gerd Hoffmann Feb. 22, 2022, 6:11 a.m. UTC | #4
Hi,

> > EFI wrapper scripts for each unit test can be generated to pass the args
> > to the unit test EFI apps automatically. For the environment, the EFI
> > vars can be set as usual for the system. For QEMU, that means creating
> > a VARS.fd and then adding another flash device to the VM to exposes it.
> 
> BTW, this tool from Gerd might be useful for that
> 
> https://gitlab.com/kraxel/edk2-tests/-/blob/master/tools/vars.py

Probably not (yet) as this right now focuses on stuff needed for secure
boot, i.e. enroll certificates etc.

Setting variables with ascii (or unicode) strings should be rather easy
to add though.

take care,
  Gerd