[SeaBIOS] [PATCH v3 2/2] QEMU fw_cfg: Add command to write back address of file
Laszlo Ersek
lersek at redhat.com
Thu Feb 9 09:17:46 CET 2017
Ben,
On 02/05/17 18:09, ben at skyportsystems.com wrote:
> From: Ben Warren <ben at skyportsystems.com>
>
> This command is similar to ADD_POINTER, but instead of patching
> memory, it writes the pointer back to QEMU over the DMA interface.
>
> Signed-off-by: Ben Warren <ben at skyportsystems.com>
> ---
> src/fw/romfile_loader.c | 37 +++++++++++++++++++++++++++++++++++++
> src/fw/romfile_loader.h | 16 ++++++++++------
> 2 files changed, 47 insertions(+), 6 deletions(-)
while working on the OVMF patches for WRITE_POINTER, something else
occurred to me.
As I mentioned in the QEMU thread,
https://www.mail-archive.com/qemu-devel@nongnu.org/msg428495.html
the VMGENID device (or more generally, each device that produces
WRITE_POINTER command(s)) should have a reset handler that makes the
device forget the GPA(s) that the firmware communicated to it, via
WRITE_POINTER. This is because after system reset, all earlier GPAs
become meaningless.
What I want to mention here is the corollary to the above. ACPI S3
resume is basically a reset, but the GPAs remain valid, because system
memory is preserved. Therefore, at S3 resume, the guest firmware has to
replay all the WRITE_POINTER commands. The QEMU reset handler will
forcibly forget about the GPAs (which is correct), so the firmware has
to re-store them.
I think it can be a separate patch for SeaBIOS (but preferably in this
series). I plan to do this in OVMF as well.
Thanks!
Laszlo
> diff --git a/src/fw/romfile_loader.c b/src/fw/romfile_loader.c
> index f4b17ff..d0ae42b 100644
> --- a/src/fw/romfile_loader.c
> +++ b/src/fw/romfile_loader.c
> @@ -5,6 +5,7 @@
> #include "romfile.h" // struct romfile_s
> #include "malloc.h" // Zone*, _malloc
> #include "output.h" // warn_*
> +#include "paravirt.h" // qemu_cfg_write_file
>
> struct romfile_loader_file {
> struct romfile_s *file;
> @@ -98,7 +99,39 @@ static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry,
> pointer += (unsigned long)src_file->data;
> pointer = cpu_to_le64(pointer);
> memcpy(dest_file->data + offset, &pointer, entry->pointer_size);
> + return;
> +err:
> + warn_internalerror();
> +}
> +
> +static void romfile_loader_write_pointer(struct romfile_loader_entry_s *entry,
> + struct romfile_loader_files *files)
> +{
> + struct romfile_s *dest_file;
> + struct romfile_loader_file *src_file;
> + unsigned offset = le32_to_cpu(entry->pointer_offset);
> + u64 pointer = 0;
> +
> + /* Writing back to a file that may not be loaded in RAM */
> + dest_file = romfile_find(entry->pointer_dest_file);
> + src_file = romfile_loader_find(entry->pointer_src_file, files);
>
> + if (!dest_file || !src_file || !src_file->data ||
> + offset + entry->pointer_size < offset ||
> + offset + entry->pointer_size > dest_file->size ||
> + entry->pointer_size < 1 || entry->pointer_size > 8 ||
> + entry->pointer_size & (entry->pointer_size - 1)) {
> + goto err;
> + }
> +
> + pointer = (unsigned long)src_file->data;
> + pointer = cpu_to_le64(pointer);
> +
> + /* Only supported on QEMU */
> + if (qemu_cfg_write_file(&pointer, dest_file, offset,
> + entry->pointer_size) != entry->pointer_size) {
> + goto err;
> + }
> return;
> err:
> warn_internalerror();
> @@ -161,6 +194,10 @@ int romfile_loader_execute(const char *name)
> break;
> case ROMFILE_LOADER_COMMAND_ADD_CHECKSUM:
> romfile_loader_add_checksum(entry, files);
> + break;
> + case ROMFILE_LOADER_COMMAND_WRITE_POINTER:
> + romfile_loader_write_pointer(entry, files);
> + break;
> default:
> /* Skip commands that we don't recognize. */
> break;
> diff --git a/src/fw/romfile_loader.h b/src/fw/romfile_loader.h
> index 15eab2a..0c0782c 100644
> --- a/src/fw/romfile_loader.h
> +++ b/src/fw/romfile_loader.h
> @@ -25,10 +25,13 @@ struct romfile_loader_entry_s {
> };
>
> /*
> - * COMMAND_ADD_POINTER - patch the table (originating from
> - * @dest_file) at @pointer_offset, by adding a pointer to the table
> + * COMMAND_ADD_POINTER &
> + * COMMAND_WRITE_POINTER - patch memory (originating from
> + * @dest_file) at @pointer.offset, by adding a pointer to the memory
> * originating from @src_file. 1,2,4 or 8 byte unsigned
> - * addition is used depending on @pointer_size.
> + * addition is used depending on @pointer.size.
> + * Instead of patching memory, COMMAND_WRITE_POINTER writes the changes
> + * to @dest_file back to the host via DMA
> */
> struct {
> char pointer_dest_file[ROMFILE_LOADER_FILESZ];
> @@ -57,9 +60,10 @@ struct romfile_loader_entry_s {
> };
>
> enum {
> - ROMFILE_LOADER_COMMAND_ALLOCATE = 0x1,
> - ROMFILE_LOADER_COMMAND_ADD_POINTER = 0x2,
> - ROMFILE_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
> + ROMFILE_LOADER_COMMAND_ALLOCATE = 0x1,
> + ROMFILE_LOADER_COMMAND_ADD_POINTER = 0x2,
> + ROMFILE_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
> + ROMFILE_LOADER_COMMAND_WRITE_POINTER = 0x4,
> };
>
> enum {
>
More information about the SeaBIOS
mailing list