UIO и msyn c: почему msyn c возвращает «неверный аргумент», даже если адрес кратен PAGESIZE - PullRequest
0 голосов
/ 12 февраля 2020

Linux версия: 4.19
Платформа: Xilinx Ultrascale + Zynq

В программируемой логике c я создал устройство с отображением памяти, расположенное по физическому адресу 0xA0001000. Я использую uio_pdrv_genirq в качестве драйвера устройства. Устройство отображается как uio0, и я готов читать и писать на него, используя mmap. Я хочу быть в состоянии гарантировать, что любые записи, которые я произвожу, будут записаны на устройство сразу, вместо того, чтобы ждать, пока Linux покажет sh грязные страницы. Для этого я должен использовать msyn c согласно всем моим исследованиям. Но я продолжаю получать ошибку, когда я делаю это. Вот моя тестовая программа:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

void main() {
    int fid;
    int rval;
    char *data;
    int idx;

    printf("Open UIO Device \n");
    fid= open("/dev/uio0", O_RDWR | O_SYNC);

    data= mmap(NULL, 0x1000, PROT_WRITE|PROT_READ, MAP_SHARED, fid, 0);
    if(MAP_FAILED == data) {
        printf("Error code when mapping! %s", strerror(errno));
    }
    printf("addr= 0x%8X\n", data);
    printf("pagesize= 0x%4X\n", getpagesize());

    printf("Write some data\n");
    data[11]= 0xDE;
    data[10]= 0xC0;
    data[ 9]= 0xDE;
    data[ 8]= 0xAD;

    rval= msync(data, 0x1000, MS_SYNC);
    if(-1 == rval) {
        printf("Error on msync! %s\n", strerror(errno));
    }

    if(munmap(data, 0x1000) < 0) {
        printf("munmap error! %s\n", strerror(errno));
    }

    printf("Close UIO device\n");
    rval= close(fid);
    if(rval != 0) {
        printf("UIO device close Error!\n");
    }
}

А вот и вывод программы:

mylinux:~/test-apps$ ./a.out
Open UIO Device
addr= 0xABA05000
pagesize= 0x1000
Write some data
Error on msync! Invalid argument
Close UIO device

Я не понимаю источник этой ошибки. Справочные страницы msyn c утверждают, что эта ошибка может возникнуть, если адрес не кратен PAGESIZE. Но, как видно из приведенного выше примера, это кратное число. Даже физический адрес кратен PAGESIZE.

Несколько других примечаний:

  1. Я получаю ту же ошибку, даже если удаляю O_SYN C из флагов функции open ,
  2. Шина AXI4 в FPGA fabri c составляет 128 бит, которая затем преобразуется в 32 бита IP-блоками Xilinx. Я не думаю, что это как-то связано с моей проблемой.

Спасибо за любые идеи, которые могут дать люди.

1 Ответ

0 голосов
/ 12 февраля 2020

Я считаю, что ошибка EINVAL связана с тем, что обработчик ядра для системного вызова msync (в " мм / мсин c. c") вызывает vfs_fsync_range:

            error = vfs_fsync_range(file, fstart, fend, 1);

и vfs_fsync_range (в " fs / syn c. c") возвращает -EINVAL здесь:

    if (!file->f_op->fsync)
        return -EINVAL;

, потому что UIO ядро драйвера (в « drivers / uio / uio. c» не устанавливается обработчик операций с файлами fsync.


Физическая память, имеющаяся у вас mmap ed отображается как не кешируемая память в таблицах страниц, поэтому записи не нужно сбрасывать. Однако вы, вероятно, должны использовать volatile доступы к отображенным в память регистрам ввода-вывода. Функции доступа к регистрам, такие как readb и writeb в ядре задают архитектуру c, но неизменно преобразуют адрес в указатель в целочисленный тип volatile (например, volatile unsigned char *, volatile unsigned short * или volatile unsigned int * в зависимости от ширины регистра доступ) до доступа к ячейке памяти.

...