void PciConfig::DumpConfig(uint16_t len) const { printf("%u bytes of raw config (base %s:%#" PRIxPTR ")\n", len, (addr_space_ == PciAddrSpace::MMIO) ? "MMIO" : "PIO", base_); if (addr_space_ == PciAddrSpace::MMIO) { hexdump8(reinterpret_cast<const void*>(base_), len); } else { // PIO space can't be dumped directly so we read a row at a time constexpr uint8_t row_len = 16; uint32_t pos = 0; uint8_t buf[row_len]; do { for (uint16_t i = 0; i < row_len; i++) { buf[i] = Read(PciReg8(static_cast<uint8_t>(pos + i))); } hexdump8_ex(buf, row_len, base_ + pos); pos += row_len; } while (pos < PCIE_BASE_CONFIG_SIZE); } }
int virtio_mmio_detect(void *ptr, uint count, const uint irqs[]) { LTRACEF("ptr %p, count %u\n", ptr, count); DEBUG_ASSERT(ptr); DEBUG_ASSERT(irqs); DEBUG_ASSERT(!devices); /* allocate an array big enough to hold a list of devices */ devices = calloc(count, sizeof(struct virtio_device)); if (!devices) return ERR_NO_MEMORY; int found = 0; for (uint i = 0; i < count; i++) { volatile struct virtio_mmio_config *mmio = (struct virtio_mmio_config *)((uint8_t *)ptr + i * 0x200); struct virtio_device *dev = &devices[i]; dev->index = i; dev->irq = irqs[i]; mask_interrupt(irqs[i]); register_int_handler(irqs[i], &virtio_mmio_irq, (void *)dev); LTRACEF("looking at magic 0x%x version 0x%x did 0x%x vid 0x%x\n", mmio->magic, mmio->version, mmio->device_id, mmio->vendor_id); if (mmio->magic != VIRTIO_MMIO_MAGIC) { continue; } #if LOCAL_TRACE if (mmio->device_id != 0) { dump_mmio_config(mmio); } #endif #if WITH_DEV_VIRTIO_BLOCK if (mmio->device_id == 2) { // block device LTRACEF("found block device\n"); dev->mmio_config = mmio; dev->config_ptr = (void *)mmio->config; status_t err = virtio_block_init(dev, mmio->host_features); if (err >= 0) { // good device dev->valid = true; if (dev->irq_driver_callback) unmask_interrupt(dev->irq); // XXX quick test code, remove #if 0 uint8_t buf[512]; memset(buf, 0x99, sizeof(buf)); virtio_block_read_write(dev, buf, 0, sizeof(buf), false); hexdump8_ex(buf, sizeof(buf), 0); buf[0]++; virtio_block_read_write(dev, buf, 0, sizeof(buf), true); virtio_block_read_write(dev, buf, 0, sizeof(buf), false); hexdump8_ex(buf, sizeof(buf), 0); #endif } } #endif // WITH_DEV_VIRTIO_BLOCK #if WITH_DEV_VIRTIO_NET if (mmio->device_id == 1) { // network device LTRACEF("found net device\n"); dev->mmio_config = mmio; dev->config_ptr = (void *)mmio->config; status_t err = virtio_net_init(dev, mmio->host_features); if (err >= 0) { // good device dev->valid = true; if (dev->irq_driver_callback) unmask_interrupt(dev->irq); } } #endif // WITH_DEV_VIRTIO_NET #if WITH_DEV_VIRTIO_GPU if (mmio->device_id == 0x10) { // virtio-gpu LTRACEF("found gpu device\n"); dev->mmio_config = mmio; dev->config_ptr = (void *)mmio->config; status_t err = virtio_gpu_init(dev, mmio->host_features); if (err >= 0) { // good device dev->valid = true; if (dev->irq_driver_callback) unmask_interrupt(dev->irq); virtio_gpu_start(dev); } } #endif // WITH_DEV_VIRTIO_GPU if (dev->valid) found++; } return found; }
static int cmd_bio(int argc, const cmd_args *argv) { int rc = 0; if (argc < 2) { notenoughargs: printf("not enough arguments:\n"); usage: printf("%s list\n", argv[0].str); printf("%s read <device> <address> <offset> <len>\n", argv[0].str); printf("%s write <device> <address> <offset> <len>\n", argv[0].str); printf("%s dump <device> <offset> <len>\n", argv[0].str); printf("%s erase <device> <offset> <len>\n", argv[0].str); printf("%s ioctl <device> <request> <arg>\n", argv[0].str); printf("%s remove <device>\n", argv[0].str); printf("%s test <device>\n", argv[0].str); #if WITH_LIB_PARTITION printf("%s partscan <device> [offset]\n", argv[0].str); #endif #if WITH_LIB_CKSUM printf("%s crc32 <device> <offset> <len> [repeat]\n", argv[0].str); #endif return -1; } if (!strcmp(argv[1].str, "list")) { bio_dump_devices(); } else if (!strcmp(argv[1].str, "read")) { if (argc < 6) goto notenoughargs; addr_t address = argv[3].u; off_t offset = argv[4].u; // XXX use long size_t len = argv[5].u; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } lk_time_t t = current_time(); ssize_t err = bio_read(dev, (void *)address, offset, len); t = current_time() - t; dprintf(INFO, "bio_read returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); bio_close(dev); rc = err; } else if (!strcmp(argv[1].str, "write")) { if (argc < 6) goto notenoughargs; addr_t address = argv[3].u; off_t offset = argv[4].u; // XXX use long size_t len = argv[5].u; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } lk_time_t t = current_time(); ssize_t err = bio_write(dev, (void *)address, offset, len); t = current_time() - t; dprintf(INFO, "bio_write returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); bio_close(dev); rc = err; } else if (!strcmp(argv[1].str, "dump")) { if (argc < 5) { printf("not enough arguments:\n"); goto usage; } off_t offset = argv[3].u; // XXX use long size_t len = argv[4].u; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } uint8_t *buf = memalign(CACHE_LINE, 256); ssize_t err = 0; while (len > 0) { size_t amt = MIN(256, len); ssize_t err = bio_read(dev, buf, offset, amt); if (err < 0) { dprintf(ALWAYS, "read error %s %zu@%zu (err %d)\n", argv[2].str, amt, (size_t)offset, (int)err); break; } DEBUG_ASSERT((size_t)err <= amt); hexdump8_ex(buf, err, offset); if ((size_t)err != amt) { dprintf(ALWAYS, "short read from %s @%zu (wanted %zu, got %zu)\n", argv[2].str, (size_t)offset, amt, (size_t)err); break; } offset += amt; len -= amt; } bio_close(dev); rc = err; } else if (!strcmp(argv[1].str, "erase")) { if (argc < 5) goto notenoughargs; off_t offset = argv[3].u; // XXX use long size_t len = argv[4].u; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } lk_time_t t = current_time(); ssize_t err = bio_erase(dev, offset, len); t = current_time() - t; dprintf(INFO, "bio_erase returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); bio_close(dev); rc = err; } else if (!strcmp(argv[1].str, "ioctl")) { if (argc < 4) goto notenoughargs; int request = argv[3].u; int arg = (argc == 5) ? argv[4].u : 0; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } int err = bio_ioctl(dev, request, (void *)arg); dprintf(INFO, "bio_ioctl returns %d\n", err); bio_close(dev); rc = err; } else if (!strcmp(argv[1].str, "remove")) { if (argc < 3) goto notenoughargs; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } bio_unregister_device(dev); bio_close(dev); } else if (!strcmp(argv[1].str, "test")) { if (argc < 3) goto notenoughargs; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } int err = bio_test_device(dev); bio_close(dev); rc = err; #if WITH_LIB_PARTITION } else if (!strcmp(argv[1].str, "partscan")) { if (argc < 3) goto notenoughargs; off_t offset = 0; if (argc > 3) offset = argv[3].u; rc = partition_publish(argv[2].str, offset); dprintf(INFO, "partition_publish returns %d\n", rc); #endif #if WITH_LIB_CKSUM } else if (!strcmp(argv[1].str, "crc32")) { if (argc < 5) goto notenoughargs; off_t offset = argv[3].u; // XXX use long size_t len = argv[4].u; bdev_t *dev = bio_open(argv[2].str); if (!dev) { printf("error opening block device\n"); return -1; } void *buf = malloc(dev->block_size); bool repeat = false; if (argc >= 6 && !strcmp(argv[5].str, "repeat")) { repeat = true; } do { ulong crc = 0; off_t pos = offset; while (pos < offset + len) { ssize_t err = bio_read(dev, buf, pos, MIN(len - (pos - offset), dev->block_size)); if (err <= 0) { printf("error reading at offset 0x%llx\n", offset + pos); break; } crc = crc32(crc, buf, err); pos += err; } printf("crc 0x%08lx\n", crc); } while (repeat); bio_close(dev); free(buf); #endif } else { printf("unrecognized subcommand\n"); goto usage; } return rc; }