* [PATCH v4 2/2] x86: re-enable rng seeding via setup_data
2022-09-13 23:41 [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file Jason A. Donenfeld
@ 2022-09-13 23:41 ` Jason A. Donenfeld
2022-09-16 7:15 ` [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file Ard Biesheuvel
` (2 subsequent siblings)
3 siblings, 0 replies; 9+ messages in thread
From: Jason A. Donenfeld @ 2022-09-13 23:41 UTC (permalink / raw)
To: qemu-devel
Cc: Jason A. Donenfeld, Laurent Vivier, Michael S . Tsirkin,
Paolo Bonzini, Peter Maydell, Philippe Mathieu-Daudé,
Richard Henderson, Ard Biesheuvel, Gerd Hoffmann
This reverts 3824e25db1 ("x86: disable rng seeding via setup_data"), but
for 7.2 rather than 7.1, now that modifying setup_data is safe to do.
Cc: Laurent Vivier <laurent@vivier.eu>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
Cc: Richard Henderson <richard.henderson@linaro.org>
Cc: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
hw/i386/microvm.c | 2 +-
hw/i386/pc_piix.c | 3 ++-
hw/i386/pc_q35.c | 3 ++-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 52cafa003d..7fe8cce03e 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -332,7 +332,7 @@ static void microvm_memory_init(MicrovmMachineState *mms)
rom_set_fw(fw_cfg);
if (machine->kernel_filename != NULL) {
- x86_load_linux(x86ms, fw_cfg, 0, true, true);
+ x86_load_linux(x86ms, fw_cfg, 0, true, false);
}
if (mms->option_roms) {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 8043a250ad..0b1a79c0fa 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -439,7 +439,6 @@ static void pc_i440fx_7_2_machine_options(MachineClass *m)
m->alias = "pc";
m->is_default = true;
pcmc->default_cpu_version = 1;
- pcmc->legacy_no_rng_seed = true;
}
DEFINE_I440FX_MACHINE(v7_2, "pc-i440fx-7.2", NULL,
@@ -447,9 +446,11 @@ DEFINE_I440FX_MACHINE(v7_2, "pc-i440fx-7.2", NULL,
static void pc_i440fx_7_1_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_7_2_machine_options(m);
m->alias = NULL;
m->is_default = false;
+ pcmc->legacy_no_rng_seed = true;
compat_props_add(m->compat_props, hw_compat_7_1, hw_compat_7_1_len);
compat_props_add(m->compat_props, pc_compat_7_1, pc_compat_7_1_len);
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 53eda50e81..a496bd6e74 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -376,7 +376,6 @@ static void pc_q35_7_2_machine_options(MachineClass *m)
pc_q35_machine_options(m);
m->alias = "q35";
pcmc->default_cpu_version = 1;
- pcmc->legacy_no_rng_seed = true;
}
DEFINE_Q35_MACHINE(v7_2, "pc-q35-7.2", NULL,
@@ -384,8 +383,10 @@ DEFINE_Q35_MACHINE(v7_2, "pc-q35-7.2", NULL,
static void pc_q35_7_1_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_7_2_machine_options(m);
m->alias = NULL;
+ pcmc->legacy_no_rng_seed = true;
compat_props_add(m->compat_props, hw_compat_7_1, hw_compat_7_1_len);
compat_props_add(m->compat_props, pc_compat_7_1, pc_compat_7_1_len);
}
--
2.37.3
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file
2022-09-13 23:41 [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file Jason A. Donenfeld
2022-09-13 23:41 ` [PATCH v4 2/2] x86: re-enable rng seeding via setup_data Jason A. Donenfeld
@ 2022-09-16 7:15 ` Ard Biesheuvel
2022-09-21 8:59 ` Paolo Bonzini
2022-09-21 9:15 ` Michael S. Tsirkin
3 siblings, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2022-09-16 7:15 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: qemu-devel, Gerd Hoffmann, Laurent Vivier, Michael S . Tsirkin,
Paolo Bonzini, Peter Maydell, Philippe Mathieu-Daudé,
Richard Henderson
On Wed, 14 Sept 2022 at 01:42, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> If setup_data is being read into a specific memory location, then
> generally the setup_data address parameter is read first, so that the
> caller knows where to read it into. In that case, we should return
> setup_data containing the absolute addresses that are hard coded and
> determined a priori. This is the case when kernels are loaded by BIOS,
> for example. In contrast, when setup_data is read as a file, then we
> shouldn't modify setup_data, since the absolute address will be wrong by
> definition. This is the case when OVMF loads the image.
>
> This allows setup_data to be used like normal, without crashing when EFI
> tries to use it.
>
> (As a small development note, strangely, fw_cfg_add_file_callback() was
> exported but fw_cfg_add_bytes_callback() wasn't, so this makes that
> consistent.)
>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Laurent Vivier <laurent@vivier.eu>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
> Cc: Richard Henderson <richard.henderson@linaro.org>
> Suggested-by: Ard Biesheuvel <ardb@kernel.org>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
This is still somewhat of a crutch, but at least we can now
disambiguate between loaders that treat the setup data as a file
(OVMF) and ones that treat it as an object that lives at a fixed
address in memory (SeaBIOS)
I'll note that this also addresses the existing issue with -dtb on
x86, which currently breaks the OVMF direct kernel boot in the same
way as the RNG seed does.
> ---
> hw/i386/x86.c | 37 +++++++++++++++++++++++++++----------
> hw/nvram/fw_cfg.c | 12 ++++++------
> include/hw/nvram/fw_cfg.h | 22 ++++++++++++++++++++++
> 3 files changed, 55 insertions(+), 16 deletions(-)
>
> diff --git a/hw/i386/x86.c b/hw/i386/x86.c
> index 050eedc0c8..933bbdd836 100644
> --- a/hw/i386/x86.c
> +++ b/hw/i386/x86.c
> @@ -764,6 +764,18 @@ static bool load_elfboot(const char *kernel_filename,
> return true;
> }
>
> +struct setup_data_fixup {
> + void *pos;
> + hwaddr val;
> + uint32_t addr;
> +};
> +
> +static void fixup_setup_data(void *opaque)
> +{
> + struct setup_data_fixup *fixup = opaque;
> + stq_p(fixup->pos, fixup->val);
> +}
> +
> void x86_load_linux(X86MachineState *x86ms,
> FWCfgState *fw_cfg,
> int acpi_data_size,
> @@ -1088,8 +1100,11 @@ void x86_load_linux(X86MachineState *x86ms,
> qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH);
> }
>
> - /* Offset 0x250 is a pointer to the first setup_data link. */
> - stq_p(header + 0x250, first_setup_data);
> + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
> + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
> + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
> + sev_load_ctx.kernel_data = (char *)kernel;
> + sev_load_ctx.kernel_size = kernel_size;
>
> /*
> * If we're starting an encrypted VM, it will be OVMF based, which uses the
> @@ -1099,16 +1114,18 @@ void x86_load_linux(X86MachineState *x86ms,
> * file the user passed in.
> */
> if (!sev_enabled()) {
> + struct setup_data_fixup *fixup = g_malloc(sizeof(*fixup));
> +
> memcpy(setup, header, MIN(sizeof(header), setup_size));
> + /* Offset 0x250 is a pointer to the first setup_data link. */
> + fixup->pos = setup + 0x250;
> + fixup->val = first_setup_data;
> + fixup->addr = real_addr;
> + fw_cfg_add_bytes_callback(fw_cfg, FW_CFG_SETUP_ADDR, fixup_setup_data, NULL,
> + fixup, &fixup->addr, sizeof(fixup->addr), true);
> + } else {
> + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
> }
> -
> - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
> - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
> - fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
> - sev_load_ctx.kernel_data = (char *)kernel;
> - sev_load_ctx.kernel_size = kernel_size;
> -
> - fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
> fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
> fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
> sev_load_ctx.setup_data = (char *)setup;
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index d605f3f45a..564bda3395 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -692,12 +692,12 @@ static const VMStateDescription vmstate_fw_cfg = {
> }
> };
>
> -static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> - FWCfgCallback select_cb,
> - FWCfgWriteCallback write_cb,
> - void *callback_opaque,
> - void *data, size_t len,
> - bool read_only)
> +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> + FWCfgCallback select_cb,
> + FWCfgWriteCallback write_cb,
> + void *callback_opaque,
> + void *data, size_t len,
> + bool read_only)
> {
> int arch = !!(key & FW_CFG_ARCH_LOCAL);
>
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index 0e7a8bc7af..e4fef393be 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -117,6 +117,28 @@ struct FWCfgMemState {
> */
> void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
>
> +/**
> + * fw_cfg_add_bytes_callback:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @select_cb: callback function when selecting
> + * @write_cb: callback function after a write
> + * @callback_opaque: argument to be passed into callback function
> + * @data: pointer to start of item data
> + * @len: size of item data
> + * @read_only: is file read only
> + *
> + * Add a new fw_cfg item, available by selecting the given key, as a raw
> + * "blob" of the given size. The data referenced by the starting pointer
> + * is only linked, NOT copied, into the data structure of the fw_cfg device.
> + */
> +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> + FWCfgCallback select_cb,
> + FWCfgWriteCallback write_cb,
> + void *callback_opaque,
> + void *data, size_t len,
> + bool read_only);
> +
> /**
> * fw_cfg_add_string:
> * @s: fw_cfg device being modified
> --
> 2.37.3
>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file
2022-09-13 23:41 [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file Jason A. Donenfeld
2022-09-13 23:41 ` [PATCH v4 2/2] x86: re-enable rng seeding via setup_data Jason A. Donenfeld
2022-09-16 7:15 ` [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file Ard Biesheuvel
@ 2022-09-21 8:59 ` Paolo Bonzini
2022-09-21 9:04 ` Jason A. Donenfeld
2022-09-21 9:15 ` Michael S. Tsirkin
3 siblings, 1 reply; 9+ messages in thread
From: Paolo Bonzini @ 2022-09-21 8:59 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: qemu-devel, Gerd Hoffmann, Laurent Vivier, Michael S . Tsirkin,
Peter Maydell, Philippe Mathieu-Daudé, Richard Henderson,
Ard Biesheuvel
> diff --git a/hw/i386/x86.c b/hw/i386/x86.c
> index 050eedc0c8..933bbdd836 100644
> --- a/hw/i386/x86.c
> +++ b/hw/i386/x86.c
> @@ -764,6 +764,18 @@ static bool load_elfboot(const char *kernel_filename,
> return true;
> }
>
> +struct setup_data_fixup {
> + void *pos;
> + hwaddr val;
> + uint32_t addr;
> +};
Just a small comment, addr should be little-endian (see
fw_cfg_add_i32). It's not used outside x86_load_linux, so it is
possible to just use cpu_to_le32 there.
Also I think it's cleaner if a reset callback puts the value back to
zero. fw_cfg already has fw_cfg_machine_reset, so perhaps the easiest
way is to add a FWCfgCallback reset_cb argument to just
fw_cfg_add_bytes_callback. If I am missing something and it's not
necessary I can do the cpu_to_le32 change myself or wait for you; in
any case I'll wait for either your ack or a v5.
By the way, does this supersede v1..v3 that use the new protocol (I'd
guess so from the presence of the same 2/2 patch), or are the two
patches doing belts-and-suspenders?
Thanks,
Paolo
> +static void fixup_setup_data(void *opaque)
> +{
> + struct setup_data_fixup *fixup = opaque;
> + stq_p(fixup->pos, fixup->val);
> +}
> +
> void x86_load_linux(X86MachineState *x86ms,
> FWCfgState *fw_cfg,
> int acpi_data_size,
> @@ -1088,8 +1100,11 @@ void x86_load_linux(X86MachineState *x86ms,
> qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH);
> }
>
> - /* Offset 0x250 is a pointer to the first setup_data link. */
> - stq_p(header + 0x250, first_setup_data);
> + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
> + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
> + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
> + sev_load_ctx.kernel_data = (char *)kernel;
> + sev_load_ctx.kernel_size = kernel_size;
>
> /*
> * If we're starting an encrypted VM, it will be OVMF based, which uses the
> @@ -1099,16 +1114,18 @@ void x86_load_linux(X86MachineState *x86ms,
> * file the user passed in.
> */
> if (!sev_enabled()) {
> + struct setup_data_fixup *fixup = g_malloc(sizeof(*fixup));
> +
> memcpy(setup, header, MIN(sizeof(header), setup_size));
> + /* Offset 0x250 is a pointer to the first setup_data link. */
> + fixup->pos = setup + 0x250;
> + fixup->val = first_setup_data;
> + fixup->addr = real_addr;
> + fw_cfg_add_bytes_callback(fw_cfg, FW_CFG_SETUP_ADDR, fixup_setup_data, NULL,
> + fixup, &fixup->addr, sizeof(fixup->addr), true);
> + } else {
> + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
> }
> -
> - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
> - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
> - fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
> - sev_load_ctx.kernel_data = (char *)kernel;
> - sev_load_ctx.kernel_size = kernel_size;
> -
> - fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
> fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
> fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
> sev_load_ctx.setup_data = (char *)setup;
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index d605f3f45a..564bda3395 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -692,12 +692,12 @@ static const VMStateDescription vmstate_fw_cfg = {
> }
> };
>
> -static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> - FWCfgCallback select_cb,
> - FWCfgWriteCallback write_cb,
> - void *callback_opaque,
> - void *data, size_t len,
> - bool read_only)
> +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> + FWCfgCallback select_cb,
> + FWCfgWriteCallback write_cb,
> + void *callback_opaque,
> + void *data, size_t len,
> + bool read_only)
> {
> int arch = !!(key & FW_CFG_ARCH_LOCAL);
>
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index 0e7a8bc7af..e4fef393be 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -117,6 +117,28 @@ struct FWCfgMemState {
> */
> void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
>
> +/**
> + * fw_cfg_add_bytes_callback:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @select_cb: callback function when selecting
> + * @write_cb: callback function after a write
> + * @callback_opaque: argument to be passed into callback function
> + * @data: pointer to start of item data
> + * @len: size of item data
> + * @read_only: is file read only
> + *
> + * Add a new fw_cfg item, available by selecting the given key, as a raw
> + * "blob" of the given size. The data referenced by the starting pointer
> + * is only linked, NOT copied, into the data structure of the fw_cfg device.
> + */
> +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> + FWCfgCallback select_cb,
> + FWCfgWriteCallback write_cb,
> + void *callback_opaque,
> + void *data, size_t len,
> + bool read_only);
> +
> /**
> * fw_cfg_add_string:
> * @s: fw_cfg device being modified
> --
> 2.37.3
>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file
2022-09-21 8:59 ` Paolo Bonzini
@ 2022-09-21 9:04 ` Jason A. Donenfeld
2022-09-21 9:12 ` Jason A. Donenfeld
2022-09-21 9:35 ` Paolo Bonzini
0 siblings, 2 replies; 9+ messages in thread
From: Jason A. Donenfeld @ 2022-09-21 9:04 UTC (permalink / raw)
To: Paolo Bonzini
Cc: qemu-devel, Gerd Hoffmann, Laurent Vivier, Michael S . Tsirkin,
Peter Maydell, Philippe Mathieu-Daudé, Richard Henderson,
Ard Biesheuvel
Hi Paolo,
On Wed, Sep 21, 2022 at 10:59 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
> Just a small comment, addr should be little-endian (see
> fw_cfg_add_i32). It's not used outside x86_load_linux, so it is
> possible to just use cpu_to_le32 there.
Oh, shucks: I thought about this and then forgot to do it. Thanks for
catching it.
> Also I think it's cleaner if a reset callback puts the value back to
> zero. fw_cfg already has fw_cfg_machine_reset, so perhaps the easiest
> way is to add a FWCfgCallback reset_cb argument to just
> fw_cfg_add_bytes_callback. If I am missing something and it's not
> necessary I can do the cpu_to_le32 change myself or wait for you; in
> any case I'll wait for either your ack or a v5.
Actually, the idea is for the change to be permanent, since that
represents how the system has actually been booted. Are there
substantial changes possible to the firmware configuration on
fw_cfg_machine_reset() that setting this back how it was would make a
difference? Or do we benefit from having some consistency?
> By the way, does this supersede v1..v3 that use the new protocol (I'd
> guess so from the presence of the same 2/2 patch), or are the two
> patches doing belts-and-suspenders?
This v4 supersedes everything else.
Jason
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file
2022-09-21 9:04 ` Jason A. Donenfeld
@ 2022-09-21 9:12 ` Jason A. Donenfeld
2022-09-21 9:35 ` Paolo Bonzini
1 sibling, 0 replies; 9+ messages in thread
From: Jason A. Donenfeld @ 2022-09-21 9:12 UTC (permalink / raw)
To: Paolo Bonzini
Cc: qemu-devel, Gerd Hoffmann, Laurent Vivier, Michael S . Tsirkin,
Peter Maydell, Philippe Mathieu-Daudé, Richard Henderson,
Ard Biesheuvel
On Wed, Sep 21, 2022 at 11:04:17AM +0200, Jason A. Donenfeld wrote:
> > Also I think it's cleaner if a reset callback puts the value back to
> > zero. fw_cfg already has fw_cfg_machine_reset, so perhaps the easiest
> > way is to add a FWCfgCallback reset_cb argument to just
> > fw_cfg_add_bytes_callback. If I am missing something and it's not
> > necessary I can do the cpu_to_le32 change myself or wait for you; in
> > any case I'll wait for either your ack or a v5.
>
> Actually, the idea is for the change to be permanent, since that
> represents how the system has actually been booted. Are there
> substantial changes possible to the firmware configuration on
> fw_cfg_machine_reset() that setting this back how it was would make a
> difference? Or do we benefit from having some consistency?
Looking at this more, I think your suggestion makes sense. I also have a
very straight forward way of implementing it. I'll send a v5 in a
minute.
Jason
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file
2022-09-21 9:04 ` Jason A. Donenfeld
2022-09-21 9:12 ` Jason A. Donenfeld
@ 2022-09-21 9:35 ` Paolo Bonzini
1 sibling, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2022-09-21 9:35 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: qemu-devel, Gerd Hoffmann, Laurent Vivier, Michael S . Tsirkin,
Peter Maydell, Philippe Mathieu-Daudé, Richard Henderson,
Ard Biesheuvel
On Wed, Sep 21, 2022 at 11:12 AM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > Also I think it's cleaner if a reset callback puts the value back to
> > zero. fw_cfg already has fw_cfg_machine_reset, so perhaps the easiest
> > way is to add a FWCfgCallback reset_cb argument to just
> > fw_cfg_add_bytes_callback. If I am missing something and it's not
> > necessary I can do the cpu_to_le32 change myself or wait for you; in
> > any case I'll wait for either your ack or a v5.
>
> Actually, the idea is for the change to be permanent, since that
> represents how the system has actually been booted. Are there
> substantial changes possible to the firmware configuration on
> fw_cfg_machine_reset() that setting this back how it was would make a
> difference? Or do we benefit from having some consistency?
It's not a very practical thing to happen but I guess you could boot
UEFI twice, but the second time go to a CSM which could use the
setup_data. But really as you say it's just more consistent if reset
brings everything back to the pristine state, unless there's a good
reason to do so (which you agreed in the next message there isn't).
I'll queue v5, thanks!
Paolo
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file
2022-09-13 23:41 [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file Jason A. Donenfeld
` (2 preceding siblings ...)
2022-09-21 8:59 ` Paolo Bonzini
@ 2022-09-21 9:15 ` Michael S. Tsirkin
2022-09-21 9:15 ` Jason A. Donenfeld
3 siblings, 1 reply; 9+ messages in thread
From: Michael S. Tsirkin @ 2022-09-21 9:15 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: qemu-devel, Gerd Hoffmann, Laurent Vivier, Paolo Bonzini,
Peter Maydell, Philippe Mathieu-Daudé, Richard Henderson,
Ard Biesheuvel
On Wed, Sep 14, 2022 at 12:41:34AM +0100, Jason A. Donenfeld wrote:
> If setup_data is being read into a specific memory location, then
> generally the setup_data address parameter is read first, so that the
> caller knows where to read it into. In that case, we should return
> setup_data containing the absolute addresses that are hard coded and
> determined a priori. This is the case when kernels are loaded by BIOS,
> for example. In contrast, when setup_data is read as a file, then we
> shouldn't modify setup_data, since the absolute address will be wrong by
> definition. This is the case when OVMF loads the image.
>
> This allows setup_data to be used like normal, without crashing when EFI
> tries to use it.
>
> (As a small development note, strangely, fw_cfg_add_file_callback() was
> exported but fw_cfg_add_bytes_callback() wasn't, so this makes that
> consistent.)
>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Laurent Vivier <laurent@vivier.eu>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
> Cc: Richard Henderson <richard.henderson@linaro.org>
> Suggested-by: Ard Biesheuvel <ardb@kernel.org>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> ---
> hw/i386/x86.c | 37 +++++++++++++++++++++++++++----------
> hw/nvram/fw_cfg.c | 12 ++++++------
> include/hw/nvram/fw_cfg.h | 22 ++++++++++++++++++++++
> 3 files changed, 55 insertions(+), 16 deletions(-)
>
> diff --git a/hw/i386/x86.c b/hw/i386/x86.c
> index 050eedc0c8..933bbdd836 100644
> --- a/hw/i386/x86.c
> +++ b/hw/i386/x86.c
> @@ -764,6 +764,18 @@ static bool load_elfboot(const char *kernel_filename,
> return true;
> }
>
> +struct setup_data_fixup {
> + void *pos;
> + hwaddr val;
> + uint32_t addr;
> +};
> +
btw
typedef struct SetupDataFixup {
void *pos;
hwaddr val;
uint32_t addr;
} SetupDataFixup;
and use typedef everywhere.
Yes I know setup_data is like this but that probably should be
fixed too.
> +static void fixup_setup_data(void *opaque)
> +{
> + struct setup_data_fixup *fixup = opaque;
> + stq_p(fixup->pos, fixup->val);
> +}
> +
> void x86_load_linux(X86MachineState *x86ms,
> FWCfgState *fw_cfg,
> int acpi_data_size,
> @@ -1088,8 +1100,11 @@ void x86_load_linux(X86MachineState *x86ms,
> qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH);
> }
>
> - /* Offset 0x250 is a pointer to the first setup_data link. */
> - stq_p(header + 0x250, first_setup_data);
> + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
> + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
> + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
> + sev_load_ctx.kernel_data = (char *)kernel;
> + sev_load_ctx.kernel_size = kernel_size;
>
> /*
> * If we're starting an encrypted VM, it will be OVMF based, which uses the
> @@ -1099,16 +1114,18 @@ void x86_load_linux(X86MachineState *x86ms,
> * file the user passed in.
> */
> if (!sev_enabled()) {
> + struct setup_data_fixup *fixup = g_malloc(sizeof(*fixup));
> +
> memcpy(setup, header, MIN(sizeof(header), setup_size));
> + /* Offset 0x250 is a pointer to the first setup_data link. */
> + fixup->pos = setup + 0x250;
> + fixup->val = first_setup_data;
> + fixup->addr = real_addr;
> + fw_cfg_add_bytes_callback(fw_cfg, FW_CFG_SETUP_ADDR, fixup_setup_data, NULL,
> + fixup, &fixup->addr, sizeof(fixup->addr), true);
> + } else {
> + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
> }
> -
> - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
> - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
> - fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
> - sev_load_ctx.kernel_data = (char *)kernel;
> - sev_load_ctx.kernel_size = kernel_size;
> -
> - fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
> fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
> fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
> sev_load_ctx.setup_data = (char *)setup;
> diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
> index d605f3f45a..564bda3395 100644
> --- a/hw/nvram/fw_cfg.c
> +++ b/hw/nvram/fw_cfg.c
> @@ -692,12 +692,12 @@ static const VMStateDescription vmstate_fw_cfg = {
> }
> };
>
> -static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> - FWCfgCallback select_cb,
> - FWCfgWriteCallback write_cb,
> - void *callback_opaque,
> - void *data, size_t len,
> - bool read_only)
> +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> + FWCfgCallback select_cb,
> + FWCfgWriteCallback write_cb,
> + void *callback_opaque,
> + void *data, size_t len,
> + bool read_only)
> {
> int arch = !!(key & FW_CFG_ARCH_LOCAL);
>
> diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
> index 0e7a8bc7af..e4fef393be 100644
> --- a/include/hw/nvram/fw_cfg.h
> +++ b/include/hw/nvram/fw_cfg.h
> @@ -117,6 +117,28 @@ struct FWCfgMemState {
> */
> void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
>
> +/**
> + * fw_cfg_add_bytes_callback:
> + * @s: fw_cfg device being modified
> + * @key: selector key value for new fw_cfg item
> + * @select_cb: callback function when selecting
> + * @write_cb: callback function after a write
> + * @callback_opaque: argument to be passed into callback function
> + * @data: pointer to start of item data
> + * @len: size of item data
> + * @read_only: is file read only
> + *
> + * Add a new fw_cfg item, available by selecting the given key, as a raw
> + * "blob" of the given size. The data referenced by the starting pointer
> + * is only linked, NOT copied, into the data structure of the fw_cfg device.
> + */
> +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
> + FWCfgCallback select_cb,
> + FWCfgWriteCallback write_cb,
> + void *callback_opaque,
> + void *data, size_t len,
> + bool read_only);
> +
> /**
> * fw_cfg_add_string:
> * @s: fw_cfg device being modified
> --
> 2.37.3
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v4 1/2] x86: return modified setup_data only if read as memory, not as file
2022-09-21 9:15 ` Michael S. Tsirkin
@ 2022-09-21 9:15 ` Jason A. Donenfeld
0 siblings, 0 replies; 9+ messages in thread
From: Jason A. Donenfeld @ 2022-09-21 9:15 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: qemu-devel, Gerd Hoffmann, Laurent Vivier, Paolo Bonzini,
Peter Maydell, Philippe Mathieu-Daudé, Richard Henderson,
Ard Biesheuvel
On Wed, Sep 21, 2022 at 11:15 AM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Wed, Sep 14, 2022 at 12:41:34AM +0100, Jason A. Donenfeld wrote:
> > If setup_data is being read into a specific memory location, then
> > generally the setup_data address parameter is read first, so that the
> > caller knows where to read it into. In that case, we should return
> > setup_data containing the absolute addresses that are hard coded and
> > determined a priori. This is the case when kernels are loaded by BIOS,
> > for example. In contrast, when setup_data is read as a file, then we
> > shouldn't modify setup_data, since the absolute address will be wrong by
> > definition. This is the case when OVMF loads the image.
> >
> > This allows setup_data to be used like normal, without crashing when EFI
> > tries to use it.
> >
> > (As a small development note, strangely, fw_cfg_add_file_callback() was
> > exported but fw_cfg_add_bytes_callback() wasn't, so this makes that
> > consistent.)
> >
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Cc: Laurent Vivier <laurent@vivier.eu>
> > Cc: Michael S. Tsirkin <mst@redhat.com>
> > Cc: Paolo Bonzini <pbonzini@redhat.com>
> > Cc: Peter Maydell <peter.maydell@linaro.org>
> > Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
> > Cc: Richard Henderson <richard.henderson@linaro.org>
> > Suggested-by: Ard Biesheuvel <ardb@kernel.org>
> > Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> > ---
> > hw/i386/x86.c | 37 +++++++++++++++++++++++++++----------
> > hw/nvram/fw_cfg.c | 12 ++++++------
> > include/hw/nvram/fw_cfg.h | 22 ++++++++++++++++++++++
> > 3 files changed, 55 insertions(+), 16 deletions(-)
> >
> > diff --git a/hw/i386/x86.c b/hw/i386/x86.c
> > index 050eedc0c8..933bbdd836 100644
> > --- a/hw/i386/x86.c
> > +++ b/hw/i386/x86.c
> > @@ -764,6 +764,18 @@ static bool load_elfboot(const char *kernel_filename,
> > return true;
> > }
> >
> > +struct setup_data_fixup {
> > + void *pos;
> > + hwaddr val;
> > + uint32_t addr;
> > +};
> > +
>
> btw
>
> typedef struct SetupDataFixup {
> void *pos;
> hwaddr val;
> uint32_t addr;
> } SetupDataFixup;
>
>
> and use typedef everywhere.
Okay no problem. Will do for v5.
Jason
^ permalink raw reply [flat|nested] 9+ messages in thread