| // Copyright Microsoft and CHERIoT Contributors. | 
 | // SPDX-License-Identifier: MIT | 
 |  | 
 | #pragma once | 
 |  | 
 | #include <cdefs.h> | 
 | #include <compartment-macros.h> | 
 | #include <riscvreg.h> | 
 | #include <stddef.h> | 
 | #include <stdint.h> | 
 |  | 
 | namespace Flute | 
 | { | 
 | 	template<typename WordT, size_t TCMBaseAddr> | 
 | 	class HardwareRevoker | 
 | 	{ | 
 | 		private: | 
 | 		// layout of the shadow space control registers | 
 | 		struct ShadowCtrl | 
 | 		{ | 
 | 			uint32_t base; | 
 | 			uint32_t pad0; | 
 | 			uint32_t top; | 
 | 			uint32_t pad1; | 
 | 			uint32_t epoch; | 
 | 			uint32_t pad2; | 
 | 			uint32_t go; | 
 | 			uint32_t pad4; | 
 | 		}; | 
 | 		static_assert(offsetof(ShadowCtrl, epoch) == 16); | 
 | 		static_assert(offsetof(ShadowCtrl, go) == 24); | 
 |  | 
 | 		volatile ShadowCtrl *shadowCtrl; | 
 |  | 
 | 		public: | 
 | 		/** | 
 | 		 * Currently the only hardware revoker implementation is async which | 
 | 		 * sweeps memory in the background. | 
 | 		 */ | 
 | 		static constexpr bool IsAsynchronous = true; | 
 |  | 
 | 		/** | 
 | 		 * Initialise a revoker instance. | 
 | 		 */ | 
 | 		void init() | 
 | 		{ | 
 | 			/** | 
 | 			 * These two symbols mark the region that needs revocation.  We | 
 | 			 * revoke capabilities everywhere from the start of compartment | 
 | 			 * globals to the end of the heap. | 
 | 			 */ | 
 | 			extern char __compart_cgps, __export_mem_heap_end; | 
 |  | 
 | 			auto base        = LA_ABS(__compart_cgps); | 
 | 			auto top         = LA_ABS(__export_mem_heap_end); | 
 | 			shadowCtrl       = MMIO_CAPABILITY(ShadowCtrl, shadowctrl); | 
 | 			shadowCtrl->base = base; | 
 | 			shadowCtrl->top  = top; | 
 | 			// Clang tidy is checking headers as stand-alone compilation units | 
 | 			// and so doesn't know what Debug is defined to. | 
 | #ifndef CLANG_TIDY | 
 | 			Debug::Invariant(base < top, | 
 | 			                 "Memory map has unexpected layout, base {} is " | 
 | 			                 "expected to be below top {}", | 
 | 			                 base, | 
 | 			                 top); | 
 | #endif | 
 | 		} | 
 |  | 
 | 		/** | 
 | 		 * Returns the revocation epoch.  This is the number of revocations | 
 | 		 * that have started. | 
 | 		 */ | 
 | 		uint32_t system_epoch_get() | 
 | 		{ | 
 | 			asm volatile("" ::: "memory"); | 
 | 			return shadowCtrl->epoch; | 
 | 		} | 
 |  | 
 | 		/** | 
 | 		 * Queries whether the specified revocation epoch has finished. | 
 | 		 */ | 
 | 		template<bool AllowPartial = false> | 
 | 		uint32_t has_revocation_finished_for_epoch(uint32_t epoch) | 
 | 		{ | 
 | 			asm volatile("" ::: "memory"); | 
 | 			if (AllowPartial) | 
 | 			{ | 
 | 				return shadowCtrl->epoch > epoch; | 
 | 			} | 
 | 			return shadowCtrl->epoch - epoch >= (2 + (epoch & 1)); | 
 | 		} | 
 |  | 
 | 		// Start a revocation. | 
 | 		void system_bg_revoker_kick() | 
 | 		{ | 
 | 			asm volatile("" ::: "memory"); | 
 | 			shadowCtrl->go = 1; | 
 | 			asm volatile("" ::: "memory"); | 
 | 		} | 
 | 	}; | 
 | } // namespace Flute | 
 |  | 
 | template<typename WordT, size_t TCMBaseAddr> | 
 | using HardwareRevoker = Flute::HardwareRevoker<WordT, TCMBaseAddr>; |