qemu-devel
[Top][All Lists]
Advanced

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

Re: [PATCH v5 1/6] hw/hppa/dino.c: Improve emulation of Dino PCI chip


From: Philippe Mathieu-Daudé
Subject: Re: [PATCH v5 1/6] hw/hppa/dino.c: Improve emulation of Dino PCI chip
Date: Thu, 13 Feb 2020 00:37:25 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.4.1

Hi Sven, Helge.

On 12/20/19 10:15 PM, Sven Schnelle wrote:
From: Helge Deller <address@hidden>

The tests of the dino chip with the Online-diagnostics CD
("ODE DINOTEST") now succeeds.
Additionally add some qemu trace events.

Signed-off-by: Helge Deller <address@hidden>
Signed-off-by: Sven Schnelle <address@hidden>
Reviewed-by: Philippe Mathieu-Daudé <address@hidden>
---
  MAINTAINERS          |  2 +-
  hw/hppa/dino.c       | 97 +++++++++++++++++++++++++++++++++++++-------
  hw/hppa/trace-events |  5 +++
  3 files changed, 89 insertions(+), 15 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 387879aebc..e333bc67a4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -876,7 +876,7 @@ F: hw/*/etraxfs_*.c
HP-PARISC Machines
  ------------------
-Dino
+HP B160L
  M: Richard Henderson <address@hidden>
  R: Helge Deller <address@hidden>
  S: Odd Fixes
diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c
index ab6969b45f..9797a7f0d9 100644
--- a/hw/hppa/dino.c
+++ b/hw/hppa/dino.c
@@ -1,7 +1,7 @@
  /*
- * HP-PARISC Dino PCI chipset emulation.
+ * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines
   *
- * (C) 2017 by Helge Deller <address@hidden>
+ * (C) 2017-2019 by Helge Deller <address@hidden>
   *
   * This work is licensed under the GNU GPL license version 2 or later.
   *
@@ -21,6 +21,7 @@
  #include "migration/vmstate.h"
  #include "hppa_sys.h"
  #include "exec/address-spaces.h"
+#include "trace.h"
#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost"
@@ -82,11 +83,28 @@
  #define DINO_PCI_HOST_BRIDGE(obj) \
      OBJECT_CHECK(DinoState, (obj), TYPE_DINO_PCI_HOST_BRIDGE)
+#define DINO800_REGS ((DINO_TLTIM - DINO_GMASK) / 4)

Coverity noticed (CID 1419394) this should be '(1 + (DINO_TLTIM - DINO_GMASK) / 4)' (13 registers).

+static const uint32_t reg800_keep_bits[DINO800_REGS] = {
+            MAKE_64BIT_MASK(0, 1),
+            MAKE_64BIT_MASK(0, 7),
+            MAKE_64BIT_MASK(0, 7),
+            MAKE_64BIT_MASK(0, 8),
+            MAKE_64BIT_MASK(0, 7),
+            MAKE_64BIT_MASK(0, 9),
+            MAKE_64BIT_MASK(0, 32),

Looking at the datasheet pp. 30, this register is 'Undefined'.
We should report GUEST_ERROR if it is accessed.

+            MAKE_64BIT_MASK(0, 8),
+            MAKE_64BIT_MASK(0, 30),
+            MAKE_64BIT_MASK(0, 25),

Still looking at the datasheet (pp. 37) PCIROR is 24-bit (not 25).

+            MAKE_64BIT_MASK(0, 22),

Here you are missing register 0x82c...

+            MAKE_64BIT_MASK(0, 9),
+};
+

Altogether:

static const uint32_t reg800_keep_bits[DINO800_REGS] = {
    MAKE_64BIT_MASK(0, 1),  /* GMASK */
    MAKE_64BIT_MASK(0, 7),  /* PAMR */
    MAKE_64BIT_MASK(0, 7),  /* PAPR */
    MAKE_64BIT_MASK(0, 8),  /* DAMODE */
    MAKE_64BIT_MASK(0, 7),  /* PCICMD */
    MAKE_64BIT_MASK(0, 9),  /* PCISTS */
    MAKE_64BIT_MASK(0, 0),  /* Undefined */
    MAKE_64BIT_MASK(0, 8),  /* MLTIM */
    MAKE_64BIT_MASK(0, 30), /* BRDG_FEAT */
    MAKE_64BIT_MASK(0, 24), /* PCIROR */
    MAKE_64BIT_MASK(0, 22), /* PCIWOR */
    MAKE_64BIT_MASK(0, 0),  /* Undocumented */
    MAKE_64BIT_MASK(0, 9),  /* TLTIM */
};

  typedef struct DinoState {
      PCIHostState parent_obj;
/* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops,
         so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops.  */
+    uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */
uint32_t iar0;
      uint32_t iar1;
@@ -94,8 +112,12 @@ typedef struct DinoState {
      uint32_t ipr;
      uint32_t icr;
      uint32_t ilr;
+    uint32_t io_fbb_en;
      uint32_t io_addr_en;
      uint32_t io_control;
+    uint32_t toc_addr;
+
+    uint32_t reg800[DINO800_REGS];
MemoryRegion this_mem;
      MemoryRegion pci_mem;
@@ -106,8 +128,6 @@ typedef struct DinoState {
      MemoryRegion bm_ram_alias;
      MemoryRegion bm_pci_alias;
      MemoryRegion bm_cpu_alias;
-
-    MemoryRegion cpu0_eir_mem;
  } DinoState;
/*
@@ -122,6 +142,8 @@ static void gsc_to_pci_forwarding(DinoState *s)
      tmp = extract32(s->io_control, 7, 2);
      enabled = (tmp == 0x01);
      io_addr_en = s->io_addr_en;
+    /* Mask out first (=firmware) and last (=Dino) areas. */
+    io_addr_en &= ~(BIT(31) | BIT(0));
memory_region_transaction_begin();
      for (i = 1; i < 31; i++) {
@@ -142,6 +164,8 @@ static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
                                  unsigned size, bool is_write,
                                  MemTxAttrs attrs)
  {
+    bool ret = false;
+
      switch (addr) {
      case DINO_IAR0:
      case DINO_IAR1:
@@ -152,16 +176,22 @@ static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
      case DINO_ICR:
      case DINO_ILR:
      case DINO_IO_CONTROL:
+    case DINO_IO_FBB_EN:
      case DINO_IO_ADDR_EN:
      case DINO_PCI_IO_DATA:
-        return true;
+    case DINO_TOC_ADDR:
+    case DINO_GMASK ... DINO_TLTIM:
+        ret = true;
+        break;
      case DINO_PCI_IO_DATA + 2:
-        return size <= 2;
+        ret = (size <= 2);
+        break;
      case DINO_PCI_IO_DATA + 1:
      case DINO_PCI_IO_DATA + 3:
-        return size == 1;
+        ret = (size == 1);
      }
-    return false;
+    trace_dino_chip_mem_valid(addr, ret);
+    return ret;
  }
static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr,
@@ -194,6 +224,9 @@ static MemTxResult dino_chip_read_with_attrs(void *opaque, 
hwaddr addr,
          }
          break;
+ case DINO_IO_FBB_EN:
+        val = s->io_fbb_en;
+        break;
      case DINO_IO_ADDR_EN:
          val = s->io_addr_en;
          break;
@@ -227,12 +260,28 @@ static MemTxResult dino_chip_read_with_attrs(void 
*opaque, hwaddr addr,
      case DINO_IRR1:
          val = s->ilr & s->imr & s->icr;
          break;
+    case DINO_TOC_ADDR:
+        val = s->toc_addr;
+        break;
+    case DINO_GMASK ... DINO_TLTIM:
+        val = s->reg800[(addr - DINO_GMASK) / 4];
+        if (addr == DINO_PAMR) {
+            val &= ~0x01;  /* LSB is hardwired to 0 */
+        }
+        if (addr == DINO_MLTIM) {
+            val &= ~0x07;  /* 3 LSB are hardwired to 0 */
+        }
+        if (addr == DINO_BRDG_FEAT) {
+            val &= ~(0x10710E0ul | 8); /* bits 5-7, 24 & 15 reserved */
+        }
+        break;
default:
          /* Controlled by dino_chip_mem_valid above.  */
          g_assert_not_reached();
      }
+ trace_dino_chip_read(addr, val);
      *data = val;
      return ret;
  }
@@ -245,6 +294,9 @@ static MemTxResult dino_chip_write_with_attrs(void *opaque, 
hwaddr addr,
      AddressSpace *io;
      MemTxResult ret;
      uint16_t ioaddr;
+    int i;
+
+    trace_dino_chip_write(addr, val);
switch (addr) {
      case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3:
@@ -266,9 +318,11 @@ static MemTxResult dino_chip_write_with_attrs(void 
*opaque, hwaddr addr,
          }
          return ret;
+ case DINO_IO_FBB_EN:
+        s->io_fbb_en = val & 0x03;
+        break;
      case DINO_IO_ADDR_EN:
-        /* Never allow first (=firmware) and last (=Dino) areas.  */
-        s->io_addr_en = val & 0x7ffffffe;
+        s->io_addr_en = val;
          gsc_to_pci_forwarding(s);
          break;
      case DINO_IO_CONTROL:
@@ -292,6 +346,10 @@ static MemTxResult dino_chip_write_with_attrs(void 
*opaque, hwaddr addr,
          /* Any write to IPR clears the register.  */
          s->ipr = 0;
          break;
+    case DINO_TOC_ADDR:
+        /* IO_COMMAND of CPU with client_id bits */
+        s->toc_addr = 0xFFFA0030 | (val & 0x1e000);
+        break;
case DINO_ILR:
      case DINO_IRR0:
@@ -299,6 +357,12 @@ static MemTxResult dino_chip_write_with_attrs(void 
*opaque, hwaddr addr,
          /* These registers are read-only.  */
          break;
+ case DINO_GMASK ... DINO_TLTIM:
+        i = (addr - DINO_GMASK) / 4;
+        val &= reg800_keep_bits[i];

Due to the missing register, Coverity reports:

>>>     CID 1419394:  Memory - illegal accesses  (OVERRUN)
>>> Overrunning array "reg800_keep_bits" of 12 4-byte elements at element index 12 (byte offset 48) using index "i" (which evaluates to 12).

+        s->reg800[i] = val;
+        break; > +
      default:
          /* Controlled by dino_chip_mem_valid above.  */
          g_assert_not_reached();
@@ -323,7 +387,7 @@ static const MemoryRegionOps dino_chip_ops = {
static const VMStateDescription vmstate_dino = {
      .name = "Dino",
-    .version_id = 1,
+    .version_id = 2,
      .minimum_version_id = 1,
      .fields = (VMStateField[]) {
          VMSTATE_UINT32(iar0, DinoState),
@@ -332,13 +396,14 @@ static const VMStateDescription vmstate_dino = {
          VMSTATE_UINT32(ipr, DinoState),
          VMSTATE_UINT32(icr, DinoState),
          VMSTATE_UINT32(ilr, DinoState),
+        VMSTATE_UINT32(io_fbb_en, DinoState),
          VMSTATE_UINT32(io_addr_en, DinoState),
          VMSTATE_UINT32(io_control, DinoState),
+        VMSTATE_UINT32(toc_addr, DinoState),
          VMSTATE_END_OF_LIST()
      }
  };
-
  /* Unlike pci_config_data_le_ops, no check of high bit set in config_reg.  */
static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len)
@@ -362,14 +427,16 @@ static const MemoryRegionOps dino_config_data_ops = {
static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len)
  {
-    PCIHostState *s = opaque;
-    return s->config_reg;
+    DinoState *s = opaque;
+    return s->config_reg_dino;
  }
static void dino_config_addr_write(void *opaque, hwaddr addr,
                                     uint64_t val, unsigned len)
  {
      PCIHostState *s = opaque;
+    DinoState *ds = opaque;
+    ds->config_reg_dino = val; /* keep a copy of original value */
      s->config_reg = val & ~3U;
  }
@@ -453,6 +520,8 @@ PCIBus *dino_init(MemoryRegion *addr_space, dev = qdev_create(NULL, TYPE_DINO_PCI_HOST_BRIDGE);
      s = DINO_PCI_HOST_BRIDGE(dev);
+    s->iar0 = s->iar1 = CPU_HPA + 3;
+    s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */
/* Dino PCI access from main memory. */
      memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops,
diff --git a/hw/hppa/trace-events b/hw/hppa/trace-events
index 4e2acb6176..f943b16c4e 100644
--- a/hw/hppa/trace-events
+++ b/hw/hppa/trace-events
@@ -2,3 +2,8 @@
# pci.c
  hppa_pci_iack_write(void) ""
+
+# dino.c
+dino_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is 
%d"
+dino_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x"
+dino_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x"





reply via email to

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