_Restarting Embedded Systems_ by Fredrik Bredberg, Ola Liljedahl, and Bengt Eliasson Example 1: typedef struct { int iDataChecksumInvalid; unsigned long ulDataChecksum; TData tData; /* Actual data */ } TDataRegion; TDataRegion *ptDataRegion = (TDataRegion *)SOME_HW_ADDRESS; Example 2: ptDataRegion -> iDataChecksumInvalid = TRUE; ptDataRegion -> tData = tNewData; ptDataRegion -> ulDataChecksum = ulChecksum(ptDataRegion -> tData, sizeof(TData)); ptDataRegion -> iDataChecksumInvalid = FALSE; Example 3: /* Return false if the invalid flag is set or if a recalculated checksum does ot match the saved one. */ int iDataRegionIsValid(void) { if (ptDataRegion -> iDataChecksumInvalid || (ptDataRegion -> ulDataChecksum != ulChecksum(ptDataRegion -> tData, sizeof(TData))) return FALSE; return TRUE; } /* iDataRegionIsValid */ Example 4: WRITE(logical_address) { 1 Check if the logical_address is valid. If it is not the page fault is of no concern to WRITE. 2 Allocate a new physical page, the working page. It is currently only accessible through the RAM shadow. 3 Copy data from the original page (accessible through the logical_address) to the working page. 4 Log the change of page for this logical_address in the transaction record. 5 Change the MMU's page table to reflect the fact that the logical_address is now physically located in the working page. 6 Make the working page writable (for instance, change the MMU's page table). } Example 5: The SYNC() function SYNC() { 1 If data pages are cached with copy back-mode then flush these pages. 2 Compute checksums of all working pages and store them into the transaction record. 3 Compute the checksum of the transaction record itself. 4 Save information about what original pages that are to be replaced so that we can deallocate them later. 5 Set update-in-progress flag. 6 Update the region descriptor from the transaction record. 7 Calculate the new checksum of the region descriptor. 8 Clear the update-in-progress flag. 9 Clear the transaction record. 10 Deallocate the old original pages, which have now been replaced by their working pages. 11 Write protect the new original pages. We now want page faults again whenever some process attempts to write to such a page. } Example 6: RECOVER() { 1 If the update-in-progress flag is set then update region descriptor from transaction record and clear update-in-progress-flag. 2 Compute checksum of the region descriptor and check it against the stored checksum. 3 Check that all page addresses in the region descriptor are valid. 4 Compute checksums of all pages addressed by the region descriptor and check them against their checksums stored in the region descriptor. 5 If any of steps 2, 3 or 4 failed then data integrity is lost. Build a new region descriptor and clear all data pages. Else all of steps 2, 3 and 4 succeeded and data is in a consistent state. 6 Build a freelist over all physical pages not used by the region descriptor and its data pages. 7 Build tables for the region's data pages. Pages should be write protected (read only), as they are all original pages. 8 Build page tables for the RAM shadow. 9 Build page tables for other memory areas not related to the atomic update scheme (ROM/RAM/IO). 10 Enable the MMU. }