NOVA-microhypervisor/inc/capability.hpp

217 lines
6.5 KiB
C++

/*
* Object Capability
*
* Copyright (C) 2009-2011 Udo Steinberg <udo@hypervisor.org>
* Economic rights: Technische Universitaet Dresden (Germany)
*
* Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation.
* Copyright (C) 2019-2025 Udo Steinberg, BlueRock Security, Inc.
*
* This file is part of the NOVA microhypervisor.
*
* NOVA is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#pragma once
#include "kobject.hpp"
#include "std.hpp"
class Capability final
{
friend class Space_obj;
private:
uintptr_t const val;
ALWAYS_INLINE
inline bool validate (Kobject::Type t, unsigned p) const
{
return obj() && obj()->type == t && (prm() & p) == p;
}
ALWAYS_INLINE
inline bool validate (Kobject::Type t, Kobject::Subtype s, unsigned p) const
{
return obj() && obj()->type == t && obj()->subtype == s && (prm() & p) == p;
}
public:
// Mask of low bits that can store permissions
static constexpr uintptr_t pmask { Kobject::alignment - 1 };
// Space Capability Permissions
enum class Perm_sp : unsigned
{
GRANT = BIT (0),
TAKE = BIT (1),
ASSIGN = BIT (2),
DEFINED_OBJ = TAKE | GRANT,
DEFINED_HST = TAKE | GRANT,
DEFINED_GST = ASSIGN | GRANT,
DEFINED_DMA = ASSIGN | GRANT,
DEFINED_PIO = ASSIGN | TAKE | GRANT,
DEFINED_MSR = ASSIGN | TAKE | GRANT,
};
// PD Object Capability Permissions
enum class Perm_pd : unsigned
{
PD = BIT (0),
EC = BIT (1),
SC = BIT (2),
PT = BIT (3),
SM = BIT (4),
DEFINED = SM | PT | SC | EC | PD,
};
// EC Object Capability Permissions
enum class Perm_ec : unsigned
{
CTRL = BIT (0),
BIND_PT = BIT (2),
BIND_SC = BIT (3),
DEFINED = BIND_SC | BIND_PT | CTRL,
};
// SC Object Capability Permissions
enum class Perm_sc : unsigned
{
CTRL = BIT (0),
DEFINED = CTRL,
};
// PT Object Capability Permissions
enum class Perm_pt : unsigned
{
CTRL = BIT (0),
CALL = BIT (1),
EVENT = BIT (2),
DEFINED = EVENT | CALL | CTRL,
};
// SM Object Capability Permissions
enum class Perm_sm : unsigned
{
CTRL_UP = BIT (0),
CTRL_DN = BIT (1),
DEFINED = CTRL_DN | CTRL_UP,
};
// Raw Capability Constructor
inline explicit Capability (uintptr_t v = 0) : val { v } {}
// Object Capability Constructor
inline Capability (Kobject *o, unsigned p) : val { p ? reinterpret_cast<uintptr_t>(o) | (p & pmask) : 0 } {}
ALWAYS_INLINE
inline Kobject *obj() const { return reinterpret_cast<Kobject *>(val & ~pmask); }
ALWAYS_INLINE
inline unsigned prm() const { return val & pmask; }
ALWAYS_INLINE
inline auto validate (Perm_sp p, Kobject::Subtype s) const { return validate (Kobject::Type::PD, s, std::to_underlying (p)); }
ALWAYS_INLINE
inline auto validate (Perm_pd p) const { return validate (Kobject::Type::PD, Kobject::Subtype::PD, std::to_underlying (p)); }
ALWAYS_INLINE
inline auto validate (Perm_ec p) const { return validate (Kobject::Type::EC, std::to_underlying (p)); }
ALWAYS_INLINE
inline auto validate (Perm_sc p) const { return validate (Kobject::Type::SC, std::to_underlying (p)); }
ALWAYS_INLINE
inline auto validate (Perm_pt p) const { return validate (Kobject::Type::PT, std::to_underlying (p)); }
ALWAYS_INLINE
inline auto validate (Perm_sm p) const { return validate (Kobject::Type::SM, std::to_underlying (p)); }
ALWAYS_INLINE
inline auto validate (Perm_sm p, Kobject::Subtype s) const { return validate (Kobject::Type::SM, s, std::to_underlying (p)); }
ALWAYS_INLINE
static inline bool validate_take_grant (Capability const &cst, Capability const &cdt, Kobject::Subtype &st, Kobject::Subtype &dt)
{
// Check capability permissions: cst requires TAKE, cdt requires GRANT
if (!(cst.prm() & std::to_underlying (Perm_sp::TAKE)) || !(cdt.prm() & std::to_underlying (Perm_sp::GRANT)))
return false;
// Non-zero permissions imply both capabilities are not null capabilities
auto const s { cst.obj() };
auto const d { cdt.obj() };
st = s->subtype;
dt = d->subtype;
// Check capability types: both capabilities must be PD subtypes
return s->type == Kobject::Type::PD && d->type == Kobject::Type::PD;
}
/*
* Publish first capability for an object
*/
void publish() const
{
auto const o { obj() };
// Must not be a null capability
assert (o);
// Acquire reference
o->ref_inc();
}
/*
* Retract first capability for an object
*/
void retract() const
{
auto const o { obj() };
// Must not be a null capability
assert (o);
// Release reference
o->ref_dec();
}
/*
* Attempt to acquire a reference for an object
*/
bool acquire() const
{
auto const o { obj() };
// Nothing to do for a null capability
if (!o) [[unlikely]]
return false;
// Try to acquire reference
return o->try_inc();
}
/*
* Release a reference for an object
*/
void release() const
{
auto const o { obj() };
// Nothing to do for a null capability
if (!o) [[unlikely]]
return;
// Release reference
o->ref_dec();
}
};