2017-05-15 1 views
1

Ich teste den Virtio-Treiber für die Kommunikation von einer Gastmaschine an den Host-Rechner in Qemu. Für den Moment möchte ich nur einen einzelnen Puffer senden.Leere Puffer während von Host zu Gast mit virtueue mit Virtio Gerät/Treiber

Mein Problem ist, dass das Gerät einen leeren Puffer erhält, wenn der Rückruf der virtuellen Warteschlange aufgerufen wird.

Die seltsame Sache ist, dass die Länge des Puffers, der im Gerät empfangen wird, sich ändert, wenn sich die Länge des vom Treiber gesendeten Puffers ändert.

In meinem Fahrer:

static int virt_test_probe(struct virtio_device *vdev) 
{ 
    struct virt_test_info *vi; 
    int retvalue = 0; 
    struct scatterlist sg[1]; 
    char *str = vmalloc(1000*sizeof(char)); 
    int err; 
    memset(str, 121, 1000*sizeof(char)); 
    vi = kzalloc(sizeof(struct virt_test_info), GFP_KERNEL); 
    if (!vi) 
     return -ENOMEM; 

    printk(KERN_ERR "TEST VIRTIO LINUX: %s. Value of str: %s\n", __FUNCTION__, str); 

    vi->vq = virtio_find_single_vq(vdev, protector_recv_done, "input"); 
    if (IS_ERR(vi->vq)) { 
     retvalue = PTR_ERR(vi->vq); 
     goto err_free; 
    } 

    vdev->priv = vi; 
    virtio_device_ready(vdev); 
    sg_init_one(sg, str, 1000*sizeof(char));  
    err = virtqueue_add_outbuf(vi->vq, sg, 1, str, GFP_ATOMIC); 
    virtqueue_kick(vi->vq); 

    return 0; 

err_free: 
    kfree(vi); 
    return retvalue; 
} 

Und in meinem QEMU-Gerät:

static void handle_output(VirtIODevice *vdev, VirtQueue *vq) 
{ 
    //VirtIOTEST *vtest = VIRTIO_TEST(vdev); 
    char *buf = malloc(1000*sizeof(char)); 
    VirtQueueElement *elem; 
    int len; 
    printf("TEST VIRTIO: %s\n", __FUNCTION__); 

    for(;;) { 
     elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 
     if (elem) 
      break; 
    } 
    memset(buf,122, 1000*sizeof(char)); // I nitialised the buffer with y char 

    len = iov_to_buf(elem->out_sg, elem->out_num, 0, buf, 1000*sizeof(char)); 

    printf("TEST VIRTIO: %s: content %s, len:%i\n", __FUNCTION__, buf, len); //the value length here changes with the the length of the driver's buffer 
    for(len=0; len<10; len++) { 
     printf("%02x",buf[len]); // here we're printing 0s 
    } 
} 

ich einen arm64 Linux bin mit. Der Wert des Puffers scheint durch den Aufruf von qemu konsistent zu sein. Ich denke, das Problem kommt vom Linux-Kernel oder etwas anderem. Ich habe überprüft, dass die Scatterliste in Ordnung ist, was ich sagen kann, und ich bekomme von add_output_buf keinen Fehler.

Antwort

1

Ich habe gerade herausgefunden, warum es nicht funktionieren würde: Verwenden kmalloc statt vmalloc den Puffer zuzuweisen, sg_init_one zu übergeben. Hier ist warum:

Die Scatterlist speichert den Puffer als eine Seite. So muss es den Puffer in eine Seite mit page_to_virt, die im Grunde eine Verschiebung auf die virtuelle Adresse wendet, um die physikalische Adresse der Seite zu erhalten.

Jetzt wird vmalloc Speicher in einem zusammenhängenden physischen Adressraum nicht zugeordnet, wie kmalloc tut. So ändert es die Seitentabellen, um nicht zusammenhängende physische Adressen auf zusammenhängenden virtuellen Adressen abzubilden. Daher scheint die Funktion page_to_virt nicht mit vmalloc zu funktionieren, da mehr als das Anwenden eines Offsets erforderlich ist, um in den physischen Adressraum zu gelangen.

Verwandte Themen