cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mmap.rst (10791B)


      1.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
      2.. c:namespace:: V4L
      3
      4.. _mmap:
      5
      6******************************
      7Streaming I/O (Memory Mapping)
      8******************************
      9
     10Input and output devices support this I/O method when the
     11``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct
     12:c:type:`v4l2_capability` returned by the
     13:ref:`VIDIOC_QUERYCAP` ioctl is set. There are two
     14streaming methods, to determine if the memory mapping flavor is
     15supported applications must call the :ref:`VIDIOC_REQBUFS` ioctl
     16with the memory type set to ``V4L2_MEMORY_MMAP``.
     17
     18Streaming is an I/O method where only pointers to buffers are exchanged
     19between application and driver, the data itself is not copied. Memory
     20mapping is primarily intended to map buffers in device memory into the
     21application's address space. Device memory can be for example the video
     22memory on a graphics card with a video capture add-on. However, being
     23the most efficient I/O method available for a long time, many other
     24drivers support streaming as well, allocating buffers in DMA-able main
     25memory.
     26
     27A driver can support many sets of buffers. Each set is identified by a
     28unique buffer type value. The sets are independent and each set can hold
     29a different type of data. To access different sets at the same time
     30different file descriptors must be used. [#f1]_
     31
     32To allocate device buffers applications call the
     33:ref:`VIDIOC_REQBUFS` ioctl with the desired number
     34of buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.
     35This ioctl can also be used to change the number of buffers or to free
     36the allocated memory, provided none of the buffers are still mapped.
     37
     38Before applications can access the buffers they must map them into their
     39address space with the :c:func:`mmap()` function. The
     40location of the buffers in device memory can be determined with the
     41:ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar
     42API case, the ``m.offset`` and ``length`` returned in a struct
     43:c:type:`v4l2_buffer` are passed as sixth and second
     44parameter to the :c:func:`mmap()` function. When using the
     45multi-planar API, struct :c:type:`v4l2_buffer` contains an
     46array of struct :c:type:`v4l2_plane` structures, each
     47containing its own ``m.offset`` and ``length``. When using the
     48multi-planar API, every plane of every buffer has to be mapped
     49separately, so the number of calls to :c:func:`mmap()` should
     50be equal to number of buffers times number of planes in each buffer. The
     51offset and length values must not be modified. Remember, the buffers are
     52allocated in physical memory, as opposed to virtual memory, which can be
     53swapped out to disk. Applications should free the buffers as soon as
     54possible with the :c:func:`munmap()` function.
     55
     56Example: Mapping buffers in the single-planar API
     57=================================================
     58
     59.. code-block:: c
     60
     61    struct v4l2_requestbuffers reqbuf;
     62    struct {
     63	void *start;
     64	size_t length;
     65    } *buffers;
     66    unsigned int i;
     67
     68    memset(&reqbuf, 0, sizeof(reqbuf));
     69    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     70    reqbuf.memory = V4L2_MEMORY_MMAP;
     71    reqbuf.count = 20;
     72
     73    if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
     74	if (errno == EINVAL)
     75	    printf("Video capturing or mmap-streaming is not supported\\n");
     76	else
     77	    perror("VIDIOC_REQBUFS");
     78
     79	exit(EXIT_FAILURE);
     80    }
     81
     82    /* We want at least five buffers. */
     83
     84    if (reqbuf.count < 5) {
     85	/* You may need to free the buffers here. */
     86	printf("Not enough buffer memory\\n");
     87	exit(EXIT_FAILURE);
     88    }
     89
     90    buffers = calloc(reqbuf.count, sizeof(*buffers));
     91    assert(buffers != NULL);
     92
     93    for (i = 0; i < reqbuf.count; i++) {
     94	struct v4l2_buffer buffer;
     95
     96	memset(&buffer, 0, sizeof(buffer));
     97	buffer.type = reqbuf.type;
     98	buffer.memory = V4L2_MEMORY_MMAP;
     99	buffer.index = i;
    100
    101	if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
    102	    perror("VIDIOC_QUERYBUF");
    103	    exit(EXIT_FAILURE);
    104	}
    105
    106	buffers[i].length = buffer.length; /* remember for munmap() */
    107
    108	buffers[i].start = mmap(NULL, buffer.length,
    109		    PROT_READ | PROT_WRITE, /* recommended */
    110		    MAP_SHARED,             /* recommended */
    111		    fd, buffer.m.offset);
    112
    113	if (MAP_FAILED == buffers[i].start) {
    114	    /* If you do not exit here you should unmap() and free()
    115	       the buffers mapped so far. */
    116	    perror("mmap");
    117	    exit(EXIT_FAILURE);
    118	}
    119    }
    120
    121    /* Cleanup. */
    122
    123    for (i = 0; i < reqbuf.count; i++)
    124	munmap(buffers[i].start, buffers[i].length);
    125
    126Example: Mapping buffers in the multi-planar API
    127================================================
    128
    129.. code-block:: c
    130
    131    struct v4l2_requestbuffers reqbuf;
    132    /* Our current format uses 3 planes per buffer */
    133    #define FMT_NUM_PLANES = 3
    134
    135    struct {
    136	void *start[FMT_NUM_PLANES];
    137	size_t length[FMT_NUM_PLANES];
    138    } *buffers;
    139    unsigned int i, j;
    140
    141    memset(&reqbuf, 0, sizeof(reqbuf));
    142    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    143    reqbuf.memory = V4L2_MEMORY_MMAP;
    144    reqbuf.count = 20;
    145
    146    if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
    147	if (errno == EINVAL)
    148	    printf("Video capturing or mmap-streaming is not supported\\n");
    149	else
    150	    perror("VIDIOC_REQBUFS");
    151
    152	exit(EXIT_FAILURE);
    153    }
    154
    155    /* We want at least five buffers. */
    156
    157    if (reqbuf.count < 5) {
    158	/* You may need to free the buffers here. */
    159	printf("Not enough buffer memory\\n");
    160	exit(EXIT_FAILURE);
    161    }
    162
    163    buffers = calloc(reqbuf.count, sizeof(*buffers));
    164    assert(buffers != NULL);
    165
    166    for (i = 0; i < reqbuf.count; i++) {
    167	struct v4l2_buffer buffer;
    168	struct v4l2_plane planes[FMT_NUM_PLANES];
    169
    170	memset(&buffer, 0, sizeof(buffer));
    171	buffer.type = reqbuf.type;
    172	buffer.memory = V4L2_MEMORY_MMAP;
    173	buffer.index = i;
    174	/* length in struct v4l2_buffer in multi-planar API stores the size
    175	 * of planes array. */
    176	buffer.length = FMT_NUM_PLANES;
    177	buffer.m.planes = planes;
    178
    179	if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) {
    180	    perror("VIDIOC_QUERYBUF");
    181	    exit(EXIT_FAILURE);
    182	}
    183
    184	/* Every plane has to be mapped separately */
    185	for (j = 0; j < FMT_NUM_PLANES; j++) {
    186	    buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
    187
    188	    buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
    189		     PROT_READ | PROT_WRITE, /* recommended */
    190		     MAP_SHARED,             /* recommended */
    191		     fd, buffer.m.planes[j].m.offset);
    192
    193	    if (MAP_FAILED == buffers[i].start[j]) {
    194		/* If you do not exit here you should unmap() and free()
    195		   the buffers and planes mapped so far. */
    196		perror("mmap");
    197		exit(EXIT_FAILURE);
    198	    }
    199	}
    200    }
    201
    202    /* Cleanup. */
    203
    204    for (i = 0; i < reqbuf.count; i++)
    205	for (j = 0; j < FMT_NUM_PLANES; j++)
    206	    munmap(buffers[i].start[j], buffers[i].length[j]);
    207
    208Conceptually streaming drivers maintain two buffer queues, an incoming
    209and an outgoing queue. They separate the synchronous capture or output
    210operation locked to a video clock from the application which is subject
    211to random disk or network delays and preemption by other processes,
    212thereby reducing the probability of data loss. The queues are organized
    213as FIFOs, buffers will be output in the order enqueued in the incoming
    214FIFO, and were captured in the order dequeued from the outgoing FIFO.
    215
    216The driver may require a minimum number of buffers enqueued at all times
    217to function, apart of this no limit exists on the number of buffers
    218applications can enqueue in advance, or dequeue and process. They can
    219also enqueue in a different order than buffers have been dequeued, and
    220the driver can *fill* enqueued *empty* buffers in any order.  [#f2]_ The
    221index number of a buffer (struct :c:type:`v4l2_buffer`
    222``index``) plays no role here, it only identifies the buffer.
    223
    224Initially all mapped buffers are in dequeued state, inaccessible by the
    225driver. For capturing applications it is customary to first enqueue all
    226mapped buffers, then to start capturing and enter the read loop. Here
    227the application waits until a filled buffer can be dequeued, and
    228re-enqueues the buffer when the data is no longer needed. Output
    229applications fill and enqueue buffers, when enough buffers are stacked
    230up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.
    231In the write loop, when the application runs out of free buffers, it
    232must wait until an empty buffer can be dequeued and reused.
    233
    234To enqueue and dequeue a buffer applications use the
    235:ref:`VIVIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
    236ioctl. The status of a buffer being mapped, enqueued, full or empty can
    237be determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two
    238methods exist to suspend execution of the application until one or more
    239buffers can be dequeued.  By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
    240blocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``
    241flag was given to the :c:func:`open()` function,
    242:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
    243error code when no buffer is available. The :c:func:`select()`
    244or :c:func:`poll()` functions are always available.
    245
    246To start and stop capturing or output applications call the
    247:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF
    248<VIDIOC_STREAMON>` ioctl.
    249
    250.. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`
    251   removes all buffers from both queues as a side effect. Since there is
    252   no notion of doing anything "now" on a multitasking system, if an
    253   application needs to synchronize with another event it should examine
    254   the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured
    255   or outputted buffers.
    256
    257Drivers implementing memory mapping I/O must support the
    258:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF
    259<VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF
    260<VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
    261and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()
    262<func-mmap>`, :c:func:`munmap()`, :ref:`select()
    263<func-select>` and :c:func:`poll()` function. [#f3]_
    264
    265[capture example]
    266
    267.. [#f1]
    268   One could use one file descriptor and set the buffer type field
    269   accordingly when calling :ref:`VIDIOC_QBUF` etc.,
    270   but it makes the :c:func:`select()` function ambiguous. We also
    271   like the clean approach of one file descriptor per logical stream.
    272   Video overlay for example is also a logical stream, although the CPU
    273   is not needed for continuous operation.
    274
    275.. [#f2]
    276   Random enqueue order permits applications processing images out of
    277   order (such as video codecs) to return buffers earlier, reducing the
    278   probability of data loss. Random fill order allows drivers to reuse
    279   buffers on a LIFO-basis, taking advantage of caches holding
    280   scatter-gather lists and the like.
    281
    282.. [#f3]
    283   At the driver level :c:func:`select()` and :c:func:`poll()` are
    284   the same, and :c:func:`select()` is too important to be optional.
    285   The rest should be evident.