From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1M39iB-0007Eg-Cz for qemu-devel@nongnu.org; Sun, 10 May 2009 10:09:03 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1M39i9-0007EU-Ub for qemu-devel@nongnu.org; Sun, 10 May 2009 10:09:02 -0400 Received: from [199.232.76.173] (port=40698 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1M39i9-0007EP-PA for qemu-devel@nongnu.org; Sun, 10 May 2009 10:09:01 -0400 Received: from qw-out-1920.google.com ([74.125.92.149]:42766) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1M39i9-0002Mt-BC for qemu-devel@nongnu.org; Sun, 10 May 2009 10:09:01 -0400 Received: by qw-out-1920.google.com with SMTP id 4so1246709qwk.4 for ; Sun, 10 May 2009 07:09:00 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: References: <5C92D599-FCA8-4C38-8863-20544C1AB520@theiggy.com> <1295ed070905040223m3e4f08cq259c4ab696b7ef44@mail.gmail.com> Date: Sun, 10 May 2009 23:08:59 +0900 Message-ID: Subject: Re: [Qemu-devel] virtio documentation or BSD licensed driver? From: higepon Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Pantelis Koukousoulas Cc: Brian Jackson , qemu-devel@nongnu.org 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 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. >