Skip to content

Commit

Permalink
Kernel: Add a new abstraction for I/O mapped registers
Browse files Browse the repository at this point in the history
  • Loading branch information
Hendiadyoin1 committed Dec 1, 2024
1 parent c385e8b commit 04095ca
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
4 changes: 4 additions & 0 deletions AK/Concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ concept Enum = IsEnum<T>;
template<typename T, typename U>
concept SameAs = IsSame<T, U>;

template<typename T, typename U>
concept SameAsIgnoringCVReference = IsSameIgnoringCV<RemoveReference<T>, RemoveReference<U>>;

template<class From, class To>
concept ConvertibleTo = IsConvertible<From, To>;

Expand Down Expand Up @@ -182,6 +185,7 @@ using AK::Concepts::IteratorPairWith;
using AK::Concepts::OneOf;
using AK::Concepts::OneOfIgnoringCV;
using AK::Concepts::SameAs;
using AK::Concepts::SameAsIgnoringCVReference;
using AK::Concepts::Signed;
using AK::Concepts::SpecializationOf;
using AK::Concepts::Unsigned;
Expand Down
115 changes: 115 additions & 0 deletions Kernel/Library/IORegister.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2024, Leon Albrecht <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/Concepts.h>
#include <AK/Types.h>
#include <Kernel/Library/IOWindow.h>

namespace Kernel {

enum IOSize {
Byte,
Word,
DWord,
};

template<typename T>
consteval IOSize io_size_for()
{
if constexpr (sizeof(T) == 1)
return IOSize::Byte;
else if constexpr (sizeof(T) == 2)
return IOSize::Word;
else if constexpr (sizeof(T) == 4)
return IOSize::DWord;
else
static_assert(false, "Invalid IO size");
}

template<Enum E, E L, typename T>
struct IOReg {
static constexpr E Location = L;
static constexpr IOSize Size = io_size_for<T>();
using Type = T;
};

template<typename T, typename E>
concept RegisterEntry = IsEnum<E> && requires {
typename T::Type;
{ T::Location } -> SameAsIgnoringCVReference<E>;
{ T::Size } -> SameAsIgnoringCVReference<IOSize>;
};

template<Enum E, RegisterEntry<E>... Entries>
class IORegister {
template<E Reg, RegisterEntry<E> First, RegisterEntry<E>... Rest>
static consteval auto find_entry(First, Rest...)
{
if constexpr (First::Location == Reg)
return First();
else if constexpr (sizeof...(Rest) > 0)
return find_entry<Reg>(Rest()...);
else
static_assert(false, "Register not found");
}

public:
explicit IORegister(NonnullOwnPtr<IOWindow> window)
: m_window(move(window))
{
}

template<E Reg, typename Entry = decltype(find_entry<Reg>(declval<Entries>()...))>
requires(Entry::Size == IOSize::Byte)
auto read()
{
return bit_cast<typename Entry::Type>(m_window->read8(static_cast<u64>(Reg)));
}

template<E Reg, typename Entry = decltype(find_entry<Reg>(declval<Entries>()...))>
requires(Entry::Size == IOSize::Word)
auto read()
{
return bit_cast<typename Entry::Type>(m_window->read16(static_cast<u64>(Reg)));
}

template<E Reg, typename Entry = decltype(find_entry<Reg>(declval<Entries>()...))>
requires(Entry::Size == IOSize::DWord)
auto read()
{
return bit_cast<typename Entry::Type>(m_window->read32(static_cast<u64>(Reg)));
}

template<E Reg, typename Entry = decltype(find_entry<Reg>(declval<Entries>()...))>
requires(Entry::Size == IOSize::Byte)
void write(Entry::Type value)
{
m_window->write8(static_cast<u64>(Reg), bit_cast<u8>(value));
}

template<E Reg, typename Entry = decltype(find_entry<Reg>(declval<Entries>()...))>
requires(Entry::Size == IOSize::Word)
void write(Entry::Type value)
{
m_window->write16(static_cast<u64>(Reg), bit_cast<u16>(value));
}

template<E Reg, typename Entry = decltype(find_entry<Reg>(declval<Entries>()...))>
requires(Entry::Size == IOSize::DWord)
void write(Entry::Type value)
{
m_window->write32(static_cast<u64>(Reg), bit_cast<u32>(value));
}

IOWindow& window() { return *m_window; }

private:
NonnullOwnPtr<IOWindow> m_window;
};

}

0 comments on commit 04095ca

Please sign in to comment.