mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 09:34:18 +00:00
doc: Reorder coding guidelines document
This patch attempts to make the guidelines clearer by reordering the sections and grouping similar topics. Change-Id: I1418d6fc060d6403fe3e1978f32fd54b8793ad5b Signed-off-by: Paul Beesley <paul.beesley@arm.com>
This commit is contained in:
parent
93fbc7142e
commit
7306de9991
1 changed files with 138 additions and 129 deletions
|
@ -30,8 +30,51 @@ include:
|
|||
contains some very useful information, there are several legimate uses of the
|
||||
volatile keyword within the TF codebase.
|
||||
|
||||
Headers and inclusion
|
||||
---------------------
|
||||
|
||||
Header guards
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
For a header file called "some_driver.h" the style used by the Trusted Firmware
|
||||
is:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#ifndef SOME_DRIVER_H
|
||||
#define SOME_DRIVER_H
|
||||
|
||||
<header content>
|
||||
|
||||
#endif /* SOME_DRIVER_H */
|
||||
|
||||
|
||||
Include statements
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Any header files under ``include/`` are *system* includes and should be
|
||||
included using the ``#include <path/to/file.h>`` syntax.
|
||||
|
||||
Platforms are allowed to add more include paths to be passed to the compiler.
|
||||
This is needed in particular for the file ``platform_def.h``:
|
||||
|
||||
.. code:: c
|
||||
|
||||
PLAT_INCLUDES += -Iinclude/plat/myplat/include
|
||||
|
||||
Header files that are included from the same or relative directory as the source
|
||||
file are *user* includes and should be included using the ``#include "relative-path/file.h"``
|
||||
syntax.
|
||||
|
||||
``#include`` statements should be in alphabetical order, with *system*
|
||||
includes listed before *user* includes and standard C library includes before
|
||||
anything else.
|
||||
|
||||
Types and typedefs
|
||||
------------------
|
||||
|
||||
Use of built-in *C* and *libc* data types
|
||||
-------------------------------------------
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The TF codebase should be kept as portable as possible, especially since both
|
||||
64-bit and 32-bit platforms are supported. To help with this, the following data
|
||||
|
@ -126,37 +169,56 @@ type usage guidelines should be followed:
|
|||
|
||||
These guidelines should be updated if additional types are needed.
|
||||
|
||||
Use logging macros to control log output
|
||||
----------------------------------------
|
||||
Avoid anonymous typedefs of structs/enums in headers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``debug.h`` provides logging macros (for example, ``WARN`` and ``ERROR``)
|
||||
which wrap ``tf_log`` and which allow the logging call to be compiled-out
|
||||
depending on the ``make`` command. Use these macros to avoid print statements
|
||||
being compiled unconditionally into the binary.
|
||||
|
||||
Each logging macro has a numerical log level:
|
||||
For example, the following definition:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define LOG_LEVEL_NONE 0
|
||||
#define LOG_LEVEL_ERROR 10
|
||||
#define LOG_LEVEL_NOTICE 20
|
||||
#define LOG_LEVEL_WARNING 30
|
||||
#define LOG_LEVEL_INFO 40
|
||||
#define LOG_LEVEL_VERBOSE 50
|
||||
typedef struct {
|
||||
int arg1;
|
||||
int arg2;
|
||||
} my_struct_t;
|
||||
|
||||
|
||||
By default, all logging statements with a log level ``<= LOG_LEVEL_INFO`` will
|
||||
be compiled into debug builds and all statements with a log level
|
||||
``<= LOG_LEVEL_NOTICE`` will be compiled into release builds. This can be
|
||||
overridden from the command line or by the platform makefile (although it may be
|
||||
necessary to clean the build directory first). For example, to enable
|
||||
``VERBOSE`` logging on FVP:
|
||||
is better written as:
|
||||
|
||||
``make PLAT=fvp LOG_LEVEL=50 all``
|
||||
.. code:: c
|
||||
|
||||
Error handling
|
||||
--------------
|
||||
struct my_struct {
|
||||
int arg1;
|
||||
int arg2;
|
||||
};
|
||||
|
||||
This allows function declarations in other header files that depend on the
|
||||
struct/enum to forward declare the struct/enum instead of including the
|
||||
entire header:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include <my_struct.h>
|
||||
void my_func(my_struct_t *arg);
|
||||
|
||||
instead of:
|
||||
|
||||
.. code:: c
|
||||
|
||||
struct my_struct;
|
||||
void my_func(struct my_struct *arg);
|
||||
|
||||
Some TF definitions use both a struct/enum name **and** a typedef name. This
|
||||
is discouraged for new definitions as it makes it difficult for TF to comply
|
||||
with MISRA rule 8.3, which states that "All declarations of an object or
|
||||
function shall use the same names and type qualifiers".
|
||||
|
||||
The Linux coding standards also discourage new typedefs and checkpatch emits
|
||||
a warning for this.
|
||||
|
||||
Existing typedefs will be retained for compatibility.
|
||||
|
||||
Error handling and robustness
|
||||
-----------------------------
|
||||
|
||||
Using CASSERT to check for compile time data errors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -333,122 +395,40 @@ The secure world **should never** crash or become unusable due to receiving too
|
|||
many normal world requests (a *Denial of Service* or *DoS* attack). It should
|
||||
have a mechanism for throttling or ignoring normal world requests.
|
||||
|
||||
Library and driver code
|
||||
-----------------------
|
||||
Performance considerations
|
||||
--------------------------
|
||||
|
||||
TF library code (under ``lib/`` and ``include/lib``) is any code that provides a
|
||||
reusable interface to other code, potentially even to code outside of TF.
|
||||
Avoid printf and use logging macros
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In some systems drivers must conform to a specific driver framework to provide
|
||||
services to the rest of the system. TF has no driver framework and the
|
||||
distinction between a driver and library is somewhat subjective.
|
||||
``debug.h`` provides logging macros (for example, ``WARN`` and ``ERROR``)
|
||||
which wrap ``tf_log`` and which allow the logging call to be compiled-out
|
||||
depending on the ``make`` command. Use these macros to avoid print statements
|
||||
being compiled unconditionally into the binary.
|
||||
|
||||
A driver (under ``drivers/`` and ``include/drivers/``) is defined as code that
|
||||
interfaces with hardware via a memory mapped interface.
|
||||
|
||||
Some drivers (for example, the Arm CCI driver in ``include/drivers/arm/cci.h``)
|
||||
provide a general purpose API to that specific hardware. Other drivers (for
|
||||
example, the Arm PL011 console driver in ``drivers/arm/pl011/pl011_console.S``)
|
||||
provide a specific hardware implementation of a more abstract library API. In
|
||||
the latter case there may potentially be multiple drivers for the same hardware
|
||||
device.
|
||||
|
||||
Neither libraries nor drivers should depend on platform-specific code. If they
|
||||
require platform-specific data (for example, a base address) to operate then
|
||||
they should provide an initialization function that takes the platform-specific
|
||||
data as arguments.
|
||||
|
||||
TF common code (under ``common/`` and ``include/common/``) is code that is re-used
|
||||
by other generic (non-platform-specific) TF code. It is effectively internal
|
||||
library code.
|
||||
|
||||
Header guards
|
||||
-------------
|
||||
|
||||
For a header file called "some_driver.h" the style used by the Trusted Firmware
|
||||
is:
|
||||
Each logging macro has a numerical log level:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#ifndef SOME_DRIVER_H
|
||||
#define SOME_DRIVER_H
|
||||
|
||||
<header content>
|
||||
|
||||
#endif /* SOME_DRIVER_H */
|
||||
#define LOG_LEVEL_NONE 0
|
||||
#define LOG_LEVEL_ERROR 10
|
||||
#define LOG_LEVEL_NOTICE 20
|
||||
#define LOG_LEVEL_WARNING 30
|
||||
#define LOG_LEVEL_INFO 40
|
||||
#define LOG_LEVEL_VERBOSE 50
|
||||
|
||||
|
||||
Include statements
|
||||
------------------
|
||||
By default, all logging statements with a log level ``<= LOG_LEVEL_INFO`` will
|
||||
be compiled into debug builds and all statements with a log level
|
||||
``<= LOG_LEVEL_NOTICE`` will be compiled into release builds. This can be
|
||||
overridden from the command line or by the platform makefile (although it may be
|
||||
necessary to clean the build directory first). For example, to enable
|
||||
``VERBOSE`` logging on FVP:
|
||||
|
||||
Any header files under ``include/`` are *system* includes and should be
|
||||
included using the ``#include <path/to/file.h>`` syntax.
|
||||
|
||||
Platforms are allowed to add more include paths to be passed to the compiler.
|
||||
This is needed in particular for the file ``platform_def.h``:
|
||||
|
||||
.. code:: c
|
||||
|
||||
PLAT_INCLUDES += -Iinclude/plat/myplat/include
|
||||
|
||||
Header files that are included from the same or relative directory as the source
|
||||
file are *user* includes and should be included using the ``#include "relative-path/file.h"``
|
||||
syntax.
|
||||
|
||||
``#include`` statements should be in alphabetical order, with *system*
|
||||
includes listed before *user* includes and standard C library includes before
|
||||
anything else.
|
||||
|
||||
Avoid anonymous typedefs of structs/enums in header files
|
||||
---------------------------------------------------------
|
||||
|
||||
For example, the following definition:
|
||||
|
||||
.. code:: c
|
||||
|
||||
typedef struct {
|
||||
int arg1;
|
||||
int arg2;
|
||||
} my_struct_t;
|
||||
|
||||
|
||||
is better written as:
|
||||
|
||||
.. code:: c
|
||||
|
||||
struct my_struct {
|
||||
int arg1;
|
||||
int arg2;
|
||||
};
|
||||
|
||||
This allows function declarations in other header files that depend on the
|
||||
struct/enum to forward declare the struct/enum instead of including the
|
||||
entire header:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include <my_struct.h>
|
||||
void my_func(my_struct_t *arg);
|
||||
|
||||
instead of:
|
||||
|
||||
.. code:: c
|
||||
|
||||
struct my_struct;
|
||||
void my_func(struct my_struct *arg);
|
||||
|
||||
Some TF definitions use both a struct/enum name **and** a typedef name. This
|
||||
is discouraged for new definitions as it makes it difficult for TF to comply
|
||||
with MISRA rule 8.3, which states that "All declarations of an object or
|
||||
function shall use the same names and type qualifiers".
|
||||
|
||||
The Linux coding standards also discourage new typedefs and checkpatch emits
|
||||
a warning for this.
|
||||
|
||||
Existing typedefs will be retained for compatibility.
|
||||
``make PLAT=fvp LOG_LEVEL=50 all``
|
||||
|
||||
Use const data where possible
|
||||
-----------------------------
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For example, the following code:
|
||||
|
||||
|
@ -491,6 +471,35 @@ writeable data section, which may result in a smaller and faster binary. Note
|
|||
that this may require dependent functions (``init()`` in the above example) to
|
||||
have ``const`` arguments, assuming they don't need to modify the data.
|
||||
|
||||
Library and driver code
|
||||
-----------------------
|
||||
|
||||
TF library code (under ``lib/`` and ``include/lib``) is any code that provides a
|
||||
reusable interface to other code, potentially even to code outside of TF.
|
||||
|
||||
In some systems drivers must conform to a specific driver framework to provide
|
||||
services to the rest of the system. TF has no driver framework and the
|
||||
distinction between a driver and library is somewhat subjective.
|
||||
|
||||
A driver (under ``drivers/`` and ``include/drivers/``) is defined as code that
|
||||
interfaces with hardware via a memory mapped interface.
|
||||
|
||||
Some drivers (for example, the Arm CCI driver in ``include/drivers/arm/cci.h``)
|
||||
provide a general purpose API to that specific hardware. Other drivers (for
|
||||
example, the Arm PL011 console driver in ``drivers/arm/pl011/pl011_console.S``)
|
||||
provide a specific hardware implementation of a more abstract library API. In
|
||||
the latter case there may potentially be multiple drivers for the same hardware
|
||||
device.
|
||||
|
||||
Neither libraries nor drivers should depend on platform-specific code. If they
|
||||
require platform-specific data (for example, a base address) to operate then
|
||||
they should provide an initialization function that takes the platform-specific
|
||||
data as arguments.
|
||||
|
||||
TF common code (under ``common/`` and ``include/common/``) is code that is re-used
|
||||
by other generic (non-platform-specific) TF code. It is effectively internal
|
||||
library code.
|
||||
|
||||
.. _`Why the “volatile” type class should not be used`: https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html
|
||||
.. _`Procedure Call Standard for the Arm Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf
|
||||
.. _`Procedure Call Standard for the Arm 64-bit Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
|
||||
|
|
Loading…
Add table
Reference in a new issue