:p
atchew
Login
From: Ben Warren <ben@skyportsystems.com> This patch set adds the capability to write to QEMU across the fw_cfg DMA link. It adds a higher-level command to write the BIOS-allocated address of one fw_cfg file into an arbitrary point within another, writeable fw_cfg file across the above-mentioned link. The initial use case is for Windows VM Generation ID, where QEMU needs to change the contents of fw_cfg data at runtime, while still having BIOS allocate and manage the memory. The final corresponding QEMU patch can be found here: https://www.mail-archive.com/qemu-devel@nongnu.org/msg430490.html v3->v4: - Added a 'src_offset' field in the message so the pointer need not point to the beginning of the file. - Changed the command struct definitions from anonymous to named. v2->v3: - fixed up the qemu_cfg_write* functions to allow writing to an arbitrary offset within the destination file. - Changed function name to COMMAND_WRITE_POINTER and its functionality to not patch memory at all, but write back to a specified offset. v1->v2: - separated patch into two functional units. - changed so writes only occur over the DMA interface. - fixed coding style. - removed change to romfile struct definition (removed new write_back method). Ben Warren (3): QEMU DMA: Add DMA write capability romfile-loader: Switch to using named structs QEMU fw_cfg: Add command to write back address of file src/fw/paravirt.c | 49 ++++++++++++++++++++++++++++++++ src/fw/paravirt.h | 3 ++ src/fw/romfile_loader.c | 74 +++++++++++++++++++++++++++++++++++++------------ src/fw/romfile_loader.h | 63 ++++++++++++++++++++++++++--------------- 4 files changed, 149 insertions(+), 40 deletions(-) -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@skyportsystems.com> This allows BIOS to write data back to QEMU using the DMA interface and provides a higher-level abstraction to write to a fw_cfg file Signed-off-by: Ben Warren <ben@skyportsystems.com> --- src/fw/paravirt.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/fw/paravirt.h | 3 +++ 2 files changed, 52 insertions(+) diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -XXX,XX +XXX,XX @@ qemu_cfg_read(void *buf, int len) } static void +qemu_cfg_write(void *buf, int len) +{ + if (len == 0) { + return; + } + + if (qemu_cfg_dma_enabled()) { + qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_WRITE); + } else { + warn_internalerror(); + } +} + +static void qemu_cfg_skip(int len) { if (len == 0) { @@ -XXX,XX +XXX,XX @@ qemu_cfg_read_entry(void *buf, int e, int len) } } +static void +qemu_cfg_write_entry(void *buf, int e, int len) +{ + if (qemu_cfg_dma_enabled()) { + u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT + | QEMU_CFG_DMA_CTL_WRITE; + qemu_cfg_dma_transfer(buf, len, control); + } else { + warn_internalerror(); + } +} + struct qemu_romfile_s { struct romfile_s file; int select, skip; @@ -XXX,XX +XXX,XX @@ qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen) return file->size; } +int +qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len) +{ + if ((file->size + offset) < len) + return -1; + + if (!qemu_cfg_dma_enabled() || (file->copy != qemu_cfg_read_file)) { + warn_internalerror(); + return -1; + } + struct qemu_romfile_s *qfile; + qfile = container_of(file, struct qemu_romfile_s, file); + if (offset == 0) { + /* Do it in one transfer */ + qemu_cfg_write_entry(src, qfile->select, len); + } else { + qemu_cfg_select(qfile->select); + qemu_cfg_skip(offset); + qemu_cfg_write(src, len); + } + return len; +} + static void qemu_romfile_add(char *name, int select, int skip, int size) { diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h index XXXXXXX..XXXXXXX 100644 --- a/src/fw/paravirt.h +++ b/src/fw/paravirt.h @@ -XXX,XX +XXX,XX @@ #include "config.h" // CONFIG_* #include "biosvar.h" // GET_GLOBAL +#include "romfile.h" // struct romfile_s // Types of paravirtualized platforms. #define PF_QEMU (1<<0) @@ -XXX,XX +XXX,XX @@ static inline int runningOnKVM(void) { #define QEMU_CFG_DMA_CTL_READ 0x02 #define QEMU_CFG_DMA_CTL_SKIP 0x04 #define QEMU_CFG_DMA_CTL_SELECT 0x08 +#define QEMU_CFG_DMA_CTL_WRITE 0x10 // QEMU_CFG_DMA ID bit #define QEMU_CFG_VERSION_DMA 2 @@ -XXX,XX +XXX,XX @@ void qemu_platform_setup(void); void qemu_cfg_init(void); u16 qemu_get_present_cpus_count(void); +int qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len); #endif -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@skyportsystems.com> This is a little cleaner and matches how the command structures are defined in QEMU. Signed-off-by: Ben Warren <ben@skyportsystems.com> --- src/fw/romfile_loader.c | 34 +++++++++++++++++----------------- src/fw/romfile_loader.h | 40 ++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/fw/romfile_loader.c b/src/fw/romfile_loader.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.c +++ b/src/fw/romfile_loader.c @@ -XXX,XX +XXX,XX @@ static void romfile_loader_allocate(struct romfile_loader_entry_s *entry, struct romfile_loader_file *file = &files->files[files->nfiles]; void *data; int ret; - unsigned alloc_align = le32_to_cpu(entry->alloc_align); + unsigned alloc_align = le32_to_cpu(entry->alloc.align); if (alloc_align & (alloc_align - 1)) goto err; - switch (entry->alloc_zone) { + switch (entry->alloc.zone) { case ROMFILE_LOADER_ALLOC_ZONE_HIGH: zone = &ZoneHigh; break; @@ -XXX,XX +XXX,XX @@ static void romfile_loader_allocate(struct romfile_loader_entry_s *entry, } if (alloc_align < MALLOC_MIN_ALIGN) alloc_align = MALLOC_MIN_ALIGN; - if (entry->alloc_file[ROMFILE_LOADER_FILESZ - 1]) + if (entry->alloc.file[ROMFILE_LOADER_FILESZ - 1]) goto err; - file->file = romfile_find(entry->alloc_file); + file->file = romfile_find(entry->alloc.file); if (!file->file || !file->file->size) return; data = _malloc(zone, file->file->size, alloc_align); @@ -XXX,XX +XXX,XX @@ static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry, { struct romfile_loader_file *dest_file; struct romfile_loader_file *src_file; - unsigned offset = le32_to_cpu(entry->pointer_offset); + unsigned offset = le32_to_cpu(entry->pointer.offset); u64 pointer = 0; - dest_file = romfile_loader_find(entry->pointer_dest_file, files); - src_file = romfile_loader_find(entry->pointer_src_file, files); + dest_file = romfile_loader_find(entry->pointer.dest_file, files); + src_file = romfile_loader_find(entry->pointer.src_file, files); if (!dest_file || !src_file || !dest_file->data || !src_file->data || - offset + entry->pointer_size < offset || - offset + entry->pointer_size > dest_file->file->size || - entry->pointer_size < 1 || entry->pointer_size > 8 || - entry->pointer_size & (entry->pointer_size - 1)) + offset + entry->pointer.size < offset || + offset + entry->pointer.size > dest_file->file->size || + entry->pointer.size < 1 || entry->pointer.size > 8 || + entry->pointer.size & (entry->pointer.size - 1)) goto err; - memcpy(&pointer, dest_file->data + offset, entry->pointer_size); + memcpy(&pointer, dest_file->data + offset, entry->pointer.size); pointer = le64_to_cpu(pointer); pointer += (unsigned long)src_file->data; pointer = cpu_to_le64(pointer); - memcpy(dest_file->data + offset, &pointer, entry->pointer_size); + memcpy(dest_file->data + offset, &pointer, entry->pointer.size); return; err: @@ -XXX,XX +XXX,XX @@ static void romfile_loader_add_checksum(struct romfile_loader_entry_s *entry, struct romfile_loader_files *files) { struct romfile_loader_file *file; - unsigned offset = le32_to_cpu(entry->cksum_offset); - unsigned start = le32_to_cpu(entry->cksum_start); - unsigned len = le32_to_cpu(entry->cksum_length); + unsigned offset = le32_to_cpu(entry->cksum.offset); + unsigned start = le32_to_cpu(entry->cksum.start); + unsigned len = le32_to_cpu(entry->cksum.length); u8 *data; - file = romfile_loader_find(entry->cksum_file, files); + file = romfile_loader_find(entry->cksum.file, files); if (!file || !file->data || offset >= file->file->size || start + len < start || start + len > file->file->size) diff --git a/src/fw/romfile_loader.h b/src/fw/romfile_loader.h index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.h +++ b/src/fw/romfile_loader.h @@ -XXX,XX +XXX,XX @@ struct romfile_loader_entry_s { u32 command; union { /* - * COMMAND_ALLOCATE - allocate a table from @alloc_file - * subject to @alloc_align alignment (must be power of 2) - * and @alloc_zone (can be HIGH or FSEG) requirements. + * COMMAND_ALLOCATE - allocate a table from @alloc.file + * subject to @alloc.align alignment (must be power of 2) + * and @alloc.zone (can be HIGH or FSEG) requirements. * * Must appear exactly once for each file, and before * this file is referenced by any other command. */ struct { - char alloc_file[ROMFILE_LOADER_FILESZ]; - u32 alloc_align; - u8 alloc_zone; - }; + char file[ROMFILE_LOADER_FILESZ]; + u32 align; + u8 zone; + } alloc; /* * COMMAND_ADD_POINTER - patch the table (originating from - * @dest_file) at @pointer_offset, by adding a pointer to the table + * @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. + * addition is used depending on @pointer.size. */ struct { - char pointer_dest_file[ROMFILE_LOADER_FILESZ]; - char pointer_src_file[ROMFILE_LOADER_FILESZ]; - u32 pointer_offset; - u8 pointer_size; - }; + char dest_file[ROMFILE_LOADER_FILESZ]; + char src_file[ROMFILE_LOADER_FILESZ]; + u32 offset; + u8 size; + } pointer; /* * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by - * @cksum_start and @cksum_length fields, + * @cksum.start and @cksum.length fields, * and then add the value at @cksum_offset. * Checksum simply sums -X for each byte X in the range * using 8-bit math. */ struct { - char cksum_file[ROMFILE_LOADER_FILESZ]; - u32 cksum_offset; - u32 cksum_start; - u32 cksum_length; - }; + char file[ROMFILE_LOADER_FILESZ]; + u32 offset; + u32 start; + u32 length; + } cksum; /* padding */ char pad[124]; -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@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@skyportsystems.com> --- src/fw/romfile_loader.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/fw/romfile_loader.h | 23 ++++++++++++++++++++--- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/fw/romfile_loader.c b/src/fw/romfile_loader.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.c +++ b/src/fw/romfile_loader.c @@ -XXX,XX +XXX,XX @@ #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; @@ -XXX,XX +XXX,XX @@ 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 dst_offset = le32_to_cpu(entry->wr_pointer.dst_offset); + unsigned src_offset = le32_to_cpu(entry->wr_pointer.src_offset); + u64 pointer = 0; + + /* Writing back to a file that may not be loaded in RAM */ + dest_file = romfile_find(entry->wr_pointer.dest_file); + src_file = romfile_loader_find(entry->wr_pointer.src_file, files); + + if (!dest_file || !src_file || !src_file->data || + dst_offset + entry->wr_pointer.size < dst_offset || + dst_offset + entry->wr_pointer.size > dest_file->size || + src_offset > src_file->file->size || + entry->wr_pointer.size < 1 || entry->wr_pointer.size > 8 || + entry->wr_pointer.size & (entry->wr_pointer.size - 1)) { + goto err; + } + + pointer = (unsigned long)src_file->data + src_offset; + pointer = cpu_to_le64(pointer); + + /* Only supported on QEMU */ + if (qemu_cfg_write_file(&pointer, dest_file, dst_offset, + entry->wr_pointer.size) != entry->wr_pointer.size) { + goto err; + } + return; + err: + warn_internalerror(); +} + int romfile_loader_execute(const char *name) { struct romfile_loader_entry_s *entry; @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.h +++ b/src/fw/romfile_loader.h @@ -XXX,XX +XXX,XX @@ struct romfile_loader_entry_s { u32 length; } cksum; + /* + * COMMAND_WRITE_POINTER - Write back to a host file via DMA, + * wr_pointer@dest_file at offset @wr_pointer.dst_offset, a pointer + * to the table originating from @wr_pointer.src_file at offset + * @wr_pointer.src_offset. + * 1,2,4 or 8 byte unsigned addition is used depending on + * @wr_pointer.size. + */ + struct { + char dest_file[ROMFILE_LOADER_FILESZ]; + char src_file[ROMFILE_LOADER_FILESZ]; + u32 dst_offset; + u32 src_offset; + u8 size; + } wr_pointer; + /* padding */ char pad[124]; }; }; 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 { -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@skyportsystems.com> This patch set adds the capability to write to QEMU across the fw_cfg DMA link. It adds a higher-level command to write the BIOS-allocated address of one fw_cfg file into an arbitrary point within another, writeable fw_cfg file across the above-mentioned link. The initial use case is for Windows VM Generation ID, where QEMU needs to change the contents of fw_cfg data at runtime, while still having BIOS allocate and manage the memory. The final corresponding QEMU patch can be found here: https://www.mail-archive.com/qemu-devel@nongnu.org/msg430490.html v5->v6: - Rebased to top-of-tree - Minor refactoring and conditional execution based on code review v4->v5: - Minor changes to range checking and data validation - Added code for replaying COMMAND_WRITE_POINTER commands on S3 resume v3->v4: - Added a 'src_offset' field in the message so the pointer need not point to the beginning of the file. - Changed the command struct definitions from anonymous to named. v2->v3: - fixed up the qemu_cfg_write* functions to allow writing to an arbitrary offset within the destination file. - Changed function name to COMMAND_WRITE_POINTER and its functionality to not patch memory at all, but write back to a specified offset. v1->v2: - separated patch into two functional units. - changed so writes only occur over the DMA interface. - fixed coding style. - removed change to romfile struct definition (removed new write_back method). Ben Warren (5): QEMU DMA: Add DMA write capability romfile-loader: Switch to using named structs QEMU fw_cfg: Add command to write back address of file QEMU fw_cfg: Add functions for accessing files by key QEMU fw_cfg: Write fw_cfg back on S3 resume src/fw/paravirt.c | 69 +++++++++++++++++++++++++++++ src/fw/paravirt.h | 5 +++ src/fw/romfile_loader.c | 112 ++++++++++++++++++++++++++++++++++++++++-------- src/fw/romfile_loader.h | 65 ++++++++++++++++++---------- src/resume.c | 4 ++ 5 files changed, 215 insertions(+), 40 deletions(-) -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@skyportsystems.com> This allows BIOS to write data back to QEMU using the DMA interface and provides a higher-level abstraction to write to a fw_cfg file Signed-off-by: Ben Warren <ben@skyportsystems.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> --- src/fw/paravirt.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/fw/paravirt.h | 3 +++ 2 files changed, 52 insertions(+) diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -XXX,XX +XXX,XX @@ qemu_cfg_read(void *buf, int len) } static void +qemu_cfg_write(void *buf, int len) +{ + if (len == 0) { + return; + } + + if (qemu_cfg_dma_enabled()) { + qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_WRITE); + } else { + warn_internalerror(); + } +} + +static void qemu_cfg_skip(int len) { if (len == 0) { @@ -XXX,XX +XXX,XX @@ qemu_cfg_read_entry(void *buf, int e, int len) } } +static void +qemu_cfg_write_entry(void *buf, int e, int len) +{ + if (qemu_cfg_dma_enabled()) { + u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT + | QEMU_CFG_DMA_CTL_WRITE; + qemu_cfg_dma_transfer(buf, len, control); + } else { + warn_internalerror(); + } +} + struct qemu_romfile_s { struct romfile_s file; int select, skip; @@ -XXX,XX +XXX,XX @@ qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen) return file->size; } +int +qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len) +{ + if ((offset + len) > file->size) + return -1; + + if (!qemu_cfg_dma_enabled() || (file->copy != qemu_cfg_read_file)) { + warn_internalerror(); + return -1; + } + struct qemu_romfile_s *qfile; + qfile = container_of(file, struct qemu_romfile_s, file); + if (offset == 0) { + /* Do it in one transfer */ + qemu_cfg_write_entry(src, qfile->select, len); + } else { + qemu_cfg_select(qfile->select); + qemu_cfg_skip(offset); + qemu_cfg_write(src, len); + } + return len; +} + static void qemu_romfile_add(char *name, int select, int skip, int size) { diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h index XXXXXXX..XXXXXXX 100644 --- a/src/fw/paravirt.h +++ b/src/fw/paravirt.h @@ -XXX,XX +XXX,XX @@ #include "config.h" // CONFIG_* #include "biosvar.h" // GET_GLOBAL +#include "romfile.h" // struct romfile_s // Types of paravirtualized platforms. #define PF_QEMU (1<<0) @@ -XXX,XX +XXX,XX @@ static inline int runningOnKVM(void) { #define QEMU_CFG_DMA_CTL_READ 0x02 #define QEMU_CFG_DMA_CTL_SKIP 0x04 #define QEMU_CFG_DMA_CTL_SELECT 0x08 +#define QEMU_CFG_DMA_CTL_WRITE 0x10 // QEMU_CFG_DMA ID bit #define QEMU_CFG_VERSION_DMA 2 @@ -XXX,XX +XXX,XX @@ void qemu_platform_setup(void); void qemu_cfg_init(void); u16 qemu_get_present_cpus_count(void); +int qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len); #endif -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@skyportsystems.com> This is a little cleaner and matches how the command structures are defined in QEMU. Signed-off-by: Ben Warren <ben@skyportsystems.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> --- src/fw/romfile_loader.c | 34 +++++++++++++++++----------------- src/fw/romfile_loader.h | 40 ++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/fw/romfile_loader.c b/src/fw/romfile_loader.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.c +++ b/src/fw/romfile_loader.c @@ -XXX,XX +XXX,XX @@ static void romfile_loader_allocate(struct romfile_loader_entry_s *entry, struct romfile_loader_file *file = &files->files[files->nfiles]; void *data; int ret; - unsigned alloc_align = le32_to_cpu(entry->alloc_align); + unsigned alloc_align = le32_to_cpu(entry->alloc.align); if (alloc_align & (alloc_align - 1)) goto err; - switch (entry->alloc_zone) { + switch (entry->alloc.zone) { case ROMFILE_LOADER_ALLOC_ZONE_HIGH: zone = &ZoneHigh; break; @@ -XXX,XX +XXX,XX @@ static void romfile_loader_allocate(struct romfile_loader_entry_s *entry, } if (alloc_align < MALLOC_MIN_ALIGN) alloc_align = MALLOC_MIN_ALIGN; - if (entry->alloc_file[ROMFILE_LOADER_FILESZ - 1]) + if (entry->alloc.file[ROMFILE_LOADER_FILESZ - 1]) goto err; - file->file = romfile_find(entry->alloc_file); + file->file = romfile_find(entry->alloc.file); if (!file->file || !file->file->size) return; data = _malloc(zone, file->file->size, alloc_align); @@ -XXX,XX +XXX,XX @@ static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry, { struct romfile_loader_file *dest_file; struct romfile_loader_file *src_file; - unsigned offset = le32_to_cpu(entry->pointer_offset); + unsigned offset = le32_to_cpu(entry->pointer.offset); u64 pointer = 0; - dest_file = romfile_loader_find(entry->pointer_dest_file, files); - src_file = romfile_loader_find(entry->pointer_src_file, files); + dest_file = romfile_loader_find(entry->pointer.dest_file, files); + src_file = romfile_loader_find(entry->pointer.src_file, files); if (!dest_file || !src_file || !dest_file->data || !src_file->data || - offset + entry->pointer_size < offset || - offset + entry->pointer_size > dest_file->file->size || - entry->pointer_size < 1 || entry->pointer_size > 8 || - entry->pointer_size & (entry->pointer_size - 1)) + offset + entry->pointer.size < offset || + offset + entry->pointer.size > dest_file->file->size || + entry->pointer.size < 1 || entry->pointer.size > 8 || + entry->pointer.size & (entry->pointer.size - 1)) goto err; - memcpy(&pointer, dest_file->data + offset, entry->pointer_size); + memcpy(&pointer, dest_file->data + offset, entry->pointer.size); pointer = le64_to_cpu(pointer); pointer += (unsigned long)src_file->data; pointer = cpu_to_le64(pointer); - memcpy(dest_file->data + offset, &pointer, entry->pointer_size); + memcpy(dest_file->data + offset, &pointer, entry->pointer.size); return; err: @@ -XXX,XX +XXX,XX @@ static void romfile_loader_add_checksum(struct romfile_loader_entry_s *entry, struct romfile_loader_files *files) { struct romfile_loader_file *file; - unsigned offset = le32_to_cpu(entry->cksum_offset); - unsigned start = le32_to_cpu(entry->cksum_start); - unsigned len = le32_to_cpu(entry->cksum_length); + unsigned offset = le32_to_cpu(entry->cksum.offset); + unsigned start = le32_to_cpu(entry->cksum.start); + unsigned len = le32_to_cpu(entry->cksum.length); u8 *data; - file = romfile_loader_find(entry->cksum_file, files); + file = romfile_loader_find(entry->cksum.file, files); if (!file || !file->data || offset >= file->file->size || start + len < start || start + len > file->file->size) diff --git a/src/fw/romfile_loader.h b/src/fw/romfile_loader.h index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.h +++ b/src/fw/romfile_loader.h @@ -XXX,XX +XXX,XX @@ struct romfile_loader_entry_s { u32 command; union { /* - * COMMAND_ALLOCATE - allocate a table from @alloc_file - * subject to @alloc_align alignment (must be power of 2) - * and @alloc_zone (can be HIGH or FSEG) requirements. + * COMMAND_ALLOCATE - allocate a table from @alloc.file + * subject to @alloc.align alignment (must be power of 2) + * and @alloc.zone (can be HIGH or FSEG) requirements. * * Must appear exactly once for each file, and before * this file is referenced by any other command. */ struct { - char alloc_file[ROMFILE_LOADER_FILESZ]; - u32 alloc_align; - u8 alloc_zone; - }; + char file[ROMFILE_LOADER_FILESZ]; + u32 align; + u8 zone; + } alloc; /* * COMMAND_ADD_POINTER - patch the table (originating from - * @dest_file) at @pointer_offset, by adding a pointer to the table + * @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. + * addition is used depending on @pointer.size. */ struct { - char pointer_dest_file[ROMFILE_LOADER_FILESZ]; - char pointer_src_file[ROMFILE_LOADER_FILESZ]; - u32 pointer_offset; - u8 pointer_size; - }; + char dest_file[ROMFILE_LOADER_FILESZ]; + char src_file[ROMFILE_LOADER_FILESZ]; + u32 offset; + u8 size; + } pointer; /* * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by - * @cksum_start and @cksum_length fields, + * @cksum.start and @cksum.length fields, * and then add the value at @cksum_offset. * Checksum simply sums -X for each byte X in the range * using 8-bit math. */ struct { - char cksum_file[ROMFILE_LOADER_FILESZ]; - u32 cksum_offset; - u32 cksum_start; - u32 cksum_length; - }; + char file[ROMFILE_LOADER_FILESZ]; + u32 offset; + u32 start; + u32 length; + } cksum; /* padding */ char pad[124]; -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@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@skyportsystems.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> --- src/fw/romfile_loader.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/fw/romfile_loader.h | 23 ++++++++++++++++++++--- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/fw/romfile_loader.c b/src/fw/romfile_loader.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.c +++ b/src/fw/romfile_loader.c @@ -XXX,XX +XXX,XX @@ #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; @@ -XXX,XX +XXX,XX @@ 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 dst_offset = le32_to_cpu(entry->wr_pointer.dst_offset); + unsigned src_offset = le32_to_cpu(entry->wr_pointer.src_offset); + u64 pointer = 0; + + /* Writing back to a file that may not be loaded in RAM */ + dest_file = romfile_find(entry->wr_pointer.dest_file); + src_file = romfile_loader_find(entry->wr_pointer.src_file, files); + + if (!dest_file || !src_file || !src_file->data || + dst_offset + entry->wr_pointer.size < dst_offset || + dst_offset + entry->wr_pointer.size > dest_file->size || + src_offset >= src_file->file->size || + entry->wr_pointer.size < 1 || entry->wr_pointer.size > 8 || + entry->wr_pointer.size & (entry->wr_pointer.size - 1)) { + goto err; + } + + pointer = (unsigned long)src_file->data + src_offset; + /* Make sure the pointer fits within wr_pointer.size */ + if ((entry->wr_pointer.size != sizeof(u64)) && + ((pointer >> (entry->wr_pointer.size * 8)) > 0)) { + goto err; + } + pointer = cpu_to_le64(pointer); + + /* Only supported on QEMU */ + if (qemu_cfg_write_file(&pointer, dest_file, dst_offset, + entry->wr_pointer.size) != entry->wr_pointer.size) { + goto err; + } + return; + err: + warn_internalerror(); +} + int romfile_loader_execute(const char *name) { struct romfile_loader_entry_s *entry; @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.h +++ b/src/fw/romfile_loader.h @@ -XXX,XX +XXX,XX @@ struct romfile_loader_entry_s { u32 length; } cksum; + /* + * COMMAND_WRITE_POINTER - Write back to a host file via DMA, + * @wr_pointer.dest_file at offset @wr_pointer.dst_offset, a pointer + * to the table originating from @wr_pointer.src_file at offset + * @wr_pointer.src_offset. + * 1,2,4 or 8 byte unsigned addition is used depending on + * @wr_pointer.size. + */ + struct { + char dest_file[ROMFILE_LOADER_FILESZ]; + char src_file[ROMFILE_LOADER_FILESZ]; + u32 dst_offset; + u32 src_offset; + u8 size; + } wr_pointer; + /* padding */ char pad[124]; }; }; 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 { -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@skyportsystems.com> Due to memory contraints, when resuming from S3 the fw_cfg "files" API isn't available. This adds a simple API to get a file 'key', and to write to the file using the key as a reference. Signed-off-by: Ben Warren <ben@skyportsystems.com> --- src/fw/paravirt.c | 32 ++++++++++++++++++++++++++------ src/fw/paravirt.h | 2 ++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -XXX,XX +XXX,XX @@ qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen) return file->size; } +// Bare-bones function for writing a file knowing only its unique +// identifying key (select) +int +qemu_cfg_write_file_simple(void *src, u16 key, u32 offset, u32 len) +{ + qemu_cfg_select(key); + qemu_cfg_skip(offset); + qemu_cfg_write(src, len); + return len; +} + int qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len) { @@ -XXX,XX +XXX,XX @@ qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len) warn_internalerror(); return -1; } - struct qemu_romfile_s *qfile; - qfile = container_of(file, struct qemu_romfile_s, file); + u16 key = qemu_get_romfile_key(file); if (offset == 0) { /* Do it in one transfer */ - qemu_cfg_write_entry(src, qfile->select, len); + qemu_cfg_write_entry(src, key, len); } else { - qemu_cfg_select(qfile->select); - qemu_cfg_skip(offset); - qemu_cfg_write(src, len); + qemu_cfg_write_file_simple(src, key, offset, len); } return len; } @@ -XXX,XX +XXX,XX @@ qemu_romfile_add(char *name, int select, int skip, int size) } u16 +qemu_get_romfile_key(struct romfile_s *file) +{ + struct qemu_romfile_s *qfile; + if (file->copy != qemu_cfg_read_file) { + warn_internalerror(); + return 0; + } + qfile = container_of(file, struct qemu_romfile_s, file); + return qfile->select; +} + +u16 qemu_get_present_cpus_count(void) { u16 smp_count = 0; diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h index XXXXXXX..XXXXXXX 100644 --- a/src/fw/paravirt.h +++ b/src/fw/paravirt.h @@ -XXX,XX +XXX,XX @@ void qemu_cfg_init(void); u16 qemu_get_present_cpus_count(void); int qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len); +int qemu_cfg_write_file_simple(void *src, u16 key, u32 offset, u32 len); +u16 qemu_get_romfile_key(struct romfile_s *file); #endif -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios
From: Ben Warren <ben@skyportsystems.com> Any pointers to BIOS-allocated memory that were written back to QEMU fw_cfg files are replayed when resuming from S3 sleep. Signed-off-by: Ben Warren <ben@skyportsystems.com> --- src/fw/romfile_loader.c | 33 +++++++++++++++++++++++++++++++++ src/fw/romfile_loader.h | 2 ++ src/resume.c | 4 ++++ 3 files changed, 39 insertions(+) diff --git a/src/fw/romfile_loader.c b/src/fw/romfile_loader.c index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.c +++ b/src/fw/romfile_loader.c @@ -XXX,XX +XXX,XX @@ #include "string.h" // strcmp #include "romfile.h" // struct romfile_s #include "malloc.h" // Zone*, _malloc +#include "list.h" // struct hlist_node #include "output.h" // warn_* #include "paravirt.h" // qemu_cfg_write_file @@ -XXX,XX +XXX,XX @@ struct romfile_loader_files { struct romfile_loader_file files[]; }; +// Data structures for storing "write pointer" entries for possible replay +struct romfile_wr_pointer_entry { + u64 pointer; + u32 offset; + u16 key; + u8 ptr_size; + struct hlist_node node; +}; +static struct hlist_head romfile_pointer_list; + static struct romfile_loader_file * romfile_loader_find(const char *name, struct romfile_loader_files *files) @@ -XXX,XX +XXX,XX @@ romfile_loader_find(const char *name, return NULL; } +// Replay "write pointer" entries back to QEMU +void romfile_fw_cfg_resume(void) +{ + if (!CONFIG_QEMU) + return; + + struct romfile_wr_pointer_entry *entry; + hlist_for_each_entry(entry, &romfile_pointer_list, node) { + qemu_cfg_write_file_simple(&entry->pointer, entry->key, + entry->offset, entry->ptr_size); + } +} + static void romfile_loader_allocate(struct romfile_loader_entry_s *entry, struct romfile_loader_files *files) { @@ -XXX,XX +XXX,XX @@ static void romfile_loader_write_pointer(struct romfile_loader_entry_s *entry, entry->wr_pointer.size) != entry->wr_pointer.size) { goto err; } + + /* Store the info so it can replayed later if necessary */ + struct romfile_wr_pointer_entry *store = malloc_high(sizeof(*store)); + store->pointer = pointer; + store->key = qemu_get_romfile_key(dest_file); + store->offset = dst_offset; + store->ptr_size = entry->wr_pointer.size; + hlist_add_head(&store->node, &romfile_pointer_list); + return; err: warn_internalerror(); diff --git a/src/fw/romfile_loader.h b/src/fw/romfile_loader.h index XXXXXXX..XXXXXXX 100644 --- a/src/fw/romfile_loader.h +++ b/src/fw/romfile_loader.h @@ -XXX,XX +XXX,XX @@ enum { int romfile_loader_execute(const char *name); +void romfile_fw_cfg_resume(void); + #endif diff --git a/src/resume.c b/src/resume.c index XXXXXXX..XXXXXXX 100644 --- a/src/resume.c +++ b/src/resume.c @@ -XXX,XX +XXX,XX @@ #include "string.h" // memset #include "util.h" // dma_setup #include "tcgbios.h" // tpm_s3_resume +#include "fw/romfile_loader.h" // romfile_fw_cfg_resume // Handler for post calls that look like a resume. void VISIBLE16 @@ -XXX,XX +XXX,XX @@ s3_resume(void) tpm_s3_resume(); s3_resume_vga(); + /* Replay any fw_cfg entries that go back to the host */ + romfile_fw_cfg_resume(); + make_bios_readonly(); // Invoke the resume vector. -- 2.7.4 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org https://www.coreboot.org/mailman/listinfo/seabios