Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Jul 2019 17:43:59 +0000 (UTC)
From:      Chuck Tuffli <chuck@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r350379 - stable/12/usr.sbin/bhyve
Message-ID:  <201907271743.x6RHhx4U089573@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: chuck
Date: Sat Jul 27 17:43:59 2019
New Revision: 350379
URL: https://svnweb.freebsd.org/changeset/base/350379

Log:
  MFC r345957
  
  bhyve: Fix NVMe data structure copy to guest
  
  bhyve's NVMe emulation was transferring Identify data back to the guest
  incorrectly causing memory corruptions. These corruptions resulted in
  core dumps and other system level errors in the guest.
  
  Approved by:	imp (mentor)

Modified:
  stable/12/usr.sbin/bhyve/pci_nvme.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/usr.sbin/bhyve/pci_nvme.c
==============================================================================
--- stable/12/usr.sbin/bhyve/pci_nvme.c	Sat Jul 27 17:27:26 2019	(r350378)
+++ stable/12/usr.sbin/bhyve/pci_nvme.c	Sat Jul 27 17:43:59 2019	(r350379)
@@ -199,6 +199,9 @@ struct pci_nvme_softc {
 
 	struct nvme_namespace_data  nsdata;
 	struct nvme_controller_data ctrldata;
+	struct nvme_error_information_entry err_log;
+	struct nvme_health_information_page health_log;
+	struct nvme_firmware_page fw_log;
 
 	struct pci_nvme_blockstore nvstore;
 
@@ -366,6 +369,15 @@ pci_nvme_init_nsdata(struct pci_nvme_softc *sc)
 }
 
 static void
+pci_nvme_init_logpages(struct pci_nvme_softc *sc)
+{
+
+	memset(&sc->err_log, 0, sizeof(sc->err_log));
+	memset(&sc->health_log, 0, sizeof(sc->health_log));
+	memset(&sc->fw_log, 0, sizeof(sc->fw_log));
+}
+
+static void
 pci_nvme_reset_locked(struct pci_nvme_softc *sc)
 {
 	DPRINTF(("%s\r\n", __func__));
@@ -455,6 +467,47 @@ pci_nvme_init_controller(struct vmctx *ctx, struct pci
 }
 
 static int
+nvme_prp_memcpy(struct vmctx *ctx, uint64_t prp1, uint64_t prp2, uint8_t *src,
+	size_t len)
+{
+	uint8_t *dst;
+	size_t bytes;
+
+	if (len > (8 * 1024)) {
+		return (-1);
+	}
+
+	/* Copy from the start of prp1 to the end of the physical page */
+	bytes = PAGE_SIZE - (prp1 & PAGE_MASK);
+	bytes = MIN(bytes, len);
+
+	dst = vm_map_gpa(ctx, prp1, bytes);
+	if (dst == NULL) {
+		return (-1);
+	}
+
+	memcpy(dst, src, bytes);
+
+	src += bytes;
+
+	len -= bytes;
+	if (len == 0) {
+		return (0);
+	}
+
+	len = MIN(len, PAGE_SIZE);
+
+	dst = vm_map_gpa(ctx, prp2, len);
+	if (dst == NULL) {
+		return (-1);
+	}
+
+	memcpy(dst, src, len);
+
+	return (0);
+}
+
+static int
 nvme_opc_delete_io_sq(struct pci_nvme_softc* sc, struct nvme_command* command,
 	struct nvme_completion* compl)
 {
@@ -587,26 +640,24 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struc
 {
 	uint32_t logsize = (1 + ((command->cdw10 >> 16) & 0xFFF)) * 2;
 	uint8_t logpage = command->cdw10 & 0xFF;
-	void *data;
 
 	DPRINTF(("%s log page %u len %u\r\n", __func__, logpage, logsize));
 
-	if (logpage >= 1 && logpage <= 3)
-		data = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1,
-		                  PAGE_SIZE);
-
 	pci_nvme_status_genc(&compl->status, NVME_SC_SUCCESS);
 
 	switch (logpage) {
-	case 0x01: /* Error information */
-		memset(data, 0, logsize > PAGE_SIZE ? PAGE_SIZE : logsize);
+	case NVME_LOG_ERROR:
+		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
+		    command->prp2, (uint8_t *)&sc->err_log, logsize);
 		break;
-	case 0x02: /* SMART/Health information */
+	case NVME_LOG_HEALTH_INFORMATION:
 		/* TODO: present some smart info */
-		memset(data, 0, logsize > PAGE_SIZE ? PAGE_SIZE : logsize);
+		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
+		    command->prp2, (uint8_t *)&sc->health_log, logsize);
 		break;
-	case 0x03: /* Firmware slot information */
-		memset(data, 0, logsize > PAGE_SIZE ? PAGE_SIZE : logsize);
+	case NVME_LOG_FIRMWARE_SLOT:
+		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
+		    command->prp2, (uint8_t *)&sc->fw_log, logsize);
 		break;
 	default:
 		WPRINTF(("%s get log page %x command not supported\r\n",
@@ -630,14 +681,13 @@ nvme_opc_identify(struct pci_nvme_softc* sc, struct nv
 
 	switch (command->cdw10 & 0xFF) {
 	case 0x00: /* return Identify Namespace data structure */
-		dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1,
-		                  sizeof(sc->nsdata));
-		memcpy(dest, &sc->nsdata, sizeof(sc->nsdata));
+		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
+		    command->prp2, (uint8_t *)&sc->nsdata, sizeof(sc->nsdata));
 		break;
 	case 0x01: /* return Identify Controller data structure */
-		dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1,
-		                  sizeof(sc->ctrldata));
-		memcpy(dest, &sc->ctrldata, sizeof(sc->ctrldata));
+		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
+		    command->prp2, (uint8_t *)&sc->ctrldata,
+		    sizeof(sc->ctrldata));
 		break;
 	case 0x02: /* list of 1024 active NSIDs > CDW1.NSID */
 		dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1,
@@ -1871,6 +1921,7 @@ pci_nvme_init(struct vmctx *ctx, struct pci_devinst *p
 	pci_nvme_reset(sc);
 	pci_nvme_init_ctrldata(sc);
 	pci_nvme_init_nsdata(sc);
+	pci_nvme_init_logpages(sc);
 
 	pci_lintr_request(pi);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201907271743.x6RHhx4U089573>