qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] virtio documentation or BSD licensed driver?


From: higepon
Subject: Re: [Qemu-devel] virtio documentation or BSD licensed driver?
Date: Sun, 10 May 2009 23:08:59 +0900

Hi.

With your kind advice,
finally I succeeded in writing to virtio-console on QEMU from my OS.

But there are a few things I don't understand about vring_avail struct.
On Rusty Russell's article "virtio: Towards a De-Facto Standard For
Virtual I/O Devices".

He explained like following.

struct vring_avail
{
__u16 flags;
__u16 idx;
__u16 ring[NUM];
};

> The available ring consists of a free-running index, an interrupt
> suppression flag, and an array of indices into the
> descriptor table (representing the heads of buffers).

(1) What does it mean "free-running index"?
    And what value guest should set to idx? The index of head of
available descriptor?

(2) What value guest should set to ring[NUM].

I've Googled these things, but there are few documents about them.

Here is my whole code.
If I did something wrong, I appreciate your pointing me out.

int main(int argc, char* argv[])
{
    // 1. Device probe
    PciInf pciInf;
    Pci pci;
    pci.CheckPciExist(PCI_VENDOR_ID_REDHAT_QUMRANET,
PCI_DEVICE_ID_VIRTIO_CONSOLE, &pciInf);

    if (!pciInf.isExist) {
        printf("device not found\n");
        exit(-1);
    }

    printf("device found\n");
    printf("baseAdress=%x\n", pciInf.baseAdress);
    printf("irqLine=%x\n", pciInf.irqLine);

    const uintptr_t baseAddress = pciInf.baseAdress & ~1;

    // 2. reset the device
    outp8(baseAddress + VIRTIO_PCI_STATUS, 0); // 0: reset
    printf("[virtio] isr=%x\n", inp8(baseAddress + VIRTIO_PCI_ISR));
// clear ISR.

    // 3. IRQ receiver
    monapi_set_irq(pciInf.irqLine, MONAPI_TRUE, MONAPI_TRUE);
    syscall_set_irq_receiver(pciInf.irqLine, SYS_MASK_INTERRUPT);

    // 4. Select the queue to use
    outp16(baseAddress + VIRTIO_PCI_QUEUE_SEL, 1); // 0: read queue,
1: write queue

    // 5. how many descriptors do the queue have?
    const int numberOfDesc = inp16(baseAddress + VIRTIO_PCI_QUEUE_NUM);
    printf("[virtio] numberOfDesc=%d\n", numberOfDesc);
    ASSERT(numberOfDesc > 0);

    // 6. Check wheter the queue is already set vring (necessary?).
    uint16_t pfn = inp16(baseAddress + VIRTIO_PCI_QUEUE_PFN);
    if (pfn != 0) {
        printf("[virtio] pfn=%x\n", pfn);
        exit(-1);
    }

    // 7. setup vring
    const int MAX_QUEUE_SIZE = PAGE_MASK + vring_size(MAX_QUEUE_NUM);
    printf("[virtio] MAX_QUEUE_SIZE=%d\n", MAX_QUEUE_SIZE);
    uint8_t queueData[MAX_QUEUE_SIZE];
    memset(queueData, 0, MAX_QUEUE_SIZE);

    struct vring vring;
    vring.num = numberOfDesc;

    // page align is required
    const uintptr_t physicalAddress =
syscall_get_physical_address((uintptr_t)queueData, NULL);
    printf("[virtio] physicalAddress=%x\n", physicalAddress);
    const uintptr_t alignedAddress = (physicalAddress + PAGE_MASK) & ~PAGE_MASK;
    printf("[virtio] alignedAddress=%x\n", alignedAddress);

    ASSERT((alignedAddress % PAGE_SIZE) == 0);

    // vring.desc is page aligned
    vring.desc = (struct vring_desc*)(queueData + alignedAddress -
physicalAddress);

    // make linked ring
    for (uintptr_t i = 0; i < vring.num; i++) {
        vring.desc[i].next = i + 1;
    }
    vring.desc[vring.num - 1].next = 0;

    // vring.avail is follow after the array of desc
    vring.avail = (struct vring_avail *)&vring.desc[numberOfDesc];

    // vring.used is also page aligned
    const uintptr_t usedPhysicalAddress =
syscall_get_physical_address((uintptr_t)&(vring.avail->ring[numberOfDesc]),
NULL);
    const uintptr_t usedAligendAddress = (usedPhysicalAddress +
PAGE_MASK) & ~PAGE_MASK;
    ASSERT((usedAligendAddress % PAGE_SIZE) == 0);
    vring.used = (struct
vring_used*)((uintptr_t)&(vring.avail->ring[numberOfDesc]) +
usedAligendAddress - usedPhysicalAddress);

    // 9. set up pfn
    printf("[virtio] set up PFN\n");
    outp32(baseAddress + VIRTIO_PCI_QUEUE_PFN,
syscall_get_physical_address((uintptr_t)vring.desc, NULL) >> 12);

    // 10. prepare the data to write
    uint8_t data[PAGE_SIZE * 2];
    const uintptr_t phys = syscall_get_physical_address((uintptr_t)data, NULL);
    const uintptr_t aphys = (phys+ PAGE_MASK) & ~PAGE_MASK;
    char* p = (char*) (data + aphys - phys);
    strcpy(p, "Hello, World");

    // 11. set the data to vring
    vring.desc[0].flags = 0; // no next
    vring.desc[0].addr = syscall_get_physical_address((uintptr_t)p, NULL);
    vring.desc[0].len = strlen(p) + 1;
    vring.avail->idx = 1; // ??????

    // 12. Notify!
    printf("[virtio] vring.used->idx = %d \n", vring.used->idx);
    outp16(baseAddress + VIRTIO_PCI_QUEUE_NOTIFY, 1);

    // 13. wait notification from host
    MessageInfo msg;
    Message::receive(&msg);

    switch (msg.header)
    {
    case MSG_INTERRUPTED:
    {
        printf("[virtio] Interrupt comes\n");
        // clear ISR.
        const uint8_t isr = inp8(baseAddress + VIRTIO_PCI_ISR);
        printf("[virtio] isr=%x\n", isr);
        monapi_set_irq(pciInf.irqLine, MONAPI_TRUE, MONAPI_TRUE);
        break;
    }
    default:
        printf("[virtio] uknown message\n");
        break;
    }

    // if data is written, idx 0 => 1
    printf("[virtio] vring.used->idx = %d \n", vring.used->idx);
}

Cheers.


On Mon, May 4, 2009 at 7:36 PM, higepon <address@hidden> wrote:
> Hi.
>
> I really appreciate your help. Thanks.
> That's what I want to know about.
>
>> 2) Think of virtio-net as just another (sophisticated) PCI driver and
>> look at its implemenation
>> in qemu. Although qemu is not BSD licensed, your work is unlikely to
>> be considered a derivative
>> of qemu since you are implementing a driver for that virtual
>> "hardware", not another copy it.
>
> Maybe this is suitable for my OS.
>
>> The BSD virtio headers, the paper and the virtio-net qemu
>> implementation should be enough to
>> allow you to write a driver for your OS imho (it is already more info
>> than you typically get for
>> real hardware)
>
> Okay I will start from reading the paper.
>
>> P.S., in practice I believe several developers for other OSes look at
>> the sources of linux drivers
>> as sort of a really good documentation for hardware, even if the
>> license of their OS is incompatible.
>> IANAL and all that, but I 'd be really suprised if you got sued for
>> porting virtio-net to your hobby OS :)
>
> Interesting and resonable.
> But Since Mona OS is my life work, i want to avoid from license problems.
>
>
> Cheers.
>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]