summaryrefslogtreecommitdiff
path: root/doc/memory.9.txt
blob: 67b8afa693a5910a4469248e3ff17a063543bba1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
MEMORY(9)
========
:doctype:       manpage
:man source:    X15
:man manual:    X15 Kernel Developer{rsquo}s Manual

NAME
----

memory - Memory model

DESCRIPTION
-----------

This document describes the memory model of the kernel.

The X15 kernel uses the freestanding execution environment. As a result,
atomic operations as provided by <stdatomic.h> are not available. Instead,
the kernel provides its own library of atomic operations. In addition,
it also provides "local atomic" operations, interrupt-safe operations that
are atomic on the local processor. These operations can transparently
replace atomic operations on single-processor configurations.

For portability, atomic operations are restricted to 32-bit and 64-bit
accesses. The availability of 64-bit atomic operations is indicated
by the definition of the ATOMIC_HAVE_64B_OPS macro.

Terms
~~~~~

AR:: acquire-release
SC:: sequentially-consistent

INTRA-THREAD MEMORY ORDERING
----------------------------

Memory ordering in a single thread of execution behaves as defined by
the C specification the kernel is conforming to. This means that the
generated code must not change the _observable behavior_ of the program,
which is informally called the _as-if rule_. During its execution,
the kernel may change the environment, and environmental changes may
conflict with compiler optimizations. For example, it may configure
an MMU and change the entire memory map. Compiler optimizations, and
in particular instruction reordering, may cause instructions intended
to run with the new memory map to run with the previous one, and
potentially trigger a fault. Since the compiler cannot recognize such
situations and adjust the generated code accordingly, this is a
responsibility of the developer.

There are several ways to control code generation.

Local atomic operations
~~~~~~~~~~~~~~~~~~~~~~~

_Local atomic operations_, as defined in module:kern/latomic, are similar
to global atomic operations, but are only valid on a single processor.
They are atomic with respect to one another and interrupts. Because they
may not be used for inter-processor communication, they allow a cheaper
implementation than atomic operations. Because they only need to be
atomic with respect to one another and interrupts, they may be provided by
a generic and portable implementation built with interrupt-based critical
sections, which is useful when starting a new port, or if the target
architecture supports a single processor at most and doesn't provide
atomic instructions.

Strong sequencing
~~~~~~~~~~~~~~~~~

_Strong sequence points_ are defined as sequence points that affect the
implementation in addition to the abstract machine. The _strongly
sequenced before_ and _strongly sequenced after_ relations are similar
to _sequenced before_ and _sequenced after_ respectively, except that
they affect the implementation in addition to the abstract machine.
Strong sequencing only affects compiler optimizations and reorderings
of loads and stores; whether hardware fence instructions are emitted
or not isn't affected.

Here is the list of strong sequence points :

* SC local atomic operation or fence
* SC global atomic operation or fence
* volatile inline assembly with the memory clobber

Technically, AR local atomic fences also are strong sequence points,
but for consistency with AR global atomic fences, which may not be
strong sequence points, they are not part of the list.

INTER-THREAD MEMORY ORDERING
----------------------------

Global atomic operations
~~~~~~~~~~~~~~~~~~~~~~~~

_Global atomic operations_, as defined in module:kern/atomic, behave
similarly to the atomic operations as defined by the C specification
the kernel is conforming to. One major difference though is that they
apply to standard integer types.

There are no special provisions for initialization. Initializing a
variable must simply happen before any other access to that variable.
For example, this may be achieved with a release-write to the variable,
or with a regular write that preceding a release sequence. This makes
the interface surface of the atomic module much more compact than
the standard one.

IMPLEMENTATION
--------------

Global atomic operations are implemented using the GCC "built-in
functions for memory model aware atomic operations".

Local atomic operations may be implemented with a generic and portable
implementation built with interrupt-based critical sections that is
part of the module:kern/latomic module. Architecture-specific code
may partially or completely override the machine-independent
implementation.

Note that, because the compiler doesn't know about local atomic
operations, they could in theory be reordered across fences. It is
assumed that all the built-in atomic operations provided by the
compiler are volatile-qualified. Local atomic operations must also
be volatile-qualified. With current compiler implementations, this
guarantees that local atomic operations may not be reordered across
fences.

SEE
---

manpage:intro

{c-specification}

{gcc-atomics}