blob: c10139fe48aa16bfcef36759d656d3fde13f4ae5 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
#include <bitmap/raw-bitmap.h>
#include <bitmap/storage.h>
#include <hypervisor/state_invalidator.h>
#include <kernel/auto_lock.h>
#include <kernel/event.h>
namespace hypervisor {
// |N| is the maximum number of interrupts to be tracked.
template <uint32_t N>
class InterruptTracker {
public:
zx_status_t Init() {
event_init(&event_, false, EVENT_FLAG_AUTOUNSIGNAL);
return bitmap_.Reset(N);
}
// Returns whether there are pending interrupts.
bool Pending() {
AutoSpinLock lock(&lock_);
return !bitmap_.Scan(0, N, false);
}
bool TryPop(uint32_t vector) {
AutoSpinLock lock(&lock_);
bool has_vector = bitmap_.GetOne(reverse(vector));
if (has_vector) {
bitmap_.ClearOne(vector);
}
return has_vector;
}
// Pops the highest priority interrupt.
zx_status_t Pop(uint32_t* vector) {
size_t value;
{
AutoSpinLock lock(&lock_);
if (bitmap_.Scan(0, N, false, &value)) {
return ZX_ERR_NOT_FOUND;
}
bitmap_.ClearOne(value);
}
*vector = reverse(static_cast<uint32_t>(value));
return ZX_OK;
}
// Tracks the given interrupt.
zx_status_t Track(uint32_t vector) {
if (vector >= N) {
return ZX_ERR_OUT_OF_RANGE;
}
AutoSpinLock lock(&lock_);
return bitmap_.SetOne(reverse(vector));
}
// Tracks the given interrupt, and signals any waiters.
zx_status_t Interrupt(uint32_t vector, bool* signaled) {
zx_status_t status = Track(vector);
if (status != ZX_OK) {
return status;
}
int threads_unblocked = event_signal(&event_, true);
if (signaled != nullptr) {
*signaled = threads_unblocked > 0;
}
return ZX_OK;
}
// Waits for an interrupt.
zx_status_t Wait(StateInvalidator* invalidator) {
if (invalidator != nullptr) {
invalidator->Invalidate();
}
do {
zx_status_t status = event_wait_deadline(&event_, ZX_TIME_INFINITE, true);
if (status != ZX_OK) {
return ZX_ERR_CANCELED;
}
} while (!Pending());
return ZX_OK;
}
private:
event_t event_;
SpinLock lock_;
bitmap::RawBitmapGeneric<bitmap::FixedStorage<N>> bitmap_;
// We reverse the value, as RawBitmapGeneric::Scan will return the
// lowest priority interrupt, but we need the highest priority.
static uint32_t reverse(uint32_t vector) {
return N - vector - 1;
}
};
} // namespace hypervisor