mirror of https://gitee.com/openkylin/linux.git
media fixes for v4.9-rc4
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJYGZuzAAoJEAhfPr2O5OEVEakQAJKu+4OwrzoWajdIibR9IVpP 1gbwqAeTDp4XuHC4WyA8U3no3I5RG+moo4GNv87LNZ/H2ix1EGQn6IwbpYG0YmOB wdcZ2WViLc4tEYN/Rn7slwjY32dNplra6xNNSb0JHOT5tp6YOCLljqApd9FBvP25 Yo10z0pRL78ce6VbXyDB5JuqUsjtHivzU45/O5M5giDFIngdqFuu0zneQeMbvulF rCz6HSqNutFaeRMdnbP6f2Vtmd2QjeCY4aYg5kQLqWiuXsdMplp9uJkeYaDgccDp TF9z33cJlmyPXY6/YH95yfca156EZIVco3yLnNp9Ehmr4S12NV0D3xMKCXPyucEJ A6FH60zqxe3qUv7sPi6w4MM7ufgq3F/i33lhhDLsNjw0R8m7ijohfIj7HI84XC+z Jjr44A/7p4hqbfvkBePyLHcqaglWnc0E6LnS7lUgJC4/h7z3H2DMoPaUwkjedAI6 ynd5Ikfw+VvI0UQFyVBBWfH+ol+6BP7QO3TmHES9zfbPNMfhXc3ON4sk9yBzY50S cH6/TagQVmuk4zA457oAU+rrYR4g+di97Wk3AMi+gKGWu2qZmHE4Tv0gQsNHoPrK 06VD1Ur04khRR3tOQ/OqDMGNyLHbCMIMXeUYc363uZ6wrcmVF5caDZ3oy3i1LNNO ZALCj0FYwNFmDs7+Ckmq =MRLH -----END PGP SIGNATURE----- Merge tag 'media/v4.9-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media into synaptics-rmi4 Sync up with media tree to bring up latest Synaptics and Atmel changes.
This commit is contained in:
commit
d27625c9d5
|
@ -396,9 +396,13 @@ locations and some common work such as cleanup has to be done. If there is no
|
|||
cleanup needed then just return directly.
|
||||
|
||||
Choose label names which say what the goto does or why the goto exists. An
|
||||
example of a good name could be "out_buffer:" if the goto frees "buffer". Avoid
|
||||
using GW-BASIC names like "err1:" and "err2:". Also don't name them after the
|
||||
goto location like "err_kmalloc_failed:"
|
||||
example of a good name could be "out_free_buffer:" if the goto frees "buffer".
|
||||
Avoid using GW-BASIC names like "err1:" and "err2:", as you would have to
|
||||
renumber them if you ever add or remove exit paths, and they make correctness
|
||||
difficult to verify anyway.
|
||||
|
||||
It is advised to indent labels with a single space (not tab), so that
|
||||
"diff -p" does not confuse labels with functions.
|
||||
|
||||
The rationale for using gotos is:
|
||||
|
||||
|
@ -425,20 +429,29 @@ The rationale for using gotos is:
|
|||
goto out_buffer;
|
||||
}
|
||||
...
|
||||
out_buffer:
|
||||
out_free_buffer:
|
||||
kfree(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
A common type of bug to be aware of is "one err bugs" which look like this:
|
||||
|
||||
err:
|
||||
err:
|
||||
kfree(foo->bar);
|
||||
kfree(foo);
|
||||
return ret;
|
||||
|
||||
The bug in this code is that on some exit paths "foo" is NULL. Normally the
|
||||
fix for this is to split it up into two error labels "err_bar:" and "err_foo:".
|
||||
fix for this is to split it up into two error labels "err_free_bar:" and
|
||||
"err_free_foo:":
|
||||
|
||||
err_free_bar:
|
||||
kfree(foo->bar);
|
||||
err_free_foo:
|
||||
kfree(foo);
|
||||
return ret;
|
||||
|
||||
Ideally you should simulate errors to test all exit paths.
|
||||
|
||||
|
||||
Chapter 8: Commenting
|
||||
|
@ -461,9 +474,6 @@ When commenting the kernel API functions, please use the kernel-doc format.
|
|||
See the files Documentation/kernel-documentation.rst and scripts/kernel-doc
|
||||
for details.
|
||||
|
||||
Linux style for comments is the C89 "/* ... */" style.
|
||||
Don't use C99-style "// ..." comments.
|
||||
|
||||
The preferred style for long (multi-line) comments is:
|
||||
|
||||
/*
|
||||
|
|
|
@ -931,10 +931,8 @@ to "Closing".
|
|||
|
||||
1) Struct scatterlist requirements.
|
||||
|
||||
Don't invent the architecture specific struct scatterlist; just use
|
||||
<asm-generic/scatterlist.h>. You need to enable
|
||||
CONFIG_NEED_SG_DMA_LENGTH if the architecture supports IOMMUs
|
||||
(including software IOMMU).
|
||||
You need to enable CONFIG_NEED_SG_DMA_LENGTH if the architecture
|
||||
supports IOMMUs (including software IOMMU).
|
||||
|
||||
2) ARCH_DMA_MINALIGN
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# To add a new book the only step required is to add the book to the
|
||||
# list of DOCBOOKS.
|
||||
|
||||
DOCBOOKS := z8530book.xml device-drivers.xml \
|
||||
DOCBOOKS := z8530book.xml \
|
||||
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
|
||||
writing_usb_driver.xml networking.xml \
|
||||
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
|
||||
|
@ -22,8 +22,14 @@ ifeq ($(DOCBOOKS),)
|
|||
# Skip DocBook build if the user explicitly requested no DOCBOOKS.
|
||||
.DEFAULT:
|
||||
@echo " SKIP DocBook $@ target (DOCBOOKS=\"\" specified)."
|
||||
|
||||
else
|
||||
ifneq ($(SPHINXDIRS),)
|
||||
|
||||
# Skip DocBook build if the user explicitly requested a sphinx dir
|
||||
.DEFAULT:
|
||||
@echo " SKIP DocBook $@ target (SPHINXDIRS specified)."
|
||||
else
|
||||
|
||||
|
||||
###
|
||||
# The build process is as follows (targets):
|
||||
|
@ -66,6 +72,7 @@ installmandocs: mandocs
|
|||
|
||||
# no-op for the DocBook toolchain
|
||||
epubdocs:
|
||||
latexdocs:
|
||||
|
||||
###
|
||||
#External programs used
|
||||
|
@ -221,6 +228,7 @@ silent_gen_xml = :
|
|||
echo "</programlisting>") > $@
|
||||
|
||||
endif # DOCBOOKS=""
|
||||
endif # SPHINDIR=...
|
||||
|
||||
###
|
||||
# Help targets as used by the top-level makefile
|
||||
|
|
|
@ -1,521 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
||||
|
||||
<book id="LinuxDriversAPI">
|
||||
<bookinfo>
|
||||
<title>Linux Device Drivers</title>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
This documentation is free software; you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This program is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
MA 02111-1307 USA
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For more details see the file COPYING in the source
|
||||
distribution of Linux.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc></toc>
|
||||
|
||||
<chapter id="Basics">
|
||||
<title>Driver Basics</title>
|
||||
<sect1><title>Driver Entry and Exit points</title>
|
||||
!Iinclude/linux/init.h
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Atomic and pointer manipulation</title>
|
||||
!Iarch/x86/include/asm/atomic.h
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Delaying, scheduling, and timer routines</title>
|
||||
!Iinclude/linux/sched.h
|
||||
!Ekernel/sched/core.c
|
||||
!Ikernel/sched/cpupri.c
|
||||
!Ikernel/sched/fair.c
|
||||
!Iinclude/linux/completion.h
|
||||
!Ekernel/time/timer.c
|
||||
</sect1>
|
||||
<sect1><title>Wait queues and Wake events</title>
|
||||
!Iinclude/linux/wait.h
|
||||
!Ekernel/sched/wait.c
|
||||
</sect1>
|
||||
<sect1><title>High-resolution timers</title>
|
||||
!Iinclude/linux/ktime.h
|
||||
!Iinclude/linux/hrtimer.h
|
||||
!Ekernel/time/hrtimer.c
|
||||
</sect1>
|
||||
<sect1><title>Workqueues and Kevents</title>
|
||||
!Iinclude/linux/workqueue.h
|
||||
!Ekernel/workqueue.c
|
||||
</sect1>
|
||||
<sect1><title>Internal Functions</title>
|
||||
!Ikernel/exit.c
|
||||
!Ikernel/signal.c
|
||||
!Iinclude/linux/kthread.h
|
||||
!Ekernel/kthread.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Kernel objects manipulation</title>
|
||||
<!--
|
||||
X!Iinclude/linux/kobject.h
|
||||
-->
|
||||
!Elib/kobject.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Kernel utility functions</title>
|
||||
!Iinclude/linux/kernel.h
|
||||
!Ekernel/printk/printk.c
|
||||
!Ekernel/panic.c
|
||||
!Ekernel/sys.c
|
||||
!Ekernel/rcu/srcu.c
|
||||
!Ekernel/rcu/tree.c
|
||||
!Ekernel/rcu/tree_plugin.h
|
||||
!Ekernel/rcu/update.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Device Resource Management</title>
|
||||
!Edrivers/base/devres.c
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="devdrivers">
|
||||
<title>Device drivers infrastructure</title>
|
||||
<sect1><title>The Basic Device Driver-Model Structures </title>
|
||||
!Iinclude/linux/device.h
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers Base</title>
|
||||
!Idrivers/base/init.c
|
||||
!Edrivers/base/driver.c
|
||||
!Edrivers/base/core.c
|
||||
!Edrivers/base/syscore.c
|
||||
!Edrivers/base/class.c
|
||||
!Idrivers/base/node.c
|
||||
!Edrivers/base/firmware_class.c
|
||||
!Edrivers/base/transport_class.c
|
||||
<!-- Cannot be included, because
|
||||
attribute_container_add_class_device_adapter
|
||||
and attribute_container_classdev_to_container
|
||||
exceed allowed 44 characters maximum
|
||||
X!Edrivers/base/attribute_container.c
|
||||
-->
|
||||
!Edrivers/base/dd.c
|
||||
<!--
|
||||
X!Edrivers/base/interface.c
|
||||
-->
|
||||
!Iinclude/linux/platform_device.h
|
||||
!Edrivers/base/platform.c
|
||||
!Edrivers/base/bus.c
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>Buffer Sharing and Synchronization</title>
|
||||
<para>
|
||||
The dma-buf subsystem provides the framework for sharing buffers
|
||||
for hardware (DMA) access across multiple device drivers and
|
||||
subsystems, and for synchronizing asynchronous hardware access.
|
||||
</para>
|
||||
<para>
|
||||
This is used, for example, by drm "prime" multi-GPU support, but
|
||||
is of course not limited to GPU use cases.
|
||||
</para>
|
||||
<para>
|
||||
The three main components of this are: (1) dma-buf, representing
|
||||
a sg_table and exposed to userspace as a file descriptor to allow
|
||||
passing between devices, (2) fence, which provides a mechanism
|
||||
to signal when one device as finished access, and (3) reservation,
|
||||
which manages the shared or exclusive fence(s) associated with
|
||||
the buffer.
|
||||
</para>
|
||||
<sect2><title>dma-buf</title>
|
||||
!Edrivers/dma-buf/dma-buf.c
|
||||
!Iinclude/linux/dma-buf.h
|
||||
</sect2>
|
||||
<sect2><title>reservation</title>
|
||||
!Pdrivers/dma-buf/reservation.c Reservation Object Overview
|
||||
!Edrivers/dma-buf/reservation.c
|
||||
!Iinclude/linux/reservation.h
|
||||
</sect2>
|
||||
<sect2><title>fence</title>
|
||||
!Edrivers/dma-buf/fence.c
|
||||
!Iinclude/linux/fence.h
|
||||
!Edrivers/dma-buf/seqno-fence.c
|
||||
!Iinclude/linux/seqno-fence.h
|
||||
!Edrivers/dma-buf/fence-array.c
|
||||
!Iinclude/linux/fence-array.h
|
||||
!Edrivers/dma-buf/reservation.c
|
||||
!Iinclude/linux/reservation.h
|
||||
!Edrivers/dma-buf/sync_file.c
|
||||
!Iinclude/linux/sync_file.h
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers DMA Management</title>
|
||||
!Edrivers/base/dma-coherent.c
|
||||
!Edrivers/base/dma-mapping.c
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers Power Management</title>
|
||||
!Edrivers/base/power/main.c
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers ACPI Support</title>
|
||||
<!-- Internal functions only
|
||||
X!Edrivers/acpi/sleep/main.c
|
||||
X!Edrivers/acpi/sleep/wakeup.c
|
||||
X!Edrivers/acpi/motherboard.c
|
||||
X!Edrivers/acpi/bus.c
|
||||
-->
|
||||
!Edrivers/acpi/scan.c
|
||||
!Idrivers/acpi/scan.c
|
||||
<!-- No correct structured comments
|
||||
X!Edrivers/acpi/pci_bind.c
|
||||
-->
|
||||
</sect1>
|
||||
<sect1><title>Device drivers PnP support</title>
|
||||
!Idrivers/pnp/core.c
|
||||
<!-- No correct structured comments
|
||||
X!Edrivers/pnp/system.c
|
||||
-->
|
||||
!Edrivers/pnp/card.c
|
||||
!Idrivers/pnp/driver.c
|
||||
!Edrivers/pnp/manager.c
|
||||
!Edrivers/pnp/support.c
|
||||
</sect1>
|
||||
<sect1><title>Userspace IO devices</title>
|
||||
!Edrivers/uio/uio.c
|
||||
!Iinclude/linux/uio_driver.h
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="parportdev">
|
||||
<title>Parallel Port Devices</title>
|
||||
!Iinclude/linux/parport.h
|
||||
!Edrivers/parport/ieee1284.c
|
||||
!Edrivers/parport/share.c
|
||||
!Idrivers/parport/daisy.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="message_devices">
|
||||
<title>Message-based devices</title>
|
||||
<sect1><title>Fusion message devices</title>
|
||||
!Edrivers/message/fusion/mptbase.c
|
||||
!Idrivers/message/fusion/mptbase.c
|
||||
!Edrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptctl.c
|
||||
!Idrivers/message/fusion/mptspi.c
|
||||
!Idrivers/message/fusion/mptfc.c
|
||||
!Idrivers/message/fusion/mptlan.c
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="snddev">
|
||||
<title>Sound Devices</title>
|
||||
!Iinclude/sound/core.h
|
||||
!Esound/sound_core.c
|
||||
!Iinclude/sound/pcm.h
|
||||
!Esound/core/pcm.c
|
||||
!Esound/core/device.c
|
||||
!Esound/core/info.c
|
||||
!Esound/core/rawmidi.c
|
||||
!Esound/core/sound.c
|
||||
!Esound/core/memory.c
|
||||
!Esound/core/pcm_memory.c
|
||||
!Esound/core/init.c
|
||||
!Esound/core/isadma.c
|
||||
!Esound/core/control.c
|
||||
!Esound/core/pcm_lib.c
|
||||
!Esound/core/hwdep.c
|
||||
!Esound/core/pcm_native.c
|
||||
!Esound/core/memalloc.c
|
||||
<!-- FIXME: Removed for now since no structured comments in source
|
||||
X!Isound/sound_firmware.c
|
||||
-->
|
||||
</chapter>
|
||||
|
||||
|
||||
<chapter id="uart16x50">
|
||||
<title>16x50 UART Driver</title>
|
||||
!Edrivers/tty/serial/serial_core.c
|
||||
!Edrivers/tty/serial/8250/8250_core.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="fbdev">
|
||||
<title>Frame Buffer Library</title>
|
||||
|
||||
<para>
|
||||
The frame buffer drivers depend heavily on four data structures.
|
||||
These structures are declared in include/linux/fb.h. They are
|
||||
fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs.
|
||||
The last three can be made available to and from userland.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
fb_info defines the current state of a particular video card.
|
||||
Inside fb_info, there exists a fb_ops structure which is a
|
||||
collection of needed functions to make fbdev and fbcon work.
|
||||
fb_info is only visible to the kernel.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
fb_var_screeninfo is used to describe the features of a video card
|
||||
that are user defined. With fb_var_screeninfo, things such as
|
||||
depth and the resolution may be defined.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The next structure is fb_fix_screeninfo. This defines the
|
||||
properties of a card that are created when a mode is set and can't
|
||||
be changed otherwise. A good example of this is the start of the
|
||||
frame buffer memory. This "locks" the address of the frame buffer
|
||||
memory, so that it cannot be changed or moved.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The last structure is fb_monospecs. In the old API, there was
|
||||
little importance for fb_monospecs. This allowed for forbidden things
|
||||
such as setting a mode of 800x600 on a fix frequency monitor. With
|
||||
the new API, fb_monospecs prevents such things, and if used
|
||||
correctly, can prevent a monitor from being cooked. fb_monospecs
|
||||
will not be useful until kernels 2.5.x.
|
||||
</para>
|
||||
|
||||
<sect1><title>Frame Buffer Memory</title>
|
||||
!Edrivers/video/fbdev/core/fbmem.c
|
||||
</sect1>
|
||||
<!--
|
||||
<sect1><title>Frame Buffer Console</title>
|
||||
X!Edrivers/video/console/fbcon.c
|
||||
</sect1>
|
||||
-->
|
||||
<sect1><title>Frame Buffer Colormap</title>
|
||||
!Edrivers/video/fbdev/core/fbcmap.c
|
||||
</sect1>
|
||||
<!-- FIXME:
|
||||
drivers/video/fbgen.c has no docs, which stuffs up the sgml. Comment
|
||||
out until somebody adds docs. KAO
|
||||
<sect1><title>Frame Buffer Generic Functions</title>
|
||||
X!Idrivers/video/fbgen.c
|
||||
</sect1>
|
||||
KAO -->
|
||||
<sect1><title>Frame Buffer Video Mode Database</title>
|
||||
!Idrivers/video/fbdev/core/modedb.c
|
||||
!Edrivers/video/fbdev/core/modedb.c
|
||||
</sect1>
|
||||
<sect1><title>Frame Buffer Macintosh Video Mode Database</title>
|
||||
!Edrivers/video/fbdev/macmodes.c
|
||||
</sect1>
|
||||
<sect1><title>Frame Buffer Fonts</title>
|
||||
<para>
|
||||
Refer to the file lib/fonts/fonts.c for more information.
|
||||
</para>
|
||||
<!-- FIXME: Removed for now since no structured comments in source
|
||||
X!Ilib/fonts/fonts.c
|
||||
-->
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="input_subsystem">
|
||||
<title>Input Subsystem</title>
|
||||
<sect1><title>Input core</title>
|
||||
!Iinclude/linux/input.h
|
||||
!Edrivers/input/input.c
|
||||
!Edrivers/input/ff-core.c
|
||||
!Edrivers/input/ff-memless.c
|
||||
</sect1>
|
||||
<sect1><title>Multitouch Library</title>
|
||||
!Iinclude/linux/input/mt.h
|
||||
!Edrivers/input/input-mt.c
|
||||
</sect1>
|
||||
<sect1><title>Polled input devices</title>
|
||||
!Iinclude/linux/input-polldev.h
|
||||
!Edrivers/input/input-polldev.c
|
||||
</sect1>
|
||||
<sect1><title>Matrix keyboards/keypads</title>
|
||||
!Iinclude/linux/input/matrix_keypad.h
|
||||
</sect1>
|
||||
<sect1><title>Sparse keymap support</title>
|
||||
!Iinclude/linux/input/sparse-keymap.h
|
||||
!Edrivers/input/sparse-keymap.c
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="spi">
|
||||
<title>Serial Peripheral Interface (SPI)</title>
|
||||
<para>
|
||||
SPI is the "Serial Peripheral Interface", widely used with
|
||||
embedded systems because it is a simple and efficient
|
||||
interface: basically a multiplexed shift register.
|
||||
Its three signal wires hold a clock (SCK, often in the range
|
||||
of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
|
||||
a "Master In, Slave Out" (MISO) data line.
|
||||
SPI is a full duplex protocol; for each bit shifted out the
|
||||
MOSI line (one per clock) another is shifted in on the MISO line.
|
||||
Those bits are assembled into words of various sizes on the
|
||||
way to and from system memory.
|
||||
An additional chipselect line is usually active-low (nCS);
|
||||
four signals are normally used for each peripheral, plus
|
||||
sometimes an interrupt.
|
||||
</para>
|
||||
<para>
|
||||
The SPI bus facilities listed here provide a generalized
|
||||
interface to declare SPI busses and devices, manage them
|
||||
according to the standard Linux driver model, and perform
|
||||
input/output operations.
|
||||
At this time, only "master" side interfaces are supported,
|
||||
where Linux talks to SPI peripherals and does not implement
|
||||
such a peripheral itself.
|
||||
(Interfaces to support implementing SPI slaves would
|
||||
necessarily look different.)
|
||||
</para>
|
||||
<para>
|
||||
The programming interface is structured around two kinds of driver,
|
||||
and two kinds of device.
|
||||
A "Controller Driver" abstracts the controller hardware, which may
|
||||
be as simple as a set of GPIO pins or as complex as a pair of FIFOs
|
||||
connected to dual DMA engines on the other side of the SPI shift
|
||||
register (maximizing throughput). Such drivers bridge between
|
||||
whatever bus they sit on (often the platform bus) and SPI, and
|
||||
expose the SPI side of their device as a
|
||||
<structname>struct spi_master</structname>.
|
||||
SPI devices are children of that master, represented as a
|
||||
<structname>struct spi_device</structname> and manufactured from
|
||||
<structname>struct spi_board_info</structname> descriptors which
|
||||
are usually provided by board-specific initialization code.
|
||||
A <structname>struct spi_driver</structname> is called a
|
||||
"Protocol Driver", and is bound to a spi_device using normal
|
||||
driver model calls.
|
||||
</para>
|
||||
<para>
|
||||
The I/O model is a set of queued messages. Protocol drivers
|
||||
submit one or more <structname>struct spi_message</structname>
|
||||
objects, which are processed and completed asynchronously.
|
||||
(There are synchronous wrappers, however.) Messages are
|
||||
built from one or more <structname>struct spi_transfer</structname>
|
||||
objects, each of which wraps a full duplex SPI transfer.
|
||||
A variety of protocol tweaking options are needed, because
|
||||
different chips adopt very different policies for how they
|
||||
use the bits transferred with SPI.
|
||||
</para>
|
||||
!Iinclude/linux/spi/spi.h
|
||||
!Fdrivers/spi/spi.c spi_register_board_info
|
||||
!Edrivers/spi/spi.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="i2c">
|
||||
<title>I<superscript>2</superscript>C and SMBus Subsystem</title>
|
||||
|
||||
<para>
|
||||
I<superscript>2</superscript>C (or without fancy typography, "I2C")
|
||||
is an acronym for the "Inter-IC" bus, a simple bus protocol which is
|
||||
widely used where low data rate communications suffice.
|
||||
Since it's also a licensed trademark, some vendors use another
|
||||
name (such as "Two-Wire Interface", TWI) for the same bus.
|
||||
I2C only needs two signals (SCL for clock, SDA for data), conserving
|
||||
board real estate and minimizing signal quality issues.
|
||||
Most I2C devices use seven bit addresses, and bus speeds of up
|
||||
to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
|
||||
found wide use.
|
||||
I2C is a multi-master bus; open drain signaling is used to
|
||||
arbitrate between masters, as well as to handshake and to
|
||||
synchronize clocks from slower clients.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The Linux I2C programming interfaces support only the master
|
||||
side of bus interactions, not the slave side.
|
||||
The programming interface is structured around two kinds of driver,
|
||||
and two kinds of device.
|
||||
An I2C "Adapter Driver" abstracts the controller hardware; it binds
|
||||
to a physical device (perhaps a PCI device or platform_device) and
|
||||
exposes a <structname>struct i2c_adapter</structname> representing
|
||||
each I2C bus segment it manages.
|
||||
On each I2C bus segment will be I2C devices represented by a
|
||||
<structname>struct i2c_client</structname>. Those devices will
|
||||
be bound to a <structname>struct i2c_driver</structname>,
|
||||
which should follow the standard Linux driver model.
|
||||
(At this writing, a legacy model is more widely used.)
|
||||
There are functions to perform various I2C protocol operations; at
|
||||
this writing all such functions are usable only from task context.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
|
||||
systems are also I2C conformant. The electrical constraints are
|
||||
tighter for SMBus, and it standardizes particular protocol messages
|
||||
and idioms. Controllers that support I2C can also support most
|
||||
SMBus operations, but SMBus controllers don't support all the protocol
|
||||
options that an I2C controller will.
|
||||
There are functions to perform various SMBus protocol operations,
|
||||
either using I2C primitives or by issuing SMBus commands to
|
||||
i2c_adapter devices which don't support those I2C operations.
|
||||
</para>
|
||||
|
||||
!Iinclude/linux/i2c.h
|
||||
!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
|
||||
!Edrivers/i2c/i2c-core.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="hsi">
|
||||
<title>High Speed Synchronous Serial Interface (HSI)</title>
|
||||
|
||||
<para>
|
||||
High Speed Synchronous Serial Interface (HSI) is a
|
||||
serial interface mainly used for connecting application
|
||||
engines (APE) with cellular modem engines (CMT) in cellular
|
||||
handsets.
|
||||
|
||||
HSI provides multiplexing for up to 16 logical channels,
|
||||
low-latency and full duplex communication.
|
||||
</para>
|
||||
|
||||
!Iinclude/linux/hsi/hsi.h
|
||||
!Edrivers/hsi/hsi_core.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="pwm">
|
||||
<title>Pulse-Width Modulation (PWM)</title>
|
||||
<para>
|
||||
Pulse-width modulation is a modulation technique primarily used to
|
||||
control power supplied to electrical devices.
|
||||
</para>
|
||||
<para>
|
||||
The PWM framework provides an abstraction for providers and consumers
|
||||
of PWM signals. A controller that provides one or more PWM signals is
|
||||
registered as <structname>struct pwm_chip</structname>. Providers are
|
||||
expected to embed this structure in a driver-specific structure. This
|
||||
structure contains fields that describe a particular chip.
|
||||
</para>
|
||||
<para>
|
||||
A chip exposes one or more PWM signal sources, each of which exposed
|
||||
as a <structname>struct pwm_device</structname>. Operations can be
|
||||
performed on PWM devices to control the period, duty cycle, polarity
|
||||
and active state of the signal.
|
||||
</para>
|
||||
<para>
|
||||
Note that PWM devices are exclusive resources: they can always only be
|
||||
used by one consumer at a time.
|
||||
</para>
|
||||
!Iinclude/linux/pwm.h
|
||||
!Edrivers/pwm/core.c
|
||||
</chapter>
|
||||
|
||||
</book>
|
|
@ -5,6 +5,9 @@
|
|||
# You can set these variables from the command line.
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXOPTS =
|
||||
SPHINXDIRS = .
|
||||
_SPHINXDIRS = $(patsubst $(srctree)/Documentation/%/conf.py,%,$(wildcard $(srctree)/Documentation/*/conf.py))
|
||||
SPHINX_CONF = conf.py
|
||||
PAPER =
|
||||
BUILDDIR = $(obj)/output
|
||||
|
||||
|
@ -25,38 +28,62 @@ else ifneq ($(DOCBOOKS),)
|
|||
|
||||
else # HAVE_SPHINX
|
||||
|
||||
# User-friendly check for rst2pdf
|
||||
HAVE_RST2PDF := $(shell if python -c "import rst2pdf" >/dev/null 2>&1; then echo 1; else echo 0; fi)
|
||||
# User-friendly check for pdflatex
|
||||
HAVE_PDFLATEX := $(shell if which xelatex >/dev/null 2>&1; then echo 1; else echo 0; fi)
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
KERNELDOC = $(srctree)/scripts/kernel-doc
|
||||
KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC)
|
||||
ALLSPHINXOPTS = -D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) -d $(BUILDDIR)/.doctrees $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) -c $(srctree)/$(src) $(SPHINXOPTS) $(srctree)/$(src)
|
||||
ALLSPHINXOPTS = $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS)
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
quiet_cmd_sphinx = SPHINX $@
|
||||
cmd_sphinx = BUILDDIR=$(BUILDDIR) $(SPHINXBUILD) -b $2 $(ALLSPHINXOPTS) $(BUILDDIR)/$2
|
||||
# commands; the 'cmd' from scripts/Kbuild.include is not *loopable*
|
||||
loop_cmd = $(echo-cmd) $(cmd_$(1))
|
||||
|
||||
# $2 sphinx builder e.g. "html"
|
||||
# $3 name of the build subfolder / e.g. "media", used as:
|
||||
# * dest folder relative to $(BUILDDIR) and
|
||||
# * cache folder relative to $(BUILDDIR)/.doctrees
|
||||
# $4 dest subfolder e.g. "man" for man pages at media/man
|
||||
# $5 reST source folder relative to $(srctree)/$(src),
|
||||
# e.g. "media" for the linux-tv book-set at ./Documentation/media
|
||||
|
||||
quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4);
|
||||
cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media all;\
|
||||
BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
|
||||
$(SPHINXBUILD) \
|
||||
-b $2 \
|
||||
-c $(abspath $(srctree)/$(src)) \
|
||||
-d $(abspath $(BUILDDIR)/.doctrees/$3) \
|
||||
-D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) \
|
||||
$(ALLSPHINXOPTS) \
|
||||
$(abspath $(srctree)/$(src)/$5) \
|
||||
$(abspath $(BUILDDIR)/$3/$4);
|
||||
|
||||
htmldocs:
|
||||
$(MAKE) BUILDDIR=$(BUILDDIR) -f $(srctree)/Documentation/media/Makefile $@
|
||||
$(call cmd,sphinx,html)
|
||||
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var)))
|
||||
|
||||
pdfdocs:
|
||||
ifeq ($(HAVE_RST2PDF),0)
|
||||
$(warning The Python 'rst2pdf' module was not found. Make sure you have the module installed to produce PDF output.)
|
||||
latexdocs:
|
||||
ifeq ($(HAVE_PDFLATEX),0)
|
||||
$(warning The 'xelatex' command was not found. Make sure you have it installed and in PATH to produce PDF output.)
|
||||
@echo " SKIP Sphinx $@ target."
|
||||
else # HAVE_RST2PDF
|
||||
$(call cmd,sphinx,pdf)
|
||||
endif # HAVE_RST2PDF
|
||||
else # HAVE_PDFLATEX
|
||||
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,latex,$(var),latex,$(var)))
|
||||
endif # HAVE_PDFLATEX
|
||||
|
||||
pdfdocs: latexdocs
|
||||
ifneq ($(HAVE_PDFLATEX),0)
|
||||
$(foreach var,$(SPHINXDIRS), $(MAKE) PDFLATEX=xelatex LATEXOPTS="-interaction=nonstopmode" -C $(BUILDDIR)/$(var)/latex)
|
||||
endif # HAVE_PDFLATEX
|
||||
|
||||
epubdocs:
|
||||
$(call cmd,sphinx,epub)
|
||||
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,epub,$(var),epub,$(var)))
|
||||
|
||||
xmldocs:
|
||||
$(call cmd,sphinx,xml)
|
||||
@$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,xml,$(var),xml,$(var)))
|
||||
|
||||
# no-ops for the Sphinx toolchain
|
||||
sgmldocs:
|
||||
|
@ -72,7 +99,14 @@ endif # HAVE_SPHINX
|
|||
dochelp:
|
||||
@echo ' Linux kernel internal documentation in different formats (Sphinx):'
|
||||
@echo ' htmldocs - HTML'
|
||||
@echo ' latexdocs - LaTeX'
|
||||
@echo ' pdfdocs - PDF'
|
||||
@echo ' epubdocs - EPUB'
|
||||
@echo ' xmldocs - XML'
|
||||
@echo ' cleandocs - clean all generated files'
|
||||
@echo
|
||||
@echo ' make SPHINXDIRS="s1 s2" [target] Generate only docs of folder s1, s2'
|
||||
@echo ' valid values for SPHINXDIRS are: $(_SPHINXDIRS)'
|
||||
@echo
|
||||
@echo ' make SPHINX_CONF={conf-file} [target] use *additional* sphinx-build'
|
||||
@echo ' configuration. This is e.g. useful to build with nit-picking config.'
|
||||
|
|
|
@ -73,4 +73,13 @@ SunXi family
|
|||
* Octa ARM Cortex-A7 based SoCs
|
||||
- Allwinner A83T
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A83T/A83T_datasheet_Revision_1.1.pdf
|
||||
https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_Datasheet_v1.3_20150510.pdf
|
||||
+ User Manual
|
||||
https://github.com/allwinner-zh/documents/raw/master/A83T/A83T_User_Manual_v1.5.1_20150513.pdf
|
||||
|
||||
* Quad ARM Cortex-A53 based SoCs
|
||||
- Allwinner A64
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A64/A64_Datasheet_V1.1.pdf
|
||||
+ User Manual
|
||||
http://dl.linux-sunxi.org/A64/Allwinner%20A64%20User%20Manual%20v1.0.pdf
|
||||
|
|
|
@ -31,24 +31,25 @@ serve as a convenient shorthand for the implementation of the
|
|||
hardware-specific bits for the hypothetical "foo" hardware.
|
||||
|
||||
Tying the two halves of this interface together is struct clk_hw, which
|
||||
is defined in struct clk_foo and pointed to within struct clk. This
|
||||
is defined in struct clk_foo and pointed to within struct clk_core. This
|
||||
allows for easy navigation between the two discrete halves of the common
|
||||
clock interface.
|
||||
|
||||
Part 2 - common data structures and api
|
||||
|
||||
Below is the common struct clk definition from
|
||||
include/linux/clk-private.h, modified for brevity:
|
||||
Below is the common struct clk_core definition from
|
||||
drivers/clk/clk.c, modified for brevity:
|
||||
|
||||
struct clk {
|
||||
struct clk_core {
|
||||
const char *name;
|
||||
const struct clk_ops *ops;
|
||||
struct clk_hw *hw;
|
||||
char **parent_names;
|
||||
struct clk **parents;
|
||||
struct clk *parent;
|
||||
struct hlist_head children;
|
||||
struct hlist_node child_node;
|
||||
struct module *owner;
|
||||
struct clk_core *parent;
|
||||
const char **parent_names;
|
||||
struct clk_core **parents;
|
||||
u8 num_parents;
|
||||
u8 new_parent_index;
|
||||
...
|
||||
};
|
||||
|
||||
|
@ -56,16 +57,19 @@ The members above make up the core of the clk tree topology. The clk
|
|||
api itself defines several driver-facing functions which operate on
|
||||
struct clk. That api is documented in include/linux/clk.h.
|
||||
|
||||
Platforms and devices utilizing the common struct clk use the struct
|
||||
clk_ops pointer in struct clk to perform the hardware-specific parts of
|
||||
the operations defined in clk.h:
|
||||
Platforms and devices utilizing the common struct clk_core use the struct
|
||||
clk_ops pointer in struct clk_core to perform the hardware-specific parts of
|
||||
the operations defined in clk-provider.h:
|
||||
|
||||
struct clk_ops {
|
||||
int (*prepare)(struct clk_hw *hw);
|
||||
void (*unprepare)(struct clk_hw *hw);
|
||||
int (*is_prepared)(struct clk_hw *hw);
|
||||
void (*unprepare_unused)(struct clk_hw *hw);
|
||||
int (*enable)(struct clk_hw *hw);
|
||||
void (*disable)(struct clk_hw *hw);
|
||||
int (*is_enabled)(struct clk_hw *hw);
|
||||
void (*disable_unused)(struct clk_hw *hw);
|
||||
unsigned long (*recalc_rate)(struct clk_hw *hw,
|
||||
unsigned long parent_rate);
|
||||
long (*round_rate)(struct clk_hw *hw,
|
||||
|
@ -84,6 +88,8 @@ the operations defined in clk.h:
|
|||
u8 index);
|
||||
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
|
||||
unsigned long parent_accuracy);
|
||||
int (*get_phase)(struct clk_hw *hw);
|
||||
int (*set_phase)(struct clk_hw *hw, int degrees);
|
||||
void (*init)(struct clk_hw *hw);
|
||||
int (*debug_init)(struct clk_hw *hw,
|
||||
struct dentry *dentry);
|
||||
|
@ -91,7 +97,7 @@ the operations defined in clk.h:
|
|||
|
||||
Part 3 - hardware clk implementations
|
||||
|
||||
The strength of the common struct clk comes from its .ops and .hw pointers
|
||||
The strength of the common struct clk_core comes from its .ops and .hw pointers
|
||||
which abstract the details of struct clk from the hardware-specific bits, and
|
||||
vice versa. To illustrate consider the simple gateable clk implementation in
|
||||
drivers/clk/clk-gate.c:
|
||||
|
@ -107,7 +113,7 @@ struct clk_gate contains struct clk_hw hw as well as hardware-specific
|
|||
knowledge about which register and bit controls this clk's gating.
|
||||
Nothing about clock topology or accounting, such as enable_count or
|
||||
notifier_count, is needed here. That is all handled by the common
|
||||
framework code and struct clk.
|
||||
framework code and struct clk_core.
|
||||
|
||||
Let's walk through enabling this clk from driver code:
|
||||
|
||||
|
@ -139,22 +145,18 @@ static void clk_gate_set_bit(struct clk_gate *gate)
|
|||
|
||||
Note that to_clk_gate is defined as:
|
||||
|
||||
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, clk)
|
||||
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
|
||||
|
||||
This pattern of abstraction is used for every clock hardware
|
||||
representation.
|
||||
|
||||
Part 4 - supporting your own clk hardware
|
||||
|
||||
When implementing support for a new type of clock it only necessary to
|
||||
When implementing support for a new type of clock it is only necessary to
|
||||
include the following header:
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
include/linux/clk.h is included within that header and clk-private.h
|
||||
must never be included from the code which implements the operations for
|
||||
a clock. More on that below in Part 5.
|
||||
|
||||
To construct a clk hardware structure for your platform you must define
|
||||
the following:
|
||||
|
||||
|
|
|
@ -14,11 +14,17 @@
|
|||
|
||||
import sys
|
||||
import os
|
||||
import sphinx
|
||||
|
||||
# Get Sphinx version
|
||||
major, minor, patch = map(int, sphinx.__version__.split("."))
|
||||
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('sphinx'))
|
||||
from load_config import loadConfig
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
|
@ -28,14 +34,13 @@ sys.path.insert(0, os.path.abspath('sphinx'))
|
|||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['kernel-doc', 'rstFlatTable', 'kernel_include']
|
||||
extensions = ['kernel-doc', 'rstFlatTable', 'kernel_include', 'cdomain']
|
||||
|
||||
# Gracefully handle missing rst2pdf.
|
||||
try:
|
||||
import rst2pdf
|
||||
extensions += ['rst2pdf.pdfbuilder']
|
||||
except ImportError:
|
||||
pass
|
||||
# The name of the math extension changed on Sphinx 1.4
|
||||
if minor > 3:
|
||||
extensions.append("sphinx.ext.imgmath")
|
||||
else:
|
||||
extensions.append("sphinx.ext.pngmath")
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
@ -252,23 +257,90 @@ htmlhelp_basename = 'TheLinuxKerneldoc'
|
|||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
'papersize': 'a4paper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
'pointsize': '8pt',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#'figure_align': 'htbp',
|
||||
|
||||
# Don't mangle with UTF-8 chars
|
||||
'inputenc': '',
|
||||
'utf8extra': '',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
'preamble': '''
|
||||
% Adjust margins
|
||||
\\usepackage[margin=0.5in, top=1in, bottom=1in]{geometry}
|
||||
|
||||
% Allow generate some pages in landscape
|
||||
\\usepackage{lscape}
|
||||
|
||||
% Put notes in color and let them be inside a table
|
||||
\\definecolor{NoteColor}{RGB}{204,255,255}
|
||||
\\definecolor{WarningColor}{RGB}{255,204,204}
|
||||
\\definecolor{AttentionColor}{RGB}{255,255,204}
|
||||
\\definecolor{OtherColor}{RGB}{204,204,204}
|
||||
\\newlength{\\mynoticelength}
|
||||
\\makeatletter\\newenvironment{coloredbox}[1]{%
|
||||
\\setlength{\\fboxrule}{1pt}
|
||||
\\setlength{\\fboxsep}{7pt}
|
||||
\\setlength{\\mynoticelength}{\\linewidth}
|
||||
\\addtolength{\\mynoticelength}{-2\\fboxsep}
|
||||
\\addtolength{\\mynoticelength}{-2\\fboxrule}
|
||||
\\begin{lrbox}{\\@tempboxa}\\begin{minipage}{\\mynoticelength}}{\\end{minipage}\\end{lrbox}%
|
||||
\\ifthenelse%
|
||||
{\\equal{\\py@noticetype}{note}}%
|
||||
{\\colorbox{NoteColor}{\\usebox{\\@tempboxa}}}%
|
||||
{%
|
||||
\\ifthenelse%
|
||||
{\\equal{\\py@noticetype}{warning}}%
|
||||
{\\colorbox{WarningColor}{\\usebox{\\@tempboxa}}}%
|
||||
{%
|
||||
\\ifthenelse%
|
||||
{\\equal{\\py@noticetype}{attention}}%
|
||||
{\\colorbox{AttentionColor}{\\usebox{\\@tempboxa}}}%
|
||||
{\\colorbox{OtherColor}{\\usebox{\\@tempboxa}}}%
|
||||
}%
|
||||
}%
|
||||
}\\makeatother
|
||||
|
||||
\\makeatletter
|
||||
\\renewenvironment{notice}[2]{%
|
||||
\\def\\py@noticetype{#1}
|
||||
\\begin{coloredbox}{#1}
|
||||
\\bf\\it
|
||||
\\par\\strong{#2}
|
||||
\\csname py@noticestart@#1\\endcsname
|
||||
}
|
||||
{
|
||||
\\csname py@noticeend@\\py@noticetype\\endcsname
|
||||
\\end{coloredbox}
|
||||
}
|
||||
\\makeatother
|
||||
|
||||
% Use some font with UTF-8 support with XeLaTeX
|
||||
\\usepackage{fontspec}
|
||||
\\setsansfont{DejaVu Serif}
|
||||
\\setromanfont{DejaVu Sans}
|
||||
\\setmonofont{DejaVu Sans Mono}
|
||||
|
||||
% To allow adjusting table sizes
|
||||
\\usepackage{adjustbox}
|
||||
|
||||
'''
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'TheLinuxKernel.tex', 'The Linux Kernel Documentation',
|
||||
('kernel-documentation', 'kernel-documentation.tex', 'The Linux Kernel Documentation',
|
||||
'The kernel development community', 'manual'),
|
||||
('gpu/index', 'gpu.tex', 'Linux GPU Driver Developer\'s Guide',
|
||||
'The kernel development community', 'manual'),
|
||||
('media/index', 'media.tex', 'Linux Media Subsystem Documentation',
|
||||
'The kernel development community', 'manual'),
|
||||
]
|
||||
|
||||
|
@ -419,3 +491,9 @@ pdf_documents = [
|
|||
# line arguments.
|
||||
kerneldoc_bin = '../scripts/kernel-doc'
|
||||
kerneldoc_srctree = '..'
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Since loadConfig overwrites settings from the global namespace, it has to be
|
||||
# the last statement in the conf.py file
|
||||
# ------------------------------------------------------------------------------
|
||||
loadConfig(globals())
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
Copyright 2010 Nicolas Palix <npalix@diku.dk>
|
||||
Copyright 2010 Julia Lawall <julia@diku.dk>
|
||||
Copyright 2010 Gilles Muller <Gilles.Muller@lip6.fr>
|
||||
.. Copyright 2010 Nicolas Palix <npalix@diku.dk>
|
||||
.. Copyright 2010 Julia Lawall <julia@diku.dk>
|
||||
.. Copyright 2010 Gilles Muller <Gilles.Muller@lip6.fr>
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
Getting Coccinelle
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Coccinelle
|
||||
==========
|
||||
|
||||
Coccinelle is a tool for pattern matching and text transformation that has
|
||||
many uses in kernel development, including the application of complex,
|
||||
tree-wide patches and detection of problematic programming patterns.
|
||||
|
||||
Getting Coccinelle
|
||||
-------------------
|
||||
|
||||
The semantic patches included in the kernel use features and options
|
||||
which are provided by Coccinelle version 1.0.0-rc11 and above.
|
||||
|
@ -22,24 +30,23 @@ of many distributions, e.g. :
|
|||
- NetBSD
|
||||
- FreeBSD
|
||||
|
||||
|
||||
You can get the latest version released from the Coccinelle homepage at
|
||||
http://coccinelle.lip6.fr/
|
||||
|
||||
Information and tips about Coccinelle are also provided on the wiki
|
||||
pages at http://cocci.ekstranet.diku.dk/wiki/doku.php
|
||||
|
||||
Once you have it, run the following command:
|
||||
Once you have it, run the following command::
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
as a regular user, and install it with
|
||||
as a regular user, and install it with::
|
||||
|
||||
sudo make install
|
||||
|
||||
Supplemental documentation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Supplemental documentation
|
||||
---------------------------
|
||||
|
||||
For supplemental documentation refer to the wiki:
|
||||
|
||||
|
@ -47,49 +54,52 @@ https://bottest.wiki.kernel.org/coccicheck
|
|||
|
||||
The wiki documentation always refers to the linux-next version of the script.
|
||||
|
||||
Using Coccinelle on the Linux kernel
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Using Coccinelle on the Linux kernel
|
||||
------------------------------------
|
||||
|
||||
A Coccinelle-specific target is defined in the top level
|
||||
Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
|
||||
front-end in the 'scripts' directory.
|
||||
Makefile. This target is named ``coccicheck`` and calls the ``coccicheck``
|
||||
front-end in the ``scripts`` directory.
|
||||
|
||||
Four basic modes are defined: patch, report, context, and org. The mode to
|
||||
use is specified by setting the MODE variable with 'MODE=<mode>'.
|
||||
Four basic modes are defined: ``patch``, ``report``, ``context``, and
|
||||
``org``. The mode to use is specified by setting the MODE variable with
|
||||
``MODE=<mode>``.
|
||||
|
||||
'patch' proposes a fix, when possible.
|
||||
- ``patch`` proposes a fix, when possible.
|
||||
|
||||
'report' generates a list in the following format:
|
||||
- ``report`` generates a list in the following format:
|
||||
file:line:column-column: message
|
||||
|
||||
'context' highlights lines of interest and their context in a
|
||||
diff-like style.Lines of interest are indicated with '-'.
|
||||
- ``context`` highlights lines of interest and their context in a
|
||||
diff-like style.Lines of interest are indicated with ``-``.
|
||||
|
||||
'org' generates a report in the Org mode format of Emacs.
|
||||
- ``org`` generates a report in the Org mode format of Emacs.
|
||||
|
||||
Note that not all semantic patches implement all modes. For easy use
|
||||
of Coccinelle, the default mode is "report".
|
||||
|
||||
Two other modes provide some common combinations of these modes.
|
||||
|
||||
'chain' tries the previous modes in the order above until one succeeds.
|
||||
- ``chain`` tries the previous modes in the order above until one succeeds.
|
||||
|
||||
'rep+ctxt' runs successively the report mode and the context mode.
|
||||
It should be used with the C option (described later)
|
||||
which checks the code on a file basis.
|
||||
- ``rep+ctxt`` runs successively the report mode and the context mode.
|
||||
It should be used with the C option (described later)
|
||||
which checks the code on a file basis.
|
||||
|
||||
Examples:
|
||||
To make a report for every semantic patch, run the following command:
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
To make a report for every semantic patch, run the following command::
|
||||
|
||||
make coccicheck MODE=report
|
||||
|
||||
To produce patches, run:
|
||||
To produce patches, run::
|
||||
|
||||
make coccicheck MODE=patch
|
||||
|
||||
|
||||
The coccicheck target applies every semantic patch available in the
|
||||
sub-directories of 'scripts/coccinelle' to the entire Linux kernel.
|
||||
sub-directories of ``scripts/coccinelle`` to the entire Linux kernel.
|
||||
|
||||
For each semantic patch, a commit message is proposed. It gives a
|
||||
description of the problem being checked by the semantic patch, and
|
||||
|
@ -99,15 +109,15 @@ As any static code analyzer, Coccinelle produces false
|
|||
positives. Thus, reports must be carefully checked, and patches
|
||||
reviewed.
|
||||
|
||||
To enable verbose messages set the V= variable, for example:
|
||||
To enable verbose messages set the V= variable, for example::
|
||||
|
||||
make coccicheck MODE=report V=1
|
||||
|
||||
Coccinelle parallelization
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Coccinelle parallelization
|
||||
---------------------------
|
||||
|
||||
By default, coccicheck tries to run as parallel as possible. To change
|
||||
the parallelism, set the J= variable. For example, to run across 4 CPUs:
|
||||
the parallelism, set the J= variable. For example, to run across 4 CPUs::
|
||||
|
||||
make coccicheck MODE=report J=4
|
||||
|
||||
|
@ -115,44 +125,47 @@ As of Coccinelle 1.0.2 Coccinelle uses Ocaml parmap for parallelization,
|
|||
if support for this is detected you will benefit from parmap parallelization.
|
||||
|
||||
When parmap is enabled coccicheck will enable dynamic load balancing by using
|
||||
'--chunksize 1' argument, this ensures we keep feeding threads with work
|
||||
``--chunksize 1`` argument, this ensures we keep feeding threads with work
|
||||
one by one, so that we avoid the situation where most work gets done by only
|
||||
a few threads. With dynamic load balancing, if a thread finishes early we keep
|
||||
feeding it more work.
|
||||
|
||||
When parmap is enabled, if an error occurs in Coccinelle, this error
|
||||
value is propagated back, the return value of the 'make coccicheck'
|
||||
value is propagated back, the return value of the ``make coccicheck``
|
||||
captures this return value.
|
||||
|
||||
Using Coccinelle with a single semantic patch
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Using Coccinelle with a single semantic patch
|
||||
---------------------------------------------
|
||||
|
||||
The optional make variable COCCI can be used to check a single
|
||||
semantic patch. In that case, the variable must be initialized with
|
||||
the name of the semantic patch to apply.
|
||||
|
||||
For instance:
|
||||
For instance::
|
||||
|
||||
make coccicheck COCCI=<my_SP.cocci> MODE=patch
|
||||
or
|
||||
|
||||
or::
|
||||
|
||||
make coccicheck COCCI=<my_SP.cocci> MODE=report
|
||||
|
||||
|
||||
Controlling Which Files are Processed by Coccinelle
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Controlling Which Files are Processed by Coccinelle
|
||||
---------------------------------------------------
|
||||
|
||||
By default the entire kernel source tree is checked.
|
||||
|
||||
To apply Coccinelle to a specific directory, M= can be used.
|
||||
For example, to check drivers/net/wireless/ one may write:
|
||||
To apply Coccinelle to a specific directory, ``M=`` can be used.
|
||||
For example, to check drivers/net/wireless/ one may write::
|
||||
|
||||
make coccicheck M=drivers/net/wireless/
|
||||
|
||||
To apply Coccinelle on a file basis, instead of a directory basis, the
|
||||
following command may be used:
|
||||
following command may be used::
|
||||
|
||||
make C=1 CHECK="scripts/coccicheck"
|
||||
|
||||
To check only newly edited code, use the value 2 for the C flag, i.e.
|
||||
To check only newly edited code, use the value 2 for the C flag, i.e.::
|
||||
|
||||
make C=2 CHECK="scripts/coccicheck"
|
||||
|
||||
|
@ -166,8 +179,8 @@ semantic patch as shown in the previous section.
|
|||
The "report" mode is the default. You can select another one with the
|
||||
MODE variable explained above.
|
||||
|
||||
Debugging Coccinelle SmPL patches
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Debugging Coccinelle SmPL patches
|
||||
---------------------------------
|
||||
|
||||
Using coccicheck is best as it provides in the spatch command line
|
||||
include options matching the options used when we compile the kernel.
|
||||
|
@ -177,8 +190,8 @@ manually run Coccinelle with debug options added.
|
|||
Alternatively you can debug running Coccinelle against SmPL patches
|
||||
by asking for stderr to be redirected to stderr, by default stderr
|
||||
is redirected to /dev/null, if you'd like to capture stderr you
|
||||
can specify the DEBUG_FILE="file.txt" option to coccicheck. For
|
||||
instance:
|
||||
can specify the ``DEBUG_FILE="file.txt"`` option to coccicheck. For
|
||||
instance::
|
||||
|
||||
rm -f cocci.err
|
||||
make coccicheck COCCI=scripts/coccinelle/free/kfree.cocci MODE=report DEBUG_FILE=cocci.err
|
||||
|
@ -186,7 +199,7 @@ instance:
|
|||
|
||||
You can use SPFLAGS to add debugging flags, for instance you may want to
|
||||
add both --profile --show-trying to SPFLAGS when debugging. For instance
|
||||
you may want to use:
|
||||
you may want to use::
|
||||
|
||||
rm -f err.log
|
||||
export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
|
||||
|
@ -198,24 +211,24 @@ work.
|
|||
|
||||
DEBUG_FILE support is only supported when using coccinelle >= 1.2.
|
||||
|
||||
.cocciconfig support
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
.cocciconfig support
|
||||
--------------------
|
||||
|
||||
Coccinelle supports reading .cocciconfig for default Coccinelle options that
|
||||
should be used every time spatch is spawned, the order of precedence for
|
||||
variables for .cocciconfig is as follows:
|
||||
|
||||
o Your current user's home directory is processed first
|
||||
o Your directory from which spatch is called is processed next
|
||||
o The directory provided with the --dir option is processed last, if used
|
||||
- Your current user's home directory is processed first
|
||||
- Your directory from which spatch is called is processed next
|
||||
- The directory provided with the --dir option is processed last, if used
|
||||
|
||||
Since coccicheck runs through make, it naturally runs from the kernel
|
||||
proper dir, as such the second rule above would be implied for picking up a
|
||||
.cocciconfig when using 'make coccicheck'.
|
||||
.cocciconfig when using ``make coccicheck``.
|
||||
|
||||
'make coccicheck' also supports using M= targets.If you do not supply
|
||||
``make coccicheck`` also supports using M= targets.If you do not supply
|
||||
any M= target, it is assumed you want to target the entire kernel.
|
||||
The kernel coccicheck script has:
|
||||
The kernel coccicheck script has::
|
||||
|
||||
if [ "$KBUILD_EXTMOD" = "" ] ; then
|
||||
OPTIONS="--dir $srctree $COCCIINCLUDE"
|
||||
|
@ -235,12 +248,12 @@ override any of the kernel's .coccicheck's settings using SPFLAGS.
|
|||
|
||||
We help Coccinelle when used against Linux with a set of sensible defaults
|
||||
options for Linux with our own Linux .cocciconfig. This hints to coccinelle
|
||||
git can be used for 'git grep' queries over coccigrep. A timeout of 200
|
||||
git can be used for ``git grep`` queries over coccigrep. A timeout of 200
|
||||
seconds should suffice for now.
|
||||
|
||||
The options picked up by coccinelle when reading a .cocciconfig do not appear
|
||||
as arguments to spatch processes running on your system, to confirm what
|
||||
options will be used by Coccinelle run:
|
||||
options will be used by Coccinelle run::
|
||||
|
||||
spatch --print-options-only
|
||||
|
||||
|
@ -252,219 +265,227 @@ carries its own .cocciconfig, you will need to use SPFLAGS to use idutils if
|
|||
desired. See below section "Additional flags" for more details on how to use
|
||||
idutils.
|
||||
|
||||
Additional flags
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
Additional flags
|
||||
----------------
|
||||
|
||||
Additional flags can be passed to spatch through the SPFLAGS
|
||||
variable. This works as Coccinelle respects the last flags
|
||||
given to it when options are in conflict.
|
||||
given to it when options are in conflict. ::
|
||||
|
||||
make SPFLAGS=--use-glimpse coccicheck
|
||||
|
||||
Coccinelle supports idutils as well but requires coccinelle >= 1.0.6.
|
||||
When no ID file is specified coccinelle assumes your ID database file
|
||||
is in the file .id-utils.index on the top level of the kernel, coccinelle
|
||||
carries a script scripts/idutils_index.sh which creates the database with
|
||||
carries a script scripts/idutils_index.sh which creates the database with::
|
||||
|
||||
mkid -i C --output .id-utils.index
|
||||
|
||||
If you have another database filename you can also just symlink with this
|
||||
name.
|
||||
name. ::
|
||||
|
||||
make SPFLAGS=--use-idutils coccicheck
|
||||
|
||||
Alternatively you can specify the database filename explicitly, for
|
||||
instance:
|
||||
instance::
|
||||
|
||||
make SPFLAGS="--use-idutils /full-path/to/ID" coccicheck
|
||||
|
||||
See spatch --help to learn more about spatch options.
|
||||
See ``spatch --help`` to learn more about spatch options.
|
||||
|
||||
Note that the '--use-glimpse' and '--use-idutils' options
|
||||
Note that the ``--use-glimpse`` and ``--use-idutils`` options
|
||||
require external tools for indexing the code. None of them is
|
||||
thus active by default. However, by indexing the code with
|
||||
one of these tools, and according to the cocci file used,
|
||||
spatch could proceed the entire code base more quickly.
|
||||
|
||||
SmPL patch specific options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
SmPL patch specific options
|
||||
---------------------------
|
||||
|
||||
SmPL patches can have their own requirements for options passed
|
||||
to Coccinelle. SmPL patch specific options can be provided by
|
||||
providing them at the top of the SmPL patch, for instance:
|
||||
providing them at the top of the SmPL patch, for instance::
|
||||
|
||||
// Options: --no-includes --include-headers
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
SmPL patch Coccinelle requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
SmPL patch Coccinelle requirements
|
||||
----------------------------------
|
||||
|
||||
As Coccinelle features get added some more advanced SmPL patches
|
||||
may require newer versions of Coccinelle. If an SmPL patch requires
|
||||
at least a version of Coccinelle, this can be specified as follows,
|
||||
as an example if requiring at least Coccinelle >= 1.0.5:
|
||||
as an example if requiring at least Coccinelle >= 1.0.5::
|
||||
|
||||
// Requires: 1.0.5
|
||||
// Requires: 1.0.5
|
||||
|
||||
Proposing new semantic patches
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Proposing new semantic patches
|
||||
-------------------------------
|
||||
|
||||
New semantic patches can be proposed and submitted by kernel
|
||||
developers. For sake of clarity, they should be organized in the
|
||||
sub-directories of 'scripts/coccinelle/'.
|
||||
sub-directories of ``scripts/coccinelle/``.
|
||||
|
||||
|
||||
Detailed description of the 'report' mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Detailed description of the ``report`` mode
|
||||
-------------------------------------------
|
||||
|
||||
``report`` generates a list in the following format::
|
||||
|
||||
'report' generates a list in the following format:
|
||||
file:line:column-column: message
|
||||
|
||||
Example:
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Running
|
||||
Running::
|
||||
|
||||
make coccicheck MODE=report COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||
|
||||
will execute the following part of the SmPL script.
|
||||
will execute the following part of the SmPL script::
|
||||
|
||||
<smpl>
|
||||
@r depends on !context && !patch && (org || report)@
|
||||
expression x;
|
||||
position p;
|
||||
@@
|
||||
<smpl>
|
||||
@r depends on !context && !patch && (org || report)@
|
||||
expression x;
|
||||
position p;
|
||||
@@
|
||||
|
||||
ERR_PTR@p(PTR_ERR(x))
|
||||
ERR_PTR@p(PTR_ERR(x))
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
|
||||
msg="ERR_CAST can be used with %s" % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
</smpl>
|
||||
msg="ERR_CAST can be used with %s" % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
</smpl>
|
||||
|
||||
This SmPL excerpt generates entries on the standard output, as
|
||||
illustrated below:
|
||||
illustrated below::
|
||||
|
||||
/home/user/linux/crypto/ctr.c:188:9-16: ERR_CAST can be used with alg
|
||||
/home/user/linux/crypto/authenc.c:619:9-16: ERR_CAST can be used with auth
|
||||
/home/user/linux/crypto/xts.c:227:9-16: ERR_CAST can be used with alg
|
||||
/home/user/linux/crypto/ctr.c:188:9-16: ERR_CAST can be used with alg
|
||||
/home/user/linux/crypto/authenc.c:619:9-16: ERR_CAST can be used with auth
|
||||
/home/user/linux/crypto/xts.c:227:9-16: ERR_CAST can be used with alg
|
||||
|
||||
|
||||
Detailed description of the 'patch' mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Detailed description of the ``patch`` mode
|
||||
------------------------------------------
|
||||
|
||||
When the 'patch' mode is available, it proposes a fix for each problem
|
||||
When the ``patch`` mode is available, it proposes a fix for each problem
|
||||
identified.
|
||||
|
||||
Example:
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Running::
|
||||
|
||||
Running
|
||||
make coccicheck MODE=patch COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||
|
||||
will execute the following part of the SmPL script.
|
||||
will execute the following part of the SmPL script::
|
||||
|
||||
<smpl>
|
||||
@ depends on !context && patch && !org && !report @
|
||||
expression x;
|
||||
@@
|
||||
<smpl>
|
||||
@ depends on !context && patch && !org && !report @
|
||||
expression x;
|
||||
@@
|
||||
|
||||
- ERR_PTR(PTR_ERR(x))
|
||||
+ ERR_CAST(x)
|
||||
</smpl>
|
||||
- ERR_PTR(PTR_ERR(x))
|
||||
+ ERR_CAST(x)
|
||||
</smpl>
|
||||
|
||||
This SmPL excerpt generates patch hunks on the standard output, as
|
||||
illustrated below:
|
||||
illustrated below::
|
||||
|
||||
diff -u -p a/crypto/ctr.c b/crypto/ctr.c
|
||||
--- a/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
||||
+++ b/crypto/ctr.c 2010-06-03 23:44:49.000000000 +0200
|
||||
@@ -185,7 +185,7 @@ static struct crypto_instance *crypto_ct
|
||||
diff -u -p a/crypto/ctr.c b/crypto/ctr.c
|
||||
--- a/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
||||
+++ b/crypto/ctr.c 2010-06-03 23:44:49.000000000 +0200
|
||||
@@ -185,7 +185,7 @@ static struct crypto_instance *crypto_ct
|
||||
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
|
||||
CRYPTO_ALG_TYPE_MASK);
|
||||
if (IS_ERR(alg))
|
||||
- return ERR_PTR(PTR_ERR(alg));
|
||||
+ return ERR_CAST(alg);
|
||||
|
||||
- return ERR_PTR(PTR_ERR(alg));
|
||||
+ return ERR_CAST(alg);
|
||||
|
||||
/* Block size must be >= 4 bytes. */
|
||||
err = -EINVAL;
|
||||
|
||||
Detailed description of the 'context' mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Detailed description of the ``context`` mode
|
||||
--------------------------------------------
|
||||
|
||||
'context' highlights lines of interest and their context
|
||||
``context`` highlights lines of interest and their context
|
||||
in a diff-like style.
|
||||
|
||||
NOTE: The diff-like output generated is NOT an applicable patch. The
|
||||
intent of the 'context' mode is to highlight the important lines
|
||||
(annotated with minus, '-') and gives some surrounding context
|
||||
**NOTE**: The diff-like output generated is NOT an applicable patch. The
|
||||
intent of the ``context`` mode is to highlight the important lines
|
||||
(annotated with minus, ``-``) and gives some surrounding context
|
||||
lines around. This output can be used with the diff mode of
|
||||
Emacs to review the code.
|
||||
|
||||
Example:
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Running::
|
||||
|
||||
Running
|
||||
make coccicheck MODE=context COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||
|
||||
will execute the following part of the SmPL script.
|
||||
will execute the following part of the SmPL script::
|
||||
|
||||
<smpl>
|
||||
@ depends on context && !patch && !org && !report@
|
||||
expression x;
|
||||
@@
|
||||
<smpl>
|
||||
@ depends on context && !patch && !org && !report@
|
||||
expression x;
|
||||
@@
|
||||
|
||||
* ERR_PTR(PTR_ERR(x))
|
||||
</smpl>
|
||||
* ERR_PTR(PTR_ERR(x))
|
||||
</smpl>
|
||||
|
||||
This SmPL excerpt generates diff hunks on the standard output, as
|
||||
illustrated below:
|
||||
illustrated below::
|
||||
|
||||
diff -u -p /home/user/linux/crypto/ctr.c /tmp/nothing
|
||||
--- /home/user/linux/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
||||
+++ /tmp/nothing
|
||||
@@ -185,7 +185,6 @@ static struct crypto_instance *crypto_ct
|
||||
diff -u -p /home/user/linux/crypto/ctr.c /tmp/nothing
|
||||
--- /home/user/linux/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
|
||||
+++ /tmp/nothing
|
||||
@@ -185,7 +185,6 @@ static struct crypto_instance *crypto_ct
|
||||
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
|
||||
CRYPTO_ALG_TYPE_MASK);
|
||||
if (IS_ERR(alg))
|
||||
- return ERR_PTR(PTR_ERR(alg));
|
||||
|
||||
- return ERR_PTR(PTR_ERR(alg));
|
||||
|
||||
/* Block size must be >= 4 bytes. */
|
||||
err = -EINVAL;
|
||||
|
||||
Detailed description of the 'org' mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Detailed description of the ``org`` mode
|
||||
----------------------------------------
|
||||
|
||||
'org' generates a report in the Org mode format of Emacs.
|
||||
``org`` generates a report in the Org mode format of Emacs.
|
||||
|
||||
Example:
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Running::
|
||||
|
||||
Running
|
||||
make coccicheck MODE=org COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||
|
||||
will execute the following part of the SmPL script.
|
||||
will execute the following part of the SmPL script::
|
||||
|
||||
<smpl>
|
||||
@r depends on !context && !patch && (org || report)@
|
||||
expression x;
|
||||
position p;
|
||||
@@
|
||||
<smpl>
|
||||
@r depends on !context && !patch && (org || report)@
|
||||
expression x;
|
||||
position p;
|
||||
@@
|
||||
|
||||
ERR_PTR@p(PTR_ERR(x))
|
||||
ERR_PTR@p(PTR_ERR(x))
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
|
||||
msg="ERR_CAST can be used with %s" % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
coccilib.org.print_todo(p[0], msg_safe)
|
||||
</smpl>
|
||||
msg="ERR_CAST can be used with %s" % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
coccilib.org.print_todo(p[0], msg_safe)
|
||||
</smpl>
|
||||
|
||||
This SmPL excerpt generates Org entries on the standard output, as
|
||||
illustrated below:
|
||||
illustrated below::
|
||||
|
||||
* TODO [[view:/home/user/linux/crypto/ctr.c::face=ovl-face1::linb=188::colb=9::cole=16][ERR_CAST can be used with alg]]
|
||||
* TODO [[view:/home/user/linux/crypto/authenc.c::face=ovl-face1::linb=619::colb=9::cole=16][ERR_CAST can be used with auth]]
|
||||
* TODO [[view:/home/user/linux/crypto/xts.c::face=ovl-face1::linb=227::colb=9::cole=16][ERR_CAST can be used with alg]]
|
||||
* TODO [[view:/home/user/linux/crypto/ctr.c::face=ovl-face1::linb=188::colb=9::cole=16][ERR_CAST can be used with alg]]
|
||||
* TODO [[view:/home/user/linux/crypto/authenc.c::face=ovl-face1::linb=619::colb=9::cole=16][ERR_CAST can be used with auth]]
|
||||
* TODO [[view:/home/user/linux/crypto/xts.c::face=ovl-face1::linb=227::colb=9::cole=16][ERR_CAST can be used with alg]]
|
|
@ -0,0 +1,256 @@
|
|||
Using gcov with the Linux kernel
|
||||
================================
|
||||
|
||||
gcov profiling kernel support enables the use of GCC's coverage testing
|
||||
tool gcov_ with the Linux kernel. Coverage data of a running kernel
|
||||
is exported in gcov-compatible format via the "gcov" debugfs directory.
|
||||
To get coverage data for a specific file, change to the kernel build
|
||||
directory and use gcov with the ``-o`` option as follows (requires root)::
|
||||
|
||||
# cd /tmp/linux-out
|
||||
# gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
|
||||
|
||||
This will create source code files annotated with execution counts
|
||||
in the current directory. In addition, graphical gcov front-ends such
|
||||
as lcov_ can be used to automate the process of collecting data
|
||||
for the entire kernel and provide coverage overviews in HTML format.
|
||||
|
||||
Possible uses:
|
||||
|
||||
* debugging (has this line been reached at all?)
|
||||
* test improvement (how do I change my test to cover these lines?)
|
||||
* minimizing kernel configurations (do I need this option if the
|
||||
associated code is never run?)
|
||||
|
||||
.. _gcov: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
|
||||
.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php
|
||||
|
||||
|
||||
Preparation
|
||||
-----------
|
||||
|
||||
Configure the kernel with::
|
||||
|
||||
CONFIG_DEBUG_FS=y
|
||||
CONFIG_GCOV_KERNEL=y
|
||||
|
||||
select the gcc's gcov format, default is autodetect based on gcc version::
|
||||
|
||||
CONFIG_GCOV_FORMAT_AUTODETECT=y
|
||||
|
||||
and to get coverage data for the entire kernel::
|
||||
|
||||
CONFIG_GCOV_PROFILE_ALL=y
|
||||
|
||||
Note that kernels compiled with profiling flags will be significantly
|
||||
larger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported
|
||||
on all architectures.
|
||||
|
||||
Profiling data will only become accessible once debugfs has been
|
||||
mounted::
|
||||
|
||||
mount -t debugfs none /sys/kernel/debug
|
||||
|
||||
|
||||
Customization
|
||||
-------------
|
||||
|
||||
To enable profiling for specific files or directories, add a line
|
||||
similar to the following to the respective kernel Makefile:
|
||||
|
||||
- For a single file (e.g. main.o)::
|
||||
|
||||
GCOV_PROFILE_main.o := y
|
||||
|
||||
- For all files in one directory::
|
||||
|
||||
GCOV_PROFILE := y
|
||||
|
||||
To exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL
|
||||
is specified, use::
|
||||
|
||||
GCOV_PROFILE_main.o := n
|
||||
|
||||
and::
|
||||
|
||||
GCOV_PROFILE := n
|
||||
|
||||
Only files which are linked to the main kernel image or are compiled as
|
||||
kernel modules are supported by this mechanism.
|
||||
|
||||
|
||||
Files
|
||||
-----
|
||||
|
||||
The gcov kernel support creates the following files in debugfs:
|
||||
|
||||
``/sys/kernel/debug/gcov``
|
||||
Parent directory for all gcov-related files.
|
||||
|
||||
``/sys/kernel/debug/gcov/reset``
|
||||
Global reset file: resets all coverage data to zero when
|
||||
written to.
|
||||
|
||||
``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda``
|
||||
The actual gcov data file as understood by the gcov
|
||||
tool. Resets file coverage data to zero when written to.
|
||||
|
||||
``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno``
|
||||
Symbolic link to a static data file required by the gcov
|
||||
tool. This file is generated by gcc when compiling with
|
||||
option ``-ftest-coverage``.
|
||||
|
||||
|
||||
Modules
|
||||
-------
|
||||
|
||||
Kernel modules may contain cleanup code which is only run during
|
||||
module unload time. The gcov mechanism provides a means to collect
|
||||
coverage data for such code by keeping a copy of the data associated
|
||||
with the unloaded module. This data remains available through debugfs.
|
||||
Once the module is loaded again, the associated coverage counters are
|
||||
initialized with the data from its previous instantiation.
|
||||
|
||||
This behavior can be deactivated by specifying the gcov_persist kernel
|
||||
parameter::
|
||||
|
||||
gcov_persist=0
|
||||
|
||||
At run-time, a user can also choose to discard data for an unloaded
|
||||
module by writing to its data file or the global reset file.
|
||||
|
||||
|
||||
Separated build and test machines
|
||||
---------------------------------
|
||||
|
||||
The gcov kernel profiling infrastructure is designed to work out-of-the
|
||||
box for setups where kernels are built and run on the same machine. In
|
||||
cases where the kernel runs on a separate machine, special preparations
|
||||
must be made, depending on where the gcov tool is used:
|
||||
|
||||
a) gcov is run on the TEST machine
|
||||
|
||||
The gcov tool version on the test machine must be compatible with the
|
||||
gcc version used for kernel build. Also the following files need to be
|
||||
copied from build to test machine:
|
||||
|
||||
from the source tree:
|
||||
- all C source files + headers
|
||||
|
||||
from the build tree:
|
||||
- all C source files + headers
|
||||
- all .gcda and .gcno files
|
||||
- all links to directories
|
||||
|
||||
It is important to note that these files need to be placed into the
|
||||
exact same file system location on the test machine as on the build
|
||||
machine. If any of the path components is symbolic link, the actual
|
||||
directory needs to be used instead (due to make's CURDIR handling).
|
||||
|
||||
b) gcov is run on the BUILD machine
|
||||
|
||||
The following files need to be copied after each test case from test
|
||||
to build machine:
|
||||
|
||||
from the gcov directory in sysfs:
|
||||
- all .gcda files
|
||||
- all links to .gcno files
|
||||
|
||||
These files can be copied to any location on the build machine. gcov
|
||||
must then be called with the -o option pointing to that directory.
|
||||
|
||||
Example directory setup on the build machine::
|
||||
|
||||
/tmp/linux: kernel source tree
|
||||
/tmp/out: kernel build directory as specified by make O=
|
||||
/tmp/coverage: location of the files copied from the test machine
|
||||
|
||||
[user@build] cd /tmp/out
|
||||
[user@build] gcov -o /tmp/coverage/tmp/out/init main.c
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
Problem
|
||||
Compilation aborts during linker step.
|
||||
|
||||
Cause
|
||||
Profiling flags are specified for source files which are not
|
||||
linked to the main kernel or which are linked by a custom
|
||||
linker procedure.
|
||||
|
||||
Solution
|
||||
Exclude affected source files from profiling by specifying
|
||||
``GCOV_PROFILE := n`` or ``GCOV_PROFILE_basename.o := n`` in the
|
||||
corresponding Makefile.
|
||||
|
||||
Problem
|
||||
Files copied from sysfs appear empty or incomplete.
|
||||
|
||||
Cause
|
||||
Due to the way seq_file works, some tools such as cp or tar
|
||||
may not correctly copy files from sysfs.
|
||||
|
||||
Solution
|
||||
Use ``cat``' to read ``.gcda`` files and ``cp -d`` to copy links.
|
||||
Alternatively use the mechanism shown in Appendix B.
|
||||
|
||||
|
||||
Appendix A: gather_on_build.sh
|
||||
------------------------------
|
||||
|
||||
Sample script to gather coverage meta files on the build machine
|
||||
(see 6a)::
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
KSRC=$1
|
||||
KOBJ=$2
|
||||
DEST=$3
|
||||
|
||||
if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
|
||||
echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
||||
KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
||||
|
||||
find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
|
||||
-perm /u+r,g+r | tar cfz $DEST -P -T -
|
||||
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo "$DEST successfully created, copy to test system and unpack with:"
|
||||
echo " tar xfz $DEST -P"
|
||||
else
|
||||
echo "Could not create file $DEST"
|
||||
fi
|
||||
|
||||
|
||||
Appendix B: gather_on_test.sh
|
||||
-----------------------------
|
||||
|
||||
Sample script to gather coverage data files on the test machine
|
||||
(see 6b)::
|
||||
|
||||
#!/bin/bash -e
|
||||
|
||||
DEST=$1
|
||||
GCDA=/sys/kernel/debug/gcov
|
||||
|
||||
if [ -z "$DEST" ] ; then
|
||||
echo "Usage: $0 <output.tar.gz>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TEMPDIR=$(mktemp -d)
|
||||
echo Collecting data..
|
||||
find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
|
||||
find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
|
||||
find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
|
||||
tar czf $DEST -C $TEMPDIR sys
|
||||
rm -rf $TEMPDIR
|
||||
|
||||
echo "$DEST successfully created, copy to build system and unpack with:"
|
||||
echo " tar xfz $DEST"
|
|
@ -1,3 +1,5 @@
|
|||
.. highlight:: none
|
||||
|
||||
Debugging kernel and modules via gdb
|
||||
====================================
|
||||
|
||||
|
@ -13,54 +15,58 @@ be transferred to the other gdb stubs as well.
|
|||
Requirements
|
||||
------------
|
||||
|
||||
o gdb 7.2+ (recommended: 7.4+) with python support enabled (typically true
|
||||
for distributions)
|
||||
- gdb 7.2+ (recommended: 7.4+) with python support enabled (typically true
|
||||
for distributions)
|
||||
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
o Create a virtual Linux machine for QEMU/KVM (see www.linux-kvm.org and
|
||||
www.qemu.org for more details). For cross-development,
|
||||
http://landley.net/aboriginal/bin keeps a pool of machine images and
|
||||
toolchains that can be helpful to start from.
|
||||
- Create a virtual Linux machine for QEMU/KVM (see www.linux-kvm.org and
|
||||
www.qemu.org for more details). For cross-development,
|
||||
http://landley.net/aboriginal/bin keeps a pool of machine images and
|
||||
toolchains that can be helpful to start from.
|
||||
|
||||
o Build the kernel with CONFIG_GDB_SCRIPTS enabled, but leave
|
||||
CONFIG_DEBUG_INFO_REDUCED off. If your architecture supports
|
||||
CONFIG_FRAME_POINTER, keep it enabled.
|
||||
- Build the kernel with CONFIG_GDB_SCRIPTS enabled, but leave
|
||||
CONFIG_DEBUG_INFO_REDUCED off. If your architecture supports
|
||||
CONFIG_FRAME_POINTER, keep it enabled.
|
||||
|
||||
o Install that kernel on the guest.
|
||||
- Install that kernel on the guest.
|
||||
Alternatively, QEMU allows to boot the kernel directly using -kernel,
|
||||
-append, -initrd command line switches. This is generally only useful if
|
||||
you do not depend on modules. See QEMU documentation for more details on
|
||||
this mode.
|
||||
|
||||
Alternatively, QEMU allows to boot the kernel directly using -kernel,
|
||||
-append, -initrd command line switches. This is generally only useful if
|
||||
you do not depend on modules. See QEMU documentation for more details on
|
||||
this mode.
|
||||
- Enable the gdb stub of QEMU/KVM, either
|
||||
|
||||
o Enable the gdb stub of QEMU/KVM, either
|
||||
- at VM startup time by appending "-s" to the QEMU command line
|
||||
or
|
||||
|
||||
or
|
||||
|
||||
- during runtime by issuing "gdbserver" from the QEMU monitor
|
||||
console
|
||||
|
||||
o cd /path/to/linux-build
|
||||
- cd /path/to/linux-build
|
||||
|
||||
o Start gdb: gdb vmlinux
|
||||
- Start gdb: gdb vmlinux
|
||||
|
||||
Note: Some distros may restrict auto-loading of gdb scripts to known safe
|
||||
directories. In case gdb reports to refuse loading vmlinux-gdb.py, add
|
||||
Note: Some distros may restrict auto-loading of gdb scripts to known safe
|
||||
directories. In case gdb reports to refuse loading vmlinux-gdb.py, add::
|
||||
|
||||
add-auto-load-safe-path /path/to/linux-build
|
||||
|
||||
to ~/.gdbinit. See gdb help for more details.
|
||||
to ~/.gdbinit. See gdb help for more details.
|
||||
|
||||
- Attach to the booted guest::
|
||||
|
||||
o Attach to the booted guest:
|
||||
(gdb) target remote :1234
|
||||
|
||||
|
||||
Examples of using the Linux-provided gdb helpers
|
||||
------------------------------------------------
|
||||
|
||||
o Load module (and main kernel) symbols:
|
||||
- Load module (and main kernel) symbols::
|
||||
|
||||
(gdb) lx-symbols
|
||||
loading vmlinux
|
||||
scanning for modules in /home/user/linux/build
|
||||
|
@ -72,17 +78,20 @@ Examples of using the Linux-provided gdb helpers
|
|||
...
|
||||
loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko
|
||||
|
||||
o Set a breakpoint on some not yet loaded module function, e.g.:
|
||||
- Set a breakpoint on some not yet loaded module function, e.g.::
|
||||
|
||||
(gdb) b btrfs_init_sysfs
|
||||
Function "btrfs_init_sysfs" not defined.
|
||||
Make breakpoint pending on future shared library load? (y or [n]) y
|
||||
Breakpoint 1 (btrfs_init_sysfs) pending.
|
||||
|
||||
o Continue the target
|
||||
- Continue the target::
|
||||
|
||||
(gdb) c
|
||||
|
||||
o Load the module on the target and watch the symbols being loaded as well as
|
||||
the breakpoint hit:
|
||||
- Load the module on the target and watch the symbols being loaded as well as
|
||||
the breakpoint hit::
|
||||
|
||||
loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko
|
||||
loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko
|
||||
loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko
|
||||
|
@ -91,7 +100,8 @@ Examples of using the Linux-provided gdb helpers
|
|||
Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36
|
||||
36 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
|
||||
|
||||
o Dump the log buffer of the target kernel:
|
||||
- Dump the log buffer of the target kernel::
|
||||
|
||||
(gdb) lx-dmesg
|
||||
[ 0.000000] Initializing cgroup subsys cpuset
|
||||
[ 0.000000] Initializing cgroup subsys cpu
|
||||
|
@ -102,19 +112,22 @@ Examples of using the Linux-provided gdb helpers
|
|||
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
|
||||
....
|
||||
|
||||
o Examine fields of the current task struct:
|
||||
- Examine fields of the current task struct::
|
||||
|
||||
(gdb) p $lx_current().pid
|
||||
$1 = 4998
|
||||
(gdb) p $lx_current().comm
|
||||
$2 = "modprobe\000\000\000\000\000\000\000"
|
||||
|
||||
o Make use of the per-cpu function for the current or a specified CPU:
|
||||
- Make use of the per-cpu function for the current or a specified CPU::
|
||||
|
||||
(gdb) p $lx_per_cpu("runqueues").nr_running
|
||||
$3 = 1
|
||||
(gdb) p $lx_per_cpu("runqueues", 2).nr_running
|
||||
$4 = 0
|
||||
|
||||
o Dig into hrtimers using the container_of helper:
|
||||
- Dig into hrtimers using the container_of helper::
|
||||
|
||||
(gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next
|
||||
(gdb) p *$container_of($next, "struct hrtimer", "node")
|
||||
$5 = {
|
||||
|
@ -144,7 +157,7 @@ List of commands and functions
|
|||
------------------------------
|
||||
|
||||
The number of commands and convenience functions may evolve over the time,
|
||||
this is just a snapshot of the initial version:
|
||||
this is just a snapshot of the initial version::
|
||||
|
||||
(gdb) apropos lx
|
||||
function lx_current -- Return current task
|
|
@ -0,0 +1,173 @@
|
|||
The Kernel Address Sanitizer (KASAN)
|
||||
====================================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
KernelAddressSANitizer (KASAN) is a dynamic memory error detector. It provides
|
||||
a fast and comprehensive solution for finding use-after-free and out-of-bounds
|
||||
bugs.
|
||||
|
||||
KASAN uses compile-time instrumentation for checking every memory access,
|
||||
therefore you will need a GCC version 4.9.2 or later. GCC 5.0 or later is
|
||||
required for detection of out-of-bounds accesses to stack or global variables.
|
||||
|
||||
Currently KASAN is supported only for the x86_64 and arm64 architectures.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To enable KASAN configure kernel with::
|
||||
|
||||
CONFIG_KASAN = y
|
||||
|
||||
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline and
|
||||
inline are compiler instrumentation types. The former produces smaller binary
|
||||
the latter is 1.1 - 2 times faster. Inline instrumentation requires a GCC
|
||||
version 5.0 or later.
|
||||
|
||||
KASAN works with both SLUB and SLAB memory allocators.
|
||||
For better bug detection and nicer reporting, enable CONFIG_STACKTRACE.
|
||||
|
||||
To disable instrumentation for specific files or directories, add a line
|
||||
similar to the following to the respective kernel Makefile:
|
||||
|
||||
- For a single file (e.g. main.o)::
|
||||
|
||||
KASAN_SANITIZE_main.o := n
|
||||
|
||||
- For all files in one directory::
|
||||
|
||||
KASAN_SANITIZE := n
|
||||
|
||||
Error reports
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
A typical out of bounds access report looks like this::
|
||||
|
||||
==================================================================
|
||||
BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
|
||||
Write of size 1 by task modprobe/1689
|
||||
=============================================================================
|
||||
BUG kmalloc-128 (Not tainted): kasan error
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Disabling lock debugging due to kernel taint
|
||||
INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689
|
||||
__slab_alloc+0x4b4/0x4f0
|
||||
kmem_cache_alloc_trace+0x10b/0x190
|
||||
kmalloc_oob_right+0x3d/0x75 [test_kasan]
|
||||
init_module+0x9/0x47 [test_kasan]
|
||||
do_one_initcall+0x99/0x200
|
||||
load_module+0x2cb3/0x3b20
|
||||
SyS_finit_module+0x76/0x80
|
||||
system_call_fastpath+0x12/0x17
|
||||
INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
|
||||
INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
|
||||
|
||||
Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
|
||||
Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
|
||||
Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........
|
||||
Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
|
||||
CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98
|
||||
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
|
||||
ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78
|
||||
ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8
|
||||
ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558
|
||||
Call Trace:
|
||||
[<ffffffff81cc68ae>] dump_stack+0x46/0x58
|
||||
[<ffffffff811fd848>] print_trailer+0xf8/0x160
|
||||
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
||||
[<ffffffff811ff0f5>] object_err+0x35/0x40
|
||||
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||
[<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0
|
||||
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
||||
[<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40
|
||||
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
||||
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
||||
[<ffffffff8120a995>] __asan_store1+0x75/0xb0
|
||||
[<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]
|
||||
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||
[<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||
[<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan]
|
||||
[<ffffffff810002d9>] do_one_initcall+0x99/0x200
|
||||
[<ffffffff811e4e5c>] ? __vunmap+0xec/0x160
|
||||
[<ffffffff81114f63>] load_module+0x2cb3/0x3b20
|
||||
[<ffffffff8110fd70>] ? m_show+0x240/0x240
|
||||
[<ffffffff81115f06>] SyS_finit_module+0x76/0x80
|
||||
[<ffffffff81cd3129>] system_call_fastpath+0x12/0x17
|
||||
Memory state around the buggy address:
|
||||
ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
|
||||
ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
|
||||
>ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
|
||||
^
|
||||
ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
==================================================================
|
||||
|
||||
The header of the report discribe what kind of bug happened and what kind of
|
||||
access caused it. It's followed by the description of the accessed slub object
|
||||
(see 'SLUB Debug output' section in Documentation/vm/slub.txt for details) and
|
||||
the description of the accessed memory page.
|
||||
|
||||
In the last section the report shows memory state around the accessed address.
|
||||
Reading this part requires some understanding of how KASAN works.
|
||||
|
||||
The state of each 8 aligned bytes of memory is encoded in one shadow byte.
|
||||
Those 8 bytes can be accessible, partially accessible, freed or be a redzone.
|
||||
We use the following encoding for each shadow byte: 0 means that all 8 bytes
|
||||
of the corresponding memory region are accessible; number N (1 <= N <= 7) means
|
||||
that the first N bytes are accessible, and other (8 - N) bytes are not;
|
||||
any negative value indicates that the entire 8-byte word is inaccessible.
|
||||
We use different negative values to distinguish between different kinds of
|
||||
inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
|
||||
|
||||
In the report above the arrows point to the shadow byte 03, which means that
|
||||
the accessed address is partially accessible.
|
||||
|
||||
|
||||
Implementation details
|
||||
----------------------
|
||||
|
||||
From a high level, our approach to memory error detection is similar to that
|
||||
of kmemcheck: use shadow memory to record whether each byte of memory is safe
|
||||
to access, and use compile-time instrumentation to check shadow memory on each
|
||||
memory access.
|
||||
|
||||
AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
|
||||
(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
|
||||
offset to translate a memory address to its corresponding shadow address.
|
||||
|
||||
Here is the function which translates an address to its corresponding shadow
|
||||
address::
|
||||
|
||||
static inline void *kasan_mem_to_shadow(const void *addr)
|
||||
{
|
||||
return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
|
||||
+ KASAN_SHADOW_OFFSET;
|
||||
}
|
||||
|
||||
where ``KASAN_SHADOW_SCALE_SHIFT = 3``.
|
||||
|
||||
Compile-time instrumentation used for checking memory accesses. Compiler inserts
|
||||
function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
|
||||
access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
|
||||
valid or not by checking corresponding shadow memory.
|
||||
|
||||
GCC 5.0 has possibility to perform inline instrumentation. Instead of making
|
||||
function calls GCC directly inserts the code to check the shadow memory.
|
||||
This option significantly enlarges kernel but it gives x1.1-x2 performance
|
||||
boost over outline instrumented kernel.
|
|
@ -12,38 +12,38 @@ To achieve this goal it does not collect coverage in soft/hard interrupts
|
|||
and instrumentation of some inherently non-deterministic parts of kernel is
|
||||
disbled (e.g. scheduler, locking).
|
||||
|
||||
Usage:
|
||||
======
|
||||
Usage
|
||||
-----
|
||||
|
||||
Configure kernel with:
|
||||
Configure the kernel with::
|
||||
|
||||
CONFIG_KCOV=y
|
||||
|
||||
CONFIG_KCOV requires gcc built on revision 231296 or later.
|
||||
Profiling data will only become accessible once debugfs has been mounted:
|
||||
Profiling data will only become accessible once debugfs has been mounted::
|
||||
|
||||
mount -t debugfs none /sys/kernel/debug
|
||||
|
||||
The following program demonstrates kcov usage from within a test program:
|
||||
The following program demonstrates kcov usage from within a test program::
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
|
||||
#define KCOV_ENABLE _IO('c', 100)
|
||||
#define KCOV_DISABLE _IO('c', 101)
|
||||
#define COVER_SIZE (64<<10)
|
||||
#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
|
||||
#define KCOV_ENABLE _IO('c', 100)
|
||||
#define KCOV_DISABLE _IO('c', 101)
|
||||
#define COVER_SIZE (64<<10)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
unsigned long *cover, n, i;
|
||||
|
||||
|
@ -83,24 +83,24 @@ int main(int argc, char **argv)
|
|||
if (close(fd))
|
||||
perror("close"), exit(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
After piping through addr2line output of the program looks as follows:
|
||||
After piping through addr2line output of the program looks as follows::
|
||||
|
||||
SyS_read
|
||||
fs/read_write.c:562
|
||||
__fdget_pos
|
||||
fs/file.c:774
|
||||
__fget_light
|
||||
fs/file.c:746
|
||||
__fget_light
|
||||
fs/file.c:750
|
||||
__fget_light
|
||||
fs/file.c:760
|
||||
__fdget_pos
|
||||
fs/file.c:784
|
||||
SyS_read
|
||||
fs/read_write.c:562
|
||||
SyS_read
|
||||
fs/read_write.c:562
|
||||
__fdget_pos
|
||||
fs/file.c:774
|
||||
__fget_light
|
||||
fs/file.c:746
|
||||
__fget_light
|
||||
fs/file.c:750
|
||||
__fget_light
|
||||
fs/file.c:760
|
||||
__fdget_pos
|
||||
fs/file.c:784
|
||||
SyS_read
|
||||
fs/read_write.c:562
|
||||
|
||||
If a program needs to collect coverage from several threads (independently),
|
||||
it needs to open /sys/kernel/debug/kcov in each thread separately.
|
|
@ -0,0 +1,733 @@
|
|||
Getting started with kmemcheck
|
||||
==============================
|
||||
|
||||
Vegard Nossum <vegardno@ifi.uio.no>
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
kmemcheck is a debugging feature for the Linux Kernel. More specifically, it
|
||||
is a dynamic checker that detects and warns about some uses of uninitialized
|
||||
memory.
|
||||
|
||||
Userspace programmers might be familiar with Valgrind's memcheck. The main
|
||||
difference between memcheck and kmemcheck is that memcheck works for userspace
|
||||
programs only, and kmemcheck works for the kernel only. The implementations
|
||||
are of course vastly different. Because of this, kmemcheck is not as accurate
|
||||
as memcheck, but it turns out to be good enough in practice to discover real
|
||||
programmer errors that the compiler is not able to find through static
|
||||
analysis.
|
||||
|
||||
Enabling kmemcheck on a kernel will probably slow it down to the extent that
|
||||
the machine will not be usable for normal workloads such as e.g. an
|
||||
interactive desktop. kmemcheck will also cause the kernel to use about twice
|
||||
as much memory as normal. For this reason, kmemcheck is strictly a debugging
|
||||
feature.
|
||||
|
||||
|
||||
Downloading
|
||||
-----------
|
||||
|
||||
As of version 2.6.31-rc1, kmemcheck is included in the mainline kernel.
|
||||
|
||||
|
||||
Configuring and compiling
|
||||
-------------------------
|
||||
|
||||
kmemcheck only works for the x86 (both 32- and 64-bit) platform. A number of
|
||||
configuration variables must have specific settings in order for the kmemcheck
|
||||
menu to even appear in "menuconfig". These are:
|
||||
|
||||
- ``CONFIG_CC_OPTIMIZE_FOR_SIZE=n``
|
||||
This option is located under "General setup" / "Optimize for size".
|
||||
|
||||
Without this, gcc will use certain optimizations that usually lead to
|
||||
false positive warnings from kmemcheck. An example of this is a 16-bit
|
||||
field in a struct, where gcc may load 32 bits, then discard the upper
|
||||
16 bits. kmemcheck sees only the 32-bit load, and may trigger a
|
||||
warning for the upper 16 bits (if they're uninitialized).
|
||||
|
||||
- ``CONFIG_SLAB=y`` or ``CONFIG_SLUB=y``
|
||||
This option is located under "General setup" / "Choose SLAB
|
||||
allocator".
|
||||
|
||||
- ``CONFIG_FUNCTION_TRACER=n``
|
||||
This option is located under "Kernel hacking" / "Tracers" / "Kernel
|
||||
Function Tracer"
|
||||
|
||||
When function tracing is compiled in, gcc emits a call to another
|
||||
function at the beginning of every function. This means that when the
|
||||
page fault handler is called, the ftrace framework will be called
|
||||
before kmemcheck has had a chance to handle the fault. If ftrace then
|
||||
modifies memory that was tracked by kmemcheck, the result is an
|
||||
endless recursive page fault.
|
||||
|
||||
- ``CONFIG_DEBUG_PAGEALLOC=n``
|
||||
This option is located under "Kernel hacking" / "Memory Debugging"
|
||||
/ "Debug page memory allocations".
|
||||
|
||||
In addition, I highly recommend turning on ``CONFIG_DEBUG_INFO=y``. This is also
|
||||
located under "Kernel hacking". With this, you will be able to get line number
|
||||
information from the kmemcheck warnings, which is extremely valuable in
|
||||
debugging a problem. This option is not mandatory, however, because it slows
|
||||
down the compilation process and produces a much bigger kernel image.
|
||||
|
||||
Now the kmemcheck menu should be visible (under "Kernel hacking" / "Memory
|
||||
Debugging" / "kmemcheck: trap use of uninitialized memory"). Here follows
|
||||
a description of the kmemcheck configuration variables:
|
||||
|
||||
- ``CONFIG_KMEMCHECK``
|
||||
This must be enabled in order to use kmemcheck at all...
|
||||
|
||||
- ``CONFIG_KMEMCHECK_``[``DISABLED`` | ``ENABLED`` | ``ONESHOT``]``_BY_DEFAULT``
|
||||
This option controls the status of kmemcheck at boot-time. "Enabled"
|
||||
will enable kmemcheck right from the start, "disabled" will boot the
|
||||
kernel as normal (but with the kmemcheck code compiled in, so it can
|
||||
be enabled at run-time after the kernel has booted), and "one-shot" is
|
||||
a special mode which will turn kmemcheck off automatically after
|
||||
detecting the first use of uninitialized memory.
|
||||
|
||||
If you are using kmemcheck to actively debug a problem, then you
|
||||
probably want to choose "enabled" here.
|
||||
|
||||
The one-shot mode is mostly useful in automated test setups because it
|
||||
can prevent floods of warnings and increase the chances of the machine
|
||||
surviving in case something is really wrong. In other cases, the one-
|
||||
shot mode could actually be counter-productive because it would turn
|
||||
itself off at the very first error -- in the case of a false positive
|
||||
too -- and this would come in the way of debugging the specific
|
||||
problem you were interested in.
|
||||
|
||||
If you would like to use your kernel as normal, but with a chance to
|
||||
enable kmemcheck in case of some problem, it might be a good idea to
|
||||
choose "disabled" here. When kmemcheck is disabled, most of the run-
|
||||
time overhead is not incurred, and the kernel will be almost as fast
|
||||
as normal.
|
||||
|
||||
- ``CONFIG_KMEMCHECK_QUEUE_SIZE``
|
||||
Select the maximum number of error reports to store in an internal
|
||||
(fixed-size) buffer. Since errors can occur virtually anywhere and in
|
||||
any context, we need a temporary storage area which is guaranteed not
|
||||
to generate any other page faults when accessed. The queue will be
|
||||
emptied as soon as a tasklet may be scheduled. If the queue is full,
|
||||
new error reports will be lost.
|
||||
|
||||
The default value of 64 is probably fine. If some code produces more
|
||||
than 64 errors within an irqs-off section, then the code is likely to
|
||||
produce many, many more, too, and these additional reports seldom give
|
||||
any more information (the first report is usually the most valuable
|
||||
anyway).
|
||||
|
||||
This number might have to be adjusted if you are not using serial
|
||||
console or similar to capture the kernel log. If you are using the
|
||||
"dmesg" command to save the log, then getting a lot of kmemcheck
|
||||
warnings might overflow the kernel log itself, and the earlier reports
|
||||
will get lost in that way instead. Try setting this to 10 or so on
|
||||
such a setup.
|
||||
|
||||
- ``CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT``
|
||||
Select the number of shadow bytes to save along with each entry of the
|
||||
error-report queue. These bytes indicate what parts of an allocation
|
||||
are initialized, uninitialized, etc. and will be displayed when an
|
||||
error is detected to help the debugging of a particular problem.
|
||||
|
||||
The number entered here is actually the logarithm of the number of
|
||||
bytes that will be saved. So if you pick for example 5 here, kmemcheck
|
||||
will save 2^5 = 32 bytes.
|
||||
|
||||
The default value should be fine for debugging most problems. It also
|
||||
fits nicely within 80 columns.
|
||||
|
||||
- ``CONFIG_KMEMCHECK_PARTIAL_OK``
|
||||
This option (when enabled) works around certain GCC optimizations that
|
||||
produce 32-bit reads from 16-bit variables where the upper 16 bits are
|
||||
thrown away afterwards.
|
||||
|
||||
The default value (enabled) is recommended. This may of course hide
|
||||
some real errors, but disabling it would probably produce a lot of
|
||||
false positives.
|
||||
|
||||
- ``CONFIG_KMEMCHECK_BITOPS_OK``
|
||||
This option silences warnings that would be generated for bit-field
|
||||
accesses where not all the bits are initialized at the same time. This
|
||||
may also hide some real bugs.
|
||||
|
||||
This option is probably obsolete, or it should be replaced with
|
||||
the kmemcheck-/bitfield-annotations for the code in question. The
|
||||
default value is therefore fine.
|
||||
|
||||
Now compile the kernel as usual.
|
||||
|
||||
|
||||
How to use
|
||||
----------
|
||||
|
||||
Booting
|
||||
~~~~~~~
|
||||
|
||||
First some information about the command-line options. There is only one
|
||||
option specific to kmemcheck, and this is called "kmemcheck". It can be used
|
||||
to override the default mode as chosen by the ``CONFIG_KMEMCHECK_*_BY_DEFAULT``
|
||||
option. Its possible settings are:
|
||||
|
||||
- ``kmemcheck=0`` (disabled)
|
||||
- ``kmemcheck=1`` (enabled)
|
||||
- ``kmemcheck=2`` (one-shot mode)
|
||||
|
||||
If SLUB debugging has been enabled in the kernel, it may take precedence over
|
||||
kmemcheck in such a way that the slab caches which are under SLUB debugging
|
||||
will not be tracked by kmemcheck. In order to ensure that this doesn't happen
|
||||
(even though it shouldn't by default), use SLUB's boot option ``slub_debug``,
|
||||
like this: ``slub_debug=-``
|
||||
|
||||
In fact, this option may also be used for fine-grained control over SLUB vs.
|
||||
kmemcheck. For example, if the command line includes
|
||||
``kmemcheck=1 slub_debug=,dentry``, then SLUB debugging will be used only
|
||||
for the "dentry" slab cache, and with kmemcheck tracking all the other
|
||||
caches. This is advanced usage, however, and is not generally recommended.
|
||||
|
||||
|
||||
Run-time enable/disable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When the kernel has booted, it is possible to enable or disable kmemcheck at
|
||||
run-time. WARNING: This feature is still experimental and may cause false
|
||||
positive warnings to appear. Therefore, try not to use this. If you find that
|
||||
it doesn't work properly (e.g. you see an unreasonable amount of warnings), I
|
||||
will be happy to take bug reports.
|
||||
|
||||
Use the file ``/proc/sys/kernel/kmemcheck`` for this purpose, e.g.::
|
||||
|
||||
$ echo 0 > /proc/sys/kernel/kmemcheck # disables kmemcheck
|
||||
|
||||
The numbers are the same as for the ``kmemcheck=`` command-line option.
|
||||
|
||||
|
||||
Debugging
|
||||
~~~~~~~~~
|
||||
|
||||
A typical report will look something like this::
|
||||
|
||||
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||
^
|
||||
|
||||
Pid: 1856, comm: ntpdate Not tainted 2.6.29-rc5 #264 945P-A
|
||||
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
||||
RSP: 0018:ffff88003cdf7d98 EFLAGS: 00210002
|
||||
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
||||
RDX: ffff88003e5d6018 RSI: ffff88003e5d6024 RDI: ffff88003cdf7e84
|
||||
RBP: ffff88003cdf7db8 R08: ffff88003e5d6000 R09: 0000000000000000
|
||||
R10: 0000000000000080 R11: 0000000000000000 R12: 000000000000000e
|
||||
R13: ffff88003cdf7e78 R14: ffff88003d530710 R15: ffff88003d5a98c8
|
||||
FS: 0000000000000000(0000) GS:ffff880001982000(0063) knlGS:00000
|
||||
CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033
|
||||
CR2: ffff88003f806ea0 CR3: 000000003c036000 CR4: 00000000000006a0
|
||||
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400
|
||||
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
||||
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
||||
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
||||
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
||||
[<ffffffffffffffff>] 0xffffffffffffffff
|
||||
|
||||
The single most valuable information in this report is the RIP (or EIP on 32-
|
||||
bit) value. This will help us pinpoint exactly which instruction that caused
|
||||
the warning.
|
||||
|
||||
If your kernel was compiled with ``CONFIG_DEBUG_INFO=y``, then all we have to do
|
||||
is give this address to the addr2line program, like this::
|
||||
|
||||
$ addr2line -e vmlinux -i ffffffff8104ede8
|
||||
arch/x86/include/asm/string_64.h:12
|
||||
include/asm-generic/siginfo.h:287
|
||||
kernel/signal.c:380
|
||||
kernel/signal.c:410
|
||||
|
||||
The "``-e vmlinux``" tells addr2line which file to look in. **IMPORTANT:**
|
||||
This must be the vmlinux of the kernel that produced the warning in the
|
||||
first place! If not, the line number information will almost certainly be
|
||||
wrong.
|
||||
|
||||
The "``-i``" tells addr2line to also print the line numbers of inlined
|
||||
functions. In this case, the flag was very important, because otherwise,
|
||||
it would only have printed the first line, which is just a call to
|
||||
``memcpy()``, which could be called from a thousand places in the kernel, and
|
||||
is therefore not very useful. These inlined functions would not show up in
|
||||
the stack trace above, simply because the kernel doesn't load the extra
|
||||
debugging information. This technique can of course be used with ordinary
|
||||
kernel oopses as well.
|
||||
|
||||
In this case, it's the caller of ``memcpy()`` that is interesting, and it can be
|
||||
found in ``include/asm-generic/siginfo.h``, line 287::
|
||||
|
||||
281 static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
|
||||
282 {
|
||||
283 if (from->si_code < 0)
|
||||
284 memcpy(to, from, sizeof(*to));
|
||||
285 else
|
||||
286 /* _sigchld is currently the largest know union member */
|
||||
287 memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
|
||||
288 }
|
||||
|
||||
Since this was a read (kmemcheck usually warns about reads only, though it can
|
||||
warn about writes to unallocated or freed memory as well), it was probably the
|
||||
"from" argument which contained some uninitialized bytes. Following the chain
|
||||
of calls, we move upwards to see where "from" was allocated or initialized,
|
||||
``kernel/signal.c``, line 380::
|
||||
|
||||
359 static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
|
||||
360 {
|
||||
...
|
||||
367 list_for_each_entry(q, &list->list, list) {
|
||||
368 if (q->info.si_signo == sig) {
|
||||
369 if (first)
|
||||
370 goto still_pending;
|
||||
371 first = q;
|
||||
...
|
||||
377 if (first) {
|
||||
378 still_pending:
|
||||
379 list_del_init(&first->list);
|
||||
380 copy_siginfo(info, &first->info);
|
||||
381 __sigqueue_free(first);
|
||||
...
|
||||
392 }
|
||||
393 }
|
||||
|
||||
Here, it is ``&first->info`` that is being passed on to ``copy_siginfo()``. The
|
||||
variable ``first`` was found on a list -- passed in as the second argument to
|
||||
``collect_signal()``. We continue our journey through the stack, to figure out
|
||||
where the item on "list" was allocated or initialized. We move to line 410::
|
||||
|
||||
395 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
|
||||
396 siginfo_t *info)
|
||||
397 {
|
||||
...
|
||||
410 collect_signal(sig, pending, info);
|
||||
...
|
||||
414 }
|
||||
|
||||
Now we need to follow the ``pending`` pointer, since that is being passed on to
|
||||
``collect_signal()`` as ``list``. At this point, we've run out of lines from the
|
||||
"addr2line" output. Not to worry, we just paste the next addresses from the
|
||||
kmemcheck stack dump, i.e.::
|
||||
|
||||
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
||||
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
||||
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
||||
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
||||
|
||||
$ addr2line -e vmlinux -i ffffffff8104f04e ffffffff81050bd8 \
|
||||
ffffffff8100b87d ffffffff8100c7b5
|
||||
kernel/signal.c:446
|
||||
kernel/signal.c:1806
|
||||
arch/x86/kernel/signal.c:805
|
||||
arch/x86/kernel/signal.c:871
|
||||
arch/x86/kernel/entry_64.S:694
|
||||
|
||||
Remember that since these addresses were found on the stack and not as the
|
||||
RIP value, they actually point to the _next_ instruction (they are return
|
||||
addresses). This becomes obvious when we look at the code for line 446::
|
||||
|
||||
422 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
|
||||
423 {
|
||||
...
|
||||
431 signr = __dequeue_signal(&tsk->signal->shared_pending,
|
||||
432 mask, info);
|
||||
433 /*
|
||||
434 * itimer signal ?
|
||||
435 *
|
||||
436 * itimers are process shared and we restart periodic
|
||||
437 * itimers in the signal delivery path to prevent DoS
|
||||
438 * attacks in the high resolution timer case. This is
|
||||
439 * compliant with the old way of self restarting
|
||||
440 * itimers, as the SIGALRM is a legacy signal and only
|
||||
441 * queued once. Changing the restart behaviour to
|
||||
442 * restart the timer in the signal dequeue path is
|
||||
443 * reducing the timer noise on heavy loaded !highres
|
||||
444 * systems too.
|
||||
445 */
|
||||
446 if (unlikely(signr == SIGALRM)) {
|
||||
...
|
||||
489 }
|
||||
|
||||
So instead of looking at 446, we should be looking at 431, which is the line
|
||||
that executes just before 446. Here we see that what we are looking for is
|
||||
``&tsk->signal->shared_pending``.
|
||||
|
||||
Our next task is now to figure out which function that puts items on this
|
||||
``shared_pending`` list. A crude, but efficient tool, is ``git grep``::
|
||||
|
||||
$ git grep -n 'shared_pending' kernel/
|
||||
...
|
||||
kernel/signal.c:828: pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
kernel/signal.c:1339: pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
...
|
||||
|
||||
There were more results, but none of them were related to list operations,
|
||||
and these were the only assignments. We inspect the line numbers more closely
|
||||
and find that this is indeed where items are being added to the list::
|
||||
|
||||
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
||||
817 int group)
|
||||
818 {
|
||||
...
|
||||
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
...
|
||||
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
||||
852 (is_si_special(info) ||
|
||||
853 info->si_code >= 0)));
|
||||
854 if (q) {
|
||||
855 list_add_tail(&q->list, &pending->list);
|
||||
...
|
||||
890 }
|
||||
|
||||
and::
|
||||
|
||||
1309 int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
|
||||
1310 {
|
||||
....
|
||||
1339 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
1340 list_add_tail(&q->list, &pending->list);
|
||||
....
|
||||
1347 }
|
||||
|
||||
In the first case, the list element we are looking for, ``q``, is being
|
||||
returned from the function ``__sigqueue_alloc()``, which looks like an
|
||||
allocation function. Let's take a look at it::
|
||||
|
||||
187 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
|
||||
188 int override_rlimit)
|
||||
189 {
|
||||
190 struct sigqueue *q = NULL;
|
||||
191 struct user_struct *user;
|
||||
192
|
||||
193 /*
|
||||
194 * We won't get problems with the target's UID changing under us
|
||||
195 * because changing it requires RCU be used, and if t != current, the
|
||||
196 * caller must be holding the RCU readlock (by way of a spinlock) and
|
||||
197 * we use RCU protection here
|
||||
198 */
|
||||
199 user = get_uid(__task_cred(t)->user);
|
||||
200 atomic_inc(&user->sigpending);
|
||||
201 if (override_rlimit ||
|
||||
202 atomic_read(&user->sigpending) <=
|
||||
203 t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
|
||||
204 q = kmem_cache_alloc(sigqueue_cachep, flags);
|
||||
205 if (unlikely(q == NULL)) {
|
||||
206 atomic_dec(&user->sigpending);
|
||||
207 free_uid(user);
|
||||
208 } else {
|
||||
209 INIT_LIST_HEAD(&q->list);
|
||||
210 q->flags = 0;
|
||||
211 q->user = user;
|
||||
212 }
|
||||
213
|
||||
214 return q;
|
||||
215 }
|
||||
|
||||
We see that this function initializes ``q->list``, ``q->flags``, and
|
||||
``q->user``. It seems that now is the time to look at the definition of
|
||||
``struct sigqueue``, e.g.::
|
||||
|
||||
14 struct sigqueue {
|
||||
15 struct list_head list;
|
||||
16 int flags;
|
||||
17 siginfo_t info;
|
||||
18 struct user_struct *user;
|
||||
19 };
|
||||
|
||||
And, you might remember, it was a ``memcpy()`` on ``&first->info`` that
|
||||
caused the warning, so this makes perfect sense. It also seems reasonable
|
||||
to assume that it is the caller of ``__sigqueue_alloc()`` that has the
|
||||
responsibility of filling out (initializing) this member.
|
||||
|
||||
But just which fields of the struct were uninitialized? Let's look at
|
||||
kmemcheck's report again::
|
||||
|
||||
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||
^
|
||||
|
||||
These first two lines are the memory dump of the memory object itself, and
|
||||
the shadow bytemap, respectively. The memory object itself is in this case
|
||||
``&first->info``. Just beware that the start of this dump is NOT the start
|
||||
of the object itself! The position of the caret (^) corresponds with the
|
||||
address of the read (ffff88003e4a2024).
|
||||
|
||||
The shadow bytemap dump legend is as follows:
|
||||
|
||||
- i: initialized
|
||||
- u: uninitialized
|
||||
- a: unallocated (memory has been allocated by the slab layer, but has not
|
||||
yet been handed off to anybody)
|
||||
- f: freed (memory has been allocated by the slab layer, but has been freed
|
||||
by the previous owner)
|
||||
|
||||
In order to figure out where (relative to the start of the object) the
|
||||
uninitialized memory was located, we have to look at the disassembly. For
|
||||
that, we'll need the RIP address again::
|
||||
|
||||
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
||||
|
||||
$ objdump -d --no-show-raw-insn vmlinux | grep -C 8 ffffffff8104ede8:
|
||||
ffffffff8104edc8: mov %r8,0x8(%r8)
|
||||
ffffffff8104edcc: test %r10d,%r10d
|
||||
ffffffff8104edcf: js ffffffff8104ee88 <__dequeue_signal+0x168>
|
||||
ffffffff8104edd5: mov %rax,%rdx
|
||||
ffffffff8104edd8: mov $0xc,%ecx
|
||||
ffffffff8104eddd: mov %r13,%rdi
|
||||
ffffffff8104ede0: mov $0x30,%eax
|
||||
ffffffff8104ede5: mov %rdx,%rsi
|
||||
ffffffff8104ede8: rep movsl %ds:(%rsi),%es:(%rdi)
|
||||
ffffffff8104edea: test $0x2,%al
|
||||
ffffffff8104edec: je ffffffff8104edf0 <__dequeue_signal+0xd0>
|
||||
ffffffff8104edee: movsw %ds:(%rsi),%es:(%rdi)
|
||||
ffffffff8104edf0: test $0x1,%al
|
||||
ffffffff8104edf2: je ffffffff8104edf5 <__dequeue_signal+0xd5>
|
||||
ffffffff8104edf4: movsb %ds:(%rsi),%es:(%rdi)
|
||||
ffffffff8104edf5: mov %r8,%rdi
|
||||
ffffffff8104edf8: callq ffffffff8104de60 <__sigqueue_free>
|
||||
|
||||
As expected, it's the "``rep movsl``" instruction from the ``memcpy()``
|
||||
that causes the warning. We know about ``REP MOVSL`` that it uses the register
|
||||
``RCX`` to count the number of remaining iterations. By taking a look at the
|
||||
register dump again (from the kmemcheck report), we can figure out how many
|
||||
bytes were left to copy::
|
||||
|
||||
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
||||
|
||||
By looking at the disassembly, we also see that ``%ecx`` is being loaded
|
||||
with the value ``$0xc`` just before (ffffffff8104edd8), so we are very
|
||||
lucky. Keep in mind that this is the number of iterations, not bytes. And
|
||||
since this is a "long" operation, we need to multiply by 4 to get the
|
||||
number of bytes. So this means that the uninitialized value was encountered
|
||||
at 4 * (0xc - 0x9) = 12 bytes from the start of the object.
|
||||
|
||||
We can now try to figure out which field of the "``struct siginfo``" that
|
||||
was not initialized. This is the beginning of the struct::
|
||||
|
||||
40 typedef struct siginfo {
|
||||
41 int si_signo;
|
||||
42 int si_errno;
|
||||
43 int si_code;
|
||||
44
|
||||
45 union {
|
||||
..
|
||||
92 } _sifields;
|
||||
93 } siginfo_t;
|
||||
|
||||
On 64-bit, the int is 4 bytes long, so it must the union member that has
|
||||
not been initialized. We can verify this using gdb::
|
||||
|
||||
$ gdb vmlinux
|
||||
...
|
||||
(gdb) p &((struct siginfo *) 0)->_sifields
|
||||
$1 = (union {...} *) 0x10
|
||||
|
||||
Actually, it seems that the union member is located at offset 0x10 -- which
|
||||
means that gcc has inserted 4 bytes of padding between the members ``si_code``
|
||||
and ``_sifields``. We can now get a fuller picture of the memory dump::
|
||||
|
||||
_----------------------------=> si_code
|
||||
/ _--------------------=> (padding)
|
||||
| / _------------=> _sifields(._kill._pid)
|
||||
| | / _----=> _sifields(._kill._uid)
|
||||
| | | /
|
||||
-------|-------|-------|-------|
|
||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||
|
||||
This allows us to realize another important fact: ``si_code`` contains the
|
||||
value 0x80. Remember that x86 is little endian, so the first 4 bytes
|
||||
"80000000" are really the number 0x00000080. With a bit of research, we
|
||||
find that this is actually the constant ``SI_KERNEL`` defined in
|
||||
``include/asm-generic/siginfo.h``::
|
||||
|
||||
144 #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
||||
|
||||
This macro is used in exactly one place in the x86 kernel: In ``send_signal()``
|
||||
in ``kernel/signal.c``::
|
||||
|
||||
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
||||
817 int group)
|
||||
818 {
|
||||
...
|
||||
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
...
|
||||
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
||||
852 (is_si_special(info) ||
|
||||
853 info->si_code >= 0)));
|
||||
854 if (q) {
|
||||
855 list_add_tail(&q->list, &pending->list);
|
||||
856 switch ((unsigned long) info) {
|
||||
...
|
||||
865 case (unsigned long) SEND_SIG_PRIV:
|
||||
866 q->info.si_signo = sig;
|
||||
867 q->info.si_errno = 0;
|
||||
868 q->info.si_code = SI_KERNEL;
|
||||
869 q->info.si_pid = 0;
|
||||
870 q->info.si_uid = 0;
|
||||
871 break;
|
||||
...
|
||||
890 }
|
||||
|
||||
Not only does this match with the ``.si_code`` member, it also matches the place
|
||||
we found earlier when looking for where siginfo_t objects are enqueued on the
|
||||
``shared_pending`` list.
|
||||
|
||||
So to sum up: It seems that it is the padding introduced by the compiler
|
||||
between two struct fields that is uninitialized, and this gets reported when
|
||||
we do a ``memcpy()`` on the struct. This means that we have identified a false
|
||||
positive warning.
|
||||
|
||||
Normally, kmemcheck will not report uninitialized accesses in ``memcpy()`` calls
|
||||
when both the source and destination addresses are tracked. (Instead, we copy
|
||||
the shadow bytemap as well). In this case, the destination address clearly
|
||||
was not tracked. We can dig a little deeper into the stack trace from above::
|
||||
|
||||
arch/x86/kernel/signal.c:805
|
||||
arch/x86/kernel/signal.c:871
|
||||
arch/x86/kernel/entry_64.S:694
|
||||
|
||||
And we clearly see that the destination siginfo object is located on the
|
||||
stack::
|
||||
|
||||
782 static void do_signal(struct pt_regs *regs)
|
||||
783 {
|
||||
784 struct k_sigaction ka;
|
||||
785 siginfo_t info;
|
||||
...
|
||||
804 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||
...
|
||||
854 }
|
||||
|
||||
And this ``&info`` is what eventually gets passed to ``copy_siginfo()`` as the
|
||||
destination argument.
|
||||
|
||||
Now, even though we didn't find an actual error here, the example is still a
|
||||
good one, because it shows how one would go about to find out what the report
|
||||
was all about.
|
||||
|
||||
|
||||
Annotating false positives
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are a few different ways to make annotations in the source code that
|
||||
will keep kmemcheck from checking and reporting certain allocations. Here
|
||||
they are:
|
||||
|
||||
- ``__GFP_NOTRACK_FALSE_POSITIVE``
|
||||
This flag can be passed to ``kmalloc()`` or ``kmem_cache_alloc()``
|
||||
(therefore also to other functions that end up calling one of
|
||||
these) to indicate that the allocation should not be tracked
|
||||
because it would lead to a false positive report. This is a "big
|
||||
hammer" way of silencing kmemcheck; after all, even if the false
|
||||
positive pertains to particular field in a struct, for example, we
|
||||
will now lose the ability to find (real) errors in other parts of
|
||||
the same struct.
|
||||
|
||||
Example::
|
||||
|
||||
/* No warnings will ever trigger on accessing any part of x */
|
||||
x = kmalloc(sizeof *x, GFP_KERNEL | __GFP_NOTRACK_FALSE_POSITIVE);
|
||||
|
||||
- ``kmemcheck_bitfield_begin(name)``/``kmemcheck_bitfield_end(name)`` and
|
||||
``kmemcheck_annotate_bitfield(ptr, name)``
|
||||
The first two of these three macros can be used inside struct
|
||||
definitions to signal, respectively, the beginning and end of a
|
||||
bitfield. Additionally, this will assign the bitfield a name, which
|
||||
is given as an argument to the macros.
|
||||
|
||||
Having used these markers, one can later use
|
||||
kmemcheck_annotate_bitfield() at the point of allocation, to indicate
|
||||
which parts of the allocation is part of a bitfield.
|
||||
|
||||
Example::
|
||||
|
||||
struct foo {
|
||||
int x;
|
||||
|
||||
kmemcheck_bitfield_begin(flags);
|
||||
int flag_a:1;
|
||||
int flag_b:1;
|
||||
kmemcheck_bitfield_end(flags);
|
||||
|
||||
int y;
|
||||
};
|
||||
|
||||
struct foo *x = kmalloc(sizeof *x);
|
||||
|
||||
/* No warnings will trigger on accessing the bitfield of x */
|
||||
kmemcheck_annotate_bitfield(x, flags);
|
||||
|
||||
Note that ``kmemcheck_annotate_bitfield()`` can be used even before the
|
||||
return value of ``kmalloc()`` is checked -- in other words, passing NULL
|
||||
as the first argument is legal (and will do nothing).
|
||||
|
||||
|
||||
Reporting errors
|
||||
----------------
|
||||
|
||||
As we have seen, kmemcheck will produce false positive reports. Therefore, it
|
||||
is not very wise to blindly post kmemcheck warnings to mailing lists and
|
||||
maintainers. Instead, I encourage maintainers and developers to find errors
|
||||
in their own code. If you get a warning, you can try to work around it, try
|
||||
to figure out if it's a real error or not, or simply ignore it. Most
|
||||
developers know their own code and will quickly and efficiently determine the
|
||||
root cause of a kmemcheck report. This is therefore also the most efficient
|
||||
way to work with kmemcheck.
|
||||
|
||||
That said, we (the kmemcheck maintainers) will always be on the lookout for
|
||||
false positives that we can annotate and silence. So whatever you find,
|
||||
please drop us a note privately! Kernel configs and steps to reproduce (if
|
||||
available) are of course a great help too.
|
||||
|
||||
Happy hacking!
|
||||
|
||||
|
||||
Technical description
|
||||
---------------------
|
||||
|
||||
kmemcheck works by marking memory pages non-present. This means that whenever
|
||||
somebody attempts to access the page, a page fault is generated. The page
|
||||
fault handler notices that the page was in fact only hidden, and so it calls
|
||||
on the kmemcheck code to make further investigations.
|
||||
|
||||
When the investigations are completed, kmemcheck "shows" the page by marking
|
||||
it present (as it would be under normal circumstances). This way, the
|
||||
interrupted code can continue as usual.
|
||||
|
||||
But after the instruction has been executed, we should hide the page again, so
|
||||
that we can catch the next access too! Now kmemcheck makes use of a debugging
|
||||
feature of the processor, namely single-stepping. When the processor has
|
||||
finished the one instruction that generated the memory access, a debug
|
||||
exception is raised. From here, we simply hide the page again and continue
|
||||
execution, this time with the single-stepping feature turned off.
|
||||
|
||||
kmemcheck requires some assistance from the memory allocator in order to work.
|
||||
The memory allocator needs to
|
||||
|
||||
1. Tell kmemcheck about newly allocated pages and pages that are about to
|
||||
be freed. This allows kmemcheck to set up and tear down the shadow memory
|
||||
for the pages in question. The shadow memory stores the status of each
|
||||
byte in the allocation proper, e.g. whether it is initialized or
|
||||
uninitialized.
|
||||
|
||||
2. Tell kmemcheck which parts of memory should be marked uninitialized.
|
||||
There are actually a few more states, such as "not yet allocated" and
|
||||
"recently freed".
|
||||
|
||||
If a slab cache is set up using the SLAB_NOTRACK flag, it will never return
|
||||
memory that can take page faults because of kmemcheck.
|
||||
|
||||
If a slab cache is NOT set up using the SLAB_NOTRACK flag, callers can still
|
||||
request memory with the __GFP_NOTRACK or __GFP_NOTRACK_FALSE_POSITIVE flags.
|
||||
This does not prevent the page faults from occurring, however, but marks the
|
||||
object in question as being initialized so that no warnings will ever be
|
||||
produced for this object.
|
||||
|
||||
Currently, the SLAB and SLUB allocators are supported by kmemcheck.
|
|
@ -1,15 +1,12 @@
|
|||
Kernel Memory Leak Detector
|
||||
===========================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Kmemleak provides a way of detecting possible kernel memory leaks in a
|
||||
way similar to a tracing garbage collector
|
||||
(https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors),
|
||||
with the difference that the orphan objects are not freed but only
|
||||
reported via /sys/kernel/debug/kmemleak. A similar method is used by the
|
||||
Valgrind tool (memcheck --leak-check) to detect the memory leaks in
|
||||
Valgrind tool (``memcheck --leak-check``) to detect the memory leaks in
|
||||
user-space applications.
|
||||
Kmemleak is supported on x86, arm, powerpc, sparc, sh, microblaze, ppc, mips, s390, metag and tile.
|
||||
|
||||
|
@ -19,20 +16,20 @@ Usage
|
|||
CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel
|
||||
thread scans the memory every 10 minutes (by default) and prints the
|
||||
number of new unreferenced objects found. To display the details of all
|
||||
the possible memory leaks:
|
||||
the possible memory leaks::
|
||||
|
||||
# mount -t debugfs nodev /sys/kernel/debug/
|
||||
# cat /sys/kernel/debug/kmemleak
|
||||
|
||||
To trigger an intermediate memory scan:
|
||||
To trigger an intermediate memory scan::
|
||||
|
||||
# echo scan > /sys/kernel/debug/kmemleak
|
||||
|
||||
To clear the list of all current possible memory leaks:
|
||||
To clear the list of all current possible memory leaks::
|
||||
|
||||
# echo clear > /sys/kernel/debug/kmemleak
|
||||
|
||||
New leaks will then come up upon reading /sys/kernel/debug/kmemleak
|
||||
New leaks will then come up upon reading ``/sys/kernel/debug/kmemleak``
|
||||
again.
|
||||
|
||||
Note that the orphan objects are listed in the order they were allocated
|
||||
|
@ -40,22 +37,31 @@ and one object at the beginning of the list may cause other subsequent
|
|||
objects to be reported as orphan.
|
||||
|
||||
Memory scanning parameters can be modified at run-time by writing to the
|
||||
/sys/kernel/debug/kmemleak file. The following parameters are supported:
|
||||
``/sys/kernel/debug/kmemleak`` file. The following parameters are supported:
|
||||
|
||||
off - disable kmemleak (irreversible)
|
||||
stack=on - enable the task stacks scanning (default)
|
||||
stack=off - disable the tasks stacks scanning
|
||||
scan=on - start the automatic memory scanning thread (default)
|
||||
scan=off - stop the automatic memory scanning thread
|
||||
scan=<secs> - set the automatic memory scanning period in seconds
|
||||
(default 600, 0 to stop the automatic scanning)
|
||||
scan - trigger a memory scan
|
||||
clear - clear list of current memory leak suspects, done by
|
||||
marking all current reported unreferenced objects grey,
|
||||
or free all kmemleak objects if kmemleak has been disabled.
|
||||
dump=<addr> - dump information about the object found at <addr>
|
||||
- off
|
||||
disable kmemleak (irreversible)
|
||||
- stack=on
|
||||
enable the task stacks scanning (default)
|
||||
- stack=off
|
||||
disable the tasks stacks scanning
|
||||
- scan=on
|
||||
start the automatic memory scanning thread (default)
|
||||
- scan=off
|
||||
stop the automatic memory scanning thread
|
||||
- scan=<secs>
|
||||
set the automatic memory scanning period in seconds
|
||||
(default 600, 0 to stop the automatic scanning)
|
||||
- scan
|
||||
trigger a memory scan
|
||||
- clear
|
||||
clear list of current memory leak suspects, done by
|
||||
marking all current reported unreferenced objects grey,
|
||||
or free all kmemleak objects if kmemleak has been disabled.
|
||||
- dump=<addr>
|
||||
dump information about the object found at <addr>
|
||||
|
||||
Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
|
||||
Kmemleak can also be disabled at boot-time by passing ``kmemleak=off`` on
|
||||
the kernel command line.
|
||||
|
||||
Memory may be allocated or freed before kmemleak is initialised and
|
||||
|
@ -63,13 +69,14 @@ these actions are stored in an early log buffer. The size of this buffer
|
|||
is configured via the CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE option.
|
||||
|
||||
If CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF are enabled, the kmemleak is
|
||||
disabled by default. Passing "kmemleak=on" on the kernel command
|
||||
disabled by default. Passing ``kmemleak=on`` on the kernel command
|
||||
line enables the function.
|
||||
|
||||
Basic Algorithm
|
||||
---------------
|
||||
|
||||
The memory allocations via kmalloc, vmalloc, kmem_cache_alloc and
|
||||
The memory allocations via :c:func:`kmalloc`, :c:func:`vmalloc`,
|
||||
:c:func:`kmem_cache_alloc` and
|
||||
friends are traced and the pointers, together with additional
|
||||
information like size and stack trace, are stored in a rbtree.
|
||||
The corresponding freeing function calls are tracked and the pointers
|
||||
|
@ -113,13 +120,13 @@ when doing development. To work around these situations you can use the
|
|||
you can find new unreferenced objects; this should help with testing
|
||||
specific sections of code.
|
||||
|
||||
To test a critical section on demand with a clean kmemleak do:
|
||||
To test a critical section on demand with a clean kmemleak do::
|
||||
|
||||
# echo clear > /sys/kernel/debug/kmemleak
|
||||
... test your kernel or modules ...
|
||||
# echo scan > /sys/kernel/debug/kmemleak
|
||||
|
||||
Then as usual to get your report with:
|
||||
Then as usual to get your report with::
|
||||
|
||||
# cat /sys/kernel/debug/kmemleak
|
||||
|
||||
|
@ -131,7 +138,7 @@ disabled by the user or due to an fatal error, internal kmemleak objects
|
|||
won't be freed when kmemleak is disabled, and those objects may occupy
|
||||
a large part of physical memory.
|
||||
|
||||
In this situation, you may reclaim memory with:
|
||||
In this situation, you may reclaim memory with::
|
||||
|
||||
# echo clear > /sys/kernel/debug/kmemleak
|
||||
|
||||
|
@ -140,20 +147,20 @@ Kmemleak API
|
|||
|
||||
See the include/linux/kmemleak.h header for the functions prototype.
|
||||
|
||||
kmemleak_init - initialize kmemleak
|
||||
kmemleak_alloc - notify of a memory block allocation
|
||||
kmemleak_alloc_percpu - notify of a percpu memory block allocation
|
||||
kmemleak_free - notify of a memory block freeing
|
||||
kmemleak_free_part - notify of a partial memory block freeing
|
||||
kmemleak_free_percpu - notify of a percpu memory block freeing
|
||||
kmemleak_update_trace - update object allocation stack trace
|
||||
kmemleak_not_leak - mark an object as not a leak
|
||||
kmemleak_ignore - do not scan or report an object as leak
|
||||
kmemleak_scan_area - add scan areas inside a memory block
|
||||
kmemleak_no_scan - do not scan a memory block
|
||||
kmemleak_erase - erase an old value in a pointer variable
|
||||
kmemleak_alloc_recursive - as kmemleak_alloc but checks the recursiveness
|
||||
kmemleak_free_recursive - as kmemleak_free but checks the recursiveness
|
||||
- ``kmemleak_init`` - initialize kmemleak
|
||||
- ``kmemleak_alloc`` - notify of a memory block allocation
|
||||
- ``kmemleak_alloc_percpu`` - notify of a percpu memory block allocation
|
||||
- ``kmemleak_free`` - notify of a memory block freeing
|
||||
- ``kmemleak_free_part`` - notify of a partial memory block freeing
|
||||
- ``kmemleak_free_percpu`` - notify of a percpu memory block freeing
|
||||
- ``kmemleak_update_trace`` - update object allocation stack trace
|
||||
- ``kmemleak_not_leak`` - mark an object as not a leak
|
||||
- ``kmemleak_ignore`` - do not scan or report an object as leak
|
||||
- ``kmemleak_scan_area`` - add scan areas inside a memory block
|
||||
- ``kmemleak_no_scan`` - do not scan a memory block
|
||||
- ``kmemleak_erase`` - erase an old value in a pointer variable
|
||||
- ``kmemleak_alloc_recursive`` - as kmemleak_alloc but checks the recursiveness
|
||||
- ``kmemleak_free_recursive`` - as kmemleak_free but checks the recursiveness
|
||||
|
||||
Dealing with false positives/negatives
|
||||
--------------------------------------
|
|
@ -1,11 +1,20 @@
|
|||
Copyright 2004 Linus Torvalds
|
||||
Copyright 2004 Pavel Machek <pavel@ucw.cz>
|
||||
Copyright 2006 Bob Copeland <me@bobcopeland.com>
|
||||
.. Copyright 2004 Linus Torvalds
|
||||
.. Copyright 2004 Pavel Machek <pavel@ucw.cz>
|
||||
.. Copyright 2006 Bob Copeland <me@bobcopeland.com>
|
||||
|
||||
Sparse
|
||||
======
|
||||
|
||||
Sparse is a semantic checker for C programs; it can be used to find a
|
||||
number of potential problems with kernel code. See
|
||||
https://lwn.net/Articles/689907/ for an overview of sparse; this document
|
||||
contains some kernel-specific sparse information.
|
||||
|
||||
|
||||
Using sparse for typechecking
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-----------------------------
|
||||
|
||||
"__bitwise" is a type attribute, so you have to do something like this:
|
||||
"__bitwise" is a type attribute, so you have to do something like this::
|
||||
|
||||
typedef int __bitwise pm_request_t;
|
||||
|
||||
|
@ -20,13 +29,13 @@ but in this case we really _do_ want to force the conversion). And because
|
|||
the enum values are all the same type, now "enum pm_request" will be that
|
||||
type too.
|
||||
|
||||
And with gcc, all the __bitwise/__force stuff goes away, and it all ends
|
||||
up looking just like integers to gcc.
|
||||
And with gcc, all the "__bitwise"/"__force stuff" goes away, and it all
|
||||
ends up looking just like integers to gcc.
|
||||
|
||||
Quite frankly, you don't need the enum there. The above all really just
|
||||
boils down to one special "int __bitwise" type.
|
||||
|
||||
So the simpler way is to just do
|
||||
So the simpler way is to just do::
|
||||
|
||||
typedef int __bitwise pm_request_t;
|
||||
|
||||
|
@ -50,7 +59,7 @@ __bitwise - noisy stuff; in particular, __le*/__be* are that. We really
|
|||
don't want to drown in noise unless we'd explicitly asked for it.
|
||||
|
||||
Using sparse for lock checking
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
------------------------------
|
||||
|
||||
The following macros are undefined for gcc and defined during a sparse
|
||||
run to use the "context" tracking feature of sparse, applied to
|
||||
|
@ -69,22 +78,22 @@ annotation is needed. The tree annotations above are for cases where
|
|||
sparse would otherwise report a context imbalance.
|
||||
|
||||
Getting sparse
|
||||
~~~~~~~~~~~~~~
|
||||
--------------
|
||||
|
||||
You can get latest released versions from the Sparse homepage at
|
||||
https://sparse.wiki.kernel.org/index.php/Main_Page
|
||||
|
||||
Alternatively, you can get snapshots of the latest development version
|
||||
of sparse using git to clone..
|
||||
of sparse using git to clone::
|
||||
|
||||
git://git.kernel.org/pub/scm/devel/sparse/sparse.git
|
||||
|
||||
DaveJ has hourly generated tarballs of the git tree available at..
|
||||
DaveJ has hourly generated tarballs of the git tree available at::
|
||||
|
||||
http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
|
||||
|
||||
|
||||
Once you have it, just do
|
||||
Once you have it, just do::
|
||||
|
||||
make
|
||||
make install
|
||||
|
@ -92,7 +101,7 @@ Once you have it, just do
|
|||
as a regular user, and it will install sparse in your ~/bin directory.
|
||||
|
||||
Using sparse
|
||||
~~~~~~~~~~~~
|
||||
------------
|
||||
|
||||
Do a kernel make with "make C=1" to run sparse on all the C files that get
|
||||
recompiled, or use "make C=2" to run sparse on the files whether they need to
|
||||
|
@ -101,7 +110,7 @@ have already built it.
|
|||
|
||||
The optional make variable CF can be used to pass arguments to sparse. The
|
||||
build system passes -Wbitwise to sparse automatically. To perform endianness
|
||||
checks, you may define __CHECK_ENDIAN__:
|
||||
checks, you may define __CHECK_ENDIAN__::
|
||||
|
||||
make C=2 CF="-D__CHECK_ENDIAN__"
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
================================
|
||||
Development tools for the kernel
|
||||
================================
|
||||
|
||||
This document is a collection of documents about development tools that can
|
||||
be used to work on the kernel. For now, the documents have been pulled
|
||||
together without any significant effot to integrate them into a coherent
|
||||
whole; patches welcome!
|
||||
|
||||
.. class:: toc-title
|
||||
|
||||
Table of contents
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
coccinelle
|
||||
sparse
|
||||
kcov
|
||||
gcov
|
||||
kasan
|
||||
ubsan
|
||||
kmemleak
|
||||
kmemcheck
|
||||
gdb-kernel-debugging
|
|
@ -1,7 +1,5 @@
|
|||
Undefined Behavior Sanitizer - UBSAN
|
||||
|
||||
Overview
|
||||
--------
|
||||
The Undefined Behavior Sanitizer - UBSAN
|
||||
========================================
|
||||
|
||||
UBSAN is a runtime undefined behaviour checker.
|
||||
|
||||
|
@ -10,11 +8,13 @@ Compiler inserts code that perform certain kinds of checks before operations
|
|||
that may cause UB. If check fails (i.e. UB detected) __ubsan_handle_*
|
||||
function called to print error message.
|
||||
|
||||
GCC has that feature since 4.9.x [1] (see -fsanitize=undefined option and
|
||||
its suboptions). GCC 5.x has more checkers implemented [2].
|
||||
GCC has that feature since 4.9.x [1_] (see ``-fsanitize=undefined`` option and
|
||||
its suboptions). GCC 5.x has more checkers implemented [2_].
|
||||
|
||||
Report example
|
||||
---------------
|
||||
--------------
|
||||
|
||||
::
|
||||
|
||||
================================================================================
|
||||
UBSAN: Undefined behaviour in ../include/linux/bitops.h:110:33
|
||||
|
@ -47,29 +47,33 @@ Report example
|
|||
Usage
|
||||
-----
|
||||
|
||||
To enable UBSAN configure kernel with:
|
||||
To enable UBSAN configure kernel with::
|
||||
|
||||
CONFIG_UBSAN=y
|
||||
|
||||
and to check the entire kernel:
|
||||
and to check the entire kernel::
|
||||
|
||||
CONFIG_UBSAN_SANITIZE_ALL=y
|
||||
|
||||
To enable instrumentation for specific files or directories, add a line
|
||||
similar to the following to the respective kernel Makefile:
|
||||
|
||||
For a single file (e.g. main.o):
|
||||
UBSAN_SANITIZE_main.o := y
|
||||
- For a single file (e.g. main.o)::
|
||||
|
||||
For all files in one directory:
|
||||
UBSAN_SANITIZE := y
|
||||
UBSAN_SANITIZE_main.o := y
|
||||
|
||||
- For all files in one directory::
|
||||
|
||||
UBSAN_SANITIZE := y
|
||||
|
||||
To exclude files from being instrumented even if
|
||||
CONFIG_UBSAN_SANITIZE_ALL=y, use:
|
||||
``CONFIG_UBSAN_SANITIZE_ALL=y``, use::
|
||||
|
||||
UBSAN_SANITIZE_main.o := n
|
||||
and:
|
||||
UBSAN_SANITIZE := n
|
||||
UBSAN_SANITIZE_main.o := n
|
||||
|
||||
and::
|
||||
|
||||
UBSAN_SANITIZE := n
|
||||
|
||||
Detection of unaligned accesses controlled through the separate option -
|
||||
CONFIG_UBSAN_ALIGNMENT. It's off by default on architectures that support
|
||||
|
@ -80,5 +84,5 @@ reports.
|
|||
References
|
||||
----------
|
||||
|
||||
[1] - https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html
|
||||
[2] - https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
|
||||
.. _1: https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html
|
||||
.. _2: https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
|
|
@ -0,0 +1,65 @@
|
|||
Atmel Image Sensor Controller (ISC)
|
||||
----------------------------------------------
|
||||
|
||||
Required properties for ISC:
|
||||
- compatible
|
||||
Must be "atmel,sama5d2-isc".
|
||||
- reg
|
||||
Physical base address and length of the registers set for the device.
|
||||
- interrupts
|
||||
Should contain IRQ line for the ISC.
|
||||
- clocks
|
||||
List of clock specifiers, corresponding to entries in
|
||||
the clock-names property;
|
||||
Please refer to clock-bindings.txt.
|
||||
- clock-names
|
||||
Required elements: "hclock", "iscck", "gck".
|
||||
- #clock-cells
|
||||
Should be 0.
|
||||
- clock-output-names
|
||||
Should be "isc-mck".
|
||||
- pinctrl-names, pinctrl-0
|
||||
Please refer to pinctrl-bindings.txt.
|
||||
|
||||
ISC supports a single port node with parallel bus. It should contain one
|
||||
'port' child node with child 'endpoint' node. Please refer to the bindings
|
||||
defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
Example:
|
||||
isc: isc@f0008000 {
|
||||
compatible = "atmel,sama5d2-isc";
|
||||
reg = <0xf0008000 0x4000>;
|
||||
interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>;
|
||||
clocks = <&isc_clk>, <&iscck>, <&isc_gclk>;
|
||||
clock-names = "hclock", "iscck", "gck";
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "isc-mck";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>;
|
||||
|
||||
port {
|
||||
isc_0: endpoint {
|
||||
remote-endpoint = <&ov7740_0>;
|
||||
hsync-active = <1>;
|
||||
vsync-active = <0>;
|
||||
pclk-sample = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c1: i2c@fc028000 {
|
||||
ov7740: camera@21 {
|
||||
compatible = "ovti,ov7740";
|
||||
reg = <0x21>;
|
||||
clocks = <&isc>;
|
||||
clock-names = "xvclk";
|
||||
assigned-clocks = <&isc>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
|
||||
port {
|
||||
ov7740_0: endpoint {
|
||||
remote-endpoint = <&isc_0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -16,9 +16,10 @@ Required properties:
|
|||
- clocks : list of clock specifiers, corresponding to entries in
|
||||
clock-names property;
|
||||
- clock-names : must contain "ppmuispx", "ppmuispx", "lite0", "lite1"
|
||||
"mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "uart",
|
||||
"ispdiv0", "ispdiv1", "mcuispdiv0", "mcuispdiv1", "aclk200",
|
||||
"div_aclk200", "aclk400mcuisp", "div_aclk400mcuisp" entries,
|
||||
"mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "gicisp",
|
||||
"pwm_isp", "mcuctl_isp", "uart", "ispdiv0", "ispdiv1",
|
||||
"mcuispdiv0", "mcuispdiv1", "aclk200", "div_aclk200",
|
||||
"aclk400mcuisp", "div_aclk400mcuisp" entries,
|
||||
matching entries in the clocks property.
|
||||
pmu subnode
|
||||
-----------
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
* Analog Devices AD5820 autofocus coil
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Must contain "adi,ad5820"
|
||||
|
||||
- reg: I2C slave address
|
||||
|
||||
- VANA-supply: supply of voltage for VANA pin
|
||||
|
||||
Example:
|
||||
|
||||
ad5820: coil@c {
|
||||
compatible = "adi,ad5820";
|
||||
reg = <0x0c>;
|
||||
|
||||
VANA-supply = <&vaux4>;
|
||||
};
|
||||
|
|
@ -15,6 +15,11 @@ Required Properties :
|
|||
"adi,adv7282"
|
||||
"adi,adv7282-m"
|
||||
|
||||
Optional Properties :
|
||||
- powerdown-gpios: reference to the GPIO connected to the powerdown pin,
|
||||
if any.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
i2c0@1c22000 {
|
||||
|
|
|
@ -7,12 +7,14 @@ conversion of AXI transactions in order to reduce the memory bandwidth.
|
|||
|
||||
There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP
|
||||
for FDP (FCPF). Their configuration and behaviour depend on the module they
|
||||
are paired with. These DT bindings currently support the FCPV only.
|
||||
are paired with. These DT bindings currently support the FCPV and FCPF.
|
||||
|
||||
- compatible: Must be one or more of the following
|
||||
|
||||
- "renesas,r8a7795-fcpv" for R8A7795 (R-Car H3) compatible 'FCP for VSP'
|
||||
- "renesas,r8a7795-fcpf" for R8A7795 (R-Car H3) compatible 'FCP for FDP'
|
||||
- "renesas,fcpv" for generic compatible 'FCP for VSP'
|
||||
- "renesas,fcpf" for generic compatible 'FCP for FDP'
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first, followed by the
|
||||
|
@ -21,6 +23,10 @@ are paired with. These DT bindings currently support the FCPV only.
|
|||
- reg: the register base and size for the device registers
|
||||
- clocks: Reference to the functional clock
|
||||
|
||||
Optional properties:
|
||||
- power-domains : power-domain property defined with a power domain specifier
|
||||
to respective power domain.
|
||||
|
||||
|
||||
Device node example
|
||||
-------------------
|
||||
|
@ -29,4 +35,5 @@ Device node example
|
|||
compatible = "renesas,r8a7795-fcpv", "renesas,fcpv";
|
||||
reg = <0 0xfea2f000 0 0x200>;
|
||||
clocks = <&cpg CPG_MOD 602>;
|
||||
power-domains = <&sysc R8A7795_PD_A3VP>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
st-hva: multi-format video encoder for STMicroelectronics SoC.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "st,st-hva".
|
||||
- reg: HVA physical address location and length, esram address location and
|
||||
length.
|
||||
- reg-names: names of the registers listed in registers property in the same
|
||||
order.
|
||||
- interrupts: HVA interrupt number.
|
||||
- clocks: from common clock binding: handle hardware IP needed clocks, the
|
||||
number of clocks may depend on the SoC type.
|
||||
See ../clock/clock-bindings.txt for details.
|
||||
- clock-names: names of the clocks listed in clocks property in the same order.
|
||||
|
||||
Example:
|
||||
hva@8c85000{
|
||||
compatible = "st,st-hva";
|
||||
reg = <0x8c85000 0x400>, <0x6000000 0x40000>;
|
||||
reg-names = "hva_registers", "hva_esram";
|
||||
interrupts = <GIC_SPI 58 IRQ_TYPE_NONE>,
|
||||
<GIC_SPI 59 IRQ_TYPE_NONE>;
|
||||
clock-names = "clk_hva";
|
||||
clocks = <&clk_s_c0_flexgen CLK_HVA>;
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
STMicroelectronics STIH4xx HDMI CEC driver
|
||||
|
||||
Required properties:
|
||||
- compatible : value should be "st,stih-cec"
|
||||
- reg : Physical base address of the IP registers and length of memory
|
||||
mapped region.
|
||||
- clocks : from common clock binding: handle to HDMI CEC clock
|
||||
- interrupts : HDMI CEC interrupt number to the CPU.
|
||||
- pinctrl-names: Contains only one value - "default"
|
||||
- pinctrl-0: Specifies the pin control groups used for CEC hardware.
|
||||
- resets: Reference to a reset controller
|
||||
|
||||
Example for STIH407:
|
||||
|
||||
sti-cec@094a087c {
|
||||
compatible = "st,stih-cec";
|
||||
reg = <0x94a087c 0x64>;
|
||||
clocks = <&clk_sysin>;
|
||||
clock-names = "cec-clk";
|
||||
interrupts = <GIC_SPI 140 IRQ_TYPE_NONE>;
|
||||
interrupt-names = "cec-irq";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_cec0_default>;
|
||||
resets = <&softreset STIH407_LPM_SOFTRESET>;
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
# -*- coding: utf-8 mode: conf-colon -*-
|
||||
#
|
||||
# docutils configuration file
|
||||
# http://docutils.sourceforge.net/docs/user/config.html
|
||||
|
||||
[general]
|
||||
halt_level: severe
|
|
@ -0,0 +1,120 @@
|
|||
Driver Basics
|
||||
=============
|
||||
|
||||
Driver Entry and Exit points
|
||||
----------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/init.h
|
||||
:internal:
|
||||
|
||||
Atomic and pointer manipulation
|
||||
-------------------------------
|
||||
|
||||
.. kernel-doc:: arch/x86/include/asm/atomic.h
|
||||
:internal:
|
||||
|
||||
Delaying, scheduling, and timer routines
|
||||
----------------------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/sched.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/sched/core.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: kernel/sched/cpupri.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/sched/fair.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: include/linux/completion.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/time/timer.c
|
||||
:export:
|
||||
|
||||
Wait queues and Wake events
|
||||
---------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/wait.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/sched/wait.c
|
||||
:export:
|
||||
|
||||
High-resolution timers
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: include/linux/ktime.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: include/linux/hrtimer.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/time/hrtimer.c
|
||||
:export:
|
||||
|
||||
Workqueues and Kevents
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: include/linux/workqueue.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/workqueue.c
|
||||
:export:
|
||||
|
||||
Internal Functions
|
||||
------------------
|
||||
|
||||
.. kernel-doc:: kernel/exit.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/signal.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: include/linux/kthread.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/kthread.c
|
||||
:export:
|
||||
|
||||
Kernel objects manipulation
|
||||
---------------------------
|
||||
|
||||
.. kernel-doc:: lib/kobject.c
|
||||
:export:
|
||||
|
||||
Kernel utility functions
|
||||
------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/kernel.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: kernel/printk/printk.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: kernel/panic.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: kernel/sys.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/srcu.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/tree.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/tree_plugin.h
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: kernel/rcu/update.c
|
||||
:export:
|
||||
|
||||
Device Resource Management
|
||||
--------------------------
|
||||
|
||||
.. kernel-doc:: drivers/base/devres.c
|
||||
:export:
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
Frame Buffer Library
|
||||
====================
|
||||
|
||||
The frame buffer drivers depend heavily on four data structures. These
|
||||
structures are declared in include/linux/fb.h. They are fb_info,
|
||||
fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs. The last
|
||||
three can be made available to and from userland.
|
||||
|
||||
fb_info defines the current state of a particular video card. Inside
|
||||
fb_info, there exists a fb_ops structure which is a collection of
|
||||
needed functions to make fbdev and fbcon work. fb_info is only visible
|
||||
to the kernel.
|
||||
|
||||
fb_var_screeninfo is used to describe the features of a video card
|
||||
that are user defined. With fb_var_screeninfo, things such as depth
|
||||
and the resolution may be defined.
|
||||
|
||||
The next structure is fb_fix_screeninfo. This defines the properties
|
||||
of a card that are created when a mode is set and can't be changed
|
||||
otherwise. A good example of this is the start of the frame buffer
|
||||
memory. This "locks" the address of the frame buffer memory, so that it
|
||||
cannot be changed or moved.
|
||||
|
||||
The last structure is fb_monospecs. In the old API, there was little
|
||||
importance for fb_monospecs. This allowed for forbidden things such as
|
||||
setting a mode of 800x600 on a fix frequency monitor. With the new API,
|
||||
fb_monospecs prevents such things, and if used correctly, can prevent a
|
||||
monitor from being cooked. fb_monospecs will not be useful until
|
||||
kernels 2.5.x.
|
||||
|
||||
Frame Buffer Memory
|
||||
-------------------
|
||||
|
||||
.. kernel-doc:: drivers/video/fbdev/core/fbmem.c
|
||||
:export:
|
||||
|
||||
Frame Buffer Colormap
|
||||
---------------------
|
||||
|
||||
.. kernel-doc:: drivers/video/fbdev/core/fbcmap.c
|
||||
:export:
|
||||
|
||||
Frame Buffer Video Mode Database
|
||||
--------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/video/fbdev/core/modedb.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/video/fbdev/core/modedb.c
|
||||
:export:
|
||||
|
||||
Frame Buffer Macintosh Video Mode Database
|
||||
------------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/video/fbdev/macmodes.c
|
||||
:export:
|
||||
|
||||
Frame Buffer Fonts
|
||||
------------------
|
||||
|
||||
Refer to the file lib/fonts/fonts.c for more information.
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
High Speed Synchronous Serial Interface (HSI)
|
||||
=============================================
|
||||
|
||||
Introduction
|
||||
---------------
|
||||
|
||||
High Speed Syncronous Interface (HSI) is a fullduplex, low latency protocol,
|
||||
that is optimized for die-level interconnect between an Application Processor
|
||||
and a Baseband chipset. It has been specified by the MIPI alliance in 2003 and
|
||||
implemented by multiple vendors since then.
|
||||
|
||||
The HSI interface supports full duplex communication over multiple channels
|
||||
(typically 8) and is capable of reaching speeds up to 200 Mbit/s.
|
||||
|
||||
The serial protocol uses two signals, DATA and FLAG as combined data and clock
|
||||
signals and an additional READY signal for flow control. An additional WAKE
|
||||
signal can be used to wakeup the chips from standby modes. The signals are
|
||||
commonly prefixed by AC for signals going from the application die to the
|
||||
cellular die and CA for signals going the other way around.
|
||||
|
||||
::
|
||||
|
||||
+------------+ +---------------+
|
||||
| Cellular | | Application |
|
||||
| Die | | Die |
|
||||
| | - - - - - - CAWAKE - - - - - - >| |
|
||||
| T|------------ CADATA ------------>|R |
|
||||
| X|------------ CAFLAG ------------>|X |
|
||||
| |<----------- ACREADY ------------| |
|
||||
| | | |
|
||||
| | | |
|
||||
| |< - - - - - ACWAKE - - - - - - -| |
|
||||
| R|<----------- ACDATA -------------|T |
|
||||
| X|<----------- ACFLAG -------------|X |
|
||||
| |------------ CAREADY ----------->| |
|
||||
| | | |
|
||||
| | | |
|
||||
+------------+ +---------------+
|
||||
|
||||
HSI Subsystem in Linux
|
||||
-------------------------
|
||||
|
||||
In the Linux kernel the hsi subsystem is supposed to be used for HSI devices.
|
||||
The hsi subsystem contains drivers for hsi controllers including support for
|
||||
multi-port controllers and provides a generic API for using the HSI ports.
|
||||
|
||||
It also contains HSI client drivers, which make use of the generic API to
|
||||
implement a protocol used on the HSI interface. These client drivers can
|
||||
use an arbitrary number of channels.
|
||||
|
||||
hsi-char Device
|
||||
------------------
|
||||
|
||||
Each port automatically registers a generic client driver called hsi_char,
|
||||
which provides a charecter device for userspace representing the HSI port.
|
||||
It can be used to communicate via HSI from userspace. Userspace may
|
||||
configure the hsi_char device using the following ioctl commands:
|
||||
|
||||
HSC_RESET
|
||||
flush the HSI port
|
||||
|
||||
HSC_SET_PM
|
||||
enable or disable the client.
|
||||
|
||||
HSC_SEND_BREAK
|
||||
send break
|
||||
|
||||
HSC_SET_RX
|
||||
set RX configuration
|
||||
|
||||
HSC_GET_RX
|
||||
get RX configuration
|
||||
|
||||
HSC_SET_TX
|
||||
set TX configuration
|
||||
|
||||
HSC_GET_TX
|
||||
get TX configuration
|
||||
|
||||
The kernel HSI API
|
||||
------------------
|
||||
|
||||
.. kernel-doc:: include/linux/hsi/hsi.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/hsi/hsi_core.c
|
||||
:export:
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
I\ :sup:`2`\ C and SMBus Subsystem
|
||||
==================================
|
||||
|
||||
I\ :sup:`2`\ C (or without fancy typography, "I2C") is an acronym for
|
||||
the "Inter-IC" bus, a simple bus protocol which is widely used where low
|
||||
data rate communications suffice. Since it's also a licensed trademark,
|
||||
some vendors use another name (such as "Two-Wire Interface", TWI) for
|
||||
the same bus. I2C only needs two signals (SCL for clock, SDA for data),
|
||||
conserving board real estate and minimizing signal quality issues. Most
|
||||
I2C devices use seven bit addresses, and bus speeds of up to 400 kHz;
|
||||
there's a high speed extension (3.4 MHz) that's not yet found wide use.
|
||||
I2C is a multi-master bus; open drain signaling is used to arbitrate
|
||||
between masters, as well as to handshake and to synchronize clocks from
|
||||
slower clients.
|
||||
|
||||
The Linux I2C programming interfaces support only the master side of bus
|
||||
interactions, not the slave side. The programming interface is
|
||||
structured around two kinds of driver, and two kinds of device. An I2C
|
||||
"Adapter Driver" abstracts the controller hardware; it binds to a
|
||||
physical device (perhaps a PCI device or platform_device) and exposes a
|
||||
:c:type:`struct i2c_adapter <i2c_adapter>` representing each
|
||||
I2C bus segment it manages. On each I2C bus segment will be I2C devices
|
||||
represented by a :c:type:`struct i2c_client <i2c_client>`.
|
||||
Those devices will be bound to a :c:type:`struct i2c_driver
|
||||
<i2c_driver>`, which should follow the standard Linux driver
|
||||
model. (At this writing, a legacy model is more widely used.) There are
|
||||
functions to perform various I2C protocol operations; at this writing
|
||||
all such functions are usable only from task context.
|
||||
|
||||
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
|
||||
systems are also I2C conformant. The electrical constraints are tighter
|
||||
for SMBus, and it standardizes particular protocol messages and idioms.
|
||||
Controllers that support I2C can also support most SMBus operations, but
|
||||
SMBus controllers don't support all the protocol options that an I2C
|
||||
controller will. There are functions to perform various SMBus protocol
|
||||
operations, either using I2C primitives or by issuing SMBus commands to
|
||||
i2c_adapter devices which don't support those I2C operations.
|
||||
|
||||
.. kernel-doc:: include/linux/i2c.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/i2c/i2c-boardinfo.c
|
||||
:functions: i2c_register_board_info
|
||||
|
||||
.. kernel-doc:: drivers/i2c/i2c-core.c
|
||||
:export:
|
|
@ -0,0 +1,26 @@
|
|||
========================================
|
||||
The Linux driver implementer's API guide
|
||||
========================================
|
||||
|
||||
The kernel offers a wide variety of interfaces to support the development
|
||||
of device drivers. This document is an only somewhat organized collection
|
||||
of some of those interfaces — it will hopefully get better over time! The
|
||||
available subsections can be seen below.
|
||||
|
||||
.. class:: toc-title
|
||||
|
||||
Table of contents
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
basics
|
||||
infrastructure
|
||||
message-based
|
||||
sound
|
||||
frame-buffer
|
||||
input
|
||||
spi
|
||||
i2c
|
||||
hsi
|
||||
miscellaneous
|
|
@ -0,0 +1,169 @@
|
|||
Device drivers infrastructure
|
||||
=============================
|
||||
|
||||
The Basic Device Driver-Model Structures
|
||||
----------------------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/device.h
|
||||
:internal:
|
||||
|
||||
Device Drivers Base
|
||||
-------------------
|
||||
|
||||
.. kernel-doc:: drivers/base/init.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/base/driver.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/core.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/syscore.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/class.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/node.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/base/firmware_class.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/transport_class.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/dd.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/platform_device.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/base/platform.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/bus.c
|
||||
:export:
|
||||
|
||||
Buffer Sharing and Synchronization
|
||||
----------------------------------
|
||||
|
||||
The dma-buf subsystem provides the framework for sharing buffers for
|
||||
hardware (DMA) access across multiple device drivers and subsystems, and
|
||||
for synchronizing asynchronous hardware access.
|
||||
|
||||
This is used, for example, by drm "prime" multi-GPU support, but is of
|
||||
course not limited to GPU use cases.
|
||||
|
||||
The three main components of this are: (1) dma-buf, representing a
|
||||
sg_table and exposed to userspace as a file descriptor to allow passing
|
||||
between devices, (2) fence, which provides a mechanism to signal when
|
||||
one device as finished access, and (3) reservation, which manages the
|
||||
shared or exclusive fence(s) associated with the buffer.
|
||||
|
||||
dma-buf
|
||||
~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/dma-buf.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/dma-buf.h
|
||||
:internal:
|
||||
|
||||
reservation
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/reservation.c
|
||||
:doc: Reservation Object Overview
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/reservation.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/reservation.h
|
||||
:internal:
|
||||
|
||||
fence
|
||||
~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/fence.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/fence.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/seqno-fence.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/seqno-fence.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/fence-array.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/fence-array.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/reservation.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/reservation.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/dma-buf/sync_file.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/sync_file.h
|
||||
:internal:
|
||||
|
||||
Device Drivers DMA Management
|
||||
-----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/base/dma-coherent.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/base/dma-mapping.c
|
||||
:export:
|
||||
|
||||
Device Drivers Power Management
|
||||
-------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/base/power/main.c
|
||||
:export:
|
||||
|
||||
Device Drivers ACPI Support
|
||||
---------------------------
|
||||
|
||||
.. kernel-doc:: drivers/acpi/scan.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/acpi/scan.c
|
||||
:internal:
|
||||
|
||||
Device drivers PnP support
|
||||
--------------------------
|
||||
|
||||
.. kernel-doc:: drivers/pnp/core.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/pnp/card.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/pnp/driver.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/pnp/manager.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/pnp/support.c
|
||||
:export:
|
||||
|
||||
Userspace IO devices
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/uio/uio.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/uio_driver.h
|
||||
:internal:
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
Input Subsystem
|
||||
===============
|
||||
|
||||
Input core
|
||||
----------
|
||||
|
||||
.. kernel-doc:: include/linux/input.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/input/input.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/input/ff-core.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/input/ff-memless.c
|
||||
:export:
|
||||
|
||||
Multitouch Library
|
||||
------------------
|
||||
|
||||
.. kernel-doc:: include/linux/input/mt.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/input/input-mt.c
|
||||
:export:
|
||||
|
||||
Polled input devices
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: include/linux/input-polldev.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/input/input-polldev.c
|
||||
:export:
|
||||
|
||||
Matrix keyboards/keypads
|
||||
------------------------
|
||||
|
||||
.. kernel-doc:: include/linux/input/matrix_keypad.h
|
||||
:internal:
|
||||
|
||||
Sparse keymap support
|
||||
---------------------
|
||||
|
||||
.. kernel-doc:: include/linux/input/sparse-keymap.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/input/sparse-keymap.c
|
||||
:export:
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
Message-based devices
|
||||
=====================
|
||||
|
||||
Fusion message devices
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: drivers/message/fusion/mptbase.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/message/fusion/mptscsih.c
|
||||
:export:
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
Parallel Port Devices
|
||||
=====================
|
||||
|
||||
.. kernel-doc:: include/linux/parport.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/parport/ieee1284.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/parport/share.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/parport/daisy.c
|
||||
:internal:
|
||||
|
||||
16x50 UART Driver
|
||||
=================
|
||||
|
||||
.. kernel-doc:: drivers/tty/serial/serial_core.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/tty/serial/8250/8250_core.c
|
||||
:export:
|
||||
|
||||
Pulse-Width Modulation (PWM)
|
||||
============================
|
||||
|
||||
Pulse-width modulation is a modulation technique primarily used to
|
||||
control power supplied to electrical devices.
|
||||
|
||||
The PWM framework provides an abstraction for providers and consumers of
|
||||
PWM signals. A controller that provides one or more PWM signals is
|
||||
registered as :c:type:`struct pwm_chip <pwm_chip>`. Providers
|
||||
are expected to embed this structure in a driver-specific structure.
|
||||
This structure contains fields that describe a particular chip.
|
||||
|
||||
A chip exposes one or more PWM signal sources, each of which exposed as
|
||||
a :c:type:`struct pwm_device <pwm_device>`. Operations can be
|
||||
performed on PWM devices to control the period, duty cycle, polarity and
|
||||
active state of the signal.
|
||||
|
||||
Note that PWM devices are exclusive resources: they can always only be
|
||||
used by one consumer at a time.
|
||||
|
||||
.. kernel-doc:: include/linux/pwm.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/pwm/core.c
|
||||
:export:
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
Sound Devices
|
||||
=============
|
||||
|
||||
.. kernel-doc:: include/sound/core.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: sound/sound_core.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/sound/pcm.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: sound/core/pcm.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/device.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/info.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/rawmidi.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/sound.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/memory.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/pcm_memory.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/init.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/isadma.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/control.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/pcm_lib.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/hwdep.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/pcm_native.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: sound/core/memalloc.c
|
||||
:export:
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
Serial Peripheral Interface (SPI)
|
||||
=================================
|
||||
|
||||
SPI is the "Serial Peripheral Interface", widely used with embedded
|
||||
systems because it is a simple and efficient interface: basically a
|
||||
multiplexed shift register. Its three signal wires hold a clock (SCK,
|
||||
often in the range of 1-20 MHz), a "Master Out, Slave In" (MOSI) data
|
||||
line, and a "Master In, Slave Out" (MISO) data line. SPI is a full
|
||||
duplex protocol; for each bit shifted out the MOSI line (one per clock)
|
||||
another is shifted in on the MISO line. Those bits are assembled into
|
||||
words of various sizes on the way to and from system memory. An
|
||||
additional chipselect line is usually active-low (nCS); four signals are
|
||||
normally used for each peripheral, plus sometimes an interrupt.
|
||||
|
||||
The SPI bus facilities listed here provide a generalized interface to
|
||||
declare SPI busses and devices, manage them according to the standard
|
||||
Linux driver model, and perform input/output operations. At this time,
|
||||
only "master" side interfaces are supported, where Linux talks to SPI
|
||||
peripherals and does not implement such a peripheral itself. (Interfaces
|
||||
to support implementing SPI slaves would necessarily look different.)
|
||||
|
||||
The programming interface is structured around two kinds of driver, and
|
||||
two kinds of device. A "Controller Driver" abstracts the controller
|
||||
hardware, which may be as simple as a set of GPIO pins or as complex as
|
||||
a pair of FIFOs connected to dual DMA engines on the other side of the
|
||||
SPI shift register (maximizing throughput). Such drivers bridge between
|
||||
whatever bus they sit on (often the platform bus) and SPI, and expose
|
||||
the SPI side of their device as a :c:type:`struct spi_master
|
||||
<spi_master>`. SPI devices are children of that master,
|
||||
represented as a :c:type:`struct spi_device <spi_device>` and
|
||||
manufactured from :c:type:`struct spi_board_info
|
||||
<spi_board_info>` descriptors which are usually provided by
|
||||
board-specific initialization code. A :c:type:`struct spi_driver
|
||||
<spi_driver>` is called a "Protocol Driver", and is bound to a
|
||||
spi_device using normal driver model calls.
|
||||
|
||||
The I/O model is a set of queued messages. Protocol drivers submit one
|
||||
or more :c:type:`struct spi_message <spi_message>` objects,
|
||||
which are processed and completed asynchronously. (There are synchronous
|
||||
wrappers, however.) Messages are built from one or more
|
||||
:c:type:`struct spi_transfer <spi_transfer>` objects, each of
|
||||
which wraps a full duplex SPI transfer. A variety of protocol tweaking
|
||||
options are needed, because different chips adopt very different
|
||||
policies for how they use the bits transferred with SPI.
|
||||
|
||||
.. kernel-doc:: include/linux/spi/spi.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/spi/spi.c
|
||||
:functions: spi_register_board_info
|
||||
|
||||
.. kernel-doc:: drivers/spi/spi.c
|
||||
:export:
|
|
@ -50,7 +50,7 @@ Attributes of devices can be exported by a device driver through sysfs.
|
|||
Please see Documentation/filesystems/sysfs.txt for more information
|
||||
on how sysfs works.
|
||||
|
||||
As explained in Documentation/kobject.txt, device attributes must be be
|
||||
As explained in Documentation/kobject.txt, device attributes must be
|
||||
created before the KOBJ_ADD uevent is generated. The only way to realize
|
||||
that is by defining an attribute group.
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ Table 1-1: Process specific entries in /proc
|
|||
symbol the task is blocked in - or "0" if not blocked.
|
||||
pagemap Page table
|
||||
stack Report full stack trace, enable via CONFIG_STACKTRACE
|
||||
smaps a extension based on maps, showing the memory consumption of
|
||||
smaps an extension based on maps, showing the memory consumption of
|
||||
each mapping and flags associated with it
|
||||
numa_maps an extension based on maps, showing the memory locality and
|
||||
binding policy as well as mem usage (in pages) of each mapping.
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
Using gcov with the Linux kernel
|
||||
================================
|
||||
|
||||
1. Introduction
|
||||
2. Preparation
|
||||
3. Customization
|
||||
4. Files
|
||||
5. Modules
|
||||
6. Separated build and test machines
|
||||
7. Troubleshooting
|
||||
Appendix A: sample script: gather_on_build.sh
|
||||
Appendix B: sample script: gather_on_test.sh
|
||||
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
gcov profiling kernel support enables the use of GCC's coverage testing
|
||||
tool gcov [1] with the Linux kernel. Coverage data of a running kernel
|
||||
is exported in gcov-compatible format via the "gcov" debugfs directory.
|
||||
To get coverage data for a specific file, change to the kernel build
|
||||
directory and use gcov with the -o option as follows (requires root):
|
||||
|
||||
# cd /tmp/linux-out
|
||||
# gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
|
||||
|
||||
This will create source code files annotated with execution counts
|
||||
in the current directory. In addition, graphical gcov front-ends such
|
||||
as lcov [2] can be used to automate the process of collecting data
|
||||
for the entire kernel and provide coverage overviews in HTML format.
|
||||
|
||||
Possible uses:
|
||||
|
||||
* debugging (has this line been reached at all?)
|
||||
* test improvement (how do I change my test to cover these lines?)
|
||||
* minimizing kernel configurations (do I need this option if the
|
||||
associated code is never run?)
|
||||
|
||||
--
|
||||
|
||||
[1] http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
|
||||
[2] http://ltp.sourceforge.net/coverage/lcov.php
|
||||
|
||||
|
||||
2. Preparation
|
||||
==============
|
||||
|
||||
Configure the kernel with:
|
||||
|
||||
CONFIG_DEBUG_FS=y
|
||||
CONFIG_GCOV_KERNEL=y
|
||||
|
||||
select the gcc's gcov format, default is autodetect based on gcc version:
|
||||
|
||||
CONFIG_GCOV_FORMAT_AUTODETECT=y
|
||||
|
||||
and to get coverage data for the entire kernel:
|
||||
|
||||
CONFIG_GCOV_PROFILE_ALL=y
|
||||
|
||||
Note that kernels compiled with profiling flags will be significantly
|
||||
larger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported
|
||||
on all architectures.
|
||||
|
||||
Profiling data will only become accessible once debugfs has been
|
||||
mounted:
|
||||
|
||||
mount -t debugfs none /sys/kernel/debug
|
||||
|
||||
|
||||
3. Customization
|
||||
================
|
||||
|
||||
To enable profiling for specific files or directories, add a line
|
||||
similar to the following to the respective kernel Makefile:
|
||||
|
||||
For a single file (e.g. main.o):
|
||||
GCOV_PROFILE_main.o := y
|
||||
|
||||
For all files in one directory:
|
||||
GCOV_PROFILE := y
|
||||
|
||||
To exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL
|
||||
is specified, use:
|
||||
|
||||
GCOV_PROFILE_main.o := n
|
||||
and:
|
||||
GCOV_PROFILE := n
|
||||
|
||||
Only files which are linked to the main kernel image or are compiled as
|
||||
kernel modules are supported by this mechanism.
|
||||
|
||||
|
||||
4. Files
|
||||
========
|
||||
|
||||
The gcov kernel support creates the following files in debugfs:
|
||||
|
||||
/sys/kernel/debug/gcov
|
||||
Parent directory for all gcov-related files.
|
||||
|
||||
/sys/kernel/debug/gcov/reset
|
||||
Global reset file: resets all coverage data to zero when
|
||||
written to.
|
||||
|
||||
/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda
|
||||
The actual gcov data file as understood by the gcov
|
||||
tool. Resets file coverage data to zero when written to.
|
||||
|
||||
/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno
|
||||
Symbolic link to a static data file required by the gcov
|
||||
tool. This file is generated by gcc when compiling with
|
||||
option -ftest-coverage.
|
||||
|
||||
|
||||
5. Modules
|
||||
==========
|
||||
|
||||
Kernel modules may contain cleanup code which is only run during
|
||||
module unload time. The gcov mechanism provides a means to collect
|
||||
coverage data for such code by keeping a copy of the data associated
|
||||
with the unloaded module. This data remains available through debugfs.
|
||||
Once the module is loaded again, the associated coverage counters are
|
||||
initialized with the data from its previous instantiation.
|
||||
|
||||
This behavior can be deactivated by specifying the gcov_persist kernel
|
||||
parameter:
|
||||
|
||||
gcov_persist=0
|
||||
|
||||
At run-time, a user can also choose to discard data for an unloaded
|
||||
module by writing to its data file or the global reset file.
|
||||
|
||||
|
||||
6. Separated build and test machines
|
||||
====================================
|
||||
|
||||
The gcov kernel profiling infrastructure is designed to work out-of-the
|
||||
box for setups where kernels are built and run on the same machine. In
|
||||
cases where the kernel runs on a separate machine, special preparations
|
||||
must be made, depending on where the gcov tool is used:
|
||||
|
||||
a) gcov is run on the TEST machine
|
||||
|
||||
The gcov tool version on the test machine must be compatible with the
|
||||
gcc version used for kernel build. Also the following files need to be
|
||||
copied from build to test machine:
|
||||
|
||||
from the source tree:
|
||||
- all C source files + headers
|
||||
|
||||
from the build tree:
|
||||
- all C source files + headers
|
||||
- all .gcda and .gcno files
|
||||
- all links to directories
|
||||
|
||||
It is important to note that these files need to be placed into the
|
||||
exact same file system location on the test machine as on the build
|
||||
machine. If any of the path components is symbolic link, the actual
|
||||
directory needs to be used instead (due to make's CURDIR handling).
|
||||
|
||||
b) gcov is run on the BUILD machine
|
||||
|
||||
The following files need to be copied after each test case from test
|
||||
to build machine:
|
||||
|
||||
from the gcov directory in sysfs:
|
||||
- all .gcda files
|
||||
- all links to .gcno files
|
||||
|
||||
These files can be copied to any location on the build machine. gcov
|
||||
must then be called with the -o option pointing to that directory.
|
||||
|
||||
Example directory setup on the build machine:
|
||||
|
||||
/tmp/linux: kernel source tree
|
||||
/tmp/out: kernel build directory as specified by make O=
|
||||
/tmp/coverage: location of the files copied from the test machine
|
||||
|
||||
[user@build] cd /tmp/out
|
||||
[user@build] gcov -o /tmp/coverage/tmp/out/init main.c
|
||||
|
||||
|
||||
7. Troubleshooting
|
||||
==================
|
||||
|
||||
Problem: Compilation aborts during linker step.
|
||||
Cause: Profiling flags are specified for source files which are not
|
||||
linked to the main kernel or which are linked by a custom
|
||||
linker procedure.
|
||||
Solution: Exclude affected source files from profiling by specifying
|
||||
GCOV_PROFILE := n or GCOV_PROFILE_basename.o := n in the
|
||||
corresponding Makefile.
|
||||
|
||||
Problem: Files copied from sysfs appear empty or incomplete.
|
||||
Cause: Due to the way seq_file works, some tools such as cp or tar
|
||||
may not correctly copy files from sysfs.
|
||||
Solution: Use 'cat' to read .gcda files and 'cp -d' to copy links.
|
||||
Alternatively use the mechanism shown in Appendix B.
|
||||
|
||||
|
||||
Appendix A: gather_on_build.sh
|
||||
==============================
|
||||
|
||||
Sample script to gather coverage meta files on the build machine
|
||||
(see 6a):
|
||||
#!/bin/bash
|
||||
|
||||
KSRC=$1
|
||||
KOBJ=$2
|
||||
DEST=$3
|
||||
|
||||
if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
|
||||
echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
||||
KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
|
||||
|
||||
find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
|
||||
-perm /u+r,g+r | tar cfz $DEST -P -T -
|
||||
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo "$DEST successfully created, copy to test system and unpack with:"
|
||||
echo " tar xfz $DEST -P"
|
||||
else
|
||||
echo "Could not create file $DEST"
|
||||
fi
|
||||
|
||||
|
||||
Appendix B: gather_on_test.sh
|
||||
=============================
|
||||
|
||||
Sample script to gather coverage data files on the test machine
|
||||
(see 6b):
|
||||
|
||||
#!/bin/bash -e
|
||||
|
||||
DEST=$1
|
||||
GCDA=/sys/kernel/debug/gcov
|
||||
|
||||
if [ -z "$DEST" ] ; then
|
||||
echo "Usage: $0 <output.tar.gz>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TEMPDIR=$(mktemp -d)
|
||||
echo Collecting data..
|
||||
find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
|
||||
find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
|
||||
find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
|
||||
tar czf $DEST -C $TEMPDIR sys
|
||||
rm -rf $TEMPDIR
|
||||
|
||||
echo "$DEST successfully created, copy to build system and unpack with:"
|
||||
echo " tar xfz $DEST"
|
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: utf-8; mode: python -*-
|
||||
|
||||
project = "Linux GPU Driver Developer's Guide"
|
||||
|
||||
tags.add("subproject")
|
|
@ -12,3 +12,10 @@ Linux GPU Driver Developer's Guide
|
|||
drm-uapi
|
||||
i915
|
||||
vga-switcheroo
|
||||
|
||||
.. only:: subproject
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
HSI - High-speed Synchronous Serial Interface
|
||||
|
||||
1. Introduction
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
High Speed Syncronous Interface (HSI) is a fullduplex, low latency protocol,
|
||||
that is optimized for die-level interconnect between an Application Processor
|
||||
and a Baseband chipset. It has been specified by the MIPI alliance in 2003 and
|
||||
implemented by multiple vendors since then.
|
||||
|
||||
The HSI interface supports full duplex communication over multiple channels
|
||||
(typically 8) and is capable of reaching speeds up to 200 Mbit/s.
|
||||
|
||||
The serial protocol uses two signals, DATA and FLAG as combined data and clock
|
||||
signals and an additional READY signal for flow control. An additional WAKE
|
||||
signal can be used to wakeup the chips from standby modes. The signals are
|
||||
commonly prefixed by AC for signals going from the application die to the
|
||||
cellular die and CA for signals going the other way around.
|
||||
|
||||
+------------+ +---------------+
|
||||
| Cellular | | Application |
|
||||
| Die | | Die |
|
||||
| | - - - - - - CAWAKE - - - - - - >| |
|
||||
| T|------------ CADATA ------------>|R |
|
||||
| X|------------ CAFLAG ------------>|X |
|
||||
| |<----------- ACREADY ------------| |
|
||||
| | | |
|
||||
| | | |
|
||||
| |< - - - - - ACWAKE - - - - - - -| |
|
||||
| R|<----------- ACDATA -------------|T |
|
||||
| X|<----------- ACFLAG -------------|X |
|
||||
| |------------ CAREADY ----------->| |
|
||||
| | | |
|
||||
| | | |
|
||||
+------------+ +---------------+
|
||||
|
||||
2. HSI Subsystem in Linux
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the Linux kernel the hsi subsystem is supposed to be used for HSI devices.
|
||||
The hsi subsystem contains drivers for hsi controllers including support for
|
||||
multi-port controllers and provides a generic API for using the HSI ports.
|
||||
|
||||
It also contains HSI client drivers, which make use of the generic API to
|
||||
implement a protocol used on the HSI interface. These client drivers can
|
||||
use an arbitrary number of channels.
|
||||
|
||||
3. hsi-char Device
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Each port automatically registers a generic client driver called hsi_char,
|
||||
which provides a charecter device for userspace representing the HSI port.
|
||||
It can be used to communicate via HSI from userspace. Userspace may
|
||||
configure the hsi_char device using the following ioctl commands:
|
||||
|
||||
* HSC_RESET:
|
||||
- flush the HSI port
|
||||
|
||||
* HSC_SET_PM
|
||||
- enable or disable the client.
|
||||
|
||||
* HSC_SEND_BREAK
|
||||
- send break
|
||||
|
||||
* HSC_SET_RX
|
||||
- set RX configuration
|
||||
|
||||
* HSC_GET_RX
|
||||
- get RX configuration
|
||||
|
||||
* HSC_SET_TX
|
||||
- set TX configuration
|
||||
|
||||
* HSC_GET_TX
|
||||
- get TX configuration
|
|
@ -6,22 +6,18 @@
|
|||
Welcome to The Linux Kernel's documentation!
|
||||
============================================
|
||||
|
||||
Nothing for you to see here *yet*. Please move along.
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
kernel-documentation
|
||||
media/media_uapi
|
||||
media/media_kapi
|
||||
media/dvb-drivers/index
|
||||
media/v4l-drivers/index
|
||||
dev-tools/tools
|
||||
driver-api/index
|
||||
media/index
|
||||
gpu/index
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
|
|
@ -34,15 +34,18 @@ will need to add a a 32-bit compat layer:
|
|||
64-bit platforms do. So we always need padding to the natural size to get
|
||||
this right.
|
||||
|
||||
* Pad the entire struct to a multiple of 64-bits - the structure size will
|
||||
otherwise differ on 32-bit versus 64-bit. Having a different structure size
|
||||
hurts when passing arrays of structures to the kernel, or if the kernel
|
||||
checks the structure size, which e.g. the drm core does.
|
||||
* Pad the entire struct to a multiple of 64-bits if the structure contains
|
||||
64-bit types - the structure size will otherwise differ on 32-bit versus
|
||||
64-bit. Having a different structure size hurts when passing arrays of
|
||||
structures to the kernel, or if the kernel checks the structure size, which
|
||||
e.g. the drm core does.
|
||||
|
||||
* Pointers are __u64, cast from/to a uintprt_t on the userspace side and
|
||||
from/to a void __user * in the kernel. Try really hard not to delay this
|
||||
conversion or worse, fiddle the raw __u64 through your code since that
|
||||
diminishes the checking tools like sparse can provide.
|
||||
diminishes the checking tools like sparse can provide. The macro
|
||||
u64_to_user_ptr can be used in the kernel to avoid warnings about integers
|
||||
and pointres of different sizes.
|
||||
|
||||
|
||||
Basics
|
||||
|
|
|
@ -1,171 +0,0 @@
|
|||
KernelAddressSanitizer (KASAN)
|
||||
==============================
|
||||
|
||||
0. Overview
|
||||
===========
|
||||
|
||||
KernelAddressSANitizer (KASAN) is a dynamic memory error detector. It provides
|
||||
a fast and comprehensive solution for finding use-after-free and out-of-bounds
|
||||
bugs.
|
||||
|
||||
KASAN uses compile-time instrumentation for checking every memory access,
|
||||
therefore you will need a GCC version 4.9.2 or later. GCC 5.0 or later is
|
||||
required for detection of out-of-bounds accesses to stack or global variables.
|
||||
|
||||
Currently KASAN is supported only for x86_64 architecture.
|
||||
|
||||
1. Usage
|
||||
========
|
||||
|
||||
To enable KASAN configure kernel with:
|
||||
|
||||
CONFIG_KASAN = y
|
||||
|
||||
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline and
|
||||
inline are compiler instrumentation types. The former produces smaller binary
|
||||
the latter is 1.1 - 2 times faster. Inline instrumentation requires a GCC
|
||||
version 5.0 or later.
|
||||
|
||||
KASAN works with both SLUB and SLAB memory allocators.
|
||||
For better bug detection and nicer reporting, enable CONFIG_STACKTRACE.
|
||||
|
||||
To disable instrumentation for specific files or directories, add a line
|
||||
similar to the following to the respective kernel Makefile:
|
||||
|
||||
For a single file (e.g. main.o):
|
||||
KASAN_SANITIZE_main.o := n
|
||||
|
||||
For all files in one directory:
|
||||
KASAN_SANITIZE := n
|
||||
|
||||
1.1 Error reports
|
||||
=================
|
||||
|
||||
A typical out of bounds access report looks like this:
|
||||
|
||||
==================================================================
|
||||
BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
|
||||
Write of size 1 by task modprobe/1689
|
||||
=============================================================================
|
||||
BUG kmalloc-128 (Not tainted): kasan error
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Disabling lock debugging due to kernel taint
|
||||
INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689
|
||||
__slab_alloc+0x4b4/0x4f0
|
||||
kmem_cache_alloc_trace+0x10b/0x190
|
||||
kmalloc_oob_right+0x3d/0x75 [test_kasan]
|
||||
init_module+0x9/0x47 [test_kasan]
|
||||
do_one_initcall+0x99/0x200
|
||||
load_module+0x2cb3/0x3b20
|
||||
SyS_finit_module+0x76/0x80
|
||||
system_call_fastpath+0x12/0x17
|
||||
INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
|
||||
INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
|
||||
|
||||
Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
|
||||
Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
|
||||
Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
|
||||
Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........
|
||||
Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
|
||||
CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98
|
||||
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
|
||||
ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78
|
||||
ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8
|
||||
ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558
|
||||
Call Trace:
|
||||
[<ffffffff81cc68ae>] dump_stack+0x46/0x58
|
||||
[<ffffffff811fd848>] print_trailer+0xf8/0x160
|
||||
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
||||
[<ffffffff811ff0f5>] object_err+0x35/0x40
|
||||
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||
[<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0
|
||||
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
||||
[<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40
|
||||
[<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
|
||||
[<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
|
||||
[<ffffffff8120a995>] __asan_store1+0x75/0xb0
|
||||
[<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]
|
||||
[<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||
[<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan]
|
||||
[<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan]
|
||||
[<ffffffff810002d9>] do_one_initcall+0x99/0x200
|
||||
[<ffffffff811e4e5c>] ? __vunmap+0xec/0x160
|
||||
[<ffffffff81114f63>] load_module+0x2cb3/0x3b20
|
||||
[<ffffffff8110fd70>] ? m_show+0x240/0x240
|
||||
[<ffffffff81115f06>] SyS_finit_module+0x76/0x80
|
||||
[<ffffffff81cd3129>] system_call_fastpath+0x12/0x17
|
||||
Memory state around the buggy address:
|
||||
ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
|
||||
ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
|
||||
>ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
|
||||
^
|
||||
ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
==================================================================
|
||||
|
||||
The header of the report discribe what kind of bug happened and what kind of
|
||||
access caused it. It's followed by the description of the accessed slub object
|
||||
(see 'SLUB Debug output' section in Documentation/vm/slub.txt for details) and
|
||||
the description of the accessed memory page.
|
||||
|
||||
In the last section the report shows memory state around the accessed address.
|
||||
Reading this part requires some understanding of how KASAN works.
|
||||
|
||||
The state of each 8 aligned bytes of memory is encoded in one shadow byte.
|
||||
Those 8 bytes can be accessible, partially accessible, freed or be a redzone.
|
||||
We use the following encoding for each shadow byte: 0 means that all 8 bytes
|
||||
of the corresponding memory region are accessible; number N (1 <= N <= 7) means
|
||||
that the first N bytes are accessible, and other (8 - N) bytes are not;
|
||||
any negative value indicates that the entire 8-byte word is inaccessible.
|
||||
We use different negative values to distinguish between different kinds of
|
||||
inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
|
||||
|
||||
In the report above the arrows point to the shadow byte 03, which means that
|
||||
the accessed address is partially accessible.
|
||||
|
||||
|
||||
2. Implementation details
|
||||
=========================
|
||||
|
||||
From a high level, our approach to memory error detection is similar to that
|
||||
of kmemcheck: use shadow memory to record whether each byte of memory is safe
|
||||
to access, and use compile-time instrumentation to check shadow memory on each
|
||||
memory access.
|
||||
|
||||
AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
|
||||
(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
|
||||
offset to translate a memory address to its corresponding shadow address.
|
||||
|
||||
Here is the function which translates an address to its corresponding shadow
|
||||
address:
|
||||
|
||||
static inline void *kasan_mem_to_shadow(const void *addr)
|
||||
{
|
||||
return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
|
||||
+ KASAN_SHADOW_OFFSET;
|
||||
}
|
||||
|
||||
where KASAN_SHADOW_SCALE_SHIFT = 3.
|
||||
|
||||
Compile-time instrumentation used for checking memory accesses. Compiler inserts
|
||||
function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
|
||||
access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
|
||||
valid or not by checking corresponding shadow memory.
|
||||
|
||||
GCC 5.0 has possibility to perform inline instrumentation. Instead of making
|
||||
function calls GCC directly inserts the code to check the shadow memory.
|
||||
This option significantly enlarges kernel but it gives x1.1-x2 performance
|
||||
boost over outline instrumented kernel.
|
|
@ -274,7 +274,44 @@ menuconfig:
|
|||
|
||||
This is similar to the simple config entry above, but it also gives a
|
||||
hint to front ends, that all suboptions should be displayed as a
|
||||
separate list of options.
|
||||
separate list of options. To make sure all the suboptions will really
|
||||
show up under the menuconfig entry and not outside of it, every item
|
||||
from the <config options> list must depend on the menuconfig symbol.
|
||||
In practice, this is achieved by using one of the next two constructs:
|
||||
|
||||
(1):
|
||||
menuconfig M
|
||||
if M
|
||||
config C1
|
||||
config C2
|
||||
endif
|
||||
|
||||
(2):
|
||||
menuconfig M
|
||||
config C1
|
||||
depends on M
|
||||
config C2
|
||||
depends on M
|
||||
|
||||
In the following examples (3) and (4), C1 and C2 still have the M
|
||||
dependency, but will not appear under menuconfig M anymore, because
|
||||
of C0, which doesn't depend on M:
|
||||
|
||||
(3):
|
||||
menuconfig M
|
||||
config C0
|
||||
if M
|
||||
config C1
|
||||
config C2
|
||||
endif
|
||||
|
||||
(4):
|
||||
menuconfig M
|
||||
config C0
|
||||
config C1
|
||||
depends on M
|
||||
config C2
|
||||
depends on M
|
||||
|
||||
choices:
|
||||
|
||||
|
|
|
@ -107,6 +107,35 @@ Here are some specific guidelines for the kernel documentation:
|
|||
the order as encountered."), having the higher levels the same overall makes
|
||||
it easier to follow the documents.
|
||||
|
||||
|
||||
the C domain
|
||||
------------
|
||||
|
||||
The `Sphinx C Domain`_ (name c) is suited for documentation of C API. E.g. a
|
||||
function prototype:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. c:function:: int ioctl( int fd, int request )
|
||||
|
||||
The C domain of the kernel-doc has some additional features. E.g. you can
|
||||
*rename* the reference name of a function with a common name like ``open`` or
|
||||
``ioctl``:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. c:function:: int ioctl( int fd, int request )
|
||||
:name: VIDIOC_LOG_STATUS
|
||||
|
||||
The func-name (e.g. ioctl) remains in the output but the ref-name changed from
|
||||
``ioctl`` to ``VIDIOC_LOG_STATUS``. The index entry for this function is also
|
||||
changed to ``VIDIOC_LOG_STATUS`` and the function can now referenced by:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
:c:func:`VIDIOC_LOG_STATUS`
|
||||
|
||||
|
||||
list tables
|
||||
-----------
|
||||
|
||||
|
|
|
@ -1688,7 +1688,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
|
||||
intel_idle.max_cstate= [KNL,HW,ACPI,X86]
|
||||
0 disables intel_idle and fall back on acpi_idle.
|
||||
1 to 6 specify maximum depth of C-state.
|
||||
1 to 9 specify maximum depth of C-state.
|
||||
|
||||
intel_pstate= [X86]
|
||||
disable
|
||||
|
@ -2161,10 +2161,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
than or equal to this physical address is ignored.
|
||||
|
||||
maxcpus= [SMP] Maximum number of processors that an SMP kernel
|
||||
should make use of. maxcpus=n : n >= 0 limits the
|
||||
kernel to using 'n' processors. n=0 is a special case,
|
||||
it is equivalent to "nosmp", which also disables
|
||||
the IO APIC.
|
||||
will bring up during bootup. maxcpus=n : n >= 0 limits
|
||||
the kernel to bring up 'n' processors. Surely after
|
||||
bootup you can bring up the other plugged cpu by executing
|
||||
"echo 1 > /sys/devices/system/cpu/cpuX/online". So maxcpus
|
||||
only takes effect during system bootup.
|
||||
While n=0 is a special case, it is equivalent to "nosmp",
|
||||
which also disables the IO APIC.
|
||||
|
||||
max_loop= [LOOP] The number of loop block devices that get
|
||||
(loop.max_loop) unconditionally pre-created at init time. The default
|
||||
|
@ -2571,8 +2574,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
|
||||
nodelayacct [KNL] Disable per-task delay accounting
|
||||
|
||||
nodisconnect [HW,SCSI,M68K] Disables SCSI disconnects.
|
||||
|
||||
nodsp [SH] Disable hardware DSP at boot time.
|
||||
|
||||
noefi Disable EFI runtime services support.
|
||||
|
@ -2773,9 +2774,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
|
||||
nr_cpus= [SMP] Maximum number of processors that an SMP kernel
|
||||
could support. nr_cpus=n : n >= 1 limits the kernel to
|
||||
supporting 'n' processors. Later in runtime you can not
|
||||
use hotplug cpu feature to put more cpu back to online.
|
||||
just like you compile the kernel NR_CPUS=n
|
||||
support 'n' processors. It could be larger than the
|
||||
number of already plugged CPU during bootup, later in
|
||||
runtime you can physically add extra cpu until it reaches
|
||||
n. So during boot up some boot time memory for per-cpu
|
||||
variables need be pre-allocated for later physical cpu
|
||||
hot plugging.
|
||||
|
||||
nr_uarts= [SERIAL] maximum number of UARTs to be registered.
|
||||
|
||||
|
|
|
@ -1,754 +0,0 @@
|
|||
GETTING STARTED WITH KMEMCHECK
|
||||
==============================
|
||||
|
||||
Vegard Nossum <vegardno@ifi.uio.no>
|
||||
|
||||
|
||||
Contents
|
||||
========
|
||||
0. Introduction
|
||||
1. Downloading
|
||||
2. Configuring and compiling
|
||||
3. How to use
|
||||
3.1. Booting
|
||||
3.2. Run-time enable/disable
|
||||
3.3. Debugging
|
||||
3.4. Annotating false positives
|
||||
4. Reporting errors
|
||||
5. Technical description
|
||||
|
||||
|
||||
0. Introduction
|
||||
===============
|
||||
|
||||
kmemcheck is a debugging feature for the Linux Kernel. More specifically, it
|
||||
is a dynamic checker that detects and warns about some uses of uninitialized
|
||||
memory.
|
||||
|
||||
Userspace programmers might be familiar with Valgrind's memcheck. The main
|
||||
difference between memcheck and kmemcheck is that memcheck works for userspace
|
||||
programs only, and kmemcheck works for the kernel only. The implementations
|
||||
are of course vastly different. Because of this, kmemcheck is not as accurate
|
||||
as memcheck, but it turns out to be good enough in practice to discover real
|
||||
programmer errors that the compiler is not able to find through static
|
||||
analysis.
|
||||
|
||||
Enabling kmemcheck on a kernel will probably slow it down to the extent that
|
||||
the machine will not be usable for normal workloads such as e.g. an
|
||||
interactive desktop. kmemcheck will also cause the kernel to use about twice
|
||||
as much memory as normal. For this reason, kmemcheck is strictly a debugging
|
||||
feature.
|
||||
|
||||
|
||||
1. Downloading
|
||||
==============
|
||||
|
||||
As of version 2.6.31-rc1, kmemcheck is included in the mainline kernel.
|
||||
|
||||
|
||||
2. Configuring and compiling
|
||||
============================
|
||||
|
||||
kmemcheck only works for the x86 (both 32- and 64-bit) platform. A number of
|
||||
configuration variables must have specific settings in order for the kmemcheck
|
||||
menu to even appear in "menuconfig". These are:
|
||||
|
||||
o CONFIG_CC_OPTIMIZE_FOR_SIZE=n
|
||||
|
||||
This option is located under "General setup" / "Optimize for size".
|
||||
|
||||
Without this, gcc will use certain optimizations that usually lead to
|
||||
false positive warnings from kmemcheck. An example of this is a 16-bit
|
||||
field in a struct, where gcc may load 32 bits, then discard the upper
|
||||
16 bits. kmemcheck sees only the 32-bit load, and may trigger a
|
||||
warning for the upper 16 bits (if they're uninitialized).
|
||||
|
||||
o CONFIG_SLAB=y or CONFIG_SLUB=y
|
||||
|
||||
This option is located under "General setup" / "Choose SLAB
|
||||
allocator".
|
||||
|
||||
o CONFIG_FUNCTION_TRACER=n
|
||||
|
||||
This option is located under "Kernel hacking" / "Tracers" / "Kernel
|
||||
Function Tracer"
|
||||
|
||||
When function tracing is compiled in, gcc emits a call to another
|
||||
function at the beginning of every function. This means that when the
|
||||
page fault handler is called, the ftrace framework will be called
|
||||
before kmemcheck has had a chance to handle the fault. If ftrace then
|
||||
modifies memory that was tracked by kmemcheck, the result is an
|
||||
endless recursive page fault.
|
||||
|
||||
o CONFIG_DEBUG_PAGEALLOC=n
|
||||
|
||||
This option is located under "Kernel hacking" / "Memory Debugging"
|
||||
/ "Debug page memory allocations".
|
||||
|
||||
In addition, I highly recommend turning on CONFIG_DEBUG_INFO=y. This is also
|
||||
located under "Kernel hacking". With this, you will be able to get line number
|
||||
information from the kmemcheck warnings, which is extremely valuable in
|
||||
debugging a problem. This option is not mandatory, however, because it slows
|
||||
down the compilation process and produces a much bigger kernel image.
|
||||
|
||||
Now the kmemcheck menu should be visible (under "Kernel hacking" / "Memory
|
||||
Debugging" / "kmemcheck: trap use of uninitialized memory"). Here follows
|
||||
a description of the kmemcheck configuration variables:
|
||||
|
||||
o CONFIG_KMEMCHECK
|
||||
|
||||
This must be enabled in order to use kmemcheck at all...
|
||||
|
||||
o CONFIG_KMEMCHECK_[DISABLED | ENABLED | ONESHOT]_BY_DEFAULT
|
||||
|
||||
This option controls the status of kmemcheck at boot-time. "Enabled"
|
||||
will enable kmemcheck right from the start, "disabled" will boot the
|
||||
kernel as normal (but with the kmemcheck code compiled in, so it can
|
||||
be enabled at run-time after the kernel has booted), and "one-shot" is
|
||||
a special mode which will turn kmemcheck off automatically after
|
||||
detecting the first use of uninitialized memory.
|
||||
|
||||
If you are using kmemcheck to actively debug a problem, then you
|
||||
probably want to choose "enabled" here.
|
||||
|
||||
The one-shot mode is mostly useful in automated test setups because it
|
||||
can prevent floods of warnings and increase the chances of the machine
|
||||
surviving in case something is really wrong. In other cases, the one-
|
||||
shot mode could actually be counter-productive because it would turn
|
||||
itself off at the very first error -- in the case of a false positive
|
||||
too -- and this would come in the way of debugging the specific
|
||||
problem you were interested in.
|
||||
|
||||
If you would like to use your kernel as normal, but with a chance to
|
||||
enable kmemcheck in case of some problem, it might be a good idea to
|
||||
choose "disabled" here. When kmemcheck is disabled, most of the run-
|
||||
time overhead is not incurred, and the kernel will be almost as fast
|
||||
as normal.
|
||||
|
||||
o CONFIG_KMEMCHECK_QUEUE_SIZE
|
||||
|
||||
Select the maximum number of error reports to store in an internal
|
||||
(fixed-size) buffer. Since errors can occur virtually anywhere and in
|
||||
any context, we need a temporary storage area which is guaranteed not
|
||||
to generate any other page faults when accessed. The queue will be
|
||||
emptied as soon as a tasklet may be scheduled. If the queue is full,
|
||||
new error reports will be lost.
|
||||
|
||||
The default value of 64 is probably fine. If some code produces more
|
||||
than 64 errors within an irqs-off section, then the code is likely to
|
||||
produce many, many more, too, and these additional reports seldom give
|
||||
any more information (the first report is usually the most valuable
|
||||
anyway).
|
||||
|
||||
This number might have to be adjusted if you are not using serial
|
||||
console or similar to capture the kernel log. If you are using the
|
||||
"dmesg" command to save the log, then getting a lot of kmemcheck
|
||||
warnings might overflow the kernel log itself, and the earlier reports
|
||||
will get lost in that way instead. Try setting this to 10 or so on
|
||||
such a setup.
|
||||
|
||||
o CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT
|
||||
|
||||
Select the number of shadow bytes to save along with each entry of the
|
||||
error-report queue. These bytes indicate what parts of an allocation
|
||||
are initialized, uninitialized, etc. and will be displayed when an
|
||||
error is detected to help the debugging of a particular problem.
|
||||
|
||||
The number entered here is actually the logarithm of the number of
|
||||
bytes that will be saved. So if you pick for example 5 here, kmemcheck
|
||||
will save 2^5 = 32 bytes.
|
||||
|
||||
The default value should be fine for debugging most problems. It also
|
||||
fits nicely within 80 columns.
|
||||
|
||||
o CONFIG_KMEMCHECK_PARTIAL_OK
|
||||
|
||||
This option (when enabled) works around certain GCC optimizations that
|
||||
produce 32-bit reads from 16-bit variables where the upper 16 bits are
|
||||
thrown away afterwards.
|
||||
|
||||
The default value (enabled) is recommended. This may of course hide
|
||||
some real errors, but disabling it would probably produce a lot of
|
||||
false positives.
|
||||
|
||||
o CONFIG_KMEMCHECK_BITOPS_OK
|
||||
|
||||
This option silences warnings that would be generated for bit-field
|
||||
accesses where not all the bits are initialized at the same time. This
|
||||
may also hide some real bugs.
|
||||
|
||||
This option is probably obsolete, or it should be replaced with
|
||||
the kmemcheck-/bitfield-annotations for the code in question. The
|
||||
default value is therefore fine.
|
||||
|
||||
Now compile the kernel as usual.
|
||||
|
||||
|
||||
3. How to use
|
||||
=============
|
||||
|
||||
3.1. Booting
|
||||
============
|
||||
|
||||
First some information about the command-line options. There is only one
|
||||
option specific to kmemcheck, and this is called "kmemcheck". It can be used
|
||||
to override the default mode as chosen by the CONFIG_KMEMCHECK_*_BY_DEFAULT
|
||||
option. Its possible settings are:
|
||||
|
||||
o kmemcheck=0 (disabled)
|
||||
o kmemcheck=1 (enabled)
|
||||
o kmemcheck=2 (one-shot mode)
|
||||
|
||||
If SLUB debugging has been enabled in the kernel, it may take precedence over
|
||||
kmemcheck in such a way that the slab caches which are under SLUB debugging
|
||||
will not be tracked by kmemcheck. In order to ensure that this doesn't happen
|
||||
(even though it shouldn't by default), use SLUB's boot option "slub_debug",
|
||||
like this: slub_debug=-
|
||||
|
||||
In fact, this option may also be used for fine-grained control over SLUB vs.
|
||||
kmemcheck. For example, if the command line includes "kmemcheck=1
|
||||
slub_debug=,dentry", then SLUB debugging will be used only for the "dentry"
|
||||
slab cache, and with kmemcheck tracking all the other caches. This is advanced
|
||||
usage, however, and is not generally recommended.
|
||||
|
||||
|
||||
3.2. Run-time enable/disable
|
||||
============================
|
||||
|
||||
When the kernel has booted, it is possible to enable or disable kmemcheck at
|
||||
run-time. WARNING: This feature is still experimental and may cause false
|
||||
positive warnings to appear. Therefore, try not to use this. If you find that
|
||||
it doesn't work properly (e.g. you see an unreasonable amount of warnings), I
|
||||
will be happy to take bug reports.
|
||||
|
||||
Use the file /proc/sys/kernel/kmemcheck for this purpose, e.g.:
|
||||
|
||||
$ echo 0 > /proc/sys/kernel/kmemcheck # disables kmemcheck
|
||||
|
||||
The numbers are the same as for the kmemcheck= command-line option.
|
||||
|
||||
|
||||
3.3. Debugging
|
||||
==============
|
||||
|
||||
A typical report will look something like this:
|
||||
|
||||
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||
^
|
||||
|
||||
Pid: 1856, comm: ntpdate Not tainted 2.6.29-rc5 #264 945P-A
|
||||
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
||||
RSP: 0018:ffff88003cdf7d98 EFLAGS: 00210002
|
||||
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
||||
RDX: ffff88003e5d6018 RSI: ffff88003e5d6024 RDI: ffff88003cdf7e84
|
||||
RBP: ffff88003cdf7db8 R08: ffff88003e5d6000 R09: 0000000000000000
|
||||
R10: 0000000000000080 R11: 0000000000000000 R12: 000000000000000e
|
||||
R13: ffff88003cdf7e78 R14: ffff88003d530710 R15: ffff88003d5a98c8
|
||||
FS: 0000000000000000(0000) GS:ffff880001982000(0063) knlGS:00000
|
||||
CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033
|
||||
CR2: ffff88003f806ea0 CR3: 000000003c036000 CR4: 00000000000006a0
|
||||
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
|
||||
DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400
|
||||
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
||||
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
||||
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
||||
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
||||
[<ffffffffffffffff>] 0xffffffffffffffff
|
||||
|
||||
The single most valuable information in this report is the RIP (or EIP on 32-
|
||||
bit) value. This will help us pinpoint exactly which instruction that caused
|
||||
the warning.
|
||||
|
||||
If your kernel was compiled with CONFIG_DEBUG_INFO=y, then all we have to do
|
||||
is give this address to the addr2line program, like this:
|
||||
|
||||
$ addr2line -e vmlinux -i ffffffff8104ede8
|
||||
arch/x86/include/asm/string_64.h:12
|
||||
include/asm-generic/siginfo.h:287
|
||||
kernel/signal.c:380
|
||||
kernel/signal.c:410
|
||||
|
||||
The "-e vmlinux" tells addr2line which file to look in. IMPORTANT: This must
|
||||
be the vmlinux of the kernel that produced the warning in the first place! If
|
||||
not, the line number information will almost certainly be wrong.
|
||||
|
||||
The "-i" tells addr2line to also print the line numbers of inlined functions.
|
||||
In this case, the flag was very important, because otherwise, it would only
|
||||
have printed the first line, which is just a call to memcpy(), which could be
|
||||
called from a thousand places in the kernel, and is therefore not very useful.
|
||||
These inlined functions would not show up in the stack trace above, simply
|
||||
because the kernel doesn't load the extra debugging information. This
|
||||
technique can of course be used with ordinary kernel oopses as well.
|
||||
|
||||
In this case, it's the caller of memcpy() that is interesting, and it can be
|
||||
found in include/asm-generic/siginfo.h, line 287:
|
||||
|
||||
281 static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
|
||||
282 {
|
||||
283 if (from->si_code < 0)
|
||||
284 memcpy(to, from, sizeof(*to));
|
||||
285 else
|
||||
286 /* _sigchld is currently the largest know union member */
|
||||
287 memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
|
||||
288 }
|
||||
|
||||
Since this was a read (kmemcheck usually warns about reads only, though it can
|
||||
warn about writes to unallocated or freed memory as well), it was probably the
|
||||
"from" argument which contained some uninitialized bytes. Following the chain
|
||||
of calls, we move upwards to see where "from" was allocated or initialized,
|
||||
kernel/signal.c, line 380:
|
||||
|
||||
359 static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
|
||||
360 {
|
||||
...
|
||||
367 list_for_each_entry(q, &list->list, list) {
|
||||
368 if (q->info.si_signo == sig) {
|
||||
369 if (first)
|
||||
370 goto still_pending;
|
||||
371 first = q;
|
||||
...
|
||||
377 if (first) {
|
||||
378 still_pending:
|
||||
379 list_del_init(&first->list);
|
||||
380 copy_siginfo(info, &first->info);
|
||||
381 __sigqueue_free(first);
|
||||
...
|
||||
392 }
|
||||
393 }
|
||||
|
||||
Here, it is &first->info that is being passed on to copy_siginfo(). The
|
||||
variable "first" was found on a list -- passed in as the second argument to
|
||||
collect_signal(). We continue our journey through the stack, to figure out
|
||||
where the item on "list" was allocated or initialized. We move to line 410:
|
||||
|
||||
395 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
|
||||
396 siginfo_t *info)
|
||||
397 {
|
||||
...
|
||||
410 collect_signal(sig, pending, info);
|
||||
...
|
||||
414 }
|
||||
|
||||
Now we need to follow the "pending" pointer, since that is being passed on to
|
||||
collect_signal() as "list". At this point, we've run out of lines from the
|
||||
"addr2line" output. Not to worry, we just paste the next addresses from the
|
||||
kmemcheck stack dump, i.e.:
|
||||
|
||||
[<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
|
||||
[<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
|
||||
[<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
|
||||
[<ffffffff8100c7b5>] int_signal+0x12/0x17
|
||||
|
||||
$ addr2line -e vmlinux -i ffffffff8104f04e ffffffff81050bd8 \
|
||||
ffffffff8100b87d ffffffff8100c7b5
|
||||
kernel/signal.c:446
|
||||
kernel/signal.c:1806
|
||||
arch/x86/kernel/signal.c:805
|
||||
arch/x86/kernel/signal.c:871
|
||||
arch/x86/kernel/entry_64.S:694
|
||||
|
||||
Remember that since these addresses were found on the stack and not as the
|
||||
RIP value, they actually point to the _next_ instruction (they are return
|
||||
addresses). This becomes obvious when we look at the code for line 446:
|
||||
|
||||
422 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
|
||||
423 {
|
||||
...
|
||||
431 signr = __dequeue_signal(&tsk->signal->shared_pending,
|
||||
432 mask, info);
|
||||
433 /*
|
||||
434 * itimer signal ?
|
||||
435 *
|
||||
436 * itimers are process shared and we restart periodic
|
||||
437 * itimers in the signal delivery path to prevent DoS
|
||||
438 * attacks in the high resolution timer case. This is
|
||||
439 * compliant with the old way of self restarting
|
||||
440 * itimers, as the SIGALRM is a legacy signal and only
|
||||
441 * queued once. Changing the restart behaviour to
|
||||
442 * restart the timer in the signal dequeue path is
|
||||
443 * reducing the timer noise on heavy loaded !highres
|
||||
444 * systems too.
|
||||
445 */
|
||||
446 if (unlikely(signr == SIGALRM)) {
|
||||
...
|
||||
489 }
|
||||
|
||||
So instead of looking at 446, we should be looking at 431, which is the line
|
||||
that executes just before 446. Here we see that what we are looking for is
|
||||
&tsk->signal->shared_pending.
|
||||
|
||||
Our next task is now to figure out which function that puts items on this
|
||||
"shared_pending" list. A crude, but efficient tool, is git grep:
|
||||
|
||||
$ git grep -n 'shared_pending' kernel/
|
||||
...
|
||||
kernel/signal.c:828: pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
kernel/signal.c:1339: pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
...
|
||||
|
||||
There were more results, but none of them were related to list operations,
|
||||
and these were the only assignments. We inspect the line numbers more closely
|
||||
and find that this is indeed where items are being added to the list:
|
||||
|
||||
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
||||
817 int group)
|
||||
818 {
|
||||
...
|
||||
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
...
|
||||
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
||||
852 (is_si_special(info) ||
|
||||
853 info->si_code >= 0)));
|
||||
854 if (q) {
|
||||
855 list_add_tail(&q->list, &pending->list);
|
||||
...
|
||||
890 }
|
||||
|
||||
and:
|
||||
|
||||
1309 int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
|
||||
1310 {
|
||||
....
|
||||
1339 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
1340 list_add_tail(&q->list, &pending->list);
|
||||
....
|
||||
1347 }
|
||||
|
||||
In the first case, the list element we are looking for, "q", is being returned
|
||||
from the function __sigqueue_alloc(), which looks like an allocation function.
|
||||
Let's take a look at it:
|
||||
|
||||
187 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
|
||||
188 int override_rlimit)
|
||||
189 {
|
||||
190 struct sigqueue *q = NULL;
|
||||
191 struct user_struct *user;
|
||||
192
|
||||
193 /*
|
||||
194 * We won't get problems with the target's UID changing under us
|
||||
195 * because changing it requires RCU be used, and if t != current, the
|
||||
196 * caller must be holding the RCU readlock (by way of a spinlock) and
|
||||
197 * we use RCU protection here
|
||||
198 */
|
||||
199 user = get_uid(__task_cred(t)->user);
|
||||
200 atomic_inc(&user->sigpending);
|
||||
201 if (override_rlimit ||
|
||||
202 atomic_read(&user->sigpending) <=
|
||||
203 t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
|
||||
204 q = kmem_cache_alloc(sigqueue_cachep, flags);
|
||||
205 if (unlikely(q == NULL)) {
|
||||
206 atomic_dec(&user->sigpending);
|
||||
207 free_uid(user);
|
||||
208 } else {
|
||||
209 INIT_LIST_HEAD(&q->list);
|
||||
210 q->flags = 0;
|
||||
211 q->user = user;
|
||||
212 }
|
||||
213
|
||||
214 return q;
|
||||
215 }
|
||||
|
||||
We see that this function initializes q->list, q->flags, and q->user. It seems
|
||||
that now is the time to look at the definition of "struct sigqueue", e.g.:
|
||||
|
||||
14 struct sigqueue {
|
||||
15 struct list_head list;
|
||||
16 int flags;
|
||||
17 siginfo_t info;
|
||||
18 struct user_struct *user;
|
||||
19 };
|
||||
|
||||
And, you might remember, it was a memcpy() on &first->info that caused the
|
||||
warning, so this makes perfect sense. It also seems reasonable to assume that
|
||||
it is the caller of __sigqueue_alloc() that has the responsibility of filling
|
||||
out (initializing) this member.
|
||||
|
||||
But just which fields of the struct were uninitialized? Let's look at
|
||||
kmemcheck's report again:
|
||||
|
||||
WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
|
||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||
^
|
||||
|
||||
These first two lines are the memory dump of the memory object itself, and the
|
||||
shadow bytemap, respectively. The memory object itself is in this case
|
||||
&first->info. Just beware that the start of this dump is NOT the start of the
|
||||
object itself! The position of the caret (^) corresponds with the address of
|
||||
the read (ffff88003e4a2024).
|
||||
|
||||
The shadow bytemap dump legend is as follows:
|
||||
|
||||
i - initialized
|
||||
u - uninitialized
|
||||
a - unallocated (memory has been allocated by the slab layer, but has not
|
||||
yet been handed off to anybody)
|
||||
f - freed (memory has been allocated by the slab layer, but has been freed
|
||||
by the previous owner)
|
||||
|
||||
In order to figure out where (relative to the start of the object) the
|
||||
uninitialized memory was located, we have to look at the disassembly. For
|
||||
that, we'll need the RIP address again:
|
||||
|
||||
RIP: 0010:[<ffffffff8104ede8>] [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
|
||||
|
||||
$ objdump -d --no-show-raw-insn vmlinux | grep -C 8 ffffffff8104ede8:
|
||||
ffffffff8104edc8: mov %r8,0x8(%r8)
|
||||
ffffffff8104edcc: test %r10d,%r10d
|
||||
ffffffff8104edcf: js ffffffff8104ee88 <__dequeue_signal+0x168>
|
||||
ffffffff8104edd5: mov %rax,%rdx
|
||||
ffffffff8104edd8: mov $0xc,%ecx
|
||||
ffffffff8104eddd: mov %r13,%rdi
|
||||
ffffffff8104ede0: mov $0x30,%eax
|
||||
ffffffff8104ede5: mov %rdx,%rsi
|
||||
ffffffff8104ede8: rep movsl %ds:(%rsi),%es:(%rdi)
|
||||
ffffffff8104edea: test $0x2,%al
|
||||
ffffffff8104edec: je ffffffff8104edf0 <__dequeue_signal+0xd0>
|
||||
ffffffff8104edee: movsw %ds:(%rsi),%es:(%rdi)
|
||||
ffffffff8104edf0: test $0x1,%al
|
||||
ffffffff8104edf2: je ffffffff8104edf5 <__dequeue_signal+0xd5>
|
||||
ffffffff8104edf4: movsb %ds:(%rsi),%es:(%rdi)
|
||||
ffffffff8104edf5: mov %r8,%rdi
|
||||
ffffffff8104edf8: callq ffffffff8104de60 <__sigqueue_free>
|
||||
|
||||
As expected, it's the "rep movsl" instruction from the memcpy() that causes
|
||||
the warning. We know about REP MOVSL that it uses the register RCX to count
|
||||
the number of remaining iterations. By taking a look at the register dump
|
||||
again (from the kmemcheck report), we can figure out how many bytes were left
|
||||
to copy:
|
||||
|
||||
RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
|
||||
|
||||
By looking at the disassembly, we also see that %ecx is being loaded with the
|
||||
value $0xc just before (ffffffff8104edd8), so we are very lucky. Keep in mind
|
||||
that this is the number of iterations, not bytes. And since this is a "long"
|
||||
operation, we need to multiply by 4 to get the number of bytes. So this means
|
||||
that the uninitialized value was encountered at 4 * (0xc - 0x9) = 12 bytes
|
||||
from the start of the object.
|
||||
|
||||
We can now try to figure out which field of the "struct siginfo" that was not
|
||||
initialized. This is the beginning of the struct:
|
||||
|
||||
40 typedef struct siginfo {
|
||||
41 int si_signo;
|
||||
42 int si_errno;
|
||||
43 int si_code;
|
||||
44
|
||||
45 union {
|
||||
..
|
||||
92 } _sifields;
|
||||
93 } siginfo_t;
|
||||
|
||||
On 64-bit, the int is 4 bytes long, so it must the union member that has
|
||||
not been initialized. We can verify this using gdb:
|
||||
|
||||
$ gdb vmlinux
|
||||
...
|
||||
(gdb) p &((struct siginfo *) 0)->_sifields
|
||||
$1 = (union {...} *) 0x10
|
||||
|
||||
Actually, it seems that the union member is located at offset 0x10 -- which
|
||||
means that gcc has inserted 4 bytes of padding between the members si_code
|
||||
and _sifields. We can now get a fuller picture of the memory dump:
|
||||
|
||||
_----------------------------=> si_code
|
||||
/ _--------------------=> (padding)
|
||||
| / _------------=> _sifields(._kill._pid)
|
||||
| | / _----=> _sifields(._kill._uid)
|
||||
| | | /
|
||||
-------|-------|-------|-------|
|
||||
80000000000000000000000000000000000000000088ffff0000000000000000
|
||||
i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
|
||||
|
||||
This allows us to realize another important fact: si_code contains the value
|
||||
0x80. Remember that x86 is little endian, so the first 4 bytes "80000000" are
|
||||
really the number 0x00000080. With a bit of research, we find that this is
|
||||
actually the constant SI_KERNEL defined in include/asm-generic/siginfo.h:
|
||||
|
||||
144 #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
||||
|
||||
This macro is used in exactly one place in the x86 kernel: In send_signal()
|
||||
in kernel/signal.c:
|
||||
|
||||
816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
||||
817 int group)
|
||||
818 {
|
||||
...
|
||||
828 pending = group ? &t->signal->shared_pending : &t->pending;
|
||||
...
|
||||
851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
|
||||
852 (is_si_special(info) ||
|
||||
853 info->si_code >= 0)));
|
||||
854 if (q) {
|
||||
855 list_add_tail(&q->list, &pending->list);
|
||||
856 switch ((unsigned long) info) {
|
||||
...
|
||||
865 case (unsigned long) SEND_SIG_PRIV:
|
||||
866 q->info.si_signo = sig;
|
||||
867 q->info.si_errno = 0;
|
||||
868 q->info.si_code = SI_KERNEL;
|
||||
869 q->info.si_pid = 0;
|
||||
870 q->info.si_uid = 0;
|
||||
871 break;
|
||||
...
|
||||
890 }
|
||||
|
||||
Not only does this match with the .si_code member, it also matches the place
|
||||
we found earlier when looking for where siginfo_t objects are enqueued on the
|
||||
"shared_pending" list.
|
||||
|
||||
So to sum up: It seems that it is the padding introduced by the compiler
|
||||
between two struct fields that is uninitialized, and this gets reported when
|
||||
we do a memcpy() on the struct. This means that we have identified a false
|
||||
positive warning.
|
||||
|
||||
Normally, kmemcheck will not report uninitialized accesses in memcpy() calls
|
||||
when both the source and destination addresses are tracked. (Instead, we copy
|
||||
the shadow bytemap as well). In this case, the destination address clearly
|
||||
was not tracked. We can dig a little deeper into the stack trace from above:
|
||||
|
||||
arch/x86/kernel/signal.c:805
|
||||
arch/x86/kernel/signal.c:871
|
||||
arch/x86/kernel/entry_64.S:694
|
||||
|
||||
And we clearly see that the destination siginfo object is located on the
|
||||
stack:
|
||||
|
||||
782 static void do_signal(struct pt_regs *regs)
|
||||
783 {
|
||||
784 struct k_sigaction ka;
|
||||
785 siginfo_t info;
|
||||
...
|
||||
804 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||
...
|
||||
854 }
|
||||
|
||||
And this &info is what eventually gets passed to copy_siginfo() as the
|
||||
destination argument.
|
||||
|
||||
Now, even though we didn't find an actual error here, the example is still a
|
||||
good one, because it shows how one would go about to find out what the report
|
||||
was all about.
|
||||
|
||||
|
||||
3.4. Annotating false positives
|
||||
===============================
|
||||
|
||||
There are a few different ways to make annotations in the source code that
|
||||
will keep kmemcheck from checking and reporting certain allocations. Here
|
||||
they are:
|
||||
|
||||
o __GFP_NOTRACK_FALSE_POSITIVE
|
||||
|
||||
This flag can be passed to kmalloc() or kmem_cache_alloc() (therefore
|
||||
also to other functions that end up calling one of these) to indicate
|
||||
that the allocation should not be tracked because it would lead to
|
||||
a false positive report. This is a "big hammer" way of silencing
|
||||
kmemcheck; after all, even if the false positive pertains to
|
||||
particular field in a struct, for example, we will now lose the
|
||||
ability to find (real) errors in other parts of the same struct.
|
||||
|
||||
Example:
|
||||
|
||||
/* No warnings will ever trigger on accessing any part of x */
|
||||
x = kmalloc(sizeof *x, GFP_KERNEL | __GFP_NOTRACK_FALSE_POSITIVE);
|
||||
|
||||
o kmemcheck_bitfield_begin(name)/kmemcheck_bitfield_end(name) and
|
||||
kmemcheck_annotate_bitfield(ptr, name)
|
||||
|
||||
The first two of these three macros can be used inside struct
|
||||
definitions to signal, respectively, the beginning and end of a
|
||||
bitfield. Additionally, this will assign the bitfield a name, which
|
||||
is given as an argument to the macros.
|
||||
|
||||
Having used these markers, one can later use
|
||||
kmemcheck_annotate_bitfield() at the point of allocation, to indicate
|
||||
which parts of the allocation is part of a bitfield.
|
||||
|
||||
Example:
|
||||
|
||||
struct foo {
|
||||
int x;
|
||||
|
||||
kmemcheck_bitfield_begin(flags);
|
||||
int flag_a:1;
|
||||
int flag_b:1;
|
||||
kmemcheck_bitfield_end(flags);
|
||||
|
||||
int y;
|
||||
};
|
||||
|
||||
struct foo *x = kmalloc(sizeof *x);
|
||||
|
||||
/* No warnings will trigger on accessing the bitfield of x */
|
||||
kmemcheck_annotate_bitfield(x, flags);
|
||||
|
||||
Note that kmemcheck_annotate_bitfield() can be used even before the
|
||||
return value of kmalloc() is checked -- in other words, passing NULL
|
||||
as the first argument is legal (and will do nothing).
|
||||
|
||||
|
||||
4. Reporting errors
|
||||
===================
|
||||
|
||||
As we have seen, kmemcheck will produce false positive reports. Therefore, it
|
||||
is not very wise to blindly post kmemcheck warnings to mailing lists and
|
||||
maintainers. Instead, I encourage maintainers and developers to find errors
|
||||
in their own code. If you get a warning, you can try to work around it, try
|
||||
to figure out if it's a real error or not, or simply ignore it. Most
|
||||
developers know their own code and will quickly and efficiently determine the
|
||||
root cause of a kmemcheck report. This is therefore also the most efficient
|
||||
way to work with kmemcheck.
|
||||
|
||||
That said, we (the kmemcheck maintainers) will always be on the lookout for
|
||||
false positives that we can annotate and silence. So whatever you find,
|
||||
please drop us a note privately! Kernel configs and steps to reproduce (if
|
||||
available) are of course a great help too.
|
||||
|
||||
Happy hacking!
|
||||
|
||||
|
||||
5. Technical description
|
||||
========================
|
||||
|
||||
kmemcheck works by marking memory pages non-present. This means that whenever
|
||||
somebody attempts to access the page, a page fault is generated. The page
|
||||
fault handler notices that the page was in fact only hidden, and so it calls
|
||||
on the kmemcheck code to make further investigations.
|
||||
|
||||
When the investigations are completed, kmemcheck "shows" the page by marking
|
||||
it present (as it would be under normal circumstances). This way, the
|
||||
interrupted code can continue as usual.
|
||||
|
||||
But after the instruction has been executed, we should hide the page again, so
|
||||
that we can catch the next access too! Now kmemcheck makes use of a debugging
|
||||
feature of the processor, namely single-stepping. When the processor has
|
||||
finished the one instruction that generated the memory access, a debug
|
||||
exception is raised. From here, we simply hide the page again and continue
|
||||
execution, this time with the single-stepping feature turned off.
|
||||
|
||||
kmemcheck requires some assistance from the memory allocator in order to work.
|
||||
The memory allocator needs to
|
||||
|
||||
1. Tell kmemcheck about newly allocated pages and pages that are about to
|
||||
be freed. This allows kmemcheck to set up and tear down the shadow memory
|
||||
for the pages in question. The shadow memory stores the status of each
|
||||
byte in the allocation proper, e.g. whether it is initialized or
|
||||
uninitialized.
|
||||
|
||||
2. Tell kmemcheck which parts of memory should be marked uninitialized.
|
||||
There are actually a few more states, such as "not yet allocated" and
|
||||
"recently freed".
|
||||
|
||||
If a slab cache is set up using the SLAB_NOTRACK flag, it will never return
|
||||
memory that can take page faults because of kmemcheck.
|
||||
|
||||
If a slab cache is NOT set up using the SLAB_NOTRACK flag, callers can still
|
||||
request memory with the __GFP_NOTRACK or __GFP_NOTRACK_FALSE_POSITIVE flags.
|
||||
This does not prevent the page faults from occurring, however, but marks the
|
||||
object in question as being initialized so that no warnings will ever be
|
||||
produced for this object.
|
||||
|
||||
Currently, the SLAB and SLUB allocators are supported by kmemcheck.
|
|
@ -103,6 +103,16 @@ Note that the probed function's args may be passed on the stack
|
|||
or in registers. The jprobe will work in either case, so long as the
|
||||
handler's prototype matches that of the probed function.
|
||||
|
||||
Note that in some architectures (e.g.: arm64 and sparc64) the stack
|
||||
copy is not done, as the actual location of stacked parameters may be
|
||||
outside of a reasonable MAX_STACK_SIZE value and because that location
|
||||
cannot be determined by the jprobes code. In this case the jprobes
|
||||
user must be careful to make certain the calling signature of the
|
||||
function does not cause parameters to be passed on the stack (e.g.:
|
||||
more than eight function arguments, an argument of more than sixteen
|
||||
bytes, or more than 64 bytes of argument data, depending on
|
||||
architecture).
|
||||
|
||||
1.3 Return Probes
|
||||
|
||||
1.3.1 How Does a Return Probe Work?
|
||||
|
|
|
@ -10,7 +10,8 @@ FILES = audio.h.rst ca.h.rst dmx.h.rst frontend.h.rst net.h.rst video.h.rst \
|
|||
|
||||
TARGETS := $(addprefix $(BUILDDIR)/, $(FILES))
|
||||
|
||||
htmldocs: $(BUILDDIR) ${TARGETS}
|
||||
.PHONY: all
|
||||
all: $(BUILDDIR) ${TARGETS}
|
||||
|
||||
$(BUILDDIR):
|
||||
$(Q)mkdir -p $@
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
ignore define _DVBAUDIO_H_
|
||||
|
||||
# Typedef pointing to structs
|
||||
replace typedef audio_karaoke_t audio-karaoke
|
||||
replace typedef audio_karaoke_t :c:type:`audio_karaoke`
|
||||
|
||||
# Undocumented audio caps, as this is a deprecated API anyway
|
||||
ignore define AUDIO_CAP_DTS
|
||||
|
@ -16,5 +16,5 @@ ignore define AUDIO_CAP_SDDS
|
|||
ignore define AUDIO_CAP_AC3
|
||||
|
||||
# some typedefs should point to struct/enums
|
||||
replace typedef audio_mixer_t audio-mixer
|
||||
replace typedef audio_status_t audio-status
|
||||
replace typedef audio_mixer_t :c:type:`audio_mixer`
|
||||
replace typedef audio_status_t :c:type:`audio_status`
|
||||
|
|
|
@ -2,23 +2,23 @@
|
|||
ignore define _DVBCA_H_
|
||||
|
||||
# struct ca_slot_info defines
|
||||
replace define CA_CI ca-slot-info
|
||||
replace define CA_CI_LINK ca-slot-info
|
||||
replace define CA_CI_PHYS ca-slot-info
|
||||
replace define CA_DESCR ca-slot-info
|
||||
replace define CA_SC ca-slot-info
|
||||
replace define CA_CI_MODULE_PRESENT ca-slot-info
|
||||
replace define CA_CI_MODULE_READY ca-slot-info
|
||||
replace define CA_CI :c:type:`ca_slot_info`
|
||||
replace define CA_CI_LINK :c:type:`ca_slot_info`
|
||||
replace define CA_CI_PHYS :c:type:`ca_slot_info`
|
||||
replace define CA_DESCR :c:type:`ca_slot_info`
|
||||
replace define CA_SC :c:type:`ca_slot_info`
|
||||
replace define CA_CI_MODULE_PRESENT :c:type:`ca_slot_info`
|
||||
replace define CA_CI_MODULE_READY :c:type:`ca_slot_info`
|
||||
|
||||
# struct ca_descr_info defines
|
||||
replace define CA_ECD ca-descr-info
|
||||
replace define CA_NDS ca-descr-info
|
||||
replace define CA_DSS ca-descr-info
|
||||
replace define CA_ECD :c:type:`ca_descr_info`
|
||||
replace define CA_NDS :c:type:`ca_descr_info`
|
||||
replace define CA_DSS :c:type:`ca_descr_info`
|
||||
|
||||
# some typedefs should point to struct/enums
|
||||
replace typedef ca_pid_t ca-pid
|
||||
replace typedef ca_slot_info_t ca-slot-info
|
||||
replace typedef ca_descr_info_t ca-descr-info
|
||||
replace typedef ca_caps_t ca-caps
|
||||
replace typedef ca_msg_t ca-msg
|
||||
replace typedef ca_descr_t ca-descr
|
||||
replace typedef ca_pid_t :c:type:`ca_pid`
|
||||
replace typedef ca_slot_info_t :c:type:`ca_slot_info`
|
||||
replace typedef ca_descr_info_t :c:type:`ca_descr_info`
|
||||
replace typedef ca_caps_t :c:type:`ca_caps`
|
||||
replace typedef ca_msg_t :c:type:`ca_msg`
|
||||
replace typedef ca_descr_t :c:type:`ca_descr`
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
# Ignore header name
|
||||
ignore define _CEC_UAPI_H
|
||||
|
||||
# Rename some symbols, to avoid namespace conflicts
|
||||
replace struct cec_event_state_change cec-event-state-change_s
|
||||
replace struct cec_event_lost_msgs cec-event-lost-msgs_s
|
||||
replace enum cec_mode_initiator cec-mode-initiator_e
|
||||
replace enum cec_mode_follower cec-mode-follower_e
|
||||
|
||||
# define macros to ignore
|
||||
|
||||
ignore define CEC_MAX_MSG_SIZE
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# -*- coding: utf-8; mode: python -*-
|
||||
|
||||
project = 'Linux Media Subsystem Documentation'
|
||||
|
||||
tags.add("subproject")
|
||||
|
||||
latex_documents = [
|
||||
('index', 'media.tex', 'Linux Media Subsystem Documentation',
|
||||
'The kernel development community', 'manual'),
|
||||
]
|
|
@ -0,0 +1,109 @@
|
|||
# -*- coding: utf-8; mode: python -*-
|
||||
|
||||
project = 'Linux Media Subsystem Documentation'
|
||||
|
||||
# It is possible to run Sphinx in nickpick mode with:
|
||||
nitpicky = True
|
||||
|
||||
# within nit-picking build, do not refer to any intersphinx object
|
||||
intersphinx_mapping = {}
|
||||
|
||||
# In nickpick mode, it will complain about lots of missing references that
|
||||
#
|
||||
# 1) are just typedefs like: bool, __u32, etc;
|
||||
# 2) It will complain for things like: enum, NULL;
|
||||
# 3) It will complain for symbols that should be on different
|
||||
# books (but currently aren't ported to ReST)
|
||||
#
|
||||
# The list below has a list of such symbols to be ignored in nitpick mode
|
||||
#
|
||||
nitpick_ignore = [
|
||||
("c:func", "clock_gettime"),
|
||||
("c:func", "close"),
|
||||
("c:func", "container_of"),
|
||||
("c:func", "copy_from_user"),
|
||||
("c:func", "copy_to_user"),
|
||||
("c:func", "determine_valid_ioctls"),
|
||||
("c:func", "ERR_PTR"),
|
||||
("c:func", "i2c_new_device"),
|
||||
("c:func", "ioctl"),
|
||||
("c:func", "IS_ERR"),
|
||||
("c:func", "KERNEL_VERSION"),
|
||||
("c:func", "mmap"),
|
||||
("c:func", "open"),
|
||||
("c:func", "pci_name"),
|
||||
("c:func", "poll"),
|
||||
("c:func", "PTR_ERR"),
|
||||
("c:func", "read"),
|
||||
("c:func", "release"),
|
||||
("c:func", "set"),
|
||||
("c:func", "struct fd_set"),
|
||||
("c:func", "struct pollfd"),
|
||||
("c:func", "usb_make_path"),
|
||||
("c:func", "wait_finish"),
|
||||
("c:func", "wait_prepare"),
|
||||
("c:func", "write"),
|
||||
|
||||
("c:type", "atomic_t"),
|
||||
("c:type", "bool"),
|
||||
("c:type", "boolean"),
|
||||
("c:type", "buf_queue"),
|
||||
("c:type", "device"),
|
||||
("c:type", "device_driver"),
|
||||
("c:type", "device_node"),
|
||||
("c:type", "enum"),
|
||||
("c:type", "fd"),
|
||||
("c:type", "fd_set"),
|
||||
("c:type", "file"),
|
||||
("c:type", "i2c_adapter"),
|
||||
("c:type", "i2c_board_info"),
|
||||
("c:type", "i2c_client"),
|
||||
("c:type", "int16_t"),
|
||||
("c:type", "ktime_t"),
|
||||
("c:type", "led_classdev_flash"),
|
||||
("c:type", "list_head"),
|
||||
("c:type", "lock_class_key"),
|
||||
("c:type", "module"),
|
||||
("c:type", "mutex"),
|
||||
("c:type", "NULL"),
|
||||
("c:type", "off_t"),
|
||||
("c:type", "pci_dev"),
|
||||
("c:type", "pdvbdev"),
|
||||
("c:type", "poll_table"),
|
||||
("c:type", "platform_device"),
|
||||
("c:type", "pollfd"),
|
||||
("c:type", "poll_table_struct"),
|
||||
("c:type", "s32"),
|
||||
("c:type", "s64"),
|
||||
("c:type", "sd"),
|
||||
("c:type", "size_t"),
|
||||
("c:type", "spi_board_info"),
|
||||
("c:type", "spi_device"),
|
||||
("c:type", "spi_master"),
|
||||
("c:type", "ssize_t"),
|
||||
("c:type", "fb_fix_screeninfo"),
|
||||
("c:type", "pollfd"),
|
||||
("c:type", "timeval"),
|
||||
("c:type", "video_capability"),
|
||||
("c:type", "timeval"),
|
||||
("c:type", "__u16"),
|
||||
("c:type", "u16"),
|
||||
("c:type", "__u32"),
|
||||
("c:type", "u32"),
|
||||
("c:type", "__u64"),
|
||||
("c:type", "u64"),
|
||||
("c:type", "u8"),
|
||||
("c:type", "uint16_t"),
|
||||
("c:type", "uint32_t"),
|
||||
("c:type", "union"),
|
||||
("c:type", "__user"),
|
||||
("c:type", "usb_device"),
|
||||
("c:type", "usb_interface"),
|
||||
("c:type", "v4l2_std_id"),
|
||||
("c:type", "video_system_t"),
|
||||
("c:type", "vm_area_struct"),
|
||||
|
||||
# Opaque structures
|
||||
|
||||
("c:type", "v4l2_m2m_dev"),
|
||||
]
|
|
@ -4,29 +4,29 @@ ignore define _UAPI_DVBDMX_H_
|
|||
# Ignore limit constants
|
||||
ignore define DMX_FILTER_SIZE
|
||||
|
||||
# dmx-pes-type-t enum symbols
|
||||
replace enum dmx_ts_pes dmx-pes-type-t
|
||||
replace symbol DMX_PES_AUDIO0 dmx-pes-type-t
|
||||
replace symbol DMX_PES_VIDEO0 dmx-pes-type-t
|
||||
replace symbol DMX_PES_TELETEXT0 dmx-pes-type-t
|
||||
replace symbol DMX_PES_SUBTITLE0 dmx-pes-type-t
|
||||
replace symbol DMX_PES_PCR0 dmx-pes-type-t
|
||||
replace symbol DMX_PES_AUDIO1 dmx-pes-type-t
|
||||
replace symbol DMX_PES_VIDEO1 dmx-pes-type-t
|
||||
replace symbol DMX_PES_TELETEXT1 dmx-pes-type-t
|
||||
replace symbol DMX_PES_SUBTITLE1 dmx-pes-type-t
|
||||
replace symbol DMX_PES_PCR1 dmx-pes-type-t
|
||||
replace symbol DMX_PES_AUDIO2 dmx-pes-type-t
|
||||
replace symbol DMX_PES_VIDEO2 dmx-pes-type-t
|
||||
replace symbol DMX_PES_TELETEXT2 dmx-pes-type-t
|
||||
replace symbol DMX_PES_SUBTITLE2 dmx-pes-type-t
|
||||
replace symbol DMX_PES_PCR2 dmx-pes-type-t
|
||||
replace symbol DMX_PES_AUDIO3 dmx-pes-type-t
|
||||
replace symbol DMX_PES_VIDEO3 dmx-pes-type-t
|
||||
replace symbol DMX_PES_TELETEXT3 dmx-pes-type-t
|
||||
replace symbol DMX_PES_SUBTITLE3 dmx-pes-type-t
|
||||
replace symbol DMX_PES_PCR3 dmx-pes-type-t
|
||||
replace symbol DMX_PES_OTHER dmx-pes-type-t
|
||||
# dmx_pes_type_t enum symbols
|
||||
replace enum dmx_ts_pes :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_AUDIO0 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_VIDEO0 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_TELETEXT0 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_SUBTITLE0 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_PCR0 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_AUDIO1 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_VIDEO1 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_TELETEXT1 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_SUBTITLE1 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_PCR1 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_AUDIO2 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_VIDEO2 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_TELETEXT2 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_SUBTITLE2 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_PCR2 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_AUDIO3 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_VIDEO3 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_TELETEXT3 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_SUBTITLE3 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_PCR3 :c:type:`dmx_pes_type`
|
||||
replace symbol DMX_PES_OTHER :c:type:`dmx_pes_type`
|
||||
|
||||
# Ignore obsolete symbols
|
||||
ignore define DMX_PES_AUDIO
|
||||
|
@ -36,28 +36,31 @@ ignore define DMX_PES_SUBTITLE
|
|||
ignore define DMX_PES_PCR
|
||||
|
||||
# dmx_input_t symbols
|
||||
replace enum dmx_input dmx-input-t
|
||||
replace symbol DMX_IN_FRONTEND dmx-input-t
|
||||
replace symbol DMX_IN_DVR dmx-input-t
|
||||
replace enum dmx_input :c:type:`dmx_input`
|
||||
replace symbol DMX_IN_FRONTEND :c:type:`dmx_input`
|
||||
replace symbol DMX_IN_DVR :c:type:`dmx_input`
|
||||
|
||||
# dmx_source_t symbols
|
||||
replace enum dmx_source dmx-source-t
|
||||
replace symbol DMX_SOURCE_FRONT0 dmx-source-t
|
||||
replace symbol DMX_SOURCE_FRONT1 dmx-source-t
|
||||
replace symbol DMX_SOURCE_FRONT2 dmx-source-t
|
||||
replace symbol DMX_SOURCE_FRONT3 dmx-source-t
|
||||
replace symbol DMX_SOURCE_DVR0 dmx-source-t
|
||||
replace symbol DMX_SOURCE_DVR1 dmx-source-t
|
||||
replace symbol DMX_SOURCE_DVR2 dmx-source-t
|
||||
replace symbol DMX_SOURCE_DVR3 dmx-source-t
|
||||
replace enum dmx_source :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_FRONT0 :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_FRONT1 :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_FRONT2 :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_FRONT3 :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_DVR0 :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_DVR1 :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_DVR2 :c:type:`dmx_source`
|
||||
replace symbol DMX_SOURCE_DVR3 :c:type:`dmx_source`
|
||||
|
||||
|
||||
# Flags for struct dmx_sct_filter_params
|
||||
replace define DMX_CHECK_CRC dmx-sct-filter-params
|
||||
replace define DMX_ONESHOT dmx-sct-filter-params
|
||||
replace define DMX_IMMEDIATE_START dmx-sct-filter-params
|
||||
replace define DMX_KERNEL_CLIENT dmx-sct-filter-params
|
||||
replace define DMX_CHECK_CRC :c:type:`dmx_sct_filter_params`
|
||||
replace define DMX_ONESHOT :c:type:`dmx_sct_filter_params`
|
||||
replace define DMX_IMMEDIATE_START :c:type:`dmx_sct_filter_params`
|
||||
replace define DMX_KERNEL_CLIENT :c:type:`dmx_sct_filter_params`
|
||||
|
||||
# some typedefs should point to struct/enums
|
||||
replace typedef dmx_caps_t dmx-caps
|
||||
replace typedef dmx_filter_t dmx-filter
|
||||
replace typedef dmx_caps_t :c:type:`dmx_caps`
|
||||
replace typedef dmx_filter_t :c:type:`dmx_filter`
|
||||
replace typedef dmx_pes_type_t :c:type:`dmx_pes_type`
|
||||
replace typedef dmx_input_t :c:type:`dmx_input`
|
||||
replace typedef dmx_source_t :c:type:`dmx_source`
|
||||
|
|
|
@ -26,22 +26,22 @@ ignore define MAX_DTV_STATS
|
|||
ignore define DTV_IOCTL_MAX_MSGS
|
||||
|
||||
# Stats enum is documented altogether
|
||||
replace enum fecap_scale_params frontend-stat-properties
|
||||
replace enum fecap_scale_params :ref:`frontend-stat-properties`
|
||||
replace symbol FE_SCALE_COUNTER frontend-stat-properties
|
||||
replace symbol FE_SCALE_DECIBEL frontend-stat-properties
|
||||
replace symbol FE_SCALE_NOT_AVAILABLE frontend-stat-properties
|
||||
replace symbol FE_SCALE_RELATIVE frontend-stat-properties
|
||||
|
||||
# the same reference is used for both get and set ioctls
|
||||
replace ioctl FE_SET_PROPERTY FE_GET_PROPERTY
|
||||
replace ioctl FE_SET_PROPERTY :c:type:`FE_GET_PROPERTY`
|
||||
|
||||
# Ignore struct used only internally at Kernel
|
||||
ignore struct dtv_cmds_h
|
||||
|
||||
# Typedefs that use the enum reference
|
||||
replace typedef fe_sec_voltage_t fe-sec-voltage
|
||||
replace typedef fe_sec_voltage_t :c:type:`fe_sec_voltage`
|
||||
|
||||
# Replaces for flag constants
|
||||
replace define FE_TUNE_MODE_ONESHOT fe_set_frontend_tune_mode
|
||||
replace define FE_TUNE_MODE_ONESHOT :c:func:`FE_SET_FRONTEND_TUNE_MODE`
|
||||
replace define LNA_AUTO dtv-lna
|
||||
replace define NO_STREAM_ID_FILTER dtv-stream-id
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
Linux Media Subsystem Documentation
|
||||
===================================
|
||||
|
||||
.. Sphinx 1.4.x has a definition for DUrole that doesn't work on alltt blocks
|
||||
.. raw:: latex
|
||||
|
||||
\renewcommand*{\DUrole}[2]{ #2 }
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
media_uapi
|
||||
media_kapi
|
||||
dvb-drivers/index
|
||||
v4l-drivers/index
|
||||
|
||||
.. only:: subproject
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
|
@ -30,7 +30,7 @@ divided into five parts.
|
|||
called as DVB API, in fact it covers several different video standards
|
||||
including DVB-T/T2, DVB-S/S2, DVB-C, ATSC, ISDB-T, ISDB-S, DTMB, etc. The
|
||||
complete list of supported standards can be found at
|
||||
:ref:`fe-delivery-system-t`.
|
||||
:c:type:`fe_delivery_system`.
|
||||
|
||||
3. The :ref:`third part <remote_controllers>` covers the Remote Controller API.
|
||||
|
||||
|
|
|
@ -36,39 +36,50 @@ CEC Adapter
|
|||
The struct cec_adapter represents the CEC adapter hardware. It is created by
|
||||
calling cec_allocate_adapter() and deleted by calling cec_delete_adapter():
|
||||
|
||||
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||
.. c:function::
|
||||
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||
void *priv, const char *name, u32 caps, u8 available_las,
|
||||
struct device *parent);
|
||||
void cec_delete_adapter(struct cec_adapter *adap);
|
||||
|
||||
.. c:function::
|
||||
void cec_delete_adapter(struct cec_adapter *adap);
|
||||
|
||||
To create an adapter you need to pass the following information:
|
||||
|
||||
ops: adapter operations which are called by the CEC framework and that you
|
||||
have to implement.
|
||||
ops:
|
||||
adapter operations which are called by the CEC framework and that you
|
||||
have to implement.
|
||||
|
||||
priv: will be stored in adap->priv and can be used by the adapter ops.
|
||||
priv:
|
||||
will be stored in adap->priv and can be used by the adapter ops.
|
||||
|
||||
name: the name of the CEC adapter. Note: this name will be copied.
|
||||
name:
|
||||
the name of the CEC adapter. Note: this name will be copied.
|
||||
|
||||
caps: capabilities of the CEC adapter. These capabilities determine the
|
||||
caps:
|
||||
capabilities of the CEC adapter. These capabilities determine the
|
||||
capabilities of the hardware and which parts are to be handled
|
||||
by userspace and which parts are handled by kernelspace. The
|
||||
capabilities are returned by CEC_ADAP_G_CAPS.
|
||||
|
||||
available_las: the number of simultaneous logical addresses that this
|
||||
available_las:
|
||||
the number of simultaneous logical addresses that this
|
||||
adapter can handle. Must be 1 <= available_las <= CEC_MAX_LOG_ADDRS.
|
||||
|
||||
parent: the parent device.
|
||||
parent:
|
||||
the parent device.
|
||||
|
||||
|
||||
To register the /dev/cecX device node and the remote control device (if
|
||||
CEC_CAP_RC is set) you call:
|
||||
|
||||
int cec_register_adapter(struct cec_adapter *adap);
|
||||
.. c:function::
|
||||
int cec_register_adapter(struct cec_adapter \*adap);
|
||||
|
||||
To unregister the devices call:
|
||||
|
||||
void cec_unregister_adapter(struct cec_adapter *adap);
|
||||
.. c:function::
|
||||
void cec_unregister_adapter(struct cec_adapter \*adap);
|
||||
|
||||
Note: if cec_register_adapter() fails, then call cec_delete_adapter() to
|
||||
clean up. But if cec_register_adapter() succeeded, then only call
|
||||
|
@ -83,18 +94,23 @@ Implementing the Low-Level CEC Adapter
|
|||
The following low-level adapter operations have to be implemented in
|
||||
your driver:
|
||||
|
||||
struct cec_adap_ops {
|
||||
/* Low-level callbacks */
|
||||
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
||||
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
||||
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
||||
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *msg);
|
||||
void (*adap_log_status)(struct cec_adapter *adap);
|
||||
.. c:type:: struct cec_adap_ops
|
||||
|
||||
/* High-level callbacks */
|
||||
...
|
||||
};
|
||||
.. code-block:: none
|
||||
|
||||
struct cec_adap_ops
|
||||
{
|
||||
/* Low-level callbacks */
|
||||
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
||||
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
||||
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
||||
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *msg);
|
||||
void (\*adap_log_status)(struct cec_adapter *adap);
|
||||
|
||||
/* High-level callbacks */
|
||||
...
|
||||
};
|
||||
|
||||
The three low-level ops deal with various aspects of controlling the CEC adapter
|
||||
hardware:
|
||||
|
@ -102,6 +118,7 @@ hardware:
|
|||
|
||||
To enable/disable the hardware:
|
||||
|
||||
.. c:function::
|
||||
int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
||||
|
||||
This callback enables or disables the CEC hardware. Enabling the CEC hardware
|
||||
|
@ -115,6 +132,7 @@ Note that adap_enable must return 0 if enable is false.
|
|||
|
||||
To enable/disable the 'monitor all' mode:
|
||||
|
||||
.. c:function::
|
||||
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
||||
|
||||
If enabled, then the adapter should be put in a mode to also monitor messages
|
||||
|
@ -127,6 +145,7 @@ Note that adap_monitor_all_enable must return 0 if enable is false.
|
|||
|
||||
To program a new logical address:
|
||||
|
||||
.. c:function::
|
||||
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
||||
|
||||
If logical_addr == CEC_LOG_ADDR_INVALID then all programmed logical addresses
|
||||
|
@ -140,6 +159,7 @@ Note that adap_log_addr must return 0 if logical_addr is CEC_LOG_ADDR_INVALID.
|
|||
|
||||
To transmit a new message:
|
||||
|
||||
.. c:function::
|
||||
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *msg);
|
||||
|
||||
|
@ -158,6 +178,7 @@ microseconds (one data bit period is 2.4 ms).
|
|||
|
||||
To log the current CEC hardware status:
|
||||
|
||||
.. c:function::
|
||||
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
|
||||
|
||||
This optional callback can be used to show the status of the CEC hardware.
|
||||
|
@ -169,29 +190,41 @@ driven) by calling into the framework in the following situations:
|
|||
|
||||
When a transmit finished (successfully or otherwise):
|
||||
|
||||
void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
|
||||
.. c:function::
|
||||
void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
|
||||
u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt);
|
||||
|
||||
The status can be one of:
|
||||
|
||||
CEC_TX_STATUS_OK: the transmit was successful.
|
||||
CEC_TX_STATUS_ARB_LOST: arbitration was lost: another CEC initiator
|
||||
took control of the CEC line and you lost the arbitration.
|
||||
CEC_TX_STATUS_NACK: the message was nacked (for a directed message) or
|
||||
acked (for a broadcast message). A retransmission is needed.
|
||||
CEC_TX_STATUS_LOW_DRIVE: low drive was detected on the CEC bus. This
|
||||
indicates that a follower detected an error on the bus and requested a
|
||||
retransmission.
|
||||
CEC_TX_STATUS_ERROR: some unspecified error occurred: this can be one of
|
||||
the previous two if the hardware cannot differentiate or something else
|
||||
entirely.
|
||||
CEC_TX_STATUS_MAX_RETRIES: could not transmit the message after
|
||||
trying multiple times. Should only be set by the driver if it has hardware
|
||||
support for retrying messages. If set, then the framework assumes that it
|
||||
doesn't have to make another attempt to transmit the message since the
|
||||
hardware did that already.
|
||||
CEC_TX_STATUS_OK:
|
||||
the transmit was successful.
|
||||
|
||||
The *_cnt arguments are the number of error conditions that were seen.
|
||||
CEC_TX_STATUS_ARB_LOST:
|
||||
arbitration was lost: another CEC initiator
|
||||
took control of the CEC line and you lost the arbitration.
|
||||
|
||||
CEC_TX_STATUS_NACK:
|
||||
the message was nacked (for a directed message) or
|
||||
acked (for a broadcast message). A retransmission is needed.
|
||||
|
||||
CEC_TX_STATUS_LOW_DRIVE:
|
||||
low drive was detected on the CEC bus. This indicates that
|
||||
a follower detected an error on the bus and requested a
|
||||
retransmission.
|
||||
|
||||
CEC_TX_STATUS_ERROR:
|
||||
some unspecified error occurred: this can be one of
|
||||
the previous two if the hardware cannot differentiate or something
|
||||
else entirely.
|
||||
|
||||
CEC_TX_STATUS_MAX_RETRIES:
|
||||
could not transmit the message after trying multiple times.
|
||||
Should only be set by the driver if it has hardware support for
|
||||
retrying messages. If set, then the framework assumes that it
|
||||
doesn't have to make another attempt to transmit the message
|
||||
since the hardware did that already.
|
||||
|
||||
The \*_cnt arguments are the number of error conditions that were seen.
|
||||
This may be 0 if no information is available. Drivers that do not support
|
||||
hardware retry can just set the counter corresponding to the transmit error
|
||||
to 1, if the hardware does support retry then either set these counters to
|
||||
|
@ -200,7 +233,8 @@ times, or fill in the correct values as reported by the hardware.
|
|||
|
||||
When a CEC message was received:
|
||||
|
||||
void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
|
||||
.. c:function::
|
||||
void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
|
||||
|
||||
Speaks for itself.
|
||||
|
||||
|
@ -210,17 +244,20 @@ Implementing the High-Level CEC Adapter
|
|||
The low-level operations drive the hardware, the high-level operations are
|
||||
CEC protocol driven. The following high-level callbacks are available:
|
||||
|
||||
struct cec_adap_ops {
|
||||
/* Low-level callbacks */
|
||||
...
|
||||
.. code-block:: none
|
||||
|
||||
/* High-level CEC message callback */
|
||||
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
||||
};
|
||||
struct cec_adap_ops {
|
||||
/\* Low-level callbacks \*/
|
||||
...
|
||||
|
||||
/\* High-level CEC message callback \*/
|
||||
int (\*received)(struct cec_adapter \*adap, struct cec_msg \*msg);
|
||||
};
|
||||
|
||||
The received() callback allows the driver to optionally handle a newly
|
||||
received CEC message
|
||||
|
||||
.. c:function::
|
||||
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
||||
|
||||
If the driver wants to process a CEC message, then it can implement this
|
||||
|
@ -234,13 +271,16 @@ CEC framework functions
|
|||
|
||||
CEC Adapter drivers can call the following CEC framework functions:
|
||||
|
||||
int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
|
||||
bool block);
|
||||
.. c:function::
|
||||
int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
|
||||
bool block);
|
||||
|
||||
Transmit a CEC message. If block is true, then wait until the message has been
|
||||
transmitted, otherwise just queue it and return.
|
||||
|
||||
void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block);
|
||||
.. c:function::
|
||||
void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr,
|
||||
bool block);
|
||||
|
||||
Change the physical address. This function will set adap->phys_addr and
|
||||
send an event if it has changed. If cec_s_log_addrs() has been called and
|
||||
|
@ -254,8 +294,9 @@ then the CEC adapter will be disabled. If you change a valid physical address
|
|||
to another valid physical address, then this function will first set the
|
||||
address to CEC_PHYS_ADDR_INVALID before enabling the new physical address.
|
||||
|
||||
int cec_s_log_addrs(struct cec_adapter *adap,
|
||||
struct cec_log_addrs *log_addrs, bool block);
|
||||
.. c:function::
|
||||
int cec_s_log_addrs(struct cec_adapter *adap,
|
||||
struct cec_log_addrs *log_addrs, bool block);
|
||||
|
||||
Claim the CEC logical addresses. Should never be called if CEC_CAP_LOG_ADDRS
|
||||
is set. If block is true, then wait until the logical addresses have been
|
|
@ -6,8 +6,6 @@ Digital TV Common functions
|
|||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_math.h
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
||||
|
||||
|
||||
|
@ -18,6 +16,42 @@ Digital TV Common functions
|
|||
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
||||
:export: drivers/media/dvb-core/dvbdev.c
|
||||
|
||||
Digital TV Ring buffer
|
||||
----------------------
|
||||
|
||||
Those routines implement ring buffers used to handle digital TV data and
|
||||
copy it from/to userspace.
|
||||
|
||||
.. note::
|
||||
|
||||
1) For performance reasons read and write routines don't check buffer sizes
|
||||
and/or number of bytes free/available. This has to be done before these
|
||||
routines are called. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* write @buflen: bytes */
|
||||
free = dvb_ringbuffer_free(rbuf);
|
||||
if (free >= buflen)
|
||||
count = dvb_ringbuffer_write(rbuf, buffer, buflen);
|
||||
else
|
||||
/* do something */
|
||||
|
||||
/* read min. 1000, max. @bufsize: bytes */
|
||||
avail = dvb_ringbuffer_avail(rbuf);
|
||||
if (avail >= 1000)
|
||||
count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
|
||||
else
|
||||
/* do something */
|
||||
|
||||
2) If there is exactly one reader and one writer, there is no need
|
||||
to lock read or write operations.
|
||||
Two or more readers must be locked against each other.
|
||||
Flushing the buffer counts as a read operation.
|
||||
Resetting the buffer counts as a read and write operation.
|
||||
Two or more writers must be locked against each other.
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h
|
||||
|
||||
|
||||
Digital TV Frontend kABI
|
||||
|
@ -121,7 +155,7 @@ triggered by a hardware interrupt, it is recommended to use the Linux
|
|||
bottom half mechanism or start a tasklet instead of making the callback
|
||||
function call directly from a hardware interrupt.
|
||||
|
||||
This mechanism is implemented by :c:func:`dmx_ts_cb()` and :cpp:func:`dmx_section_cb()`
|
||||
This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()`
|
||||
callbacks.
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/demux.h
|
||||
|
|
|
@ -34,7 +34,7 @@ pad to a sink pad.
|
|||
Media device
|
||||
^^^^^^^^^^^^
|
||||
|
||||
A media device is represented by a :c:type:`struct media_device <media_device>`
|
||||
A media device is represented by a struct :c:type:`media_device`
|
||||
instance, defined in ``include/media/media-device.h``.
|
||||
Allocation of the structure is handled by the media device driver, usually by
|
||||
embedding the :c:type:`media_device` instance in a larger driver-specific
|
||||
|
@ -47,7 +47,7 @@ and unregistered by calling :c:func:`media_device_unregister()`.
|
|||
Entities
|
||||
^^^^^^^^
|
||||
|
||||
Entities are represented by a :c:type:`struct media_entity <media_entity>`
|
||||
Entities are represented by a struct :c:type:`media_entity`
|
||||
instance, defined in ``include/media/media-entity.h``. The structure is usually
|
||||
embedded into a higher-level structure, such as
|
||||
:c:type:`v4l2_subdev` or :c:type:`video_device`
|
||||
|
@ -65,10 +65,10 @@ Interfaces
|
|||
^^^^^^^^^^
|
||||
|
||||
Interfaces are represented by a
|
||||
:c:type:`struct media_interface <media_interface>` instance, defined in
|
||||
struct :c:type:`media_interface` instance, defined in
|
||||
``include/media/media-entity.h``. Currently, only one type of interface is
|
||||
defined: a device node. Such interfaces are represented by a
|
||||
:c:type:`struct media_intf_devnode <media_intf_devnode>`.
|
||||
struct :c:type:`media_intf_devnode`.
|
||||
|
||||
Drivers initialize and create device node interfaces by calling
|
||||
:c:func:`media_devnode_create()`
|
||||
|
@ -77,7 +77,7 @@ and remove them by calling:
|
|||
|
||||
Pads
|
||||
^^^^
|
||||
Pads are represented by a :c:type:`struct media_pad <media_pad>` instance,
|
||||
Pads are represented by a struct :c:type:`media_pad` instance,
|
||||
defined in ``include/media/media-entity.h``. Each entity stores its pads in
|
||||
a pads array managed by the entity driver. Drivers usually embed the array in
|
||||
a driver-specific structure.
|
||||
|
@ -85,8 +85,9 @@ a driver-specific structure.
|
|||
Pads are identified by their entity and their 0-based index in the pads
|
||||
array.
|
||||
|
||||
Both information are stored in the :c:type:`struct media_pad`, making the
|
||||
:c:type:`media_pad` pointer the canonical way to store and pass link references.
|
||||
Both information are stored in the struct :c:type:`media_pad`,
|
||||
making the struct :c:type:`media_pad` pointer the canonical way
|
||||
to store and pass link references.
|
||||
|
||||
Pads have flags that describe the pad capabilities and state.
|
||||
|
||||
|
@ -101,7 +102,7 @@ Pads have flags that describe the pad capabilities and state.
|
|||
Links
|
||||
^^^^^
|
||||
|
||||
Links are represented by a :c:type:`struct media_link <media_link>` instance,
|
||||
Links are represented by a struct :c:type:`media_link` instance,
|
||||
defined in ``include/media/media-entity.h``. There are two types of links:
|
||||
|
||||
**1. pad to pad links**:
|
||||
|
@ -184,7 +185,7 @@ Use count and power handling
|
|||
|
||||
Due to the wide differences between drivers regarding power management
|
||||
needs, the media controller does not implement power management. However,
|
||||
the :c:type:`struct media_entity <media_entity>` includes a ``use_count``
|
||||
the struct :c:type:`media_entity` includes a ``use_count``
|
||||
field that media drivers
|
||||
can use to track the number of users of every entity for power management
|
||||
needs.
|
||||
|
@ -210,11 +211,11 @@ prevent link states from being modified during streaming by calling
|
|||
The function will mark all entities connected to the given entity through
|
||||
enabled links, either directly or indirectly, as streaming.
|
||||
|
||||
The :c:type:`struct media_pipeline <media_pipeline>` instance pointed to by
|
||||
The struct :c:type:`media_pipeline` instance pointed to by
|
||||
the pipe argument will be stored in every entity in the pipeline.
|
||||
Drivers should embed the :c:type:`struct media_pipeline <media_pipeline>`
|
||||
Drivers should embed the struct :c:type:`media_pipeline`
|
||||
in higher-level pipeline structures and can then access the
|
||||
pipeline through the :c:type:`struct media_entity <media_entity>`
|
||||
pipeline through the struct :c:type:`media_entity`
|
||||
pipe field.
|
||||
|
||||
Calls to :c:func:`media_entity_pipeline_start()` can be nested.
|
||||
|
|
|
@ -56,7 +56,7 @@ You should also set these fields of :c:type:`video_device`:
|
|||
:c:type:`video_device`->vfl_dir fields are used to disable ops that do not
|
||||
match the type/dir combination. E.g. VBI ops are disabled for non-VBI nodes,
|
||||
and output ops are disabled for a capture device. This makes it possible to
|
||||
provide just one :c:type:`v4l2_ioctl_ops struct` for both vbi and
|
||||
provide just one :c:type:`v4l2_ioctl_ops` struct for both vbi and
|
||||
video nodes.
|
||||
|
||||
- :c:type:`video_device`->lock: leave to ``NULL`` if you want to do all the
|
||||
|
@ -166,14 +166,14 @@ something.
|
|||
In the case of :ref:`videobuf2 <vb2_framework>` you will need to implement the
|
||||
``wait_prepare()`` and ``wait_finish()`` callbacks to unlock/lock if applicable.
|
||||
If you use the ``queue->lock`` pointer, then you can use the helper functions
|
||||
:c:func:`vb2_ops_wait_prepare` and :cpp:func:`vb2_ops_wait_finish`.
|
||||
:c:func:`vb2_ops_wait_prepare` and :c:func:`vb2_ops_wait_finish`.
|
||||
|
||||
The implementation of a hotplug disconnect should also take the lock from
|
||||
:c:type:`video_device` before calling v4l2_device_disconnect. If you are also
|
||||
using :c:type:`video_device`->queue->lock, then you have to first lock
|
||||
:c:type:`video_device`->queue->lock followed by :c:type:`video_device`->lock.
|
||||
That way you can be sure no ioctl is running when you call
|
||||
:c:type:`v4l2_device_disconnect`.
|
||||
:c:func:`v4l2_device_disconnect`.
|
||||
|
||||
Video device registration
|
||||
-------------------------
|
||||
|
@ -200,6 +200,7 @@ types exist:
|
|||
- ``VFL_TYPE_VBI``: ``/dev/vbiX`` for vertical blank data (i.e. closed captions, teletext)
|
||||
- ``VFL_TYPE_RADIO``: ``/dev/radioX`` for radio tuners
|
||||
- ``VFL_TYPE_SDR``: ``/dev/swradioX`` for Software Defined Radio tuners
|
||||
- ``VFL_TYPE_TOUCH``: ``/dev/v4l-touchX`` for touch sensors
|
||||
|
||||
The last argument gives you a certain amount of control over the device
|
||||
device node number used (i.e. the X in ``videoX``). Normally you will pass -1
|
||||
|
@ -262,6 +263,7 @@ file operations.
|
|||
|
||||
It is a bitmask and the following bits can be set:
|
||||
|
||||
.. tabularcolumns:: |p{5ex}|L|
|
||||
|
||||
===== ================================================================
|
||||
Mask Description
|
||||
|
@ -334,7 +336,7 @@ And this function:
|
|||
|
||||
returns the video_device belonging to the file struct.
|
||||
|
||||
The :c:func:`video_devdata` function combines :cpp:func:`video_get_drvdata`
|
||||
The :c:func:`video_devdata` function combines :c:func:`video_get_drvdata`
|
||||
with :c:func:`video_devdata`:
|
||||
|
||||
:c:func:`video_drvdata <video_drvdata>`
|
||||
|
|
|
@ -40,7 +40,7 @@ A good example of these ``replace``/``merge`` callbacks is in v4l2-event.c:
|
|||
In order to queue events to video device, drivers should call:
|
||||
|
||||
:c:func:`v4l2_event_queue <v4l2_event_queue>`
|
||||
(:c:type:`vdev <video_device>`, :ref:`ev <v4l2-event>`)
|
||||
(:c:type:`vdev <video_device>`, :c:type:`ev <v4l2_event>`)
|
||||
|
||||
The driver's only responsibility is to fill in the type and the data fields.
|
||||
The other fields will be filled in by V4L2.
|
||||
|
@ -51,7 +51,7 @@ Event subscription
|
|||
Subscribing to an event is via:
|
||||
|
||||
:c:func:`v4l2_event_subscribe <v4l2_event_subscribe>`
|
||||
(:c:type:`fh <v4l2_fh>`, :ref:`sub <v4l2-event-subscription>` ,
|
||||
(:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>` ,
|
||||
elems, :c:type:`ops <v4l2_subscribed_event_ops>`)
|
||||
|
||||
|
||||
|
@ -86,7 +86,7 @@ Unsubscribing an event
|
|||
Unsubscribing to an event is via:
|
||||
|
||||
:c:func:`v4l2_event_unsubscribe <v4l2_event_unsubscribe>`
|
||||
(:c:type:`fh <v4l2_fh>`, :ref:`sub <v4l2-event-subscription>`)
|
||||
(:c:type:`fh <v4l2_fh>`, :c:type:`sub <v4l2_event_subscription>`)
|
||||
|
||||
This function is used to implement :c:type:`video_device`->
|
||||
:c:type:`ioctl_ops <v4l2_ioctl_ops>`-> ``vidioc_unsubscribe_event``.
|
||||
|
|
|
@ -21,8 +21,8 @@ function by the driver.
|
|||
In many cases the struct :c:type:`v4l2_fh` will be embedded in a larger
|
||||
structure. In that case you should call:
|
||||
|
||||
#) :c:func:`v4l2_fh_init` and :cpp:func:`v4l2_fh_add` in ``open()``
|
||||
#) :c:func:`v4l2_fh_del` and :cpp:func:`v4l2_fh_exit` in ``release()``
|
||||
#) :c:func:`v4l2_fh_init` and :c:func:`v4l2_fh_add` in ``open()``
|
||||
#) :c:func:`v4l2_fh_del` and :c:func:`v4l2_fh_exit` in ``release()``
|
||||
|
||||
Drivers can extract their own file handle structure by using the container_of
|
||||
macro.
|
||||
|
|
|
@ -27,7 +27,7 @@ methods.
|
|||
Bridges might also need to store per-subdev private data, such as a pointer to
|
||||
bridge-specific per-subdev private data. The :c:type:`v4l2_subdev` structure
|
||||
provides host private data for that purpose that can be accessed with
|
||||
:c:func:`v4l2_get_subdev_hostdata` and :cpp:func:`v4l2_set_subdev_hostdata`.
|
||||
:c:func:`v4l2_get_subdev_hostdata` and :c:func:`v4l2_set_subdev_hostdata`.
|
||||
|
||||
From the bridge driver perspective, you load the sub-device module and somehow
|
||||
obtain the :c:type:`v4l2_subdev` pointer. For i2c devices this is easy: you call
|
||||
|
@ -412,19 +412,7 @@ later date. It differs between i2c drivers and as such can be confusing.
|
|||
To see which chip variants are supported you can look in the i2c driver code
|
||||
for the i2c_device_id table. This lists all the possibilities.
|
||||
|
||||
There are two more helper functions:
|
||||
|
||||
:c:func:`v4l2_i2c_new_subdev_cfg`: this function adds new irq and
|
||||
platform_data arguments and has both 'addr' and 'probed_addrs' arguments:
|
||||
if addr is not 0 then that will be used (non-probing variant), otherwise the
|
||||
probed_addrs are probed.
|
||||
|
||||
For example: this will probe for address 0x10:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct v4l2_subdev *sd = v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter,
|
||||
"module_foo", "chipid", 0, NULL, 0, I2C_ADDRS(0x10));
|
||||
There are one more helper function:
|
||||
|
||||
:c:func:`v4l2_i2c_new_subdev_board` uses an :c:type:`i2c_board_info` struct
|
||||
which is passed to the i2c driver and replaces the irq, platform_data and addr
|
||||
|
@ -433,9 +421,10 @@ arguments.
|
|||
If the subdev supports the s_config core ops, then that op is called with
|
||||
the irq and platform_data arguments after the subdev was setup.
|
||||
|
||||
The older :c:func:`v4l2_i2c_new_subdev` and
|
||||
:c:func:`v4l2_i2c_new_probed_subdev` functions will call ``s_config`` as
|
||||
well, but with irq set to 0 and platform_data set to ``NULL``.
|
||||
The :c:func:`v4l2_i2c_new_subdev` function will call
|
||||
:c:func:`v4l2_i2c_new_subdev_board`, internally filling a
|
||||
:c:type:`i2c_board_info` structure using the ``client_type`` and the
|
||||
``addr`` to fill it.
|
||||
|
||||
V4L2 sub-device functions and data structures
|
||||
---------------------------------------------
|
||||
|
|
Binary file not shown.
|
@ -32,3 +32,4 @@ For more details see the file COPYING in the source distribution of Linux.
|
|||
kapi/dtv-core
|
||||
kapi/rc-core
|
||||
kapi/mc-core
|
||||
kapi/cec-core
|
||||
|
|
|
@ -7,5 +7,5 @@ ignore ioctl __NET_GET_IF_OLD
|
|||
ignore struct __dvb_net_if_old
|
||||
|
||||
# Macros used at struct dvb_net_if
|
||||
replace define DVB_NET_FEEDTYPE_MPE dvb-net-if
|
||||
replace define DVB_NET_FEEDTYPE_ULE dvb-net-if
|
||||
replace define DVB_NET_FEEDTYPE_MPE :c:type:`dvb_net_if`
|
||||
replace define DVB_NET_FEEDTYPE_ULE :c:type:`dvb_net_if`
|
||||
|
|
|
@ -20,19 +20,22 @@ Synopsis
|
|||
#include <unistd.h>
|
||||
|
||||
|
||||
.. cpp:function:: int close( int fd )
|
||||
.. c:function:: int close( int fd )
|
||||
:name: cec-close
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
``fd``
|
||||
File descriptor returned by :ref:`open() <func-open>`.
|
||||
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
Closes the cec device. Resources associated with the file descriptor are
|
||||
|
|
|
@ -19,17 +19,18 @@ Synopsis
|
|||
#include <sys/ioctl.h>
|
||||
|
||||
|
||||
.. cpp:function:: int ioctl( int fd, int request, void *argp )
|
||||
.. c:function:: int ioctl( int fd, int request, void *argp )
|
||||
:name: cec-ioctl
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
``fd``
|
||||
File descriptor returned by :ref:`open() <func-open>`.
|
||||
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||
|
||||
``request``
|
||||
CEC ioctl request code as defined in the cec.h header file, for
|
||||
example :ref:`CEC_ADAP_G_CAPS`.
|
||||
example :c:func:`CEC_ADAP_G_CAPS`.
|
||||
|
||||
``argp``
|
||||
Pointer to a request-specific structure.
|
||||
|
@ -38,7 +39,9 @@ Arguments
|
|||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
The :c:func:`ioctl()` function manipulates cec device parameters. The
|
||||
|
|
|
@ -19,7 +19,8 @@ Synopsis
|
|||
#include <fcntl.h>
|
||||
|
||||
|
||||
.. cpp:function:: int open( const char *device_name, int flags )
|
||||
.. c:function:: int open( const char *device_name, int flags )
|
||||
:name: cec-open
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -32,7 +33,7 @@ Arguments
|
|||
Open flags. Access mode must be ``O_RDWR``.
|
||||
|
||||
When the ``O_NONBLOCK`` flag is given, the
|
||||
:ref:`CEC_RECEIVE <CEC_RECEIVE>` and :ref:`CEC_DQEVENT <CEC_DQEVENT>` ioctls
|
||||
:ref:`CEC_RECEIVE <CEC_RECEIVE>` and :c:func:`CEC_DQEVENT` ioctls
|
||||
will return the ``EAGAIN`` error code when no message or event is available, and
|
||||
ioctls :ref:`CEC_TRANSMIT <CEC_TRANSMIT>`,
|
||||
:ref:`CEC_ADAP_S_PHYS_ADDR <CEC_ADAP_S_PHYS_ADDR>` and
|
||||
|
@ -45,7 +46,9 @@ Arguments
|
|||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
To open a cec device applications call :c:func:`open()` with the
|
||||
|
|
|
@ -20,16 +20,28 @@ Synopsis
|
|||
#include <sys/poll.h>
|
||||
|
||||
|
||||
.. cpp:function:: int poll( struct pollfd *ufds, unsigned int nfds, int timeout )
|
||||
.. c:function:: int poll( struct pollfd *ufds, unsigned int nfds, int timeout )
|
||||
:name: cec-poll
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
``ufds``
|
||||
List of FD events to be watched
|
||||
|
||||
``nfds``
|
||||
Number of FD efents at the \*ufds array
|
||||
|
||||
``timeout``
|
||||
Timeout to wait for events
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
With the :c:func:`poll()` function applications can wait for CEC
|
||||
|
@ -37,7 +49,7 @@ events.
|
|||
|
||||
On success :c:func:`poll()` returns the number of file descriptors
|
||||
that have been selected (that is, file descriptors for which the
|
||||
``revents`` field of the respective :c:type:`struct pollfd` structure
|
||||
``revents`` field of the respective struct :c:type:`pollfd`
|
||||
is non-zero). CEC devices set the ``POLLIN`` and ``POLLRDNORM`` flags in
|
||||
the ``revents`` field if there are messages in the receive queue. If the
|
||||
transmit queue has room for new messages, the ``POLLOUT`` and
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
Introduction
|
||||
============
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
HDMI connectors provide a single pin for use by the Consumer Electronics
|
||||
|
|
|
@ -14,7 +14,8 @@ CEC_ADAP_G_CAPS - Query device capabilities
|
|||
Synopsis
|
||||
========
|
||||
|
||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_caps *argp )
|
||||
.. c:function:: int ioctl( int fd, CEC_ADAP_G_CAPS, struct cec_caps *argp )
|
||||
:name: CEC_ADAP_G_CAPS
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
@ -22,25 +23,25 @@ Arguments
|
|||
``fd``
|
||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||
|
||||
``request``
|
||||
CEC_ADAP_G_CAPS
|
||||
|
||||
``argp``
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
All cec devices must support :ref:`ioctl CEC_ADAP_G_CAPS <CEC_ADAP_G_CAPS>`. To query
|
||||
device information, applications call the ioctl with a pointer to a
|
||||
struct :ref:`cec_caps <cec-caps>`. The driver fills the structure and
|
||||
struct :c:type:`cec_caps`. The driver fills the structure and
|
||||
returns the information to the application. The ioctl never fails.
|
||||
|
||||
.. tabularcolumns:: |p{1.2cm}|p{2.5cm}|p{13.8cm}|
|
||||
|
||||
.. _cec-caps:
|
||||
.. c:type:: cec_caps
|
||||
|
||||
.. flat-table:: struct cec_caps
|
||||
:header-rows: 0
|
||||
|
@ -84,6 +85,7 @@ returns the information to the application. The ioctl never fails.
|
|||
macro.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}|
|
||||
|
||||
.. _cec-capabilities:
|
||||
|
||||
|
|
|
@ -17,33 +17,35 @@ CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS - Get or set the logical addresses
|
|||
Synopsis
|
||||
========
|
||||
|
||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_log_addrs *argp )
|
||||
.. c:function:: int ioctl( int fd, CEC_ADAP_G_LOG_ADDRS, struct cec_log_addrs *argp )
|
||||
:name: CEC_ADAP_G_LOG_ADDRS
|
||||
|
||||
.. c:function:: int ioctl( int fd, CEC_ADAP_S_LOG_ADDRS, struct cec_log_addrs *argp )
|
||||
:name: CEC_ADAP_S_LOG_ADDRS
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
``fd``
|
||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||
|
||||
``request``
|
||||
CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS
|
||||
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||
|
||||
``argp``
|
||||
|
||||
Pointer to struct :c:type:`cec_log_addrs`.
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
To query the current CEC logical addresses, applications call
|
||||
:ref:`ioctl CEC_ADAP_G_LOG_ADDRS <CEC_ADAP_G_LOG_ADDRS>` with a pointer to a
|
||||
:c:type:`struct cec_log_addrs` where the driver stores the logical addresses.
|
||||
struct :c:type:`cec_log_addrs` where the driver stores the logical addresses.
|
||||
|
||||
To set new logical addresses, applications fill in
|
||||
:c:type:`struct cec_log_addrs` and call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
||||
struct :c:type:`cec_log_addrs` and call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
||||
with a pointer to this struct. The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
||||
is only available if ``CEC_CAP_LOG_ADDRS`` is set (the ``ENOTTY`` error code is
|
||||
returned otherwise). The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>`
|
||||
|
@ -64,8 +66,11 @@ logical addresses are claimed or cleared.
|
|||
Attempting to call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS <CEC_ADAP_S_LOG_ADDRS>` when
|
||||
logical address types are already defined will return with error ``EBUSY``.
|
||||
|
||||
.. c:type:: cec_log_addrs
|
||||
|
||||
.. _cec-log-addrs:
|
||||
.. tabularcolumns:: |p{1.0cm}|p{7.5cm}|p{8.0cm}|
|
||||
|
||||
.. cssclass:: longtable
|
||||
|
||||
.. flat-table:: struct cec_log_addrs
|
||||
:header-rows: 0
|
||||
|
@ -220,6 +225,8 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||
fallback to the Unregistered logical address. Note that if the Unregistered
|
||||
logical address was explicitly requested, then this flag has no effect.
|
||||
|
||||
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||
|
||||
.. _cec-versions:
|
||||
|
||||
.. flat-table:: CEC Versions
|
||||
|
@ -253,6 +260,7 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||
- CEC version according to the HDMI 2.0 standard.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||
|
||||
.. _cec-prim-dev-types:
|
||||
|
||||
|
@ -319,6 +327,7 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||
- Use for a video processor device.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||
|
||||
.. _cec-log-addr-types:
|
||||
|
||||
|
@ -388,6 +397,8 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
|
||||
|
||||
.. _cec-all-dev-types-flags:
|
||||
|
||||
.. flat-table:: CEC All Device Types Flags
|
||||
|
|
|
@ -17,24 +17,27 @@ CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR - Get or set the physical address
|
|||
Synopsis
|
||||
========
|
||||
|
||||
.. cpp:function:: int ioctl( int fd, int request, __u16 *argp )
|
||||
.. c:function:: int ioctl( int fd, CEC_ADAP_G_PHYS_ADDR, __u16 *argp )
|
||||
:name: CEC_ADAP_G_PHYS_ADDR
|
||||
|
||||
.. c:function:: int ioctl( int fd, CEC_ADAP_S_PHYS_ADDR, __u16 *argp )
|
||||
:name: CEC_ADAP_S_PHYS_ADDR
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
``fd``
|
||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||
|
||||
``request``
|
||||
CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR
|
||||
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||
|
||||
``argp``
|
||||
|
||||
Pointer to the CEC address.
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
To query the current physical address applications call
|
||||
|
|
|
@ -15,7 +15,8 @@ CEC_DQEVENT - Dequeue a CEC event
|
|||
Synopsis
|
||||
========
|
||||
|
||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_event *argp )
|
||||
.. c:function:: int ioctl( int fd, CEC_DQEVENT, struct cec_event *argp )
|
||||
:name: CEC_DQEVENT
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
@ -23,20 +24,19 @@ Arguments
|
|||
``fd``
|
||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||
|
||||
``request``
|
||||
CEC_DQEVENT
|
||||
|
||||
``argp``
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
CEC devices can send asynchronous events. These can be retrieved by
|
||||
calling :ref:`ioctl CEC_DQEVENT <CEC_DQEVENT>`. If the file descriptor is in
|
||||
calling :c:func:`CEC_DQEVENT`. If the file descriptor is in
|
||||
non-blocking mode and no event is pending, then it will return -1 and
|
||||
set errno to the ``EAGAIN`` error code.
|
||||
|
||||
|
@ -49,8 +49,9 @@ two :ref:`CEC_EVENT_STATE_CHANGE <CEC-EVENT-STATE-CHANGE>` events with
|
|||
the same state). In that case the intermediate state changes were lost but
|
||||
it is guaranteed that the state did change in between the two events.
|
||||
|
||||
.. tabularcolumns:: |p{1.2cm}|p{2.9cm}|p{13.4cm}|
|
||||
|
||||
.. _cec-event-state-change_s:
|
||||
.. c:type:: cec_event_state_change
|
||||
|
||||
.. flat-table:: struct cec_event_state_change
|
||||
:header-rows: 0
|
||||
|
@ -79,8 +80,9 @@ it is guaranteed that the state did change in between the two events.
|
|||
has the unregistered logical address. In that case all other bits are 0.
|
||||
|
||||
|
||||
.. c:type:: cec_event_lost_msgs
|
||||
|
||||
.. _cec-event-lost-msgs_s:
|
||||
.. tabularcolumns:: |p{1.0cm}|p{2.0cm}|p{14.5cm}|
|
||||
|
||||
.. flat-table:: struct cec_event_lost_msgs
|
||||
:header-rows: 0
|
||||
|
@ -105,8 +107,9 @@ it is guaranteed that the state did change in between the two events.
|
|||
this is more than enough.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{1.0cm}|p{4.2cm}|p{2.5cm}|p{8.8cm}|
|
||||
|
||||
.. _cec-event:
|
||||
.. c:type:: cec_event
|
||||
|
||||
.. flat-table:: struct cec_event
|
||||
:header-rows: 0
|
||||
|
@ -120,11 +123,10 @@ it is guaranteed that the state did change in between the two events.
|
|||
|
||||
- ``ts``
|
||||
|
||||
- Timestamp of the event in ns.
|
||||
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
||||
the same clock from userspace use :c:func:`clock_gettime(2)`.
|
||||
- :cspan:`1` Timestamp of the event in ns.
|
||||
|
||||
-
|
||||
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
||||
the same clock from userspace use :c:func:`clock_gettime`.
|
||||
|
||||
- .. row 2
|
||||
|
||||
|
@ -132,9 +134,7 @@ it is guaranteed that the state did change in between the two events.
|
|||
|
||||
- ``event``
|
||||
|
||||
- The CEC event type, see :ref:`cec-events`.
|
||||
|
||||
-
|
||||
- :cspan:`1` The CEC event type, see :ref:`cec-events`.
|
||||
|
||||
- .. row 3
|
||||
|
||||
|
@ -142,9 +142,7 @@ it is guaranteed that the state did change in between the two events.
|
|||
|
||||
- ``flags``
|
||||
|
||||
- Event flags, see :ref:`cec-event-flags`.
|
||||
|
||||
-
|
||||
- :cspan:`1` Event flags, see :ref:`cec-event-flags`.
|
||||
|
||||
- .. row 4
|
||||
|
||||
|
@ -176,6 +174,7 @@ it is guaranteed that the state did change in between the two events.
|
|||
event.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||
|
||||
.. _cec-events:
|
||||
|
||||
|
@ -205,6 +204,7 @@ it is guaranteed that the state did change in between the two events.
|
|||
application didn't dequeue CEC messages fast enough.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{6.0cm}|p{0.6cm}|p{10.9cm}|
|
||||
|
||||
.. _cec-event-flags:
|
||||
|
||||
|
|
|
@ -13,24 +13,27 @@ CEC_G_MODE, CEC_S_MODE - Get or set exclusive use of the CEC adapter
|
|||
Synopsis
|
||||
========
|
||||
|
||||
.. cpp:function:: int ioctl( int fd, int request, __u32 *argp )
|
||||
.. c:function:: int ioctl( int fd, CEC_G_MODE, __u32 *argp )
|
||||
:name: CEC_G_MODE
|
||||
|
||||
.. c:function:: int ioctl( int fd, CEC_S_MODE, __u32 *argp )
|
||||
:name: CEC_S_MODE
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
``fd``
|
||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||
|
||||
``request``
|
||||
CEC_G_MODE, CEC_S_MODE
|
||||
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||
|
||||
``argp``
|
||||
|
||||
Pointer to CEC mode.
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
By default any filehandle can use :ref:`CEC_TRANSMIT`, but in order to prevent
|
||||
|
@ -71,6 +74,7 @@ always call :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>`.
|
|||
|
||||
Available initiator modes are:
|
||||
|
||||
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||
|
||||
.. _cec-mode-initiator_e:
|
||||
|
||||
|
@ -114,6 +118,7 @@ Available initiator modes are:
|
|||
|
||||
Available follower modes are:
|
||||
|
||||
.. tabularcolumns:: |p{6.6cm}|p{0.9cm}|p{10.0cm}|
|
||||
|
||||
.. _cec-mode-follower_e:
|
||||
|
||||
|
@ -206,6 +211,7 @@ Available follower modes are:
|
|||
|
||||
Core message processing details:
|
||||
|
||||
.. tabularcolumns:: |p{6.6cm}|p{10.9cm}|
|
||||
|
||||
.. _cec-core-processing:
|
||||
|
||||
|
|
|
@ -16,28 +16,32 @@ CEC_RECEIVE, CEC_TRANSMIT - Receive or transmit a CEC message
|
|||
Synopsis
|
||||
========
|
||||
|
||||
.. cpp:function:: int ioctl( int fd, int request, struct cec_msg *argp )
|
||||
.. c:function:: int ioctl( int fd, CEC_RECEIVE, struct cec_msg *argp )
|
||||
:name: CEC_RECEIVE
|
||||
|
||||
.. c:function:: int ioctl( int fd, CEC_TRANSMIT, struct cec_msg *argp )
|
||||
:name: CEC_TRANSMIT
|
||||
|
||||
Arguments
|
||||
=========
|
||||
|
||||
``fd``
|
||||
File descriptor returned by :ref:`open() <cec-func-open>`.
|
||||
|
||||
``request``
|
||||
CEC_RECEIVE, CEC_TRANSMIT
|
||||
File descriptor returned by :c:func:`open() <cec-open>`.
|
||||
|
||||
``argp``
|
||||
|
||||
Pointer to struct cec_msg.
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
.. note:: This documents the proposed CEC API. This API is not yet finalized
|
||||
.. note::
|
||||
|
||||
This documents the proposed CEC API. This API is not yet finalized
|
||||
and is currently only available as a staging kernel module.
|
||||
|
||||
To receive a CEC message the application has to fill in the
|
||||
``timeout`` field of :c:type:`struct cec_msg` and pass it to :ref:`ioctl CEC_RECEIVE <CEC_RECEIVE>`.
|
||||
``timeout`` field of struct :c:type:`cec_msg` and pass it to
|
||||
:ref:`ioctl CEC_RECEIVE <CEC_RECEIVE>`.
|
||||
If the file descriptor is in non-blocking mode and there are no received
|
||||
messages pending, then it will return -1 and set errno to the ``EAGAIN``
|
||||
error code. If the file descriptor is in blocking mode and ``timeout``
|
||||
|
@ -51,9 +55,9 @@ A received message can be:
|
|||
2. the result of an earlier non-blocking transmit (the ``sequence`` field will
|
||||
be non-zero).
|
||||
|
||||
To send a CEC message the application has to fill in the
|
||||
:c:type:`struct cec_msg` and pass it to
|
||||
:ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>`. The :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>` is only available if
|
||||
To send a CEC message the application has to fill in the struct
|
||||
:c:type:` cec_msg` and pass it to :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>`.
|
||||
The :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>` is only available if
|
||||
``CEC_CAP_TRANSMIT`` is set. If there is no more room in the transmit
|
||||
queue, then it will return -1 and set errno to the ``EBUSY`` error code.
|
||||
The transmit queue has enough room for 18 messages (about 1 second worth
|
||||
|
@ -71,7 +75,11 @@ checked against the received messages to find the corresponding transmit
|
|||
result.
|
||||
|
||||
|
||||
.. _cec-msg:
|
||||
.. tabularcolumns:: |p{1.0cm}|p{3.5cm}|p{13.0cm}|
|
||||
|
||||
.. c:type:: cec_msg
|
||||
|
||||
.. cssclass:: longtable
|
||||
|
||||
.. flat-table:: struct cec_msg
|
||||
:header-rows: 0
|
||||
|
@ -87,7 +95,7 @@ result.
|
|||
|
||||
- Timestamp in ns of when the last byte of the message was transmitted.
|
||||
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
||||
the same clock from userspace use :c:func:`clock_gettime(2)`.
|
||||
the same clock from userspace use :c:func:`clock_gettime`.
|
||||
|
||||
- .. row 2
|
||||
|
||||
|
@ -97,7 +105,7 @@ result.
|
|||
|
||||
- Timestamp in ns of when the last byte of the message was received.
|
||||
The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access
|
||||
the same clock from userspace use :c:func:`clock_gettime(2)`.
|
||||
the same clock from userspace use :c:func:`clock_gettime`.
|
||||
|
||||
- .. row 3
|
||||
|
||||
|
@ -247,6 +255,7 @@ result.
|
|||
valid if the :ref:`CEC_TX_STATUS_ERROR <CEC-TX-STATUS-ERROR>` status bit is set.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||
|
||||
.. _cec-tx-status:
|
||||
|
||||
|
@ -315,6 +324,7 @@ result.
|
|||
be set to explain which failures were seen.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
|
||||
|
||||
.. _cec-rx-status:
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_BILINGUAL_CHANNEL_SELECT
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_BILINGUAL_CHANNEL_SELECT, audio_channel_select_t)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct *audio_channel_select)
|
||||
:name: AUDIO_BILINGUAL_CHANNEL_SELECT
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -25,20 +27,13 @@ Arguments
|
|||
:header-rows: 0
|
||||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_BILINGUAL_CHANNEL_SELECT for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- audio_channel_select_t ch
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_CHANNEL_SELECT
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_CHANNEL_SELECT, audio_channel_select_t)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct *audio_channel_select)
|
||||
:name: AUDIO_CHANNEL_SELECT
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -26,19 +28,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_CHANNEL_SELECT for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- audio_channel_select_t ch
|
||||
|
||||
|
|
|
@ -11,12 +11,13 @@ Name
|
|||
|
||||
AUDIO_CLEAR_BUFFER
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_CLEAR_BUFFER)
|
||||
|
||||
.. c:function:: int ioctl(int fd, AUDIO_CLEAR_BUFFER)
|
||||
:name: AUDIO_CLEAR_BUFFER
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
@ -32,13 +33,6 @@ Arguments
|
|||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_CLEAR_BUFFER for this command.
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_CONTINUE
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_CONTINUE)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_CONTINUE)
|
||||
:name: AUDIO_CONTINUE
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -32,13 +34,6 @@ Arguments
|
|||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_CONTINUE for this command.
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
DVB audio close()
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int close(int fd)
|
||||
.. c:function:: int close(int fd)
|
||||
:name: dvb-audio-close
|
||||
|
||||
|
||||
Arguments
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
DVB audio open()
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int open(const char *deviceName, int flags)
|
||||
.. c:function:: int open(const char *deviceName, int flags)
|
||||
:name: dvb-audio-open
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -80,6 +82,8 @@ AUDIO_GET_STATUS. All other call will return with an error code.
|
|||
Return Value
|
||||
------------
|
||||
|
||||
.. tabularcolumns:: |p{2.5cm}|p{15.0cm}|
|
||||
|
||||
.. flat-table::
|
||||
:header-rows: 0
|
||||
:stub-columns: 0
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
DVB audio write()
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: size_t write(int fd, const void *buf, size_t count)
|
||||
.. c:function:: size_t write(int fd, const void *buf, size_t count)
|
||||
:name: dvb-audio-write
|
||||
|
||||
|
||||
Arguments
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_GET_CAPABILITIES
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_GET_CAPABILITIES, unsigned int *cap)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap)
|
||||
:name: AUDIO_GET_CAPABILITIES
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -26,19 +28,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_GET_CAPABILITIES for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- unsigned int \*cap
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_GET_PTS
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_GET_PTS, __u64 *pts)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_GET_PTS, __u64 *pts)
|
||||
:name: AUDIO_GET_PTS
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -26,19 +28,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_GET_PTS for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- __u64 \*pts
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_GET_STATUS
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_GET_STATUS, struct audio_status *status)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status)
|
||||
:name: AUDIO_GET_STATUS
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -26,19 +28,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_GET_STATUS for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- struct audio_status \*status
|
||||
|
||||
|
|
|
@ -11,12 +11,13 @@ Name
|
|||
|
||||
AUDIO_PAUSE
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_PAUSE)
|
||||
|
||||
.. c:function:: int ioctl(int fd, AUDIO_PAUSE)
|
||||
:name: AUDIO_PAUSE
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
@ -32,12 +33,6 @@ Arguments
|
|||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_PAUSE for this command.
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_PLAY
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_PLAY)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_PLAY)
|
||||
:name: AUDIO_PLAY
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -32,13 +34,6 @@ Arguments
|
|||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_PLAY for this command.
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_SELECT_SOURCE
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SELECT_SOURCE, audio_stream_source_t source)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source)
|
||||
:name: AUDIO_SELECT_SOURCE
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -26,19 +28,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_SELECT_SOURCE for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- audio_stream_source_t source
|
||||
|
||||
|
|
|
@ -11,12 +11,14 @@ Name
|
|||
|
||||
AUDIO_SET_ATTRIBUTES
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(fd, int request = AUDIO_SET_ATTRIBUTES, audio_attributes_t attr )
|
||||
|
||||
.. c:function:: int ioctl(fd, AUDIO_SET_ATTRIBUTES, struct audio_attributes *attr )
|
||||
:name: AUDIO_SET_ATTRIBUTES
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
@ -26,19 +28,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_SET_ATTRIBUTES for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- audio_attributes_t attr
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ Name
|
|||
|
||||
AUDIO_SET_AV_SYNC
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SET_AV_SYNC, boolean state)
|
||||
.. c:function:: int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state)
|
||||
:name: AUDIO_SET_AV_SYNC
|
||||
|
||||
|
||||
Arguments
|
||||
|
@ -26,33 +28,21 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_AV_SYNC for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- boolean state
|
||||
|
||||
- Tells the DVB subsystem if A/V synchronization shall be ON or OFF.
|
||||
|
||||
- .. row 4
|
||||
TRUE: AV-sync ON
|
||||
|
||||
-
|
||||
- TRUE AV-sync ON
|
||||
|
||||
- .. row 5
|
||||
|
||||
-
|
||||
- FALSE AV-sync OFF
|
||||
FALSE: AV-sync OFF
|
||||
|
||||
|
||||
Description
|
||||
|
|
|
@ -11,12 +11,13 @@ Name
|
|||
|
||||
AUDIO_SET_BYPASS_MODE
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SET_BYPASS_MODE, boolean mode)
|
||||
|
||||
.. c:function:: int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode)
|
||||
:name: AUDIO_SET_BYPASS_MODE
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
@ -26,34 +27,22 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_SET_BYPASS_MODE for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- boolean mode
|
||||
|
||||
- Enables or disables the decoding of the current Audio stream in
|
||||
the DVB subsystem.
|
||||
|
||||
- .. row 4
|
||||
TRUE: Bypass is disabled
|
||||
|
||||
-
|
||||
- TRUE Bypass is disabled
|
||||
|
||||
- .. row 5
|
||||
|
||||
-
|
||||
- FALSE Bypass is enabled
|
||||
FALSE: Bypass is enabled
|
||||
|
||||
|
||||
Description
|
||||
|
|
|
@ -11,12 +11,13 @@ Name
|
|||
|
||||
AUDIO_SET_EXT_ID
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(fd, int request = AUDIO_SET_EXT_ID, int id)
|
||||
|
||||
.. c:function:: int ioctl(fd, AUDIO_SET_EXT_ID, int id)
|
||||
:name: AUDIO_SET_EXT_ID
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
@ -26,19 +27,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_SET_EXT_ID for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- int id
|
||||
|
||||
|
|
|
@ -11,12 +11,13 @@ Name
|
|||
|
||||
AUDIO_SET_ID
|
||||
|
||||
.. attention:: This ioctl is deprecated
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. cpp:function:: int ioctl(int fd, int request = AUDIO_SET_ID, int id)
|
||||
|
||||
.. c:function:: int ioctl(int fd, AUDIO_SET_ID, int id)
|
||||
:name: AUDIO_SET_ID
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
@ -26,19 +27,13 @@ Arguments
|
|||
:stub-columns: 0
|
||||
|
||||
|
||||
- .. row 1
|
||||
-
|
||||
|
||||
- int fd
|
||||
|
||||
- File descriptor returned by a previous call to open().
|
||||
|
||||
- .. row 2
|
||||
|
||||
- int request
|
||||
|
||||
- Equals AUDIO_SET_ID for this command.
|
||||
|
||||
- .. row 3
|
||||
-
|
||||
|
||||
- int id
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue