Print this page
8622 panic in PTE_set_all()
8623 IMMU_CONTIG_PADDR is broken for cookies with more than one page
8625 nvme causes bad free panic in IOMMU
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>

Split
Expand all
Collapse all
          --- old/usr/src/uts/i86pc/io/immu_dvma.c
          +++ new/usr/src/uts/i86pc/io/immu_dvma.c
↓ open down ↓ 20 lines elided ↑ open up ↑
  21   21  /*
  22   22   * Portions Copyright (c) 2010, Oracle and/or its affiliates.
  23   23   * All rights reserved.
  24   24   */
  25   25  /*
  26   26   * Copyright (c) 2009, Intel Corporation.
  27   27   * All rights reserved.
  28   28   */
  29   29  /*
  30   30   * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
       31 + * Copyright 2017 Joyent, Inc.
  31   32   */
  32   33  
  33   34  /*
  34   35   * DVMA code
  35   36   * This file contains Intel IOMMU code that deals with DVMA
  36   37   * i.e. DMA remapping.
  37   38   */
  38   39  
  39   40  #include <sys/sysmacros.h>
  40   41  #include <sys/pcie.h>
↓ open down ↓ 10 lines elided ↑ open up ↑
  51   52  #undef  TEST
  52   53  
  53   54  /*
  54   55   * Macros based on PCI spec
  55   56   */
  56   57  #define IMMU_PCI_REV2CLASS(r)   ((r) >> 8)  /* classcode from revid */
  57   58  #define IMMU_PCI_CLASS2BASE(c)  ((c) >> 16) /* baseclass from classcode */
  58   59  #define IMMU_PCI_CLASS2SUB(c)   (((c) >> 8) & 0xff); /* classcode */
  59   60  
  60   61  #define IMMU_CONTIG_PADDR(d, p) \
  61      -        ((d).dck_paddr && ((d).dck_paddr + IMMU_PAGESIZE) == (p))
       62 +        ((d).dck_paddr && ((d).dck_paddr + (d).dck_npages * IMMU_PAGESIZE) \
       63 +            == (p))
  62   64  
  63   65  typedef struct dvma_arg {
  64   66          immu_t *dva_immu;
  65   67          dev_info_t *dva_rdip;
  66   68          dev_info_t *dva_ddip;
  67   69          domain_t *dva_domain;
  68   70          int dva_level;
  69   71          immu_flags_t dva_flags;
  70   72          list_t *dva_list;
  71   73          int dva_error;
↓ open down ↓ 2046 lines elided ↑ open up ↑
2118 2120           */
2119 2121          shwp = (hw_pdte_t *)(pgtable->hwpg_vaddr) + idx;
2120 2122  
2121 2123          hwp = shwp;
2122 2124          for (j = dcount - 1; j >= 0; j--) {
2123 2125                  if (nvpages <= dcookies[j].dck_npages)
2124 2126                          break;
2125 2127                  nvpages -= dcookies[j].dck_npages;
2126 2128          }
2127 2129  
     2130 +        VERIFY(j >= 0);
2128 2131          nppages = nvpages;
2129 2132          paddr = dcookies[j].dck_paddr +
2130 2133              (dcookies[j].dck_npages - nppages) * IMMU_PAGESIZE;
2131 2134  
2132 2135          nvpages = *nvpages_ptr;
2133 2136          nset = 0;
2134 2137          for (; nvpages > 0 && idx <= IMMU_PGTABLE_MAXIDX; idx++, hwp++) {
2135 2138                  PTE_set_one(immu, hwp, paddr, rdip, immu_flags);
2136 2139                  nset++;
2137 2140  
↓ open down ↓ 521 lines elided ↑ open up ↑
2659 2662                  } else if (pparray != NULL) {
2660 2663                          /* index into the array of page_t's to get the paddr */
2661 2664                          paddr = pfn_to_pa(pparray[pcnt]->p_pagenum);
2662 2665                          pcnt++;
2663 2666                  } else {
2664 2667                          /* call into the VM to get the paddr */
2665 2668                          paddr = pfn_to_pa(hat_getpfnum(vas->a_hat, vaddr));
2666 2669                          vaddr += psize;
2667 2670                  }
2668 2671  
2669      -                npages++;
2670      -
2671 2672                  if (ihp->ihp_npremapped > 0) {
2672      -                        *ihp->ihp_preptes[npages - 1] =
     2673 +                        *ihp->ihp_preptes[npages] =
2673 2674                              PDTE_PADDR(paddr) | rwmask;
2674 2675                  } else if (IMMU_CONTIG_PADDR(dcookies[dmax], paddr)) {
2675 2676                          dcookies[dmax].dck_npages++;
2676 2677                  } else {
2677 2678                          /* No, we need a new dcookie */
2678 2679                          if (dmax == (IMMU_NDCK - 1)) {
2679 2680                                  /*
2680 2681                                   * Ran out of dcookies. Map them now.
2681 2682                                   */
2682 2683                                  if (dvma_map(domain, dvma,
↓ open down ↓ 1 lines elided ↑ open up ↑
2684 2685                                      immu_flags))
2685 2686                                          pde_set++;
2686 2687  
2687 2688                                  IMMU_DPROBE4(immu__dvmamap__early,
2688 2689                                      dev_info_t *, rdip, uint64_t, dvma,
2689 2690                                      uint_t, npages, uint_t, dmax+1);
2690 2691  
2691 2692                                  dvma += (npages << IMMU_PAGESHIFT);
2692 2693                                  npages = 0;
2693 2694                                  dmax = 0;
2694      -                        } else
     2695 +                        } else {
2695 2696                                  dmax++;
     2697 +                        }
2696 2698                          dcookies[dmax].dck_paddr = paddr;
2697 2699                          dcookies[dmax].dck_npages = 1;
2698 2700                  }
2699 2701                  size -= psize;
     2702 +                if (npages != 0)
     2703 +                        npages++;
2700 2704          }
2701 2705  
2702 2706          /*
2703 2707           * Finish up, mapping all, or all of the remaining,
2704 2708           * physical memory ranges.
2705 2709           */
2706 2710          if (ihp->ihp_npremapped == 0 && npages > 0) {
2707 2711                  IMMU_DPROBE4(immu__dvmamap__late, dev_info_t *, rdip, \
2708 2712                      uint64_t, dvma, uint_t, npages, uint_t, dmax+1);
2709 2713  
↓ open down ↓ 470 lines elided ↑ open up ↑