Exemple #1
0
static int install_virtiocon(struct unit *unit) {
  struct virtiocon *vcon;
  int rc;
  int size;
  int i;

  // Setup unit information
  if (!unit) return -ENOSYS;
  unit->vendorname = "VIRTIO";
  unit->productname = "VIRTIO Virtual Console Device";

  // Allocate memory for device
  vcon = kmalloc(sizeof(struct virtiocon));
  if (vcon == NULL) return -ENOMEM;
  memset(vcon, 0, sizeof(struct virtiocon));

  // Initialize virtual device
  rc = virtio_device_init(&vcon->vd, unit, VIRTIO_CON_F_SIZE);
  if (rc < 0) return rc;

  // Get console device configuration
  virtio_get_config(&vcon->vd, &vcon->config, sizeof(vcon->config));

  // Initialize queues for console
  rc = virtio_queue_init(&vcon->input_queue, &vcon->vd, 0, virtiocon_input_callback);
  if (rc < 0) return rc;
  rc = virtio_queue_init(&vcon->output_queue, &vcon->vd, 1, virtiocon_output_callback);
  if (rc < 0) return rc;

  // Fill input queue
  size = virtio_queue_size(&vcon->input_queue);
  for (i = 0; i < size; ++i) {
    struct scatterlist sg[1];
    char *data = kmalloc(PAGESIZE);
    if (!data) return -ENOMEM;
    sg[0].data = data;
    sg[0].size = PAGESIZE;
    virtio_enqueue(&vcon->input_queue, sg, 0, 1, data);
  }
  virtio_kick(&vcon->input_queue);

  // Create device
  vcon->devno = dev_make("vc#", &virtiocon_driver, unit, vcon);
  virtio_setup_complete(&vcon->vd, 1);
  kprintf(KERN_INFO "%s: virtio console, %dx%d, %d ports, feats=%d\n", 
          device(vcon->devno)->name, 
          vcon->config.cols, vcon->config.rows, vcon->config.max_ports, vcon->vd.features);

  return 0;
}
Exemple #2
0
static int install_virtioblk(struct unit *unit) {
  struct virtioblk *vblk;
  int rc;

  // Setup unit information
  if (!unit) return -ENOSYS;
  unit->vendorname = "VIRTIO";
  unit->productname = "VIRTIO Virtual Block Device";
  
  // Allocate memory for device
  vblk = kmalloc(sizeof(struct virtioblk));
  if (vblk == NULL) return -ENOMEM;
  memset(vblk, 0, sizeof(struct virtioblk));

  // Initialize virtual device
  rc = virtio_device_init(&vblk->vd, unit, VIRTIO_BLK_F_SEG_MAX | VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_FLUSH);
  if (rc < 0) return rc;
  
  // Get block device configuration
  virtio_get_config(&vblk->vd, &vblk->config, sizeof(vblk->config));
  if ((vblk->config.capacity & ~0x7FFFFFFF)) {
    vblk->capacity = 0x7FFFFFFF;
  } else {
    vblk->capacity = (int) vblk->config.capacity;
  }

  // Initialize queue for disk requests
  rc = virtio_queue_init(&vblk->vq, &vblk->vd, 0, virtioblk_callback);
  if (rc < 0) return rc;

  // Create device
  vblk->devno = dev_make("vd#", &virtioblk_driver, unit, vblk);
  virtio_setup_complete(&vblk->vd, 1);
  kprintf(KERN_INFO "%s: virtio disk, %dMB\n", device(vblk->devno)->name, vblk->capacity / (1024 * 1024 / SECTORSIZE));

  return 0;
}
Exemple #3
0
/**
 * virtio_9p_load
 *
 * Read a file from the 9P Server on the VIRTIO interface.
 *
 * @param file_name[in]	File to read, use Linux style paths.
 * @param buffer[out]	Where to read the file to.
 * @return	+ve = amount of data read, -ve = error.
 */
int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer)
{
	int rc;
	uint16_t tag_len;
	char tag_name[TAG_SIZE];
	uint64_t offset = 0;
	uint8_t *pos = (uint8_t *)file_name;
	int start_fid = ROOT_FID;
	p9_connection_t connection = {
		.message_size = __buf_size,
		.fid = ROOT_FID,
		.uname = "slof"
	};
	p9_file_t file = {
		.connection = &connection,
		.fid = FILE_FID,
	};


	/* Get the share name from 9P config space. */
	tag_len = virtio_get_config(dev, 0, sizeof(tag_len));
	if (tag_len >= TAG_SIZE)
		tag_len = TAG_SIZE - 1;
	__virtio_read_config(dev, tag_name, 2, tag_len);
	connection.aname = tag_name;

	/* Connect to the 9P server. */
	dprintf("%s : connecting, tag = %s, user = %s, msgsize = %d\n",
			__func__, connection.aname, connection.uname,
			connection.message_size);
	rc = p9_version(&connection);
	if (rc != 0) {
		printf("Version check failed, rc = %d\n", rc);
		goto cleanup_connection;
	}
	rc = p9_attach(&connection);
	if (rc != 0) {
		printf("Attach failed, rc = %d\n", rc);
		goto cleanup_connection;
	}
	dprintf("%s : connected, msgsize = %d\n", __func__,
			connection.message_size);

	/* Walk to the file. */
	do {
		dprintf("%s : walk path %s\n", __func__, pos);
		rc = p9_walk(&connection, start_fid, FILE_FID, &pos);

		if (rc < 0) {	/* Some error. */
			printf("Walk failed, rc = %d\n", rc);
			goto cleanup_connection;
		}

		/*
		 * If partial walk (*pos != 0) then continue the walk from
		 * mid point with start_fid updated to current position
		 * FILE_FID. FILE_FID will then be reused for the result of
		 * the next call to walk.
		 */
		start_fid = FILE_FID;
	} while (*pos != 0);

	/* Open the file. */
	dprintf("%s : stat and open\n", __func__);
	rc = p9_stat(&file);
	if (rc != 0) {
		printf("Stat failed, rc = %d\n", rc);
		goto cleanup_file;
	}
	rc = p9_open(&file, 0x00); /* TODO find include for "read mode" */
	if (rc != 0) {
		printf("Open failed, rc = %d\n", rc);
		goto cleanup_file;
	}
	dprintf("%s : file opened, size %lld\n", __func__, file.length);

	/* Read the file contents to buffer. */
	while (offset < file.length) {
		dprintf("%s : read from offset %llu\n", __func__, offset);
		rc = p9_read(&file, buffer + offset,
				file.length - offset, offset);
		dprintf("%s : read done, length was %d\n", __func__, rc);
		if (rc < 0) {
			printf("Read failed, rc = %d\n", rc);
			goto cleanup_file;
		}
		if (rc == 0) {
			break;
		}
		offset += rc;
		rc = 0;
	}

	/* Cleanup and disconnect. */
cleanup_file:
	dprintf("%s : clunking file\n", __func__);
	p9_clunk(&connection, file.fid);

cleanup_connection:
	dprintf("%s : clunking connection\n", __func__);
	p9_clunk(&connection, connection.fid);


	dprintf("%s : complete, read %llu bytes\n", __func__, offset);
	return rc == 0 ? offset : rc;
}
Exemple #4
0
/**
 * Read blocks
 * @param  reg  pointer to "reg" property
 * @param  buf  pointer to destination buffer
 * @param  blocknum  block number of the first block that should be read
 * @param  cnt  amount of blocks that should be read
 * @return number of blocks that have been read successfully
 */
int
virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
{
	struct vring_desc *desc;
	int id;
	static struct virtio_blk_req blkhdr;
	//struct virtio_blk_config *blkconf;
	uint64_t capacity;
	uint32_t vq_size, time;
	struct vring_desc *vq_desc;		/* Descriptor vring */
	struct vring_avail *vq_avail;		/* "Available" vring */
	struct vring_used *vq_used;		/* "Used" vring */
	volatile uint8_t status = -1;
	volatile uint16_t *current_used_idx;
	uint16_t last_used_idx;

	//printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n",
	//	dev, buf, blocknum, cnt);

	/* Check whether request is within disk capacity */
	capacity = virtio_get_config(dev, 0, sizeof(capacity));
	if (blocknum + cnt - 1 > capacity) {
		puts("virtioblk_read: Access beyond end of device!");
		return 0;
	}

	vq_size = virtio_get_qsize(dev, 0);
	vq_desc = virtio_get_vring_desc(dev, 0);
	vq_avail = virtio_get_vring_avail(dev, 0);
	vq_used = virtio_get_vring_used(dev, 0);

	last_used_idx = vq_used->idx;
	current_used_idx = &vq_used->idx;

	/* Set up header */
	blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER;
	blkhdr.ioprio = 1;
	blkhdr.sector = blocknum;

	/* Determine descriptor index */
	id = (vq_avail->idx * 3) % vq_size;

	/* Set up virtqueue descriptor for header */
	desc = &vq_desc[id];
	desc->addr = (uint64_t)&blkhdr;
	desc->len = sizeof(struct virtio_blk_req);
	desc->flags = VRING_DESC_F_NEXT;
	desc->next = (id + 1) % vq_size;

	/* Set up virtqueue descriptor for data */
	desc = &vq_desc[(id + 1) % vq_size];
	desc->addr = (uint64_t)buf;
	desc->len = cnt * 512;
	desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
	desc->next = (id + 2) % vq_size;

	/* Set up virtqueue descriptor for status */
	desc = &vq_desc[(id + 2) % vq_size];
	desc->addr = (uint64_t)&status;
	desc->len = 1;
	desc->flags = VRING_DESC_F_WRITE;
	desc->next = 0;

	vq_avail->ring[vq_avail->idx % vq_size] = id;
	mb();
	vq_avail->idx += 1;

	/* Tell HV that the queue is ready */
	virtio_queue_notify(dev, 0);

	/* Wait for host to consume the descriptor */
	time = SLOF_GetTimer() + VIRTIO_TIMEOUT;
	while (*current_used_idx == last_used_idx) {
		// do something better
		mb();
		if (time < SLOF_GetTimer())
			break;
	}

	if (status == 0)
		return cnt;

	printf("virtioblk_read failed! status = %i\n", status);

	return 0;
}
VOID
RhelGetDiskGeometry(
    IN PVOID DeviceExtension
)
{
    u64                cap;
    u32                v;
    struct virtio_blk_geometry vgeo;

    PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
    adaptExt->features = virtio_get_features(&adaptExt->vdev);

    if (CHECKBIT(adaptExt->features, VIRTIO_BLK_F_BARRIER)) {
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_BLK_F_BARRIER\n"));
    }

    if (CHECKBIT(adaptExt->features, VIRTIO_BLK_F_RO)) {
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_BLK_F_RO\n"));
    }

    if (CHECKBIT(adaptExt->features, VIRTIO_BLK_F_SIZE_MAX)) {
        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, size_max),
                          &v, sizeof(v));
        adaptExt->info.size_max = v;
    } else {
        adaptExt->info.size_max = SECTOR_SIZE;
    }

    if (CHECKBIT(adaptExt->features, VIRTIO_BLK_F_SEG_MAX)) {
        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, seg_max),
                          &v, sizeof(v));
        adaptExt->info.seg_max = v;
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_BLK_F_SEG_MAX = %d\n", adaptExt->info.seg_max));
    }

    if (CHECKBIT(adaptExt->features, VIRTIO_BLK_F_BLK_SIZE)) {
        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, blk_size),
                          &v, sizeof(v));
        adaptExt->info.blk_size = v;
    } else {
        adaptExt->info.blk_size = SECTOR_SIZE;
    }
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_BLK_F_BLK_SIZE = %d\n", adaptExt->info.blk_size));

    if (CHECKBIT(adaptExt->features, VIRTIO_BLK_F_GEOMETRY)) {
        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, geometry),
                          &vgeo, sizeof(vgeo));
        adaptExt->info.geometry.cylinders= vgeo.cylinders;
        adaptExt->info.geometry.heads    = vgeo.heads;
        adaptExt->info.geometry.sectors  = vgeo.sectors;
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_BLK_F_GEOMETRY. cylinders = %d  heads = %d  sectors = %d\n", adaptExt->info.geometry.cylinders, adaptExt->info.geometry.heads, adaptExt->info.geometry.sectors));
    }

    virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, capacity),
                      &cap, sizeof(cap));
    adaptExt->info.capacity = cap;
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("capacity = %08I64X\n", adaptExt->info.capacity));


    if(CHECKBIT(adaptExt->features, VIRTIO_BLK_F_TOPOLOGY)) {
        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, physical_block_exp),
                          &adaptExt->info.physical_block_exp, sizeof(adaptExt->info.physical_block_exp));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("physical_block_exp = %d\n", adaptExt->info.physical_block_exp));

        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, alignment_offset),
                          &adaptExt->info.alignment_offset, sizeof(adaptExt->info.alignment_offset));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("alignment_offset = %d\n", adaptExt->info.alignment_offset));

        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, min_io_size),
                          &adaptExt->info.min_io_size, sizeof(adaptExt->info.min_io_size));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("min_io_size = %d\n", adaptExt->info.min_io_size));

        virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(blk_config, opt_io_size),
                          &adaptExt->info.opt_io_size, sizeof(adaptExt->info.opt_io_size));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("opt_io_size = %d\n", adaptExt->info.opt_io_size));
    }
}