From f037adcebd8e360eeb21cde9efaf3f450af39063 Mon Sep 17 00:00:00 2001 From: Rick Rongen Date: Thu, 1 Sep 2022 20:45:40 +0200 Subject: [PATCH] feat: start setup virtio --- include/endian.h | 21 +++++ include/myke/drivers/pci/pci.h | 3 +- include/myke/drivers/pci/virtio.h | 18 +++++ include/virtio_queue.h | 103 ++++++++++++++++++++++++ kernel/drivers/pci/ide.c | 4 +- kernel/drivers/pci/virtio/virtio-lock.c | 46 +++++++++++ launch-qemu.sh | 4 + 7 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 include/endian.h create mode 100644 include/myke/drivers/pci/virtio.h create mode 100644 include/virtio_queue.h create mode 100644 kernel/drivers/pci/virtio/virtio-lock.c diff --git a/include/endian.h b/include/endian.h new file mode 100644 index 0000000..fb6816a --- /dev/null +++ b/include/endian.h @@ -0,0 +1,21 @@ +// +// Created by rick on 14-5-22. +// + +#ifndef NEW_KERNEL_ENDIAN_H +#define NEW_KERNEL_ENDIAN_H + +#include + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define leu16_to_native(x) x +#define leu32_to_native(x) x +#else +#define leu16_to_native(x) ((x) >> 8 | (x) << 8) +#define leu32_to_native(x) (((x)>>24)&0xff) | \ + (((x)<<8)&0xff0000) | \ + (((x)>>8)&0xff00) | \ + (((x)<<24)&0xff000000) +#endif + +#endif //NEW_KERNEL_ENDIAN_H diff --git a/include/myke/drivers/pci/pci.h b/include/myke/drivers/pci/pci.h index 64126f7..f4b60ba 100644 --- a/include/myke/drivers/pci/pci.h +++ b/include/myke/drivers/pci/pci.h @@ -14,7 +14,8 @@ #define PCI_CLASS_BRIDGE 0x06 // class MASS STORAGE 0x01 -#define PCI_SUB_CLASS_IDE 0x01 +#define PCI_SUB_CLASS_MASS_SCSI 0x00 +#define PCI_SUB_CLASS_MASS_IDE 0x01 // class BRIDGE 0x06 #define PCI_SUB_CLASS_PCI_PCI_BRIDGE_4 0x04 diff --git a/include/myke/drivers/pci/virtio.h b/include/myke/drivers/pci/virtio.h new file mode 100644 index 0000000..6f76d2c --- /dev/null +++ b/include/myke/drivers/pci/virtio.h @@ -0,0 +1,18 @@ +// +// Created by rick on 14-5-22. +// + +#ifndef NEW_KERNEL_VIRTIO_H +#define NEW_KERNEL_VIRTIO_H + +#define PCI_VENDOR_VIRTIO 0x1af4 + +#define PCI_DEVICE_VIRTIO_NETWORK 0x1000 +#define PCI_DEVICE_VIRTIO_BLOCK 0x1001 +#define PCI_DEVICE_VIRTIO_BALLOON 0x1002 +#define PCI_DEVICE_VIRTIO_CONSOLE 0x1003 +#define PCI_DEVICE_VIRTIO_SCSI 0x1004 +#define PCI_DEVICE_VIRTIO_ENTROPY 0x1005 +#define PCI_DEVICE_VIRTIO_9P 0x1009 + +#endif //NEW_KERNEL_VIRTIO_H diff --git a/include/virtio_queue.h b/include/virtio_queue.h new file mode 100644 index 0000000..fbdf78f --- /dev/null +++ b/include/virtio_queue.h @@ -0,0 +1,103 @@ +#ifndef VIRTQUEUE_H +#define VIRTQUEUE_H +/* + * Virtual I/O Device (VIRTIO) Version 1.2 + * Committee Specification Draft 01 + * 09 May 2022 + * Copyright (c) OASIS Open 2022. All Rights Reserved. + * Source: http://docs.oasis-open.org/virtio/virtio/v1.2/csd01/listings/ + * Latest stage of narrative specification: http://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.html + * TC IPR Statement: https://github.com/oasis-tcs/virtio-admin/blob/master/IPR.md + */ + +/* + * An interface for efficient virtio implementation. + */ +#include + +/* This marks a buffer as continuing via the next field. */ +#define VIRTQ_DESC_F_NEXT 1 +/* This marks a buffer as write-only (otherwise read-only). */ +#define VIRTQ_DESC_F_WRITE 2 +/* This means the buffer contains a list of buffer descriptors. */ +#define VIRTQ_DESC_F_INDIRECT 4 + +/* The device uses this in used->flags to advise the driver: don't kick me + * when you add a buffer. It's unreliable, so it's simply an + * optimization. */ +#define VIRTQ_USED_F_NO_NOTIFY 1 +/* The driver uses this in avail->flags to advise the device: don't + * interrupt me when you consume a buffer. It's unreliable, so it's + * simply an optimization. */ +#define VIRTQ_AVAIL_F_NO_INTERRUPT 1 + +/* Support for indirect descriptors */ +#define VIRTIO_F_INDIRECT_DESC 28 + +/* Support for avail_event and used_event fields */ +#define VIRTIO_F_EVENT_IDX 29 + +/* Arbitrary descriptor layouts. */ +#define VIRTIO_F_ANY_LAYOUT 27 + +/* Virtqueue descriptors: 16 bytes. + * These can chain together via "next". */ +struct virtq_desc { + /* Address (guest-physical). */ + le64 addr; + /* Length. */ + le32 len; + /* The flags as indicated above. */ + le16 flags; + /* We chain unused descriptors via this, too */ + le16 next; +}; + +struct virtq_avail { + le16 flags; + le16 idx; + le16 ring[]; + /* Only if VIRTIO_F_EVENT_IDX: le16 used_event; */ +}; + +/* le32 is used here for ids for padding reasons. */ +struct virtq_used_elem { + /* Index of start of used descriptor chain. */ + le32 id; + /* Total length of the descriptor chain which was written to. */ + le32 len; +}; + +struct virtq_used { + le16 flags; + le16 idx; + struct virtq_used_elem ring[]; + /* Only if VIRTIO_F_EVENT_IDX: le16 avail_event; */ +}; + +struct virtq { + unsigned int num; + + struct virtq_desc *desc; + struct virtq_avail *avail; + struct virtq_used *used; +}; + +static inline int virtq_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx) +{ + return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old_idx); +} + +/* Get location of event indices (only with VIRTIO_F_EVENT_IDX) */ +static inline le16 *virtq_used_event(struct virtq *vq) +{ + /* For backwards compat, used event index is at *end* of avail ring. */ + return &vq->avail->ring[vq->num]; +} + +static inline le16 *virtq_avail_event(struct virtq *vq) +{ + /* For backwards compat, avail event index is at *end* of used ring. */ + return (le16 *)&vq->used->ring[vq->num]; +} +#endif /* VIRTQUEUE_H */ diff --git a/kernel/drivers/pci/ide.c b/kernel/drivers/pci/ide.c index c4dec7d..f00d3eb 100644 --- a/kernel/drivers/pci/ide.c +++ b/kernel/drivers/pci/ide.c @@ -421,7 +421,7 @@ void ide_register_block_devices() { uint8_t att_used ide_pci_validate(const pci_device *device) { if (device->class != PCI_CLASS_MASS_STORAGE - || device->subclass != PCI_SUB_CLASS_IDE + || device->subclass != PCI_SUB_CLASS_MASS_IDE || (device->programInterface != 0x8A && device->programInterface != 0x80)) { return PCI_VALIDATE_FAIL; } @@ -686,7 +686,7 @@ PCI_DRIVER(900) = { .validatable = true, .initialisable = true, .match.class = PCI_CLASS_MASS_STORAGE, - .match.subclass = PCI_SUB_CLASS_IDE, + .match.subclass = PCI_SUB_CLASS_MASS_IDE, .mask.class = true, .mask.subclass = true, .validate = ide_pci_validate, diff --git a/kernel/drivers/pci/virtio/virtio-lock.c b/kernel/drivers/pci/virtio/virtio-lock.c new file mode 100644 index 0000000..c0b8180 --- /dev/null +++ b/kernel/drivers/pci/virtio/virtio-lock.c @@ -0,0 +1,46 @@ +// +// Created by rick on 14-5-22. +// + +#include + +#include +#include + +uint8_t att_used virtio_pci_block_validate(const pci_device *pci_device) { + uint32_t capacity_l = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x14); + uint32_t capacity_h = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x18); + uint32_t segment_size_max = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x1c); + uint32_t segment_count_max = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x20); + uint16_t cylinder_count = pci_config_read_word(pci_device->bus, pci_device->slot, pci_device->func, 0x24); + uint8_t head_count = pci_config_read_byte(pci_device->bus, pci_device->slot, pci_device->func, 0x26); + uint8_t sector_count = pci_config_read_byte(pci_device->bus, pci_device->slot, pci_device->func, 0x27); + uint32_t block_length = pci_config_read_double_word(pci_device->bus, pci_device->slot, pci_device->func, 0x28); + + capacity_l = leu32_to_native(capacity_l); + capacity_h = leu32_to_native(capacity_h); + uint64_t capacity = ((uint64_t) capacity_h) >> 32 | capacity_l; + + return PCI_VALIDATE_FAIL; +} + +uint8_t att_used virtio_pci_block_initialize(pci_device *pci_device) { + return PCI_INIT_FAIL; +} + +PCI_DRIVER(900) = { + .name = "pci-virtio-block", + .description = "Para-virtualized Block Device", + .validatable = true, + .initialisable = true, + .match.class = PCI_CLASS_MASS_STORAGE, + .match.subclass = PCI_SUB_CLASS_MASS_SCSI, + .match.vendor = PCI_VENDOR_VIRTIO, + .match.device = PCI_DEVICE_VIRTIO_BLOCK, + .mask.class = true, + .mask.subclass = true, + .mask.vendor = true, + .mask.device = true, + .validate = virtio_pci_block_validate, + .initialize = virtio_pci_block_initialize, +}; \ No newline at end of file diff --git a/launch-qemu.sh b/launch-qemu.sh index f26d226..fac60cb 100755 --- a/launch-qemu.sh +++ b/launch-qemu.sh @@ -37,6 +37,10 @@ while [[ "$#" -gt 0 ]]; do ARGS="${ARGS} -drive id=disk1,file=$2,if=none -device ahci,id=ahci -device ide-drive,drive=disk1,bus=ahci.0" shift 2 ;; + --virtio) + ARGS="$ARGS -drive id=disk1,file=$2,if=virtio" + shift 2 + ;; -m | --max-cpu) ARGS="${ARGS} -cpu max" shift