xref: /aosp_15_r20/external/pigweed/pw_persistent_ram/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_persistent_ram:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker=================
4*61c4878aSAndroid Build Coastguard Workerpw_persistent_ram
5*61c4878aSAndroid Build Coastguard Worker=================
6*61c4878aSAndroid Build Coastguard WorkerThe ``pw_persistent_ram`` module contains utilities and containers for using
7*61c4878aSAndroid Build Coastguard Workerpersistent RAM. By persistent RAM we are referring to memory which is not
8*61c4878aSAndroid Build Coastguard Workerinitialized across reboots by the hardware nor bootloader(s). This memory may
9*61c4878aSAndroid Build Coastguard Workerdecay or bit rot between reboots including brownouts, ergo integrity checking is
10*61c4878aSAndroid Build Coastguard Workerhighly recommended.
11*61c4878aSAndroid Build Coastguard Worker
12*61c4878aSAndroid Build Coastguard Worker.. Note::
13*61c4878aSAndroid Build Coastguard Worker  This is something that not all architectures and applications built on them
14*61c4878aSAndroid Build Coastguard Worker  support and requires hardware in the loop testing to verify it works as
15*61c4878aSAndroid Build Coastguard Worker  intended.
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker.. Warning::
18*61c4878aSAndroid Build Coastguard Worker  Do not treat the current containers provided in this module as stable storage
19*61c4878aSAndroid Build Coastguard Worker  primitives. We are still evaluating lighterweight checksums from a code size
20*61c4878aSAndroid Build Coastguard Worker  point of view. In other words, future updates to this module may result in a
21*61c4878aSAndroid Build Coastguard Worker  loss of persistent data across software updates.
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker------------------------
24*61c4878aSAndroid Build Coastguard WorkerPersistent RAM Placement
25*61c4878aSAndroid Build Coastguard Worker------------------------
26*61c4878aSAndroid Build Coastguard WorkerPersistent RAM is typically provided through specially carved out linker script
27*61c4878aSAndroid Build Coastguard Workersections and/or memory ranges which are located in such a way that any
28*61c4878aSAndroid Build Coastguard Workerbootloaders and the application boot code do not clobber it.
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard Worker1. If persistent linker sections are provided, use the ``PW_PLACE_IN_SECTION()``
31*61c4878aSAndroid Build Coastguard Worker   macro to assign variables to that memory region. For example, if the
32*61c4878aSAndroid Build Coastguard Worker   persistent memory section name is ``.noinit``, then you could instantiate an
33*61c4878aSAndroid Build Coastguard Worker   object as such:
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker   .. code-block:: cpp
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Worker      #include "pw_persistent_ram/persistent.h"
38*61c4878aSAndroid Build Coastguard Worker      #include "pw_preprocessor/compiler.h"
39*61c4878aSAndroid Build Coastguard Worker
40*61c4878aSAndroid Build Coastguard Worker      using pw::persistent_ram::Persistent;
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker      PW_PLACE_IN_SECTION(".noinit") Persistent<bool> persistent_bool;
43*61c4878aSAndroid Build Coastguard Worker
44*61c4878aSAndroid Build Coastguard Worker2. If persistent memory ranges are provided, you can use use a struct to wrap
45*61c4878aSAndroid Build Coastguard Worker   the different persisted objects. This makes it possible to ensure that the
46*61c4878aSAndroid Build Coastguard Worker   data fits in the provided memory range. This must be done via a runtime check
47*61c4878aSAndroid Build Coastguard Worker   against variables provided through the linker script since the addresses
48*61c4878aSAndroid Build Coastguard Worker   of linker script symbols aren't available at compile time.
49*61c4878aSAndroid Build Coastguard Worker
50*61c4878aSAndroid Build Coastguard Worker   .. code-block:: cpp
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Worker      #include "pw_assert/check.h"
53*61c4878aSAndroid Build Coastguard Worker      #include "pw_persistent_ram/persistent.h"
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker      // Provided for example through a linker script.
56*61c4878aSAndroid Build Coastguard Worker      extern "C" uint8_t __noinit_begin;
57*61c4878aSAndroid Build Coastguard Worker      extern "C" uint8_t __noinit_end;
58*61c4878aSAndroid Build Coastguard Worker
59*61c4878aSAndroid Build Coastguard Worker      struct PersistentData {
60*61c4878aSAndroid Build Coastguard Worker        Persistent<bool> persistent_bool;
61*61c4878aSAndroid Build Coastguard Worker      };
62*61c4878aSAndroid Build Coastguard Worker      PersistentData& persistent_data =
63*61c4878aSAndroid Build Coastguard Worker        *reinterpret_cast<NoinitData*>(&__noinit_begin);
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker      void CheckPersistentDataSize() {
66*61c4878aSAndroid Build Coastguard Worker        PW_DCHECK_UINT_LE(sizeof(PersistentData),
67*61c4878aSAndroid Build Coastguard Worker                          __noinit_end - __noinit_begin,
68*61c4878aSAndroid Build Coastguard Worker                          "PersistentData overflowed the noinit memory range");
69*61c4878aSAndroid Build Coastguard Worker      }
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard Worker-----------------------------------
72*61c4878aSAndroid Build Coastguard WorkerPersistent RAM Lifecycle Management
73*61c4878aSAndroid Build Coastguard Worker-----------------------------------
74*61c4878aSAndroid Build Coastguard WorkerIn order for persistent RAM containers to be as useful as possible, any
75*61c4878aSAndroid Build Coastguard Workerinvalidation of persistent RAM and the containers therein should be executed
76*61c4878aSAndroid Build Coastguard Workerbefore the global static C++ constructors, but after the BSS and data sections
77*61c4878aSAndroid Build Coastguard Workerare initialized in RAM.
78*61c4878aSAndroid Build Coastguard Worker
79*61c4878aSAndroid Build Coastguard WorkerThe preferred way to clear Persistent RAM is to simply zero entire persistent
80*61c4878aSAndroid Build Coastguard WorkerRAM sections and/or memory regions. Pigweed's persistent containers have picked
81*61c4878aSAndroid Build Coastguard Workerintegrity checks which work with zeroed memory, meaning they do not hold a value
82*61c4878aSAndroid Build Coastguard Workerafter zeroing. Alternatively containers can be individually cleared.
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard WorkerThe boot sequence itself is tightly coupled to the number of persistent sections
85*61c4878aSAndroid Build Coastguard Workerand/or memory regions which exist in the final image, ergo this is something
86*61c4878aSAndroid Build Coastguard Workerwhich Pigweed cannot provide to the user directly. However, we do recommend
87*61c4878aSAndroid Build Coastguard Workerfollowing some guidelines:
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker1. Do not instantiate regular types/objects in persistent RAM, ensure integrity
90*61c4878aSAndroid Build Coastguard Worker   checking is always used! This is a major risk with this technique and can
91*61c4878aSAndroid Build Coastguard Worker   lead to unexpected memory corruption.
92*61c4878aSAndroid Build Coastguard Worker2. Always instantiate persistent containers outside of the objects which depend
93*61c4878aSAndroid Build Coastguard Worker   on them and use dependency injection. This permits unit testing and avoids
94*61c4878aSAndroid Build Coastguard Worker   placement accidents of persistents and/or their users.
95*61c4878aSAndroid Build Coastguard Worker3. Always erase persistent RAM data after software updates unless the
96*61c4878aSAndroid Build Coastguard Worker   persistent storage containers are explicitly stored at fixed address and
97*61c4878aSAndroid Build Coastguard Worker   with a fixed layout. This prevents use of swapped objects or their members
98*61c4878aSAndroid Build Coastguard Worker   where the same integrity checks are used.
99*61c4878aSAndroid Build Coastguard Worker4. Consider zeroing persistent RAM to recover from crashes which may be induced
100*61c4878aSAndroid Build Coastguard Worker   by persistent RAM usage, for example by checking the reboot/crash reason.
101*61c4878aSAndroid Build Coastguard Worker5. Consider zeroing persistent RAM on cold boots to always start from a
102*61c4878aSAndroid Build Coastguard Worker   consistent state if persistence is only desired across warm reboots. This can
103*61c4878aSAndroid Build Coastguard Worker   create determinism from cold boots when using for example DRAM.
104*61c4878aSAndroid Build Coastguard Worker6. Consider an explicit persistent clear request which can be set before a warm
105*61c4878aSAndroid Build Coastguard Worker   reboot as a signal to zero all persistent RAM on the next boot to emulate
106*61c4878aSAndroid Build Coastguard Worker   persistent memory loss in a threadsafe manner.
107*61c4878aSAndroid Build Coastguard Worker
108*61c4878aSAndroid Build Coastguard Worker---------------------------------
109*61c4878aSAndroid Build Coastguard Workerpw::persistent_ram::Persistent<T>
110*61c4878aSAndroid Build Coastguard Worker---------------------------------
111*61c4878aSAndroid Build Coastguard WorkerThe Persistent is a simple container for holding its templated value ``T`` with
112*61c4878aSAndroid Build Coastguard WorkerCRC16 integrity checking. Note that a Persistent will be lost if a write/set
113*61c4878aSAndroid Build Coastguard Workeroperation is interrupted or otherwise not completed, as it is not double
114*61c4878aSAndroid Build Coastguard Workerbuffered.
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard WorkerThe default constructor does nothing, meaning it will result in either invalid
117*61c4878aSAndroid Build Coastguard Workerstate initially or a valid persisted value from a previous session.
118*61c4878aSAndroid Build Coastguard Worker
119*61c4878aSAndroid Build Coastguard WorkerThe destructor does nothing, ergo it is okay if it is not executed during
120*61c4878aSAndroid Build Coastguard Workershutdown.
121*61c4878aSAndroid Build Coastguard Worker
122*61c4878aSAndroid Build Coastguard WorkerExample: Storing an integer
123*61c4878aSAndroid Build Coastguard Worker---------------------------
124*61c4878aSAndroid Build Coastguard WorkerA common use case of persistent data is to track boot counts, or effectively
125*61c4878aSAndroid Build Coastguard Workerhow often the device has rebooted. This can be useful for monitoring how many
126*61c4878aSAndroid Build Coastguard Workertimes the device rebooted and/or crashed. This can be easily accomplished using
127*61c4878aSAndroid Build Coastguard Workerthe Persistent container.
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
130*61c4878aSAndroid Build Coastguard Worker
131*61c4878aSAndroid Build Coastguard Worker   #include "pw_persistent_ram/persistent.h"
132*61c4878aSAndroid Build Coastguard Worker   #include "pw_preprocessor/compiler.h"
133*61c4878aSAndroid Build Coastguard Worker
134*61c4878aSAndroid Build Coastguard Worker   using pw::persistent_ram::Persistent;
135*61c4878aSAndroid Build Coastguard Worker
136*61c4878aSAndroid Build Coastguard Worker   class BootCount {
137*61c4878aSAndroid Build Coastguard Worker    public:
138*61c4878aSAndroid Build Coastguard Worker     explicit BootCount(Persistent<uint16_t>& persistent_boot_count)
139*61c4878aSAndroid Build Coastguard Worker         : persistent_(persistent_boot_count) {
140*61c4878aSAndroid Build Coastguard Worker       if (!persistent_.has_value()) {
141*61c4878aSAndroid Build Coastguard Worker         persistent_ = 0;
142*61c4878aSAndroid Build Coastguard Worker       } else {
143*61c4878aSAndroid Build Coastguard Worker         persistent_ = persistent_.value() + 1;
144*61c4878aSAndroid Build Coastguard Worker       }
145*61c4878aSAndroid Build Coastguard Worker       boot_count_ = persistent_.value();
146*61c4878aSAndroid Build Coastguard Worker     }
147*61c4878aSAndroid Build Coastguard Worker
148*61c4878aSAndroid Build Coastguard Worker     uint16_t GetBootCount() { return boot_count_; }
149*61c4878aSAndroid Build Coastguard Worker
150*61c4878aSAndroid Build Coastguard Worker    private:
151*61c4878aSAndroid Build Coastguard Worker     Persistent<uint16_t>& persistent_;
152*61c4878aSAndroid Build Coastguard Worker     uint16_t boot_count_;
153*61c4878aSAndroid Build Coastguard Worker   };
154*61c4878aSAndroid Build Coastguard Worker
155*61c4878aSAndroid Build Coastguard Worker   PW_PLACE_IN_SECTION(".noinit") Persistent<uint16_t> persistent_boot_count;
156*61c4878aSAndroid Build Coastguard Worker   BootCount boot_count(persistent_boot_count);
157*61c4878aSAndroid Build Coastguard Worker
158*61c4878aSAndroid Build Coastguard Worker   int main() {
159*61c4878aSAndroid Build Coastguard Worker     const uint16_t boot_count = boot_count.GetBootCount();
160*61c4878aSAndroid Build Coastguard Worker     // ... rest of main
161*61c4878aSAndroid Build Coastguard Worker   }
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard WorkerExample: Storing larger objects
164*61c4878aSAndroid Build Coastguard Worker-------------------------------
165*61c4878aSAndroid Build Coastguard WorkerLarger objects may be inefficient to copy back and forth due to the need for
166*61c4878aSAndroid Build Coastguard Workera working copy. To work around this, you can get a Mutator handle that provides
167*61c4878aSAndroid Build Coastguard Workerdirect access to the underlying object. As long as the Mutator is in scope, it
168*61c4878aSAndroid Build Coastguard Workeris invalid to access the underlying Persistent, but you'll be able to directly
169*61c4878aSAndroid Build Coastguard Workermodify the object in place. Once the Mutator goes out of scope, the Persistent
170*61c4878aSAndroid Build Coastguard Workerobject's checksum is updated to reflect the changes.
171*61c4878aSAndroid Build Coastguard Worker
172*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker   #include "pw_persistent_ram/persistent.h"
175*61c4878aSAndroid Build Coastguard Worker   #include "pw_preprocessor/compiler.h"
176*61c4878aSAndroid Build Coastguard Worker
177*61c4878aSAndroid Build Coastguard Worker   using pw::persistent_ram::Persistent;
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard Worker   contexpr size_t kMaxReasonLength = 256;
180*61c4878aSAndroid Build Coastguard Worker
181*61c4878aSAndroid Build Coastguard Worker   struct LastCrashInfo {
182*61c4878aSAndroid Build Coastguard Worker     uint32_t uptime_ms;
183*61c4878aSAndroid Build Coastguard Worker     uint32_t boot_id;
184*61c4878aSAndroid Build Coastguard Worker     char reason[kMaxReasonLength];
185*61c4878aSAndroid Build Coastguard Worker   }
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker   PW_PLACE_IN_SECTION(".noinit") Persistent<LastBootInfo> persistent_crash_info;
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard Worker   void HandleCrash(const char* fmt, va_list args) {
190*61c4878aSAndroid Build Coastguard Worker     // Once this scope ends, we know the persistent object has been updated
191*61c4878aSAndroid Build Coastguard Worker     // to reflect changes.
192*61c4878aSAndroid Build Coastguard Worker     {
193*61c4878aSAndroid Build Coastguard Worker       auto& mutable_crash_info =
194*61c4878aSAndroid Build Coastguard Worker           persistent_crash_info.mutator(GetterAction::kReset);
195*61c4878aSAndroid Build Coastguard Worker       vsnprintf(mutable_crash_info->reason,
196*61c4878aSAndroid Build Coastguard Worker                 sizeof(mutable_crash_info->reason),
197*61c4878aSAndroid Build Coastguard Worker                 fmt,
198*61c4878aSAndroid Build Coastguard Worker                 args);
199*61c4878aSAndroid Build Coastguard Worker       mutable_crash_info->uptime_ms = system::GetUptimeMs();
200*61c4878aSAndroid Build Coastguard Worker       mutable_crash_info->boot_id = system::GetBootId();
201*61c4878aSAndroid Build Coastguard Worker     }
202*61c4878aSAndroid Build Coastguard Worker     // ...
203*61c4878aSAndroid Build Coastguard Worker   }
204*61c4878aSAndroid Build Coastguard Worker
205*61c4878aSAndroid Build Coastguard Worker   int main() {
206*61c4878aSAndroid Build Coastguard Worker     if (persistent_crash_info.has_value()) {
207*61c4878aSAndroid Build Coastguard Worker       LogLastCrashInfo(persistent_crash_info.value());
208*61c4878aSAndroid Build Coastguard Worker       // Clear crash info once it has been dumped.
209*61c4878aSAndroid Build Coastguard Worker       persistent_crash_info.Invalidate();
210*61c4878aSAndroid Build Coastguard Worker     }
211*61c4878aSAndroid Build Coastguard Worker
212*61c4878aSAndroid Build Coastguard Worker     // ... rest of main
213*61c4878aSAndroid Build Coastguard Worker   }
214*61c4878aSAndroid Build Coastguard Worker
215*61c4878aSAndroid Build Coastguard Worker.. _module-pw_persistent_ram-persistent_buffer:
216*61c4878aSAndroid Build Coastguard Worker
217*61c4878aSAndroid Build Coastguard Worker------------------------------------
218*61c4878aSAndroid Build Coastguard Workerpw::persistent_ram::PersistentBuffer
219*61c4878aSAndroid Build Coastguard Worker------------------------------------
220*61c4878aSAndroid Build Coastguard WorkerThe PersistentBuffer is a persistent storage container for variable-length
221*61c4878aSAndroid Build Coastguard Workerserialized data. Rather than allowing direct access to the underlying buffer for
222*61c4878aSAndroid Build Coastguard Workerrandom-access mutations, the PersistentBuffer is mutable through a
223*61c4878aSAndroid Build Coastguard WorkerPersistentBufferWriter that implements the pw::stream::Writer interface. This
224*61c4878aSAndroid Build Coastguard Workerremoves the potential for logical errors due to RAII or open()/close() semantics
225*61c4878aSAndroid Build Coastguard Workeras both the PersistentBuffer and PersistentBufferWriter can be used validly as
226*61c4878aSAndroid Build Coastguard Workerlong as their access is serialized.
227*61c4878aSAndroid Build Coastguard Worker
228*61c4878aSAndroid Build Coastguard WorkerExample
229*61c4878aSAndroid Build Coastguard Worker-------
230*61c4878aSAndroid Build Coastguard WorkerAn example use case is emitting crash handler logs to a buffer for them to be
231*61c4878aSAndroid Build Coastguard Workeravailable after a the device reboots. Once the device reboots, the logs would be
232*61c4878aSAndroid Build Coastguard Workeremitted by the logging system. While this isn't always practical for plaintext
233*61c4878aSAndroid Build Coastguard Workerlogs, tokenized logs are small enough for this to be useful.
234*61c4878aSAndroid Build Coastguard Worker
235*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
236*61c4878aSAndroid Build Coastguard Worker
237*61c4878aSAndroid Build Coastguard Worker   #include "pw_persistent_ram/persistent_buffer.h"
238*61c4878aSAndroid Build Coastguard Worker   #include "pw_preprocessor/compiler.h"
239*61c4878aSAndroid Build Coastguard Worker
240*61c4878aSAndroid Build Coastguard Worker   using pw::persistent_ram::PersistentBuffer;
241*61c4878aSAndroid Build Coastguard Worker   using pw::persistent_ram::PersistentBuffer::PersistentBufferWriter;
242*61c4878aSAndroid Build Coastguard Worker
243*61c4878aSAndroid Build Coastguard Worker   PW_KEEP_IN_SECTION(".noinit") PersistentBuffer<2048> crash_logs;
244*61c4878aSAndroid Build Coastguard Worker   void CheckForCrashLogs() {
245*61c4878aSAndroid Build Coastguard Worker     if (crash_logs.has_value()) {
246*61c4878aSAndroid Build Coastguard Worker       // A function that dumps sequentially serialized logs using pw_log.
247*61c4878aSAndroid Build Coastguard Worker       DumpRawLogs(crash_logs.written_data());
248*61c4878aSAndroid Build Coastguard Worker       crash_logs.clear();
249*61c4878aSAndroid Build Coastguard Worker     }
250*61c4878aSAndroid Build Coastguard Worker   }
251*61c4878aSAndroid Build Coastguard Worker
252*61c4878aSAndroid Build Coastguard Worker   void HandleCrash(CrashInfo* crash_info) {
253*61c4878aSAndroid Build Coastguard Worker     PersistentBufferWriter crash_log_writer = crash_logs.GetWriter();
254*61c4878aSAndroid Build Coastguard Worker     // Sets the pw::stream::Writer that pw_log should dump logs to.
255*61c4878aSAndroid Build Coastguard Worker     crash_log_writer.clear();
256*61c4878aSAndroid Build Coastguard Worker     SetLogSink(crash_log_writer);
257*61c4878aSAndroid Build Coastguard Worker     // Handle crash, calling PW_LOG to log useful info.
258*61c4878aSAndroid Build Coastguard Worker   }
259*61c4878aSAndroid Build Coastguard Worker
260*61c4878aSAndroid Build Coastguard Worker   int main() {
261*61c4878aSAndroid Build Coastguard Worker     void CheckForCrashLogs();
262*61c4878aSAndroid Build Coastguard Worker     // ... rest of main
263*61c4878aSAndroid Build Coastguard Worker   }
264*61c4878aSAndroid Build Coastguard Worker
265*61c4878aSAndroid Build Coastguard WorkerSize Report
266*61c4878aSAndroid Build Coastguard Worker-----------
267*61c4878aSAndroid Build Coastguard WorkerThe following size report showcases the overhead for using Persistent. Note that
268*61c4878aSAndroid Build Coastguard Workerthis is templating the Persistent only on a ``uint32_t``, ergo the cost without
269*61c4878aSAndroid Build Coastguard Workerpw_checksum's CRC16 is the approximate cost per type.
270*61c4878aSAndroid Build Coastguard Worker
271*61c4878aSAndroid Build Coastguard Worker.. include:: persistent_size
272*61c4878aSAndroid Build Coastguard Worker
273*61c4878aSAndroid Build Coastguard WorkerCompatibility
274*61c4878aSAndroid Build Coastguard Worker-------------
275*61c4878aSAndroid Build Coastguard Worker* C++17
276*61c4878aSAndroid Build Coastguard Worker
277*61c4878aSAndroid Build Coastguard WorkerDependencies
278*61c4878aSAndroid Build Coastguard Worker------------
279*61c4878aSAndroid Build Coastguard Worker* ``pw_checksum``
280