verified working on Purism Librem hardware :)

perhaps worth rolling into a 1.15.1 release, so that coreboot doesn't
have to roll back to 1.14.0 until 1.16.0 is released?

On Wed, Jan 19, 2022 at 8:22 AM Alexander Graf <g...@amazon.com> wrote:
>
> Commit 01f2736cc905d ("nvme: Pass large I/O requests as PRP lists")
> introduced multi-page requests using the NVMe PRP mechanism. To store the
> list and "first page to write to" hints, it added fields to the NVMe
> namespace struct.
>
> Unfortunately, that struct resides in fseg which is read-only at runtime.
> While KVM ignores the read-only part and allows writes, real hardware and
> TCG adhere to the semantics and ignore writes to the fseg region. The net
> effect of that is that reads and writes were always happening on address 0,
> unless they went through the bounce buffer logic.
>
> This patch splits moves all PRP maintenance data from the actual namespace
> allocation and allocates them in ZoneHigh instead. That way, the PRP list
> is fully read-write at runtime.
>
> Fixes: 01f2736cc905d ("nvme: Pass large I/O requests as PRP lists")
> Reported-by: Matt DeVillier <matt.devill...@gmail.com>
> Signed-off-by: Alexander Graf <g...@amazon.com>
> ---
>  src/hw/nvme-int.h | 12 ++++++++----
>  src/hw/nvme.c     | 24 ++++++++++++++++--------
>  2 files changed, 24 insertions(+), 12 deletions(-)
>
> diff --git a/src/hw/nvme-int.h b/src/hw/nvme-int.h
> index a4c1555..ceb2c79 100644
> --- a/src/hw/nvme-int.h
> +++ b/src/hw/nvme-int.h
> @@ -108,6 +108,13 @@ struct nvme_ctrl {
>      struct nvme_cq io_cq;
>  };
>
> +/* Page List Maintenance Data */
> +struct nvme_prp_info {
> +    u32 prpl_len;
> +    void *prp1;
> +    u64 prpl[NVME_MAX_PRPL_ENTRIES];
> +};
> +
>  struct nvme_namespace {
>      struct drive_s drive;
>      struct nvme_ctrl *ctrl;
> @@ -123,10 +130,7 @@ struct nvme_namespace {
>      /* Page aligned buffer of size NVME_PAGE_SIZE. */
>      char *dma_buffer;
>
> -    /* Page List */
> -    u32 prpl_len;
> -    void *prp1;
> -    u64 prpl[NVME_MAX_PRPL_ENTRIES];
> +    struct nvme_prp_info *prp;
>  };
>
>  /* Data structures for NVMe admin identify commands */
> diff --git a/src/hw/nvme.c b/src/hw/nvme.c
> index f035fa2..963c31e 100644
> --- a/src/hw/nvme.c
> +++ b/src/hw/nvme.c
> @@ -267,6 +267,14 @@ nvme_probe_ns(struct nvme_ctrl *ctrl, u32 ns_idx, u8 
> mdts)
>      ns->ns_id = ns_id;
>      ns->lba_count = id->nsze;
>
> +    ns->prp = malloc_high(sizeof(*ns->prp));
> +    if (!ns->prp) {
> +        warn_noalloc();
> +        free(ns);
> +        goto free_buffer;
> +    }
> +    memset(ns->prp, 0, sizeof(*ns->prp));
> +
>      struct nvme_lba_format *fmt = &id->lbaf[current_lba_format];
>
>      ns->block_size    = 1U << fmt->lbads;
> @@ -431,10 +439,10 @@ nvme_io_readwrite(struct nvme_namespace *ns, u64 lba, 
> char *buf, u16 count,
>
>      if ((ns->block_size * count) > (NVME_PAGE_SIZE * 2)) {
>          /* We need to describe more than 2 pages, rely on PRP List */
> -        prp2 = ns->prpl;
> +        prp2 = ns->prp->prpl;
>      } else if ((ns->block_size * count) > NVME_PAGE_SIZE) {
>          /* Directly embed the 2nd page if we only need 2 pages */
> -        prp2 = (void *)(long)ns->prpl[0];
> +        prp2 = (void *)(long)ns->prp->prpl[0];
>      } else {
>          /* One page is enough, don't expose anything else */
>          prp2 = NULL;
> @@ -465,15 +473,15 @@ nvme_io_readwrite(struct nvme_namespace *ns, u64 lba, 
> char *buf, u16 count,
>
>  static void nvme_reset_prpl(struct nvme_namespace *ns)
>  {
> -    ns->prpl_len = 0;
> +    ns->prp->prpl_len = 0;
>  }
>
>  static int nvme_add_prpl(struct nvme_namespace *ns, u64 base)
>  {
> -    if (ns->prpl_len >= NVME_MAX_PRPL_ENTRIES)
> +    if (ns->prp->prpl_len >= NVME_MAX_PRPL_ENTRIES)
>          return -1;
>
> -    ns->prpl[ns->prpl_len++] = base;
> +    ns->prp->prpl[ns->prp->prpl_len++] = base;
>
>      return 0;
>  }
> @@ -492,7 +500,7 @@ static int nvme_build_prpl(struct nvme_namespace *ns, 
> void *op_buf, u16 count)
>      size = count * ns->block_size;
>      /* Special case for transfers that fit into PRP1, but are unaligned */
>      if (((size + (base & ~NVME_PAGE_MASK)) <= NVME_PAGE_SIZE)) {
> -        ns->prp1 = op_buf;
> +        ns->prp->prp1 = op_buf;
>          return count;
>      }
>
> @@ -507,7 +515,7 @@ static int nvme_build_prpl(struct nvme_namespace *ns, 
> void *op_buf, u16 count)
>      for (; size > 0; base += NVME_PAGE_SIZE, size -= NVME_PAGE_SIZE) {
>          if (first_page) {
>              /* First page is special */
> -            ns->prp1 = (void*)base;
> +            ns->prp->prp1 = (void*)base;
>              first_page = 0;
>              continue;
>          }
> @@ -726,7 +734,7 @@ nvme_cmd_readwrite(struct nvme_namespace *ns, struct 
> disk_op_s *op, int write)
>
>          blocks = nvme_build_prpl(ns, op_buf, blocks_remaining);
>          if (blocks) {
> -            res = nvme_io_readwrite(ns, op->lba + i, ns->prp1, blocks, 
> write);
> +            res = nvme_io_readwrite(ns, op->lba + i, ns->prp->prp1, blocks, 
> write);
>              dprintf(5, "ns %u %s lba %llu+%u: %d\n", ns->ns_id, write ? 
> "write"
>                                                                        : 
> "read",
>                      op->lba, blocks, res);
> --
> 2.28.0.394.ge197136389
>
>
>
>
> Amazon Development Center Germany GmbH
> Krausenstr. 38
> 10117 Berlin
> Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
> Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
> Sitz: Berlin
> Ust-ID: DE 289 237 879
>
>
>
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-le...@seabios.org

Reply via email to