blob: 759db15ee71386551e684501640240bc2154bb71 [file] [log] [blame]
// 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>;