Compare commits
1 Commits
main
...
3bdcd8f1fb
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bdcd8f1fb |
13
.clangd
13
.clangd
@@ -1,13 +0,0 @@
|
|||||||
Diagnostics:
|
|
||||||
Suppress: target_unsupported_type
|
|
||||||
|
|
||||||
CompileFlags:
|
|
||||||
Remove: [
|
|
||||||
-fstrict-volatile-bitfields,
|
|
||||||
-fno-tree-loop-distribute-patterns
|
|
||||||
]
|
|
||||||
Add: [
|
|
||||||
-D__banan_os__,
|
|
||||||
-D__arch__=x86_64,
|
|
||||||
-D__x86_64__
|
|
||||||
]
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,4 +3,3 @@
|
|||||||
build/
|
build/
|
||||||
base/
|
base/
|
||||||
script/fakeroot-context
|
script/fakeroot-context
|
||||||
tools/update-image-perms
|
|
||||||
|
|||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -2,9 +2,5 @@
|
|||||||
"cmake.configureOnOpen": false,
|
"cmake.configureOnOpen": false,
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.insertSpaces": false,
|
"editor.insertSpaces": false,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false
|
||||||
"clangd.arguments": [
|
|
||||||
"--compile-commands-dir=${workspaceFolder}/build",
|
|
||||||
"-header-insertion=never"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,5 @@ banan_link_library(ban libc)
|
|||||||
|
|
||||||
set_target_properties(ban PROPERTIES OUTPUT_NAME libban)
|
set_target_properties(ban PROPERTIES OUTPUT_NAME libban)
|
||||||
|
|
||||||
# set SONAME as cmake doesn't set it for some reason??
|
|
||||||
set_target_properties(ban PROPERTIES LINK_FLAGS "-Wl,-soname,libban.so")
|
|
||||||
|
|
||||||
banan_install_headers(ban)
|
banan_install_headers(ban)
|
||||||
install(TARGETS ban OPTIONAL)
|
install(TARGETS ban OPTIONAL)
|
||||||
|
|||||||
@@ -18,78 +18,78 @@ namespace BAN
|
|||||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr Array() = default;
|
Array() = default;
|
||||||
constexpr Array(const T&);
|
Array(const T&);
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
iterator end() { return iterator(m_data + size()); }
|
iterator end() { return iterator(m_data + size()); }
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + size()); }
|
const_iterator end() const { return const_iterator(m_data + size()); }
|
||||||
|
|
||||||
constexpr const T& operator[](size_type) const;
|
const T& operator[](size_type) const;
|
||||||
constexpr T& operator[](size_type);
|
T& operator[](size_type);
|
||||||
|
|
||||||
constexpr const T& back() const;
|
const T& back() const;
|
||||||
constexpr T& back();
|
T& back();
|
||||||
constexpr const T& front() const;
|
const T& front() const;
|
||||||
constexpr T& front();
|
T& front();
|
||||||
|
|
||||||
Span<T> span() { return Span(m_data, size()); }
|
Span<T> span() { return Span(m_data, size()); }
|
||||||
Span<const T> span() const { return Span(m_data, size()); }
|
const Span<T> span() const { return Span(m_data, size()); }
|
||||||
|
|
||||||
constexpr size_type size() const;
|
constexpr size_type size() const;
|
||||||
|
|
||||||
constexpr const T* data() const { return m_data; }
|
const T* data() const { return m_data; }
|
||||||
constexpr T* data() { return m_data; }
|
T* data() { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_data[S] {};
|
T m_data[S] {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
constexpr Array<T, S>::Array(const T& value)
|
Array<T, S>::Array(const T& value)
|
||||||
{
|
{
|
||||||
for (size_type i = 0; i < S; i++)
|
for (size_type i = 0; i < S; i++)
|
||||||
m_data[i] = value;
|
m_data[i] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
constexpr const T& Array<T, S>::operator[](size_type index) const
|
const T& Array<T, S>::operator[](size_type index) const
|
||||||
{
|
{
|
||||||
ASSERT(index < S);
|
ASSERT(index < S);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
constexpr T& Array<T, S>::operator[](size_type index)
|
T& Array<T, S>::operator[](size_type index)
|
||||||
{
|
{
|
||||||
ASSERT(index < S);
|
ASSERT(index < S);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
constexpr const T& Array<T, S>::back() const
|
const T& Array<T, S>::back() const
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[S - 1];
|
return m_data[S - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
constexpr T& Array<T, S>::back()
|
T& Array<T, S>::back()
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[S - 1];
|
return m_data[S - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
constexpr const T& Array<T, S>::front() const
|
const T& Array<T, S>::front() const
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[0];
|
return m_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
constexpr T& Array<T, S>::front()
|
T& Array<T, S>::front()
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[0];
|
return m_data[0];
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Traits.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -15,36 +13,8 @@ namespace BAN
|
|||||||
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> concept atomic_c = is_integral_v<T> || is_pointer_v<T>;
|
template<typename T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
||||||
template<typename T> concept atomic_lockfree_c = (is_integral_v<T> || is_pointer_v<T>) && __atomic_always_lock_free(sizeof(T), 0);
|
requires requires { __atomic_always_lock_free(sizeof(T), 0); }
|
||||||
|
|
||||||
template<atomic_lockfree_c T, atomic_c U>
|
|
||||||
inline void atomic_store(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { __atomic_store_n(&obj, value, mem_order); }
|
|
||||||
template<atomic_lockfree_c T>
|
|
||||||
inline T atomic_load(T& obj, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_load_n(&obj, mem_order); }
|
|
||||||
|
|
||||||
template<atomic_lockfree_c T, atomic_c U>
|
|
||||||
inline T atomic_exchange(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_exchange_n(&obj, value, mem_order); }
|
|
||||||
template<atomic_lockfree_c T, atomic_lockfree_c U, atomic_c V>
|
|
||||||
inline bool atomic_compare_exchange(T& obj, U& expected, V value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_compare_exchange_n(&obj, &expected, value, false, mem_order, mem_order); }
|
|
||||||
|
|
||||||
#define DECL_ATOMIC_INLINE template<atomic_lockfree_c T, atomic_c U> inline
|
|
||||||
DECL_ATOMIC_INLINE T atomic_add_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_add_fetch (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_sub_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_sub_fetch (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_and_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_and_fetch (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_xor_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_xor_fetch (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_or_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_or_fetch (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_nand_fetch(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_nand_fetch(&obj, value, mem_order); }
|
|
||||||
|
|
||||||
DECL_ATOMIC_INLINE T atomic_fetch_add (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_add (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_fetch_sub (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_sub (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_fetch_and (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_and (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_fetch_xor (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_xor (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_fetch_or (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_or (&obj, value, mem_order); }
|
|
||||||
DECL_ATOMIC_INLINE T atomic_fetch_nand(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_nand(&obj, value, mem_order); }
|
|
||||||
#undef DECL_ATOMIC_INLINE
|
|
||||||
|
|
||||||
template<atomic_lockfree_c T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
|
||||||
class Atomic
|
class Atomic
|
||||||
{
|
{
|
||||||
Atomic(const Atomic&) = delete;
|
Atomic(const Atomic&) = delete;
|
||||||
@@ -56,41 +26,41 @@ namespace BAN
|
|||||||
constexpr Atomic() : m_value(0) {}
|
constexpr Atomic() : m_value(0) {}
|
||||||
constexpr Atomic(T val) : m_value(val) {}
|
constexpr Atomic(T val) : m_value(val) {}
|
||||||
|
|
||||||
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return atomic_load(m_value, mem_order); }
|
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return __atomic_load_n(&m_value, mem_order); }
|
||||||
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { atomic_store(m_value, val, mem_order); }
|
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { __atomic_store_n(&m_value, val, mem_order); }
|
||||||
|
|
||||||
inline T operator=(T val) volatile { store(val); return val; }
|
inline T operator=(T val) volatile { store(val); return val; }
|
||||||
|
|
||||||
inline operator T() const volatile { return load(); }
|
inline operator T() const volatile { return load(); }
|
||||||
|
|
||||||
inline T operator+=(T val) volatile { return atomic_add_fetch(m_value, val, MEM_ORDER); }
|
inline T operator+=(T val) volatile { return __atomic_add_fetch(&m_value, val, MEM_ORDER); }
|
||||||
inline T operator-=(T val) volatile { return atomic_sub_fetch(m_value, val, MEM_ORDER); }
|
inline T operator-=(T val) volatile { return __atomic_sub_fetch(&m_value, val, MEM_ORDER); }
|
||||||
inline T operator&=(T val) volatile { return atomic_and_fetch(m_value, val, MEM_ORDER); }
|
inline T operator&=(T val) volatile { return __atomic_and_fetch(&m_value, val, MEM_ORDER); }
|
||||||
inline T operator^=(T val) volatile { return atomic_xor_fetch(m_value, val, MEM_ORDER); }
|
inline T operator^=(T val) volatile { return __atomic_xor_fetch(&m_value, val, MEM_ORDER); }
|
||||||
inline T operator|=(T val) volatile { return atomic_or_fetch(m_value, val, MEM_ORDER); }
|
inline T operator|=(T val) volatile { return __atomic_or_fetch(&m_value, val, MEM_ORDER); }
|
||||||
|
|
||||||
inline T operator--() volatile { return atomic_sub_fetch(m_value, 1, MEM_ORDER); }
|
inline T operator--() volatile { return __atomic_sub_fetch(&m_value, 1, MEM_ORDER); }
|
||||||
inline T operator++() volatile { return atomic_add_fetch(m_value, 1, MEM_ORDER); }
|
inline T operator++() volatile { return __atomic_add_fetch(&m_value, 1, MEM_ORDER); }
|
||||||
|
|
||||||
inline T operator--(int) volatile { return atomic_fetch_sub(m_value, 1, MEM_ORDER); }
|
inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); }
|
||||||
inline T operator++(int) volatile { return atomic_fetch_add(m_value, 1, MEM_ORDER); }
|
inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); }
|
||||||
|
|
||||||
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_compare_exchange(m_value, expected, desired, mem_order); }
|
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); }
|
||||||
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_exchange(m_value, desired, mem_order); };
|
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_exchange_n(&m_value, desired, mem_order); };
|
||||||
|
|
||||||
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_add_fetch (m_value, val, mem_order); }
|
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_add_fetch (&m_value, val, mem_order); }
|
||||||
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_sub_fetch (m_value, val, mem_order); }
|
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_sub_fetch (&m_value, val, mem_order); }
|
||||||
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_and_fetch (m_value, val, mem_order); }
|
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_and_fetch (&m_value, val, mem_order); }
|
||||||
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_xor_fetch (m_value, val, mem_order); }
|
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_xor_fetch (&m_value, val, mem_order); }
|
||||||
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_or_fetch (m_value, val, mem_order); }
|
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_or_fetch (&m_value, val, mem_order); }
|
||||||
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_nand_fetch(m_value, val, mem_order); }
|
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nand_fetch(&m_value, val, mem_order); }
|
||||||
|
|
||||||
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_add (m_value, val, mem_order); }
|
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_add (&m_value, val, mem_order); }
|
||||||
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_sub (m_value, val, mem_order); }
|
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_sub (&m_value, val, mem_order); }
|
||||||
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_and (m_value, val, mem_order); }
|
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_and (&m_value, val, mem_order); }
|
||||||
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_xor (m_value, val, mem_order); }
|
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_xor (&m_value, val, mem_order); }
|
||||||
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_or (m_value, val, mem_order); }
|
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch__or (&m_value, val, mem_order); }
|
||||||
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_nand(m_value, val, mem_order); }
|
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nfetch_and(&m_value, val, mem_order); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_value;
|
T m_value;
|
||||||
|
|||||||
@@ -21,56 +21,75 @@ namespace BAN
|
|||||||
, m_size(size)
|
, m_size(size)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
template<bool SRC_CONST>
|
ByteSpanGeneral(ByteSpanGeneral& other)
|
||||||
ByteSpanGeneral(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{ }
|
{ }
|
||||||
template<bool SRC_CONST>
|
ByteSpanGeneral(ByteSpanGeneral&& other)
|
||||||
ByteSpanGeneral(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{
|
{
|
||||||
other.clear();
|
other.m_data = nullptr;
|
||||||
|
other.m_size = 0;
|
||||||
}
|
}
|
||||||
|
template<bool C2>
|
||||||
template<typename T>
|
ByteSpanGeneral(const ByteSpanGeneral<C2>& other) requires(CONST)
|
||||||
ByteSpanGeneral(const Span<T>& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{ }
|
{ }
|
||||||
template<typename T>
|
template<bool C2>
|
||||||
ByteSpanGeneral(Span<T>&& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
ByteSpanGeneral(ByteSpanGeneral<C2>&& other) requires(CONST)
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{
|
{
|
||||||
other.clear();
|
other.m_data = nullptr;
|
||||||
|
other.m_size = 0;
|
||||||
}
|
}
|
||||||
|
ByteSpanGeneral(Span<uint8_t> other)
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{ }
|
||||||
|
ByteSpanGeneral(const Span<const uint8_t>& other) requires(CONST)
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{ }
|
||||||
|
|
||||||
template<bool SRC_CONST>
|
ByteSpanGeneral& operator=(ByteSpanGeneral other)
|
||||||
ByteSpanGeneral& operator=(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
|
||||||
{
|
{
|
||||||
m_data = other.data();
|
m_data = other.data();
|
||||||
m_size = other.size();
|
m_size = other.size();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
template<bool SRC_CONST>
|
template<bool C2>
|
||||||
ByteSpanGeneral& operator=(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
ByteSpanGeneral& operator=(const ByteSpanGeneral<C2>& other) requires(CONST)
|
||||||
|
{
|
||||||
|
m_data = other.data();
|
||||||
|
m_size = other.size();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ByteSpanGeneral& operator=(Span<uint8_t> other)
|
||||||
|
{
|
||||||
|
m_data = other.data();
|
||||||
|
m_size = other.size();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ByteSpanGeneral& operator=(const Span<const uint8_t>& other) requires(CONST)
|
||||||
{
|
{
|
||||||
m_data = other.data();
|
m_data = other.data();
|
||||||
m_size = other.size();
|
m_size = other.size();
|
||||||
other.clear();
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
static ByteSpanGeneral from(S& value) requires(CONST || !is_const_v<S>)
|
requires(CONST || !is_const_v<S>)
|
||||||
|
static ByteSpanGeneral from(S& value)
|
||||||
{
|
{
|
||||||
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
S& as() const requires(!CONST || is_const_v<S>)
|
requires(!CONST && !is_const_v<S>)
|
||||||
|
S& as()
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
ASSERT(m_size >= sizeof(S));
|
ASSERT(m_size >= sizeof(S));
|
||||||
@@ -78,13 +97,30 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
Span<S> as_span() const requires(!CONST || is_const_v<S>)
|
requires(is_const_v<S>)
|
||||||
|
S& as() const
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
ASSERT(m_size >= sizeof(S));
|
||||||
|
return *reinterpret_cast<S*>(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
requires(!CONST && !is_const_v<S>)
|
||||||
|
Span<S> as_span()
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1)) const
|
template<typename S>
|
||||||
|
const Span<S> as_span() const
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1))
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
ASSERT(m_size >= offset);
|
ASSERT(m_size >= offset);
|
||||||
@@ -94,23 +130,22 @@ namespace BAN
|
|||||||
return ByteSpanGeneral(m_data + offset, length);
|
return ByteSpanGeneral(m_data + offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type& operator[](size_type offset) const
|
value_type& operator[](size_type offset)
|
||||||
|
{
|
||||||
|
ASSERT(offset < m_size);
|
||||||
|
return m_data[offset];
|
||||||
|
}
|
||||||
|
const value_type& operator[](size_type offset) const
|
||||||
{
|
{
|
||||||
ASSERT(offset < m_size);
|
ASSERT(offset < m_size);
|
||||||
return m_data[offset];
|
return m_data[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type* data() const { return m_data; }
|
value_type* data() { return m_data; }
|
||||||
|
const value_type* data() const { return m_data; }
|
||||||
|
|
||||||
bool empty() const { return m_size == 0; }
|
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_data = nullptr;
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type* m_data { nullptr };
|
value_type* m_data { nullptr };
|
||||||
size_type m_size { 0 };
|
size_type m_size { 0 };
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace BAN
|
|||||||
void push(const T&);
|
void push(const T&);
|
||||||
void push(T&&);
|
void push(T&&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void emplace(Args&&... args) requires is_constructible_v<T, Args...>;
|
void emplace(Args&&... args);
|
||||||
|
|
||||||
void pop();
|
void pop();
|
||||||
|
|
||||||
@@ -34,11 +34,6 @@ namespace BAN
|
|||||||
const T& back() const;
|
const T& back() const;
|
||||||
T& back();
|
T& back();
|
||||||
|
|
||||||
const T& operator[](size_t index) const;
|
|
||||||
T& operator[](size_t index);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
bool empty() const { return size() == 0; }
|
bool empty() const { return size() == 0; }
|
||||||
bool full() const { return size() == capacity(); }
|
bool full() const { return size() == capacity(); }
|
||||||
@@ -58,7 +53,8 @@ namespace BAN
|
|||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
CircularQueue<T, S>::~CircularQueue()
|
CircularQueue<T, S>::~CircularQueue()
|
||||||
{
|
{
|
||||||
clear();
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
element_at((m_first + i) % capacity())->~T();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
@@ -75,7 +71,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void CircularQueue<T, S>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
void CircularQueue<T, S>::emplace(Args&&... args)
|
||||||
{
|
{
|
||||||
ASSERT(!full());
|
ASSERT(!full());
|
||||||
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
||||||
@@ -119,28 +115,6 @@ namespace BAN
|
|||||||
return *element_at((m_first + m_size - 1) % capacity());
|
return *element_at((m_first + m_size - 1) % capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
|
||||||
const T& CircularQueue<T, S>::operator[](size_t index) const
|
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
return *element_at((m_first + index) % capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, size_t S>
|
|
||||||
T& CircularQueue<T, S>::operator[](size_t index)
|
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
return *element_at((m_first + index) % capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, size_t S>
|
|
||||||
void CircularQueue<T, S>::clear()
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
element_at((m_first + i) % capacity())->~T();
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T* CircularQueue<T, S>::element_at(size_type index) const
|
const T* CircularQueue<T, S>::element_at(size_type index) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,35 +9,29 @@
|
|||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define __debug_putchar [](int c) { putc_unlocked(c, stddbg); }
|
#define __debug_putchar [](int c) { putc(c, stddbg); }
|
||||||
|
|
||||||
#define dprintln(...) \
|
#define dprintln(...) \
|
||||||
do { \
|
do { \
|
||||||
flockfile(stddbg); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar,"\n"); \
|
BAN::Formatter::print(__debug_putchar,"\r\n"); \
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
funlockfile(stddbg); \
|
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define dwarnln(...) \
|
#define dwarnln(...) \
|
||||||
do { \
|
do { \
|
||||||
flockfile(stddbg); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
funlockfile(stddbg); \
|
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#define derrorln(...) \
|
#define derrorln(...) \
|
||||||
do { \
|
do { \
|
||||||
flockfile(stddbg); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
funlockfile(stddbg); \
|
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#define dprintln_if(cond, ...) \
|
#define dprintln_if(cond, ...) \
|
||||||
|
|||||||
@@ -70,19 +70,15 @@ namespace BAN
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
struct LittleEndian
|
struct LittleEndian
|
||||||
{
|
{
|
||||||
constexpr LittleEndian()
|
|
||||||
: raw(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
constexpr LittleEndian(T value)
|
constexpr LittleEndian(T value)
|
||||||
: raw(host_to_little_endian(value))
|
{
|
||||||
{ }
|
raw = host_to_little_endian(value);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_little_endian(raw);
|
return host_to_little_endian(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T raw;
|
T raw;
|
||||||
};
|
};
|
||||||
@@ -90,19 +86,15 @@ namespace BAN
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
struct BigEndian
|
struct BigEndian
|
||||||
{
|
{
|
||||||
constexpr BigEndian()
|
|
||||||
: raw(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
constexpr BigEndian(T value)
|
constexpr BigEndian(T value)
|
||||||
: raw(host_to_big_endian(value))
|
{
|
||||||
{ }
|
raw = host_to_big_endian(value);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_big_endian(raw);
|
return host_to_big_endian(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T raw;
|
T raw;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
|
||||||
#include <BAN/Variant.h>
|
#include <BAN/Variant.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -10,16 +9,16 @@
|
|||||||
#ifdef __is_kernel
|
#ifdef __is_kernel
|
||||||
#include <kernel/Panic.h>
|
#include <kernel/Panic.h>
|
||||||
#include <kernel/Errors.h>
|
#include <kernel/Errors.h>
|
||||||
#define MUST(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
#define MUST(expr) ({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
||||||
#define MUST_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
#define MUST_REF(expr) *({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
||||||
#else
|
#else
|
||||||
#include <BAN/Debug.h>
|
#include <assert.h>
|
||||||
#define MUST(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) { derrorln("MUST(" #__VA_ARGS__ "): {}", e.error()); __builtin_trap(); } e.release_value(); })
|
#define MUST(expr) ({ auto&& e = expr; assert(!e.is_error()); e.release_value(); })
|
||||||
#define MUST_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) { derrorln("MUST(" #__VA_ARGS__ "): {}", e.error()); __builtin_trap(); } &e.release_value(); })
|
#define MUST_REF(expr) *({ auto&& e = expr; assert(!e.is_error()); &e.release_value(); })
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TRY(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) return e.release_error(); e.release_value(); })
|
#define TRY(expr) ({ auto&& e = expr; if (e.is_error()) return e.release_error(); e.release_value(); })
|
||||||
#define TRY_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) return e.release_error(); &e.release_value(); })
|
#define TRY_REF(expr) *({ auto&& e = expr; if (e.is_error()) return e.release_error(); &e.release_value(); })
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
@@ -37,14 +36,7 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
return Error((uint64_t)error | kernel_error_mask);
|
return Error((uint64_t)error | kernel_error_mask);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
template<size_t N>
|
|
||||||
consteval static Error from_literal(const char (&message)[N])
|
|
||||||
{
|
|
||||||
return Error(message);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Error from_errno(int error)
|
static Error from_errno(int error)
|
||||||
{
|
{
|
||||||
return Error(error);
|
return Error(error);
|
||||||
@@ -62,15 +54,12 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr uint64_t get_error_code() const { return m_error_code; }
|
uint64_t get_error_code() const { return m_error_code; }
|
||||||
const char* get_message() const
|
const char* get_message() const
|
||||||
{
|
{
|
||||||
#ifdef __is_kernel
|
#ifdef __is_kernel
|
||||||
if (m_error_code & kernel_error_mask)
|
if (m_error_code & kernel_error_mask)
|
||||||
return Kernel::error_string(kernel_error());
|
return Kernel::error_string(kernel_error());
|
||||||
#else
|
|
||||||
if (m_message)
|
|
||||||
return m_message;
|
|
||||||
#endif
|
#endif
|
||||||
if (auto* desc = strerrordesc_np(m_error_code))
|
if (auto* desc = strerrordesc_np(m_error_code))
|
||||||
return desc;
|
return desc;
|
||||||
@@ -78,27 +67,16 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr Error(uint64_t error)
|
Error(uint64_t error)
|
||||||
: m_error_code(error)
|
: m_error_code(error)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
#ifndef __is_kernel
|
uint64_t m_error_code;
|
||||||
constexpr Error(const char* message)
|
|
||||||
: m_message(message)
|
|
||||||
{}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint64_t m_error_code { 0 };
|
|
||||||
|
|
||||||
#ifndef __is_kernel
|
|
||||||
const char* m_message { nullptr };
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class [[nodiscard]] ErrorOr
|
class [[nodiscard]] ErrorOr
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(ErrorOr);
|
|
||||||
public:
|
public:
|
||||||
ErrorOr(const T& value)
|
ErrorOr(const T& value)
|
||||||
: m_data(value)
|
: m_data(value)
|
||||||
@@ -112,14 +90,6 @@ namespace BAN
|
|||||||
ErrorOr(Error&& error)
|
ErrorOr(Error&& error)
|
||||||
: m_data(move(error))
|
: m_data(move(error))
|
||||||
{}
|
{}
|
||||||
ErrorOr(ErrorOr&& other)
|
|
||||||
: m_data(move(other.m_data))
|
|
||||||
{}
|
|
||||||
ErrorOr& operator=(ErrorOr&& other)
|
|
||||||
{
|
|
||||||
m_data = move(other.m_data);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_error() const { return m_data.template has<Error>(); }
|
bool is_error() const { return m_data.template has<Error>(); }
|
||||||
const Error& error() const { return m_data.template get<Error>(); }
|
const Error& error() const { return m_data.template get<Error>(); }
|
||||||
|
|||||||
@@ -10,11 +10,14 @@ namespace BAN::Formatter
|
|||||||
|
|
||||||
struct ValueFormat;
|
struct ValueFormat;
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
inline void print(F putc, const char* format);
|
||||||
|
|
||||||
|
template<typename F, typename Arg, typename... Args>
|
||||||
|
inline void print(F putc, const char* format, Arg&& arg, Args&&... args);
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
template<typename F, typename... Args>
|
||||||
concept PrintableArguments = requires(F putc, Args&&... args, const ValueFormat& format)
|
inline void println(F putc, const char* format, Args&&... args);
|
||||||
{
|
|
||||||
(print_argument(putc, BAN::forward<Args>(args), format), ...);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
inline void print_argument(F putc, T value, const ValueFormat& format);
|
inline void print_argument(F putc, T value, const ValueFormat& format);
|
||||||
@@ -50,7 +53,7 @@ namespace BAN::Formatter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename Arg, typename... Args> requires PrintableArguments<F, Arg, Args...>
|
template<typename F, typename Arg, typename... Args>
|
||||||
inline void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
inline void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
||||||
{
|
{
|
||||||
while (*format && *format != '{')
|
while (*format && *format != '{')
|
||||||
@@ -204,14 +207,10 @@ namespace BAN::Formatter
|
|||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
inline void print_floating(F putc, T value, const ValueFormat& format)
|
inline void print_floating(F putc, T value, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
if (value < 0)
|
|
||||||
{
|
|
||||||
putc('-');
|
|
||||||
return print_floating(putc, -value, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t int_part = (int64_t)value;
|
int64_t int_part = (int64_t)value;
|
||||||
T frac_part = value - (T)int_part;
|
T frac_part = value - (T)int_part;
|
||||||
|
if (frac_part < 0)
|
||||||
|
frac_part = -frac_part;
|
||||||
|
|
||||||
print_integer(putc, int_part, format);
|
print_integer(putc, int_part, format);
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ namespace BAN
|
|||||||
new (m_storage) CallablePointer(function);
|
new (m_storage) CallablePointer(function);
|
||||||
}
|
}
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
Function(Ret(Own::*function)(Args...), Own& owner)
|
Function(Ret(Own::*function)(Args...), Own* owner)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableMember<Own>) <= m_size);
|
static_assert(sizeof(CallableMember<Own>) <= m_size);
|
||||||
new (m_storage) CallableMember<Own>(function, owner);
|
new (m_storage) CallableMember<Own>(function, owner);
|
||||||
}
|
}
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
Function(Ret(Own::*function)(Args...) const, const Own& owner)
|
Function(Ret(Own::*function)(Args...) const, const Own* owner)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableMemberConst<Own>) <= m_size);
|
static_assert(sizeof(CallableMemberConst<Own>) <= m_size);
|
||||||
new (m_storage) CallableMemberConst<Own>(function, owner);
|
new (m_storage) CallableMemberConst<Own>(function, owner);
|
||||||
@@ -91,36 +91,36 @@ namespace BAN
|
|||||||
template<typename Own>
|
template<typename Own>
|
||||||
struct CallableMember : public CallableBase
|
struct CallableMember : public CallableBase
|
||||||
{
|
{
|
||||||
CallableMember(Ret(Own::*function)(Args...), Own& owner)
|
CallableMember(Ret(Own::*function)(Args...), Own* owner)
|
||||||
: m_owner(owner)
|
: m_owner(owner)
|
||||||
, m_function(function)
|
, m_function(function)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Ret call(Args... args) const override
|
virtual Ret call(Args... args) const override
|
||||||
{
|
{
|
||||||
return (m_owner.*m_function)(forward<Args>(args)...);
|
return (m_owner->*m_function)(forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Own& m_owner;
|
Own* m_owner = nullptr;
|
||||||
Ret(Own::*m_function)(Args...) = nullptr;
|
Ret(Own::*m_function)(Args...) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
struct CallableMemberConst : public CallableBase
|
struct CallableMemberConst : public CallableBase
|
||||||
{
|
{
|
||||||
CallableMemberConst(Ret(Own::*function)(Args...) const, const Own& owner)
|
CallableMemberConst(Ret(Own::*function)(Args...) const, const Own* owner)
|
||||||
: m_owner(owner)
|
: m_owner(owner)
|
||||||
, m_function(function)
|
, m_function(function)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Ret call(Args... args) const override
|
virtual Ret call(Args... args) const override
|
||||||
{
|
{
|
||||||
return (m_owner.*m_function)(forward<Args>(args)...);
|
return (m_owner->*m_function)(forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Own& m_owner;
|
const Own* m_owner = nullptr;
|
||||||
Ret(Own::*m_function)(Args...) const = nullptr;
|
Ret(Own::*m_function)(Args...) const = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,261 +1,287 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/HashSet.h>
|
#include <BAN/Hash.h>
|
||||||
|
#include <BAN/LinkedList.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename HashSetIt, typename HashMap, typename Entry>
|
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
||||||
class HashMapIterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HashMapIterator() = default;
|
|
||||||
|
|
||||||
Entry& operator*()
|
|
||||||
{
|
|
||||||
return const_cast<Entry&>(m_iterator.operator*());
|
|
||||||
}
|
|
||||||
const Entry& operator*() const
|
|
||||||
{
|
|
||||||
return m_iterator.operator*();
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry* operator->()
|
|
||||||
{
|
|
||||||
return const_cast<Entry*>(m_iterator.operator->());
|
|
||||||
}
|
|
||||||
const Entry* operator->() const
|
|
||||||
{
|
|
||||||
return m_iterator.operator->();
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMapIterator& operator++()
|
|
||||||
{
|
|
||||||
++m_iterator;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
HashMapIterator operator++(int)
|
|
||||||
{
|
|
||||||
auto temp = *this;
|
|
||||||
++(*this);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(HashMapIterator other) const
|
|
||||||
{
|
|
||||||
return m_iterator == other.m_iterator;
|
|
||||||
}
|
|
||||||
bool operator!=(HashMapIterator other) const
|
|
||||||
{
|
|
||||||
return m_iterator != other.m_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit HashMapIterator(HashSetIt it)
|
|
||||||
: m_iterator(it)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
private:
|
|
||||||
HashSetIt m_iterator;
|
|
||||||
friend HashMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
template<typename T, typename Key, typename HASH, typename COMP>
|
|
||||||
concept HashMapFindable = requires(const Key& a, const T& b) { COMP()(a, b); HASH()(b); };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>, typename COMP = BAN::equal<Key>>
|
|
||||||
class HashMap
|
class HashMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
const Key key;
|
|
||||||
T value;
|
|
||||||
|
|
||||||
Entry() = delete;
|
|
||||||
Entry& operator=(const Entry&) = delete;
|
|
||||||
Entry& operator=(Entry&&) = delete;
|
|
||||||
|
|
||||||
Entry(const Entry& other)
|
|
||||||
: key(other.key)
|
|
||||||
, value(other.value)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
Entry(Entry&& other)
|
|
||||||
: key(BAN::move(const_cast<Key&>(other.key)))
|
|
||||||
, value(BAN::move(other.value))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
Entry(Key&& key, Args&&... args)
|
Entry(const Key& key, Args&&... args)
|
||||||
: key(BAN::move(key))
|
: key(key)
|
||||||
, value(BAN::forward<Args>(args)...)
|
, value(forward<Args>(args)...)
|
||||||
{}
|
{}
|
||||||
};
|
|
||||||
|
|
||||||
struct EntryHash
|
Key key;
|
||||||
{
|
T value;
|
||||||
constexpr bool operator()(const Key& a)
|
|
||||||
{
|
|
||||||
return HASH()(a);
|
|
||||||
}
|
|
||||||
constexpr bool operator()(const Entry& a)
|
|
||||||
{
|
|
||||||
return HASH()(a.key);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EntryComp
|
|
||||||
{
|
|
||||||
constexpr bool operator()(const Entry& a, const Key& b)
|
|
||||||
{
|
|
||||||
return COMP()(a.key, b);
|
|
||||||
}
|
|
||||||
constexpr bool operator()(const Entry& a, const Entry& b)
|
|
||||||
{
|
|
||||||
return COMP()(a.key, b.key);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using key_type = Key;
|
using key_type = Key;
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using iterator = HashMapIterator<typename HashSet<Entry, EntryHash, EntryComp>::iterator, HashMap, Entry>;
|
using iterator = IteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
||||||
using const_iterator = HashMapIterator<typename HashSet<Entry, EntryHash, EntryComp>::const_iterator, HashMap, const Entry>;
|
using const_iterator = ConstIteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashMap() = default;
|
HashMap() = default;
|
||||||
~HashMap() { clear(); }
|
HashMap(const HashMap<Key, T, HASH>&);
|
||||||
|
HashMap(HashMap<Key, T, HASH>&&);
|
||||||
|
~HashMap();
|
||||||
|
|
||||||
HashMap(const HashMap& other) { *this = other; }
|
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
||||||
HashMap& operator=(const HashMap& other)
|
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
||||||
|
|
||||||
|
ErrorOr<void> insert(const Key&, const T&);
|
||||||
|
ErrorOr<void> insert(const Key&, T&&);
|
||||||
|
template<typename... Args>
|
||||||
|
ErrorOr<void> emplace(const Key&, Args&&...);
|
||||||
|
|
||||||
|
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||||
|
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||||
|
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
||||||
|
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
||||||
|
|
||||||
|
ErrorOr<void> reserve(size_type);
|
||||||
|
|
||||||
|
void remove(const Key&);
|
||||||
|
void remove(iterator it);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
T& operator[](const Key&);
|
||||||
|
const T& operator[](const Key&) const;
|
||||||
|
|
||||||
|
iterator find(const Key& key);
|
||||||
|
const_iterator find(const Key& key) const;
|
||||||
|
bool contains(const Key&) const;
|
||||||
|
|
||||||
|
bool empty() const;
|
||||||
|
size_type size() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ErrorOr<void> rebucket(size_type);
|
||||||
|
LinkedList<Entry>& get_bucket(const Key&);
|
||||||
|
const LinkedList<Entry>& get_bucket(const Key&) const;
|
||||||
|
Vector<LinkedList<Entry>>::iterator get_bucket_iterator(const Key&);
|
||||||
|
Vector<LinkedList<Entry>>::const_iterator get_bucket_iterator(const Key&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector<LinkedList<Entry>> m_buckets;
|
||||||
|
size_type m_size = 0;
|
||||||
|
|
||||||
|
friend iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
HashMap<Key, T, HASH>::HashMap(const HashMap<Key, T, HASH>& other)
|
||||||
{
|
{
|
||||||
m_hash_set = other.m_hash_set;
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
HashMap<Key, T, HASH>::HashMap(HashMap<Key, T, HASH>&& other)
|
||||||
|
{
|
||||||
|
*this = move(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
HashMap<Key, T, HASH>::~HashMap()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(const HashMap<Key, T, HASH>& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
m_buckets = other.m_buckets;
|
||||||
|
m_size = other.m_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap(HashMap&& other) { *this = BAN::move(other); }
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap& operator=(HashMap&& other)
|
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(HashMap<Key, T, HASH>&& other)
|
||||||
{
|
{
|
||||||
m_hash_set = BAN::move(other.m_hash_set);
|
clear();
|
||||||
|
m_buckets = move(other.m_buckets);
|
||||||
|
m_size = other.m_size;
|
||||||
|
other.m_size = 0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator begin() { return iterator(m_hash_set.begin()); }
|
template<typename Key, typename T, typename HASH>
|
||||||
iterator end() { return iterator(m_hash_set.end()); }
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, const T& value)
|
||||||
const_iterator begin() const { return const_iterator(m_hash_set.begin()); }
|
{
|
||||||
const_iterator end() const { return const_iterator(m_hash_set.end()); }
|
return insert(key, move(T(value)));
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, value); }
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<iterator> insert(const Key& key, T&& value) { return emplace(key, move(value)); }
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, T&& value)
|
||||||
ErrorOr<iterator> insert(Key&& key, const T& value) { return emplace(move(key), value); }
|
{
|
||||||
ErrorOr<iterator> insert(Key&& key, T&& value) { return emplace(move(key), move(value)); }
|
return emplace(key, move(value));
|
||||||
|
}
|
||||||
ErrorOr<iterator> insert_or_assign(const Key& key, const T& value) { return emplace_or_assign(key, value); }
|
|
||||||
ErrorOr<iterator> insert_or_assign(const Key& key, T&& value) { return emplace_or_assign(key, move(value)); }
|
|
||||||
ErrorOr<iterator> insert_or_assign(Key&& key, const T& value) { return emplace_or_assign(move(key), value); }
|
|
||||||
ErrorOr<iterator> insert_or_assign(Key&& key, T&& value) { return emplace_or_assign(move(key), move(value)); }
|
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> HashMap<Key, T, HASH>::emplace(const Key& key, Args&&... args)
|
||||||
{ return emplace(Key(key), BAN::forward<Args>(args)...); }
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<iterator> emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
{
|
{
|
||||||
ASSERT(!contains(key));
|
ASSERT(!contains(key));
|
||||||
auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward<Args>(args)...) }));
|
TRY(rebucket(m_size + 1));
|
||||||
return iterator(it);
|
auto& bucket = get_bucket(key);
|
||||||
|
TRY(bucket.emplace_back(key, forward<Args>(args)...));
|
||||||
|
m_size++;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> HashMap<Key, T, HASH>::reserve(size_type size)
|
||||||
{ return emplace_or_assign(Key(key), BAN::forward<Args>(args)...); }
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<iterator> emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
{
|
{
|
||||||
if (auto it = m_hash_set.find(key); it != m_hash_set.end())
|
TRY(rebucket(size));
|
||||||
{
|
return {};
|
||||||
const_cast<T&>(it->value) = T(BAN::forward<Args>(args)...);
|
|
||||||
return iterator(it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward<Args>(args)...) }));
|
template<typename Key, typename T, typename HASH>
|
||||||
return iterator(it);
|
void HashMap<Key, T, HASH>::remove(const Key& key)
|
||||||
}
|
|
||||||
|
|
||||||
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
|
||||||
void remove(const U& key)
|
|
||||||
{
|
{
|
||||||
if (auto it = find(key); it != end())
|
auto it = find(key);
|
||||||
|
if (it != end())
|
||||||
remove(it);
|
remove(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator remove(iterator it)
|
template<typename Key, typename T, typename HASH>
|
||||||
|
void HashMap<Key, T, HASH>::remove(iterator it)
|
||||||
{
|
{
|
||||||
return iterator(m_hash_set.remove(it.m_iterator));
|
it.outer_current()->remove(it.inner_current());
|
||||||
|
m_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
template<typename Key, typename T, typename HASH>
|
||||||
iterator find(const U& key)
|
void HashMap<Key, T, HASH>::clear()
|
||||||
{
|
{
|
||||||
return iterator(m_hash_set.find(key));
|
m_buckets.clear();
|
||||||
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
template<typename Key, typename T, typename HASH>
|
||||||
const_iterator find(const U& key) const
|
T& HashMap<Key, T, HASH>::operator[](const Key& key)
|
||||||
{
|
{
|
||||||
return const_iterator(m_hash_set.find(key));
|
ASSERT(!empty());
|
||||||
|
auto& bucket = get_bucket(key);
|
||||||
|
for (Entry& entry : bucket)
|
||||||
|
if (entry.key == key)
|
||||||
|
return entry.value;
|
||||||
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
template<typename Key, typename T, typename HASH>
|
||||||
|
const T& HashMap<Key, T, HASH>::operator[](const Key& key) const
|
||||||
{
|
{
|
||||||
m_hash_set.clear();
|
ASSERT(!empty());
|
||||||
|
const auto& bucket = get_bucket(key);
|
||||||
|
for (const Entry& entry : bucket)
|
||||||
|
if (entry.key == key)
|
||||||
|
return entry.value;
|
||||||
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type size)
|
template<typename Key, typename T, typename HASH>
|
||||||
|
typename HashMap<Key, T, HASH>::iterator HashMap<Key, T, HASH>::find(const Key& key)
|
||||||
{
|
{
|
||||||
return m_hash_set.reserve(size);
|
if (empty())
|
||||||
|
return end();
|
||||||
|
auto bucket_it = get_bucket_iterator(key);
|
||||||
|
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
||||||
|
if (it->key == key)
|
||||||
|
return iterator(m_buckets.end(), bucket_it, it);
|
||||||
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
template<typename Key, typename T, typename HASH>
|
||||||
T& operator[](const U& key)
|
typename HashMap<Key, T, HASH>::const_iterator HashMap<Key, T, HASH>::find(const Key& key) const
|
||||||
{
|
{
|
||||||
return find(key)->value;
|
if (empty())
|
||||||
|
return end();
|
||||||
|
auto bucket_it = get_bucket_iterator(key);
|
||||||
|
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
||||||
|
if (it->key == key)
|
||||||
|
return const_iterator(m_buckets.end(), bucket_it, it);
|
||||||
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
template<typename Key, typename T, typename HASH>
|
||||||
const T& operator[](const U& key) const
|
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
||||||
{
|
|
||||||
return find(key)->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
|
||||||
bool contains(const U& key) const
|
|
||||||
{
|
{
|
||||||
return find(key) != end();
|
return find(key) != end();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type capacity() const
|
template<typename Key, typename T, typename HASH>
|
||||||
|
bool HashMap<Key, T, HASH>::empty() const
|
||||||
{
|
{
|
||||||
return m_hash_set.capacity();
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type size() const
|
template<typename Key, typename T, typename HASH>
|
||||||
|
typename HashMap<Key, T, HASH>::size_type HashMap<Key, T, HASH>::size() const
|
||||||
{
|
{
|
||||||
return m_hash_set.size();
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const
|
template<typename Key, typename T, typename HASH>
|
||||||
|
ErrorOr<void> HashMap<Key, T, HASH>::rebucket(size_type bucket_count)
|
||||||
{
|
{
|
||||||
return m_hash_set.empty();
|
if (m_buckets.size() >= bucket_count)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||||
|
Vector<LinkedList<Entry>> new_buckets;
|
||||||
|
TRY(new_buckets.resize(new_bucket_count));
|
||||||
|
|
||||||
|
for (auto& bucket : m_buckets)
|
||||||
|
{
|
||||||
|
for (auto it = bucket.begin(); it != bucket.end();)
|
||||||
|
{
|
||||||
|
size_type new_bucket_index = HASH()(it->key) % new_buckets.size();
|
||||||
|
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
m_buckets = move(new_buckets);
|
||||||
HashSet<Entry, EntryHash, EntryComp> m_hash_set;
|
return {};
|
||||||
};
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
||||||
|
{
|
||||||
|
return *get_bucket_iterator(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
||||||
|
{
|
||||||
|
return *get_bucket_iterator(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key)
|
||||||
|
{
|
||||||
|
ASSERT(!m_buckets.empty());
|
||||||
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
|
return next(m_buckets.begin(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH>
|
||||||
|
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::const_iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key) const
|
||||||
|
{
|
||||||
|
ASSERT(!m_buckets.empty());
|
||||||
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
|
return next(m_buckets.begin(), index);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,358 +2,198 @@
|
|||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Hash.h>
|
||||||
|
#include <BAN/Iterators.h>
|
||||||
|
#include <BAN/LinkedList.h>
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/New.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename HashSet, typename Bucket, typename T>
|
template<typename T, typename HASH = hash<T>>
|
||||||
class HashSetIterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HashSetIterator() = default;
|
|
||||||
|
|
||||||
const T& operator*() const
|
|
||||||
{
|
|
||||||
ASSERT(m_bucket);
|
|
||||||
return *m_bucket->element();
|
|
||||||
}
|
|
||||||
|
|
||||||
const T* operator->() const
|
|
||||||
{
|
|
||||||
ASSERT(m_bucket);
|
|
||||||
return m_bucket->element();
|
|
||||||
}
|
|
||||||
|
|
||||||
HashSetIterator& operator++()
|
|
||||||
{
|
|
||||||
ASSERT(m_bucket);
|
|
||||||
m_bucket++;
|
|
||||||
skip_to_valid_bucket();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
HashSetIterator operator++(int)
|
|
||||||
{
|
|
||||||
auto temp = *this;
|
|
||||||
++(*this);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(HashSetIterator other) const
|
|
||||||
{
|
|
||||||
return m_bucket == other.m_bucket;
|
|
||||||
}
|
|
||||||
bool operator!=(HashSetIterator other) const
|
|
||||||
{
|
|
||||||
return m_bucket != other.m_bucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit HashSetIterator(Bucket* bucket)
|
|
||||||
: m_bucket(bucket)
|
|
||||||
{
|
|
||||||
if (m_bucket != nullptr)
|
|
||||||
skip_to_valid_bucket();
|
|
||||||
}
|
|
||||||
|
|
||||||
void skip_to_valid_bucket()
|
|
||||||
{
|
|
||||||
while (m_bucket->state != Bucket::USED && !m_bucket->end)
|
|
||||||
m_bucket++;
|
|
||||||
if (m_bucket->end)
|
|
||||||
m_bucket = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Bucket* m_bucket { nullptr };
|
|
||||||
friend HashSet;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
template<typename T, typename U, typename HASH, typename COMP>
|
|
||||||
concept HashSetFindable = requires(const U& a, const T& b) { COMP()(a, b); HASH()(b); };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename HASH = BAN::hash<T>, typename COMP = BAN::equal<T>>
|
|
||||||
class HashSet
|
class HashSet
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
struct Bucket
|
|
||||||
{
|
|
||||||
static constexpr uint8_t UNUSED = 0;
|
|
||||||
static constexpr uint8_t USED = 1;
|
|
||||||
static constexpr uint8_t REMOVED = 2;
|
|
||||||
|
|
||||||
alignas(T) uint8_t storage[sizeof(T)];
|
|
||||||
hash_t hash;
|
|
||||||
uint8_t state : 2;
|
|
||||||
uint8_t chain_start : 1;
|
|
||||||
uint8_t end : 1;
|
|
||||||
|
|
||||||
T* element() { return reinterpret_cast<T*>(storage); }
|
|
||||||
const T* element() const { return reinterpret_cast<const T*>(storage); }
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using iterator = HashSetIterator<HashSet, Bucket, T>;
|
using iterator = IteratorDouble<T, Vector, LinkedList, HashSet>;
|
||||||
using const_iterator = HashSetIterator<HashSet, const Bucket, const T>;
|
using const_iterator = ConstIteratorDouble<T, Vector, LinkedList, HashSet>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashSet() = default;
|
HashSet() = default;
|
||||||
~HashSet() { clear(); }
|
HashSet(const HashSet&);
|
||||||
|
HashSet(HashSet&&);
|
||||||
|
|
||||||
HashSet(const HashSet& other) { *this = other; }
|
HashSet& operator=(const HashSet&);
|
||||||
HashSet& operator=(const HashSet& other)
|
HashSet& operator=(HashSet&&);
|
||||||
|
|
||||||
|
ErrorOr<void> insert(const T&);
|
||||||
|
ErrorOr<void> insert(T&&);
|
||||||
|
void remove(const T&);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
ErrorOr<void> reserve(size_type);
|
||||||
|
|
||||||
|
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||||
|
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||||
|
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
||||||
|
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
||||||
|
|
||||||
|
bool contains(const T&) const;
|
||||||
|
|
||||||
|
size_type size() const;
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ErrorOr<void> rebucket(size_type);
|
||||||
|
LinkedList<T>& get_bucket(const T&);
|
||||||
|
const LinkedList<T>& get_bucket(const T&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector<LinkedList<T>> m_buckets;
|
||||||
|
size_type m_size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
HashSet<T, HASH>::HashSet(const HashSet& other)
|
||||||
|
: m_buckets(other.m_buckets)
|
||||||
|
, m_size(other.m_size)
|
||||||
{
|
{
|
||||||
clear();
|
|
||||||
|
|
||||||
MUST(reserve(other.size()));
|
|
||||||
for (auto& bucket : other)
|
|
||||||
MUST(insert(bucket));
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet(HashSet&& other) { *this = BAN::move(other); }
|
template<typename T, typename HASH>
|
||||||
HashSet& operator=(HashSet&& other)
|
HashSet<T, HASH>::HashSet(HashSet&& other)
|
||||||
|
: m_buckets(move(other.m_buckets))
|
||||||
|
, m_size(other.m_size)
|
||||||
|
{
|
||||||
|
other.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
m_buckets = other.m_buckets;
|
m_buckets = other.m_buckets;
|
||||||
m_capacity = other.m_capacity;
|
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
m_removed = other.m_removed;
|
|
||||||
|
|
||||||
other.m_buckets = nullptr;
|
|
||||||
other.m_capacity = 0;
|
|
||||||
other.m_size = 0;
|
|
||||||
other.m_removed = 0;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator begin() { return iterator(m_buckets); }
|
template<typename T, typename HASH>
|
||||||
iterator end() { return iterator(nullptr); }
|
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet&& other)
|
||||||
const_iterator begin() const { return const_iterator(m_buckets); }
|
|
||||||
const_iterator end() const { return const_iterator(nullptr); }
|
|
||||||
|
|
||||||
ErrorOr<iterator> insert(const T& value)
|
|
||||||
{
|
{
|
||||||
return insert(T(value));
|
clear();
|
||||||
|
m_buckets = move(other.m_buckets);
|
||||||
|
m_size = other.m_size;
|
||||||
|
other.clear();
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<iterator> insert(T&& value)
|
template<typename T, typename HASH>
|
||||||
|
ErrorOr<void> HashSet<T, HASH>::insert(const T& key)
|
||||||
{
|
{
|
||||||
if (should_rehash_with_size(m_size + 1))
|
return insert(move(T(key)));
|
||||||
TRY(rehash(m_size * 2));
|
|
||||||
return insert_impl(BAN::move(value), HASH()(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
template<typename T, typename HASH>
|
||||||
void remove(const U& value)
|
ErrorOr<void> HashSet<T, HASH>::insert(T&& key)
|
||||||
{
|
{
|
||||||
if (auto it = find(value); it != end())
|
if (!empty() && get_bucket(key).contains(key))
|
||||||
remove(it);
|
return {};
|
||||||
}
|
|
||||||
|
|
||||||
iterator remove(iterator it)
|
TRY(rebucket(m_size + 1));
|
||||||
{
|
TRY(get_bucket(key).push_back(move(key)));
|
||||||
auto& bucket = *it.m_bucket;
|
m_size++;
|
||||||
bucket.element()->~T();
|
|
||||||
bucket.state = Bucket::REMOVED;
|
|
||||||
m_size--;
|
|
||||||
m_removed++;
|
|
||||||
return iterator(&bucket);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
|
||||||
iterator find(const U& value)
|
|
||||||
{
|
|
||||||
return iterator(const_cast<Bucket*>(find_impl(value).m_bucket));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
|
||||||
const_iterator find(const U& value) const
|
|
||||||
{
|
|
||||||
return find_impl(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
if (m_buckets == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (size_type i = 0; i < m_capacity; i++)
|
|
||||||
if (m_buckets[i].state == Bucket::USED)
|
|
||||||
m_buckets[i].element()->~T();
|
|
||||||
|
|
||||||
BAN::deallocator(m_buckets);
|
|
||||||
m_buckets = nullptr;
|
|
||||||
m_capacity = 0;
|
|
||||||
m_size = 0;
|
|
||||||
m_removed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type size)
|
|
||||||
{
|
|
||||||
if (should_rehash_with_size(size))
|
|
||||||
TRY(rehash(size * 2));
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
template<typename T, typename HASH>
|
||||||
bool contains(const U& value) const
|
void HashSet<T, HASH>::remove(const T& key)
|
||||||
{
|
{
|
||||||
return find(value) != end();
|
if (empty()) return;
|
||||||
|
auto& bucket = get_bucket(key);
|
||||||
|
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
||||||
|
{
|
||||||
|
if (*it == key)
|
||||||
|
{
|
||||||
|
bucket.remove(it);
|
||||||
|
m_size--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type capacity() const
|
template<typename T, typename HASH>
|
||||||
|
void HashSet<T, HASH>::clear()
|
||||||
{
|
{
|
||||||
return m_capacity;
|
m_buckets.clear();
|
||||||
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type size() const
|
template<typename T, typename HASH>
|
||||||
|
ErrorOr<void> HashSet<T, HASH>::reserve(size_type size)
|
||||||
|
{
|
||||||
|
TRY(rebucket(size));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
bool HashSet<T, HASH>::contains(const T& key) const
|
||||||
|
{
|
||||||
|
if (empty()) return false;
|
||||||
|
return get_bucket(key).contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
typename HashSet<T, HASH>::size_type HashSet<T, HASH>::size() const
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const
|
template<typename T, typename HASH>
|
||||||
|
bool HashSet<T, HASH>::empty() const
|
||||||
{
|
{
|
||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
template<typename T, typename HASH>
|
||||||
ErrorOr<void> rehash(size_type new_capacity)
|
ErrorOr<void> HashSet<T, HASH>::rebucket(size_type bucket_count)
|
||||||
{
|
{
|
||||||
new_capacity = BAN::Math::max<size_t>(16, BAN::Math::max(new_capacity, m_size + 1));
|
if (m_buckets.size() >= bucket_count)
|
||||||
new_capacity = BAN::Math::round_up_to_power_of_two(new_capacity);
|
return {};
|
||||||
|
|
||||||
void* new_buckets = BAN::allocator((new_capacity + 1) * sizeof(Bucket));
|
size_type new_bucket_count = Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||||
if (new_buckets == nullptr)
|
Vector<LinkedList<T>> new_buckets;
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
if (new_buckets.resize(new_bucket_count).is_error())
|
||||||
memset(new_buckets, 0, (new_capacity + 1) * sizeof(Bucket));
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
Bucket* old_buckets = m_buckets;
|
for (auto& bucket : m_buckets)
|
||||||
const size_type old_capacity = m_capacity;
|
|
||||||
|
|
||||||
m_buckets = static_cast<Bucket*>(new_buckets);
|
|
||||||
m_capacity = new_capacity;
|
|
||||||
m_size = 0;
|
|
||||||
m_removed = 0;
|
|
||||||
|
|
||||||
for (size_type i = 0; i < old_capacity; i++)
|
|
||||||
{
|
{
|
||||||
auto& old_bucket = old_buckets[i];
|
for (auto it = bucket.begin(); it != bucket.end();)
|
||||||
if (old_bucket.state != Bucket::USED)
|
{
|
||||||
continue;
|
size_type new_bucket_index = HASH()(*it) % new_buckets.size();
|
||||||
insert_impl(BAN::move(*old_bucket.element()), old_bucket.hash);
|
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||||
old_bucket.element()->~T();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buckets[m_capacity].end = true;
|
m_buckets = move(new_buckets);
|
||||||
|
|
||||||
BAN::deallocator(old_buckets);
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
template<typename T, typename HASH>
|
||||||
const_iterator find_impl(const U& value) const
|
LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key)
|
||||||
{
|
{
|
||||||
if (m_capacity == 0)
|
ASSERT(!m_buckets.empty());
|
||||||
return end();
|
size_type index = HASH()(key) % m_buckets.size();
|
||||||
|
return m_buckets[index];
|
||||||
|
}
|
||||||
|
|
||||||
bool first = true;
|
template<typename T, typename HASH>
|
||||||
const hash_t orig_hash = HASH()(value);
|
const LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key) const
|
||||||
for (auto hash = orig_hash;; hash = get_next_hash_in_chain(hash, orig_hash), first = false)
|
|
||||||
{
|
{
|
||||||
auto& bucket = m_buckets[hash & (m_capacity - 1)];
|
ASSERT(!m_buckets.empty());
|
||||||
if (bucket.state == Bucket::USED && bucket.hash == orig_hash && COMP()(*bucket.element(), value))
|
size_type index = HASH()(key) % m_buckets.size();
|
||||||
return const_iterator(&bucket);
|
return m_buckets[index];
|
||||||
if (bucket.state == Bucket::UNUSED)
|
|
||||||
return end();
|
|
||||||
if (!first && bucket.chain_start)
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator insert_impl(T&& value, hash_t orig_hash)
|
|
||||||
{
|
|
||||||
ASSERT(!should_rehash_with_size(m_size + 1));
|
|
||||||
|
|
||||||
Bucket* target = nullptr;
|
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
for (auto hash = orig_hash;; hash = get_next_hash_in_chain(hash, orig_hash), first = false)
|
|
||||||
{
|
|
||||||
auto& bucket = m_buckets[hash & (m_capacity - 1)];
|
|
||||||
|
|
||||||
if (!first)
|
|
||||||
bucket.chain_start = false;
|
|
||||||
|
|
||||||
if (bucket.state == Bucket::USED)
|
|
||||||
{
|
|
||||||
if (bucket.hash != orig_hash || !COMP()(*bucket.element(), value))
|
|
||||||
continue;
|
|
||||||
target = &bucket;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target == nullptr)
|
|
||||||
target = &bucket;
|
|
||||||
|
|
||||||
if (bucket.state == Bucket::UNUSED)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (target->state)
|
|
||||||
{
|
|
||||||
case Bucket::USED:
|
|
||||||
target->element()->~T();
|
|
||||||
break;
|
|
||||||
case Bucket::REMOVED:
|
|
||||||
m_removed--;
|
|
||||||
[[fallthrough]];
|
|
||||||
case Bucket::UNUSED:
|
|
||||||
m_size++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
target->chain_start = first && target->state == Bucket::UNUSED;
|
|
||||||
target->hash = orig_hash;
|
|
||||||
target->state = Bucket::USED;
|
|
||||||
|
|
||||||
new (target->element()) T(BAN::move(value));
|
|
||||||
|
|
||||||
return iterator(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_rehash_with_size(size_type size) const
|
|
||||||
{
|
|
||||||
if (m_capacity < 16)
|
|
||||||
return true;
|
|
||||||
if (size + m_removed > m_capacity / 4 * 3)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_t get_next_hash_in_chain(hash_t prev_hash, hash_t orig_hash) const
|
|
||||||
{
|
|
||||||
// TODO: does this even provide better performance than `return prev_hash + 1`
|
|
||||||
// when using "good" hash functions
|
|
||||||
return prev_hash * 1103515245 + (orig_hash | 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Bucket* m_buckets { nullptr };
|
|
||||||
size_type m_capacity { 0 };
|
|
||||||
size_type m_size { 0 };
|
|
||||||
size_type m_removed { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Iterators.h>
|
|
||||||
#include <BAN/Swap.h>
|
|
||||||
#include <BAN/Traits.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
void heapify_up(It begin, size_t index, Comp comp)
|
|
||||||
{
|
|
||||||
size_t parent = (index - 1) / 2;
|
|
||||||
while (parent < index)
|
|
||||||
{
|
|
||||||
if (comp(*(begin + index), *(begin + parent)))
|
|
||||||
break;
|
|
||||||
swap(*(begin + parent), *(begin + index));
|
|
||||||
index = parent;
|
|
||||||
parent = (index - 1) / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
void heapify_down(It begin, size_t index, size_t len, Comp comp)
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
const size_t lchild = 2 * index + 1;
|
|
||||||
const size_t rchild = 2 * index + 2;
|
|
||||||
|
|
||||||
size_t child = 0;
|
|
||||||
if (lchild < len && !comp(*(begin + lchild), *(begin + index)))
|
|
||||||
{
|
|
||||||
if (rchild < len && !comp(*(begin + rchild), *(begin + lchild)))
|
|
||||||
child = rchild;
|
|
||||||
else
|
|
||||||
child = lchild;
|
|
||||||
}
|
|
||||||
else if (rchild < len && !comp(*(begin + rchild), *(begin + index)))
|
|
||||||
child = rchild;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
swap(*(begin + child), *(begin + index));
|
|
||||||
index = child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
|
||||||
void make_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
if (len <= 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t index = (len - 2) / 2;
|
|
||||||
while (index < len)
|
|
||||||
detail::heapify_down(begin, index--, len, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
|
||||||
void push_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
detail::heapify_up(begin, len - 1, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
|
||||||
void pop_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
swap(*begin, *(begin + len - 1));
|
|
||||||
detail::heapify_down(begin, 0, len - 1, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
|
||||||
void sort_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
while (begin != end)
|
|
||||||
pop_heap(begin, end--, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -9,10 +9,6 @@ namespace BAN
|
|||||||
|
|
||||||
struct IPv4Address
|
struct IPv4Address
|
||||||
{
|
{
|
||||||
constexpr IPv4Address()
|
|
||||||
: IPv4Address(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
constexpr IPv4Address(uint32_t u32_address)
|
constexpr IPv4Address(uint32_t u32_address)
|
||||||
{
|
{
|
||||||
raw = u32_address;
|
raw = u32_address;
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ namespace BAN
|
|||||||
ErrorOr<void> insert(iterator, const T&);
|
ErrorOr<void> insert(iterator, const T&);
|
||||||
ErrorOr<void> insert(iterator, T&&);
|
ErrorOr<void> insert(iterator, T&&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace_back(Args&&...);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(iterator, Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace(iterator, Args&&...);
|
||||||
|
|
||||||
void pop_back();
|
void pop_back();
|
||||||
iterator remove(iterator);
|
iterator remove(iterator);
|
||||||
@@ -196,14 +196,14 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args)
|
||||||
{
|
{
|
||||||
return emplace(end(), forward<Args>(args)...);
|
return emplace(end(), forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
|
||||||
{
|
{
|
||||||
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
||||||
insert_node(iter, new_node);
|
insert_node(iter, new_node);
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define _ban_count_args_impl(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
|
|
||||||
#define _ban_count_args(...) _ban_count_args_impl(__VA_ARGS__ __VA_OPT__(,) 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
|
||||||
|
|
||||||
#define _ban_concat_impl(a, b) a##b
|
|
||||||
#define _ban_concat(a, b) _ban_concat_impl(a, b)
|
|
||||||
|
|
||||||
#define _ban_stringify_impl(x) #x
|
|
||||||
#define _ban_stringify(x) _ban_stringify_impl(x)
|
|
||||||
|
|
||||||
#define _ban_fe_0(f)
|
|
||||||
#define _ban_fe_1(f, _0) f(0, _0)
|
|
||||||
#define _ban_fe_2(f, _0, _1) f(0, _0) f(1, _1)
|
|
||||||
#define _ban_fe_3(f, _0, _1, _2) f(0, _0) f(1, _1) f(2, _2)
|
|
||||||
#define _ban_fe_4(f, _0, _1, _2, _3) f(0, _0) f(1, _1) f(2, _2) f(3, _3)
|
|
||||||
#define _ban_fe_5(f, _0, _1, _2, _3, _4) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4)
|
|
||||||
#define _ban_fe_6(f, _0, _1, _2, _3, _4, _5) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5)
|
|
||||||
#define _ban_fe_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6)
|
|
||||||
#define _ban_fe_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7)
|
|
||||||
#define _ban_fe_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7) f(8, _8)
|
|
||||||
#define _ban_for_each(f, ...) _ban_concat(_ban_fe_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
|
|
||||||
|
|
||||||
#define _ban_fe_comma_0(f)
|
|
||||||
#define _ban_fe_comma_1(f, _0) f(0, _0)
|
|
||||||
#define _ban_fe_comma_2(f, _0, _1) f(0, _0), f(1, _1)
|
|
||||||
#define _ban_fe_comma_3(f, _0, _1, _2) f(0, _0), f(1, _1), f(2, _2)
|
|
||||||
#define _ban_fe_comma_4(f, _0, _1, _2, _3) f(0, _0), f(1, _1), f(2, _2), f(3, _3)
|
|
||||||
#define _ban_fe_comma_5(f, _0, _1, _2, _3, _4) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4)
|
|
||||||
#define _ban_fe_comma_6(f, _0, _1, _2, _3, _4, _5) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5)
|
|
||||||
#define _ban_fe_comma_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6)
|
|
||||||
#define _ban_fe_comma_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7)
|
|
||||||
#define _ban_fe_comma_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7), f(8, _8)
|
|
||||||
#define _ban_for_each_comma(f, ...) _ban_concat(_ban_fe_comma_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
|
|
||||||
|
|
||||||
#define _ban_get_0(a0, ...) a0
|
|
||||||
#define _ban_get_1(a0, a1, ...) a1
|
|
||||||
#define _ban_get_2(a0, a1, a2, ...) a2
|
|
||||||
#define _ban_get_3(a0, a1, a2, a3, ...) a3
|
|
||||||
#define _ban_get_4(a0, a1, a2, a3, a4, ...) a4
|
|
||||||
#define _ban_get_5(a0, a1, a2, a3, a4, a5, ...) a5
|
|
||||||
#define _ban_get_6(a0, a1, a2, a3, a4, a5, a6, ...) a6
|
|
||||||
#define _ban_get_7(a0, a1, a2, a3, a4, a5, a6, a7, ...) a7
|
|
||||||
#define _ban_get_8(a0, a1, a2, a3, a4, a5, a6, a7, a8, ...) a8
|
|
||||||
#define _ban_get_9(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
|
|
||||||
#define _ban_get(n, ...) _ban_concat(_ban_get_, n)(__VA_ARGS__)
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Limits.h>
|
#include <BAN/Limits.h>
|
||||||
#include <BAN/Numbers.h>
|
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
#include <float.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace BAN::Math
|
namespace BAN::Math
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr T abs(T x)
|
inline constexpr T abs(T val)
|
||||||
{
|
{
|
||||||
return x < 0 ? -x : x;
|
return val < 0 ? -val : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -36,11 +36,12 @@ namespace BAN::Math
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
inline constexpr T gcd(T a, T b)
|
inline constexpr T gcd(T a, T b)
|
||||||
{
|
{
|
||||||
|
T t;
|
||||||
while (b)
|
while (b)
|
||||||
{
|
{
|
||||||
T temp = b;
|
t = b;
|
||||||
b = a % b;
|
b = a % b;
|
||||||
a = temp;
|
a = t;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -58,424 +59,86 @@ namespace BAN::Math
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
inline constexpr bool is_power_of_two(T x)
|
inline constexpr bool is_power_of_two(T value)
|
||||||
{
|
{
|
||||||
if (x == 0)
|
if (value == 0)
|
||||||
return false;
|
return false;
|
||||||
return (x & (x - 1)) == 0;
|
return (value & (value - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<integral T> requires(sizeof(T) <= 8)
|
template<BAN::integral T>
|
||||||
inline constexpr T round_up_to_power_of_two(T x)
|
static constexpr bool will_multiplication_overflow(T a, T b)
|
||||||
{
|
{
|
||||||
x--;
|
if (a == 0 || b == 0)
|
||||||
x |= x >> 1;
|
return false;
|
||||||
x |= x >> 2;
|
if ((a > 0) == (b > 0))
|
||||||
x |= x >> 4;
|
return a > BAN::numeric_limits<T>::max() / b;
|
||||||
if constexpr(sizeof(T) >= 2)
|
else
|
||||||
x |= x >> 8;
|
return a < BAN::numeric_limits<T>::min() / b;
|
||||||
if constexpr(sizeof(T) >= 4)
|
|
||||||
x |= x >> 16;
|
|
||||||
if constexpr(sizeof(T) >= 8)
|
|
||||||
x |= x >> 32;
|
|
||||||
return x + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<integral T>
|
template<BAN::integral T>
|
||||||
__attribute__((always_inline))
|
static constexpr bool will_addition_overflow(T a, T b)
|
||||||
inline constexpr bool will_multiplication_overflow(T a, T b)
|
|
||||||
{
|
{
|
||||||
T dummy;
|
if (a > 0 && b > 0)
|
||||||
return __builtin_mul_overflow(a, b, &dummy);
|
return a > BAN::numeric_limits<T>::max() - b;
|
||||||
}
|
if (a < 0 && b < 0)
|
||||||
|
return a < BAN::numeric_limits<T>::min() - b;
|
||||||
template<integral T>
|
return false;
|
||||||
__attribute__((always_inline))
|
|
||||||
inline constexpr bool will_addition_overflow(T a, T b)
|
|
||||||
{
|
|
||||||
T dummy;
|
|
||||||
return __builtin_add_overflow(a, b, &dummy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||||
inline constexpr T ilog2(T x)
|
inline constexpr T ilog2(T value)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, unsigned int>)
|
if constexpr(is_same_v<T, unsigned int>)
|
||||||
return sizeof(T) * 8 - __builtin_clz(x) - 1;
|
return sizeof(T) * 8 - __builtin_clz(value) - 1;
|
||||||
if constexpr(is_same_v<T, unsigned long>)
|
if constexpr(is_same_v<T, unsigned long>)
|
||||||
return sizeof(T) * 8 - __builtin_clzl(x) - 1;
|
return sizeof(T) * 8 - __builtin_clzl(value) - 1;
|
||||||
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
return sizeof(T) * 8 - __builtin_clzll(value) - 1;
|
||||||
}
|
|
||||||
|
|
||||||
// This is ugly but my clangd does not like including
|
|
||||||
// intrinsic headers at all
|
|
||||||
#if !defined(__SSE__) || !defined(__SSE2__)
|
|
||||||
#pragma GCC push_options
|
|
||||||
#ifndef __SSE__
|
|
||||||
#pragma GCC target("sse")
|
|
||||||
#endif
|
|
||||||
#ifndef __SSE2__
|
|
||||||
#pragma GCC target("sse2")
|
|
||||||
#endif
|
|
||||||
#define BAN_MATH_POP_OPTIONS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T floor(T x)
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __builtin_floorf(x);
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __builtin_floor(x);
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_floorl(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T ceil(T x)
|
inline constexpr T log2(T value)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, float>)
|
T result;
|
||||||
return __builtin_ceilf(x);
|
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"((T)1.0) : "st(1)");
|
||||||
if constexpr(is_same_v<T, double>)
|
return result;
|
||||||
return __builtin_ceil(x);
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_ceill(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T round(T x)
|
inline constexpr T log10(T value)
|
||||||
{
|
{
|
||||||
if (x == (T)0.0)
|
constexpr T INV_LOG_2_10 = 0.3010299956639811952137388947244930267681898814621085413104274611;
|
||||||
return x;
|
T result;
|
||||||
if (x > (T)0.0)
|
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"(INV_LOG_2_10) : "st(1)");
|
||||||
return floor<T>(x + (T)0.5);
|
return result;
|
||||||
return ceil<T>(x - (T)0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T trunc(T x)
|
inline constexpr T log(T value, T base)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, float>)
|
return log2(value) / log2(base);
|
||||||
return __builtin_truncf(x);
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __builtin_trunc(x);
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_truncl(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T rint(T x)
|
inline constexpr T pow(T base, T exp)
|
||||||
{
|
{
|
||||||
asm("frndint" : "+t"(x));
|
T result;
|
||||||
return x;
|
asm volatile(
|
||||||
}
|
"fyl2x;"
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T fmod(T a, T b)
|
|
||||||
{
|
|
||||||
asm(
|
|
||||||
"1:"
|
|
||||||
"fprem;"
|
|
||||||
"fnstsw %%ax;"
|
|
||||||
"testb $4, %%ah;"
|
|
||||||
"jne 1b;"
|
|
||||||
: "+t"(a)
|
|
||||||
: "u"(b)
|
|
||||||
: "ax", "cc"
|
|
||||||
);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T remainder(T a, T b)
|
|
||||||
{
|
|
||||||
asm(
|
|
||||||
"1:"
|
|
||||||
"fprem1;"
|
|
||||||
"fnstsw %%ax;"
|
|
||||||
"testb $4, %%ah;"
|
|
||||||
"jne 1b;"
|
|
||||||
: "+t"(a)
|
|
||||||
: "u"(b)
|
|
||||||
: "ax", "cc"
|
|
||||||
);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
static T modf(T x, T* iptr)
|
|
||||||
{
|
|
||||||
const T frac = BAN::Math::fmod<T>(x, (T)1.0);
|
|
||||||
*iptr = x - frac;
|
|
||||||
return frac;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T frexp(T num, int* exp)
|
|
||||||
{
|
|
||||||
if (num == (T)0.0)
|
|
||||||
{
|
|
||||||
*exp = 0;
|
|
||||||
return (T)0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
T e;
|
|
||||||
asm("fxtract" : "+t"(num), "=u"(e));
|
|
||||||
*exp = (int)e + 1;
|
|
||||||
return num / (T)2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T copysign(T x, T y)
|
|
||||||
{
|
|
||||||
if ((x < (T)0.0) != (y < (T)0.0))
|
|
||||||
x = -x;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T fyl2x(T x, T y)
|
|
||||||
{
|
|
||||||
asm("fyl2x" : "+t"(x) : "u"(y) : "st(1)");
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T log(T x)
|
|
||||||
{
|
|
||||||
return detail::fyl2x<T>(x, numbers::ln2_v<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T log2(T x)
|
|
||||||
{
|
|
||||||
return detail::fyl2x<T>(x, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T log10(T x)
|
|
||||||
{
|
|
||||||
return detail::fyl2x<T>(x, numbers::lg2_v<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T logb(T x)
|
|
||||||
{
|
|
||||||
static_assert(FLT_RADIX == 2);
|
|
||||||
return log2<T>(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T exp2(T x)
|
|
||||||
{
|
|
||||||
if (abs(x) <= (T)1.0)
|
|
||||||
{
|
|
||||||
asm("f2xm1" : "+t"(x));
|
|
||||||
return x + (T)1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
asm(
|
|
||||||
"fld1;"
|
"fld1;"
|
||||||
"fld %%st(1);"
|
"fld %%st(1);"
|
||||||
"fprem;"
|
"fprem;"
|
||||||
"f2xm1;"
|
"f2xm1;"
|
||||||
"faddp;"
|
"faddp;"
|
||||||
"fscale;"
|
"fscale;"
|
||||||
"fstp %%st(1);"
|
"fxch %%st(1);"
|
||||||
: "+t"(x)
|
"fstp %%st;"
|
||||||
|
: "=t"(result)
|
||||||
|
: "0"(base), "u"(exp)
|
||||||
);
|
);
|
||||||
|
return result;
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T exp(T x)
|
|
||||||
{
|
|
||||||
return exp2<T>(x * numbers::log2e_v<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T pow(T x, T y)
|
|
||||||
{
|
|
||||||
if (x == (T)0.0)
|
|
||||||
return (T)0.0;
|
|
||||||
return exp2<T>(y * log2<T>(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T scalbn(T x, int n)
|
|
||||||
{
|
|
||||||
asm("fscale" : "+t"(x) : "u"(static_cast<T>(n)));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T ldexp(T x, int y)
|
|
||||||
{
|
|
||||||
const bool exp_sign = y < 0;
|
|
||||||
if (exp_sign)
|
|
||||||
y = -y;
|
|
||||||
|
|
||||||
T exp = (T)1.0;
|
|
||||||
T mult = (T)2.0;
|
|
||||||
while (y)
|
|
||||||
{
|
|
||||||
if (y & 1)
|
|
||||||
exp *= mult;
|
|
||||||
mult *= mult;
|
|
||||||
y >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp_sign)
|
|
||||||
exp = (T)1.0 / exp;
|
|
||||||
|
|
||||||
return x * exp;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T sqrt(T x)
|
|
||||||
{
|
|
||||||
if constexpr(BAN::is_same_v<T, float>)
|
|
||||||
{
|
|
||||||
using v4sf = float __attribute__((vector_size(16)));
|
|
||||||
return __builtin_ia32_sqrtss((v4sf) { x, 0.0f, 0.0f, 0.0f })[0];
|
|
||||||
}
|
|
||||||
else if constexpr(BAN::is_same_v<T, double>)
|
|
||||||
{
|
|
||||||
using v2df = double __attribute__((vector_size(16)));
|
|
||||||
return __builtin_ia32_sqrtsd((v2df) { x, 0.0 })[0];
|
|
||||||
}
|
|
||||||
else if constexpr(BAN::is_same_v<T, long double>)
|
|
||||||
{
|
|
||||||
asm("fsqrt" : "+t"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T cbrt(T value)
|
|
||||||
{
|
|
||||||
return pow<T>(value, (T)1.0 / (T)3.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T sin(T x)
|
|
||||||
{
|
|
||||||
asm("fsin" : "+t"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T cos(T x)
|
|
||||||
{
|
|
||||||
asm("fcos" : "+t"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr void sincos(T x, T& sin, T& cos)
|
|
||||||
{
|
|
||||||
asm("fsincos" : "=t"(cos), "=u"(sin) : "0"(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T tan(T x)
|
|
||||||
{
|
|
||||||
T one, ret;
|
|
||||||
asm("fptan" : "=t"(one), "=u"(ret) : "0"(x));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T atan2(T y, T x)
|
|
||||||
{
|
|
||||||
asm("fpatan" : "+t"(x) : "u"(y) : "st(1)");
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T atan(T x)
|
|
||||||
{
|
|
||||||
return atan2<T>(x, (T)1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T asin(T x)
|
|
||||||
{
|
|
||||||
if (x == (T)0.0)
|
|
||||||
return (T)0.0;
|
|
||||||
if (x == (T)1.0)
|
|
||||||
return +numbers::pi_v<T> / (T)2.0;
|
|
||||||
if (x == (T)-1.0)
|
|
||||||
return -numbers::pi_v<T> / (T)2.0;
|
|
||||||
return (T)2.0 * atan<T>(x / ((T)1.0 + sqrt<T>((T)1.0 - x * x)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T acos(T x)
|
|
||||||
{
|
|
||||||
if (x == (T)0.0)
|
|
||||||
return numbers::pi_v<T> / (T)2.0;
|
|
||||||
if (x == (T)1.0)
|
|
||||||
return (T)0.0;
|
|
||||||
if (x == (T)-1.0)
|
|
||||||
return numbers::pi_v<T>;
|
|
||||||
return (T)2.0 * atan<T>(sqrt<T>((T)1.0 - x * x) / ((T)1.0 + x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T sinh(T x)
|
|
||||||
{
|
|
||||||
return (exp<T>(x) - exp<T>(-x)) / (T)2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T cosh(T x)
|
|
||||||
{
|
|
||||||
return (exp<T>(x) + exp<T>(-x)) / (T)2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T tanh(T x)
|
|
||||||
{
|
|
||||||
const T exp_px = exp<T>(+x);
|
|
||||||
const T exp_nx = exp<T>(-x);
|
|
||||||
return (exp_px - exp_nx) / (exp_px + exp_nx);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T asinh(T x)
|
|
||||||
{
|
|
||||||
return log<T>(x + sqrt<T>(x * x + (T)1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T acosh(T x)
|
|
||||||
{
|
|
||||||
return log<T>(x + sqrt<T>(x * x - (T)1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T atanh(T x)
|
|
||||||
{
|
|
||||||
return (T)0.5 * log<T>(((T)1.0 + x) / ((T)1.0 - x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T hypot(T x, T y)
|
|
||||||
{
|
|
||||||
return sqrt<T>(x * x + y * y);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BAN_MATH_POP_OPTIONS
|
|
||||||
#undef BAN_MATH_POP_OPTIONS
|
|
||||||
#pragma GCC pop_options
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,10 @@
|
|||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
#if defined(__is_kernel)
|
#if defined(__is_kernel)
|
||||||
static constexpr void*(*allocator)(size_t) = kmalloc;
|
static constexpr void*(&allocator)(size_t) = kmalloc;
|
||||||
static constexpr void*(*reallocator)(void*, size_t) = nullptr;
|
static constexpr void(&deallocator)(void*) = kfree;
|
||||||
static constexpr void(*deallocator)(void*) = kfree;
|
|
||||||
#else
|
#else
|
||||||
static constexpr void*(*allocator)(size_t) = malloc;
|
static constexpr void*(&allocator)(size_t) = malloc;
|
||||||
static constexpr void*(*reallocator)(void*, size_t) = realloc;
|
static constexpr void(&deallocator)(void*) = free;
|
||||||
static constexpr void(*deallocator)(void*) = free;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Traits.h>
|
|
||||||
|
|
||||||
namespace BAN::numbers
|
|
||||||
{
|
|
||||||
|
|
||||||
template<floating_point T> inline constexpr T e_v = 2.71828182845904523536;
|
|
||||||
template<floating_point T> inline constexpr T log2e_v = 1.44269504088896340736;
|
|
||||||
template<floating_point T> inline constexpr T lge_v = 0.43429448190325182765;
|
|
||||||
template<floating_point T> inline constexpr T lg2_v = 0.30102999566398119521;
|
|
||||||
template<floating_point T> inline constexpr T ln2_v = 0.69314718055994530942;
|
|
||||||
template<floating_point T> inline constexpr T ln10_v = 2.30258509299404568402;
|
|
||||||
template<floating_point T> inline constexpr T pi_v = 3.14159265358979323846;
|
|
||||||
template<floating_point T> inline constexpr T sqrt2_v = 1.41421356237309504880;
|
|
||||||
template<floating_point T> inline constexpr T sqrt3_v = 1.73205080756887729353;
|
|
||||||
|
|
||||||
inline constexpr double e = e_v<double>;
|
|
||||||
inline constexpr double log2e = log2e_v<double>;
|
|
||||||
inline constexpr double lge = lge_v<double>;
|
|
||||||
inline constexpr double lg2 = lge_v<double>;
|
|
||||||
inline constexpr double ln2 = ln2_v<double>;
|
|
||||||
inline constexpr double ln10 = ln10_v<double>;
|
|
||||||
inline constexpr double pi = pi_v<double>;
|
|
||||||
inline constexpr double sqrt2 = sqrt2_v<double>;
|
|
||||||
inline constexpr double sqrt3 = sqrt3_v<double>;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,7 @@ namespace BAN
|
|||||||
constexpr Optional& operator=(const Optional&);
|
constexpr Optional& operator=(const Optional&);
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr Optional& emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
constexpr Optional& emplace(Args&&...);
|
||||||
|
|
||||||
constexpr T* operator->();
|
constexpr T* operator->();
|
||||||
constexpr const T* operator->() const;
|
constexpr const T* operator->() const;
|
||||||
@@ -111,7 +111,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr Optional<T>& Optional<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
constexpr Optional<T>& Optional<T>::emplace(Args&&... args)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = true;
|
m_has_value = true;
|
||||||
@@ -167,14 +167,14 @@ namespace BAN
|
|||||||
constexpr T& Optional<T>::value()
|
constexpr T& Optional<T>::value()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return *reinterpret_cast<T*>(&m_storage);
|
return (T&)m_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr const T& Optional<T>::value() const
|
constexpr const T& Optional<T>::value() const
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return *reinterpret_cast<const T*>(&m_storage);
|
return (const T&)m_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -182,7 +182,7 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
if (!has_value())
|
if (!has_value())
|
||||||
return empty;
|
return empty;
|
||||||
return value();
|
return (T&)m_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -190,7 +190,7 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
if (!has_value())
|
if (!has_value())
|
||||||
return empty;
|
return empty;
|
||||||
return value();
|
return (const T&)m_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if __has_include(<new>)
|
|
||||||
#include <new>
|
|
||||||
#else
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
inline void* operator new(size_t, void* addr) { return addr; }
|
inline void* operator new(size_t, void* addr) { return addr; }
|
||||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
inline void* operator new[](size_t, void* addr) { return addr; }
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "BAN/Errors.h"
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
#include <BAN/Heap.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename T, typename Comp = less<T>>
|
|
||||||
class PriorityQueue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PriorityQueue() = default;
|
|
||||||
PriorityQueue(Comp comp)
|
|
||||||
: m_comp(comp)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
ErrorOr<void> push(const T& value)
|
|
||||||
{
|
|
||||||
TRY(m_data.push_back(value));
|
|
||||||
push_heap(m_data.begin(), m_data.end());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> push(T&& value)
|
|
||||||
{
|
|
||||||
TRY(m_data.push_back(move(value)));
|
|
||||||
push_heap(m_data.begin(), m_data.end());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<void> emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
{
|
|
||||||
TRY(m_data.emplace_back(forward<Args>(args)...));
|
|
||||||
push_heap(m_data.begin(), m_data.end());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop()
|
|
||||||
{
|
|
||||||
pop_heap(m_data.begin(), m_data.end());
|
|
||||||
m_data.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> reserve(Vector<T>::size_type size)
|
|
||||||
{
|
|
||||||
return m_data.reserve(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
T& top() { return m_data.front(); }
|
|
||||||
const T& top() const { return m_data.front(); }
|
|
||||||
|
|
||||||
bool empty() const { return m_data.empty(); }
|
|
||||||
Vector<T>::size_type size() const { return m_data.size(); }
|
|
||||||
Vector<T>::size_type capacity() const { return m_data.capacity(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Comp m_comp;
|
|
||||||
Vector<T> m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -31,7 +31,7 @@ namespace BAN
|
|||||||
ErrorOr<void> push(T&&);
|
ErrorOr<void> push(T&&);
|
||||||
ErrorOr<void> push(const T&);
|
ErrorOr<void> push(const T&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace(Args&&...);
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type);
|
ErrorOr<void> reserve(size_type);
|
||||||
ErrorOr<void> shrink_to_fit();
|
ErrorOr<void> shrink_to_fit();
|
||||||
@@ -131,7 +131,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Queue<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> Queue<T>::emplace(Args&&... args)
|
||||||
{
|
{
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
new (m_data + m_size) T(forward<Args>(args)...);
|
new (m_data + m_size) T(forward<Args>(args)...);
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include <BAN/Atomic.h>
|
#include <BAN/Atomic.h>
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Hash.h>
|
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
@@ -76,9 +76,8 @@ namespace BAN
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: don't use is_constructible_v<T, Args...> as RefPtr<T> is allowed with friends
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static ErrorOr<RefPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
static ErrorOr<RefPtr> create(Args&&... args)
|
||||||
{
|
{
|
||||||
T* pointer = new T(forward<Args>(args)...);
|
T* pointer = new T(forward<Args>(args)...);
|
||||||
if (pointer == nullptr)
|
if (pointer == nullptr)
|
||||||
@@ -129,9 +128,14 @@ namespace BAN
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* ptr() const { return m_pointer; }
|
T* ptr() { ASSERT(!empty()); return m_pointer; }
|
||||||
T& operator*() const { ASSERT(!empty()); return *ptr(); }
|
const T* ptr() const { ASSERT(!empty()); return m_pointer; }
|
||||||
T* operator->() const { ASSERT(!empty()); return ptr(); }
|
|
||||||
|
T& operator*() { return *ptr(); }
|
||||||
|
const T& operator*() const { return *ptr(); }
|
||||||
|
|
||||||
|
T* operator->() { return ptr(); }
|
||||||
|
const T* operator->() const { return ptr(); }
|
||||||
|
|
||||||
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
|
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
|
||||||
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
|
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
|
||||||
@@ -153,13 +157,4 @@ namespace BAN
|
|||||||
friend class RefPtr;
|
friend class RefPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct hash<RefPtr<T>>
|
|
||||||
{
|
|
||||||
constexpr hash_t operator()(const RefPtr<T>& ptr) const
|
|
||||||
{
|
|
||||||
return hash<T*>()(ptr.ptr());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Heap.h>
|
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Swap.h>
|
#include <BAN/Swap.h>
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
@@ -9,7 +8,7 @@
|
|||||||
namespace BAN::sort
|
namespace BAN::sort
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
void exchange_sort(It begin, It end, Comp comp = {})
|
void exchange_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
for (It lhs = begin; lhs != end; ++lhs)
|
for (It lhs = begin; lhs != end; ++lhs)
|
||||||
@@ -43,7 +42,7 @@ namespace BAN::sort
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
void quick_sort(It begin, It end, Comp comp = {})
|
void quick_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
if (distance(begin, end) <= 1)
|
if (distance(begin, end) <= 1)
|
||||||
@@ -53,14 +52,14 @@ namespace BAN::sort
|
|||||||
quick_sort(++mid, end, comp);
|
quick_sort(++mid, end, comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
void insertion_sort(It begin, It end, Comp comp = {})
|
void insertion_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
if (distance(begin, end) <= 1)
|
if (distance(begin, end) <= 1)
|
||||||
return;
|
return;
|
||||||
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
||||||
{
|
{
|
||||||
auto x = move(*it1);
|
typename It::value_type x = move(*it1);
|
||||||
It it2 = it1;
|
It it2 = it1;
|
||||||
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
||||||
*it2 = move(*prev(it2, 1));
|
*it2 = move(*prev(it2, 1));
|
||||||
@@ -68,7 +67,83 @@ namespace BAN::sort
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename It, typename Comp>
|
||||||
|
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
|
||||||
|
{
|
||||||
|
size_t parent = (hole_index - 1) / 2;
|
||||||
|
while (hole_index > top_index && comp(*next(begin, parent), value))
|
||||||
|
{
|
||||||
|
*next(begin, hole_index) = move(*next(begin, parent));
|
||||||
|
hole_index = parent;
|
||||||
|
parent = (hole_index - 1) / 2;
|
||||||
|
}
|
||||||
|
*next(begin, hole_index) = move(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp>
|
||||||
|
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
|
||||||
|
{
|
||||||
|
const size_t top_index = hole_index;
|
||||||
|
size_t child = hole_index;
|
||||||
|
while (child < (len - 1) / 2)
|
||||||
|
{
|
||||||
|
child = 2 * (child + 1);
|
||||||
|
if (comp(*next(begin, child), *next(begin, child - 1)))
|
||||||
|
child--;
|
||||||
|
*next(begin, hole_index) = move(*next(begin, child));
|
||||||
|
hole_index = child;
|
||||||
|
}
|
||||||
|
if (len % 2 == 0 && child == (len - 2) / 2)
|
||||||
|
{
|
||||||
|
child = 2 * (child + 1);
|
||||||
|
*next(begin, hole_index) = move(*next(begin, child - 1));
|
||||||
|
hole_index = child - 1;
|
||||||
|
}
|
||||||
|
push_heap(begin, hole_index, top_index, move(value), comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
|
void make_heap(It begin, It end, Comp comp = {})
|
||||||
|
{
|
||||||
|
const size_t len = distance(begin, end);
|
||||||
|
if (len <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t parent = (len - 2) / 2;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
|
||||||
|
|
||||||
|
if (parent == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
parent--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
|
void sort_heap(It begin, It end, Comp comp = {})
|
||||||
|
{
|
||||||
|
const size_t len = distance(begin, end);
|
||||||
|
if (len <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t last = len;
|
||||||
|
while (last > 1)
|
||||||
|
{
|
||||||
|
last--;
|
||||||
|
typename It::value_type x = move(*next(begin, last));
|
||||||
|
*next(begin, last) = move(*begin);
|
||||||
|
detail::adjust_heap(begin, 0, last, move(x), comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
void heap_sort(It begin, It end, Comp comp = {})
|
void heap_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
make_heap(begin, end, comp);
|
make_heap(begin, end, comp);
|
||||||
@@ -92,7 +167,7 @@ namespace BAN::sort
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
void intro_sort(It begin, It end, Comp comp = {})
|
void intro_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
const size_t len = distance(begin, end);
|
const size_t len = distance(begin, end);
|
||||||
@@ -115,10 +190,10 @@ namespace BAN::sort
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, size_t radix = 256>
|
template<typename It, size_t radix = 256>
|
||||||
requires is_unsigned_v<it_value_type_t<It>> && (radix > 0 && (radix & (radix - 1)) == 0)
|
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
|
||||||
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
||||||
{
|
{
|
||||||
using value_type = it_value_type_t<It>;
|
using value_type = typename It::value_type;
|
||||||
|
|
||||||
const size_t len = distance(begin, end);
|
const size_t len = distance(begin, end);
|
||||||
if (len <= 1)
|
if (len <= 1)
|
||||||
@@ -156,7 +231,7 @@ namespace BAN::sort
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
void sort(It begin, It end, Comp comp = {})
|
void sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
return intro_sort(begin, end, comp);
|
return intro_sort(begin, end, comp);
|
||||||
|
|||||||
@@ -14,75 +14,116 @@ namespace BAN
|
|||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using iterator = IteratorSimple<value_type, Span>;
|
using iterator = IteratorSimple<T, Span>;
|
||||||
using const_iterator = ConstIteratorSimple<value_type, Span>;
|
using const_iterator = ConstIteratorSimple<T, Span>;
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename S>
|
|
||||||
static inline constexpr bool can_init_from_v = is_same_v<value_type, const S> || is_same_v<value_type, S>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Span() = default;
|
Span() = default;
|
||||||
Span(value_type* data, size_type size)
|
Span(T*, size_type);
|
||||||
: m_data(data)
|
Span(Span<T>&);
|
||||||
, m_size(size)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
Span(const Span<S>& other) requires can_init_from_v<S>
|
requires(is_same_v<T, const S>)
|
||||||
: m_data(other.m_data)
|
Span(const Span<S>&);
|
||||||
, m_size(other.m_size)
|
|
||||||
{ }
|
|
||||||
template<typename S>
|
|
||||||
Span(Span<S>&& other) requires can_init_from_v<S>
|
|
||||||
: m_data(other.m_data)
|
|
||||||
, m_size(other.m_size)
|
|
||||||
{
|
|
||||||
other.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
Span& operator=(const Span<S>& other) requires can_init_from_v<S>
|
|
||||||
{
|
|
||||||
m_data = other.m_data;
|
|
||||||
m_size = other.m_size;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
template<typename S>
|
|
||||||
Span& operator=(Span<S>&& other) requires can_init_from_v<S>
|
|
||||||
{
|
|
||||||
m_data = other.m_data;
|
|
||||||
m_size = other.m_size;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
iterator end() { return iterator(m_data + m_size); }
|
iterator end() { return iterator(m_data + m_size); }
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||||
|
|
||||||
value_type& operator[](size_type index) const
|
T& operator[](size_type);
|
||||||
|
const T& operator[](size_type) const;
|
||||||
|
|
||||||
|
T* data();
|
||||||
|
const T* data() const;
|
||||||
|
|
||||||
|
bool empty() const;
|
||||||
|
size_type size() const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
Span slice(size_type, size_type = ~size_type(0));
|
||||||
|
|
||||||
|
Span<const T> as_const() const { return Span<const T>(m_data, m_size); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* m_data = nullptr;
|
||||||
|
size_type m_size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Span<T>::Span(T* data, size_type size)
|
||||||
|
: m_data(data)
|
||||||
|
, m_size(size)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Span<T>::Span(Span& other)
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
template<typename S>
|
||||||
|
requires(is_same_v<T, const S>)
|
||||||
|
Span<T>::Span(const Span<S>& other)
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T& Span<T>::operator[](size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
ASSERT(index < m_size);
|
ASSERT(index < m_size);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type* data() const
|
template<typename T>
|
||||||
|
const T& Span<T>::operator[](size_type index) const
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Span<T>::data()
|
||||||
{
|
{
|
||||||
return m_data;
|
return m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const { return m_size == 0; }
|
template<typename T>
|
||||||
size_type size() const { return m_size; }
|
const T* Span<T>::data() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
void clear()
|
template<typename T>
|
||||||
|
bool Span<T>::empty() const
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename Span<T>::size_type Span<T>::size() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Span<T>::clear()
|
||||||
{
|
{
|
||||||
m_data = nullptr;
|
m_data = nullptr;
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Span slice(size_type start, size_type length = ~size_type(0)) const
|
template<typename T>
|
||||||
|
Span<T> Span<T>::slice(size_type start, size_type length)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
ASSERT(start <= m_size);
|
ASSERT(start <= m_size);
|
||||||
if (length == ~size_type(0))
|
if (length == ~size_type(0))
|
||||||
length = m_size - start;
|
length = m_size - start;
|
||||||
@@ -90,13 +131,4 @@ namespace BAN
|
|||||||
return Span(m_data + start, length);
|
return Span(m_data + start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<const value_type> as_const() const { return *this; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
value_type* m_data = nullptr;
|
|
||||||
size_type m_size = 0;
|
|
||||||
|
|
||||||
friend class Span<const value_type>;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using value_type = char;
|
|
||||||
using iterator = IteratorSimple<char, String>;
|
using iterator = IteratorSimple<char, String>;
|
||||||
using const_iterator = ConstIteratorSimple<char, String>;
|
using const_iterator = ConstIteratorSimple<char, String>;
|
||||||
static constexpr size_type sso_capacity = 15;
|
static constexpr size_type sso_capacity = 15;
|
||||||
@@ -128,7 +127,7 @@ namespace BAN
|
|||||||
void remove(size_type index)
|
void remove(size_type index)
|
||||||
{
|
{
|
||||||
ASSERT(index < m_size);
|
ASSERT(index < m_size);
|
||||||
memmove(data() + index, data() + index + 1, m_size - index);
|
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||||
m_size--;
|
m_size--;
|
||||||
data()[m_size] = '\0';
|
data()[m_size] = '\0';
|
||||||
}
|
}
|
||||||
@@ -353,9 +352,10 @@ namespace BAN::Formatter
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void print_argument(F putc, const String& string, const ValueFormat& format)
|
void print_argument(F putc, const String& string, const ValueFormat&)
|
||||||
{
|
{
|
||||||
print_argument(putc, string.sv(), format);
|
for (String::size_type i = 0; i < string.size(); i++)
|
||||||
|
putc(string[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using value_type = char;
|
|
||||||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -22,8 +21,7 @@ namespace BAN
|
|||||||
constexpr StringView(const char* string, size_type len = -1)
|
constexpr StringView(const char* string, size_type len = -1)
|
||||||
{
|
{
|
||||||
if (len == size_type(-1))
|
if (len == size_type(-1))
|
||||||
for (len = 0; string[len];)
|
len = strlen(string);
|
||||||
len++;
|
|
||||||
m_data = string;
|
m_data = string;
|
||||||
m_size = len;
|
m_size = len;
|
||||||
}
|
}
|
||||||
@@ -188,11 +186,16 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
if (target.size() > m_size)
|
if (target.size() > m_size)
|
||||||
return false;
|
return false;
|
||||||
for (size_type i = 0; i < target.size(); i++)
|
for (size_type i = 0; i < m_size - target.size(); i++)
|
||||||
if (m_data[i] != target[i])
|
{
|
||||||
return false;
|
bool valid = true;
|
||||||
|
for (size_type j = 0; j < target.size() && valid; j++)
|
||||||
|
valid = (m_data[i + j] == target[j]);
|
||||||
|
if (valid)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr bool contains(char ch) const
|
constexpr bool contains(char ch) const
|
||||||
{
|
{
|
||||||
@@ -247,12 +250,10 @@ namespace BAN::Formatter
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void print_argument(F putc, const StringView& sv, const ValueFormat& format)
|
void print_argument(F putc, const StringView& sv, const ValueFormat&)
|
||||||
{
|
{
|
||||||
for (StringView::size_type i = 0; i < sv.size(); i++)
|
for (StringView::size_type i = 0; i < sv.size(); i++)
|
||||||
putc(sv[i]);
|
putc(sv[i]);
|
||||||
for (int i = sv.size(); i < format.fill; i++)
|
|
||||||
putc(' ');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,6 @@ namespace BAN
|
|||||||
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
||||||
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
||||||
|
|
||||||
template<typename T> struct is_trivially_copyable { static constexpr bool value = __is_trivially_copyable(T); };
|
|
||||||
template<typename T> inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
|
|
||||||
|
|
||||||
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
||||||
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
||||||
template<typename T> concept integral = is_integral_v<T>;
|
template<typename T> concept integral = is_integral_v<T>;
|
||||||
@@ -93,9 +90,6 @@ namespace BAN
|
|||||||
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
||||||
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
||||||
|
|
||||||
template<typename T> struct is_pod { static constexpr bool value = __is_pod(T); };
|
|
||||||
template<typename T> inline constexpr bool is_pod_v = is_pod<T>::value;
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
||||||
@@ -142,10 +136,6 @@ namespace BAN
|
|||||||
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
||||||
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
||||||
|
|
||||||
template<typename T> struct it_value_type { using value_type = T::value_type; };
|
|
||||||
template<typename T> struct it_value_type<T*> { using value_type = T; };
|
|
||||||
template<typename T> using it_value_type_t = typename it_value_type<T>::value_type;
|
|
||||||
|
|
||||||
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
||||||
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
||||||
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace BAN::UTF8
|
|||||||
return 3;
|
return 3;
|
||||||
if ((first_byte & 0xF8) == 0xF0)
|
if ((first_byte & 0xF8) == 0xF0)
|
||||||
return 4;
|
return 4;
|
||||||
return UTF8::invalid;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> requires (sizeof(T) == 1)
|
template<typename T> requires (sizeof(T) == 1)
|
||||||
@@ -76,8 +76,6 @@ namespace BAN::UTF8
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*ptr = '\0';
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Hash.h>
|
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
@@ -34,9 +33,8 @@ namespace BAN
|
|||||||
return uniq;
|
return uniq;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: don't use is_constructible_v<T, Args...> as UniqPtr<T> is allowed with friends
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static BAN::ErrorOr<UniqPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
static BAN::ErrorOr<UniqPtr> create(Args&&... args)
|
||||||
{
|
{
|
||||||
UniqPtr uniq;
|
UniqPtr uniq;
|
||||||
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
||||||
@@ -54,12 +52,32 @@ namespace BAN
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* ptr() const { return m_pointer; }
|
T& operator*()
|
||||||
T& operator*() const { ASSERT(!empty()); return *ptr(); }
|
{
|
||||||
T* operator->() const { ASSERT(!empty()); return ptr(); }
|
ASSERT(m_pointer);
|
||||||
|
return *m_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
bool empty() const { return m_pointer == nullptr; }
|
const T& operator*() const
|
||||||
explicit operator bool() const { return m_pointer; }
|
{
|
||||||
|
ASSERT(m_pointer);
|
||||||
|
return *m_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator->()
|
||||||
|
{
|
||||||
|
ASSERT(m_pointer);
|
||||||
|
return m_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* operator->() const
|
||||||
|
{
|
||||||
|
ASSERT(m_pointer);
|
||||||
|
return m_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* ptr() { return m_pointer; }
|
||||||
|
const T* ptr() const { return m_pointer; }
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
@@ -68,6 +86,8 @@ namespace BAN
|
|||||||
m_pointer = nullptr;
|
m_pointer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator bool() const { return m_pointer != nullptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* m_pointer = nullptr;
|
T* m_pointer = nullptr;
|
||||||
|
|
||||||
@@ -75,13 +95,4 @@ namespace BAN
|
|||||||
friend class UniqPtr;
|
friend class UniqPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct hash<UniqPtr<T>>
|
|
||||||
{
|
|
||||||
constexpr hash_t operator()(const UniqPtr<T>& ptr) const
|
|
||||||
{
|
|
||||||
return hash<T*>()(ptr.ptr());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ namespace BAN
|
|||||||
Variant(Variant&& other)
|
Variant(Variant&& other)
|
||||||
: m_index(other.m_index)
|
: m_index(other.m_index)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
|
||||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
other.clear();
|
other.clear();
|
||||||
}
|
}
|
||||||
@@ -134,7 +133,6 @@ namespace BAN
|
|||||||
Variant(const Variant& other)
|
Variant(const Variant& other)
|
||||||
: m_index(other.m_index)
|
: m_index(other.m_index)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
|
||||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,12 +157,11 @@ namespace BAN
|
|||||||
|
|
||||||
Variant& operator=(Variant&& other)
|
Variant& operator=(Variant&& other)
|
||||||
{
|
{
|
||||||
if (m_index == other.m_index && m_index != invalid_index())
|
if (m_index == other.m_index)
|
||||||
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
|
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
if (other.has_value())
|
|
||||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
}
|
}
|
||||||
@@ -174,12 +171,11 @@ namespace BAN
|
|||||||
|
|
||||||
Variant& operator=(const Variant& other)
|
Variant& operator=(const Variant& other)
|
||||||
{
|
{
|
||||||
if (m_index == other.m_index && m_index != invalid_index())
|
if (m_index == other.m_index)
|
||||||
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
|
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
if (other.has_value())
|
|
||||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
}
|
}
|
||||||
@@ -221,7 +217,7 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
void emplace(Args&&... args) requires (can_have<T>() && is_constructible_v<T, Args...>)
|
void emplace(Args&&... args) requires (can_have<T>())
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_index = detail::index<T, Ts...>();
|
m_index = detail::index<T, Ts...>();
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ namespace BAN
|
|||||||
ErrorOr<void> push_back(T&&);
|
ErrorOr<void> push_back(T&&);
|
||||||
ErrorOr<void> push_back(const T&);
|
ErrorOr<void> push_back(const T&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace_back(Args&&...);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(size_type, Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace(size_type, Args&&...);
|
||||||
ErrorOr<void> insert(size_type, T&&);
|
ErrorOr<void> insert(size_type, T&&);
|
||||||
ErrorOr<void> insert(size_type, const T&);
|
ErrorOr<void> insert(size_type, const T&);
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ namespace BAN
|
|||||||
bool contains(const T&) const;
|
bool contains(const T&) const;
|
||||||
|
|
||||||
Span<T> span() { return Span(m_data, m_size); }
|
Span<T> span() { return Span(m_data, m_size); }
|
||||||
Span<const T> span() const { return Span(m_data, m_size); }
|
const Span<T> span() const { return Span(m_data, m_size); }
|
||||||
|
|
||||||
const T& operator[](size_type) const;
|
const T& operator[](size_type) const;
|
||||||
T& operator[](size_type);
|
T& operator[](size_type);
|
||||||
@@ -169,7 +169,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Vector<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> Vector<T>::emplace_back(Args&&... args)
|
||||||
{
|
{
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
new (m_data + m_size) T(forward<Args>(args)...);
|
new (m_data + m_size) T(forward<Args>(args)...);
|
||||||
@@ -179,7 +179,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Vector<T>::emplace(size_type index, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> Vector<T>::emplace(size_type index, Args&&... args)
|
||||||
{
|
{
|
||||||
ASSERT(index <= m_size);
|
ASSERT(index <= m_size);
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
@@ -381,35 +381,10 @@ namespace BAN
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> Vector<T>::ensure_capacity(size_type size)
|
ErrorOr<void> Vector<T>::ensure_capacity(size_type size)
|
||||||
{
|
{
|
||||||
static_assert(alignof(T) <= alignof(max_align_t), "over aligned types not supported");
|
|
||||||
|
|
||||||
if (m_capacity >= size)
|
if (m_capacity >= size)
|
||||||
return {};
|
return {};
|
||||||
|
size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
|
||||||
const size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
|
T* new_data = (T*)BAN::allocator(new_cap * sizeof(T));
|
||||||
|
|
||||||
if constexpr (BAN::is_trivially_copyable_v<T>)
|
|
||||||
{
|
|
||||||
if constexpr (BAN::reallocator)
|
|
||||||
{
|
|
||||||
auto* new_data = static_cast<T*>(BAN::reallocator(m_data, new_cap * sizeof(T)));
|
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
m_data = new_data;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
|
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
memcpy(new_data, m_data, m_size * sizeof(T));
|
|
||||||
BAN::deallocator(m_data);
|
|
||||||
m_data = new_data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
|
|
||||||
if (new_data == nullptr)
|
if (new_data == nullptr)
|
||||||
return Error::from_errno(ENOMEM);
|
return Error::from_errno(ENOMEM);
|
||||||
for (size_type i = 0; i < m_size; i++)
|
for (size_type i = 0; i < m_size; i++)
|
||||||
@@ -419,8 +394,6 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
BAN::deallocator(m_data);
|
BAN::deallocator(m_data);
|
||||||
m_data = new_data;
|
m_data = new_data;
|
||||||
}
|
|
||||||
|
|
||||||
m_capacity = new_cap;
|
m_capacity = new_cap;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace BAN
|
|||||||
class WeakLink : public RefCounted<WeakLink<T>>
|
class WeakLink : public RefCounted<WeakLink<T>>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RefPtr<T> try_lock() const
|
RefPtr<T> try_lock()
|
||||||
{
|
{
|
||||||
#if __is_kernel
|
#if __is_kernel
|
||||||
Kernel::SpinLockGuard _(m_weak_lock);
|
Kernel::SpinLockGuard _(m_weak_lock);
|
||||||
@@ -44,7 +44,7 @@ namespace BAN
|
|||||||
private:
|
private:
|
||||||
T* m_ptr;
|
T* m_ptr;
|
||||||
#if __is_kernel
|
#if __is_kernel
|
||||||
mutable Kernel::SpinLock m_weak_lock;
|
Kernel::SpinLock m_weak_lock;
|
||||||
#endif
|
#endif
|
||||||
friend class RefPtr<WeakLink<T>>;
|
friend class RefPtr<WeakLink<T>>;
|
||||||
};
|
};
|
||||||
@@ -99,7 +99,7 @@ namespace BAN
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<T> lock() const
|
RefPtr<T> lock()
|
||||||
{
|
{
|
||||||
if (m_link)
|
if (m_link)
|
||||||
return m_link->try_lock();
|
return m_link->try_lock();
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
|
|||||||
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
set(BANAN_ENABLE_SSE 1)
|
||||||
|
|
||||||
project(banan-os CXX C ASM)
|
project(banan-os CXX C ASM)
|
||||||
|
|
||||||
|
set(BANAN_BASE_SYSROOT ${CMAKE_SOURCE_DIR}/base-sysroot.tar.gz)
|
||||||
|
|
||||||
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
||||||
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
||||||
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
||||||
@@ -25,16 +29,17 @@ set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
|||||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||||
set(BUILD_SHARED_LIBS True)
|
set(BUILD_SHARED_LIBS True)
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||||
|
|
||||||
# include headers of ${library} to ${target}
|
# include headers of ${library} to ${target}
|
||||||
function(banan_include_headers target library)
|
function(banan_include_headers target library)
|
||||||
target_include_directories(${target} PUBLIC $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
target_include_directories(${target} PRIVATE $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# include headers and link ${library} to ${target}
|
# include headers and link ${library} to ${target}
|
||||||
function(banan_link_library target library)
|
function(banan_link_library target library)
|
||||||
target_link_libraries(${target} PUBLIC ${library})
|
target_link_libraries(${target} PRIVATE ${library})
|
||||||
banan_include_headers(${target} ${library})
|
banan_include_headers(${target} ${library})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
@@ -52,3 +57,8 @@ add_subdirectory(kernel)
|
|||||||
add_subdirectory(bootloader)
|
add_subdirectory(bootloader)
|
||||||
add_subdirectory(BAN)
|
add_subdirectory(BAN)
|
||||||
add_subdirectory(userspace)
|
add_subdirectory(userspace)
|
||||||
|
|
||||||
|
add_custom_target(sysroot
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${BANAN_SYSROOT}
|
||||||
|
COMMAND cd ${BANAN_SYSROOT} && tar xf ${BANAN_BASE_SYSROOT}
|
||||||
|
)
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -9,8 +9,6 @@ This is my hobby operating system written in C++. Currently supports x86\_64 and
|
|||||||
|
|
||||||
You can find a live demo [here](https://bananymous.com/banan-os)
|
You can find a live demo [here](https://bananymous.com/banan-os)
|
||||||
|
|
||||||
If you want to try out DOOM, you should first enter the GUI environment using the `start-gui` command. Then you can run `doom` in the GUI terminal.
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
#### General
|
#### General
|
||||||
@@ -22,8 +20,8 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [x] AML interpreter (partial)
|
- [x] AML interpreter (partial)
|
||||||
- [x] Basic graphical environment
|
- [x] Basic graphical environment
|
||||||
- [x] Terminal emulator
|
- [x] Terminal emulator
|
||||||
- [x] Status bar
|
- [ ] Task bar
|
||||||
- [x] Program launcher
|
- [ ] Program launcher
|
||||||
- [ ] Some nice apps
|
- [ ] Some nice apps
|
||||||
- [x] ELF dynamic linking
|
- [x] ELF dynamic linking
|
||||||
- [x] copy-on-write memory
|
- [x] copy-on-write memory
|
||||||
@@ -34,18 +32,13 @@ If you want to try out DOOM, you should first enter the GUI environment using th
|
|||||||
- [x] NVMe disks
|
- [x] NVMe disks
|
||||||
- [x] ATA (IDE, SATA) disks
|
- [x] ATA (IDE, SATA) disks
|
||||||
- [x] E1000 and E1000E NICs
|
- [x] E1000 and E1000E NICs
|
||||||
- [x] RTL8111/8168/8211/8411 NICs
|
|
||||||
- [x] PS2 keyboard (all scancode sets)
|
- [x] PS2 keyboard (all scancode sets)
|
||||||
- [x] PS2 mouse
|
- [x] PS2 mouse
|
||||||
- [x] USB
|
- [x] USB
|
||||||
- [x] xHCI
|
|
||||||
- [ ] EHCI
|
|
||||||
- [ ] OHCI
|
|
||||||
- [ ] UHCI
|
|
||||||
- [x] Keyboard
|
- [x] Keyboard
|
||||||
- [x] Mouse
|
- [x] Mouse
|
||||||
- [x] Mass storage
|
- [ ] Hubs
|
||||||
- [x] Hubs
|
- [ ] Mass storage
|
||||||
- [ ] ...
|
- [ ] ...
|
||||||
- [ ] virtio devices (network, storage)
|
- [ ] virtio devices (network, storage)
|
||||||
|
|
||||||
@@ -118,8 +111,6 @@ To change the bootloader you can set environment variable BANAN\_BOOTLOADER; sup
|
|||||||
|
|
||||||
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
|
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
|
||||||
|
|
||||||
To build an image with no physical root filesystem, but an initrd set environment variable BANAN\_INITRD=1. This can be used when testing on hardware with unsupported USB controller.
|
|
||||||
|
|
||||||
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
||||||
```sh
|
```sh
|
||||||
./bos image-full
|
./bos image-full
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
@@ -84,4 +84,4 @@ command_line:
|
|||||||
# 100 character command line
|
# 100 character command line
|
||||||
command_line_buffer:
|
command_line_buffer:
|
||||||
.ascii "root=/dev/sda2"
|
.ascii "root=/dev/sda2"
|
||||||
.skip 100 - (. - command_line_buffer)
|
.skip 100 - 28
|
||||||
|
|||||||
@@ -306,8 +306,20 @@ memset32:
|
|||||||
movw $GDT_DATA32, %dx
|
movw $GDT_DATA32, %dx
|
||||||
movw %dx, %es
|
movw %dx, %es
|
||||||
|
|
||||||
|
movl %ecx, %edx
|
||||||
|
|
||||||
|
andl $3, %ecx
|
||||||
rep stosb %es:(%edi)
|
rep stosb %es:(%edi)
|
||||||
|
|
||||||
|
movl %edx, %ecx
|
||||||
|
shrl $2, %ecx
|
||||||
|
|
||||||
|
movb %al, %ah
|
||||||
|
movw %ax, %dx
|
||||||
|
shll $16, %eax
|
||||||
|
movw %dx, %ax
|
||||||
|
rep stosl %es:(%edi)
|
||||||
|
|
||||||
ljmpl $GDT_CODE16, $.memset32_pmode16
|
ljmpl $GDT_CODE16, $.memset32_pmode16
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
@@ -358,8 +370,14 @@ memcpy32:
|
|||||||
movw %dx, %ds
|
movw %dx, %ds
|
||||||
movw %dx, %es
|
movw %dx, %es
|
||||||
|
|
||||||
|
movl %ecx, %edx
|
||||||
|
andl $3, %ecx
|
||||||
rep movsb %ds:(%esi), %es:(%edi)
|
rep movsb %ds:(%esi), %es:(%edi)
|
||||||
|
|
||||||
|
movl %edx, %ecx
|
||||||
|
shrl $2, %ecx
|
||||||
|
rep movsl %ds:(%esi), %es:(%edi)
|
||||||
|
|
||||||
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
font/prefs.psf.o
|
font/prefs.psf.o
|
||||||
kernel/ACPI/ACPI.cpp
|
kernel/ACPI/ACPI.cpp
|
||||||
|
kernel/ACPI/AML.cpp
|
||||||
|
kernel/ACPI/AML/Field.cpp
|
||||||
|
kernel/ACPI/AML/Integer.cpp
|
||||||
|
kernel/ACPI/AML/NamedObject.cpp
|
||||||
kernel/ACPI/AML/Namespace.cpp
|
kernel/ACPI/AML/Namespace.cpp
|
||||||
kernel/ACPI/AML/Node.cpp
|
kernel/ACPI/AML/Node.cpp
|
||||||
kernel/ACPI/AML/OpRegion.cpp
|
kernel/ACPI/AML/Package.cpp
|
||||||
kernel/ACPI/BatterySystem.cpp
|
kernel/ACPI/AML/Register.cpp
|
||||||
kernel/ACPI/EmbeddedController.cpp
|
kernel/ACPI/AML/Scope.cpp
|
||||||
|
kernel/ACPI/AML/String.cpp
|
||||||
kernel/APIC.cpp
|
kernel/APIC.cpp
|
||||||
kernel/Audio/AC97/Controller.cpp
|
|
||||||
kernel/Audio/Controller.cpp
|
|
||||||
kernel/Audio/HDAudio/AudioFunctionGroup.cpp
|
|
||||||
kernel/Audio/HDAudio/Controller.cpp
|
|
||||||
kernel/BootInfo.cpp
|
kernel/BootInfo.cpp
|
||||||
kernel/CPUID.cpp
|
kernel/CPUID.cpp
|
||||||
kernel/Credentials.cpp
|
kernel/Credentials.cpp
|
||||||
@@ -22,10 +23,8 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Device/RandomDevice.cpp
|
kernel/Device/RandomDevice.cpp
|
||||||
kernel/Device/ZeroDevice.cpp
|
kernel/Device/ZeroDevice.cpp
|
||||||
kernel/ELF.cpp
|
kernel/ELF.cpp
|
||||||
kernel/Epoll.cpp
|
|
||||||
kernel/Errors.cpp
|
kernel/Errors.cpp
|
||||||
kernel/FS/DevFS/FileSystem.cpp
|
kernel/FS/DevFS/FileSystem.cpp
|
||||||
kernel/FS/EventFD.cpp
|
|
||||||
kernel/FS/Ext2/FileSystem.cpp
|
kernel/FS/Ext2/FileSystem.cpp
|
||||||
kernel/FS/Ext2/Inode.cpp
|
kernel/FS/Ext2/Inode.cpp
|
||||||
kernel/FS/FAT/FileSystem.cpp
|
kernel/FS/FAT/FileSystem.cpp
|
||||||
@@ -37,7 +36,6 @@ set(KERNEL_SOURCES
|
|||||||
kernel/FS/ProcFS/Inode.cpp
|
kernel/FS/ProcFS/Inode.cpp
|
||||||
kernel/FS/TmpFS/FileSystem.cpp
|
kernel/FS/TmpFS/FileSystem.cpp
|
||||||
kernel/FS/TmpFS/Inode.cpp
|
kernel/FS/TmpFS/Inode.cpp
|
||||||
kernel/FS/USTARModule.cpp
|
|
||||||
kernel/FS/VirtualFileSystem.cpp
|
kernel/FS/VirtualFileSystem.cpp
|
||||||
kernel/GDT.cpp
|
kernel/GDT.cpp
|
||||||
kernel/IDT.cpp
|
kernel/IDT.cpp
|
||||||
@@ -50,8 +48,6 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Interruptable.cpp
|
kernel/Interruptable.cpp
|
||||||
kernel/InterruptController.cpp
|
kernel/InterruptController.cpp
|
||||||
kernel/kernel.cpp
|
kernel/kernel.cpp
|
||||||
kernel/Lock/SpinLock.cpp
|
|
||||||
kernel/Memory/ByteRingBuffer.cpp
|
|
||||||
kernel/Memory/DMARegion.cpp
|
kernel/Memory/DMARegion.cpp
|
||||||
kernel/Memory/FileBackedRegion.cpp
|
kernel/Memory/FileBackedRegion.cpp
|
||||||
kernel/Memory/Heap.cpp
|
kernel/Memory/Heap.cpp
|
||||||
@@ -65,12 +61,10 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Networking/E1000/E1000.cpp
|
kernel/Networking/E1000/E1000.cpp
|
||||||
kernel/Networking/E1000/E1000E.cpp
|
kernel/Networking/E1000/E1000E.cpp
|
||||||
kernel/Networking/IPv4Layer.cpp
|
kernel/Networking/IPv4Layer.cpp
|
||||||
kernel/Networking/Loopback.cpp
|
|
||||||
kernel/Networking/NetworkInterface.cpp
|
kernel/Networking/NetworkInterface.cpp
|
||||||
kernel/Networking/NetworkLayer.cpp
|
kernel/Networking/NetworkLayer.cpp
|
||||||
kernel/Networking/NetworkManager.cpp
|
kernel/Networking/NetworkManager.cpp
|
||||||
kernel/Networking/NetworkSocket.cpp
|
kernel/Networking/NetworkSocket.cpp
|
||||||
kernel/Networking/RTL8169/RTL8169.cpp
|
|
||||||
kernel/Networking/TCPSocket.cpp
|
kernel/Networking/TCPSocket.cpp
|
||||||
kernel/Networking/UDPSocket.cpp
|
kernel/Networking/UDPSocket.cpp
|
||||||
kernel/Networking/UNIX/Socket.cpp
|
kernel/Networking/UNIX/Socket.cpp
|
||||||
@@ -82,6 +76,7 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Processor.cpp
|
kernel/Processor.cpp
|
||||||
kernel/Random.cpp
|
kernel/Random.cpp
|
||||||
kernel/Scheduler.cpp
|
kernel/Scheduler.cpp
|
||||||
|
kernel/ThreadBlocker.cpp
|
||||||
kernel/SSP.cpp
|
kernel/SSP.cpp
|
||||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||||
kernel/Storage/ATA/AHCI/Device.cpp
|
kernel/Storage/ATA/AHCI/Device.cpp
|
||||||
@@ -93,31 +88,22 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Storage/NVMe/Namespace.cpp
|
kernel/Storage/NVMe/Namespace.cpp
|
||||||
kernel/Storage/NVMe/Queue.cpp
|
kernel/Storage/NVMe/Queue.cpp
|
||||||
kernel/Storage/Partition.cpp
|
kernel/Storage/Partition.cpp
|
||||||
kernel/Storage/SCSI.cpp
|
|
||||||
kernel/Storage/StorageDevice.cpp
|
kernel/Storage/StorageDevice.cpp
|
||||||
kernel/Syscall.cpp
|
kernel/Syscall.cpp
|
||||||
kernel/Terminal/FramebufferTerminal.cpp
|
kernel/Terminal/FramebufferTerminal.cpp
|
||||||
kernel/Terminal/PseudoTerminal.cpp
|
kernel/Terminal/PseudoTerminal.cpp
|
||||||
kernel/Terminal/Serial.cpp
|
kernel/Terminal/Serial.cpp
|
||||||
kernel/Terminal/TerminalDriver.cpp
|
|
||||||
kernel/Terminal/TextModeTerminal.cpp
|
|
||||||
kernel/Terminal/TTY.cpp
|
kernel/Terminal/TTY.cpp
|
||||||
kernel/Terminal/VirtualTTY.cpp
|
kernel/Terminal/VirtualTTY.cpp
|
||||||
kernel/Thread.cpp
|
kernel/Thread.cpp
|
||||||
kernel/ThreadBlocker.cpp
|
|
||||||
kernel/Timer/HPET.cpp
|
kernel/Timer/HPET.cpp
|
||||||
kernel/Timer/PIT.cpp
|
kernel/Timer/PIT.cpp
|
||||||
kernel/Timer/RTC.cpp
|
kernel/Timer/RTC.cpp
|
||||||
kernel/Timer/Timer.cpp
|
kernel/Timer/Timer.cpp
|
||||||
kernel/USB/Controller.cpp
|
|
||||||
kernel/USB/Device.cpp
|
kernel/USB/Device.cpp
|
||||||
kernel/USB/HID/HIDDriver.cpp
|
kernel/USB/HID/HIDDriver.cpp
|
||||||
kernel/USB/HID/Joystick.cpp
|
|
||||||
kernel/USB/HID/Keyboard.cpp
|
kernel/USB/HID/Keyboard.cpp
|
||||||
kernel/USB/HID/Mouse.cpp
|
kernel/USB/HID/Mouse.cpp
|
||||||
kernel/USB/Hub/HubDriver.cpp
|
|
||||||
kernel/USB/MassStorage/MassStorageDriver.cpp
|
|
||||||
kernel/USB/MassStorage/SCSIDevice.cpp
|
|
||||||
kernel/USB/USBManager.cpp
|
kernel/USB/USBManager.cpp
|
||||||
kernel/USB/XHCI/Controller.cpp
|
kernel/USB/XHCI/Controller.cpp
|
||||||
kernel/USB/XHCI/Device.cpp
|
kernel/USB/XHCI/Device.cpp
|
||||||
@@ -139,8 +125,6 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|||||||
arch/x86_64/Signal.S
|
arch/x86_64/Signal.S
|
||||||
arch/x86_64/Syscall.S
|
arch/x86_64/Syscall.S
|
||||||
arch/x86_64/Thread.S
|
arch/x86_64/Thread.S
|
||||||
arch/x86_64/User.S
|
|
||||||
arch/x86_64/Yield.S
|
|
||||||
)
|
)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
@@ -151,8 +135,6 @@ elseif("${BANAN_ARCH}" STREQUAL "i686")
|
|||||||
arch/i686/Signal.S
|
arch/i686/Signal.S
|
||||||
arch/i686/Syscall.S
|
arch/i686/Syscall.S
|
||||||
arch/i686/Thread.S
|
arch/i686/Thread.S
|
||||||
arch/i686/User.S
|
|
||||||
arch/i686/Yield.S
|
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
||||||
@@ -168,13 +150,6 @@ set(BAN_SOURCES
|
|||||||
set(KLIBC_SOURCES
|
set(KLIBC_SOURCES
|
||||||
klibc/ctype.cpp
|
klibc/ctype.cpp
|
||||||
klibc/string.cpp
|
klibc/string.cpp
|
||||||
klibc/arch/${BANAN_ARCH}/string.S
|
|
||||||
)
|
|
||||||
|
|
||||||
set(LIBDEFLATE_SOURCE
|
|
||||||
../userspace/libraries/LibDEFLATE/Compressor.cpp
|
|
||||||
../userspace/libraries/LibDEFLATE/Decompressor.cpp
|
|
||||||
../userspace/libraries/LibDEFLATE/HuffmanTree.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBFONT_SOURCES
|
set(LIBFONT_SOURCES
|
||||||
@@ -187,25 +162,19 @@ set(LIBINPUT_SOURCE
|
|||||||
../userspace/libraries/LibInput/KeyEvent.cpp
|
../userspace/libraries/LibInput/KeyEvent.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBQR_SOURCE
|
|
||||||
../userspace/libraries/LibQR/QRCode.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
${BAN_SOURCES}
|
${BAN_SOURCES}
|
||||||
${KLIBC_SOURCES}
|
${KLIBC_SOURCES}
|
||||||
${LIBDEFLATE_SOURCE}
|
|
||||||
${LIBFONT_SOURCES}
|
${LIBFONT_SOURCES}
|
||||||
${LIBINPUT_SOURCE}
|
${LIBINPUT_SOURCE}
|
||||||
${LIBQR_SOURCE}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(kernel ${KERNEL_SOURCES})
|
add_executable(kernel ${KERNEL_SOURCES})
|
||||||
|
|
||||||
target_compile_definitions(kernel PRIVATE __is_kernel)
|
target_compile_definitions(kernel PRIVATE __is_kernel)
|
||||||
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
|
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
|
||||||
target_compile_definitions(kernel PRIVATE LIBDEFLATE_AVOID_STACK=1)
|
target_compile_definitions(kernel PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||||
|
|
||||||
target_compile_options(kernel PRIVATE
|
target_compile_options(kernel PRIVATE
|
||||||
-O2 -g
|
-O2 -g
|
||||||
@@ -259,11 +228,9 @@ add_custom_command(
|
|||||||
|
|
||||||
banan_include_headers(kernel ban)
|
banan_include_headers(kernel ban)
|
||||||
banan_include_headers(kernel libc)
|
banan_include_headers(kernel libc)
|
||||||
banan_include_headers(kernel libdeflate)
|
|
||||||
banan_include_headers(kernel libelf)
|
|
||||||
banan_include_headers(kernel libfont)
|
banan_include_headers(kernel libfont)
|
||||||
|
banan_include_headers(kernel libelf)
|
||||||
banan_include_headers(kernel libinput)
|
banan_include_headers(kernel libinput)
|
||||||
banan_include_headers(kernel libqr)
|
|
||||||
|
|
||||||
banan_install_headers(kernel)
|
banan_install_headers(kernel)
|
||||||
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)
|
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)
|
||||||
@@ -277,7 +244,7 @@ endif()
|
|||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT font/prefs.psf.o
|
OUTPUT font/prefs.psf.o
|
||||||
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/font && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
|
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_COMPILER} <CMAKE_CXX_LINK_FLAGS> <FLAGS> <LINK_FLAGS> -o <TARGET> ${CMAKE_CURRENT_BINARY_DIR}/crti.o ${CMAKE_CURRENT_BINARY_DIR}/crtbegin.o <OBJECTS> ${CMAKE_CURRENT_BINARY_DIR}/crtend.o ${CMAKE_CURRENT_BINARY_DIR}/crtn.o -lgcc ")
|
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_COMPILER} <CMAKE_CXX_LINK_FLAGS> <FLAGS> <LINK_FLAGS> -o <TARGET> ${CMAKE_CURRENT_BINARY_DIR}/crti.o ${CMAKE_CURRENT_BINARY_DIR}/crtbegin.o <OBJECTS> ${CMAKE_CURRENT_BINARY_DIR}/crtend.o ${CMAKE_CURRENT_BINARY_DIR}/crtn.o -lgcc ")
|
||||||
|
|||||||
@@ -16,18 +16,11 @@ extern uint8_t g_kernel_writable_end[];
|
|||||||
extern uint8_t g_userspace_start[];
|
extern uint8_t g_userspace_start[];
|
||||||
extern uint8_t g_userspace_end[];
|
extern uint8_t g_userspace_end[];
|
||||||
|
|
||||||
extern uint64_t g_boot_fast_page_pt[];
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
SpinLock PageTable::s_fast_page_lock;
|
SpinLock PageTable::s_fast_page_lock;
|
||||||
|
|
||||||
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
|
||||||
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
|
||||||
|
|
||||||
static bool s_is_initialized = false;
|
|
||||||
|
|
||||||
static PageTable* s_kernel = nullptr;
|
static PageTable* s_kernel = nullptr;
|
||||||
static bool s_has_nxe = false;
|
static bool s_has_nxe = false;
|
||||||
static bool s_has_pge = false;
|
static bool s_has_pge = false;
|
||||||
@@ -35,28 +28,6 @@ namespace Kernel
|
|||||||
|
|
||||||
static paddr_t s_global_pdpte = 0;
|
static paddr_t s_global_pdpte = 0;
|
||||||
|
|
||||||
static uint64_t* s_fast_page_pt { nullptr };
|
|
||||||
|
|
||||||
static uint64_t* allocate_zeroed_page_aligned_page()
|
|
||||||
{
|
|
||||||
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
|
|
||||||
ASSERT(page);
|
|
||||||
memset(page, 0, PAGE_SIZE);
|
|
||||||
return (uint64_t*)page;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static paddr_t V2P(const T vaddr)
|
|
||||||
{
|
|
||||||
return (vaddr_t)vaddr - KERNEL_OFFSET + g_boot_info.kernel_paddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static uint64_t* P2V(const T paddr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<uint64_t*>(reinterpret_cast<paddr_t>(paddr) - g_boot_info.kernel_paddr + KERNEL_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline PageTable::flags_t parse_flags(uint64_t entry)
|
static inline PageTable::flags_t parse_flags(uint64_t entry)
|
||||||
{
|
{
|
||||||
using Flags = PageTable::Flags;
|
using Flags = PageTable::Flags;
|
||||||
@@ -75,22 +46,26 @@ namespace Kernel
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::initialize_fast_page()
|
void PageTable::initialize()
|
||||||
{
|
|
||||||
s_fast_page_pt = g_boot_fast_page_pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void detect_cpu_features()
|
|
||||||
{
|
{
|
||||||
if (CPUID::has_nxe())
|
if (CPUID::has_nxe())
|
||||||
s_has_nxe = true;
|
s_has_nxe = true;
|
||||||
|
|
||||||
if (CPUID::has_pge())
|
if (CPUID::has_pge())
|
||||||
s_has_pge = true;
|
s_has_pge = true;
|
||||||
|
|
||||||
if (CPUID::has_pat())
|
if (CPUID::has_pat())
|
||||||
s_has_pat = true;
|
s_has_pat = true;
|
||||||
|
|
||||||
|
ASSERT(s_kernel == nullptr);
|
||||||
|
s_kernel = new PageTable();
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
|
s_kernel->initialize_kernel();
|
||||||
|
s_kernel->initial_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::enable_cpu_features()
|
void PageTable::initial_load()
|
||||||
{
|
{
|
||||||
if (s_has_nxe)
|
if (s_has_nxe)
|
||||||
{
|
{
|
||||||
@@ -131,56 +106,8 @@ namespace Kernel
|
|||||||
"movl %%eax, %%cr0;"
|
"movl %%eax, %%cr0;"
|
||||||
::: "rax"
|
::: "rax"
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::initialize_and_load()
|
load();
|
||||||
{
|
|
||||||
detect_cpu_features();
|
|
||||||
enable_cpu_features();
|
|
||||||
|
|
||||||
ASSERT(s_kernel == nullptr);
|
|
||||||
s_kernel = new PageTable();
|
|
||||||
ASSERT(s_kernel);
|
|
||||||
|
|
||||||
auto* pdpt = allocate_zeroed_page_aligned_page();
|
|
||||||
ASSERT(pdpt);
|
|
||||||
|
|
||||||
s_kernel->m_highest_paging_struct = V2P(pdpt);
|
|
||||||
s_kernel->map_kernel_memory();
|
|
||||||
|
|
||||||
PageTable::with_fast_page(s_kernel->m_highest_paging_struct, [] {
|
|
||||||
s_global_pdpte = PageTable::fast_page_as_sized<paddr_t>(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
// update fast page pt
|
|
||||||
{
|
|
||||||
constexpr vaddr_t vaddr = fast_page();
|
|
||||||
constexpr uint16_t pdpte = (vaddr >> 30) & 0x1FF;
|
|
||||||
constexpr uint16_t pde = (vaddr >> 21) & 0x1FF;
|
|
||||||
|
|
||||||
const auto get_or_allocate_entry =
|
|
||||||
[](paddr_t table_paddr, uint16_t entry, uint64_t flags)
|
|
||||||
{
|
|
||||||
uint64_t* table = P2V(table_paddr);
|
|
||||||
|
|
||||||
if (!(table[entry] & Flags::Present))
|
|
||||||
{
|
|
||||||
auto* vaddr = allocate_zeroed_page_aligned_page();
|
|
||||||
ASSERT(vaddr);
|
|
||||||
table[entry] = V2P(vaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
table[entry] |= flags;
|
|
||||||
|
|
||||||
return table[entry] & s_page_addr_mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
const paddr_t pdpt = s_kernel->m_highest_paging_struct;
|
|
||||||
const paddr_t pd = get_or_allocate_entry(pdpt, pdpte, Flags::Present);
|
|
||||||
s_fast_page_pt = P2V(get_or_allocate_entry(pd, pde, Flags::ReadWrite | Flags::Present));
|
|
||||||
}
|
|
||||||
|
|
||||||
s_kernel->load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable& PageTable::kernel()
|
PageTable& PageTable::kernel()
|
||||||
@@ -194,12 +121,48 @@ namespace Kernel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_kernel_memory()
|
static uint64_t* allocate_zeroed_page_aligned_page()
|
||||||
{
|
{
|
||||||
|
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
|
||||||
|
ASSERT(page);
|
||||||
|
memset(page, 0, PAGE_SIZE);
|
||||||
|
return (uint64_t*)page;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static paddr_t V2P(const T vaddr)
|
||||||
|
{
|
||||||
|
return (vaddr_t)vaddr - KERNEL_OFFSET + g_boot_info.kernel_paddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static vaddr_t P2V(const T paddr)
|
||||||
|
{
|
||||||
|
return (paddr_t)paddr - g_boot_info.kernel_paddr + KERNEL_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::initialize_kernel()
|
||||||
|
{
|
||||||
|
ASSERT(s_global_pdpte == 0);
|
||||||
|
s_global_pdpte = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
|
||||||
|
map_kernel_memory();
|
||||||
|
|
||||||
|
prepare_fast_page();
|
||||||
|
|
||||||
|
// Map main bios area below 1 MiB
|
||||||
|
map_range_at(
|
||||||
|
0x000E0000,
|
||||||
|
P2V(0x000E0000),
|
||||||
|
0x00100000 - 0x000E0000,
|
||||||
|
PageTable::Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
||||||
|
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
||||||
map_range_at(
|
map_range_at(
|
||||||
V2P(g_kernel_start),
|
V2P(g_kernel_start),
|
||||||
reinterpret_cast<vaddr_t>(g_kernel_start),
|
(vaddr_t)g_kernel_start,
|
||||||
g_kernel_end - g_kernel_start,
|
g_kernel_end - g_kernel_start,
|
||||||
Flags::Present
|
Flags::Present
|
||||||
);
|
);
|
||||||
@@ -207,7 +170,7 @@ namespace Kernel
|
|||||||
// Map executable kernel memory as executable
|
// Map executable kernel memory as executable
|
||||||
map_range_at(
|
map_range_at(
|
||||||
V2P(g_kernel_execute_start),
|
V2P(g_kernel_execute_start),
|
||||||
reinterpret_cast<vaddr_t>(g_kernel_execute_start),
|
(vaddr_t)g_kernel_execute_start,
|
||||||
g_kernel_execute_end - g_kernel_execute_start,
|
g_kernel_execute_end - g_kernel_execute_start,
|
||||||
Flags::Execute | Flags::Present
|
Flags::Execute | Flags::Present
|
||||||
);
|
);
|
||||||
@@ -215,7 +178,7 @@ namespace Kernel
|
|||||||
// Map writable kernel memory as writable
|
// Map writable kernel memory as writable
|
||||||
map_range_at(
|
map_range_at(
|
||||||
V2P(g_kernel_writable_start),
|
V2P(g_kernel_writable_start),
|
||||||
reinterpret_cast<vaddr_t>(g_kernel_writable_start),
|
(vaddr_t)g_kernel_writable_start,
|
||||||
g_kernel_writable_end - g_kernel_writable_start,
|
g_kernel_writable_end - g_kernel_writable_start,
|
||||||
Flags::ReadWrite | Flags::Present
|
Flags::ReadWrite | Flags::Present
|
||||||
);
|
);
|
||||||
@@ -223,34 +186,69 @@ namespace Kernel
|
|||||||
// Map userspace memory
|
// Map userspace memory
|
||||||
map_range_at(
|
map_range_at(
|
||||||
V2P(g_userspace_start),
|
V2P(g_userspace_start),
|
||||||
reinterpret_cast<vaddr_t>(g_userspace_start),
|
(vaddr_t)g_userspace_start,
|
||||||
g_userspace_end - g_userspace_start,
|
g_userspace_end - g_userspace_start,
|
||||||
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PageTable::prepare_fast_page()
|
||||||
|
{
|
||||||
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||||
|
ASSERT(pdpt[pdpte] & Flags::Present);
|
||||||
|
|
||||||
|
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte]) & PAGE_ADDR_MASK);
|
||||||
|
ASSERT(!(pd[pde] & Flags::Present));
|
||||||
|
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde]) & PAGE_ADDR_MASK);
|
||||||
|
ASSERT(!(pt[pte] & Flags::Present));
|
||||||
|
pt[pte] = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
}
|
||||||
|
|
||||||
void PageTable::map_fast_page(paddr_t paddr)
|
void PageTable::map_fast_page(paddr_t paddr)
|
||||||
{
|
{
|
||||||
ASSERT(paddr && paddr % PAGE_SIZE == 0);
|
ASSERT(s_kernel);
|
||||||
|
ASSERT(paddr);
|
||||||
|
|
||||||
ASSERT(s_fast_page_pt);
|
|
||||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
ASSERT(!(*s_fast_page_pt & Flags::Present));
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
s_fast_page_pt[0] = paddr | Flags::ReadWrite | Flags::Present;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(fast_page()));
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
||||||
|
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||||
|
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||||
|
|
||||||
|
ASSERT(!(pt[pte] & Flags::Present));
|
||||||
|
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
invalidate(fast_page(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_fast_page()
|
void PageTable::unmap_fast_page()
|
||||||
{
|
{
|
||||||
ASSERT(s_fast_page_pt);
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
ASSERT((*s_fast_page_pt & Flags::Present));
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
s_fast_page_pt[0] = 0;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(fast_page()));
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
||||||
|
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||||
|
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||||
|
|
||||||
|
ASSERT(pt[pte] & Flags::Present);
|
||||||
|
pt[pte] = 0;
|
||||||
|
|
||||||
|
invalidate(fast_page(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||||
@@ -259,41 +257,41 @@ namespace Kernel
|
|||||||
PageTable* page_table = new PageTable;
|
PageTable* page_table = new PageTable;
|
||||||
if (page_table == nullptr)
|
if (page_table == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
page_table->map_kernel_memory();
|
||||||
uint64_t* pdpt = allocate_zeroed_page_aligned_page();
|
return page_table;
|
||||||
if (pdpt == nullptr)
|
|
||||||
{
|
|
||||||
delete page_table;
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
page_table->m_highest_paging_struct = V2P(pdpt);
|
void PageTable::map_kernel_memory()
|
||||||
|
{
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
ASSERT(s_global_pdpte);
|
||||||
|
|
||||||
|
ASSERT(m_highest_paging_struct == 0);
|
||||||
|
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
||||||
|
ASSERT(m_highest_paging_struct);
|
||||||
|
|
||||||
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||||
pdpt[0] = 0;
|
pdpt[0] = 0;
|
||||||
pdpt[1] = 0;
|
pdpt[1] = 0;
|
||||||
pdpt[2] = 0;
|
pdpt[2] = 0;
|
||||||
pdpt[3] = s_global_pdpte | Flags::Present;
|
pdpt[3] = s_global_pdpte | Flags::Present;
|
||||||
static_assert(KERNEL_OFFSET == 0xC0000000);
|
static_assert(KERNEL_OFFSET == 0xC0000000);
|
||||||
|
|
||||||
return page_table;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable::~PageTable()
|
PageTable::~PageTable()
|
||||||
{
|
{
|
||||||
if (m_highest_paging_struct == 0)
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||||
return;
|
|
||||||
|
|
||||||
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
|
||||||
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||||
for (uint32_t pde = 0; pde < 512; pde++)
|
for (uint32_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
kfree(P2V(pd[pde] & s_page_addr_mask));
|
kfree(reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)));
|
||||||
}
|
}
|
||||||
kfree(pd);
|
kfree(pd);
|
||||||
}
|
}
|
||||||
@@ -304,43 +302,15 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
ASSERT(m_highest_paging_struct < 0x100000000);
|
ASSERT(m_highest_paging_struct < 0x100000000);
|
||||||
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
const uint32_t pdpt_lo = m_highest_paging_struct;
|
||||||
|
asm volatile("movl %0, %%cr3" :: "r"(pdpt_lo));
|
||||||
Processor::set_current_page_table(this);
|
Processor::set_current_page_table(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
|
void PageTable::invalidate(vaddr_t vaddr, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
||||||
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
|
||||||
if (is_userspace && this != &PageTable::current())
|
|
||||||
;
|
|
||||||
else if (pages <= 32 || !s_is_initialized)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(vaddr));
|
|
||||||
}
|
|
||||||
else if (is_userspace || !s_has_pge)
|
|
||||||
{
|
|
||||||
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
"movl %%cr4, %%eax;"
|
|
||||||
|
|
||||||
"andl $~0x80, %%eax;"
|
|
||||||
"movl %%eax, %%cr4;"
|
|
||||||
|
|
||||||
"movl %0, %%cr3;"
|
|
||||||
|
|
||||||
"orl $0x80, %%eax;"
|
|
||||||
"movl %%eax, %%cr4;"
|
|
||||||
:
|
|
||||||
: "r"(static_cast<uint32_t>(m_highest_paging_struct))
|
|
||||||
: "eax"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send_smp_message)
|
if (send_smp_message)
|
||||||
{
|
{
|
||||||
@@ -348,14 +318,13 @@ namespace Kernel
|
|||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
.flush_tlb = {
|
.flush_tlb = {
|
||||||
.vaddr = vaddr,
|
.vaddr = vaddr,
|
||||||
.page_count = pages,
|
.page_count = 1
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
void PageTable::unmap_page(vaddr_t vaddr, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
@@ -374,16 +343,12 @@ namespace Kernel
|
|||||||
if (is_page_free(vaddr))
|
if (is_page_free(vaddr))
|
||||||
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
||||||
|
|
||||||
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||||
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||||
|
|
||||||
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
|
||||||
|
|
||||||
pt[pte] = 0;
|
pt[pte] = 0;
|
||||||
|
invalidate(vaddr, send_smp_message);
|
||||||
if (invalidate && old_paddr != 0)
|
|
||||||
invalidate_page(vaddr, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||||
@@ -395,10 +360,17 @@ namespace Kernel
|
|||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (vaddr_t page = 0; page < page_count; page++)
|
for (vaddr_t page = 0; page < page_count; page++)
|
||||||
unmap_page(vaddr + page * PAGE_SIZE, false);
|
unmap_page(vaddr + page * PAGE_SIZE, false);
|
||||||
invalidate_range(vaddr, page_count, true);
|
|
||||||
|
Processor::broadcast_smp_message({
|
||||||
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
|
.flush_tlb = {
|
||||||
|
.vaddr = vaddr,
|
||||||
|
.page_count = page_count
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
@@ -433,11 +405,11 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
||||||
|
|
||||||
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||||
if ((pd[pde] & uwr_flags) != uwr_flags)
|
if ((pd[pde] & uwr_flags) != uwr_flags)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
@@ -448,14 +420,10 @@ namespace Kernel
|
|||||||
if (!(flags & Flags::Present))
|
if (!(flags & Flags::Present))
|
||||||
uwr_flags &= ~Flags::Present;
|
uwr_flags &= ~Flags::Present;
|
||||||
|
|
||||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||||
|
|
||||||
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
|
||||||
|
|
||||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||||
|
|
||||||
if (invalidate && old_paddr != 0)
|
invalidate(vaddr, send_smp_message);
|
||||||
invalidate_page(vaddr, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
@@ -469,49 +437,14 @@ namespace Kernel
|
|||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (size_t page = 0; page < page_count; page++)
|
for (size_t page = 0; page < page_count; page++)
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
||||||
invalidate_range(vaddr, page_count, true);
|
|
||||||
|
Processor::broadcast_smp_message({
|
||||||
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
|
.flush_tlb = {
|
||||||
|
.vaddr = vaddr,
|
||||||
|
.page_count = page_count
|
||||||
}
|
}
|
||||||
|
});
|
||||||
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
|
|
||||||
{
|
|
||||||
ASSERT(vaddr);
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
|
|
||||||
uint32_t pdpte = (vaddr >> 30) & 0x1FF;
|
|
||||||
uint32_t pde = (vaddr >> 21) & 0x1FF;
|
|
||||||
uint32_t pte = (vaddr >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
const uint32_t e_pdpte = ((vaddr + size - 1) >> 30) & 0x1FF;
|
|
||||||
const uint32_t e_pde = ((vaddr + size - 1) >> 21) & 0x1FF;
|
|
||||||
const uint32_t e_pte = ((vaddr + size - 1) >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
|
||||||
for (; pdpte <= e_pdpte; pdpte++)
|
|
||||||
{
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
|
||||||
for (; pde < 512; pde++)
|
|
||||||
{
|
|
||||||
if (pdpte == e_pdpte && pde > e_pde)
|
|
||||||
break;
|
|
||||||
if (!(pd[pde] & Flags::ReadWrite))
|
|
||||||
continue;
|
|
||||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
|
||||||
for (; pte < 512; pte++)
|
|
||||||
{
|
|
||||||
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
|
||||||
break;
|
|
||||||
pt[pte] &= ~static_cast<uint64_t>(Flags::ReadWrite);
|
|
||||||
}
|
|
||||||
pte = 0;
|
|
||||||
}
|
|
||||||
pde = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidate_range(vaddr, size / PAGE_SIZE, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
@@ -524,15 +457,15 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
uint64_t* pdpt = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
if (!(pt[pte] & Flags::Used))
|
if (!(pt[pte] & Flags::Used))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -546,7 +479,8 @@ namespace Kernel
|
|||||||
|
|
||||||
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
||||||
{
|
{
|
||||||
return get_page_data(vaddr) & s_page_addr_mask;
|
uint64_t page_data = get_page_data(vaddr);
|
||||||
|
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::is_page_free(vaddr_t vaddr) const
|
bool PageTable::is_page_free(vaddr_t vaddr) const
|
||||||
@@ -567,13 +501,13 @@ namespace Kernel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
if (only_free && !is_page_free(vaddr))
|
if (only_free && !is_page_free(vaddr))
|
||||||
return false;
|
return false;
|
||||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
map_page_at(0, vaddr, Flags::Reserved);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,9 +521,7 @@ namespace Kernel
|
|||||||
if (only_free && !is_range_free(vaddr, bytes))
|
if (only_free && !is_range_free(vaddr, bytes))
|
||||||
return false;
|
return false;
|
||||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||||
reserve_page(vaddr + offset, true, false);
|
reserve_page(vaddr + offset);
|
||||||
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,37 +534,39 @@ namespace Kernel
|
|||||||
if (size_t rem = last_address % PAGE_SIZE)
|
if (size_t rem = last_address % PAGE_SIZE)
|
||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
uint32_t pdpte = (first_address >> 30) & 0x1FF;
|
const uint32_t s_pdpte = (first_address >> 30) & 0x1FF;
|
||||||
uint32_t pde = (first_address >> 21) & 0x1FF;
|
const uint32_t s_pde = (first_address >> 21) & 0x1FF;
|
||||||
uint32_t pte = (first_address >> 12) & 0x1FF;
|
const uint32_t s_pte = (first_address >> 12) & 0x1FF;
|
||||||
|
|
||||||
const uint32_t e_pdpte = ((last_address - 1) >> 30) & 0x1FF;
|
const uint32_t e_pdpte = (last_address >> 30) & 0x1FF;
|
||||||
const uint32_t e_pde = ((last_address - 1) >> 21) & 0x1FF;
|
const uint32_t e_pde = (last_address >> 21) & 0x1FF;
|
||||||
const uint32_t e_pte = ((last_address - 1) >> 12) & 0x1FF;
|
const uint32_t e_pte = (last_address >> 12) & 0x1FF;
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
// Try to find free page that can be mapped without
|
// Try to find free page that can be mapped without
|
||||||
// allocations (page table with unused entries)
|
// allocations (page table with unused entries)
|
||||||
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||||
for (; pdpte <= e_pdpte; pdpte++)
|
for (uint32_t pdpte = s_pdpte; pdpte < 4; pdpte++)
|
||||||
{
|
{
|
||||||
|
if (pdpte > e_pdpte)
|
||||||
|
break;
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||||
for (; pde < 512; pde++)
|
for (uint32_t pde = s_pde; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (pdpte == e_pdpte && pde > e_pde)
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
break;
|
break;
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
for (; pte < 512; pte++)
|
for (uint32_t pte = s_pte; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
if (pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
||||||
break;
|
break;
|
||||||
if (pt[pte] & Flags::Used)
|
if (!(pt[pte] & Flags::Used))
|
||||||
continue;
|
{
|
||||||
vaddr_t vaddr = 0;
|
vaddr_t vaddr = 0;
|
||||||
vaddr |= (vaddr_t)pdpte << 30;
|
vaddr |= (vaddr_t)pdpte << 30;
|
||||||
vaddr |= (vaddr_t)pde << 21;
|
vaddr |= (vaddr_t)pde << 21;
|
||||||
@@ -640,9 +574,8 @@ namespace Kernel
|
|||||||
ASSERT(reserve_page(vaddr));
|
ASSERT(reserve_page(vaddr));
|
||||||
return vaddr;
|
return vaddr;
|
||||||
}
|
}
|
||||||
pte = 0;
|
|
||||||
}
|
}
|
||||||
pde = 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find any free page
|
// Find any free page
|
||||||
@@ -655,7 +588,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||||
@@ -688,7 +621,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
||||||
@@ -711,7 +644,7 @@ namespace Kernel
|
|||||||
flags_t flags = 0;
|
flags_t flags = 0;
|
||||||
vaddr_t start = 0;
|
vaddr_t start = 0;
|
||||||
|
|
||||||
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||||
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
@@ -720,7 +653,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
for (uint64_t pde = 0; pde < 512; pde++)
|
for (uint64_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
@@ -729,7 +662,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
for (uint64_t pte = 0; pte < 512; pte++)
|
for (uint64_t pte = 0; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (parse_flags(pt[pte]) != flags)
|
if (parse_flags(pt[pte]) != flags)
|
||||||
|
|||||||
@@ -1,86 +1,35 @@
|
|||||||
.section .userspace, "ax"
|
.section .userspace, "ax"
|
||||||
|
|
||||||
// stack contains
|
// stack contains
|
||||||
// (4 bytes) return address (on return stack)
|
// return address
|
||||||
// (4 bytes) return stack
|
// signal number
|
||||||
// (4 bytes) return rflags
|
// signal handler
|
||||||
// (8 bytes) restore sigmask
|
|
||||||
// (36 bytes) siginfo_t
|
|
||||||
// (4 bytes) signal number
|
|
||||||
// (4 bytes) signal handler
|
|
||||||
|
|
||||||
.global signal_trampoline
|
.global signal_trampoline
|
||||||
signal_trampoline:
|
signal_trampoline:
|
||||||
pushl %esi // gregs
|
|
||||||
pushl %edi
|
|
||||||
pushl %edx
|
|
||||||
pushl %ecx
|
|
||||||
pushl %ebx
|
|
||||||
pushl %eax
|
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
movl 84(%esp), %eax
|
pusha
|
||||||
pushl %eax; addl $4, (%esp)
|
|
||||||
pushl (%eax)
|
|
||||||
|
|
||||||
// FIXME: populate these
|
movl 40(%esp), %edi
|
||||||
xorl %eax, %eax
|
movl 36(%esp), %eax
|
||||||
pushl %eax // stack
|
|
||||||
pushl %eax
|
|
||||||
pushl %eax
|
|
||||||
pushl %eax // sigset
|
|
||||||
pushl %eax
|
|
||||||
pushl %eax // link
|
|
||||||
|
|
||||||
movl %esp, %edx // ucontext
|
|
||||||
leal 68(%esp), %esi // siginfo
|
|
||||||
movl 64(%esp), %edi // signal number
|
|
||||||
movl 60(%esp), %eax // handlers
|
|
||||||
|
|
||||||
// align stack to 16 bytes
|
// align stack to 16 bytes
|
||||||
movl %esp, %ebp
|
movl %esp, %ebx
|
||||||
andl $-16, %esp
|
andl $0x0F, %ebx
|
||||||
|
subl %ebx, %esp
|
||||||
|
|
||||||
subl $512, %esp
|
subl $12, %esp
|
||||||
fxsave (%esp)
|
|
||||||
|
|
||||||
subl $4, %esp
|
|
||||||
pushl %edx
|
|
||||||
pushl %esi
|
|
||||||
pushl %edi
|
pushl %edi
|
||||||
call *%eax
|
call *%eax
|
||||||
addl $16, %esp
|
addl $16, %esp
|
||||||
|
|
||||||
fxrstor (%esp)
|
|
||||||
addl $512, %esp
|
|
||||||
|
|
||||||
// restore stack
|
// restore stack
|
||||||
movl %ebp, %esp
|
addl %ebx, %esp
|
||||||
addl $24, %esp
|
popa
|
||||||
|
|
||||||
// restore sigmask
|
leave
|
||||||
movl $83, %eax // SYS_SIGPROCMASK
|
|
||||||
movl $3, %ebx // SIG_SETMASK
|
|
||||||
leal 72(%esp), %ecx // set
|
|
||||||
xorl %edx, %edx // oset
|
|
||||||
int $0xF0
|
|
||||||
|
|
||||||
// restore registers
|
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
popl %ebp
|
|
||||||
popl %eax
|
|
||||||
popl %ebx
|
|
||||||
popl %ecx
|
|
||||||
popl %edx
|
|
||||||
popl %edi
|
|
||||||
popl %esi
|
|
||||||
|
|
||||||
// skip handler, number, siginfo_t, sigmask
|
|
||||||
addl $52, %esp
|
|
||||||
|
|
||||||
// restore flags
|
|
||||||
popf
|
|
||||||
|
|
||||||
movl (%esp), %esp
|
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
|
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
|
||||||
.global asm_syscall_handler
|
.global asm_syscall_handler
|
||||||
asm_syscall_handler:
|
asm_syscall_handler:
|
||||||
|
# save segment registers
|
||||||
|
pushw %ds
|
||||||
|
pushw %es
|
||||||
|
pushw %fs
|
||||||
|
pushw %gs
|
||||||
|
|
||||||
# save general purpose registers
|
# save general purpose registers
|
||||||
pushl %ebx
|
pushl %ebx
|
||||||
pushl %ecx
|
pushl %ecx
|
||||||
@@ -8,14 +14,16 @@ asm_syscall_handler:
|
|||||||
pushl %edi
|
pushl %edi
|
||||||
pushl %esi
|
pushl %esi
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
cld
|
|
||||||
|
|
||||||
# align stack
|
# align stack
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
andl $-16, %esp
|
subl $15, %esp
|
||||||
|
andl $0xFFFFFFF0, %esp
|
||||||
|
|
||||||
# push arguments
|
# push arguments
|
||||||
subl $8, %esp
|
subl $4, %esp
|
||||||
|
pushl %ebp
|
||||||
|
addl $32, (%esp)
|
||||||
pushl %edi
|
pushl %edi
|
||||||
pushl %esi
|
pushl %esi
|
||||||
pushl %edx
|
pushl %edx
|
||||||
@@ -35,15 +43,6 @@ asm_syscall_handler:
|
|||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
# restore userspace segments
|
|
||||||
movw $(0x20 | 3), %bx
|
|
||||||
movw %bx, %ds
|
|
||||||
movw %bx, %es
|
|
||||||
movw $(0x30 | 3), %bx
|
|
||||||
movw %bx, %fs
|
|
||||||
movw $(0x38 | 3), %bx
|
|
||||||
movw %bx, %gs
|
|
||||||
|
|
||||||
# restore general purpose registers
|
# restore general purpose registers
|
||||||
popl %ebp
|
popl %ebp
|
||||||
popl %esi
|
popl %esi
|
||||||
@@ -52,6 +51,12 @@ asm_syscall_handler:
|
|||||||
popl %ecx
|
popl %ecx
|
||||||
popl %ebx
|
popl %ebx
|
||||||
|
|
||||||
|
# restore segment registers
|
||||||
|
popw %gs
|
||||||
|
popw %fs
|
||||||
|
popw %es
|
||||||
|
popw %ds
|
||||||
|
|
||||||
iret
|
iret
|
||||||
|
|
||||||
.global sys_fork_trampoline
|
.global sys_fork_trampoline
|
||||||
@@ -63,7 +68,7 @@ sys_fork_trampoline:
|
|||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testl %eax, %eax
|
testl %eax, %eax
|
||||||
jz .done
|
jz .reload_stack
|
||||||
|
|
||||||
movl %esp, %ebx
|
movl %esp, %ebx
|
||||||
|
|
||||||
@@ -79,3 +84,9 @@ sys_fork_trampoline:
|
|||||||
popl %ebx
|
popl %ebx
|
||||||
popl %ebp
|
popl %ebp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.reload_stack:
|
||||||
|
call get_thread_start_sp
|
||||||
|
movl %eax, %esp
|
||||||
|
xorl %eax, %eax
|
||||||
|
jmp .done
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ read_ip:
|
|||||||
# void start_kernel_thread()
|
# void start_kernel_thread()
|
||||||
.global start_kernel_thread
|
.global start_kernel_thread
|
||||||
start_kernel_thread:
|
start_kernel_thread:
|
||||||
|
call get_thread_start_sp
|
||||||
|
movl %eax, %esp
|
||||||
|
|
||||||
# STACK LAYOUT
|
# STACK LAYOUT
|
||||||
# on_exit arg
|
# on_exit arg
|
||||||
# on_exit func
|
# on_exit func
|
||||||
@@ -28,15 +31,39 @@ start_kernel_thread:
|
|||||||
subl $12, %esp
|
subl $12, %esp
|
||||||
pushl %edi
|
pushl %edi
|
||||||
call *%esi
|
call *%esi
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
|
|
||||||
.global start_userspace_thread
|
.global start_userspace_thread
|
||||||
start_userspace_thread:
|
start_userspace_thread:
|
||||||
|
call get_thread_start_sp
|
||||||
|
movl %eax, %esp
|
||||||
|
|
||||||
|
# STACK LAYOUT
|
||||||
|
# entry
|
||||||
|
# argc
|
||||||
|
# argv
|
||||||
|
# envp
|
||||||
|
# userspace stack
|
||||||
|
|
||||||
|
call get_userspace_thread_stack_top
|
||||||
|
|
||||||
movw $(0x20 | 3), %bx
|
movw $(0x20 | 3), %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
movw %bx, %es
|
movw %bx, %es
|
||||||
movw $(0x30 | 3), %bx
|
|
||||||
movw %bx, %fs
|
movw %bx, %fs
|
||||||
movw $(0x38 | 3), %bx
|
|
||||||
movw %bx, %gs
|
movw %bx, %gs
|
||||||
|
xorw %bx, %bx
|
||||||
|
|
||||||
|
popl %edi
|
||||||
|
popl %esi
|
||||||
|
popl %edx
|
||||||
|
popl %ecx
|
||||||
|
popl %ebx
|
||||||
|
|
||||||
|
pushl $(0x20 | 3)
|
||||||
|
pushl %eax
|
||||||
|
pushl $0x202
|
||||||
|
pushl $(0x18 | 3)
|
||||||
|
pushl %ebx
|
||||||
iret
|
iret
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
# bool safe_user_memcpy(void*, const void*, size_t)
|
|
||||||
.global safe_user_memcpy
|
|
||||||
.global safe_user_memcpy_end
|
|
||||||
.global safe_user_memcpy_fault
|
|
||||||
safe_user_memcpy:
|
|
||||||
xorl %eax, %eax
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
xchgl 8(%esp), %esi
|
|
||||||
movl 12(%esp), %ecx
|
|
||||||
movl %edi, %edx
|
|
||||||
rep movsb
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
movl 8(%esp), %esi
|
|
||||||
incl %eax
|
|
||||||
safe_user_memcpy_fault:
|
|
||||||
ret
|
|
||||||
safe_user_memcpy_end:
|
|
||||||
|
|
||||||
# bool safe_user_strncpy(void*, const void*, size_t)
|
|
||||||
.global safe_user_strncpy
|
|
||||||
.global safe_user_strncpy_end
|
|
||||||
.global safe_user_strncpy_fault
|
|
||||||
safe_user_strncpy:
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
xchgl 8(%esp), %esi
|
|
||||||
movl 12(%esp), %ecx
|
|
||||||
|
|
||||||
testl %ecx, %ecx
|
|
||||||
jz safe_user_strncpy_fault
|
|
||||||
|
|
||||||
.safe_user_strncpy_loop:
|
|
||||||
movb (%esi), %al
|
|
||||||
movb %al, (%edi)
|
|
||||||
testb %al, %al
|
|
||||||
jz .safe_user_strncpy_done
|
|
||||||
|
|
||||||
incl %edi
|
|
||||||
incl %esi
|
|
||||||
decl %ecx
|
|
||||||
jnz .safe_user_strncpy_loop
|
|
||||||
|
|
||||||
safe_user_strncpy_fault:
|
|
||||||
xorl %eax, %eax
|
|
||||||
jmp .safe_user_strncpy_return
|
|
||||||
|
|
||||||
.safe_user_strncpy_done:
|
|
||||||
movl $1, %eax
|
|
||||||
|
|
||||||
.safe_user_strncpy_return:
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
movl 8(%esp), %esi
|
|
||||||
ret
|
|
||||||
|
|
||||||
safe_user_strncpy_end:
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
.global asm_yield_trampoline
|
|
||||||
asm_yield_trampoline:
|
|
||||||
leal 4(%esp), %ecx
|
|
||||||
movl 4(%esp), %esp
|
|
||||||
|
|
||||||
pushl -4(%ecx)
|
|
||||||
pushl %ecx
|
|
||||||
pushl %eax
|
|
||||||
pushl %ebx
|
|
||||||
pushl %esi
|
|
||||||
pushl %edi
|
|
||||||
pushl %ebp
|
|
||||||
|
|
||||||
pushl %esp
|
|
||||||
call scheduler_on_yield
|
|
||||||
addl $4, %esp
|
|
||||||
|
|
||||||
popl %ebp
|
|
||||||
popl %edi
|
|
||||||
popl %esi
|
|
||||||
popl %ebx
|
|
||||||
popl %eax
|
|
||||||
movl 4(%esp), %ecx
|
|
||||||
movl 0(%esp), %esp
|
|
||||||
jmp *%ecx
|
|
||||||
@@ -11,28 +11,9 @@
|
|||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
// video mode info, page align modules
|
# multiboot2 header
|
||||||
.set multiboot_flags, (1 << 2) | (1 << 0)
|
|
||||||
|
|
||||||
.section .multiboot, "aw"
|
.section .multiboot, "aw"
|
||||||
multiboot_start:
|
.align 8
|
||||||
.long 0x1BADB002
|
|
||||||
.long multiboot_flags
|
|
||||||
.long -(0x1BADB002 + multiboot_flags)
|
|
||||||
|
|
||||||
.long 0
|
|
||||||
.long 0
|
|
||||||
.long 0
|
|
||||||
.long 0
|
|
||||||
.long 0
|
|
||||||
|
|
||||||
.long 0
|
|
||||||
.long FB_WIDTH
|
|
||||||
.long FB_HEIGHT
|
|
||||||
.long FB_BPP
|
|
||||||
multiboot_end:
|
|
||||||
|
|
||||||
.section .multiboot2, "aw"
|
|
||||||
multiboot2_start:
|
multiboot2_start:
|
||||||
.long 0xE85250D6
|
.long 0xE85250D6
|
||||||
.long 0
|
.long 0
|
||||||
@@ -55,12 +36,6 @@ multiboot2_start:
|
|||||||
.long 12
|
.long 12
|
||||||
.long V2P(_start)
|
.long V2P(_start)
|
||||||
|
|
||||||
# page align modules
|
|
||||||
.align 8
|
|
||||||
.short 6
|
|
||||||
.short 0
|
|
||||||
.long 8
|
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.short 0
|
.short 0
|
||||||
.short 0
|
.short 0
|
||||||
@@ -68,6 +43,7 @@ multiboot2_start:
|
|||||||
multiboot2_end:
|
multiboot2_end:
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
.section .bananboot, "aw"
|
||||||
|
.align 8
|
||||||
bananboot_start:
|
bananboot_start:
|
||||||
.long 0xBABAB007
|
.long 0xBABAB007
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
@@ -77,10 +53,10 @@ bananboot_start:
|
|||||||
bananboot_end:
|
bananboot_end:
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
.global g_boot_stack_top
|
.align 4096
|
||||||
g_boot_stack_bottom:
|
boot_stack_bottom:
|
||||||
.skip 4096 * 4
|
.skip 4096 * 4
|
||||||
g_boot_stack_top:
|
boot_stack_top:
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
.global g_kernel_cmdline
|
||||||
g_kernel_cmdline:
|
g_kernel_cmdline:
|
||||||
@@ -98,7 +74,8 @@ bananboot_end:
|
|||||||
boot_pdpt:
|
boot_pdpt:
|
||||||
.long V2P(boot_pd) + (PG_PRESENT)
|
.long V2P(boot_pd) + (PG_PRESENT)
|
||||||
.long 0
|
.long 0
|
||||||
.skip 2 * 8
|
.quad 0
|
||||||
|
.quad 0
|
||||||
.long V2P(boot_pd) + (PG_PRESENT)
|
.long V2P(boot_pd) + (PG_PRESENT)
|
||||||
.long 0
|
.long 0
|
||||||
.align 4096
|
.align 4096
|
||||||
@@ -111,16 +88,13 @@ boot_pd:
|
|||||||
.endr
|
.endr
|
||||||
boot_pts:
|
boot_pts:
|
||||||
.set i, 0
|
.set i, 0
|
||||||
.rept 511
|
.rept 512
|
||||||
.rept 512
|
.rept 512
|
||||||
.long i + (PG_READ_WRITE | PG_PRESENT)
|
.long i + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.long 0
|
.long 0
|
||||||
.set i, i + 0x1000
|
.set i, i + 0x1000
|
||||||
.endr
|
.endr
|
||||||
.endr
|
.endr
|
||||||
.global g_boot_fast_page_pt
|
|
||||||
g_boot_fast_page_pt:
|
|
||||||
.skip 512 * 8
|
|
||||||
|
|
||||||
boot_gdt:
|
boot_gdt:
|
||||||
.quad 0x0000000000000000 # null descriptor
|
.quad 0x0000000000000000 # null descriptor
|
||||||
@@ -187,13 +161,6 @@ enable_sse:
|
|||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
ret
|
ret
|
||||||
|
|
||||||
enable_tsc:
|
|
||||||
# allow userspace to use RDTSC
|
|
||||||
movl %cr4, %ecx
|
|
||||||
andl $0xFFFFFFFB, %ecx
|
|
||||||
movl %ecx, %cr4
|
|
||||||
ret
|
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# enable PAE
|
# enable PAE
|
||||||
movl %cr4, %ecx
|
movl %cr4, %ecx
|
||||||
@@ -221,7 +188,7 @@ _start:
|
|||||||
movl %ebx, V2P(bootloader_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
# load boot stack
|
# load boot stack
|
||||||
movl $V2P(g_boot_stack_top), %esp
|
movl $V2P(boot_stack_top), %esp
|
||||||
|
|
||||||
# load boot GDT
|
# load boot GDT
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
@@ -236,11 +203,10 @@ gdt_flush:
|
|||||||
# do processor initialization
|
# do processor initialization
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
call enable_tsc
|
|
||||||
call initialize_paging
|
call initialize_paging
|
||||||
|
|
||||||
# load higher half stack pointer
|
# load higher half stack pointer
|
||||||
movl $g_boot_stack_top, %esp
|
movl $boot_stack_top, %esp
|
||||||
|
|
||||||
# jump to higher half
|
# jump to higher half
|
||||||
leal higher_half, %ecx
|
leal higher_half, %ecx
|
||||||
@@ -276,7 +242,7 @@ system_halt:
|
|||||||
jmp 1b
|
jmp 1b
|
||||||
|
|
||||||
|
|
||||||
#define AP_REL(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
#define AP_V2P(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
||||||
|
|
||||||
.section .ap_init, "ax"
|
.section .ap_init, "ax"
|
||||||
|
|
||||||
@@ -286,27 +252,21 @@ ap_trampoline:
|
|||||||
jmp 1f
|
jmp 1f
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
ap_stack_paddr:
|
ap_stack_ptr:
|
||||||
.skip 4
|
|
||||||
ap_stack_vaddr:
|
|
||||||
.skip 4
|
|
||||||
ap_prepare_paging:
|
|
||||||
.skip 4
|
|
||||||
ap_page_table:
|
|
||||||
.skip 4
|
|
||||||
ap_ready:
|
|
||||||
.skip 4
|
.skip 4
|
||||||
|
ap_stack_loaded:
|
||||||
|
.skip 1
|
||||||
|
|
||||||
1: cli; cld
|
1: cli; cld
|
||||||
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
ljmpl $0x00, $AP_V2P(ap_cs_clear)
|
||||||
|
|
||||||
ap_cs_clear:
|
ap_cs_clear:
|
||||||
# load ap gdt and enter protected mode
|
# load ap gdt and enter protected mode
|
||||||
lgdt AP_REL(ap_gdtr)
|
lgdt AP_V2P(ap_gdtr)
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
ljmpl $0x08, $AP_V2P(ap_protected_mode)
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
ap_protected_mode:
|
ap_protected_mode:
|
||||||
@@ -315,36 +275,32 @@ ap_protected_mode:
|
|||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
|
|
||||||
movl AP_REL(ap_stack_paddr), %esp
|
movl AP_V2P(ap_stack_ptr), %esp
|
||||||
|
movb $1, AP_V2P(ap_stack_loaded)
|
||||||
|
|
||||||
leal V2P(enable_sse), %ecx; call *%ecx
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
leal V2P(enable_tsc), %ecx; call *%ecx
|
|
||||||
leal V2P(initialize_paging), %ecx; call *%ecx
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $AP_REL(ap_flush_gdt)
|
ljmpl $0x08, $AP_V2P(ap_flush_gdt)
|
||||||
|
|
||||||
ap_flush_gdt:
|
ap_flush_gdt:
|
||||||
movl $ap_higher_half, %ecx
|
# move stack pointer to higher half
|
||||||
|
movl %esp, %esp
|
||||||
|
addl $KERNEL_OFFSET, %esp
|
||||||
|
|
||||||
|
# jump to higher half
|
||||||
|
leal ap_higher_half, %ecx
|
||||||
jmp *%ecx
|
jmp *%ecx
|
||||||
|
|
||||||
ap_higher_half:
|
ap_higher_half:
|
||||||
movl AP_REL(ap_prepare_paging), %eax
|
|
||||||
call *%eax
|
|
||||||
|
|
||||||
# load AP's initial values
|
|
||||||
movl AP_REL(ap_stack_vaddr), %esp
|
|
||||||
movl AP_REL(ap_page_table), %eax
|
|
||||||
movl $1, AP_REL(ap_ready)
|
|
||||||
movl %eax, %cr3
|
|
||||||
|
|
||||||
# clear rbp for stacktrace
|
# clear rbp for stacktrace
|
||||||
xorl %ebp, %ebp
|
xorl %ebp, %ebp
|
||||||
|
|
||||||
1: pause
|
1: pause
|
||||||
cmpb $0, g_ap_startup_done
|
cmpb $0, g_ap_startup_done
|
||||||
je 1b
|
jz 1b
|
||||||
|
|
||||||
lock incb g_ap_running_count
|
lock incb g_ap_running_count
|
||||||
|
|
||||||
|
|||||||
@@ -1,107 +1,133 @@
|
|||||||
.macro intr_header, n
|
.macro push_userspace
|
||||||
|
pushw %gs
|
||||||
|
pushw %fs
|
||||||
|
pushw %es
|
||||||
|
pushw %ds
|
||||||
pushal
|
pushal
|
||||||
testb $3, \n+8*4(%esp)
|
.endm
|
||||||
jz 1f
|
|
||||||
|
.macro load_kernel_segments
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
movw %ax, %fs
|
movw %ax, %fs
|
||||||
|
|
||||||
movw $0x28, %ax
|
movw $0x28, %ax
|
||||||
movw %ax, %gs
|
movw %ax, %gs
|
||||||
1: cld
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro intr_footer, n
|
.macro pop_userspace
|
||||||
testb $3, \n+8*4(%esp)
|
popal
|
||||||
jz 1f
|
popw %ds
|
||||||
call cpp_check_signal
|
popw %es
|
||||||
movw $(0x20 | 3), %bx
|
popw %fs
|
||||||
movw %bx, %ds
|
popw %gs
|
||||||
movw %bx, %es
|
|
||||||
movw $(0x30 | 3), %bx
|
|
||||||
movw %bx, %fs
|
|
||||||
movw $(0x38 | 3), %bx
|
|
||||||
movw %bx, %gs
|
|
||||||
1: popal
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
isr_stub:
|
isr_stub:
|
||||||
intr_header 12
|
push_userspace
|
||||||
|
load_kernel_segments
|
||||||
|
|
||||||
movl %cr0, %eax; pushl %eax
|
movl %cr0, %eax; pushl %eax
|
||||||
movl %cr2, %eax; pushl %eax
|
movl %cr2, %eax; pushl %eax
|
||||||
movl %cr3, %eax; pushl %eax
|
movl %cr3, %eax; pushl %eax
|
||||||
movl %cr4, %eax; pushl %eax
|
movl %cr4, %eax; pushl %eax
|
||||||
|
|
||||||
movl 48(%esp), %edi // isr number
|
movl %esp, %eax // register ptr
|
||||||
movl 52(%esp), %esi // error code
|
leal 64(%esp), %ebx // interrupt stack ptr
|
||||||
leal 56(%esp), %edx // interrupt stack ptr
|
movl 60(%esp), %ecx // error code
|
||||||
movl %esp, %ecx // register ptr
|
movl 56(%esp), %edx // isr number
|
||||||
|
|
||||||
# stack frame for stack trace
|
|
||||||
leal 56(%esp), %eax
|
|
||||||
pushl (%eax)
|
|
||||||
pushl %ebp
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
andl $-16, %esp
|
subl $15, %esp
|
||||||
|
andl $0xFFFFFFF0, %esp
|
||||||
|
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
pushl %ecx
|
pushl %ecx
|
||||||
pushl %edx
|
pushl %edx
|
||||||
pushl %esi
|
|
||||||
pushl %edi
|
|
||||||
call cpp_isr_handler
|
call cpp_isr_handler
|
||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
addl $24, %esp
|
addl $16, %esp
|
||||||
|
|
||||||
intr_footer 12
|
pop_userspace
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
iret
|
iret
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
intr_header 12
|
push_userspace
|
||||||
|
load_kernel_segments
|
||||||
|
|
||||||
movl 32(%esp), %edi # interrupt number
|
movl 40(%esp), %eax # interrupt number
|
||||||
|
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
andl $-16, %esp
|
subl $15, %esp
|
||||||
|
andl $0xFFFFFFF0, %esp
|
||||||
|
|
||||||
subl $12, %esp
|
subl $12, %esp
|
||||||
pushl %edi
|
pushl %eax
|
||||||
call cpp_irq_handler
|
call cpp_irq_handler
|
||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
intr_footer 12
|
pop_userspace
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
iret
|
iret
|
||||||
|
|
||||||
|
.global asm_yield_handler
|
||||||
|
asm_yield_handler:
|
||||||
|
# This can only be called from kernel, so no segment saving is needed
|
||||||
|
pushal
|
||||||
|
|
||||||
|
movl %esp, %eax # interrupt registers ptr
|
||||||
|
leal 32(%esp), %ebx # interrupt stack ptr
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
subl $15, %esp
|
||||||
|
andl $0xFFFFFFF0, %esp
|
||||||
|
|
||||||
|
subl $8, %esp
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
|
call cpp_yield_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
popal
|
||||||
|
iret
|
||||||
|
|
||||||
.global asm_ipi_handler
|
.global asm_ipi_handler
|
||||||
asm_ipi_handler:
|
asm_ipi_handler:
|
||||||
intr_header 4
|
push_userspace
|
||||||
|
load_kernel_segments
|
||||||
|
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
andl $-16, %esp
|
subl $15, %esp
|
||||||
|
andl $0xFFFFFFF0, %esp
|
||||||
|
|
||||||
call cpp_ipi_handler
|
call cpp_ipi_handler
|
||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
intr_footer 4
|
pop_userspace
|
||||||
iret
|
iret
|
||||||
|
|
||||||
|
|
||||||
.global asm_timer_handler
|
.global asm_timer_handler
|
||||||
asm_timer_handler:
|
asm_timer_handler:
|
||||||
intr_header 4
|
push_userspace
|
||||||
|
load_kernel_segments
|
||||||
|
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
andl $-16, %esp
|
subl $15, %esp
|
||||||
|
andl $0xFFFFFFF0, %esp
|
||||||
|
|
||||||
call cpp_timer_handler
|
call cpp_timer_handler
|
||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
intr_footer 4
|
pop_userspace
|
||||||
iret
|
iret
|
||||||
|
|
||||||
.macro isr n
|
.macro isr n
|
||||||
@@ -160,26 +186,35 @@ isr 29
|
|||||||
isr 30
|
isr 30
|
||||||
isr 31
|
isr 31
|
||||||
|
|
||||||
.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
|
irq 0
|
||||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \
|
irq 1
|
||||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
|
irq 2
|
||||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
|
irq 3
|
||||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \
|
irq 4
|
||||||
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \
|
irq 5
|
||||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, \
|
irq 6
|
||||||
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \
|
irq 7
|
||||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, \
|
irq 8
|
||||||
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, \
|
irq 9
|
||||||
100,101,102,103,104,105,106,107,108,109, \
|
irq 10
|
||||||
110,111,112,113,114,115,116,117,118,119, \
|
irq 11
|
||||||
120,121,122,123,124,125,126,127,128,129, \
|
irq 12
|
||||||
130,131,132,133,134,135,136,137,138,139, \
|
irq 13
|
||||||
140,141,142,143,144,145,146,147,148,149, \
|
irq 14
|
||||||
150,151,152,153,154,155,156,157,158,159, \
|
irq 15
|
||||||
160,161,162,163,164,165,166,167,168,169, \
|
irq 16
|
||||||
170,171,172,173,174,175,176,177,178,179, \
|
irq 17
|
||||||
180,181,182,183,184,185,186,187,188,189, \
|
irq 18
|
||||||
190,191,192,193,194,195,196,197,198,199, \
|
irq 19
|
||||||
200,201,202,203,204,205,206,207
|
irq 20
|
||||||
irq \i
|
irq 21
|
||||||
.endr
|
irq 22
|
||||||
|
irq 23
|
||||||
|
irq 24
|
||||||
|
irq 25
|
||||||
|
irq 26
|
||||||
|
irq 27
|
||||||
|
irq 28
|
||||||
|
irq 29
|
||||||
|
irq 30
|
||||||
|
irq 31
|
||||||
|
|||||||
@@ -11,21 +11,20 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
g_kernel_execute_start = .;
|
g_kernel_execute_start = .;
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
*(.multiboot2)
|
|
||||||
*(.bananboot)
|
*(.bananboot)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
}
|
}
|
||||||
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
g_ap_init_addr = .;
|
|
||||||
*(.ap_init)
|
|
||||||
g_kernel_execute_end = .;
|
|
||||||
}
|
|
||||||
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
g_userspace_start = .;
|
g_userspace_start = .;
|
||||||
*(.userspace)
|
*(.userspace)
|
||||||
g_userspace_end = .;
|
g_userspace_end = .;
|
||||||
|
g_kernel_execute_end = .;
|
||||||
|
}
|
||||||
|
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_ap_init_addr = .;
|
||||||
|
*(.ap_init)
|
||||||
}
|
}
|
||||||
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <kernel/BootInfo.h>
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/CPUID.h>
|
#include <kernel/CPUID.h>
|
||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
|
||||||
extern uint8_t g_kernel_start[];
|
extern uint8_t g_kernel_start[];
|
||||||
@@ -16,27 +16,17 @@ extern uint8_t g_kernel_writable_end[];
|
|||||||
extern uint8_t g_userspace_start[];
|
extern uint8_t g_userspace_start[];
|
||||||
extern uint8_t g_userspace_end[];
|
extern uint8_t g_userspace_end[];
|
||||||
|
|
||||||
extern uint64_t g_boot_fast_page_pt[];
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
SpinLock PageTable::s_fast_page_lock;
|
SpinLock PageTable::s_fast_page_lock;
|
||||||
|
|
||||||
static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000;
|
|
||||||
static bool s_is_initialized = false;
|
|
||||||
|
|
||||||
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
|
||||||
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
|
||||||
|
|
||||||
static PageTable* s_kernel = nullptr;
|
static PageTable* s_kernel = nullptr;
|
||||||
static bool s_has_nxe = false;
|
static bool s_has_nxe = false;
|
||||||
static bool s_has_pge = false;
|
static bool s_has_pge = false;
|
||||||
static bool s_has_gib = false;
|
|
||||||
|
|
||||||
static paddr_t s_global_pml4_entries[512] { 0 };
|
// PML4 entry for kernel memory
|
||||||
|
static paddr_t s_global_pml4e = 0;
|
||||||
static uint64_t* s_fast_page_pt { nullptr };
|
|
||||||
|
|
||||||
static constexpr inline bool is_canonical(uintptr_t addr)
|
static constexpr inline bool is_canonical(uintptr_t addr)
|
||||||
{
|
{
|
||||||
@@ -57,27 +47,7 @@ namespace Kernel
|
|||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static paddr_t allocate_zeroed_page_aligned_page()
|
static inline PageTable::flags_t parse_flags(uint64_t entry)
|
||||||
{
|
|
||||||
const paddr_t paddr = Heap::get().take_free_page();
|
|
||||||
ASSERT(paddr);
|
|
||||||
memset(reinterpret_cast<void*>(paddr + s_hhdm_offset), 0, PAGE_SIZE);
|
|
||||||
return paddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unallocate_page(paddr_t paddr)
|
|
||||||
{
|
|
||||||
Heap::get().release_page(paddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t* P2V(paddr_t paddr)
|
|
||||||
{
|
|
||||||
ASSERT(paddr != 0);
|
|
||||||
ASSERT(!BAN::Math::will_addition_overflow(paddr, s_hhdm_offset));
|
|
||||||
return reinterpret_cast<uint64_t*>(paddr + s_hhdm_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PageTable::flags_t parse_flags(uint64_t entry)
|
|
||||||
{
|
{
|
||||||
using Flags = PageTable::Flags;
|
using Flags = PageTable::Flags;
|
||||||
|
|
||||||
@@ -95,129 +65,22 @@ namespace Kernel
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// page size:
|
void PageTable::initialize()
|
||||||
// 0: 4 KiB
|
|
||||||
// 1: 2 MiB
|
|
||||||
// 2: 1 GiB
|
|
||||||
static void map_hhdm_page(paddr_t pml4, paddr_t paddr, uint8_t page_size)
|
|
||||||
{
|
|
||||||
ASSERT(0 <= page_size && page_size <= 2);
|
|
||||||
|
|
||||||
const vaddr_t vaddr = paddr + s_hhdm_offset;
|
|
||||||
ASSERT(vaddr < KERNEL_OFFSET);
|
|
||||||
|
|
||||||
const vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
|
||||||
const uint16_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
|
||||||
const uint16_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
|
||||||
const uint16_t pde = (uc_vaddr >> 21) & 0x1FF;
|
|
||||||
const uint16_t pte = (uc_vaddr >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
static constexpr uint64_t hhdm_flags = (1u << 1) | (1u << 0);
|
|
||||||
|
|
||||||
const auto get_or_allocate_entry =
|
|
||||||
[](paddr_t table, uint16_t table_entry, uint64_t extra_flags) -> paddr_t
|
|
||||||
{
|
|
||||||
paddr_t result = 0;
|
|
||||||
PageTable::with_fast_page(table, [&] {
|
|
||||||
const uint64_t entry = PageTable::fast_page_as_sized<uint64_t>(table_entry);
|
|
||||||
if (entry & (1u << 0))
|
|
||||||
result = entry & s_page_addr_mask;
|
|
||||||
});
|
|
||||||
if (result != 0)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
const paddr_t new_paddr = Heap::get().take_free_page();
|
|
||||||
ASSERT(new_paddr);
|
|
||||||
|
|
||||||
PageTable::with_fast_page(new_paddr, [] {
|
|
||||||
memset(reinterpret_cast<void*>(PageTable::fast_page_as_ptr()), 0, PAGE_SIZE);
|
|
||||||
});
|
|
||||||
|
|
||||||
PageTable::with_fast_page(table, [&] {
|
|
||||||
uint64_t& entry = PageTable::fast_page_as_sized<uint64_t>(table_entry);
|
|
||||||
entry = new_paddr | hhdm_flags | extra_flags;
|
|
||||||
});
|
|
||||||
|
|
||||||
return new_paddr;
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint64_t pgsize_flag = page_size ? (static_cast<uint64_t>(1) << 7) : 0;
|
|
||||||
const uint64_t global_flag = s_has_pge ? (static_cast<uint64_t>(1) << 8) : 0;
|
|
||||||
const uint64_t noexec_flag = s_has_nxe ? (static_cast<uint64_t>(1) << 63) : 0;
|
|
||||||
|
|
||||||
const paddr_t pdpt = get_or_allocate_entry(pml4, pml4e, noexec_flag);
|
|
||||||
s_global_pml4_entries[pml4e] = pdpt | hhdm_flags | noexec_flag;
|
|
||||||
|
|
||||||
paddr_t lowest_paddr = pdpt;
|
|
||||||
uint16_t lowest_entry = pdpte;
|
|
||||||
|
|
||||||
if (page_size < 2)
|
|
||||||
{
|
|
||||||
lowest_paddr = get_or_allocate_entry(lowest_paddr, lowest_entry, noexec_flag);
|
|
||||||
lowest_entry = pde;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (page_size < 1)
|
|
||||||
{
|
|
||||||
lowest_paddr = get_or_allocate_entry(lowest_paddr, lowest_entry, noexec_flag);
|
|
||||||
lowest_entry = pte;
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable::with_fast_page(lowest_paddr, [&] {
|
|
||||||
uint64_t& entry = PageTable::fast_page_as_sized<uint64_t>(lowest_entry);
|
|
||||||
entry = paddr | hhdm_flags | noexec_flag | global_flag | pgsize_flag;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initialize_hhdm(paddr_t pml4)
|
|
||||||
{
|
|
||||||
for (const auto& entry : g_boot_info.memory_map_entries)
|
|
||||||
{
|
|
||||||
if (entry.type != MemoryMapEntry::Type::Available)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
constexpr size_t one_gib = 1024 * 1024 * 1024;
|
|
||||||
constexpr size_t two_mib = 2 * 1024 * 1024;
|
|
||||||
|
|
||||||
const paddr_t entry_start = (entry.address + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
|
|
||||||
const paddr_t entry_end = (entry.address + entry.length) & PAGE_ADDR_MASK;
|
|
||||||
for (paddr_t paddr = entry_start; paddr < entry_end;)
|
|
||||||
{
|
|
||||||
if (s_has_gib && paddr % one_gib == 0 && paddr + one_gib <= entry_end)
|
|
||||||
{
|
|
||||||
map_hhdm_page(pml4, paddr, 2);
|
|
||||||
paddr += one_gib;
|
|
||||||
}
|
|
||||||
else if (paddr % two_mib == 0 && paddr + two_mib <= entry_end)
|
|
||||||
{
|
|
||||||
map_hhdm_page(pml4, paddr, 1);
|
|
||||||
paddr += two_mib;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
map_hhdm_page(pml4, paddr, 0);
|
|
||||||
paddr += PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::initialize_fast_page()
|
|
||||||
{
|
|
||||||
s_fast_page_pt = g_boot_fast_page_pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void detect_cpu_features()
|
|
||||||
{
|
{
|
||||||
if (CPUID::has_nxe())
|
if (CPUID::has_nxe())
|
||||||
s_has_nxe = true;
|
s_has_nxe = true;
|
||||||
|
|
||||||
if (CPUID::has_pge())
|
if (CPUID::has_pge())
|
||||||
s_has_pge = true;
|
s_has_pge = true;
|
||||||
if (CPUID::has_1gib_pages())
|
|
||||||
s_has_gib = true;
|
ASSERT(s_kernel == nullptr);
|
||||||
|
s_kernel = new PageTable();
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
|
s_kernel->initialize_kernel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::enable_cpu_features()
|
void PageTable::initial_load()
|
||||||
{
|
{
|
||||||
if (s_has_nxe)
|
if (s_has_nxe)
|
||||||
{
|
{
|
||||||
@@ -256,63 +119,8 @@ namespace Kernel
|
|||||||
"movq %%rax, %%cr0;"
|
"movq %%rax, %%cr0;"
|
||||||
::: "rax"
|
::: "rax"
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::initialize_and_load()
|
load();
|
||||||
{
|
|
||||||
detect_cpu_features();
|
|
||||||
enable_cpu_features();
|
|
||||||
|
|
||||||
const paddr_t boot_pml4_paddr = ({
|
|
||||||
paddr_t paddr;
|
|
||||||
asm volatile("movq %%cr3, %0" : "=r"(paddr));
|
|
||||||
paddr;
|
|
||||||
});
|
|
||||||
|
|
||||||
initialize_hhdm(boot_pml4_paddr);
|
|
||||||
|
|
||||||
ASSERT(s_kernel == nullptr);
|
|
||||||
s_kernel = new PageTable();
|
|
||||||
ASSERT(s_kernel != nullptr);
|
|
||||||
|
|
||||||
s_kernel->m_highest_paging_struct = allocate_zeroed_page_aligned_page();
|
|
||||||
ASSERT(s_kernel->m_highest_paging_struct);
|
|
||||||
|
|
||||||
uint64_t* pml4 = P2V(s_kernel->m_highest_paging_struct);
|
|
||||||
memcpy(pml4, s_global_pml4_entries, sizeof(s_global_pml4_entries));
|
|
||||||
s_kernel->map_kernel_memory();
|
|
||||||
s_global_pml4_entries[511] = pml4[511];
|
|
||||||
|
|
||||||
// update fast page pt
|
|
||||||
{
|
|
||||||
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
|
||||||
constexpr uint16_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
|
||||||
constexpr uint16_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
|
||||||
constexpr uint16_t pde = (uc_vaddr >> 21) & 0x1FF;
|
|
||||||
|
|
||||||
const auto get_or_allocate_entry =
|
|
||||||
[](paddr_t table_paddr, uint16_t entry, uint64_t flags)
|
|
||||||
{
|
|
||||||
uint64_t* table = P2V(table_paddr);
|
|
||||||
|
|
||||||
if (!(table[entry] & Flags::Present))
|
|
||||||
{
|
|
||||||
table[entry] = allocate_zeroed_page_aligned_page();
|
|
||||||
ASSERT(table[entry]);
|
|
||||||
}
|
|
||||||
|
|
||||||
table[entry] |= flags;
|
|
||||||
|
|
||||||
return table[entry] & s_page_addr_mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
const paddr_t pml4 = s_kernel->m_highest_paging_struct;
|
|
||||||
const paddr_t pdpt = get_or_allocate_entry(pml4, pml4e, Flags::ReadWrite | Flags::Present);
|
|
||||||
const paddr_t pd = get_or_allocate_entry(pdpt, pdpte, Flags::ReadWrite | Flags::Present);
|
|
||||||
s_fast_page_pt = P2V(get_or_allocate_entry(pd, pde, Flags::ReadWrite | Flags::Present));
|
|
||||||
}
|
|
||||||
|
|
||||||
s_kernel->load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable& PageTable::kernel()
|
PageTable& PageTable::kernel()
|
||||||
@@ -328,118 +136,202 @@ namespace Kernel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_kernel_memory()
|
static uint64_t* allocate_zeroed_page_aligned_page()
|
||||||
{
|
{
|
||||||
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
|
||||||
const vaddr_t kernel_start = reinterpret_cast<vaddr_t>(g_kernel_start);
|
ASSERT(page);
|
||||||
|
memset(page, 0, PAGE_SIZE);
|
||||||
|
return (uint64_t*)page;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static paddr_t V2P(const T vaddr)
|
||||||
|
{
|
||||||
|
return (vaddr_t)vaddr - KERNEL_OFFSET + g_boot_info.kernel_paddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static vaddr_t P2V(const T paddr)
|
||||||
|
{
|
||||||
|
return (paddr_t)paddr - g_boot_info.kernel_paddr + KERNEL_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::initialize_kernel()
|
||||||
|
{
|
||||||
|
ASSERT(s_global_pml4e == 0);
|
||||||
|
s_global_pml4e = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
|
||||||
|
m_highest_paging_struct = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
|
||||||
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
|
pml4[511] = s_global_pml4e;
|
||||||
|
|
||||||
|
prepare_fast_page();
|
||||||
|
|
||||||
|
// Map main bios area below 1 MiB
|
||||||
map_range_at(
|
map_range_at(
|
||||||
kernel_start - KERNEL_OFFSET + g_boot_info.kernel_paddr,
|
0x000E0000,
|
||||||
kernel_start,
|
P2V(0x000E0000),
|
||||||
|
0x00100000 - 0x000E0000,
|
||||||
|
PageTable::Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
||||||
|
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_kernel_start),
|
||||||
|
(vaddr_t)g_kernel_start,
|
||||||
g_kernel_end - g_kernel_start,
|
g_kernel_end - g_kernel_start,
|
||||||
Flags::Present
|
Flags::Present
|
||||||
);
|
);
|
||||||
|
|
||||||
// Map executable kernel memory as executable
|
// Map executable kernel memory as executable
|
||||||
const vaddr_t kernel_execute_start = reinterpret_cast<vaddr_t>(g_kernel_execute_start);
|
|
||||||
map_range_at(
|
map_range_at(
|
||||||
kernel_execute_start - KERNEL_OFFSET + g_boot_info.kernel_paddr,
|
V2P(g_kernel_execute_start),
|
||||||
kernel_execute_start,
|
(vaddr_t)g_kernel_execute_start,
|
||||||
g_kernel_execute_end - g_kernel_execute_start,
|
g_kernel_execute_end - g_kernel_execute_start,
|
||||||
Flags::Execute | Flags::Present
|
Flags::Execute | Flags::Present
|
||||||
);
|
);
|
||||||
|
|
||||||
// Map writable kernel memory as writable
|
// Map writable kernel memory as writable
|
||||||
const vaddr_t kernel_writable_start = reinterpret_cast<vaddr_t>(g_kernel_writable_start);
|
|
||||||
map_range_at(
|
map_range_at(
|
||||||
kernel_writable_start - KERNEL_OFFSET + g_boot_info.kernel_paddr,
|
V2P(g_kernel_writable_start),
|
||||||
kernel_writable_start,
|
(vaddr_t)g_kernel_writable_start,
|
||||||
g_kernel_writable_end - g_kernel_writable_start,
|
g_kernel_writable_end - g_kernel_writable_start,
|
||||||
Flags::ReadWrite | Flags::Present
|
Flags::ReadWrite | Flags::Present
|
||||||
);
|
);
|
||||||
|
|
||||||
// Map userspace memory
|
// Map userspace memory
|
||||||
const vaddr_t userspace_start = reinterpret_cast<vaddr_t>(g_userspace_start);
|
|
||||||
map_range_at(
|
map_range_at(
|
||||||
userspace_start - KERNEL_OFFSET + g_boot_info.kernel_paddr,
|
V2P(g_userspace_start),
|
||||||
userspace_start,
|
(vaddr_t)g_userspace_start,
|
||||||
g_userspace_end - g_userspace_start,
|
g_userspace_end - g_userspace_start,
|
||||||
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PageTable::prepare_fast_page()
|
||||||
|
{
|
||||||
|
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||||
|
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||||
|
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||||
|
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
|
ASSERT(!(pml4[pml4e] & Flags::Present));
|
||||||
|
pml4[pml4e] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
|
ASSERT(!(pdpt[pdpte] & Flags::Present));
|
||||||
|
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
|
ASSERT(!(pd[pde] & Flags::Present));
|
||||||
|
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
|
ASSERT(!(pt[pte] & Flags::Present));
|
||||||
|
pt[pte] = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
}
|
||||||
|
|
||||||
void PageTable::map_fast_page(paddr_t paddr)
|
void PageTable::map_fast_page(paddr_t paddr)
|
||||||
{
|
{
|
||||||
ASSERT(paddr && paddr % PAGE_SIZE == 0);
|
ASSERT(s_kernel);
|
||||||
|
ASSERT(paddr);
|
||||||
|
|
||||||
ASSERT(s_fast_page_pt);
|
|
||||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
ASSERT(!(*s_fast_page_pt & Flags::Present));
|
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||||
s_fast_page_pt[0] = paddr | Flags::ReadWrite | Flags::Present;
|
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||||
|
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||||
|
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(fast_page()));
|
uint64_t* pml4 = (uint64_t*)P2V(s_kernel->m_highest_paging_struct);
|
||||||
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
|
|
||||||
|
ASSERT(!(pt[pte] & Flags::Present));
|
||||||
|
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
invalidate(fast_page(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_fast_page()
|
void PageTable::unmap_fast_page()
|
||||||
{
|
{
|
||||||
ASSERT(s_fast_page_pt);
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
ASSERT((*s_fast_page_pt & Flags::Present));
|
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||||
s_fast_page_pt[0] = 0;
|
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||||
|
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||||
|
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(fast_page()));
|
uint64_t* pml4 = (uint64_t*)P2V(s_kernel->m_highest_paging_struct);
|
||||||
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
|
|
||||||
|
ASSERT(pt[pte] & Flags::Present);
|
||||||
|
pt[pte] = 0;
|
||||||
|
|
||||||
|
invalidate(fast_page(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||||
{
|
{
|
||||||
SpinLockGuard _(s_kernel->m_lock);
|
SpinLockGuard _(s_kernel->m_lock);
|
||||||
|
|
||||||
PageTable* page_table = new PageTable;
|
PageTable* page_table = new PageTable;
|
||||||
if (page_table == nullptr)
|
if (page_table == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
page_table->map_kernel_memory();
|
||||||
page_table->m_highest_paging_struct = allocate_zeroed_page_aligned_page();
|
return page_table;
|
||||||
if (page_table->m_highest_paging_struct == 0)
|
|
||||||
{
|
|
||||||
delete page_table;
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t* pml4 = P2V(page_table->m_highest_paging_struct);
|
void PageTable::map_kernel_memory()
|
||||||
memcpy(pml4, s_global_pml4_entries, sizeof(s_global_pml4_entries));
|
{
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
ASSERT(s_global_pml4e);
|
||||||
|
|
||||||
return page_table;
|
ASSERT(m_highest_paging_struct == 0);
|
||||||
|
m_highest_paging_struct = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
|
||||||
|
uint64_t* kernel_pml4 = (uint64_t*)P2V(s_kernel->m_highest_paging_struct);
|
||||||
|
|
||||||
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
|
pml4[511] = kernel_pml4[511];
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable::~PageTable()
|
PageTable::~PageTable()
|
||||||
{
|
{
|
||||||
if (m_highest_paging_struct == 0)
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
return;
|
|
||||||
|
|
||||||
// NOTE: we only loop until 256 since after that is hhdm
|
// NOTE: we only loop until 511 since the last one is the kernel memory
|
||||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
for (uint64_t pml4e = 0; pml4e < 511; pml4e++)
|
||||||
for (uint64_t pml4e = 0; pml4e < 256; pml4e++)
|
|
||||||
{
|
{
|
||||||
if (!(pml4[pml4e] & Flags::Present))
|
if (!(pml4[pml4e] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
|
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
for (uint64_t pde = 0; pde < 512; pde++)
|
for (uint64_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
unallocate_page(pd[pde] & s_page_addr_mask);
|
kfree((void*)P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||||
}
|
}
|
||||||
unallocate_page(pdpt[pdpte] & s_page_addr_mask);
|
kfree(pd);
|
||||||
}
|
}
|
||||||
unallocate_page(pml4[pml4e] & s_page_addr_mask);
|
kfree(pdpt);
|
||||||
}
|
}
|
||||||
unallocate_page(m_highest_paging_struct);
|
kfree(pml4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::load()
|
void PageTable::load()
|
||||||
@@ -449,39 +341,10 @@ namespace Kernel
|
|||||||
Processor::set_current_page_table(this);
|
Processor::set_current_page_table(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
|
void PageTable::invalidate(vaddr_t vaddr, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
||||||
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
|
||||||
if (is_userspace && this != &PageTable::current())
|
|
||||||
;
|
|
||||||
else if (pages <= 32 || !s_is_initialized)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(vaddr));
|
|
||||||
}
|
|
||||||
else if (is_userspace || !s_has_pge)
|
|
||||||
{
|
|
||||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
"movq %%cr4, %%rax;"
|
|
||||||
|
|
||||||
"andq $~0x80, %%rax;"
|
|
||||||
"movq %%rax, %%cr4;"
|
|
||||||
|
|
||||||
"movq %0, %%cr3;"
|
|
||||||
|
|
||||||
"orq $0x80, %%rax;"
|
|
||||||
"movq %%rax, %%cr4;"
|
|
||||||
:
|
|
||||||
: "r"(m_highest_paging_struct)
|
|
||||||
: "rax"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send_smp_message)
|
if (send_smp_message)
|
||||||
{
|
{
|
||||||
@@ -489,14 +352,13 @@ namespace Kernel
|
|||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
.flush_tlb = {
|
.flush_tlb = {
|
||||||
.vaddr = vaddr,
|
.vaddr = vaddr,
|
||||||
.page_count = pages,
|
.page_count = 1
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
void PageTable::unmap_page(vaddr_t vaddr, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
@@ -506,65 +368,66 @@ namespace Kernel
|
|||||||
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
||||||
|
|
||||||
ASSERT(is_canonical(vaddr));
|
ASSERT(is_canonical(vaddr));
|
||||||
const vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
||||||
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
const uint16_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||||
const uint16_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||||
const uint16_t pde = (uc_vaddr >> 21) & 0x1FF;
|
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||||
const uint16_t pte = (uc_vaddr >> 12) & 0x1FF;
|
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
if (is_page_free(vaddr))
|
if (is_page_free(vaddr))
|
||||||
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
||||||
|
|
||||||
uint64_t* pml4 = P2V(m_highest_paging_struct);
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
|
|
||||||
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
|
|
||||||
|
|
||||||
pt[pte] = 0;
|
pt[pte] = 0;
|
||||||
|
invalidate(vaddr, send_smp_message);
|
||||||
if (invalidate && old_paddr != 0)
|
|
||||||
invalidate_page(vaddr, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
const size_t page_count = range_page_count(vaddr, size);
|
size_t page_count = range_page_count(vaddr, size);
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (vaddr_t page = 0; page < page_count; page++)
|
for (vaddr_t page = 0; page < page_count; page++)
|
||||||
unmap_page(vaddr + page * PAGE_SIZE, false);
|
unmap_page(vaddr + page * PAGE_SIZE, false);
|
||||||
invalidate_range(vaddr, page_count, true);
|
|
||||||
|
Processor::broadcast_smp_message({
|
||||||
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
|
.flush_tlb = {
|
||||||
|
.vaddr = vaddr,
|
||||||
|
.page_count = page_count
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
if (vaddr < KERNEL_OFFSET && this == s_kernel)
|
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||||
panic("kernel is mapping below kernel offset");
|
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
||||||
if (vaddr >= s_hhdm_offset && this != s_kernel)
|
|
||||||
panic("user is mapping above hhdm offset");
|
|
||||||
|
|
||||||
ASSERT(is_canonical(vaddr));
|
ASSERT(is_canonical(vaddr));
|
||||||
const vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
||||||
|
|
||||||
ASSERT(paddr % PAGE_SIZE == 0);
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
ASSERT(flags & Flags::Used);
|
ASSERT(flags & Flags::Used);
|
||||||
|
|
||||||
const uint16_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||||
const uint16_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||||
const uint16_t pde = (uc_vaddr >> 21) & 0x1FF;
|
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||||
const uint16_t pte = (uc_vaddr >> 12) & 0x1FF;
|
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t extra_flags = 0;
|
uint64_t extra_flags = 0;
|
||||||
if (s_has_pge && pml4e == 511) // Map kernel memory as global
|
if (s_has_pge && pml4e == 511) // Map kernel memory as global
|
||||||
@@ -586,32 +449,37 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
const auto allocate_entry_if_needed =
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
[](uint64_t* table, uint16_t index, flags_t flags) -> uint64_t*
|
if ((pml4[pml4e] & uwr_flags) != uwr_flags)
|
||||||
{
|
{
|
||||||
uint64_t entry = table[index];
|
if (!(pml4[pml4e] & Flags::Present))
|
||||||
if ((entry & flags) == flags)
|
pml4[pml4e] = V2P(allocate_zeroed_page_aligned_page());
|
||||||
return P2V(entry & s_page_addr_mask);
|
pml4[pml4e] |= uwr_flags;
|
||||||
if (!(entry & Flags::Present))
|
}
|
||||||
entry = allocate_zeroed_page_aligned_page();
|
|
||||||
table[index] = entry | flags;
|
|
||||||
return P2V(entry & s_page_addr_mask);
|
|
||||||
};
|
|
||||||
|
|
||||||
uint64_t* pml4 = P2V(m_highest_paging_struct);
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
uint64_t* pdpt = allocate_entry_if_needed(pml4, pml4e, uwr_flags);
|
if ((pdpt[pdpte] & uwr_flags) != uwr_flags)
|
||||||
uint64_t* pd = allocate_entry_if_needed(pdpt, pdpte, uwr_flags);
|
{
|
||||||
uint64_t* pt = allocate_entry_if_needed(pd, pde, uwr_flags);
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
pdpt[pdpte] |= uwr_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
|
if ((pd[pde] & uwr_flags) != uwr_flags)
|
||||||
|
{
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
pd[pde] = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
pd[pde] |= uwr_flags;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(flags & Flags::Present))
|
if (!(flags & Flags::Present))
|
||||||
uwr_flags &= ~Flags::Present;
|
uwr_flags &= ~Flags::Present;
|
||||||
|
|
||||||
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
|
|
||||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||||
|
|
||||||
if (invalidate && old_paddr != 0)
|
invalidate(vaddr, send_smp_message);
|
||||||
invalidate_page(vaddr, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
@@ -627,95 +495,43 @@ namespace Kernel
|
|||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (size_t page = 0; page < page_count; page++)
|
for (size_t page = 0; page < page_count; page++)
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
||||||
invalidate_range(vaddr, page_count, true);
|
|
||||||
|
Processor::broadcast_smp_message({
|
||||||
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
|
.flush_tlb = {
|
||||||
|
.vaddr = vaddr,
|
||||||
|
.page_count = page_count
|
||||||
}
|
}
|
||||||
|
});
|
||||||
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
|
|
||||||
{
|
|
||||||
ASSERT(vaddr);
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
|
|
||||||
ASSERT(is_canonical(vaddr));
|
|
||||||
ASSERT(is_canonical(vaddr + size - 1));
|
|
||||||
|
|
||||||
const vaddr_t uc_vaddr_start = uncanonicalize(vaddr);
|
|
||||||
const vaddr_t uc_vaddr_end = uncanonicalize(vaddr + size - 1);
|
|
||||||
|
|
||||||
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
|
||||||
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
|
||||||
uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF;
|
|
||||||
uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
const uint16_t e_pml4e = (uc_vaddr_end >> 39) & 0x1FF;
|
|
||||||
const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF;
|
|
||||||
const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF;
|
|
||||||
const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
|
||||||
for (; pml4e <= e_pml4e; pml4e++)
|
|
||||||
{
|
|
||||||
if (!(pml4[pml4e] & Flags::ReadWrite))
|
|
||||||
continue;
|
|
||||||
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
|
||||||
for (; pdpte < 512; pdpte++)
|
|
||||||
{
|
|
||||||
if (pml4e == e_pml4e && pdpte > e_pdpte)
|
|
||||||
break;
|
|
||||||
if (!(pdpt[pdpte] & Flags::ReadWrite))
|
|
||||||
continue;
|
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
|
||||||
for (; pde < 512; pde++)
|
|
||||||
{
|
|
||||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde)
|
|
||||||
break;
|
|
||||||
if (!(pd[pde] & Flags::ReadWrite))
|
|
||||||
continue;
|
|
||||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
|
||||||
for (; pte < 512; pte++)
|
|
||||||
{
|
|
||||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
|
||||||
break;
|
|
||||||
pt[pte] &= ~static_cast<uint64_t>(Flags::ReadWrite);
|
|
||||||
}
|
|
||||||
pte = 0;
|
|
||||||
}
|
|
||||||
pde = 0;
|
|
||||||
}
|
|
||||||
pdpte = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidate_range(vaddr, size / PAGE_SIZE, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
{
|
{
|
||||||
ASSERT(is_canonical(vaddr));
|
ASSERT(is_canonical(vaddr));
|
||||||
const vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
||||||
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
const uint16_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||||
const uint16_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||||
const uint16_t pde = (uc_vaddr >> 21) & 0x1FF;
|
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||||
const uint16_t pte = (uc_vaddr >> 12) & 0x1FF;
|
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
if (!(pml4[pml4e] & Flags::Present))
|
if (!(pml4[pml4e] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
if (!(pt[pte] & Flags::Used))
|
if (!(pt[pte] & Flags::Used))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -730,16 +546,16 @@ namespace Kernel
|
|||||||
paddr_t PageTable::physical_address_of(vaddr_t addr) const
|
paddr_t PageTable::physical_address_of(vaddr_t addr) const
|
||||||
{
|
{
|
||||||
uint64_t page_data = get_page_data(addr);
|
uint64_t page_data = get_page_data(addr);
|
||||||
return page_data & s_page_addr_mask;
|
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool invalidate)
|
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
if (only_free && !is_page_free(vaddr))
|
if (only_free && !is_page_free(vaddr))
|
||||||
return false;
|
return false;
|
||||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, invalidate);
|
map_page_at(0, vaddr, Flags::Reserved);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,8 +569,7 @@ namespace Kernel
|
|||||||
if (only_free && !is_range_free(vaddr, bytes))
|
if (only_free && !is_range_free(vaddr, bytes))
|
||||||
return false;
|
return false;
|
||||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||||
reserve_page(vaddr + offset, true, false);
|
reserve_page(vaddr + offset);
|
||||||
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,9 +583,9 @@ namespace Kernel
|
|||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
ASSERT(is_canonical(first_address));
|
ASSERT(is_canonical(first_address));
|
||||||
ASSERT(is_canonical(last_address - 1));
|
ASSERT(is_canonical(last_address));
|
||||||
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
||||||
const vaddr_t uc_vaddr_end = uncanonicalize(last_address - 1);
|
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
|
||||||
|
|
||||||
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
||||||
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
||||||
@@ -786,58 +601,61 @@ namespace Kernel
|
|||||||
|
|
||||||
// Try to find free page that can be mapped without
|
// Try to find free page that can be mapped without
|
||||||
// allocations (page table with unused entries)
|
// allocations (page table with unused entries)
|
||||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
for (; pml4e <= e_pml4e; pml4e++)
|
for (; pml4e < 512; pml4e++)
|
||||||
{
|
{
|
||||||
|
if (pml4e > e_pml4e)
|
||||||
|
break;
|
||||||
if (!(pml4[pml4e] & Flags::Present))
|
if (!(pml4[pml4e] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
for (; pdpte < 512; pdpte++)
|
for (; pdpte < 512; pdpte++)
|
||||||
{
|
{
|
||||||
if (pml4e == e_pml4e && pdpte > e_pdpte)
|
if (pml4e == e_pml4e && pdpte > e_pdpte)
|
||||||
break;
|
break;
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
for (; pde < 512; pde++)
|
for (; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde)
|
if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde)
|
||||||
break;
|
break;
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
for (; pte < 512; pte++)
|
for (; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
||||||
break;
|
break;
|
||||||
if (pt[pte] & Flags::Used)
|
if (!(pt[pte] & Flags::Used))
|
||||||
continue;
|
{
|
||||||
vaddr_t vaddr = 0;
|
vaddr_t vaddr = 0;
|
||||||
vaddr |= static_cast<uint64_t>(pml4e) << 39;
|
vaddr |= (uint64_t)pml4e << 39;
|
||||||
vaddr |= static_cast<uint64_t>(pdpte) << 30;
|
vaddr |= (uint64_t)pdpte << 30;
|
||||||
vaddr |= static_cast<uint64_t>(pde) << 21;
|
vaddr |= (uint64_t)pde << 21;
|
||||||
vaddr |= static_cast<uint64_t>(pte) << 12;
|
vaddr |= (uint64_t)pte << 12;
|
||||||
vaddr = canonicalize(vaddr);
|
vaddr = canonicalize(vaddr);
|
||||||
ASSERT(reserve_page(vaddr));
|
ASSERT(reserve_page(vaddr));
|
||||||
return vaddr;
|
return vaddr;
|
||||||
}
|
}
|
||||||
pte = 0;
|
|
||||||
}
|
}
|
||||||
pde = 0;
|
|
||||||
}
|
}
|
||||||
pdpte = 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (vaddr_t uc_vaddr = uc_vaddr_start; uc_vaddr < uc_vaddr_end; uc_vaddr += PAGE_SIZE)
|
// Find any free page
|
||||||
|
vaddr_t uc_vaddr = uc_vaddr_start;
|
||||||
|
while (uc_vaddr < uc_vaddr_end)
|
||||||
{
|
{
|
||||||
if (vaddr_t vaddr = canonicalize(uc_vaddr); is_page_free(vaddr))
|
if (vaddr_t vaddr = canonicalize(uc_vaddr); is_page_free(vaddr))
|
||||||
{
|
{
|
||||||
ASSERT(reserve_page(vaddr));
|
ASSERT(reserve_page(vaddr));
|
||||||
return vaddr;
|
return vaddr;
|
||||||
}
|
}
|
||||||
|
uc_vaddr += PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||||
@@ -850,7 +668,7 @@ namespace Kernel
|
|||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
ASSERT(is_canonical(first_address));
|
ASSERT(is_canonical(first_address));
|
||||||
ASSERT(is_canonical(last_address - 1));
|
ASSERT(is_canonical(last_address));
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
@@ -879,7 +697,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::is_page_free(vaddr_t page) const
|
bool PageTable::is_page_free(vaddr_t page) const
|
||||||
@@ -921,16 +739,16 @@ namespace Kernel
|
|||||||
flags_t flags = 0;
|
flags_t flags = 0;
|
||||||
vaddr_t start = 0;
|
vaddr_t start = 0;
|
||||||
|
|
||||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||||
for (uint64_t pml4e = 0; pml4e < 512; pml4e++)
|
for (uint64_t pml4e = 0; pml4e < 512; pml4e++)
|
||||||
{
|
{
|
||||||
if (!(pml4[pml4e] & Flags::Present) || (pml4e >= 256 && pml4e < 511))
|
if (!(pml4[pml4e] & Flags::Present))
|
||||||
{
|
{
|
||||||
dump_range(start, (pml4e << 39), flags);
|
dump_range(start, (pml4e << 39), flags);
|
||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||||
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
|
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
@@ -939,7 +757,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||||
for (uint64_t pde = 0; pde < 512; pde++)
|
for (uint64_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
@@ -948,7 +766,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||||
for (uint64_t pte = 0; pte < 512; pte++)
|
for (uint64_t pte = 0; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (parse_flags(pt[pte]) != flags)
|
if (parse_flags(pt[pte]) != flags)
|
||||||
|
|||||||
@@ -1,97 +1,57 @@
|
|||||||
.section .userspace, "ax"
|
.section .userspace, "ax"
|
||||||
|
|
||||||
// stack contains
|
// stack contains
|
||||||
// (8 bytes) return address (on return stack)
|
// return address
|
||||||
// (8 bytes) return stack
|
// signal number
|
||||||
// (8 bytes) return rflags
|
// signal handler
|
||||||
// (8 bytes) restore sigmask
|
|
||||||
// (56 bytes) siginfo_t
|
|
||||||
// (8 bytes) signal number
|
|
||||||
// (8 bytes) signal handler
|
|
||||||
|
|
||||||
.global signal_trampoline
|
.global signal_trampoline
|
||||||
signal_trampoline:
|
signal_trampoline:
|
||||||
pushq %r15 // gregs
|
pushq %rax
|
||||||
pushq %r14
|
|
||||||
pushq %r13
|
|
||||||
pushq %r12
|
|
||||||
pushq %r11
|
|
||||||
pushq %r10
|
|
||||||
pushq %r9
|
|
||||||
pushq %r8
|
|
||||||
pushq %rsi
|
|
||||||
pushq %rdi
|
|
||||||
pushq %rdx
|
|
||||||
pushq %rcx
|
|
||||||
pushq %rbx
|
pushq %rbx
|
||||||
pushq %rax
|
pushq %rcx
|
||||||
|
pushq %rdx
|
||||||
pushq %rbp
|
pushq %rbp
|
||||||
|
pushq %rdi
|
||||||
|
pushq %rsi
|
||||||
|
pushq %r8
|
||||||
|
pushq %r9
|
||||||
|
pushq %r10
|
||||||
|
pushq %r11
|
||||||
|
pushq %r12
|
||||||
|
pushq %r13
|
||||||
|
pushq %r14
|
||||||
|
pushq %r15
|
||||||
|
|
||||||
movq 208(%rsp), %rax
|
movq 128(%rsp), %rdi
|
||||||
pushq %rax; addq $(128 + 8), (%rsp)
|
movq 120(%rsp), %rax
|
||||||
pushq (%rax)
|
|
||||||
|
|
||||||
// FIXME: populate these
|
|
||||||
xorq %rax, %rax
|
|
||||||
pushq %rax // stack
|
|
||||||
pushq %rax
|
|
||||||
pushq %rax
|
|
||||||
pushq %rax // sigset
|
|
||||||
pushq %rax // link
|
|
||||||
|
|
||||||
movq %rsp, %rdx // ucontext
|
|
||||||
leaq 192(%rsp), %rsi // siginfo
|
|
||||||
movq 184(%rsp), %rdi // signal number
|
|
||||||
movq 176(%rsp), %rax // handler
|
|
||||||
|
|
||||||
// align stack to 16 bytes
|
// align stack to 16 bytes
|
||||||
movq %rsp, %rbp
|
movq %rsp, %rbx
|
||||||
andq $-16, %rsp
|
andq $0x0F, %rbx
|
||||||
|
subq %rbx, %rsp
|
||||||
subq $512, %rsp
|
|
||||||
fxsave64 (%rsp)
|
|
||||||
|
|
||||||
call *%rax
|
call *%rax
|
||||||
|
|
||||||
fxrstor64 (%rsp)
|
|
||||||
addq $512, %rsp
|
|
||||||
|
|
||||||
// restore stack
|
// restore stack
|
||||||
movq %rbp, %rsp
|
addq %rbx, %rsp
|
||||||
addq $40, %rsp
|
|
||||||
|
|
||||||
// restore sigmask
|
|
||||||
movq $83, %rdi // SYS_SIGPROCMASK
|
|
||||||
movq $3, %rsi // SIG_SETMASK
|
|
||||||
leaq 192(%rsp), %rdx // set
|
|
||||||
xorq %r10, %r10 // oset
|
|
||||||
syscall
|
|
||||||
|
|
||||||
// restore registers
|
|
||||||
addq $16, %rsp
|
|
||||||
popq %rbp
|
|
||||||
popq %rax
|
|
||||||
popq %rbx
|
|
||||||
popq %rcx
|
|
||||||
popq %rdx
|
|
||||||
popq %rdi
|
|
||||||
popq %rsi
|
|
||||||
popq %r8
|
|
||||||
popq %r9
|
|
||||||
popq %r10
|
|
||||||
popq %r11
|
|
||||||
popq %r12
|
|
||||||
popq %r13
|
|
||||||
popq %r14
|
|
||||||
popq %r15
|
popq %r15
|
||||||
|
popq %r14
|
||||||
|
popq %r13
|
||||||
|
popq %r12
|
||||||
|
popq %r11
|
||||||
|
popq %r10
|
||||||
|
popq %r9
|
||||||
|
popq %r8
|
||||||
|
popq %rsi
|
||||||
|
popq %rdi
|
||||||
|
popq %rbp
|
||||||
|
popq %rdx
|
||||||
|
popq %rcx
|
||||||
|
popq %rbx
|
||||||
|
popq %rax
|
||||||
|
|
||||||
// skip handler, number, siginfo_t, sigmask
|
addq $16, %rsp
|
||||||
addq $80, %rsp
|
|
||||||
|
|
||||||
// restore flags
|
|
||||||
popfq
|
|
||||||
|
|
||||||
movq (%rsp), %rsp
|
|
||||||
|
|
||||||
// return over red-zone
|
// return over red-zone
|
||||||
ret $128
|
ret $128
|
||||||
|
|||||||
@@ -1,26 +1,48 @@
|
|||||||
|
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
|
||||||
|
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
|
||||||
.global asm_syscall_handler
|
.global asm_syscall_handler
|
||||||
asm_syscall_handler:
|
asm_syscall_handler:
|
||||||
swapgs
|
pushq %rbx
|
||||||
|
|
||||||
movq %rsp, %rax
|
|
||||||
movq %gs:8, %rsp
|
|
||||||
|
|
||||||
pushq $(0x20 | 3)
|
|
||||||
pushq %rax
|
|
||||||
pushq %r11
|
|
||||||
pushq $(0x28 | 3)
|
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
subq $8, %rsp
|
pushq %rdx
|
||||||
|
pushq %rdi
|
||||||
|
pushq %rsi
|
||||||
|
pushq %rbp
|
||||||
|
pushq %r8
|
||||||
|
pushq %r9
|
||||||
|
pushq %r10
|
||||||
|
pushq %r11
|
||||||
|
pushq %r12
|
||||||
|
pushq %r13
|
||||||
|
pushq %r14
|
||||||
|
pushq %r15
|
||||||
|
|
||||||
movq %r10, %rcx
|
movq %rsi, %r8
|
||||||
|
movq %rdi, %r9
|
||||||
|
movq %rax, %rdi
|
||||||
|
movq %rbx, %rsi
|
||||||
|
xchgq %rcx, %rdx
|
||||||
|
leaq 112(%rsp), %rbx
|
||||||
|
pushq %rbx
|
||||||
call cpp_syscall_handler
|
call cpp_syscall_handler
|
||||||
|
addq $8, %rsp
|
||||||
|
|
||||||
movq 8(%rsp), %rcx
|
popq %r15
|
||||||
movq 24(%rsp), %r11
|
popq %r14
|
||||||
movq 32(%rsp), %rsp
|
popq %r13
|
||||||
|
popq %r12
|
||||||
|
popq %r11
|
||||||
|
popq %r10
|
||||||
|
popq %r9
|
||||||
|
popq %r8
|
||||||
|
popq %rbp
|
||||||
|
popq %rsi
|
||||||
|
popq %rdi
|
||||||
|
popq %rdx
|
||||||
|
popq %rcx
|
||||||
|
popq %rbx
|
||||||
|
iretq
|
||||||
|
|
||||||
swapgs
|
|
||||||
sysretq
|
|
||||||
|
|
||||||
.global sys_fork_trampoline
|
.global sys_fork_trampoline
|
||||||
sys_fork_trampoline:
|
sys_fork_trampoline:
|
||||||
@@ -33,7 +55,7 @@ sys_fork_trampoline:
|
|||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testq %rax, %rax
|
testq %rax, %rax
|
||||||
jz .done
|
je .reload_stack
|
||||||
|
|
||||||
movq %rax, %rsi
|
movq %rax, %rsi
|
||||||
movq %rsp, %rdi
|
movq %rsp, %rdi
|
||||||
@@ -47,3 +69,9 @@ sys_fork_trampoline:
|
|||||||
popq %rbp
|
popq %rbp
|
||||||
popq %rbx
|
popq %rbx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.reload_stack:
|
||||||
|
call get_thread_start_sp
|
||||||
|
movq %rax, %rsp
|
||||||
|
xorq %rax, %rax
|
||||||
|
jmp .done
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ read_ip:
|
|||||||
# void start_kernel_thread()
|
# void start_kernel_thread()
|
||||||
.global start_kernel_thread
|
.global start_kernel_thread
|
||||||
start_kernel_thread:
|
start_kernel_thread:
|
||||||
|
call get_thread_start_sp
|
||||||
|
movq %rax, %rsp
|
||||||
|
|
||||||
# STACK LAYOUT
|
# STACK LAYOUT
|
||||||
# on_exit arg
|
# on_exit arg
|
||||||
# on_exit func
|
# on_exit func
|
||||||
@@ -24,5 +27,27 @@ start_kernel_thread:
|
|||||||
|
|
||||||
.global start_userspace_thread
|
.global start_userspace_thread
|
||||||
start_userspace_thread:
|
start_userspace_thread:
|
||||||
swapgs
|
call get_thread_start_sp
|
||||||
|
movq %rax, %rsp
|
||||||
|
|
||||||
|
# STACK LAYOUT
|
||||||
|
# entry
|
||||||
|
# argc
|
||||||
|
# argv
|
||||||
|
# envp
|
||||||
|
# userspace stack
|
||||||
|
|
||||||
|
call get_userspace_thread_stack_top
|
||||||
|
|
||||||
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
|
popq %rdx
|
||||||
|
popq %rcx
|
||||||
|
popq %rbx
|
||||||
|
|
||||||
|
pushq $(0x20 | 3)
|
||||||
|
pushq %rax
|
||||||
|
pushq $0x202
|
||||||
|
pushq $(0x18 | 3)
|
||||||
|
pushq %rbx
|
||||||
iretq
|
iretq
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
# bool safe_user_memcpy(void*, const void*, size_t)
|
|
||||||
.global safe_user_memcpy
|
|
||||||
.global safe_user_memcpy_end
|
|
||||||
.global safe_user_memcpy_fault
|
|
||||||
safe_user_memcpy:
|
|
||||||
xorq %rax, %rax
|
|
||||||
movq %rdx, %rcx
|
|
||||||
rep movsb
|
|
||||||
incq %rax
|
|
||||||
safe_user_memcpy_fault:
|
|
||||||
ret
|
|
||||||
safe_user_memcpy_end:
|
|
||||||
|
|
||||||
# bool safe_user_strncpy(void*, const void*, size_t)
|
|
||||||
.global safe_user_strncpy
|
|
||||||
.global safe_user_strncpy_end
|
|
||||||
.global safe_user_strncpy_fault
|
|
||||||
safe_user_strncpy:
|
|
||||||
movq %rdx, %rcx
|
|
||||||
testq %rcx, %rcx
|
|
||||||
jz safe_user_strncpy_fault
|
|
||||||
|
|
||||||
.safe_user_strncpy_align_loop:
|
|
||||||
testb $0x7, %sil
|
|
||||||
jz .safe_user_strncpy_align_done
|
|
||||||
|
|
||||||
movb (%rsi), %al
|
|
||||||
movb %al, (%rdi)
|
|
||||||
testb %al, %al
|
|
||||||
jz .safe_user_strncpy_done
|
|
||||||
|
|
||||||
incq %rdi
|
|
||||||
incq %rsi
|
|
||||||
decq %rcx
|
|
||||||
jnz .safe_user_strncpy_align_loop
|
|
||||||
jmp safe_user_strncpy_fault
|
|
||||||
|
|
||||||
.safe_user_strncpy_align_done:
|
|
||||||
movq $0x0101010101010101, %r8
|
|
||||||
movq $0x8080808080808080, %r9
|
|
||||||
|
|
||||||
.safe_user_strncpy_qword_loop:
|
|
||||||
cmpq $8, %rcx
|
|
||||||
jb .safe_user_strncpy_qword_done
|
|
||||||
|
|
||||||
movq (%rsi), %rax
|
|
||||||
movq %rax, %r10
|
|
||||||
movq %rax, %r11
|
|
||||||
|
|
||||||
# https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
|
|
||||||
subq %r8, %r10
|
|
||||||
notq %r11
|
|
||||||
andq %r11, %r10
|
|
||||||
andq %r9, %r10
|
|
||||||
jnz .safe_user_strncpy_byte_loop
|
|
||||||
|
|
||||||
movq %rax, (%rdi)
|
|
||||||
|
|
||||||
addq $8, %rdi
|
|
||||||
addq $8, %rsi
|
|
||||||
subq $8, %rcx
|
|
||||||
jnz .safe_user_strncpy_qword_loop
|
|
||||||
jmp safe_user_strncpy_fault
|
|
||||||
|
|
||||||
.safe_user_strncpy_qword_done:
|
|
||||||
testq %rcx, %rcx
|
|
||||||
jz safe_user_strncpy_fault
|
|
||||||
|
|
||||||
.safe_user_strncpy_byte_loop:
|
|
||||||
movb (%rsi), %al
|
|
||||||
movb %al, (%rdi)
|
|
||||||
testb %al, %al
|
|
||||||
jz .safe_user_strncpy_done
|
|
||||||
|
|
||||||
incq %rdi
|
|
||||||
incq %rsi
|
|
||||||
decq %rcx
|
|
||||||
jnz .safe_user_strncpy_byte_loop
|
|
||||||
|
|
||||||
safe_user_strncpy_fault:
|
|
||||||
xorq %rax, %rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
.safe_user_strncpy_done:
|
|
||||||
movb $1, %al
|
|
||||||
ret
|
|
||||||
safe_user_strncpy_end:
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
.global asm_yield_trampoline
|
|
||||||
asm_yield_trampoline:
|
|
||||||
leaq 8(%rsp), %rcx
|
|
||||||
movq %rdi, %rsp
|
|
||||||
|
|
||||||
subq $8, %rsp
|
|
||||||
pushq -8(%rcx)
|
|
||||||
pushq %rcx
|
|
||||||
pushq %rax
|
|
||||||
pushq %rbx
|
|
||||||
pushq %rbp
|
|
||||||
pushq %r12
|
|
||||||
pushq %r13
|
|
||||||
pushq %r14
|
|
||||||
pushq %r15
|
|
||||||
|
|
||||||
movq %rsp, %rdi
|
|
||||||
call scheduler_on_yield
|
|
||||||
|
|
||||||
popq %r15
|
|
||||||
popq %r14
|
|
||||||
popq %r13
|
|
||||||
popq %r12
|
|
||||||
popq %rbp
|
|
||||||
popq %rbx
|
|
||||||
popq %rax
|
|
||||||
movq 8(%rsp), %rcx
|
|
||||||
movq 0(%rsp), %rsp
|
|
||||||
jmp *%rcx
|
|
||||||
@@ -11,28 +11,9 @@
|
|||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
// custom addresses, video mode info, page align modules
|
# multiboot2 header
|
||||||
.set multiboot_flags, (1 << 16) | (1 << 2) | (1 << 0)
|
|
||||||
|
|
||||||
.section .multiboot, "aw"
|
.section .multiboot, "aw"
|
||||||
multiboot_start:
|
.align 8
|
||||||
.long 0x1BADB002
|
|
||||||
.long multiboot_flags
|
|
||||||
.long -(0x1BADB002 + multiboot_flags)
|
|
||||||
|
|
||||||
.long V2P(multiboot_start)
|
|
||||||
.long V2P(g_kernel_start)
|
|
||||||
.long V2P(g_kernel_bss_start)
|
|
||||||
.long V2P(g_kernel_end)
|
|
||||||
.long V2P(_start)
|
|
||||||
|
|
||||||
.long 0
|
|
||||||
.long FB_WIDTH
|
|
||||||
.long FB_HEIGHT
|
|
||||||
.long FB_BPP
|
|
||||||
multiboot_end:
|
|
||||||
|
|
||||||
.section .multiboot2, "aw"
|
|
||||||
multiboot2_start:
|
multiboot2_start:
|
||||||
.long 0xE85250D6
|
.long 0xE85250D6
|
||||||
.long 0
|
.long 0
|
||||||
@@ -55,12 +36,6 @@ multiboot2_start:
|
|||||||
.long 12
|
.long 12
|
||||||
.long V2P(_start)
|
.long V2P(_start)
|
||||||
|
|
||||||
# page align modules
|
|
||||||
.align 8
|
|
||||||
.short 6
|
|
||||||
.short 0
|
|
||||||
.long 8
|
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.short 0
|
.short 0
|
||||||
.short 0
|
.short 0
|
||||||
@@ -68,6 +43,7 @@ multiboot2_start:
|
|||||||
multiboot2_end:
|
multiboot2_end:
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
.section .bananboot, "aw"
|
||||||
|
.align 8
|
||||||
bananboot_start:
|
bananboot_start:
|
||||||
.long 0xBABAB007
|
.long 0xBABAB007
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
@@ -77,10 +53,9 @@ bananboot_start:
|
|||||||
bananboot_end:
|
bananboot_end:
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
.global g_boot_stack_top
|
boot_stack_bottom:
|
||||||
g_boot_stack_bottom:
|
.skip 4096 * 64
|
||||||
.skip 4096 * 4
|
boot_stack_top:
|
||||||
g_boot_stack_top:
|
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
.global g_kernel_cmdline
|
||||||
g_kernel_cmdline:
|
g_kernel_cmdline:
|
||||||
@@ -97,25 +72,27 @@ bananboot_end:
|
|||||||
.align 4096
|
.align 4096
|
||||||
boot_pml4:
|
boot_pml4:
|
||||||
.quad V2P(boot_pdpt_lo) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pdpt_lo) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.skip 510 * 8
|
.rept 510
|
||||||
|
.quad 0
|
||||||
|
.endr
|
||||||
.quad V2P(boot_pdpt_hi) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pdpt_hi) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
boot_pdpt_lo:
|
boot_pdpt_lo:
|
||||||
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.skip 511 * 8
|
.rept 511
|
||||||
|
.quad 0
|
||||||
|
.endr
|
||||||
boot_pdpt_hi:
|
boot_pdpt_hi:
|
||||||
.skip 510 * 8
|
.rept 510
|
||||||
|
.quad 0
|
||||||
|
.endr
|
||||||
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.skip 8
|
.quad 0
|
||||||
boot_pd:
|
boot_pd:
|
||||||
.set i, 0
|
.set i, 0
|
||||||
.rept 511
|
.rept 512
|
||||||
.quad i + (PG_PAGE_SIZE | PG_READ_WRITE | PG_PRESENT)
|
.quad i + (PG_PAGE_SIZE | PG_READ_WRITE | PG_PRESENT)
|
||||||
.set i, i + 0x200000
|
.set i, i + 0x200000
|
||||||
.endr
|
.endr
|
||||||
.quad V2P(g_boot_fast_page_pt) + (PG_READ_WRITE | PG_PRESENT)
|
|
||||||
.global g_boot_fast_page_pt
|
|
||||||
g_boot_fast_page_pt:
|
|
||||||
.skip 512 * 8
|
|
||||||
|
|
||||||
boot_gdt:
|
boot_gdt:
|
||||||
.quad 0x0000000000000000 # null descriptor
|
.quad 0x0000000000000000 # null descriptor
|
||||||
@@ -178,13 +155,6 @@ enable_sse:
|
|||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
ret
|
ret
|
||||||
|
|
||||||
enable_tsc:
|
|
||||||
# allow userspace to use RDTSC
|
|
||||||
movl %cr4, %ecx
|
|
||||||
andl $0xFFFFFFFB, %ecx
|
|
||||||
movl %ecx, %cr4
|
|
||||||
ret
|
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# enable PAE
|
# enable PAE
|
||||||
movl %cr4, %ecx
|
movl %cr4, %ecx
|
||||||
@@ -217,11 +187,10 @@ _start:
|
|||||||
movl %eax, V2P(bootloader_magic)
|
movl %eax, V2P(bootloader_magic)
|
||||||
movl %ebx, V2P(bootloader_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
movl $V2P(g_boot_stack_top), %esp
|
movl $V2P(boot_stack_top), %esp
|
||||||
|
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
call enable_tsc
|
|
||||||
call initialize_paging
|
call initialize_paging
|
||||||
|
|
||||||
# flush gdt and jump to 64 bit
|
# flush gdt and jump to 64 bit
|
||||||
@@ -271,7 +240,7 @@ system_halt:
|
|||||||
jmp 1b
|
jmp 1b
|
||||||
|
|
||||||
|
|
||||||
#define AP_REL(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
#define AP_V2P(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
||||||
|
|
||||||
.section .ap_init, "ax"
|
.section .ap_init, "ax"
|
||||||
|
|
||||||
@@ -281,27 +250,21 @@ ap_trampoline:
|
|||||||
jmp 1f
|
jmp 1f
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
ap_stack_paddr:
|
ap_stack_ptr:
|
||||||
.skip 8
|
.skip 4
|
||||||
ap_stack_vaddr:
|
ap_stack_loaded:
|
||||||
.skip 8
|
.skip 1
|
||||||
ap_prepare_paging:
|
|
||||||
.skip 8
|
|
||||||
ap_page_table:
|
|
||||||
.skip 8
|
|
||||||
ap_ready:
|
|
||||||
.skip 8
|
|
||||||
|
|
||||||
1: cli; cld
|
1: cli; cld
|
||||||
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
ljmpl $0x00, $AP_V2P(ap_cs_clear)
|
||||||
|
|
||||||
ap_cs_clear:
|
ap_cs_clear:
|
||||||
# load ap gdt and enter protected mode
|
# load ap gdt and enter protected mode
|
||||||
lgdt AP_REL(ap_gdtr)
|
lgdt AP_V2P(ap_gdtr)
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
ljmpl $0x08, $AP_V2P(ap_protected_mode)
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
ap_protected_mode:
|
ap_protected_mode:
|
||||||
@@ -310,42 +273,36 @@ ap_protected_mode:
|
|||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
|
|
||||||
movl AP_REL(ap_stack_paddr), %esp
|
movl AP_V2P(ap_stack_ptr), %esp
|
||||||
|
movb $1, AP_V2P(ap_stack_loaded)
|
||||||
|
|
||||||
leal V2P(enable_sse), %ecx; call *%ecx
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
leal V2P(enable_tsc), %ecx; call *%ecx
|
|
||||||
leal V2P(initialize_paging), %ecx; call *%ecx
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $AP_REL(ap_long_mode)
|
ljmpl $0x08, $AP_V2P(ap_long_mode)
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
ap_long_mode:
|
ap_long_mode:
|
||||||
movq $ap_higher_half, %rax
|
# move stack pointer to higher half
|
||||||
jmp *%rax
|
movl %esp, %esp
|
||||||
|
addq $KERNEL_OFFSET, %rsp
|
||||||
ap_higher_half:
|
|
||||||
movq AP_REL(ap_prepare_paging), %rax
|
|
||||||
call *%rax
|
|
||||||
|
|
||||||
# load AP's initial values
|
|
||||||
movq AP_REL(ap_stack_vaddr), %rsp
|
|
||||||
movq AP_REL(ap_page_table), %rax
|
|
||||||
movq $1, AP_REL(ap_ready)
|
|
||||||
movq %rax, %cr3
|
|
||||||
|
|
||||||
# clear rbp for stacktrace
|
# clear rbp for stacktrace
|
||||||
xorq %rbp, %rbp
|
xorq %rbp, %rbp
|
||||||
|
|
||||||
|
xorb %al, %al
|
||||||
1: pause
|
1: pause
|
||||||
cmpb $0, g_ap_startup_done
|
cmpb %al, g_ap_startup_done
|
||||||
je 1b
|
jz 1b
|
||||||
|
|
||||||
lock incb g_ap_running_count
|
lock incb g_ap_running_count
|
||||||
|
|
||||||
call ap_main
|
# jump to ap_main in higher half
|
||||||
jmp system_halt
|
movabsq $ap_main, %rcx
|
||||||
|
call *%rcx
|
||||||
|
jmp V2P(system_halt)
|
||||||
|
|
||||||
ap_gdt:
|
ap_gdt:
|
||||||
.quad 0x0000000000000000 # null descriptor
|
.quad 0x0000000000000000 # null descriptor
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.macro intr_header, n
|
.macro pushaq
|
||||||
pushq %rax
|
pushq %rax
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
@@ -14,18 +14,10 @@
|
|||||||
pushq %r13
|
pushq %r13
|
||||||
pushq %r14
|
pushq %r14
|
||||||
pushq %r15
|
pushq %r15
|
||||||
testb $3, \n+15*8(%rsp)
|
|
||||||
jz 1f
|
|
||||||
swapgs
|
|
||||||
1: cld
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro intr_footer, n
|
.macro popaq
|
||||||
testb $3, \n+15*8(%rsp)
|
popq %r15
|
||||||
jz 1f
|
|
||||||
call cpp_check_signal
|
|
||||||
swapgs
|
|
||||||
1: popq %r15
|
|
||||||
popq %r14
|
popq %r14
|
||||||
popq %r13
|
popq %r13
|
||||||
popq %r12
|
popq %r12
|
||||||
@@ -43,7 +35,8 @@
|
|||||||
.endm
|
.endm
|
||||||
|
|
||||||
isr_stub:
|
isr_stub:
|
||||||
intr_header 24
|
pushaq
|
||||||
|
|
||||||
movq %cr0, %rax; pushq %rax
|
movq %cr0, %rax; pushq %rax
|
||||||
movq %cr2, %rax; pushq %rax
|
movq %cr2, %rax; pushq %rax
|
||||||
movq %cr3, %rax; pushq %rax
|
movq %cr3, %rax; pushq %rax
|
||||||
@@ -56,33 +49,39 @@ isr_stub:
|
|||||||
call cpp_isr_handler
|
call cpp_isr_handler
|
||||||
addq $32, %rsp
|
addq $32, %rsp
|
||||||
|
|
||||||
intr_footer 24
|
popaq
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
intr_header 24
|
pushaq
|
||||||
xorq %rbp, %rbp
|
|
||||||
movq 120(%rsp), %rdi # irq number
|
movq 120(%rsp), %rdi # irq number
|
||||||
call cpp_irq_handler
|
call cpp_irq_handler
|
||||||
intr_footer 24
|
popaq
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
.global asm_yield_handler
|
||||||
|
asm_yield_handler:
|
||||||
|
pushaq
|
||||||
|
leaq 120(%rsp), %rdi # interrupt stack ptr
|
||||||
|
movq %rsp, %rsi # interrupt register ptr
|
||||||
|
call cpp_yield_handler
|
||||||
|
popaq
|
||||||
|
iretq
|
||||||
|
|
||||||
.global asm_ipi_handler
|
.global asm_ipi_handler
|
||||||
asm_ipi_handler:
|
asm_ipi_handler:
|
||||||
intr_header 8
|
pushaq
|
||||||
xorq %rbp, %rbp
|
|
||||||
call cpp_ipi_handler
|
call cpp_ipi_handler
|
||||||
intr_footer 8
|
popaq
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
.global asm_timer_handler
|
.global asm_timer_handler
|
||||||
asm_timer_handler:
|
asm_timer_handler:
|
||||||
intr_header 8
|
pushaq
|
||||||
xorq %rbp, %rbp
|
|
||||||
call cpp_timer_handler
|
call cpp_timer_handler
|
||||||
intr_footer 8
|
popaq
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
.macro isr n
|
.macro isr n
|
||||||
@@ -141,26 +140,35 @@ isr 29
|
|||||||
isr 30
|
isr 30
|
||||||
isr 31
|
isr 31
|
||||||
|
|
||||||
.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
|
irq 0
|
||||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \
|
irq 1
|
||||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
|
irq 2
|
||||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
|
irq 3
|
||||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \
|
irq 4
|
||||||
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \
|
irq 5
|
||||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, \
|
irq 6
|
||||||
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \
|
irq 7
|
||||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, \
|
irq 8
|
||||||
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, \
|
irq 9
|
||||||
100,101,102,103,104,105,106,107,108,109, \
|
irq 10
|
||||||
110,111,112,113,114,115,116,117,118,119, \
|
irq 11
|
||||||
120,121,122,123,124,125,126,127,128,129, \
|
irq 12
|
||||||
130,131,132,133,134,135,136,137,138,139, \
|
irq 13
|
||||||
140,141,142,143,144,145,146,147,148,149, \
|
irq 14
|
||||||
150,151,152,153,154,155,156,157,158,159, \
|
irq 15
|
||||||
160,161,162,163,164,165,166,167,168,169, \
|
irq 16
|
||||||
170,171,172,173,174,175,176,177,178,179, \
|
irq 17
|
||||||
180,181,182,183,184,185,186,187,188,189, \
|
irq 18
|
||||||
190,191,192,193,194,195,196,197,198,199, \
|
irq 19
|
||||||
200,201,202,203,204,205,206,207
|
irq 20
|
||||||
irq \i
|
irq 21
|
||||||
.endr
|
irq 22
|
||||||
|
irq 23
|
||||||
|
irq 24
|
||||||
|
irq 25
|
||||||
|
irq 26
|
||||||
|
irq 27
|
||||||
|
irq 28
|
||||||
|
irq 29
|
||||||
|
irq 30
|
||||||
|
irq 31
|
||||||
|
|||||||
@@ -11,21 +11,20 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
g_kernel_execute_start = .;
|
g_kernel_execute_start = .;
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
*(.multiboot2)
|
|
||||||
*(.bananboot)
|
*(.bananboot)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
}
|
}
|
||||||
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
g_ap_init_addr = .;
|
|
||||||
*(.ap_init)
|
|
||||||
g_kernel_execute_end = .;
|
|
||||||
}
|
|
||||||
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
g_userspace_start = .;
|
g_userspace_start = .;
|
||||||
*(.userspace)
|
*(.userspace)
|
||||||
g_userspace_end = .;
|
g_userspace_end = .;
|
||||||
|
g_kernel_execute_end = .;
|
||||||
|
}
|
||||||
|
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_ap_init_addr = .;
|
||||||
|
*(.ap_init)
|
||||||
}
|
}
|
||||||
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
@@ -44,7 +43,6 @@ SECTIONS
|
|||||||
}
|
}
|
||||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
g_kernel_bss_start = .;
|
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
g_kernel_writable_end = .;
|
g_kernel_writable_end = .;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Method.h>
|
||||||
#include <kernel/ACPI/AML/Namespace.h>
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
#include <kernel/ACPI/EmbeddedController.h>
|
|
||||||
#include <kernel/ACPI/Headers.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
#include <kernel/ThreadBlocker.h>
|
#include <kernel/ThreadBlocker.h>
|
||||||
@@ -29,38 +29,25 @@ namespace Kernel::ACPI
|
|||||||
// 2: SAPIC
|
// 2: SAPIC
|
||||||
BAN::ErrorOr<void> enter_acpi_mode(uint8_t mode);
|
BAN::ErrorOr<void> enter_acpi_mode(uint8_t mode);
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize_acpi_devices();
|
// This function will power off the system
|
||||||
|
// This function will return only if there was an error
|
||||||
|
void poweroff();
|
||||||
|
|
||||||
AML::Namespace* acpi_namespace() { return m_namespace; }
|
// This function will reset the system
|
||||||
|
// This function will return only if there was an error
|
||||||
BAN::ErrorOr<void> poweroff();
|
void reset();
|
||||||
BAN::ErrorOr<void> reset();
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument);
|
|
||||||
|
|
||||||
void handle_irq() override;
|
void handle_irq() override;
|
||||||
|
|
||||||
BAN::Span<BAN::UniqPtr<EmbeddedController>> embedded_controllers() { return m_embedded_controllers.span(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ACPI() = default;
|
ACPI() = default;
|
||||||
BAN::ErrorOr<void> initialize_impl();
|
BAN::ErrorOr<void> initialize_impl();
|
||||||
|
|
||||||
FADT& fadt() { return *m_fadt; }
|
FADT& fadt() { return *m_fadt; }
|
||||||
|
|
||||||
BAN::ErrorOr<void> prepare_sleep(uint8_t sleep_state);
|
bool prepare_sleep(uint8_t sleep_state);
|
||||||
void acpi_event_task();
|
void acpi_event_task();
|
||||||
|
|
||||||
BAN::ErrorOr<void> load_aml_tables(BAN::StringView name, bool all);
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask);
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize_embedded_controller(const AML::Scope& embedded_controller);
|
|
||||||
BAN::ErrorOr<void> initialize_embedded_controllers();
|
|
||||||
|
|
||||||
BAN::Optional<GAS> find_gpe_block(size_t index);
|
|
||||||
bool enable_gpe(uint8_t gpe);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
paddr_t m_header_table_paddr = 0;
|
paddr_t m_header_table_paddr = 0;
|
||||||
vaddr_t m_header_table_vaddr = 0;
|
vaddr_t m_header_table_vaddr = 0;
|
||||||
@@ -78,27 +65,10 @@ namespace Kernel::ACPI
|
|||||||
FADT* m_fadt { nullptr };
|
FADT* m_fadt { nullptr };
|
||||||
|
|
||||||
ThreadBlocker m_event_thread_blocker;
|
ThreadBlocker m_event_thread_blocker;
|
||||||
|
BAN::Array<BAN::RefPtr<AML::Method>, 0xFF> m_gpe_methods;
|
||||||
BAN::Vector<BAN::UniqPtr<EmbeddedController>> m_embedded_controllers;
|
|
||||||
|
|
||||||
struct GPEHandler
|
|
||||||
{
|
|
||||||
bool has_callback { false };
|
|
||||||
union {
|
|
||||||
AML::Reference* method;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
void (*callback)(void*);
|
|
||||||
void* argument;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
bool m_has_any_gpes { false };
|
|
||||||
AML::Scope m_gpe_scope;
|
|
||||||
BAN::Array<GPEHandler, 0xFF> m_gpe_methods;
|
|
||||||
|
|
||||||
bool m_hardware_reduced { false };
|
bool m_hardware_reduced { false };
|
||||||
AML::Namespace* m_namespace { nullptr };
|
BAN::RefPtr<AML::Namespace> m_namespace;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
kernel/include/kernel/ACPI/AML.h
Normal file
11
kernel/include/kernel/ACPI/AML.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/Headers.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Namespace> initialize_namespace();
|
||||||
|
|
||||||
|
}
|
||||||
48
kernel/include/kernel/ACPI/AML/Alias.h
Normal file
48
kernel/include/kernel/ACPI/AML/Alias.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Alias
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::AliasOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto source_string = AML::NameString::parse(context.aml_data);
|
||||||
|
if (!source_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto source_object = AML::Namespace::root_namespace()->find_object(context.scope, source_string.value(), AML::Namespace::FindMode::Normal);
|
||||||
|
auto alias_string = AML::NameString::parse(context.aml_data);
|
||||||
|
if (!alias_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (!source_object)
|
||||||
|
{
|
||||||
|
AML_PRINT("Alias target could not be found");
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, alias_string.value(), source_object))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINT("Alias \"");
|
||||||
|
alias_string->debug_print();
|
||||||
|
AML_DEBUG_PRINT("\" => ");
|
||||||
|
source_object->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
312
kernel/include/kernel/ACPI/AML/Buffer.h
Normal file
312
kernel/include/kernel/ACPI/AML/Buffer.h
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/String.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Buffer final : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::Vector<uint8_t> buffer;
|
||||||
|
|
||||||
|
Buffer()
|
||||||
|
: AML::Node(Node::Type::Buffer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop)
|
||||||
|
{
|
||||||
|
auto rhs_node = node ? node->convert(AML::Node::ConvBuffer) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!rhs_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Buffer logical compare RHS cannot be converted to buffer");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)binaryop;
|
||||||
|
AML_TODO("Logical compare buffer");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
if (mask & AML::Node::ConvBuffer)
|
||||||
|
return this;
|
||||||
|
if (mask & AML::Node::ConvInteger)
|
||||||
|
return as_integer();
|
||||||
|
if (mask & AML::Node::ConvString)
|
||||||
|
{
|
||||||
|
AML_TODO("Convert BufferField to String");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||||
|
{
|
||||||
|
ASSERT(node);
|
||||||
|
auto conv_node = node->convert(AML::Node::ConvBuffer);
|
||||||
|
if (!conv_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Buffer store could not convert to buffer");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& conv_buffer = static_cast<AML::Buffer*>(conv_node.ptr())->buffer;
|
||||||
|
MUST(buffer.resize(conv_buffer.size()));
|
||||||
|
for (size_t i = 0; i < buffer.size(); i++)
|
||||||
|
buffer[i] = conv_buffer[i];
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::BufferOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto buffer_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!buffer_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto buffer_context = context;
|
||||||
|
buffer_context.aml_data = buffer_pkg.value();
|
||||||
|
|
||||||
|
auto buffer_size_result = AML::parse_object(buffer_context);
|
||||||
|
if (!buffer_size_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto buffer_size_node = buffer_size_result.node() ? buffer_size_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!buffer_size_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Buffer size is not an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t actual_buffer_size = BAN::Math::max<uint32_t>(
|
||||||
|
static_cast<AML::Integer*>(buffer_size_node.ptr())->value,
|
||||||
|
buffer_context.aml_data.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
auto buffer = MUST(BAN::RefPtr<Buffer>::create());
|
||||||
|
MUST(buffer->buffer.resize(actual_buffer_size, 0));
|
||||||
|
for (uint32_t i = 0; i < buffer_context.aml_data.size(); i++)
|
||||||
|
buffer->buffer[i] = buffer_context.aml_data[i];
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
buffer->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Buffer ({} bytes)", buffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::RefPtr<AML::Integer> as_integer()
|
||||||
|
{
|
||||||
|
uint64_t value = 0;
|
||||||
|
for (size_t i = 0; i < BAN::Math::min<size_t>(buffer.size(), 8); i++)
|
||||||
|
value |= static_cast<uint64_t>(buffer[i]) << (8 * i);
|
||||||
|
return MUST(BAN::RefPtr<Integer>::create(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BufferField final : AML::NamedObject
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::Node> buffer;
|
||||||
|
size_t field_bit_offset;
|
||||||
|
size_t field_bit_size;
|
||||||
|
|
||||||
|
template<typename T> requires BAN::is_same_v<T, AML::Buffer> || BAN::is_same_v<T, AML::String>
|
||||||
|
BufferField(AML::NameSeg name, BAN::RefPtr<T> buffer, size_t field_bit_offset, size_t field_bit_size)
|
||||||
|
: AML::NamedObject(Node::Type::BufferField, name)
|
||||||
|
, buffer(buffer)
|
||||||
|
, field_bit_offset(field_bit_offset)
|
||||||
|
, field_bit_size(field_bit_size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
if (mask & AML::Node::ConvBufferField)
|
||||||
|
return this;
|
||||||
|
if (mask & AML::Node::ConvInteger)
|
||||||
|
return as_integer();
|
||||||
|
if (mask & AML::Node::ConvBuffer)
|
||||||
|
{
|
||||||
|
AML_TODO("Convert BufferField to Buffer");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (mask & AML::Node::ConvString)
|
||||||
|
{
|
||||||
|
AML_TODO("Convert BufferField to String");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||||
|
{
|
||||||
|
ASSERT(buffer);
|
||||||
|
ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String);
|
||||||
|
auto& buffer = (this->buffer->type == AML::Node::Type::Buffer)
|
||||||
|
? static_cast<AML::Buffer*>(this->buffer.ptr())->buffer
|
||||||
|
: static_cast<AML::String*>(this->buffer.ptr())->string;
|
||||||
|
ASSERT(field_bit_offset + field_bit_size <= buffer.size() * 8);
|
||||||
|
|
||||||
|
auto value_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!value_node)
|
||||||
|
return {};
|
||||||
|
const auto value = static_cast<AML::Integer*>(value_node.ptr())->value;
|
||||||
|
|
||||||
|
// TODO: optimize for whole byte accesses
|
||||||
|
for (size_t i = 0; i < field_bit_size; i++)
|
||||||
|
{
|
||||||
|
const size_t bit = field_bit_offset + i;
|
||||||
|
buffer[bit / 8] &= ~(1 << (bit % 8));
|
||||||
|
buffer[bit / 8] |= ((value >> i) & 1) << (bit % 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
|
||||||
|
bool offset_in_bytes;
|
||||||
|
size_t field_bit_size;
|
||||||
|
switch (static_cast<AML::Byte>(context.aml_data[0]))
|
||||||
|
{
|
||||||
|
case AML::Byte::CreateBitFieldOp:
|
||||||
|
field_bit_size = 1;
|
||||||
|
offset_in_bytes = false;
|
||||||
|
break;
|
||||||
|
case AML::Byte::CreateByteFieldOp:
|
||||||
|
field_bit_size = 8;
|
||||||
|
offset_in_bytes = true;
|
||||||
|
break;
|
||||||
|
case AML::Byte::CreateWordFieldOp:
|
||||||
|
field_bit_size = 16;
|
||||||
|
offset_in_bytes = true;
|
||||||
|
break;
|
||||||
|
case AML::Byte::CreateDWordFieldOp:
|
||||||
|
field_bit_size = 32;
|
||||||
|
offset_in_bytes = true;
|
||||||
|
break;
|
||||||
|
case AML::Byte::CreateQWordFieldOp:
|
||||||
|
field_bit_size = 64;
|
||||||
|
offset_in_bytes = true;
|
||||||
|
break;
|
||||||
|
case AML::Byte::ExtOpPrefix:
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::CreateFieldOp);
|
||||||
|
field_bit_size = 0;
|
||||||
|
offset_in_bytes = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
context.aml_data = context.aml_data.slice(1 + (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix));
|
||||||
|
|
||||||
|
auto buffer_result = AML::parse_object(context);
|
||||||
|
if (!buffer_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto buffer_node = buffer_result.node() ? buffer_result.node()->convert(AML::Node::ConvBuffer) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!buffer_node || buffer_node->type != Node::Type::Buffer)
|
||||||
|
{
|
||||||
|
AML_ERROR("Buffer source does not evaluate to a Buffer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
auto buffer = BAN::RefPtr<AML::Buffer>(static_cast<AML::Buffer*>(buffer_node.ptr()));
|
||||||
|
|
||||||
|
auto index_result = AML::parse_object(context);
|
||||||
|
if (!index_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto index_node = index_result.node() ? index_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!index_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Failed to parse index for BufferField");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_bit_size == 0)
|
||||||
|
{
|
||||||
|
auto bit_count_result = AML::parse_object(context);
|
||||||
|
if (!bit_count_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto bit_count_node = bit_count_result.node() ? bit_count_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!bit_count_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Failed to parse bit count for BufferField");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
field_bit_size = static_cast<AML::Integer*>(bit_count_node.ptr())->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto field_name = AML::NameString::parse(context.aml_data);
|
||||||
|
if (!field_name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
if (field_name->path.empty())
|
||||||
|
{
|
||||||
|
AML_ERROR("Empty field name for BufferField");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t field_bit_offset = static_cast<AML::Integer*>(index_node.ptr())->value;
|
||||||
|
if (offset_in_bytes)
|
||||||
|
field_bit_offset *= 8;
|
||||||
|
|
||||||
|
auto field = MUST(BAN::RefPtr<BufferField>::create(field_name->path.back(), buffer, field_bit_offset, field_bit_size));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, field_name.value(), field))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
field->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("BufferField {} at bit offset {} ({} bits) to { ", name, field_bit_offset, field_bit_size);
|
||||||
|
buffer->debug_print(0);
|
||||||
|
AML_DEBUG_PRINT(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::RefPtr<AML::Integer> as_integer()
|
||||||
|
{
|
||||||
|
ASSERT(buffer);
|
||||||
|
ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String);
|
||||||
|
|
||||||
|
const auto& buffer = (this->buffer->type == AML::Node::Type::Buffer)
|
||||||
|
? static_cast<AML::Buffer*>(this->buffer.ptr())->buffer
|
||||||
|
: static_cast<AML::String*>(this->buffer.ptr())->string;
|
||||||
|
|
||||||
|
uint64_t value = 0;
|
||||||
|
|
||||||
|
// TODO: optimize for whole byte accesses
|
||||||
|
for (size_t i = 0; i < BAN::Math::min<size_t>(field_bit_size, 64); i++)
|
||||||
|
{
|
||||||
|
const size_t bit = field_bit_offset + i;
|
||||||
|
value |= static_cast<uint64_t>((buffer[bit / 8] >> (bit % 8)) & 1) << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MUST(BAN::RefPtr<Integer>::create(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -145,35 +145,19 @@ namespace Kernel::ACPI::AML
|
|||||||
DataRegionOp = 0x88,
|
DataRegionOp = 0x88,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr bool is_digit_char(uint8_t ch)
|
static constexpr bool is_digit_char(uint8_t ch)
|
||||||
{
|
{
|
||||||
return '0' <= ch && ch <= '9';
|
return '0' <= ch && ch <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr bool is_lead_name_char(uint8_t ch)
|
static constexpr bool is_lead_name_char(uint8_t ch)
|
||||||
{
|
{
|
||||||
return ('A' <= ch && ch <= 'Z') || ch == '_';
|
return ('A' <= ch && ch <= 'Z') || ch == '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr bool is_name_char(uint8_t ch)
|
static constexpr bool is_name_char(uint8_t ch)
|
||||||
{
|
{
|
||||||
return is_lead_name_char(ch) || is_digit_char(ch);
|
return is_lead_name_char(ch) || is_digit_char(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr bool is_name_string_start(uint8_t ch)
|
|
||||||
{
|
|
||||||
if (is_lead_name_char(ch))
|
|
||||||
return true;
|
|
||||||
switch (static_cast<AML::Byte>(ch))
|
|
||||||
{
|
|
||||||
case AML::Byte::RootChar:
|
|
||||||
case AML::Byte::ParentPrefixChar:
|
|
||||||
case AML::Byte::MultiNamePrefix:
|
|
||||||
case AML::Byte::DualNamePrefix:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
92
kernel/include/kernel/ACPI/AML/Conversion.h
Normal file
92
kernel/include/kernel/ACPI/AML/Conversion.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Buffer.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/String.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Conversion
|
||||||
|
{
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
const auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case AML::Byte::ToIntegerOp:
|
||||||
|
case AML::Byte::ToBufferOp:
|
||||||
|
case AML::Byte::ToStringOp:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data_result = AML::parse_object(context);
|
||||||
|
if (!data_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto data_node = data_result.node();
|
||||||
|
if (!data_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Conversion {2H} data could not be evaluated", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
{
|
||||||
|
AML_ERROR("Conversion {2H} missing target", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> target_node;
|
||||||
|
if (context.aml_data[0] == 0x00)
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto target_result = AML::parse_object(context);
|
||||||
|
if (!target_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
target_node = target_result.node();
|
||||||
|
if (!target_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Conversion {2H} target invalid", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> converted;
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case AML::Byte::ToBufferOp:
|
||||||
|
converted = data_node->convert(AML::Node::ConvBuffer);
|
||||||
|
break;
|
||||||
|
case AML::Byte::ToIntegerOp:
|
||||||
|
converted = data_node->convert(AML::Node::ConvInteger);
|
||||||
|
break;
|
||||||
|
case AML::Byte::ToStringOp:
|
||||||
|
converted = data_node->convert(AML::Node::ConvString);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!converted)
|
||||||
|
{
|
||||||
|
AML_ERROR("Conversion {2H} could not convert from node type {}", static_cast<uint8_t>(opcode), static_cast<uint8_t>(data_node->type));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_node && !target_node->store(converted))
|
||||||
|
{
|
||||||
|
AML_ERROR("Conversion {2H} failed to store converted value", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseResult(converted);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
65
kernel/include/kernel/ACPI/AML/CopyObject.h
Normal file
65
kernel/include/kernel/ACPI/AML/CopyObject.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Alias.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Register.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct CopyObject
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::CopyObjectOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto source_result = AML::parse_object(context);
|
||||||
|
if (!source_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto source = source_result.node()
|
||||||
|
? source_result.node()->to_underlying()
|
||||||
|
: BAN::RefPtr<AML::Node>();
|
||||||
|
if (!source)
|
||||||
|
{
|
||||||
|
AML_ERROR("CopyObject source is null");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto destination_result = AML::parse_object(context);
|
||||||
|
if (!destination_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto destination = destination_result.node();
|
||||||
|
if (!destination)
|
||||||
|
{
|
||||||
|
AML_ERROR("CopyObject destination is null");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINTLN("CopyObject {");
|
||||||
|
source->debug_print(1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
AML_DEBUG_PRINTLN("} to {");
|
||||||
|
destination->debug_print(1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
AML_DEBUG_PRINTLN("}");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (destination->type)
|
||||||
|
{
|
||||||
|
case AML::Node::Type::Name:
|
||||||
|
static_cast<AML::Name*>(destination.ptr())->object = source->copy();
|
||||||
|
return source;
|
||||||
|
case AML::Node::Type::Register:
|
||||||
|
static_cast<AML::Register*>(destination.ptr())->value = source->copy();
|
||||||
|
return source;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
59
kernel/include/kernel/ACPI/AML/Device.h
Normal file
59
kernel/include/kernel/ACPI/AML/Device.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Method.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Device final : public AML::Scope
|
||||||
|
{
|
||||||
|
Device(NameSeg name)
|
||||||
|
: Scope(Node::Type::Device, name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::DeviceOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto device_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!device_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto name_string = AML::NameString::parse(device_pkg.value());
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto device = MUST(BAN::RefPtr<Device>::create(name_string->path.back()));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), device))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Device ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINTLN(" {");
|
||||||
|
Namespace::root_namespace()->for_each_child(scope,
|
||||||
|
[&](const auto&, const auto& child)
|
||||||
|
{
|
||||||
|
child->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
148
kernel/include/kernel/ACPI/AML/Event.h
Normal file
148
kernel/include/kernel/ACPI/AML/Event.h
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Event final : public AML::NamedObject
|
||||||
|
{
|
||||||
|
BAN::Atomic<uint32_t> signal_count { 0 };
|
||||||
|
ThreadBlocker thread_blocker;
|
||||||
|
|
||||||
|
Event(NameSeg name)
|
||||||
|
: NamedObject(Node::Type::Event, name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
|
||||||
|
const auto ext_op = static_cast<AML::ExtOp>(context.aml_data[1]);
|
||||||
|
switch (ext_op)
|
||||||
|
{
|
||||||
|
case AML::ExtOp::EventOp:
|
||||||
|
return parse_event(context);
|
||||||
|
case AML::ExtOp::ResetOp:
|
||||||
|
case AML::ExtOp::SignalOp:
|
||||||
|
case AML::ExtOp::WaitOp:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto event_result = parse_object(context);
|
||||||
|
if (!event_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto general_node = event_result.node();
|
||||||
|
if (!general_node || general_node->type != Node::Type::Event)
|
||||||
|
{
|
||||||
|
AML_ERROR("Release, Wait or Signal does not name an event");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* event_node = static_cast<AML::Event*>(general_node.ptr());
|
||||||
|
|
||||||
|
if (ext_op == AML::ExtOp::WaitOp)
|
||||||
|
{
|
||||||
|
auto timeout_result = parse_object(context);
|
||||||
|
if (!timeout_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto timeout_node = timeout_result.node()
|
||||||
|
? timeout_result.node()->convert(AML::Node::ConvInteger)
|
||||||
|
: BAN::RefPtr<AML::Node>();
|
||||||
|
if (!timeout_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Wait timeout does not evaluate to integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
const auto timeout_value = static_cast<AML::Integer*>(timeout_node.ptr())->value;
|
||||||
|
|
||||||
|
const uint64_t start_ms = SystemTimer::get().ms_since_boot();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto expected = event_node->signal_count.load();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (expected == 0)
|
||||||
|
break;
|
||||||
|
if (event_node->signal_count.compare_exchange(expected, expected - 1))
|
||||||
|
return ParseResult(Integer::Constants::Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout_value >= 0xFFFF)
|
||||||
|
event_node->thread_blocker.block_indefinite();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const uint64_t current_ms = SystemTimer::get().ms_since_boot();
|
||||||
|
if (current_ms >= start_ms + timeout_value)
|
||||||
|
return ParseResult(Integer::Constants::Ones);
|
||||||
|
event_node->thread_blocker.block_with_timeout_ms(start_ms + timeout_value - current_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ext_op)
|
||||||
|
{
|
||||||
|
case AML::ExtOp::ResetOp:
|
||||||
|
event_node->signal_count = 0;
|
||||||
|
break;
|
||||||
|
case AML::ExtOp::SignalOp:
|
||||||
|
event_node->signal_count++;
|
||||||
|
event_node->thread_blocker.unblock();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Event ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(" (Signals: {})", signal_count.load());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ParseResult parse_event(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::EventOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto name_string = NameString::parse(context.aml_data);
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto event = MUST(BAN::RefPtr<Event>::create(name_string->path.back()));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), event))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
event->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
243
kernel/include/kernel/ACPI/AML/Expression.h
Normal file
243
kernel/include/kernel/ACPI/AML/Expression.h
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Buffer.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/String.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Expression
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
switch (static_cast<Byte>(context.aml_data[0]))
|
||||||
|
{
|
||||||
|
// unary
|
||||||
|
case AML::Byte::IncrementOp:
|
||||||
|
case AML::Byte::DecrementOp:
|
||||||
|
{
|
||||||
|
auto opcode = (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::IncrementOp) ? AML::Byte::AddOp : AML::Byte::SubtractOp;
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto source_result = AML::parse_object(context);
|
||||||
|
if (!source_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!conv_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("UnaryOp source not integer, type {}", static_cast<uint8_t>(source_result.node()->type));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto source_node = static_cast<AML::Integer*>(conv_node.ptr());
|
||||||
|
if (source_node->constant)
|
||||||
|
{
|
||||||
|
AML_ERROR("UnaryOp source is constant");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_node->value += (opcode == AML::Byte::AddOp) ? 1 : -1;
|
||||||
|
return ParseResult(source_node);
|
||||||
|
}
|
||||||
|
case AML::Byte::NotOp:
|
||||||
|
AML_TODO("NotOp", context.aml_data[0]);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
case AML::Byte::LNotOp:
|
||||||
|
{
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto source_result = AML::parse_object(context);
|
||||||
|
if (!source_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!conv_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("UnaryOp source not integer, type {}", static_cast<uint8_t>(source_result.node()->type));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
auto source_node = static_cast<AML::Integer*>(conv_node.ptr());
|
||||||
|
if (!source_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Logical NotOp source is not integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = source_node->value ? Integer::Constants::Zero : Integer::Constants::Ones;
|
||||||
|
return ParseResult(result);
|
||||||
|
}
|
||||||
|
case AML::Byte::AddOp:
|
||||||
|
case AML::Byte::AndOp:
|
||||||
|
case AML::Byte::ModOp:
|
||||||
|
case AML::Byte::MultiplyOp:
|
||||||
|
case AML::Byte::NandOp:
|
||||||
|
case AML::Byte::NorOp:
|
||||||
|
case AML::Byte::OrOp:
|
||||||
|
case AML::Byte::ShiftLeftOp:
|
||||||
|
case AML::Byte::ShiftRightOp:
|
||||||
|
case AML::Byte::SubtractOp:
|
||||||
|
case AML::Byte::XorOp:
|
||||||
|
return parse_binary_op(context);
|
||||||
|
case AML::Byte::LAndOp:
|
||||||
|
case AML::Byte::LEqualOp:
|
||||||
|
case AML::Byte::LGreaterOp:
|
||||||
|
case AML::Byte::LLessOp:
|
||||||
|
case AML::Byte::LOrOp:
|
||||||
|
return parse_logical_binary_op(context);
|
||||||
|
case AML::Byte::DivideOp:
|
||||||
|
AML_TODO("DivideOp");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ParseResult parse_binary_op(ParseContext& context)
|
||||||
|
{
|
||||||
|
auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto lhs_result = AML::parse_object(context);
|
||||||
|
if (!lhs_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto lhs_conv = lhs_result.node() ? lhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!lhs_conv)
|
||||||
|
{
|
||||||
|
AML_ERROR("BinaryOP {2H} LHS not an integer, type {}",
|
||||||
|
static_cast<uint8_t>(opcode),
|
||||||
|
static_cast<uint8_t>(lhs_result.node()->type)
|
||||||
|
);
|
||||||
|
if (lhs_result.node())
|
||||||
|
lhs_result.node()->debug_print(1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
const auto lhs_value = static_cast<AML::Integer*>(lhs_conv.ptr())->value;
|
||||||
|
|
||||||
|
auto rhs_result = AML::parse_object(context);
|
||||||
|
if (!rhs_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto rhs_conv = rhs_result.node() ? rhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!rhs_conv)
|
||||||
|
{
|
||||||
|
AML_ERROR("BinaryOP {2H} RHS not an integer", static_cast<uint8_t>(opcode));
|
||||||
|
if (rhs_result.node())
|
||||||
|
rhs_result.node()->debug_print(1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
const auto rhs_value = static_cast<AML::Integer*>(rhs_conv.ptr())->value;
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
{
|
||||||
|
AML_ERROR("BinaryOP {2H} missing target", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> target_node;
|
||||||
|
if (context.aml_data[0] == 0x00)
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto target_result = AML::parse_object(context);
|
||||||
|
if (!target_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
target_node = target_result.node();
|
||||||
|
if (!target_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("BinaryOP {2H} target invalid", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t (*func)(uint64_t, uint64_t) = nullptr;
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case AML::Byte::AddOp: func = [](uint64_t a, uint64_t b) { return a + b; }; break;
|
||||||
|
case AML::Byte::AndOp: func = [](uint64_t a, uint64_t b) { return a & b; }; break;
|
||||||
|
case AML::Byte::ModOp: func = [](uint64_t a, uint64_t b) { return a % b; }; break;
|
||||||
|
case AML::Byte::MultiplyOp: func = [](uint64_t a, uint64_t b) { return a * b; }; break;
|
||||||
|
case AML::Byte::NandOp: func = [](uint64_t a, uint64_t b) { return ~(a & b); }; break;
|
||||||
|
case AML::Byte::NorOp: func = [](uint64_t a, uint64_t b) { return ~(a | b); }; break;
|
||||||
|
case AML::Byte::OrOp: func = [](uint64_t a, uint64_t b) { return a | b; }; break;
|
||||||
|
case AML::Byte::ShiftLeftOp: func = [](uint64_t a, uint64_t b) { return a << b; }; break;
|
||||||
|
case AML::Byte::ShiftRightOp: func = [](uint64_t a, uint64_t b) { return a >> b; }; break;
|
||||||
|
case AML::Byte::SubtractOp: func = [](uint64_t a, uint64_t b) { return a - b; }; break;
|
||||||
|
case AML::Byte::XorOp: func = [](uint64_t a, uint64_t b) { return a ^ b; }; break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result_node = MUST(BAN::RefPtr<AML::Integer>::create(func(lhs_value, rhs_value)));
|
||||||
|
if (target_node && !target_node->store(result_node))
|
||||||
|
{
|
||||||
|
AML_ERROR("BinaryOp {2H} failed to store result", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseResult(result_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse_logical_binary_op(ParseContext& context)
|
||||||
|
{
|
||||||
|
auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
uint8_t mask;
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case AML::Byte::LAndOp:
|
||||||
|
case AML::Byte::LOrOp:
|
||||||
|
mask = AML::Node::ConvInteger;
|
||||||
|
break;
|
||||||
|
case AML::Byte::LEqualOp:
|
||||||
|
case AML::Byte::LGreaterOp:
|
||||||
|
case AML::Byte::LLessOp:
|
||||||
|
mask = AML::Node::ConvInteger | AML::Node::ConvString | AML::Node::ConvBuffer;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lhs_result = AML::parse_object(context);
|
||||||
|
if (!lhs_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto lhs_node = lhs_result.node() ? lhs_result.node()->convert(mask) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!lhs_node)
|
||||||
|
{
|
||||||
|
AML_TODO("Logical BinaryOP {2H} LHS evaluated to nothing", static_cast<uint8_t>(opcode));
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rhs_result = AML::parse_object(context);
|
||||||
|
if (!rhs_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
BAN::Optional<bool> result = false;
|
||||||
|
switch (lhs_node->type)
|
||||||
|
{
|
||||||
|
case AML::Node::Type::Integer:
|
||||||
|
result = static_cast<AML::Integer*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Buffer:
|
||||||
|
result = static_cast<AML::Buffer*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::String:
|
||||||
|
result = static_cast<AML::String*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
return ParseResult(result.value() ? AML::Integer::Constants::Ones : AML::Integer::Constants::Zero);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
199
kernel/include/kernel/ACPI/AML/Field.h
Normal file
199
kernel/include/kernel/ACPI/AML/Field.h
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Region.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct FieldRules
|
||||||
|
{
|
||||||
|
enum class AccessType
|
||||||
|
{
|
||||||
|
Any = 0,
|
||||||
|
Byte = 1,
|
||||||
|
Word = 2,
|
||||||
|
DWord = 3,
|
||||||
|
QWord = 4,
|
||||||
|
Buffer = 5,
|
||||||
|
};
|
||||||
|
AccessType access_type;
|
||||||
|
|
||||||
|
enum class LockRule
|
||||||
|
{
|
||||||
|
NoLock = 0,
|
||||||
|
Lock = 1,
|
||||||
|
};
|
||||||
|
LockRule lock_rule;
|
||||||
|
|
||||||
|
enum class UpdateRule
|
||||||
|
{
|
||||||
|
Preserve = 0,
|
||||||
|
WriteAsOnes = 1,
|
||||||
|
WriteAsZeros = 2,
|
||||||
|
};
|
||||||
|
UpdateRule update_rule;
|
||||||
|
|
||||||
|
enum class AccessAttrib
|
||||||
|
{
|
||||||
|
Normal = 0,
|
||||||
|
Bytes = 1,
|
||||||
|
RawBytes = 2,
|
||||||
|
RawProcessBytes = 3,
|
||||||
|
};
|
||||||
|
AccessAttrib access_attrib = AccessAttrib::Normal;
|
||||||
|
uint8_t access_length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FieldElement final : public AML::NamedObject
|
||||||
|
{
|
||||||
|
uint64_t bit_offset;
|
||||||
|
uint64_t bit_count;
|
||||||
|
|
||||||
|
FieldRules access_rules;
|
||||||
|
|
||||||
|
BAN::RefPtr<OpRegion> op_region;
|
||||||
|
|
||||||
|
FieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
|
||||||
|
: NamedObject(Node::Type::FieldElement, name)
|
||||||
|
, bit_offset(bit_offset)
|
||||||
|
, bit_count(bit_count)
|
||||||
|
, access_rules(access_rules)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
if (mask & AML::Node::ConvInteger)
|
||||||
|
return as_integer();
|
||||||
|
if (mask & AML::Node::ConvBuffer)
|
||||||
|
{
|
||||||
|
AML_TODO("Convert BankFieldElement to Buffer");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (mask & AML::Node::ConvString)
|
||||||
|
{
|
||||||
|
AML_TODO("Convert BankFieldElement to String");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::RefPtr<AML::Integer> as_integer();
|
||||||
|
|
||||||
|
BAN::Optional<uint64_t> evaluate_internal();
|
||||||
|
bool store_internal(uint64_t value);
|
||||||
|
|
||||||
|
friend struct IndexFieldElement;
|
||||||
|
friend struct BankFieldElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Field
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndexFieldElement final : public AML::NamedObject
|
||||||
|
{
|
||||||
|
uint64_t bit_offset;
|
||||||
|
uint64_t bit_count;
|
||||||
|
|
||||||
|
FieldRules access_rules;
|
||||||
|
|
||||||
|
BAN::RefPtr<FieldElement> index_element;
|
||||||
|
BAN::RefPtr<FieldElement> data_element;
|
||||||
|
|
||||||
|
IndexFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
|
||||||
|
: NamedObject(Node::Type::IndexFieldElement, name)
|
||||||
|
, bit_offset(bit_offset)
|
||||||
|
, bit_count(bit_count)
|
||||||
|
, access_rules(access_rules)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
if (mask & AML::Node::ConvInteger)
|
||||||
|
if (auto node = as_integer())
|
||||||
|
return node;
|
||||||
|
if (mask & AML::Node::ConvBuffer)
|
||||||
|
{
|
||||||
|
AML_TODO("convert BankFieldElement to Buffer");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (mask & AML::Node::ConvString)
|
||||||
|
{
|
||||||
|
AML_TODO("convert BankFieldElement to String");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::RefPtr<AML::Integer> as_integer();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndexField
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BankFieldElement final : public AML::NamedObject
|
||||||
|
{
|
||||||
|
uint64_t bit_offset;
|
||||||
|
uint64_t bit_count;
|
||||||
|
|
||||||
|
FieldRules access_rules;
|
||||||
|
|
||||||
|
BAN::RefPtr<OpRegion> op_region;
|
||||||
|
BAN::RefPtr<FieldElement> bank_selector;
|
||||||
|
uint64_t bank_value;
|
||||||
|
|
||||||
|
BankFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
|
||||||
|
: NamedObject(Node::Type::BankFieldElement, name)
|
||||||
|
, bit_offset(bit_offset)
|
||||||
|
, bit_count(bit_count)
|
||||||
|
, access_rules(access_rules)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
if (mask & AML::Node::ConvInteger)
|
||||||
|
if (auto node = as_integer())
|
||||||
|
return node;
|
||||||
|
if (mask & AML::Node::ConvBuffer)
|
||||||
|
{
|
||||||
|
AML_TODO("convert BankFieldElement to Buffer");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (mask & AML::Node::ConvString)
|
||||||
|
{
|
||||||
|
AML_TODO("convert BankFieldElement to String");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::RefPtr<AML::Integer> as_integer();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BankField
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
65
kernel/include/kernel/ACPI/AML/IfElse.h
Normal file
65
kernel/include/kernel/ACPI/AML/IfElse.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/HashMap.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct IfElse
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::IfOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto if_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!if_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto outer_aml_data = context.aml_data;
|
||||||
|
context.aml_data = if_pkg.value();
|
||||||
|
|
||||||
|
auto predicate_result = AML::parse_object(context);
|
||||||
|
if (!predicate_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto predicate_node = predicate_result.node() ? predicate_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!predicate_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("If predicate is not an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
const auto predicate_value = static_cast<AML::Integer*>(predicate_node.ptr())->value;
|
||||||
|
|
||||||
|
// Else
|
||||||
|
BAN::ConstByteSpan else_pkg;
|
||||||
|
if (outer_aml_data.size() >= 1 && static_cast<AML::Byte>(outer_aml_data[0]) == Byte::ElseOp)
|
||||||
|
{
|
||||||
|
outer_aml_data = outer_aml_data.slice(1);
|
||||||
|
auto else_pkg_result = AML::parse_pkg(outer_aml_data);
|
||||||
|
if (!else_pkg_result.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
else_pkg = else_pkg_result.value();
|
||||||
|
}
|
||||||
|
if (predicate_value == 0)
|
||||||
|
context.aml_data = else_pkg;
|
||||||
|
|
||||||
|
while (context.aml_data.size() > 0)
|
||||||
|
{
|
||||||
|
auto object_result = AML::parse_object(context);
|
||||||
|
if (object_result.returned() || object_result.breaked() || object_result.continued())
|
||||||
|
return object_result;
|
||||||
|
if (!object_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.aml_data = outer_aml_data;
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
126
kernel/include/kernel/ACPI/AML/Index.h
Normal file
126
kernel/include/kernel/ACPI/AML/Index.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Buffer.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/Package.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Reference.h>
|
||||||
|
#include <kernel/ACPI/AML/Register.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Index
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::IndexOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto source_result = AML::parse_object(context);
|
||||||
|
if (!source_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto source = source_result.node() ? source_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
|
||||||
|
if (source && source->type != AML::Node::Type::Package)
|
||||||
|
source = source->convert(AML::Node::ConvBuffer | AML::Node::ConvInteger | AML::Node::ConvString);
|
||||||
|
if (!source)
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexOp source could not be converted");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto index_result = AML::parse_object(context);
|
||||||
|
if (!index_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto index_node = index_result.node()
|
||||||
|
? index_result.node()->convert(AML::Node::ConvInteger)
|
||||||
|
: BAN::RefPtr<AML::Node>();
|
||||||
|
if (!index_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexOp index is not an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
const auto index = static_cast<AML::Integer*>(index_node.ptr())->value;
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Reference> result;
|
||||||
|
switch (source->type)
|
||||||
|
{
|
||||||
|
case AML::Node::Type::Buffer:
|
||||||
|
{
|
||||||
|
auto buffer = BAN::RefPtr<AML::Buffer>(static_cast<AML::Buffer*>(source.ptr()));
|
||||||
|
if (index >= buffer->buffer.size())
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexOp index is out of buffer bounds");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
auto buffer_field = MUST(BAN::RefPtr<BufferField>::create(NameSeg(""_sv), buffer, index * 8, 8));
|
||||||
|
result = MUST(BAN::RefPtr<AML::Reference>::create(buffer_field));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AML::Node::Type::Package:
|
||||||
|
{
|
||||||
|
auto package = static_cast<AML::Package*>(source.ptr());
|
||||||
|
if (index >= package->elements.size())
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexOp index is out of package bounds");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
auto package_element = package->elements[index];
|
||||||
|
if (!package_element)
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexOp target is null package element");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
result = MUST(BAN::RefPtr<AML::Reference>::create(package_element));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AML::Node::Type::String:
|
||||||
|
{
|
||||||
|
auto string = BAN::RefPtr<AML::String>(static_cast<AML::String*>(source.ptr()));
|
||||||
|
if (index >= string->string.size())
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexOp index is out of string bounds");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
auto buffer_field = MUST(BAN::RefPtr<BufferField>::create(NameSeg(""_sv), string, index * 8, 8));
|
||||||
|
result = MUST(BAN::RefPtr<AML::Reference>::create(buffer_field));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
AML_ERROR("IndexOp source is not a Buffer, Package, or String");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINT("Index {}, ", index);
|
||||||
|
source->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (context.aml_data[0] == 0x00)
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto destination_result = AML::parse_object(context);
|
||||||
|
if (!destination_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto destination = destination_result.node();
|
||||||
|
if (!destination)
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexOp failed to resolve destination");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!destination->store(result))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseResult(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
39
kernel/include/kernel/ACPI/AML/Integer.h
Normal file
39
kernel/include/kernel/ACPI/AML/Integer.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Integer final : public AML::Node
|
||||||
|
{
|
||||||
|
struct Constants
|
||||||
|
{
|
||||||
|
// Initialized in Namespace::create_root_namespace
|
||||||
|
static BAN::RefPtr<Integer> Zero;
|
||||||
|
static BAN::RefPtr<Integer> One;
|
||||||
|
static BAN::RefPtr<Integer> Ones;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t value;
|
||||||
|
const bool constant;
|
||||||
|
|
||||||
|
Integer(uint64_t value, bool constant = false);
|
||||||
|
|
||||||
|
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop);
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
|
||||||
|
BAN::RefPtr<Node> copy() override;
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> store_node) override;
|
||||||
|
|
||||||
|
static ParseResult parse(BAN::ConstByteSpan& aml_data);
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
182
kernel/include/kernel/ACPI/AML/Method.h
Normal file
182
kernel/include/kernel/ACPI/AML/Method.h
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Function.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Register.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Method final : public AML::Scope
|
||||||
|
{
|
||||||
|
Kernel::Mutex mutex;
|
||||||
|
uint8_t arg_count;
|
||||||
|
bool serialized;
|
||||||
|
uint8_t sync_level;
|
||||||
|
|
||||||
|
BAN::Function<BAN::RefPtr<AML::Node>(ParseContext&)> override_function;
|
||||||
|
BAN::ConstByteSpan term_list;
|
||||||
|
|
||||||
|
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level)
|
||||||
|
: AML::Scope(Node::Type::Method, name)
|
||||||
|
, arg_count(arg_count)
|
||||||
|
, serialized(serialized)
|
||||||
|
, sync_level(sync_level)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::MethodOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto method_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!method_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto name_string = AML::NameString::parse(method_pkg.value());
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (method_pkg->size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto method_flags = method_pkg.value()[0];
|
||||||
|
method_pkg = method_pkg.value().slice(1);
|
||||||
|
|
||||||
|
auto method = MUST(BAN::RefPtr<Method>::create(
|
||||||
|
name_string.value().path.back(),
|
||||||
|
method_flags & 0x07,
|
||||||
|
(method_flags >> 3) & 0x01,
|
||||||
|
method_flags >> 4
|
||||||
|
));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), method))
|
||||||
|
return ParseResult::Success;
|
||||||
|
method->term_list = method_pkg.value();
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
method->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<BAN::RefPtr<AML::Node>> invoke(
|
||||||
|
BAN::RefPtr<AML::Node> arg0 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg1 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg2 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg3 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg4 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg5 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg6 = {}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BAN::Vector<uint8_t> sync_stack;
|
||||||
|
return invoke_with_sync_stack(sync_stack, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<BAN::RefPtr<AML::Node>> invoke_with_sync_stack(
|
||||||
|
BAN::Vector<uint8_t>& current_sync_stack,
|
||||||
|
BAN::RefPtr<AML::Node> arg0 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg1 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg2 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg3 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg4 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg5 = {},
|
||||||
|
BAN::RefPtr<AML::Node> arg6 = {}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (serialized && !current_sync_stack.empty() && sync_level < current_sync_stack.back())
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to evaluate method {} with lower sync level than current sync level", scope);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseContext context;
|
||||||
|
context.aml_data = term_list;
|
||||||
|
context.scope = scope;
|
||||||
|
context.method_args[0] = MUST(BAN::RefPtr<AML::Register>::create(arg0));
|
||||||
|
context.method_args[1] = MUST(BAN::RefPtr<AML::Register>::create(arg1));
|
||||||
|
context.method_args[2] = MUST(BAN::RefPtr<AML::Register>::create(arg2));
|
||||||
|
context.method_args[3] = MUST(BAN::RefPtr<AML::Register>::create(arg3));
|
||||||
|
context.method_args[4] = MUST(BAN::RefPtr<AML::Register>::create(arg4));
|
||||||
|
context.method_args[5] = MUST(BAN::RefPtr<AML::Register>::create(arg5));
|
||||||
|
context.method_args[6] = MUST(BAN::RefPtr<AML::Register>::create(arg6));
|
||||||
|
context.sync_stack = BAN::move(current_sync_stack);
|
||||||
|
for (auto& local : context.method_locals)
|
||||||
|
local = MUST(BAN::RefPtr<AML::Register>::create());
|
||||||
|
|
||||||
|
if (serialized)
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
MUST(context.sync_stack.push_back(sync_level));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINTLN("Evaluating {}", scope);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BAN::Optional<BAN::RefPtr<AML::Node>> return_value = BAN::RefPtr<AML::Node>();
|
||||||
|
|
||||||
|
if (override_function)
|
||||||
|
return_value = override_function(context);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (context.aml_data.size() > 0)
|
||||||
|
{
|
||||||
|
auto parse_result = AML::parse_object(context);
|
||||||
|
if (parse_result.returned())
|
||||||
|
{
|
||||||
|
return_value = parse_result.node();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!parse_result.success())
|
||||||
|
{
|
||||||
|
AML_ERROR("Method {} evaluate failed", scope);
|
||||||
|
return_value = {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (return_value.has_value() && return_value.value() && return_value.value()->type == AML::Node::Type::Register)
|
||||||
|
return_value.value() = static_cast<AML::Register*>(return_value.value().ptr())->value;
|
||||||
|
|
||||||
|
while (!context.created_objects.empty())
|
||||||
|
{
|
||||||
|
Namespace::root_namespace()->remove_named_object(context.created_objects.back());
|
||||||
|
context.created_objects.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serialized)
|
||||||
|
{
|
||||||
|
context.sync_stack.pop_back();
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
current_sync_stack = BAN::move(context.sync_stack);
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Method ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINTLN("({} args, {}Serialized, 0x{H}) {", arg_count, serialized ? "" : "Not", sync_level);
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("TermList: {} bytes", term_list.size());
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
170
kernel/include/kernel/ACPI/AML/Mutex.h
Normal file
170
kernel/include/kernel/ACPI/AML/Mutex.h
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Mutex final : public AML::NamedObject
|
||||||
|
{
|
||||||
|
Kernel::Mutex mutex;
|
||||||
|
uint8_t sync_level;
|
||||||
|
bool global;
|
||||||
|
|
||||||
|
Mutex(NameSeg name, uint8_t sync_level, bool global = false)
|
||||||
|
: NamedObject(Node::Type::Mutex, name)
|
||||||
|
, sync_level(sync_level)
|
||||||
|
, global(global)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
|
||||||
|
switch (static_cast<AML::ExtOp>(context.aml_data[1]))
|
||||||
|
{
|
||||||
|
case AML::ExtOp::MutexOp:
|
||||||
|
return parse_mutex(context);
|
||||||
|
case AML::ExtOp::AcquireOp:
|
||||||
|
return parse_acquire(context);
|
||||||
|
case AML::ExtOp::ReleaseOp:
|
||||||
|
return parse_release(context);
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Mutex ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(" (SyncLevel: {})", sync_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ParseResult parse_mutex(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::MutexOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto name = NameString::parse(context.aml_data);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto sync_level = context.aml_data[0];
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
if (sync_level & 0xF0)
|
||||||
|
{
|
||||||
|
AML_ERROR("Invalid sync level {}", sync_level);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mutex = MUST(BAN::RefPtr<Mutex>::create(name->path.back(), sync_level));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name.value(), mutex))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
mutex->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse_acquire(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::AcquireOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto mutex_result = AML::parse_object(context);
|
||||||
|
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
|
||||||
|
{
|
||||||
|
AML_ERROR("Acquire does not name a valid mutex");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
|
||||||
|
if (mutex->sync_level < context.sync_level())
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to acquire mutex with lower sync level than current sync level");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 2)
|
||||||
|
{
|
||||||
|
AML_ERROR("Missing timeout value");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
uint16_t timeout = context.aml_data[0] | (context.aml_data[1] << 8);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
if (timeout >= 0xFFFF)
|
||||||
|
mutex->mutex.lock();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: This is a very inefficient way to wait for a mutex
|
||||||
|
uint64_t wake_time = SystemTimer::get().ms_since_boot() + timeout;
|
||||||
|
while (!mutex->mutex.try_lock())
|
||||||
|
{
|
||||||
|
if (SystemTimer::get().ms_since_boot() >= wake_time)
|
||||||
|
return ParseResult(Integer::Constants::Ones);
|
||||||
|
Processor::yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MUST(context.sync_stack.push_back(mutex->sync_level));
|
||||||
|
return ParseResult(Integer::Constants::Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse_release(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ReleaseOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto mutex_result = AML::parse_object(context);
|
||||||
|
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
|
||||||
|
{
|
||||||
|
AML_ERROR("Release does not name a valid mutex");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.sync_stack.empty())
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to release mutex without having acquired it");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
|
||||||
|
if (mutex->sync_level != context.sync_level())
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to release mutex with different sync level than current sync level");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex->mutex.unlock();
|
||||||
|
context.sync_stack.pop_back();
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
44
kernel/include/kernel/ACPI/AML/NamedObject.h
Normal file
44
kernel/include/kernel/ACPI/AML/NamedObject.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/HashMap.h>
|
||||||
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NamedObject : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::RefPtr<NamedObject> parent;
|
||||||
|
NameSeg name;
|
||||||
|
|
||||||
|
NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Name final : public AML::NamedObject
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::Node> object;
|
||||||
|
|
||||||
|
Name(NameSeg name, BAN::RefPtr<AML::Node> object)
|
||||||
|
: NamedObject(Node::Type::Name, name), object(BAN::move(object))
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> to_underlying() override { return object; }
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
ASSERT(object);
|
||||||
|
return object->convert(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||||
|
{
|
||||||
|
ASSERT(object);
|
||||||
|
ASSERT(object->type != AML::Node::Type::Reference);
|
||||||
|
return object->store(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
virtual void debug_print(int indent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
244
kernel/include/kernel/ACPI/AML/Names.h
Normal file
244
kernel/include/kernel/ACPI/AML/Names.h
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NameSeg
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
char chars[4];
|
||||||
|
uint32_t u32;
|
||||||
|
};
|
||||||
|
|
||||||
|
NameSeg() = default;
|
||||||
|
|
||||||
|
NameSeg(BAN::StringView name)
|
||||||
|
{
|
||||||
|
ASSERT(name.size() <= 4);
|
||||||
|
for (size_t i = 0; i < name.size(); i++)
|
||||||
|
chars[i] = static_cast<char>(name[i]);
|
||||||
|
for (size_t i = name.size(); i < 4; i++)
|
||||||
|
chars[i] = '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
NameSeg(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
ASSERT(aml_data.size() >= 4);
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
chars[i] = static_cast<char>(aml_data[i]);
|
||||||
|
aml_data = aml_data.slice(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::StringView sv() const
|
||||||
|
{
|
||||||
|
size_t len = 4;
|
||||||
|
while (len > 0 && chars[len - 1] == '_')
|
||||||
|
len--;
|
||||||
|
return BAN::StringView(chars, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::Optional<NameSeg> parse(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 4)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!is_lead_name_char(aml_data[0])
|
||||||
|
|| !is_name_char(aml_data[1])
|
||||||
|
|| !is_name_char(aml_data[2])
|
||||||
|
|| !is_name_char(aml_data[3]))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return NameSeg(aml_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const NameSeg& other) const
|
||||||
|
{
|
||||||
|
return u32 == other.u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_print() const
|
||||||
|
{
|
||||||
|
size_t len = 4;
|
||||||
|
while (len > 0 && chars[len - 1] == '_')
|
||||||
|
len--;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
AML_DEBUG_PUTC(chars[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NameString
|
||||||
|
{
|
||||||
|
BAN::String prefix;
|
||||||
|
BAN::Vector<NameSeg> path;
|
||||||
|
|
||||||
|
NameString() = default;
|
||||||
|
NameString(BAN::StringView str)
|
||||||
|
{
|
||||||
|
if (!str.empty() && str.front() == '\\')
|
||||||
|
{
|
||||||
|
MUST(prefix.push_back('\\'));
|
||||||
|
str = str.substring(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (str.size() > 0 && str.front() == '^')
|
||||||
|
{
|
||||||
|
MUST(prefix.push_back('^'));
|
||||||
|
str = str.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!str.empty())
|
||||||
|
{
|
||||||
|
ASSERT(str[0] != '.');
|
||||||
|
size_t len = 1;
|
||||||
|
while (len < str.size() && str[len] != '.')
|
||||||
|
len++;
|
||||||
|
ASSERT(len <= 4);
|
||||||
|
|
||||||
|
MUST(path.push_back(NameSeg(str.substring(0, len))));
|
||||||
|
str = str.substring(len);
|
||||||
|
|
||||||
|
if (!str.empty())
|
||||||
|
{
|
||||||
|
ASSERT(str[0] == '.');
|
||||||
|
str = str.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan aml_data)
|
||||||
|
{
|
||||||
|
if (aml_data.size() == 0)
|
||||||
|
return false;
|
||||||
|
switch (static_cast<AML::Byte>(aml_data[0]))
|
||||||
|
{
|
||||||
|
case AML::Byte::RootChar:
|
||||||
|
case AML::Byte::ParentPrefixChar:
|
||||||
|
case AML::Byte::NullName:
|
||||||
|
case AML::Byte::DualNamePrefix:
|
||||||
|
case AML::Byte::MultiNamePrefix:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return is_lead_name_char(aml_data[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::Optional<NameString> parse(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
if (aml_data.size() == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
NameString result;
|
||||||
|
|
||||||
|
if (static_cast<AML::Byte>(aml_data[0]) == AML::Byte::RootChar)
|
||||||
|
{
|
||||||
|
MUST(result.prefix.push_back('\\'));
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (aml_data.size() > 0 && static_cast<AML::Byte>(aml_data[0]) == AML::Byte::ParentPrefixChar)
|
||||||
|
{
|
||||||
|
MUST(result.prefix.push_back(aml_data[0]));
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aml_data.size() == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
size_t name_count = 1;
|
||||||
|
switch (static_cast<AML::Byte>(aml_data[0]))
|
||||||
|
{
|
||||||
|
case AML::Byte::NullName:
|
||||||
|
name_count = 0;
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
break;
|
||||||
|
case AML::Byte::DualNamePrefix:
|
||||||
|
name_count = 2;
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
break;
|
||||||
|
case AML::Byte::MultiNamePrefix:
|
||||||
|
if (aml_data.size() < 2)
|
||||||
|
return {};
|
||||||
|
name_count = aml_data[1];
|
||||||
|
aml_data = aml_data.slice(2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < name_count; i++)
|
||||||
|
{
|
||||||
|
auto name_seg = NameSeg::parse(aml_data);
|
||||||
|
if (!name_seg.has_value())
|
||||||
|
return {};
|
||||||
|
MUST(result.path.push_back(name_seg.release_value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_print() const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < prefix.size(); i++)
|
||||||
|
AML_DEBUG_PUTC(prefix[i]);
|
||||||
|
if (!path.empty())
|
||||||
|
path.front().debug_print();
|
||||||
|
for (size_t i = 1; i < path.size(); i++)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PUTC('.');
|
||||||
|
path[i].debug_print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<Kernel::ACPI::AML::NameSeg>
|
||||||
|
{
|
||||||
|
constexpr hash_t operator()(Kernel::ACPI::AML::NameSeg name) const
|
||||||
|
{
|
||||||
|
return hash<uint32_t>()(name.u32);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Formatter
|
||||||
|
{
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::AML::NameSeg& name_seg, const ValueFormat&)
|
||||||
|
{
|
||||||
|
size_t len = 4;
|
||||||
|
while (len > 0 && name_seg.chars[len - 1] == '_')
|
||||||
|
len--;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
putc(name_seg.chars[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
|
||||||
|
{
|
||||||
|
print_argument(putc, name_string.prefix, {});
|
||||||
|
if (!name_string.path.empty())
|
||||||
|
print_argument(putc, name_string.path.front(), {});
|
||||||
|
for (size_t i = 1; i < name_string.path.size(); i++)
|
||||||
|
{
|
||||||
|
putc('.');
|
||||||
|
print_argument(putc, name_string.path[i], {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,74 +1,66 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Bitcast.h>
|
|
||||||
#include <BAN/ByteSpan.h>
|
|
||||||
#include <BAN/Function.h>
|
|
||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
#include <BAN/HashSet.h>
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
#include <BAN/Iteration.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
#include <kernel/ACPI/AML/Node.h>
|
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Namespace
|
struct Namespace final : public AML::Scope
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(Namespace);
|
static BAN::RefPtr<AML::Namespace> create_root_namespace();
|
||||||
BAN_NON_MOVABLE(Namespace);
|
static BAN::RefPtr<AML::Namespace> root_namespace();
|
||||||
public:
|
static BAN::RefPtr<AML::Node> debug_node;
|
||||||
Namespace() = default;
|
|
||||||
~Namespace();
|
|
||||||
|
|
||||||
static BAN::ErrorOr<void> prepare_root_namespace();
|
template<typename F>
|
||||||
static Namespace& root_namespace();
|
static void for_each_child(const AML::NameString& scope, const F& callback)
|
||||||
|
|
||||||
BAN::ErrorOr<void> post_load_initialize();
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> parse(BAN::ConstByteSpan);
|
|
||||||
|
|
||||||
BAN::ErrorOr<Node> evaluate(BAN::StringView path) { return evaluate(Scope {}, path); }
|
|
||||||
BAN::ErrorOr<Node> evaluate(const Scope& scope, BAN::StringView);
|
|
||||||
|
|
||||||
// returns empty scope if object already exited
|
|
||||||
BAN::ErrorOr<Scope> add_named_object(ParseContext& context, const NameString& name_string, Node&& node);
|
|
||||||
BAN::ErrorOr<Scope> add_alias(ParseContext& scope, const NameString& name_string, Reference* reference);
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> remove_named_object(const Scope& absolute_path);
|
|
||||||
|
|
||||||
// node is nullptr if it is not found
|
|
||||||
struct FindResult
|
|
||||||
{
|
{
|
||||||
Scope path;
|
auto canonical_path = root_namespace()->resolve_path(scope, {}, FindMode::ForceAbsolute);
|
||||||
Reference* node { nullptr };
|
ASSERT(canonical_path.has_value());
|
||||||
|
|
||||||
|
for (auto& [path, child] : root_namespace()->m_objects)
|
||||||
|
{
|
||||||
|
if (path.size() < canonical_path->size() + 1)
|
||||||
|
continue;
|
||||||
|
if (canonical_path->size() != 1 && path[canonical_path->size()] != '.')
|
||||||
|
continue;
|
||||||
|
if (path.sv().substring(0, canonical_path->size()) != canonical_path->sv())
|
||||||
|
continue;
|
||||||
|
if (path.sv().substring(canonical_path->size() + 1).contains('.'))
|
||||||
|
continue;
|
||||||
|
callback(path, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
bool parse(const SDTHeader& header);
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
|
||||||
|
enum class FindMode
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
ForceAbsolute,
|
||||||
};
|
};
|
||||||
BAN::ErrorOr<FindResult> find_named_object(const Scope& scope, const NameString& name_string, bool force_absolute = false);
|
BAN::Optional<BAN::String> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode, bool check_existence = true) const;
|
||||||
|
|
||||||
BAN::ErrorOr<Scope> find_reference_scope(const Reference* reference);
|
// Find an object in the namespace. Returns nullptr if the object is not found.
|
||||||
|
BAN::RefPtr<NamedObject> find_object(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode);
|
||||||
|
|
||||||
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(BAN::StringView, Reference*)>&);
|
// Add an object to the namespace. Returns false if the parent object could not be added.
|
||||||
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&);
|
bool add_named_object(ParseContext&, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object);
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::StringView eisa_id);
|
// Remove an object from the namespace. Returns false if the object could not be removed.
|
||||||
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::Span<BAN::StringView> eisa_ids);
|
bool remove_named_object(const AML::NameString& absolute_path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::ErrorOr<Scope> resolve_path(const Scope& scope, const NameString& name_string);
|
BAN::HashMap<BAN::String, BAN::RefPtr<NamedObject>> m_objects;
|
||||||
|
mutable Mutex m_object_mutex;
|
||||||
BAN::ErrorOr<void> initialize_scope(const Scope& scope);
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> opregion_call_reg(const Scope& scope, const Node& opregion);
|
|
||||||
|
|
||||||
BAN::ErrorOr<uint64_t> evaluate_sta(const Scope& scope);
|
|
||||||
BAN::ErrorOr<void> evaluate_ini(const Scope& scope);
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize_op_regions();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_has_initialized_namespace { false };
|
|
||||||
BAN::HashMap<Scope, Reference*> m_named_objects;
|
|
||||||
BAN::HashMap<Scope, uint32_t> m_called_reg_bitmaps;
|
|
||||||
BAN::HashSet<Scope> m_aliases;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,449 +1,115 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Array.h>
|
|
||||||
#include <BAN/ByteSpan.h>
|
#include <BAN/ByteSpan.h>
|
||||||
#include <BAN/LinkedList.h>
|
|
||||||
#include <BAN/NoCopyMove.h>
|
|
||||||
#include <BAN/Optional.h>
|
#include <BAN/Optional.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/RefPtr.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
#include <kernel/ACPI/AML/Scope.h>
|
|
||||||
#include <kernel/ACPI/Headers.h>
|
|
||||||
#include <kernel/Lock/Mutex.h>
|
|
||||||
|
|
||||||
#define AML_DUMP_FUNCTION_CALLS 0
|
|
||||||
#define AML_ENABLE_DEBUG 1
|
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
|
|
||||||
struct NameString
|
struct Buffer;
|
||||||
|
struct Integer;
|
||||||
|
struct String;
|
||||||
|
|
||||||
|
struct Node : public BAN::RefCounted<Node>
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(NameString);
|
static uint64_t total_node_count;
|
||||||
public:
|
|
||||||
NameString() = default;
|
|
||||||
NameString(NameString&& other)
|
|
||||||
: base(other.base)
|
|
||||||
, parts(BAN::move(other.parts))
|
|
||||||
{}
|
|
||||||
NameString& operator=(NameString&& other)
|
|
||||||
{
|
|
||||||
base = other.base;
|
|
||||||
parts = BAN::move(other.parts);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BAN::ErrorOr<NameString> from_string(BAN::StringView name);
|
|
||||||
|
|
||||||
BAN::ErrorOr<NameString> copy() const
|
|
||||||
{
|
|
||||||
NameString result;
|
|
||||||
result.base = this->base;
|
|
||||||
|
|
||||||
TRY(result.parts.resize(parts.size()));
|
|
||||||
for (size_t i = 0; i < parts.size(); i++)
|
|
||||||
result.parts[i] = parts[i];
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr uint32_t base_root = -1;
|
|
||||||
uint32_t base { 0 };
|
|
||||||
BAN::Vector<uint32_t> parts;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Pair
|
|
||||||
{
|
|
||||||
T1 elem1;
|
|
||||||
T2 elem2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Node;
|
|
||||||
struct ParseContext;
|
|
||||||
struct Reference;
|
|
||||||
|
|
||||||
struct Mutex
|
|
||||||
{
|
|
||||||
Kernel::Mutex mutex;
|
|
||||||
uint8_t sync_level;
|
|
||||||
bool global_lock;
|
|
||||||
uint32_t ref_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Buffer
|
|
||||||
{
|
|
||||||
BAN::StringView as_sv() const
|
|
||||||
{
|
|
||||||
return BAN::StringView(reinterpret_cast<const char*>(bytes), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t size;
|
|
||||||
uint32_t ref_count;
|
|
||||||
uint8_t bytes[];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OpRegion
|
|
||||||
{
|
|
||||||
GAS::AddressSpaceID address_space;
|
|
||||||
uint64_t offset;
|
|
||||||
uint64_t length;
|
|
||||||
alignas(Scope) uint8_t scope_storage[sizeof(Scope)];
|
|
||||||
Scope& scope() { return *reinterpret_cast<Scope*>(scope_storage); }
|
|
||||||
const Scope& scope() const { return *reinterpret_cast<const Scope*>(scope_storage); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FieldUnit
|
|
||||||
{
|
|
||||||
enum class Type {
|
|
||||||
Field,
|
|
||||||
IndexField,
|
|
||||||
BankField,
|
|
||||||
};
|
|
||||||
uint64_t offset;
|
|
||||||
uint64_t length;
|
|
||||||
uint8_t flags;
|
|
||||||
Type type;
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
OpRegion opregion;
|
|
||||||
} field;
|
|
||||||
struct {
|
|
||||||
Reference* index;
|
|
||||||
Reference* data;
|
|
||||||
} index_field;
|
|
||||||
struct {
|
|
||||||
OpRegion opregion;
|
|
||||||
Reference* bank_selector;
|
|
||||||
uint64_t bank_value;
|
|
||||||
} bank_field;
|
|
||||||
} as;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Package
|
|
||||||
{
|
|
||||||
struct Element
|
|
||||||
{
|
|
||||||
struct Location {
|
|
||||||
NameString name;
|
|
||||||
Scope scope;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool resolved { true };
|
|
||||||
union {
|
|
||||||
Node* node { nullptr };
|
|
||||||
Location* location;
|
|
||||||
} value;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint64_t num_elements;
|
|
||||||
uint32_t ref_count;
|
|
||||||
Element elements[];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Node
|
|
||||||
{
|
|
||||||
BAN_NON_COPYABLE(Node);
|
|
||||||
public:
|
|
||||||
Node() = default;
|
|
||||||
~Node() { clear(); }
|
|
||||||
|
|
||||||
Node(Node&& other) { *this = BAN::move(other); }
|
|
||||||
Node& operator=(Node&&);
|
|
||||||
|
|
||||||
static BAN::ErrorOr<Node> create_string(BAN::StringView string)
|
|
||||||
{
|
|
||||||
const auto* u8_data = reinterpret_cast<const uint8_t*>(string.data());
|
|
||||||
auto result = TRY(create_buffer({ u8_data, string.size() }));
|
|
||||||
result.type = Node::Type::String;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BAN::ErrorOr<Node> create_buffer(BAN::ConstByteSpan buffer)
|
|
||||||
{
|
|
||||||
Node node;
|
|
||||||
node.type = Node::Type::Buffer;
|
|
||||||
node.as.str_buf = static_cast<Buffer*>(kmalloc(sizeof(Buffer) + buffer.size()));
|
|
||||||
if (node.as.str_buf == nullptr)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
node.as.str_buf->ref_count = 1;
|
|
||||||
node.as.str_buf->size = buffer.size();
|
|
||||||
memcpy(node.as.str_buf->bytes, buffer.data(), buffer.size());
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
Uninitialized,
|
|
||||||
Debug,
|
|
||||||
Integer,
|
|
||||||
String,
|
|
||||||
Buffer,
|
|
||||||
Package,
|
|
||||||
BufferField,
|
|
||||||
OpRegion,
|
|
||||||
FieldUnit,
|
|
||||||
Event,
|
|
||||||
Device,
|
|
||||||
Processor,
|
|
||||||
PowerResource,
|
|
||||||
ThermalZone,
|
|
||||||
Method,
|
|
||||||
Mutex,
|
|
||||||
// FIXME: Index should not be its own type
|
|
||||||
// parsing index should return references
|
|
||||||
Index,
|
|
||||||
Reference,
|
|
||||||
PredefinedScope,
|
|
||||||
Count
|
|
||||||
} type { Type::Uninitialized };
|
|
||||||
|
|
||||||
inline bool is_scope() const
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case Type::Device:
|
|
||||||
case Type::Processor:
|
|
||||||
case Type::PowerResource:
|
|
||||||
case Type::ThermalZone:
|
|
||||||
case Type::PredefinedScope:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
uint64_t value;
|
|
||||||
} integer;
|
|
||||||
Package* package;
|
|
||||||
Buffer* str_buf;
|
|
||||||
struct {
|
|
||||||
Buffer* buffer;
|
|
||||||
uint64_t bit_offset;
|
|
||||||
uint64_t bit_count;
|
|
||||||
} buffer_field;
|
|
||||||
OpRegion opregion;
|
|
||||||
FieldUnit field_unit;
|
|
||||||
struct {
|
|
||||||
uint32_t signal_count;
|
|
||||||
} event;
|
|
||||||
struct {
|
|
||||||
uint8_t storage[sizeof(Kernel::Mutex)];
|
|
||||||
const uint8_t* start;
|
|
||||||
size_t length;
|
|
||||||
uint8_t arg_count;
|
|
||||||
BAN::ErrorOr<Node> (*override_func)(const BAN::Array<Reference*, 7>&);
|
|
||||||
bool serialized;
|
|
||||||
Mutex* mutex;
|
|
||||||
} method;
|
|
||||||
Mutex* mutex;
|
|
||||||
struct {
|
|
||||||
Node::Type type;
|
|
||||||
union {
|
|
||||||
Buffer* str_buf;
|
|
||||||
Package* package;
|
|
||||||
} as;
|
|
||||||
uint64_t index;
|
|
||||||
} index;
|
|
||||||
Reference* reference;
|
|
||||||
} as;
|
|
||||||
|
|
||||||
BAN::ErrorOr<Node> copy() const;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Reference
|
|
||||||
{
|
|
||||||
Node node {};
|
|
||||||
uint32_t ref_count { 1 };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ParseContext
|
|
||||||
{
|
|
||||||
Scope scope;
|
|
||||||
BAN::ConstByteSpan aml_data;
|
|
||||||
|
|
||||||
uint32_t call_depth { 0 };
|
|
||||||
BAN::Array<Reference*, 8> locals;
|
|
||||||
BAN::Array<Reference*, 7> args;
|
|
||||||
|
|
||||||
BAN::LinkedList<Scope> created_nodes;
|
|
||||||
|
|
||||||
~ParseContext();
|
|
||||||
BAN::ErrorOr<void> allocate_locals();
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ExecutionFlow
|
|
||||||
{
|
|
||||||
Normal,
|
|
||||||
Break,
|
|
||||||
Continue,
|
|
||||||
Return,
|
|
||||||
};
|
|
||||||
using ExecutionFlowResult = Pair<ExecutionFlow, BAN::Optional<Node>>;
|
|
||||||
|
|
||||||
enum Conversion : uint8_t
|
enum Conversion : uint8_t
|
||||||
{
|
{
|
||||||
ConvInteger = 1,
|
ConvBuffer = 1 << 0,
|
||||||
ConvBuffer = 2,
|
ConvBufferField = 1 << 1,
|
||||||
ConvString = 4,
|
ConvFieldUnit = 1 << 2,
|
||||||
|
ConvInteger = 1 << 3,
|
||||||
|
ConvString = 1 << 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
BAN::ErrorOr<Node> parse_node(ParseContext& context, bool return_ref = false);
|
enum class Type : uint8_t
|
||||||
BAN::ErrorOr<ExecutionFlowResult> parse_node_or_execution_flow(ParseContext& context);
|
|
||||||
|
|
||||||
BAN::ErrorOr<NameString> parse_name_string(BAN::ConstByteSpan& aml_data);
|
|
||||||
BAN::ErrorOr<BAN::ConstByteSpan> parse_pkg(BAN::ConstByteSpan& aml_data);
|
|
||||||
|
|
||||||
BAN::ErrorOr<Node> convert_node(Node&& source, uint8_t conversion, uint64_t max_length);
|
|
||||||
BAN::ErrorOr<Node> convert_node(Node&& source, const Node& target);
|
|
||||||
|
|
||||||
BAN::ErrorOr<Node> evaluate_node(const Scope& node_path, const Node& node);
|
|
||||||
|
|
||||||
// If method has no return, it will return <integer 0>
|
|
||||||
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method, BAN::Array<Reference*, 7>&& args, uint32_t call_depth = 0);
|
|
||||||
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method,
|
|
||||||
Node&& arg0 = {}, Node&& arg1 = {}, Node&& arg2 = {}, Node&& arg3 = {}, Node&& arg4 = {}, Node&& arg5 = {}, Node&& arg6 = {});
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> resolve_package_element(Package::Element& element, bool error_if_not_exists);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace BAN::Formatter
|
|
||||||
{
|
{
|
||||||
|
None,
|
||||||
|
BankFieldElement,
|
||||||
|
Buffer,
|
||||||
|
BufferField,
|
||||||
|
Debug,
|
||||||
|
Device,
|
||||||
|
Event,
|
||||||
|
FieldElement,
|
||||||
|
IndexFieldElement,
|
||||||
|
Integer,
|
||||||
|
Method,
|
||||||
|
Mutex,
|
||||||
|
Name,
|
||||||
|
Namespace,
|
||||||
|
OpRegion,
|
||||||
|
Package,
|
||||||
|
PackageElement,
|
||||||
|
PowerResource,
|
||||||
|
Processor,
|
||||||
|
Reference,
|
||||||
|
Register,
|
||||||
|
String,
|
||||||
|
ThermalZone,
|
||||||
|
};
|
||||||
|
const Type type;
|
||||||
|
|
||||||
template<typename F>
|
Node(Type type) : type(type) { total_node_count++; }
|
||||||
void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
|
virtual ~Node() { total_node_count--; }
|
||||||
|
|
||||||
|
virtual bool is_scope() const { return false; }
|
||||||
|
|
||||||
|
[[nodiscard]] virtual BAN::RefPtr<AML::Node> to_underlying() { return this; }
|
||||||
|
[[nodiscard]] virtual BAN::RefPtr<AML::Node> convert(uint8_t mask) = 0;
|
||||||
|
[[nodiscard]] virtual BAN::RefPtr<Node> copy() { return this; }
|
||||||
|
[[nodiscard]] virtual BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node>) { AML_TODO("store, type {}", static_cast<uint8_t>(type)); return {}; }
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParseContext;
|
||||||
|
struct ParseResult
|
||||||
{
|
{
|
||||||
if (name_string.base == Kernel::ACPI::AML::NameString::base_root)
|
static ParseResult Failure;
|
||||||
putc('\\');
|
static ParseResult Success;
|
||||||
else for (uint32_t i = 0; i < name_string.base; i++)
|
|
||||||
putc('^');
|
enum class Result
|
||||||
for (size_t i = 0; i < name_string.parts.size(); i++) {
|
{
|
||||||
if (i != 0)
|
Success,
|
||||||
putc('.');
|
Failure,
|
||||||
const char* name_seg = reinterpret_cast<const char*>(&name_string.parts[i]);
|
Returned,
|
||||||
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
|
Breaked,
|
||||||
}
|
Continued,
|
||||||
|
};
|
||||||
|
|
||||||
|
ParseResult(Result success)
|
||||||
|
: m_result(success)
|
||||||
|
{}
|
||||||
|
ParseResult(Result success, BAN::RefPtr<Node> node)
|
||||||
|
: m_result(success)
|
||||||
|
, m_node(BAN::move(node))
|
||||||
|
{}
|
||||||
|
ParseResult(BAN::RefPtr<Node> node)
|
||||||
|
: m_result(Result::Success)
|
||||||
|
, m_node(BAN::move(node))
|
||||||
|
{
|
||||||
|
ASSERT(m_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
bool success() const { return m_result == Result::Success; }
|
||||||
void print_argument(F putc, const Kernel::ACPI::AML::Buffer& buffer, const ValueFormat&)
|
bool returned() const { return m_result == Result::Returned; }
|
||||||
{
|
bool breaked() const { return m_result == Result::Breaked; }
|
||||||
static constexpr size_t max_elements { 16 };
|
bool continued() const { return m_result == Result::Continued; }
|
||||||
|
|
||||||
print(putc, "<buffer '");
|
BAN::RefPtr<Node> node()
|
||||||
if (buffer.size)
|
{
|
||||||
print(putc, "{2H}", buffer.bytes[0]);
|
return m_node;
|
||||||
for (size_t i = 1; i < buffer.size && i < max_elements; i++)
|
|
||||||
print(putc, " {2H}", buffer.bytes[i]);
|
|
||||||
if (buffer.size > max_elements)
|
|
||||||
print(putc, "...");
|
|
||||||
print(putc, "'>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
private:
|
||||||
void print_argument(F putc, const Kernel::ACPI::AML::Package& package, const ValueFormat&)
|
Result m_result = Result::Failure;
|
||||||
{
|
BAN::RefPtr<Node> m_node;
|
||||||
print(putc, "<package '{} elements'>", package.num_elements);
|
};
|
||||||
}
|
ParseResult parse_object(ParseContext& context);
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
void print_argument(F putc, const Kernel::ACPI::AML::Node& node, const ValueFormat&)
|
|
||||||
{
|
|
||||||
switch (node.type)
|
|
||||||
{
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Uninitialized:
|
|
||||||
print(putc, "<uninitialized>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Debug:
|
|
||||||
print(putc, "<debug>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Integer:
|
|
||||||
print(putc, "<integer 0x{H}>", node.as.integer.value);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::String:
|
|
||||||
print(putc, "<string '{}'>", node.as.str_buf->as_sv());
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Package:
|
|
||||||
print(putc, "{}", *node.as.package);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Buffer:
|
|
||||||
print(putc, "{}", *node.as.str_buf);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::BufferField:
|
|
||||||
print(putc, "<buffer field '{} bytes, offset 0x{H}, bit count {}'>",
|
|
||||||
node.as.buffer_field.buffer->size,
|
|
||||||
node.as.buffer_field.bit_offset,
|
|
||||||
node.as.buffer_field.bit_count
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::OpRegion:
|
|
||||||
print(putc, "<opregion 'type {2H}, offset 0x{H}, length 0x{H}'>",
|
|
||||||
static_cast<uint8_t>(node.as.opregion.address_space),
|
|
||||||
node.as.opregion.offset,
|
|
||||||
node.as.opregion.length
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::FieldUnit:
|
|
||||||
print(putc, "<field unit ({}), 'offset 0x{H}, length 0x{H}'>",
|
|
||||||
static_cast<uint8_t>(node.as.field_unit.type),
|
|
||||||
node.as.field_unit.offset,
|
|
||||||
node.as.field_unit.length
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Event:
|
|
||||||
print(putc, "<event '{} signals'>", node.as.event.signal_count);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Device:
|
|
||||||
print(putc, "<device>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Processor:
|
|
||||||
print(putc, "<processor>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::PowerResource:
|
|
||||||
print(putc, "<power resouce>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::ThermalZone:
|
|
||||||
print(putc, "<thermal zone>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Method:
|
|
||||||
print(putc, "<method '{} bytes'>", node.as.method.length);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Mutex:
|
|
||||||
print(putc, "<mutex>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Index:
|
|
||||||
switch (node.as.index.type)
|
|
||||||
{
|
|
||||||
case Kernel::ACPI::AML::Node::Type::String:
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Buffer:
|
|
||||||
print(putc, "<index {}, {}>", *node.as.index.as.str_buf, node.as.index.index);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Package:
|
|
||||||
print(putc, "<index {}, {}>", *node.as.index.as.package, node.as.index.index);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
print(putc, "<index {}??, {}>", (uint32_t)node.as.index.type, node.as.index.index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Reference:
|
|
||||||
print(putc, "<reference {}, {} refs>", node.as.reference->node, node.as.reference->ref_count);
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::PredefinedScope:
|
|
||||||
print(putc, "<scope>");
|
|
||||||
break;
|
|
||||||
case Kernel::ACPI::AML::Node::Type::Count:
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
67
kernel/include/kernel/ACPI/AML/Notify.h
Normal file
67
kernel/include/kernel/ACPI/AML/Notify.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Device.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Processor.h>
|
||||||
|
#include <kernel/ACPI/AML/ThermalZone.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Notify
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::NotifyOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto object_result = AML::parse_object(context);
|
||||||
|
if (!object_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto object = object_result.node();
|
||||||
|
if (!object)
|
||||||
|
{
|
||||||
|
AML_ERROR("Notify object is null");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value_result = AML::parse_object(context);
|
||||||
|
if (!value_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto value_node = value_result.node() ? value_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||||
|
if (!value_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Notify value is not an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
const auto value = static_cast<AML::Integer*>(value_node.ptr())->value;
|
||||||
|
|
||||||
|
BAN::StringView object_type_sv;
|
||||||
|
BAN::StringView object_name_sv;
|
||||||
|
switch (object->type)
|
||||||
|
{
|
||||||
|
case AML::Node::Type::Device:
|
||||||
|
object_type_sv = "Device"_sv;
|
||||||
|
object_name_sv = static_cast<AML::Device*>(object.ptr())->name.sv();
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Processor:
|
||||||
|
object_type_sv = "Processor"_sv;
|
||||||
|
object_name_sv = static_cast<AML::Processor*>(object.ptr())->name.sv();
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::ThermalZone:
|
||||||
|
object_type_sv = "ThermalZone"_sv;
|
||||||
|
object_name_sv = static_cast<AML::ThermalZone*>(object.ptr())->name.sv();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
object_type_sv = "Unknown"_sv;
|
||||||
|
object_name_sv = "????"_sv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
AML_TODO("Notify: {} {}: {2H}", object_type_sv, object_name_sv, value);
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
107
kernel/include/kernel/ACPI/AML/ObjectType.h
Normal file
107
kernel/include/kernel/ACPI/AML/ObjectType.h
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Reference.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ObjectType
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ObjectTypeOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto object_result = AML::parse_object(context);
|
||||||
|
if (!object_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto object = object_result.node()
|
||||||
|
? object_result.node()->to_underlying()
|
||||||
|
: BAN::RefPtr<AML::Node>();
|
||||||
|
|
||||||
|
if (object && object->type == AML::Node::Type::Reference)
|
||||||
|
object = static_cast<AML::Reference*>(object.ptr())->node->to_underlying();
|
||||||
|
|
||||||
|
uint64_t value = 0;
|
||||||
|
if (object)
|
||||||
|
{
|
||||||
|
switch (object->type)
|
||||||
|
{
|
||||||
|
case AML::Node::Type::None:
|
||||||
|
case AML::Node::Type::Name:
|
||||||
|
case AML::Node::Type::PackageElement:
|
||||||
|
case AML::Node::Type::Reference:
|
||||||
|
case AML::Node::Type::Register:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
case AML::Node::Type::Namespace:
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Integer:
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::String:
|
||||||
|
value = 2;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Buffer:
|
||||||
|
value = 3;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Package:
|
||||||
|
value = 4;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::FieldElement:
|
||||||
|
case AML::Node::Type::BankFieldElement:
|
||||||
|
case AML::Node::Type::IndexFieldElement:
|
||||||
|
value = 5;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Device:
|
||||||
|
value = 6;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Event:
|
||||||
|
value = 7;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Method:
|
||||||
|
value = 8;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Mutex:
|
||||||
|
value = 9;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::OpRegion:
|
||||||
|
value = 10;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::PowerResource:
|
||||||
|
value = 11;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Processor:
|
||||||
|
value = 12;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::ThermalZone:
|
||||||
|
value = 13;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::BufferField:
|
||||||
|
value = 14;
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Debug:
|
||||||
|
value = 16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
if (!object)
|
||||||
|
AML_DEBUG_PRINTLN("ObjectType { null }");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINTLN("ObjectType {");
|
||||||
|
object->debug_print(1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<AML::Integer>::create(value)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kernel/ACPI/AML/Node.h>
|
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML
|
|
||||||
{
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> parse_opregion_op(ParseContext& context);
|
|
||||||
BAN::ErrorOr<void> parse_field_op(ParseContext& context);
|
|
||||||
BAN::ErrorOr<void> parse_index_field_op(ParseContext& context);
|
|
||||||
BAN::ErrorOr<void> parse_bank_field_op(ParseContext& context);
|
|
||||||
|
|
||||||
BAN::ErrorOr<Node> convert_from_field_unit(const Node& node, uint8_t conversion, uint64_t max_length);
|
|
||||||
BAN::ErrorOr<void> store_to_field_unit(const Node& source, const Node& target);
|
|
||||||
|
|
||||||
}
|
|
||||||
168
kernel/include/kernel/ACPI/AML/Package.h
Normal file
168
kernel/include/kernel/ACPI/AML/Package.h
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Reference.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PackageElement;
|
||||||
|
|
||||||
|
struct Package final : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::Vector<BAN::RefPtr<PackageElement>> elements;
|
||||||
|
AML::NameString scope;
|
||||||
|
|
||||||
|
Package(AML::NameString scope)
|
||||||
|
: Node(Node::Type::Package)
|
||||||
|
, elements(BAN::move(elements))
|
||||||
|
, scope(scope)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context);
|
||||||
|
virtual void debug_print(int indent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PackageElement final : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::Package> parent;
|
||||||
|
BAN::RefPtr<AML::Node> element;
|
||||||
|
AML::NameString unresolved_name;
|
||||||
|
bool resolved = false;
|
||||||
|
bool initialized = false;
|
||||||
|
|
||||||
|
PackageElement(BAN::RefPtr<AML::Package> parent, BAN::RefPtr<AML::Node> element)
|
||||||
|
: Node(Node::Type::PackageElement)
|
||||||
|
, parent(parent)
|
||||||
|
, element(element)
|
||||||
|
{
|
||||||
|
ASSERT(element);
|
||||||
|
resolved = true;
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageElement(BAN::RefPtr<AML::Package> parent, AML::NameString unresolved_name)
|
||||||
|
: Node(Node::Type::PackageElement)
|
||||||
|
, parent(parent)
|
||||||
|
, unresolved_name(unresolved_name)
|
||||||
|
{
|
||||||
|
resolved = false;
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageElement(BAN::RefPtr<AML::Package> parent)
|
||||||
|
: Node(Node::Type::PackageElement)
|
||||||
|
, parent(parent)
|
||||||
|
{
|
||||||
|
resolved = false;
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resolve()
|
||||||
|
{
|
||||||
|
ASSERT(!resolved);
|
||||||
|
|
||||||
|
auto object = Namespace::root_namespace()->find_object(parent->scope, unresolved_name, Namespace::FindMode::Normal);
|
||||||
|
if (!object)
|
||||||
|
{
|
||||||
|
AML_ERROR("Failed to resolve reference {} in package {}", unresolved_name, parent->scope);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
element = object;
|
||||||
|
resolved = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to convert uninitialized PackageElement");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!resolved && !resolve())
|
||||||
|
return {};
|
||||||
|
return element->convert(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> to_underlying() override
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to read uninitialized PackageElement");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!resolved && !resolve())
|
||||||
|
return {};
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
initialized = true;
|
||||||
|
resolved = true;
|
||||||
|
}
|
||||||
|
if (!resolved && !resolve())
|
||||||
|
return {};
|
||||||
|
ASSERT(!element || element->type != AML::Node::Type::Reference);
|
||||||
|
if (node->type == AML::Node::Type::Reference)
|
||||||
|
element = static_cast<AML::Reference*>(node.ptr())->node;
|
||||||
|
else
|
||||||
|
element = node->copy();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context, BAN::RefPtr<AML::Package> package)
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::PackageElement> element;
|
||||||
|
if (context.aml_data[0] != 0x00 && AML::NameString::can_parse(context.aml_data))
|
||||||
|
{
|
||||||
|
auto name = AML::NameString::parse(context.aml_data);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
element = MUST(BAN::RefPtr<PackageElement>::create(package, name.value()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto element_result = AML::parse_object(context);
|
||||||
|
if (!element_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
element = MUST(BAN::RefPtr<PackageElement>::create(package, element_result.node()));
|
||||||
|
}
|
||||||
|
return ParseResult(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINTLN("PackageElement {");
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||||
|
AML_DEBUG_PRINT("Uninitialized");
|
||||||
|
}
|
||||||
|
else if (!resolved)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||||
|
AML_DEBUG_PRINT("Unresolved {}", unresolved_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
element->debug_print(indent + 1);
|
||||||
|
}
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
30
kernel/include/kernel/ACPI/AML/ParseContext.h
Normal file
30
kernel/include/kernel/ACPI/AML/ParseContext.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Array.h>
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/LinkedList.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/AML/Register.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ParseContext
|
||||||
|
{
|
||||||
|
BAN::ConstByteSpan aml_data;
|
||||||
|
AML::NameString scope;
|
||||||
|
|
||||||
|
// Used for cleaning up on method exit
|
||||||
|
// NOTE: This uses linked list instead of vector because
|
||||||
|
// we don't really need large contiguous memory
|
||||||
|
BAN::LinkedList<AML::NameString> created_objects;
|
||||||
|
|
||||||
|
uint8_t sync_level() const { return !sync_stack.empty() ? sync_stack.back() : 0; }
|
||||||
|
BAN::Vector<uint8_t> sync_stack;
|
||||||
|
|
||||||
|
BAN::Array<BAN::RefPtr<Register>, 7> method_args;
|
||||||
|
BAN::Array<BAN::RefPtr<Register>, 8> method_locals;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
51
kernel/include/kernel/ACPI/AML/Pkg.h
Normal file
51
kernel/include/kernel/ACPI/AML/Pkg.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
static BAN::Optional<uint32_t> parse_pkg_length(BAN::ConstByteSpan aml_data)
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 1)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
uint8_t lead_byte = aml_data[0];
|
||||||
|
if ((lead_byte & 0xC0) && (lead_byte & 0x30))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
uint32_t pkg_length = lead_byte & 0x3F;
|
||||||
|
uint8_t byte_count = (lead_byte >> 6) + 1;
|
||||||
|
|
||||||
|
if (aml_data.size() < byte_count)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
for (uint8_t i = 1; i < byte_count; i++)
|
||||||
|
pkg_length |= aml_data[i] << (i * 8 - 4);
|
||||||
|
|
||||||
|
return pkg_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trim_pkg_length(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
ASSERT(aml_data.size() >= 1);
|
||||||
|
uint8_t byte_count = (aml_data[0] >> 6) + 1;
|
||||||
|
aml_data = aml_data.slice(byte_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::Optional<BAN::ConstByteSpan> parse_pkg(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
auto pkg_length = parse_pkg_length(aml_data);
|
||||||
|
if (!pkg_length.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto result = aml_data.slice(0, pkg_length.value());
|
||||||
|
trim_pkg_length(result);
|
||||||
|
|
||||||
|
aml_data = aml_data.slice(pkg_length.value());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
70
kernel/include/kernel/ACPI/AML/PowerResource.h
Normal file
70
kernel/include/kernel/ACPI/AML/PowerResource.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PowerResource final : public AML::Scope
|
||||||
|
{
|
||||||
|
uint8_t system_level;
|
||||||
|
uint16_t resource_order;
|
||||||
|
|
||||||
|
PowerResource(NameSeg name, uint8_t system_level, uint16_t resource_order)
|
||||||
|
: Scope(Node::Type::PowerResource, name)
|
||||||
|
, system_level(system_level)
|
||||||
|
, resource_order(resource_order)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::PowerResOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto opt_power_res_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!opt_power_res_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto power_res_pkg = opt_power_res_pkg.value();
|
||||||
|
|
||||||
|
auto name = NameString::parse(power_res_pkg);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (power_res_pkg.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint8_t system_level = power_res_pkg[0];
|
||||||
|
power_res_pkg = power_res_pkg.slice(1);
|
||||||
|
|
||||||
|
if (power_res_pkg.size() < 2)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint16_t resource_order = BAN::little_endian_to_host<uint16_t>(*reinterpret_cast<const uint16_t*>(power_res_pkg.data()));
|
||||||
|
power_res_pkg = power_res_pkg.slice(2);
|
||||||
|
|
||||||
|
auto power_res = MUST(BAN::RefPtr<PowerResource>::create(name->path.back(), system_level, resource_order));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name.value(), power_res))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
power_res->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return power_res->enter_context_and_parse_term_list(context, name.value(), power_res_pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("PowerResource {} (SystemLevel {}, ResourceOrder {})", name, system_level, resource_order);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
86
kernel/include/kernel/ACPI/AML/Processor.h
Normal file
86
kernel/include/kernel/ACPI/AML/Processor.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Processor final : public AML::Scope
|
||||||
|
{
|
||||||
|
uint8_t id;
|
||||||
|
uint32_t pblk_addr;
|
||||||
|
uint8_t pblk_len;
|
||||||
|
|
||||||
|
Processor(NameSeg name, uint8_t id, uint32_t pblk_addr, uint8_t pblk_len)
|
||||||
|
: Scope(Node::Type::Processor, name)
|
||||||
|
, id(id)
|
||||||
|
, pblk_addr(pblk_addr)
|
||||||
|
, pblk_len(pblk_len)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ProcessorOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto opt_processor_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!opt_processor_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto processor_pkg = opt_processor_pkg.value();
|
||||||
|
|
||||||
|
auto name = NameString::parse(processor_pkg);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (processor_pkg.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint8_t id = processor_pkg[0];
|
||||||
|
processor_pkg = processor_pkg.slice(1);
|
||||||
|
|
||||||
|
if (processor_pkg.size() < 4)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint32_t pblk_addr = BAN::little_endian_to_host<uint32_t>(*reinterpret_cast<const uint32_t*>(processor_pkg.data()));
|
||||||
|
processor_pkg = processor_pkg.slice(4);
|
||||||
|
|
||||||
|
if (processor_pkg.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint8_t pblk_len = processor_pkg[0];
|
||||||
|
processor_pkg = processor_pkg.slice(1);
|
||||||
|
|
||||||
|
auto processor = MUST(BAN::RefPtr<Processor>::create(name->path.back(), id, pblk_addr, pblk_len));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name.value(), processor))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
processor->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINTLN("Processor {} (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {}) {", name, id, pblk_addr, pblk_len);
|
||||||
|
Namespace::root_namespace()->for_each_child(scope,
|
||||||
|
[&](const auto&, const auto& child)
|
||||||
|
{
|
||||||
|
child->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
186
kernel/include/kernel/ACPI/AML/Reference.h
Normal file
186
kernel/include/kernel/ACPI/AML/Reference.h
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
|
#include <kernel/ACPI/AML/String.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Reference final : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::Node> node;
|
||||||
|
|
||||||
|
Reference(BAN::RefPtr<AML::Node> node)
|
||||||
|
: Node(AML::Node::Type::Reference)
|
||||||
|
, node(node)
|
||||||
|
{
|
||||||
|
ASSERT(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||||
|
{
|
||||||
|
ASSERT(node);
|
||||||
|
return node->convert(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> value) override
|
||||||
|
{
|
||||||
|
ASSERT(node);
|
||||||
|
return node->store(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
|
||||||
|
bool conditional = false;
|
||||||
|
switch (static_cast<AML::Byte>(context.aml_data[0]))
|
||||||
|
{
|
||||||
|
case AML::Byte::DerefOfOp:
|
||||||
|
return parse_dereference(context);
|
||||||
|
case AML::Byte::RefOfOp:
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
conditional = false;
|
||||||
|
break;
|
||||||
|
case AML::Byte::ExtOpPrefix:
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::CondRefOfOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
conditional = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> object;
|
||||||
|
if (NameString::can_parse(context.aml_data))
|
||||||
|
{
|
||||||
|
auto name = NameString::parse(context.aml_data);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
object = Namespace::root_namespace()->find_object(context.scope, name.value(), Namespace::FindMode::Normal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto parse_result = AML::parse_object(context);
|
||||||
|
if (!parse_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
object = parse_result.node();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object && object->type == AML::Node::Type::Reference)
|
||||||
|
object = static_cast<AML::Reference*>(object.ptr())->node;
|
||||||
|
if (object && object->type == AML::Node::Type::Register)
|
||||||
|
object = static_cast<AML::Register*>(object.ptr())->value;
|
||||||
|
|
||||||
|
if (!conditional)
|
||||||
|
{
|
||||||
|
if (!object)
|
||||||
|
{
|
||||||
|
AML_ERROR("RefOf failed to resolve reference");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
auto reference = MUST(BAN::RefPtr<Reference>::create(object));
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
reference->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
return ParseResult(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
{
|
||||||
|
AML_ERROR("CondRefOf missing target");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> target_node;
|
||||||
|
if (context.aml_data[0] == 0x00)
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto target_result = AML::parse_object(context);
|
||||||
|
if (!target_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
target_node = target_result.node();
|
||||||
|
if (!target_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("CondRefOf failed to resolve target");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINT("CondRefOf ");
|
||||||
|
if (object)
|
||||||
|
object->debug_print(0);
|
||||||
|
else
|
||||||
|
AML_DEBUG_PRINT("null");
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!object)
|
||||||
|
return AML::ParseResult(Integer::Constants::Zero);
|
||||||
|
|
||||||
|
if (target_node && !target_node->store(object))
|
||||||
|
{
|
||||||
|
AML_ERROR("CondRefOf failed to store into target");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AML::ParseResult(Integer::Constants::Ones);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse_dereference(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::DerefOfOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
if (context.aml_data.size() >= 1 && static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::StringPrefix)
|
||||||
|
{
|
||||||
|
auto string_result = AML::String::parse(context);
|
||||||
|
if (!string_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
ASSERT(string_result.node());
|
||||||
|
auto string = static_cast<AML::String*>(string_result.node().ptr());
|
||||||
|
AML_TODO("DerefOf String ({})", string->string);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto parse_result = AML::parse_object(context);
|
||||||
|
if (!parse_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto node = parse_result.node();
|
||||||
|
if (node && node->type == AML::Node::Type::Register)
|
||||||
|
node = static_cast<AML::Register*>(node.ptr())->value;
|
||||||
|
if (!node || node->type != AML::Node::Type::Reference)
|
||||||
|
{
|
||||||
|
AML_TODO("DerefOf source is not a Reference, but a {}", node ? static_cast<uint8_t>(node->type) : 999);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINT("DerefOf ");
|
||||||
|
node->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
return ParseResult(static_cast<Reference*>(node.ptr())->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINTLN("Reference {");
|
||||||
|
node->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
116
kernel/include/kernel/ACPI/AML/Region.h
Normal file
116
kernel/include/kernel/ACPI/AML/Region.h
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct OpRegion final : public AML::NamedObject
|
||||||
|
{
|
||||||
|
using RegionSpace = GAS::AddressSpaceID;
|
||||||
|
RegionSpace region_space;
|
||||||
|
uint64_t region_offset;
|
||||||
|
uint64_t region_length;
|
||||||
|
|
||||||
|
Kernel::Mutex mutex;
|
||||||
|
|
||||||
|
OpRegion(NameSeg name, RegionSpace region_space, uint64_t region_offset, uint64_t region_length)
|
||||||
|
: NamedObject(Node::Type::OpRegion, name)
|
||||||
|
, region_space(region_space)
|
||||||
|
, region_offset(region_offset)
|
||||||
|
, region_length(region_length)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() > 2);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<ExtOp>(context.aml_data[1]) == ExtOp::OpRegionOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto name = NameString::parse(context.aml_data);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto region_space = static_cast<RegionSpace>(context.aml_data[0]);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto offset_result = AML::parse_object(context);
|
||||||
|
if (!offset_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto offset_node = offset_result.node()
|
||||||
|
? offset_result.node()->convert(AML::Node::ConvInteger)
|
||||||
|
: BAN::RefPtr<AML::Node>();
|
||||||
|
if (!offset_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("OpRegion offset must be an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto length_result = AML::parse_object(context);
|
||||||
|
if (!length_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto length_node = length_result.node()
|
||||||
|
? length_result.node()->convert(AML::Node::ConvInteger)
|
||||||
|
: BAN::RefPtr<AML::Node>();
|
||||||
|
if (!length_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("OpRegion length must be an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto offset = static_cast<AML::Integer*>(offset_node.ptr())->value;
|
||||||
|
const auto length = static_cast<AML::Integer*>(length_node.ptr())->value;
|
||||||
|
|
||||||
|
auto op_region = MUST(BAN::RefPtr<OpRegion>::create(
|
||||||
|
name->path.back(),
|
||||||
|
region_space,
|
||||||
|
offset,
|
||||||
|
length
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name.value(), op_region))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
op_region->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
BAN::StringView region_space_name;
|
||||||
|
switch (region_space)
|
||||||
|
{
|
||||||
|
case RegionSpace::SystemMemory: region_space_name = "SystemMemory"_sv; break;
|
||||||
|
case RegionSpace::SystemIO: region_space_name = "SystemIO"_sv; break;
|
||||||
|
case RegionSpace::PCIConfig: region_space_name = "PCIConfig"_sv; break;
|
||||||
|
case RegionSpace::EmbeddedController: region_space_name = "EmbeddedController"_sv; break;
|
||||||
|
case RegionSpace::SMBus: region_space_name = "SMBus"_sv; break;
|
||||||
|
case RegionSpace::SystemCMOS: region_space_name = "SystemCMOS"_sv; break;
|
||||||
|
case RegionSpace::PCIBarTarget: region_space_name = "PCIBarTarget"_sv; break;
|
||||||
|
case RegionSpace::IPMI: region_space_name = "IPMI"_sv; break;
|
||||||
|
case RegionSpace::GeneralPurposeIO: region_space_name = "GeneralPurposeIO"_sv; break;
|
||||||
|
case RegionSpace::GenericSerialBus: region_space_name = "GenericSerialBus"_sv; break;
|
||||||
|
case RegionSpace::PlatformCommunicationChannel: region_space_name = "PlatformCommunicationChannel"_sv; break;
|
||||||
|
default: region_space_name = "Unknown"_sv; break;
|
||||||
|
}
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("OperationRegion(");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(", {}, 0x{H}, 0x{H})", region_space_name, region_offset, region_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
23
kernel/include/kernel/ACPI/AML/Register.h
Normal file
23
kernel/include/kernel/ACPI/AML/Register.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Register final : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::Node> value;
|
||||||
|
|
||||||
|
Register();
|
||||||
|
Register(BAN::RefPtr<AML::Node> node);
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> to_underlying() override { return value->to_underlying(); }
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> source) override;
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,74 +1,27 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Hash.h>
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Scope
|
struct Scope : public AML::NamedObject
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(Scope);
|
AML::NameString scope;
|
||||||
public:
|
|
||||||
Scope() = default;
|
|
||||||
Scope(Scope&& other) { *this = BAN::move(other); }
|
|
||||||
Scope& operator=(Scope&& other) { parts = BAN::move(other.parts); return *this; }
|
|
||||||
|
|
||||||
BAN::Vector<uint32_t> parts;
|
Scope(Node::Type type, NameSeg name)
|
||||||
|
: NamedObject(type, name)
|
||||||
|
{}
|
||||||
|
|
||||||
BAN::ErrorOr<Scope> copy() const
|
virtual bool is_scope() const override { return true; }
|
||||||
{
|
|
||||||
Scope result;
|
|
||||||
TRY(result.parts.reserve(parts.size()));
|
|
||||||
for (uint32_t part : parts)
|
|
||||||
TRY(result.parts.push_back(part));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Scope& other) const
|
static ParseResult parse(ParseContext& context);
|
||||||
{
|
|
||||||
if (parts.size() != other.parts.size())
|
protected:
|
||||||
return false;
|
ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data);
|
||||||
for (size_t i = 0; i < parts.size(); i++)
|
|
||||||
if (parts[i] != other.parts[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
bool initialize_scope(BAN::RefPtr<Scope> scope);
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct hash<Kernel::ACPI::AML::Scope>
|
|
||||||
{
|
|
||||||
hash_t operator()(const Kernel::ACPI::AML::Scope& scope) const
|
|
||||||
{
|
|
||||||
hash_t hash { 0 };
|
|
||||||
for (uint32_t part : scope.parts)
|
|
||||||
hash ^= u32_hash(part);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace BAN::Formatter
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
void print_argument(F putc, const Kernel::ACPI::AML::Scope& scope, const ValueFormat&)
|
|
||||||
{
|
|
||||||
putc('\\');
|
|
||||||
for (size_t i = 0; i < scope.parts.size(); i++) {
|
|
||||||
if (i != 0)
|
|
||||||
putc('.');
|
|
||||||
const char* name_seg = reinterpret_cast<const char*>(&scope.parts[i]);
|
|
||||||
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
60
kernel/include/kernel/ACPI/AML/SizeOf.h
Normal file
60
kernel/include/kernel/ACPI/AML/SizeOf.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Buffer.h>
|
||||||
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
|
#include <kernel/ACPI/AML/Package.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Reference.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct SizeOf
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::SizeOfOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto object_result = AML::parse_object(context);
|
||||||
|
if (!object_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto object_node = object_result.node();
|
||||||
|
if (object_node)
|
||||||
|
object_node = object_node->to_underlying();
|
||||||
|
if (!object_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("SizeOf object is null");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
if (object_node->type != AML::Node::Type::Package)
|
||||||
|
object_node = object_node->convert(AML::Node::ConvBuffer | AML::Node::ConvString);
|
||||||
|
if (!object_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("SizeOf object is not Buffer, String or Package");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t size = 0;
|
||||||
|
switch (object_node->type)
|
||||||
|
{
|
||||||
|
case AML::Node::Type::Buffer:
|
||||||
|
size = static_cast<AML::Buffer*>(object_node.ptr())->buffer.size();
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::String:
|
||||||
|
size = static_cast<AML::String*>(object_node.ptr())->string.size();
|
||||||
|
break;
|
||||||
|
case AML::Node::Type::Package:
|
||||||
|
size = static_cast<AML::Package*>(object_node.ptr())->elements.size();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(size)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
42
kernel/include/kernel/ACPI/AML/Sleep.h
Normal file
42
kernel/include/kernel/ACPI/AML/Sleep.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Sleep
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::SleepOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto sleep_time_result = AML::parse_object(context);
|
||||||
|
if (!sleep_time_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto sleep_time_node = sleep_time_result.node()
|
||||||
|
? sleep_time_result.node()->convert(AML::Node::ConvInteger)
|
||||||
|
: BAN::RefPtr<AML::Node>();
|
||||||
|
if (!sleep_time_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Sleep time cannot be evaluated to an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto sleep_time_value = static_cast<AML::Integer*>(sleep_time_node.ptr())->value;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINTLN("Sleeping for {} ms", sleep_time_value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SystemTimer::get().sleep_ms(sleep_time_value);
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
53
kernel/include/kernel/ACPI/AML/Store.h
Normal file
53
kernel/include/kernel/ACPI/AML/Store.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Store
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::StoreOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto source_result = AML::parse_object(context);
|
||||||
|
if (!source_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto source = source_result.node();
|
||||||
|
if (!source)
|
||||||
|
{
|
||||||
|
AML_ERROR("Store source is null");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto destination_result = AML::parse_object(context);
|
||||||
|
if (!destination_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto destination = destination_result.node();
|
||||||
|
if (!destination)
|
||||||
|
{
|
||||||
|
AML_ERROR("Store destination is null");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
AML_DEBUG_PRINTLN("Storing {");
|
||||||
|
source->debug_print(1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
AML_DEBUG_PRINTLN("} to {");
|
||||||
|
destination->debug_print(1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
AML_DEBUG_PRINTLN("}");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (auto stored = destination->store(source))
|
||||||
|
return ParseResult(stored);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
69
kernel/include/kernel/ACPI/AML/String.h
Normal file
69
kernel/include/kernel/ACPI/AML/String.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct String final : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::Vector<uint8_t> string;
|
||||||
|
|
||||||
|
String() : Node(Node::Type::String) {}
|
||||||
|
String(BAN::StringView string)
|
||||||
|
: Node(Node::Type::String)
|
||||||
|
{
|
||||||
|
MUST(this->string.resize(string.size()));
|
||||||
|
for (size_t i = 0; i < string.size(); i++)
|
||||||
|
this->string[i] = string[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop);
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> copy() override
|
||||||
|
{
|
||||||
|
auto new_string = MUST(BAN::RefPtr<AML::String>::create());
|
||||||
|
MUST(new_string->string.resize(this->string.size()));
|
||||||
|
for (size_t i = 0; i < this->string.size(); i++)
|
||||||
|
new_string->string[i] = this->string[i];
|
||||||
|
return new_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||||
|
{
|
||||||
|
ASSERT(node);
|
||||||
|
auto conv_node = node->convert(AML::Node::ConvString);
|
||||||
|
if (!conv_node)
|
||||||
|
{
|
||||||
|
AML_ERROR("Could not convert to String");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto* string_node = static_cast<AML::String*>(conv_node.ptr());
|
||||||
|
MUST(string.resize(string_node->string.size()));
|
||||||
|
for (size_t i = 0; i < string.size(); i++)
|
||||||
|
string[i] = string_node->string[i];
|
||||||
|
return string_node->copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::StringView string_view() const
|
||||||
|
{
|
||||||
|
return BAN::StringView(reinterpret_cast<const char*>(string.data()), string.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("String \"{}\"", string_view());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::RefPtr<AML::Buffer> as_buffer();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
64
kernel/include/kernel/ACPI/AML/ThermalZone.h
Normal file
64
kernel/include/kernel/ACPI/AML/ThermalZone.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ThermalZone final : public AML::Scope
|
||||||
|
{
|
||||||
|
ThermalZone(NameSeg name)
|
||||||
|
: Scope(Node::Type::ThermalZone, name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ThermalZoneOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto opt_thermal_zone_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!opt_thermal_zone_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto thermal_zone_pkg = opt_thermal_zone_pkg.value();
|
||||||
|
|
||||||
|
auto name = NameString::parse(thermal_zone_pkg);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto thermal_zone = MUST(BAN::RefPtr<ThermalZone>::create(name->path.back()));
|
||||||
|
if (!Namespace::root_namespace()->add_named_object(context, name.value(), thermal_zone))
|
||||||
|
return ParseResult::Success;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
thermal_zone->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return thermal_zone->enter_context_and_parse_term_list(context, name.value(), thermal_zone_pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("ThermalZone {} {", name);
|
||||||
|
Namespace::root_namespace()->for_each_child(scope,
|
||||||
|
[&](const auto&, const auto& child)
|
||||||
|
{
|
||||||
|
child->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
36
kernel/include/kernel/ACPI/AML/Utils.h
Normal file
36
kernel/include/kernel/ACPI/AML/Utils.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Formatter.h>
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
|
||||||
|
// AML_DEBUG_LEVEL:
|
||||||
|
// 0: No debug output
|
||||||
|
// 1: Dump AML after parsing
|
||||||
|
// 2: Dump AML while parsing
|
||||||
|
#define AML_DEBUG_LEVEL 0
|
||||||
|
|
||||||
|
#define AML_TODO(...) \
|
||||||
|
do { \
|
||||||
|
BAN::Formatter::print(Debug::putchar, "\e[33mTODO: "); \
|
||||||
|
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::println(Debug::putchar, "\e[m"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define AML_ERROR(...) \
|
||||||
|
do { \
|
||||||
|
BAN::Formatter::print(Debug::putchar, "\e[31mERROR: "); \
|
||||||
|
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::println(Debug::putchar, "\e[m"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define AML_PRINT(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define AML_DEBUG_PRINT_INDENT(indent) \
|
||||||
|
do { \
|
||||||
|
for (int i = 0; i < (indent) * 2; i++) \
|
||||||
|
AML_DEBUG_PUTC(' '); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define AML_DEBUG_PUTC(c) Debug::putchar(c)
|
||||||
|
#define AML_DEBUG_PRINT(...) BAN::Formatter::print(Debug::putchar, __VA_ARGS__)
|
||||||
|
#define AML_DEBUG_PRINTLN(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user