2017-05-15 14 views
1

Qemu에서 게스트 시스템에서 호스트 시스템으로 통신하기 위해 virtio 드라이버를 테스트하고 있습니다. 지금은 하나의 버퍼 만 보내고 싶습니다.virtio 장치/드라이버와 함께 virtqueue를 사용하여 호스트에서 게스트로가는 동안 빈 버퍼

제 문제는 가상 대기열과 관련된 콜백이 호출 될 때 장치가 빈 버퍼를 수신한다는 것입니다.

이상한 점은 드라이버에서 보낸 버퍼의 길이가 변경되면 장치에서 수신 된 버퍼의 길이가 변경된다는 것입니다. 내 드라이버에서

:

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; 
} 

그리고 내 QEMU 장치에서 : 내가 arm64 리눅스를 사용하고

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 
    } 
} 

. 버퍼의 값은 qemu의 호출을 통해 일관성이있는 것처럼 보입니다. 그래서 문제는 리눅스 커널이나 다른 것에서 오는 것 같습니다. 나는 scatterlist가 내가 알 수있는 것에서 ok로 갔다. 그리고 add_output_buf에서 어떤 에러도받지 못했다.

답변

1

난 그냥 작동하지 않을 이유를 발견 : 사용 kmalloc 대신 vmallocsg_init_one에 전달하기 위해 버퍼를 할당 할 수 있습니다. 이유는 다음과 같습니다.

scatterlist는 버퍼를 페이지로 저장합니다. 따라서 버퍼를 page_to_virt을 사용하여 페이지로 변환해야합니다. 기본적으로 가상 주소에 오프셋을 적용하여 페이지의 실제 주소를 가져옵니다.

이제 vmallockmalloc과 같이 인접한 실제 주소 공간에서 메모리를 매핑하지 않습니다. 따라서 페이지 테이블을 변경하여 인접하지 않은 실제 주소를 인접한 가상 주소에 매핑합니다. 따라서 page_to_virt 함수는 vmalloc과 함께 작동하지 않는 것처럼 보이므로 실제 주소 공간에 들어가기 위해 오프셋을 적용하는 것 이상을 필요로합니다.