qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: higepon <higepon@gmail.com>
To: Pantelis Koukousoulas <pktoss@gmail.com>
Cc: Brian Jackson <iggy@theiggy.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] virtio documentation or BSD licensed driver?
Date: Sun, 10 May 2009 23:08:59 +0900	[thread overview]
Message-ID: <f07386410905100708r365478a9oe136223096bbced6@mail.gmail.com> (raw)
In-Reply-To: <f07386410905040336m77f93966j8d545f6f06189a93@mail.gmail.com>

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 <higepon@gmail.com> 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	other threads:[~2009-05-10 14:09 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-04  4:05 [Qemu-devel] virtio documentation or BSD licensed driver? higepon
2009-05-04  4:21 ` Brian Jackson
2009-05-04  6:07   ` higepon
2009-05-04  9:23     ` Pantelis Koukousoulas
2009-05-04 10:36       ` higepon
2009-05-10 14:08         ` higepon [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f07386410905100708r365478a9oe136223096bbced6@mail.gmail.com \
    --to=higepon@gmail.com \
    --cc=iggy@theiggy.com \
    --cc=pktoss@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).