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

Bug#859417: unblock: seabios/1.10.2-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package seabios

This package is only used by qemu system emulator on x86
(qemu-system-x86 package). Upstream qemu just released
a new stable/bugfix release of current qemu code, of
version 2.8.1, which I intend to upload to be shipped
in stretch.  This release, among other things, includes
updated seabios version 1.10.2 (the one I'm currently
asking to unblock).

Primary reason for this version requiriment is due to
a bugfix in qemu which triggered a bug in seabios which
is fixed in this release.  It is the ahci changes, needed
for proper guest reboot with fixed qemu.

However, there are other changes in seabios - especially
the fw_cfg changes - which might look somewhat larger than
it would be good.  These changes are specific to a small
area (fw_cfg interface is how qemu iteracts with seabios),
and intend to fix another, while rare to hit, bug, -
memory corruption due to lost memory pointers after guest
resume from S3 state. Rare because it's very rare to put
a guest to sleep.

I can, ofcourse, backport just the single ahci change -
5 new lines of code in src/hw/ahci.c, below in the
debdiff. If the release team chooses that it's better
way I'll do that.  But I don't really want to diviege
from upstream for too much - history shows that this
leads to difficult to diagnose issues which no one can
help with, because upstream behavour is different. 

Here's the git shortlog between upstream 1.10.1 and 1.10.2:

 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

 Kevin O'Connor (1):
      ps2port: Disable keyboard/mouse prior to resetting ps2 controller

 Ladi Prosek (1):
      ahci: Set upper 32-bit registers to zero

 Paul Menzel (1):
      vgasrc: Increase debug level

Unblock request for qemu follows shortly.

Thank you!

/mjt

unblock seabios/1.10.2-1

diff -Nru seabios-1.10.1/debian/changelog seabios-1.10.2/debian/changelog
--- seabios-1.10.1/debian/changelog	2016-12-26 23:43:43.000000000 +0300
+++ seabios-1.10.2/debian/changelog	2017-04-03 13:51:52.000000000 +0300
@@ -1,3 +1,12 @@
+seabios (1.10.2-1) unstable; urgency=medium
+
+  * new upstream stable/bugfix release,
+    required for qemu 2.8.1+ due to ahci changes,
+    plus fixes for guest resume from S3
+    and ps/2 keyboard/mouse handling
+
+ -- Michael Tokarev <mjt@tls.msk.ru>  Mon, 03 Apr 2017 13:47:29 +0300
+
 seabios (1.10.1-1) unstable; urgency=medium
 
   * new upstream release
diff -Nru seabios-1.10.1/src/fw/paravirt.c seabios-1.10.2/src/fw/paravirt.c
--- seabios-1.10.1/src/fw/paravirt.c	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/src/fw/paravirt.c	2017-02-24 17:01:20.000000000 +0300
@@ -253,6 +253,20 @@
 }
 
 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) {
@@ -280,6 +294,18 @@
     }
 }
 
+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;
@@ -303,6 +329,36 @@
     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)
+{
+    if (offset == 0) {
+        /* Do it in one transfer */
+        qemu_cfg_write_entry(src, key, len);
+    } else {
+        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)
+{
+    if ((offset + len) > file->size)
+        return -1;
+
+    if (!qemu_cfg_dma_enabled() || (file->copy != qemu_cfg_read_file)) {
+        warn_internalerror();
+        return -1;
+    }
+    return qemu_cfg_write_file_simple(src, qemu_get_romfile_key(file),
+                                      offset, len);
+}
+
 static void
 qemu_romfile_add(char *name, int select, int skip, int size)
 {
@@ -321,6 +377,18 @@
 }
 
 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 -Nru seabios-1.10.1/src/fw/paravirt.h seabios-1.10.2/src/fw/paravirt.h
--- seabios-1.10.1/src/fw/paravirt.h	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/src/fw/paravirt.h	2017-02-24 17:01:20.000000000 +0300
@@ -3,6 +3,7 @@
 
 #include "config.h" // CONFIG_*
 #include "biosvar.h" // GET_GLOBAL
+#include "romfile.h" // struct romfile_s
 
 // Types of paravirtualized platforms.
 #define PF_QEMU     (1<<0)
@@ -43,6 +44,7 @@
 #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
@@ -53,5 +55,8 @@
 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
diff -Nru seabios-1.10.1/src/fw/romfile_loader.c seabios-1.10.2/src/fw/romfile_loader.c
--- seabios-1.10.1/src/fw/romfile_loader.c	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/src/fw/romfile_loader.c	2017-02-24 17:01:20.000000000 +0300
@@ -4,7 +4,9 @@
 #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
 
 struct romfile_loader_file {
     struct romfile_s *file;
@@ -15,6 +17,16 @@
     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)
@@ -28,6 +40,19 @@
     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)
 {
@@ -35,12 +60,12 @@
     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;
@@ -52,9 +77,9 @@
     }
     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);
@@ -80,24 +105,24 @@
 {
     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:
@@ -108,12 +133,12 @@
                                         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)
@@ -127,6 +152,59 @@
     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;
+    }
+
+    /* Store the info so it can replayed later if necessary */
+    struct romfile_wr_pointer_entry *store = malloc_high(sizeof(*store));
+    if (!store) {
+        warn_noalloc();
+        return;
+    }
+    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();
+}
+
 int romfile_loader_execute(const char *name)
 {
     struct romfile_loader_entry_s *entry;
@@ -161,6 +239,10 @@
                         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 -Nru seabios-1.10.1/src/fw/romfile_loader.h seabios-1.10.2/src/fw/romfile_loader.h
--- seabios-1.10.1/src/fw/romfile_loader.h	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/src/fw/romfile_loader.h	2017-02-24 17:01:20.000000000 +0300
@@ -11,45 +11,61 @@
     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;
+
+        /*
+         * 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];
@@ -57,9 +73,10 @@
 };
 
 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 {
@@ -69,4 +86,6 @@
 
 int romfile_loader_execute(const char *name);
 
+void romfile_fw_cfg_resume(void);
+
 #endif
diff -Nru seabios-1.10.1/src/hw/ahci.c seabios-1.10.2/src/hw/ahci.c
--- seabios-1.10.1/src/hw/ahci.c	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/src/hw/ahci.c	2017-02-24 17:01:20.000000000 +0300
@@ -361,6 +361,11 @@
 
     ahci_port_writel(ctrl, pnr, PORT_LST_ADDR, (u32)port->list);
     ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR, (u32)port->fis);
+    if (ctrl->caps & HOST_CAP_64) {
+        ahci_port_writel(ctrl, pnr, PORT_LST_ADDR_HI, 0);
+        ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR_HI, 0);
+    }
+
     return port;
 }
 
diff -Nru seabios-1.10.1/src/hw/ps2port.c seabios-1.10.2/src/hw/ps2port.c
--- seabios-1.10.1/src/hw/ps2port.c	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/src/hw/ps2port.c	2017-02-24 17:01:20.000000000 +0300
@@ -449,11 +449,22 @@
 static void
 ps2_keyboard_setup(void *data)
 {
-    /* flush incoming keys */
+    // flush incoming keys (also verifies port is likely present)
     int ret = i8042_flush();
     if (ret)
         return;
 
+    // Disable keyboard / mouse and drain any input they may have sent
+    ret = i8042_command(I8042_CMD_KBD_DISABLE, NULL);
+    if (ret)
+        return;
+    ret = i8042_command(I8042_CMD_AUX_DISABLE, NULL);
+    if (ret)
+        return;
+    ret = i8042_flush();
+    if (ret)
+        return;
+
     // Controller self-test.
     u8 param[2];
     ret = i8042_command(I8042_CMD_CTL_TEST, param);
diff -Nru seabios-1.10.1/src/resume.c seabios-1.10.2/src/resume.c
--- seabios-1.10.1/src/resume.c	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/src/resume.c	2017-02-24 17:01:20.000000000 +0300
@@ -17,6 +17,7 @@
 #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
@@ -105,6 +106,9 @@
     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.
diff -Nru seabios-1.10.1/.version seabios-1.10.2/.version
--- seabios-1.10.1/.version	2016-11-22 11:22:51.000000000 +0300
+++ seabios-1.10.2/.version	2017-02-28 11:41:58.000000000 +0300
@@ -1 +1 @@
-1.10.1
+1.10.2
diff -Nru seabios-1.10.1/vgasrc/vgabios.h seabios-1.10.2/vgasrc/vgabios.h
--- seabios-1.10.1/vgasrc/vgabios.h	2016-11-21 18:56:36.000000000 +0300
+++ seabios-1.10.2/vgasrc/vgabios.h	2017-02-24 17:01:20.000000000 +0300
@@ -73,7 +73,7 @@
 
 // Debug settings
 #define DEBUG_VGA_POST 1
-#define DEBUG_VGA_10 3
+#define DEBUG_VGA_10 9
 
 // vgabios.c
 int vga_bpp(struct vgamode_s *vmode_g);


Reply to: