qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v6 1/7] linker-loader: Add new 'write pointer' c


From: Igor Mammedov
Subject: Re: [Qemu-devel] [PATCH v6 1/7] linker-loader: Add new 'write pointer' command
Date: Wed, 15 Feb 2017 19:35:20 +0100

On Wed, 15 Feb 2017 10:14:55 -0800
Ben Warren <address@hidden> wrote:

> > On Feb 15, 2017, at 10:06 AM, Michael S. Tsirkin <address@hidden> wrote:
> > 
> > On Wed, Feb 15, 2017 at 09:54:08AM -0800, Ben Warren wrote:  
> >> 
> >>    On Feb 15, 2017, at 9:43 AM, Igor Mammedov <address@hidden> wrote:
> >> 
> >>    On Wed, 15 Feb 2017 18:39:06 +0200
> >>    "Michael S. Tsirkin" <address@hidden> wrote:
> >> 
> >> 
> >>        On Wed, Feb 15, 2017 at 04:56:02PM +0100, Igor Mammedov wrote:
> >> 
> >>            On Wed, 15 Feb 2017 17:30:00 +0200
> >>            "Michael S. Tsirkin" <address@hidden> wrote:
> >> 
> >> 
> >>                On Wed, Feb 15, 2017 at 04:22:25PM +0100, Igor Mammedov 
> >> wrote:
> >> 
> >> 
> >>                    On Wed, 15 Feb 2017 15:13:20 +0100
> >>                    Laszlo Ersek <address@hidden> wrote:
> >> 
> >> 
> >>                        Commenting under Igor's reply for simplicity
> >> 
> >>                        On 02/15/17 11:57, Igor Mammedov wrote:    
> >> 
> >>                            On Tue, 14 Feb 2017 22:15:43 -0800
> >>                            address@hidden wrote:
> >> 
> >> 
> >>                                From: Ben Warren <address@hidden>
> >> 
> >>                                This is similar to the existing 'add 
> >> pointer'
> >>                                functionality, but instead
> >>                                of instructing the guest (BIOS or UEFI) to
> >>                                patch memory, it instructs
> >>                                the guest to write the pointer back to QEMU 
> >> via
> >>                                a writeable fw_cfg file.
> >> 
> >>                                Signed-off-by: Ben Warren <  
> >>                                address@hidden>  
> >>                                ---
> >>                                hw/acpi/bios-linker-loader.c         | 58
> >>                                ++++++++++++++++++++++++++++++++++--
> >>                                include/hw/acpi/bios-linker-loader.h |  6 
> >> ++++
> >>                                2 files changed, 61 insertions(+), 3 
> >> deletions
> >>                                (-)
> >> 
> >>                                diff --git a/hw/acpi/bios-linker-loader.c 
> >> b/hw/
> >>                                acpi/bios-linker-loader.c
> >>                                index d963ebe..5030cf1 100644
> >>                                --- a/hw/acpi/bios-linker-loader.c
> >>                                +++ b/hw/acpi/bios-linker-loader.c
> >>                                @@ -78,6 +78,19 @@ struct 
> >> BiosLinkerLoaderEntry
> >>                                {
> >>                                            uint32_t length;
> >>                                        } cksum;
> >> 
> >>                                +        /*
> >>                                +         * COMMAND_WRITE_POINTER - write 
> >> the
> >>                                fw_cfg file (originating from
> >>                                +         * @dest_file) at 
> >> @wr_pointer.offset,
> >>                                by adding a pointer to the table
> >>                                +         * originating from @src_file. 
> >> 1,2,4
> >>                                or 8 byte unsigned
> >>                                +         * addition is used depending on
> >>                                @wr_pointer.size.
> >>                                +         */      
> >> 
> >> 
> >>                        The words "adding" and "addition" are causing 
> >> confusion
> >>                        here.
> >> 
> >>                        In all of the previous discussion, *addition* was 
> >> out
> >>                        of scope from
> >>                        WRITE_POINTER. Again, the firmware is specifically 
> >> not
> >>                        required to
> >>                        *read* any part of the fw_cfg blob identified by
> >>                        "dest_file".
> >> 
> >>                        WRITE_POINTER instructs the firmware to return the
> >>                        allocation address of
> >>                        the downloaded "src_file" to QEMU. Any necessary
> >>                        runtime subscripting
> >>                        within "src_file" is to be handled by QEMU code
> >>                        dynamically.
> >> 
> >>                        For example, consider that "src_file" has *several*
> >>                        fields that QEMU
> >>                        wants to massage; in that case, indexing within QEMU
> >>                        code with field
> >>                        offsets is simply unavoidable.    
> >> 
> >>                    what I don't like here is that this indexing would be
> >>                    rather fragile
> >>                    and has to be done in different parts of QEMU /device, 
> >> AML
> >>                    /.
> >> 
> >>                    I'd prefer this helper function to have the same
> >>                    @src_offset
> >>                    behavior as ADD_POINTER where patched address could 
> >> point
> >>                    to
> >>                    any part of src_file i.e. not just beginning.    
> >> 
> >> 
> >> 
> >> 
> >>                       /*
> >>                        * COMMAND_ADD_POINTER - patch the table (originating
> >>                from
> >>                        * @dest_file) at @pointer.offset, by adding a 
> >> pointer
> >>                to the table
> >>                        * originating from @src_file. 1,2,4 or 8 byte 
> >> unsigned
> >>                        * addition is used depending on @pointer.size.
> >>                        */
> >> 
> >>                so the way ADD works is
> >>                read at offset
> >>                add table address
> >>                write result at offset
> >> 
> >>                in other words it is always beginning of table that is 
> >> added.  
> >> 
> >>            more exactly it's, read at 
> >>             src_offset = *(dst_blob_ptr+dst_offset)
> >>             *(dst_blob+dst_offset) = src_blob_ptr + src_offset
> >> 
> >> 
> >>                Would the following be acceptable?
> >> 
> >> 
> >>                        * COMMAND_WRITE_POINTER - update the fw_cfg file
> >>                (originating from
> >>                        * @dest_file) at @wr_pointer.offset, by writing a
> >>                pointer to the table
> >>                        * originating from @src_file. 1,2,4 or 8 byte 
> >> unsigned
> >>                value
> >>                        * is written depending on @wr_pointer.size.  
> >> 
> >>            it looses 'adding' part of ADD_POINTER command which handles
> >>            src_offset,
> >>            however implementing adding part looks a bit complicated
> >>            as patched blob (dst) is not in guest memory but in QEMU and
> >>            on reset *(dst_blob+dst_offset) should be reset to src_offset.
> >>            Considering dst file could be device specific memory 
> >> (field/blob/
> >>            whatever)
> >>            it could be hard to track/notice proper reset behavior.
> >> 
> >>            So now I'm not sure if src_offset is worth adding.  
> >> 
> >> 
> >>        Right. Let's just do this math in QEMU if we have to.
> >> 
> >>    Math complicates QEMU code though and not only QMEMU but AML code as 
> >> well.
> >>    Considering that we are adding a new command and don't have to keep
> >>    any sort of compatibility we can pass src_offset as part
> >>    of command instead of hiding it inside of dst_file.
> >>    Something like this:
> >> 
> >>           /*
> >>            * COMMAND_WRITE_POINTER - write the fw_cfg file (originating 
> >> from
> >>            * @dest_file) at @wr_pointer.offset, by writing a pointer to
> >>    @src_offset
> >>            * within the table originating from @src_file. 1,2,4 or 8 byte
> >>    unsigned
> >>            * addition is used depending on @wr_pointer.size.
> >>            */
> >>           struct {
> >>                char dest_file[BIOS_LINKER_LOADER_FILESZ];
> >>                char src_file[BIOS_LINKER_LOADER_FILESZ];
> >>    -            uint32_t offset;
> >>    +            uint32_t dst_offset;
> >>    +            uint32_t src_offset;
> >>                uint8_t size;
> >>           } wr_pointer;
> >> 
> >> 
> >> OK, this is easy enough to do and maybe we’ll have a use case in the 
> >> future.
> >> I’ll make this change in v7  
> > 
> > 
> > So if you do, you want to set it to VMGENID_GUID_OFFSET.
> >   
> Oh, I was going to set it to 0 since that doesn’t require any other changes 
> (other than to SeaBIOS)
it should be changed in following places:

    bios_linker_loader_write_pointer(linker,
        VMGENID_ADDR_FW_CFG_FILE, 0, sizeof(uint64_t),
-        VMGENID_GUID_FW_CFG_FILE);
+        VMGENID_GUID_FW_CFG_FILE, VMGENID_GUID_OFFSET);
 
...
-            cpu_physical_memory_write(vmgenid_addr + VMGENID_GUID_OFFSET,
+            cpu_physical_memory_write(vmgenid_addr,
                                      guid_le.data, sizeof(guid_le.data));


> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >>                        (1) So, the above looks correct, but please replace
> >>                        "adding" with
> >>                        "storing", and "unsigned addition" with "store".
> >> 
> >>                        Side point: the case for ADD_POINTER is different;
> >>                        there we patch
> >>                        several individual ACPI objects. The fact that I
> >>                        requested explicit
> >>                        addition within the ADDR method, as opposed to
> >>                        pre-setting VGIA to a
> >>                        nonzero offset, is an *incidental* limitation 
> >> (coming
> >>                        from the OVMF ACPI
> >>                        SDT header probe suppressor), and we'll likely fix 
> >> that
> >>                        up later, with
> >>                        ALLOCATE command hints or something like that. 
> >> However,
> >>                        in
> >>                        WRITE_POINTER, asking for the exact allocation 
> >> address
> >>                        of "src_file" is
> >>                        an *inherent* characteristic.
> >> 
> >>                        For reference, this is the command's description 
> >> from
> >>                        the (not as yet
> >>                        posted) OVMF series:
> >> 
> >>                        // QemuLoaderCmdWritePointer: the bytes at
> >>                        // [PointerOffset..PointerOffset+PointerSize) in the
> >>                        writeable fw_cfg
> >>                        // file PointerFile are to receive the absolute 
> >> address
> >>                        of PointeeFile,
> >>                        // as allocated and downloaded by the firmware. 
> >> Store
> >>                        the base address
> >>                        // of where PointeeFile's contents have been placed
> >>                        (when
> >>                        // QemuLoaderCmdAllocate has been executed for
> >>                        PointeeFile) to this
> >>                        // portion of PointerFile.
> >>                        //
> >>                        // This command is similar to 
> >> QemuLoaderCmdAddPointer;
> >>                        the difference is
> >>                        // that the "pointer to patch" does not exist in
> >>                        guest-physical address
> >>                        // space, only in "fw_cfg file space". In addition, 
> >> the
> >>                        "pointer to
> >>                        // patch" is not initialized by QEMU with a possibly
> >>                        nonzero offset
> >>                        // value: the base address of the memory allocated 
> >> for
> >>                        downloading
> >>                        // PointeeFile shall not increment the pointer, but
> >>                        overwrite it.
> >> 
> >>                        In the last SeaBIOS patch series, namely
> >> 
> >>                        [SeaBIOS] [PATCH v3 2/2] QEMU fw_cfg: Add command to
> >>                        write back address
> >>                                                of file
> >> 
> >>                        function romfile_loader_write_pointer() implemented
> >>                        just that plain
> >>                        store (not an addition), and that was exactly right.
> >> 
> >>                        Continuing:
> >> 
> >> 
> >>                                +        struct {
> >>                                +            char dest_file
> >>                                [BIOS_LINKER_LOADER_FILESZ];
> >>                                +            char src_file
> >>                                [BIOS_LINKER_LOADER_FILESZ];
> >>                                +            uint32_t offset;
> >>                                +            uint8_t size;
> >>                                +        } wr_pointer;
> >>                                +
> >>                                        /* padding */
> >>                                        char pad[124];
> >>                                    };
> >>                                @@ -85,9 +98,10 @@ struct 
> >> BiosLinkerLoaderEntry
> >>                                {
> >>                                typedef struct BiosLinkerLoaderEntry
> >>                                BiosLinkerLoaderEntry;
> >> 
> >>                                enum {
> >>                                -    BIOS_LINKER_LOADER_COMMAND_ALLOCATE    
> >>  =
> >>                                0x1,
> >>                                -    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER 
> >>  =
> >>                                0x2,
> >>                                -    
> >> BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM =
> >>                                0x3,
> >>                                +    BIOS_LINKER_LOADER_COMMAND_ALLOCATE
> >>                                         = 0x1,
> >>                                +    BIOS_LINKER_LOADER_COMMAND_ADD_POINTER
> >>                                      = 0x2,
> >>                                +    BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM
> >>                                     = 0x3,
> >>                                +    
> >> BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER
> >>                                    = 0x4,
> >>                                };
> >> 
> >>                                enum {
> >>                                @@ -278,3 +292,41 @@ void
> >>                                bios_linker_loader_add_pointer(BIOSLinker
> >>                                *linker,
> >> 
> >>                                    g_array_append_vals(linker->cmd_blob, &
> >>                                entry, sizeof entry);
> >>                                }
> >>                                +
> >>                                +/*
> >>                                + * bios_linker_loader_write_pointer: ask 
> >> guest
> >>                                to write a pointer to the
> >>                                + * source file into the destination file, 
> >> and
> >>                                write it back to QEMU via
> >>                                + * fw_cfg DMA.
> >>                                + *
> >>                                + * @linker: linker object instance
> >>                                + * @dest_file: destination file that must 
> >> be
> >>                                written
> >>                                + * @dst_patched_offset: location within
> >>                                destination file blob to be patched
> >>                                + *                      with the pointer to
> >>                                @src_file, in bytes
> >>                                + * @dst_patched_offset_size: size of the
> >>                                pointer to be patched
> >>                                + *                      at 
> >> @dst_patched_offset
> >>                                in @dest_file blob, in bytes
> >>                                + * @src_file: source file who's address 
> >> must
> >>                                be taken
> >>                                + */
> >>                                +void bios_linker_loader_write_pointer
> >>                                (BIOSLinker *linker,
> >>                                +                                    const 
> >> char
> >>                                *dest_file,
> >>                                +                                    
> >> uint32_t
> >>                                dst_patched_offset,
> >>                                +                                    uint8_t
> >>                                dst_patched_size,
> >>                                +                                    const 
> >> char
> >>                                *src_file)      
> >> 
> >>                            API is missing "src_offset" even though it's not
> >>                            used in this series,
> >>                            a patch on top to fix it up is ok for me as far 
> >> as
> >>                            Seabios/OVMF
> >>                            counterpart can handle src_offset correctly from
> >>                            starters.      
> >> 
> >> 
> >>                        According to the above, it is the right thing not to
> >>                        add "src_offset"
> >>                        here. The documentation on the command is slightly
> >>                        incorrect (and causes
> >>                        confusion), but the helper function's signature and
> >>                        comments are okay.
> >> 
> >> 
> >> 
> >> 
> >>                                +{
> >>                                +    BiosLinkerLoaderEntry entry;
> >>                                +    const BiosLinkerFileEntry *source_file 
> >> =
> >>                                +        bios_linker_find_file(linker,
> >>                                src_file);
> >>                                +
> >>                                +    assert(source_file);      
> >> 
> >> 
> >>                        I wish we kept the following asserts from
> >>                        bios_linker_loader_add_pointer():
> >> 
> >>                           assert(dst_patched_offset < dst_file->blob->len);
> >>                           assert(dst_patched_offset + dst_patched_size <=
> >>                        dst_file->blob->len);
> >> 
> >>                        Namely, just because the dst_file is never supposed 
> >> to
> >>                        be downloaded by
> >>                        the firmware, it still remains a requirement that 
> >> the
> >>                        "dst file offset
> >>                        range" that is to be rewritten *do fall* within the 
> >> dst
> >>                        file.
> >> 
> >>                        Nonetheless, this is not critical. (OVMF at least
> >>                        verifies it anyway.)
> >> 
> >>                        Summary (from my side anyway): I feel that the
> >>                        documentation of the new
> >>                        command is very important. Please fix it up as
> >>                        suggested under (1), in
> >>                        v7. Regarding the asserts, I'll let you decide.
> >> 
> >>                        With the documentation fixed up:
> >> 
> >>                        Reviewed-by: Laszlo Ersek <address@hidden>
> >> 
> >>                        (If you don't wish to post a v7, I'm also completely
> >>                        fine if Michael or
> >>                        someone else fixes up the docs as proposed in (1),
> >>                        before committing the
> >>                        patch.)
> >> 
> >>                        Thanks!
> >>                        Laszlo
> >> 
> >> 
> >>                                +    memset(&entry, 0, sizeof entry);
> >>                                +    strncpy(entry.wr_pointer.dest_file,
> >>                                dest_file,
> >>                                +            sizeof 
> >> entry.wr_pointer.dest_file
> >>                                - 1);
> >>                                +    strncpy(entry.wr_pointer.src_file,
> >>                                src_file,
> >>                                +            sizeof 
> >> entry.wr_pointer.src_file -
> >>                                1);
> >>                                +    entry.command = cpu_to_le32
> >>                                (BIOS_LINKER_LOADER_COMMAND_WRITE_POINTER);
> >>                                +    entry.wr_pointer.offset = cpu_to_le32
> >>                                (dst_patched_offset);
> >>                                +    entry.wr_pointer.size = 
> >> dst_patched_size;
> >>                                +    assert(dst_patched_size == 1 ||
> >>                                dst_patched_size == 2 ||
> >>                                +           dst_patched_size == 4 ||
> >>                                dst_patched_size == 8);
> >>                                +
> >>                                +    g_array_append_vals(linker->cmd_blob, &
> >>                                entry, sizeof entry);
> >>                                +}
> >>                                diff --git a/include/hw/acpi/
> >>                                bios-linker-loader.h b/include/hw/acpi/
> >>                                bios-linker-loader.h
> >>                                index fa1e5d1..f9ba5d6 100644
> >>                                --- a/include/hw/acpi/bios-linker-loader.h
> >>                                +++ b/include/hw/acpi/bios-linker-loader.h
> >>                                @@ -26,5 +26,11 @@ void
> >>                                bios_linker_loader_add_pointer(BIOSLinker
> >>                                *linker,
> >>                                                                    const 
> >> char
> >>                                *src_file,
> >>                                                                    uint32_t
> >>                                src_offset);
> >> 
> >>                                +void bios_linker_loader_write_pointer
> >>                                (BIOSLinker *linker,
> >>                                +                                      const
> >>                                char *dest_file,
> >>                                +                                      
> >> uint32_t
> >>                                dst_patched_offset,
> >>                                +                                      
> >> uint8_t
> >>                                dst_patched_size,
> >>                                +                                      const
> >>                                char *src_file);
> >>                                +
> >>                                void bios_linker_loader_cleanup(BIOSLinker
> >>                                *linker);
> >>                                #endif        
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]